vigthoria-cli 1.13.18 → 1.13.20
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 +21 -7
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +85 -0
- package/dist/commands/config.js +10 -14
- package/dist/index.js +95 -4
- package/dist/utils/api.d.ts +1 -3
- package/dist/utils/api.js +64 -77
- package/dist/utils/config.js +7 -5
- package/dist/utils/fastAgentRouter.d.ts +2 -2
- package/dist/utils/fastAgentRouter.js +4 -5
- package/dist/utils/session.d.ts +18 -0
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +2 -1
- package/scripts/release/validate-no-go-gates.sh +6 -4
package/dist/commands/auth.js
CHANGED
|
@@ -11,9 +11,13 @@ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
|
11
11
|
const KNOWN_AUTH_BASE_URLS = ['https://coder.vigthoria.io'];
|
|
12
12
|
class HttpError extends Error {
|
|
13
13
|
status;
|
|
14
|
-
|
|
14
|
+
code;
|
|
15
|
+
upgradeUrl;
|
|
16
|
+
constructor(status, message, code, upgradeUrl) {
|
|
15
17
|
super(message);
|
|
16
18
|
this.status = status;
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.upgradeUrl = upgradeUrl;
|
|
17
21
|
}
|
|
18
22
|
}
|
|
19
23
|
function trimTrailingSlash(value) {
|
|
@@ -206,12 +210,19 @@ async function requestJson(url, init) {
|
|
|
206
210
|
}
|
|
207
211
|
}
|
|
208
212
|
if (!response.ok) {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
const errorBody = typeof body === 'object' && body ? body : {};
|
|
214
|
+
const code = String(errorBody.code || '');
|
|
215
|
+
const planNames = Array.isArray(errorBody.requiredPlans)
|
|
216
|
+
? errorBody.requiredPlans.map(plan => plan.name || plan.id).filter(Boolean)
|
|
217
|
+
: [];
|
|
218
|
+
const message = code === 'SUBSCRIPTION_REQUIRED'
|
|
219
|
+
? `This project requires a paid Vigthoria subscription.${planNames.length ? ` Eligible plans: ${planNames.join(', ')}.` : ''} Upgrade: ${errorBody.upgradeUrl || 'https://hub.vigthoria.io/subscriptions?application=coder'}`
|
|
220
|
+
: 'error' in errorBody && errorBody.error
|
|
221
|
+
? String(errorBody.error)
|
|
222
|
+
: 'message' in errorBody && errorBody.message
|
|
223
|
+
? String(errorBody.message)
|
|
224
|
+
: `Request failed with status ${response.status}`;
|
|
225
|
+
throw new HttpError(response.status, message, code || undefined, errorBody.upgradeUrl);
|
|
215
226
|
}
|
|
216
227
|
return body;
|
|
217
228
|
}
|
|
@@ -316,6 +327,9 @@ export async function login(email, password) {
|
|
|
316
327
|
return config;
|
|
317
328
|
}
|
|
318
329
|
catch (error) {
|
|
330
|
+
if (error instanceof HttpError && error.code === 'SUBSCRIPTION_REQUIRED') {
|
|
331
|
+
throw error;
|
|
332
|
+
}
|
|
319
333
|
const message = humanMessage(error);
|
|
320
334
|
failures.push(`${endpoint} -> ${message}`);
|
|
321
335
|
}
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -272,6 +272,8 @@ export declare class ChatCommand {
|
|
|
272
272
|
private truncateText;
|
|
273
273
|
private getLastUserPrompt;
|
|
274
274
|
private saveSession;
|
|
275
|
+
private persistAgentExecutionCheckpoint;
|
|
276
|
+
private updateAgentExecutionCheckpoint;
|
|
275
277
|
private requestPermission;
|
|
276
278
|
getCurrentSessionInfo(): string;
|
|
277
279
|
getChatHistory(): ChatMessage[];
|
package/dist/commands/chat.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from 'fs';
|
|
|
3
3
|
import * as os from 'os';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import * as readline from 'readline';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
6
7
|
import { createSpinner } from '../utils/logger.js';
|
|
7
8
|
import { APIClient, CLIError, classifyError, formatCLIError, sanitizeUserFacingErrorText, sanitizeUserFacingPathText, propagateError, VIGTHORIA_SERVER_TEMPORARILY_UNAVAILABLE_MESSAGE } from '../utils/api.js';
|
|
8
9
|
import { AgenticTools, robustifyStreamResponse } from '../utils/tools.js';
|
|
@@ -1838,6 +1839,35 @@ export class ChatCommand {
|
|
|
1838
1839
|
originalPrompt: saved.originalPrompt ?? null,
|
|
1839
1840
|
};
|
|
1840
1841
|
}
|
|
1842
|
+
else if (this.currentSession.activeAgentRun?.prompt) {
|
|
1843
|
+
const checkpoint = this.currentSession.activeAgentRun;
|
|
1844
|
+
this.lastAgentRunOutcome = {
|
|
1845
|
+
prompt: checkpoint.prompt,
|
|
1846
|
+
originalPrompt: checkpoint.originalPrompt || checkpoint.prompt,
|
|
1847
|
+
taskId: checkpoint.executionId,
|
|
1848
|
+
contextId: checkpoint.contextId,
|
|
1849
|
+
tasksSucceeded: 0,
|
|
1850
|
+
tasksTotal: 0,
|
|
1851
|
+
failedTaskIds: [...(checkpoint.failedTaskIds || [])],
|
|
1852
|
+
unfinishedTaskIds: checkpoint.unfinishedTaskIds?.length
|
|
1853
|
+
? [...checkpoint.unfinishedTaskIds]
|
|
1854
|
+
: ['resume-interrupted-agent-run'],
|
|
1855
|
+
qualityScore: null,
|
|
1856
|
+
qualityMissing: [],
|
|
1857
|
+
qualityBlockers: checkpoint.error ? [checkpoint.error] : [],
|
|
1858
|
+
hasOutput: false,
|
|
1859
|
+
answerContent: null,
|
|
1860
|
+
selfHealStatus: 'skipped',
|
|
1861
|
+
selfHealTool: null,
|
|
1862
|
+
plannerError: null,
|
|
1863
|
+
executorError: checkpoint.error || 'The previous client process ended before the agent run completed.',
|
|
1864
|
+
clientToolErrors: [],
|
|
1865
|
+
transportErrors: [],
|
|
1866
|
+
workspacePath: checkpoint.workspacePath || this.currentProjectPath,
|
|
1867
|
+
workspaceSyncIssue: null,
|
|
1868
|
+
finishedAt: Date.parse(checkpoint.updatedAt) || Date.now(),
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1841
1871
|
return;
|
|
1842
1872
|
}
|
|
1843
1873
|
}
|
|
@@ -3193,12 +3223,33 @@ export class ChatCommand {
|
|
|
3193
3223
|
...(resumeTaskIds.length > 0 ? { remaining_task_ids: resumeTaskIds } : {}),
|
|
3194
3224
|
}
|
|
3195
3225
|
: executionHints;
|
|
3226
|
+
const previousExecutionId = this.currentSession?.activeAgentRun?.executionId || null;
|
|
3227
|
+
const executionId = `cli-${Date.now()}-${randomUUID().slice(0, 8)}`;
|
|
3196
3228
|
const workspaceContext = {
|
|
3197
3229
|
workspacePath: workspacePath,
|
|
3198
3230
|
projectPath: workspacePath,
|
|
3199
3231
|
targetPath: workspacePath,
|
|
3232
|
+
contextId: executionId,
|
|
3233
|
+
executionId,
|
|
3200
3234
|
...runtimeContext,
|
|
3201
3235
|
};
|
|
3236
|
+
this.persistAgentExecutionCheckpoint({
|
|
3237
|
+
executionId,
|
|
3238
|
+
parentExecutionId: shouldResumePlan ? previousExecutionId : null,
|
|
3239
|
+
contextId: executionId,
|
|
3240
|
+
prompt,
|
|
3241
|
+
originalPrompt: priorOutcome?.originalPrompt || priorOutcome?.prompt || prompt,
|
|
3242
|
+
workspacePath,
|
|
3243
|
+
userTier: String(this.config.get('subscription')?.plan || '').trim() || null,
|
|
3244
|
+
taskType: agentTaskType,
|
|
3245
|
+
workflowType,
|
|
3246
|
+
status: 'submitted',
|
|
3247
|
+
submittedAt: new Date().toISOString(),
|
|
3248
|
+
updatedAt: new Date().toISOString(),
|
|
3249
|
+
failedTaskIds: resumeTaskIds,
|
|
3250
|
+
unfinishedTaskIds: resumeTaskIds.length ? resumeTaskIds : ['agent-run-in-progress'],
|
|
3251
|
+
error: null,
|
|
3252
|
+
});
|
|
3202
3253
|
// Start workspace watcher for bidirectional real-time sync
|
|
3203
3254
|
let watcher = null;
|
|
3204
3255
|
if (this.shouldStartWorkspaceWatcher(workspacePath)) {
|
|
@@ -3252,6 +3303,7 @@ export class ChatCommand {
|
|
|
3252
3303
|
return;
|
|
3253
3304
|
}
|
|
3254
3305
|
if (event.type === 'plan') {
|
|
3306
|
+
this.updateAgentExecutionCheckpoint({ status: 'running' });
|
|
3255
3307
|
taskDisplay.complete(0);
|
|
3256
3308
|
const tasks = event?.plan?.tasks;
|
|
3257
3309
|
if (Array.isArray(tasks) && tasks.length > 0) {
|
|
@@ -3552,6 +3604,15 @@ export class ChatCommand {
|
|
|
3552
3604
|
: null,
|
|
3553
3605
|
finishedAt: Date.now(),
|
|
3554
3606
|
}, prompt);
|
|
3607
|
+
this.updateAgentExecutionCheckpoint({
|
|
3608
|
+
status: executorSucceeded ? 'completed' : 'failed',
|
|
3609
|
+
contextId: response.contextId || executionId,
|
|
3610
|
+
failedTaskIds: [...liveOutcome.failedTaskIds],
|
|
3611
|
+
unfinishedTaskIds: [...liveOutcome.unfinishedTaskIds],
|
|
3612
|
+
error: executorSucceeded
|
|
3613
|
+
? null
|
|
3614
|
+
: (liveOutcome.executorError || liveOutcome.plannerError || runEvaluation.statusHeadline),
|
|
3615
|
+
});
|
|
3555
3616
|
if (!this.jsonOutput && !this.directPromptMode) {
|
|
3556
3617
|
if (this.lastAgentRunOutcome) {
|
|
3557
3618
|
this.printAgentRunSummary(this.lastAgentRunOutcome, runEvaluation, changedFileCount);
|
|
@@ -3653,6 +3714,12 @@ export class ChatCommand {
|
|
|
3653
3714
|
workspaceSyncIssue: null,
|
|
3654
3715
|
finishedAt: Date.now(),
|
|
3655
3716
|
}, prompt);
|
|
3717
|
+
this.updateAgentExecutionCheckpoint({
|
|
3718
|
+
status: 'failed',
|
|
3719
|
+
failedTaskIds: [...liveOutcome.failedTaskIds],
|
|
3720
|
+
unfinishedTaskIds: [...liveOutcome.unfinishedTaskIds],
|
|
3721
|
+
error: liveOutcome.executorError || safeDetail || 'Connection aborted',
|
|
3722
|
+
});
|
|
3656
3723
|
if (!this.jsonOutput) {
|
|
3657
3724
|
process.exitCode = 1;
|
|
3658
3725
|
}
|
|
@@ -5056,6 +5123,24 @@ export class ChatCommand {
|
|
|
5056
5123
|
sessionSummary: this.currentSession.memorySummary || '',
|
|
5057
5124
|
});
|
|
5058
5125
|
}
|
|
5126
|
+
persistAgentExecutionCheckpoint(checkpoint) {
|
|
5127
|
+
if (!this.currentSession) {
|
|
5128
|
+
this.currentSession = this.sessionManager.create(this.currentProjectPath, this.currentModel, this.agentMode, this.operatorMode);
|
|
5129
|
+
}
|
|
5130
|
+
this.currentSession.activeAgentRun = checkpoint;
|
|
5131
|
+
this.saveSession();
|
|
5132
|
+
}
|
|
5133
|
+
updateAgentExecutionCheckpoint(update) {
|
|
5134
|
+
if (!this.currentSession?.activeAgentRun) {
|
|
5135
|
+
return;
|
|
5136
|
+
}
|
|
5137
|
+
this.currentSession.activeAgentRun = {
|
|
5138
|
+
...this.currentSession.activeAgentRun,
|
|
5139
|
+
...update,
|
|
5140
|
+
updatedAt: new Date().toISOString(),
|
|
5141
|
+
};
|
|
5142
|
+
this.saveSession();
|
|
5143
|
+
}
|
|
5059
5144
|
async requestPermission(action) {
|
|
5060
5145
|
if (this.autoApprove) {
|
|
5061
5146
|
return true;
|
package/dist/commands/config.js
CHANGED
|
@@ -40,7 +40,7 @@ export class ConfigCommand {
|
|
|
40
40
|
console.log();
|
|
41
41
|
const cwd = process.cwd();
|
|
42
42
|
const configFile = path.join(cwd, '.vigthoria.json');
|
|
43
|
-
const allowedModels = new Set(['code', 'code-35b', 'code-9b', 'balanced', 'balanced-4b']);
|
|
43
|
+
const allowedModels = new Set(['architect', 'code', 'assistant', 'code-35b', 'code-9b', 'balanced', 'balanced-4b']);
|
|
44
44
|
const hasOverrides = Boolean(options.model ||
|
|
45
45
|
options.ignorePatterns !== undefined ||
|
|
46
46
|
options.autoApplyFixes !== undefined ||
|
|
@@ -71,16 +71,16 @@ export class ConfigCommand {
|
|
|
71
71
|
let settings;
|
|
72
72
|
if (nonInteractive) {
|
|
73
73
|
const profileDefaults = {
|
|
74
|
-
safe: { defaultModel: '
|
|
74
|
+
safe: { defaultModel: 'assistant', autoApplyFixes: false },
|
|
75
75
|
balanced: { defaultModel: 'code', autoApplyFixes: false },
|
|
76
|
-
fast: { defaultModel: '
|
|
76
|
+
fast: { defaultModel: 'assistant', autoApplyFixes: true },
|
|
77
77
|
};
|
|
78
78
|
const profile = options.profile && profileDefaults[options.profile] ? options.profile : 'balanced';
|
|
79
79
|
const defaults = profileDefaults[profile];
|
|
80
80
|
const model = options.model || defaults.defaultModel;
|
|
81
81
|
if (!allowedModels.has(model)) {
|
|
82
82
|
this.logger.error(`Invalid --model: ${model}`);
|
|
83
|
-
this.logger.info('Allowed values: code, code-35b, code-9b, balanced, balanced-4b');
|
|
83
|
+
this.logger.info('Allowed values: architect, code, assistant, code-35b, code-9b, balanced, balanced-4b');
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
settings = {
|
|
@@ -98,12 +98,9 @@ export class ConfigCommand {
|
|
|
98
98
|
message: 'Default AI model:',
|
|
99
99
|
choices: [
|
|
100
100
|
{ name: '═══ Code Models ═══', disabled: true },
|
|
101
|
-
{ name: 'Vigthoria
|
|
102
|
-
{ name: 'Vigthoria
|
|
103
|
-
{ name: 'Vigthoria
|
|
104
|
-
{ name: '═══ General Models ═══', disabled: true },
|
|
105
|
-
{ name: 'Vigthoria Master 7.6B - Balanced general model', value: 'balanced' },
|
|
106
|
-
{ name: 'Vigthoria v3 Balanced 4B - Efficient general purpose', value: 'balanced-4b' },
|
|
101
|
+
{ name: 'Vigthoria v4 Creative 27B - Architect and planning', value: 'architect' },
|
|
102
|
+
{ name: 'Vigthoria v4 Code 27B - Production executor', value: 'code' },
|
|
103
|
+
{ name: 'Vigthoria v4 Assistant 9B - Fast FIM and diagnostics', value: 'assistant' },
|
|
107
104
|
],
|
|
108
105
|
default: 'code',
|
|
109
106
|
},
|
|
@@ -294,10 +291,9 @@ export class ConfigCommand {
|
|
|
294
291
|
name: 'defaultModel',
|
|
295
292
|
message: 'Default AI model:',
|
|
296
293
|
choices: [
|
|
297
|
-
{ name: 'Vigthoria
|
|
298
|
-
{ name: 'Vigthoria
|
|
299
|
-
{ name: 'Vigthoria
|
|
300
|
-
{ name: 'Vigthoria v3 Balanced 4B', value: 'balanced-4b' },
|
|
294
|
+
{ name: 'Vigthoria v4 Creative 27B — Architect', value: 'architect' },
|
|
295
|
+
{ name: 'Vigthoria v4 Code 27B — Executor', value: 'code' },
|
|
296
|
+
{ name: 'Vigthoria v4 Assistant 9B — FIM and diagnostics', value: 'assistant' },
|
|
301
297
|
],
|
|
302
298
|
default: current.preferences.defaultModel,
|
|
303
299
|
},
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,7 @@ import * as fs from 'fs';
|
|
|
49
49
|
import * as path from 'path';
|
|
50
50
|
import * as os from 'os';
|
|
51
51
|
import { fileURLToPath } from 'url';
|
|
52
|
+
import { createRequire } from 'module';
|
|
52
53
|
import { createHash } from 'crypto';
|
|
53
54
|
import axios from 'axios';
|
|
54
55
|
import { renderDynamicHelp, selectInteractiveCommand } from './utils/command-menu.js';
|
|
@@ -1608,9 +1609,57 @@ Examples:
|
|
|
1608
1609
|
: process.platform === 'win32' || process.platform === 'linux'
|
|
1609
1610
|
? 'supported-desktop'
|
|
1610
1611
|
: 'unsupported';
|
|
1612
|
+
const nodeMatch = process.versions.node.match(/^(\d+)\.(\d+)/);
|
|
1613
|
+
const nodeCompatible = Boolean(nodeMatch && (Number(nodeMatch[1]) > 20
|
|
1614
|
+
|| (Number(nodeMatch[1]) === 20 && Number(nodeMatch[2]) >= 19)));
|
|
1615
|
+
const runtimeRequire = createRequire(import.meta.url);
|
|
1616
|
+
const requiredRuntimePackages = ['axios', 'commander', 'inquirer', 'ws'];
|
|
1617
|
+
const missingRuntimePackages = requiredRuntimePackages.filter((name) => {
|
|
1618
|
+
try {
|
|
1619
|
+
runtimeRequire.resolve(name);
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
catch {
|
|
1623
|
+
return true;
|
|
1624
|
+
}
|
|
1625
|
+
});
|
|
1626
|
+
const sessionsDir = path.join(os.homedir(), '.vigthoria', 'sessions');
|
|
1627
|
+
let sessionStorageWritable = false;
|
|
1628
|
+
let latestCheckpoint = null;
|
|
1629
|
+
try {
|
|
1630
|
+
fs.mkdirSync(sessionsDir, { recursive: true, mode: 0o700 });
|
|
1631
|
+
const probePath = path.join(sessionsDir, `.doctor-${process.pid}-${Date.now()}.tmp`);
|
|
1632
|
+
fs.writeFileSync(probePath, '{}', { encoding: 'utf8', mode: 0o600 });
|
|
1633
|
+
fs.unlinkSync(probePath);
|
|
1634
|
+
sessionStorageWritable = true;
|
|
1635
|
+
const latestSessionFile = fs.readdirSync(sessionsDir)
|
|
1636
|
+
.filter((name) => name.endsWith('.json'))
|
|
1637
|
+
.map((name) => ({ name, mtime: fs.statSync(path.join(sessionsDir, name)).mtimeMs }))
|
|
1638
|
+
.sort((left, right) => right.mtime - left.mtime)[0]?.name;
|
|
1639
|
+
if (latestSessionFile) {
|
|
1640
|
+
const persisted = JSON.parse(fs.readFileSync(path.join(sessionsDir, latestSessionFile), 'utf8'));
|
|
1641
|
+
const checkpoint = persisted?.activeAgentRun;
|
|
1642
|
+
if (checkpoint && typeof checkpoint === 'object') {
|
|
1643
|
+
latestCheckpoint = {
|
|
1644
|
+
executionId: checkpoint.executionId || null,
|
|
1645
|
+
status: checkpoint.status || null,
|
|
1646
|
+
updatedAt: checkpoint.updatedAt || null,
|
|
1647
|
+
resumable: ['submitted', 'running', 'failed'].includes(String(checkpoint.status || '')),
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
catch {
|
|
1653
|
+
sessionStorageWritable = false;
|
|
1654
|
+
}
|
|
1655
|
+
const envToken = String(process.env.VIGTHORIA_AUTH_TOKEN || process.env.VIGTHORIA_TOKEN || '').trim();
|
|
1656
|
+
const configuredToken = envToken || String(config.get('authToken') || '').trim();
|
|
1657
|
+
const tokenSegments = configuredToken ? configuredToken.split('.').length : 0;
|
|
1611
1658
|
const report = {
|
|
1612
1659
|
cliVersion: VERSION,
|
|
1613
1660
|
nodeVersion: process.version,
|
|
1661
|
+
nodeCompatible,
|
|
1662
|
+
runtimeDependencies: missingRuntimePackages.length === 0 ? 'complete' : `missing: ${missingRuntimePackages.join(', ')}`,
|
|
1614
1663
|
platform: `${process.platform} ${process.arch}`,
|
|
1615
1664
|
clientOs: resolveClientOsSlug(),
|
|
1616
1665
|
platformSupport,
|
|
@@ -1624,6 +1673,14 @@ Examples:
|
|
|
1624
1673
|
apiUrl,
|
|
1625
1674
|
modelsApiUrl,
|
|
1626
1675
|
loggedIn: config.isAuthenticated(),
|
|
1676
|
+
authToken: configuredToken
|
|
1677
|
+
? { present: true, source: envToken ? 'environment' : 'secure-config', structure: tokenSegments === 3 ? 'jwt' : 'opaque' }
|
|
1678
|
+
: { present: false, source: null, structure: null },
|
|
1679
|
+
sessionPersistence: {
|
|
1680
|
+
directory: sessionsDir,
|
|
1681
|
+
writable: sessionStorageWritable,
|
|
1682
|
+
latestCheckpoint,
|
|
1683
|
+
},
|
|
1627
1684
|
subscriptionPlan: subscription.plan || null,
|
|
1628
1685
|
subscriptionStatus: subscription.status || null,
|
|
1629
1686
|
offlineMode: offline,
|
|
@@ -1638,20 +1695,52 @@ Examples:
|
|
|
1638
1695
|
},
|
|
1639
1696
|
};
|
|
1640
1697
|
if (options.checkApi && !offline) {
|
|
1698
|
+
const api = new APIClient(config, logger);
|
|
1699
|
+
if (configuredToken) {
|
|
1700
|
+
try {
|
|
1701
|
+
const tokenCheck = await api.validateToken({ allowNetworkFailOpen: false, enforceTokenShape: true });
|
|
1702
|
+
report.authValidation = tokenCheck.valid ? 'authenticated' : `failed (${tokenCheck.error || 'invalid token'})`;
|
|
1703
|
+
}
|
|
1704
|
+
catch (error) {
|
|
1705
|
+
report.authValidation = `unreachable (${sanitizeUserFacingErrorText(error.message)})`;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
else {
|
|
1709
|
+
report.authValidation = 'not checked (login required)';
|
|
1710
|
+
}
|
|
1641
1711
|
try {
|
|
1642
|
-
const probe = await axios.get(`${apiUrl}/api/health`, { timeout:
|
|
1712
|
+
const probe = await axios.get(`${apiUrl}/api/health`, { timeout: 12000, validateStatus: () => true });
|
|
1643
1713
|
report.apiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
|
|
1644
1714
|
}
|
|
1645
1715
|
catch (error) {
|
|
1646
1716
|
report.apiHealth = `unreachable (${error.message})`;
|
|
1647
1717
|
}
|
|
1648
1718
|
try {
|
|
1649
|
-
const probe = await axios.get(`${modelsApiUrl}/health`, { timeout:
|
|
1650
|
-
|
|
1719
|
+
const probe = await axios.get(`${modelsApiUrl}/health`, { timeout: 12000, validateStatus: () => true });
|
|
1720
|
+
const body = typeof probe.data === 'string' ? probe.data : JSON.stringify(probe.data || {});
|
|
1721
|
+
report.modelsApiHealth = probe.status >= 200 && probe.status < 400
|
|
1722
|
+
? 'online'
|
|
1723
|
+
: probe.status === 503 && /pre-release validation|closed/i.test(body)
|
|
1724
|
+
? 'pre-release-closed (Agent mode uses the Coder gateway)'
|
|
1725
|
+
: `status ${probe.status}`;
|
|
1651
1726
|
}
|
|
1652
1727
|
catch (error) {
|
|
1653
1728
|
report.modelsApiHealth = `unreachable (${error.message})`;
|
|
1654
1729
|
}
|
|
1730
|
+
if (configuredToken) {
|
|
1731
|
+
try {
|
|
1732
|
+
const capabilities = await api.getCapabilityTruthStatus({ workspacePath: process.cwd() });
|
|
1733
|
+
report.agentInfrastructure = {
|
|
1734
|
+
overall: capabilities.overallOk ? 'online' : 'degraded',
|
|
1735
|
+
v3Agent: capabilities.v3Agent.ok ? 'online' : capabilities.v3Agent.error || 'offline',
|
|
1736
|
+
hyperLoop: capabilities.hyperLoop.ok ? 'online' : capabilities.hyperLoop.error || 'offline',
|
|
1737
|
+
repoMemory: capabilities.repoMemory.ok ? 'online' : capabilities.repoMemory.error || 'offline',
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
catch (error) {
|
|
1741
|
+
report.agentInfrastructure = `unreachable (${sanitizeUserFacingErrorText(error.message)})`;
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1655
1744
|
}
|
|
1656
1745
|
if (options.json) {
|
|
1657
1746
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -1673,7 +1762,9 @@ Examples:
|
|
|
1673
1762
|
console.log(chalk.gray('\nTip: pass --check-api to verify API reachability.'));
|
|
1674
1763
|
}
|
|
1675
1764
|
}
|
|
1676
|
-
|
|
1765
|
+
const requiredLocalChecksPassed = nodeCompatible && missingRuntimePackages.length === 0 && sessionStorageWritable;
|
|
1766
|
+
const coderReachable = !options.checkApi || offline || report.apiHealth === 'online';
|
|
1767
|
+
process.exitCode = requiredLocalChecksPassed && coderReachable ? 0 : 1;
|
|
1677
1768
|
});
|
|
1678
1769
|
// Config command
|
|
1679
1770
|
program
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -362,8 +362,7 @@ export declare class APIClient {
|
|
|
362
362
|
private buildLocalWorkspaceSummary;
|
|
363
363
|
/**
|
|
364
364
|
* Build complete workspace hydration separately from model context.
|
|
365
|
-
*
|
|
366
|
-
* locally; context compaction must never become filesystem compaction.
|
|
365
|
+
* Context compaction must not become filesystem compaction.
|
|
367
366
|
*/
|
|
368
367
|
private buildOutOfBandWorkspaceFiles;
|
|
369
368
|
/**
|
|
@@ -417,7 +416,6 @@ export declare class APIClient {
|
|
|
417
416
|
status: string;
|
|
418
417
|
files: Record<string, string>;
|
|
419
418
|
file_count: number;
|
|
420
|
-
confirmed_mutations?: string[];
|
|
421
419
|
local_workspace_path?: string;
|
|
422
420
|
}>;
|
|
423
421
|
applyV3BackgroundJobFiles(jobId: string, context?: Record<string, any>): Promise<{
|
package/dist/utils/api.js
CHANGED
|
@@ -673,9 +673,8 @@ export class APIClient {
|
|
|
673
673
|
const normalizedRemote = remoteCandidates
|
|
674
674
|
.filter(Boolean)
|
|
675
675
|
.map((url) => String(url).replace(/\/$/, ''));
|
|
676
|
-
// An explicit
|
|
677
|
-
//
|
|
678
|
-
// cannot abort a healthy service-key-authenticated internal CLI run.
|
|
676
|
+
// An explicit endpoint is an operator routing decision. External installs
|
|
677
|
+
// have none and continue to use the public Coder gateway first.
|
|
679
678
|
const urls = (preferLocal || localTestMode || explicitV3EndpointConfigured) && localCandidates.length > 0
|
|
680
679
|
? [...localCandidates, ...normalizedRemote]
|
|
681
680
|
: [...normalizedRemote, ...localCandidates];
|
|
@@ -898,9 +897,6 @@ export class APIClient {
|
|
|
898
897
|
return null;
|
|
899
898
|
}
|
|
900
899
|
if (withoutQuery.startsWith('/')) {
|
|
901
|
-
// Preview/runtime serve a nested HTML entry from its containing
|
|
902
|
-
// directory, so `/styles.css` beside `showcase/index.html` resolves to
|
|
903
|
-
// `showcase/styles.css` in the hydrated workspace.
|
|
904
900
|
return this.normalizeWorkspaceRelativePath(path.posix.normalize(path.posix.join(entryDir, withoutQuery.slice(1))));
|
|
905
901
|
}
|
|
906
902
|
return this.normalizeWorkspaceRelativePath(path.posix.normalize(path.posix.join(entryDir, withoutQuery)));
|
|
@@ -923,9 +919,8 @@ export class APIClient {
|
|
|
923
919
|
const assetPattern = /<(?:link|img|source|video|audio)\b[^>]+(?:href|src)=["']([^"']+)["'][^>]*>/gi;
|
|
924
920
|
while ((match = assetPattern.exec(String(html || ''))) !== null) {
|
|
925
921
|
const resolved = normalizeAsset(match[1]);
|
|
926
|
-
if (resolved)
|
|
922
|
+
if (resolved)
|
|
927
923
|
assets.add(resolved);
|
|
928
|
-
}
|
|
929
924
|
}
|
|
930
925
|
return {
|
|
931
926
|
css: Array.from(css),
|
|
@@ -1618,18 +1613,10 @@ export class APIClient {
|
|
|
1618
1613
|
if (used + entryLen > budgetChars) {
|
|
1619
1614
|
const normalizedPath = this.normalizeWorkspaceRelativePath(filePath);
|
|
1620
1615
|
if (mandatory.has(normalizedPath)) {
|
|
1621
|
-
// Explicit prompt targets are hydration requirements, not ranking
|
|
1622
|
-
// hints. Skipping an HTML entry merely because a larger targeted
|
|
1623
|
-
// stylesheet consumed the provisional budget creates false preview
|
|
1624
|
-
// failures in the remote V3 workspace. Keep the complete explicit
|
|
1625
|
-
// file and let later context-compaction phases shed history/metadata.
|
|
1626
1616
|
trimmed[filePath] = clipped;
|
|
1627
1617
|
used += entryLen;
|
|
1628
1618
|
}
|
|
1629
1619
|
else if (explicitPriority.has(normalizedPath)) {
|
|
1630
|
-
// Linked preview assets are important enough to hydrate, but unlike
|
|
1631
|
-
// edit targets they may be compacted. Keep a bounded prefix so the
|
|
1632
|
-
// remote static server resolves the asset instead of returning 404.
|
|
1633
1620
|
const envelope = JSON.stringify(filePath).length + 128;
|
|
1634
1621
|
const available = Math.max(256, budgetChars - used - envelope);
|
|
1635
1622
|
const dependencyClip = content.length > available
|
|
@@ -1666,10 +1653,6 @@ export class APIClient {
|
|
|
1666
1653
|
const localWorkspaceRef = localWorkspaceName ? `vigthoria://local-workspace/${localWorkspaceName}` : null;
|
|
1667
1654
|
const executionSurface = String(resolvedContext.executionSurface || resolvedContext.clientSurface || 'cli');
|
|
1668
1655
|
const localMachineCapable = resolvedContext.localMachineCapable !== false;
|
|
1669
|
-
// A workspace under a configured server root is already available to the
|
|
1670
|
-
// V3 service. Keep tool execution on the server in that case; delegating
|
|
1671
|
-
// tools back to the CLI can turn server paths into invalid client paths.
|
|
1672
|
-
// An explicit caller override remains authoritative for specialist flows.
|
|
1673
1656
|
const clientToolExecution = resolvedContext.clientToolExecution === false
|
|
1674
1657
|
? false
|
|
1675
1658
|
: (resolvedContext.clientToolExecution === true
|
|
@@ -2739,8 +2722,7 @@ menu {
|
|
|
2739
2722
|
}
|
|
2740
2723
|
}
|
|
2741
2724
|
catch {
|
|
2742
|
-
//
|
|
2743
|
-
// the original focus list; dependency expansion is best effort.
|
|
2725
|
+
// Best effort: the explicit target remains in focusFiles.
|
|
2744
2726
|
}
|
|
2745
2727
|
}
|
|
2746
2728
|
const hydrationFocusFiles = [...focusFiles, ...linkedFocusAssets];
|
|
@@ -2807,8 +2789,7 @@ menu {
|
|
|
2807
2789
|
}
|
|
2808
2790
|
/**
|
|
2809
2791
|
* Build complete workspace hydration separately from model context.
|
|
2810
|
-
*
|
|
2811
|
-
* locally; context compaction must never become filesystem compaction.
|
|
2792
|
+
* Context compaction must not become filesystem compaction.
|
|
2812
2793
|
*/
|
|
2813
2794
|
buildOutOfBandWorkspaceFiles(context) {
|
|
2814
2795
|
const resolvedContext = this.ensureExecutionContext(context);
|
|
@@ -4475,12 +4456,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4475
4456
|
await this.ensureV3ServiceKey();
|
|
4476
4457
|
const executionContext = await this.bindExecutionContext({
|
|
4477
4458
|
...context,
|
|
4478
|
-
// Background callers historically supplied only workspace metadata.
|
|
4479
|
-
// Without the request in the execution context, buildV3AgentContext()
|
|
4480
|
-
// classified every detached job from an empty prompt and emitted an
|
|
4481
|
-
// `analysis_only` workflow. V3 would then inspect the workspace but was
|
|
4482
|
-
// correctly forbidden from writing. Preserve an explicit caller value,
|
|
4483
|
-
// otherwise make the submitted job request authoritative for routing.
|
|
4484
4459
|
rawPrompt: context.rawPrompt || context.prompt || message,
|
|
4485
4460
|
prompt: context.prompt || context.rawPrompt || message,
|
|
4486
4461
|
backgroundJob: true,
|
|
@@ -4649,13 +4624,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4649
4624
|
return;
|
|
4650
4625
|
mutatedPaths.add(normalized);
|
|
4651
4626
|
};
|
|
4652
|
-
for (const filePath of data.confirmed_mutations || [])
|
|
4627
|
+
for (const filePath of (data.confirmed_mutations || []))
|
|
4653
4628
|
addMutatedPath(filePath);
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
if (event?.type === 'file_mutation' && event?.action !== 'delete') {
|
|
4629
|
+
for (const event of (Array.isArray(job?.events) ? job.events : [])) {
|
|
4630
|
+
if (event?.type === 'file_mutation' && event?.action !== 'delete')
|
|
4657
4631
|
addMutatedPath(event.path);
|
|
4658
|
-
}
|
|
4659
4632
|
if (event?.type === 'executor_complete') {
|
|
4660
4633
|
let summary = event.summary;
|
|
4661
4634
|
if (typeof summary === 'string') {
|
|
@@ -5118,7 +5091,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5118
5091
|
'vigthoria-cloud-ultra',
|
|
5119
5092
|
]);
|
|
5120
5093
|
if (cloudModels.has(resolvedModel)) {
|
|
5121
|
-
return '
|
|
5094
|
+
return 'Vigthoria-v4-Code-27B';
|
|
5122
5095
|
}
|
|
5123
5096
|
return null;
|
|
5124
5097
|
}
|
|
@@ -5134,10 +5107,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5134
5107
|
}
|
|
5135
5108
|
resolvePermittedModelId(shortName) {
|
|
5136
5109
|
const normalizedRequested = String(shortName || '').trim().toLowerCase();
|
|
5137
|
-
const blockedModels = new Set(['
|
|
5110
|
+
const blockedModels = new Set(['mini', 'creative-v3', 'creative-v4']);
|
|
5138
5111
|
if (blockedModels.has(normalizedRequested)) {
|
|
5139
|
-
this.logger.debug(`Blocked
|
|
5140
|
-
return '
|
|
5112
|
+
this.logger.debug(`Blocked retired model ${shortName}; using fallback Vigthoria-v4-Code-27B`);
|
|
5113
|
+
return 'Vigthoria-v4-Code-27B';
|
|
5141
5114
|
}
|
|
5142
5115
|
const resolvedModel = this.resolveModelId(shortName);
|
|
5143
5116
|
if (this.isCloudModelId(resolvedModel) && !this.canUseCloudModel()) {
|
|
@@ -5163,6 +5136,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5163
5136
|
isSelfHostedPreferredModel(resolvedModel, requestedModel) {
|
|
5164
5137
|
const normalizedRequested = String(requestedModel || '').toLowerCase();
|
|
5165
5138
|
const selfHostedModels = new Set([
|
|
5139
|
+
'Vigthoria-v4-Creative-27B',
|
|
5140
|
+
'Vigthoria-v4-Code-27B',
|
|
5141
|
+
'Vigthoria-v4-Assistant-9B',
|
|
5166
5142
|
'vigthoria-v3-code-35b',
|
|
5167
5143
|
'vigthoria-v3-code-35b:latest',
|
|
5168
5144
|
'vigthoria-v3-code-9b',
|
|
@@ -5173,6 +5149,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5173
5149
|
]);
|
|
5174
5150
|
return selfHostedModels.has(resolvedModel)
|
|
5175
5151
|
|| normalizedRequested === 'agent'
|
|
5152
|
+
|| normalizedRequested === 'architect'
|
|
5153
|
+
|| normalizedRequested === 'assistant'
|
|
5176
5154
|
|| normalizedRequested === 'code'
|
|
5177
5155
|
|| normalizedRequested === 'code-30b'
|
|
5178
5156
|
|| normalizedRequested === 'code-35b'
|
|
@@ -5183,9 +5161,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5183
5161
|
}
|
|
5184
5162
|
getSelfHostedFallbackModelId(resolvedModel, requestedModel) {
|
|
5185
5163
|
if (this.isSelfHostedPreferredModel(resolvedModel, requestedModel)) {
|
|
5186
|
-
return resolvedModel === 'qwen3-coder:latest' ? '
|
|
5164
|
+
return resolvedModel === 'qwen3-coder:latest' ? 'Vigthoria-v4-Code-27B' : resolvedModel;
|
|
5187
5165
|
}
|
|
5188
|
-
return '
|
|
5166
|
+
return 'Vigthoria-v4-Code-27B';
|
|
5189
5167
|
}
|
|
5190
5168
|
// Streaming chat
|
|
5191
5169
|
async *chatStream(messages, model) {
|
|
@@ -5268,7 +5246,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5268
5246
|
// (/v1/chat/completions on api.vigthoria.io) which is the only
|
|
5269
5247
|
// backend that reliably accepts our auth token.
|
|
5270
5248
|
async chatComplete(systemPrompt, userPrompt, model, maxTokens) {
|
|
5271
|
-
const resolvedModel = model ? this.resolvePermittedModelId(model) : '
|
|
5249
|
+
const resolvedModel = model ? this.resolvePermittedModelId(model) : 'Vigthoria-v4-Code-27B';
|
|
5272
5250
|
const response = await this.modelRouterClient.post('/v1/chat/completions', {
|
|
5273
5251
|
model: resolvedModel,
|
|
5274
5252
|
messages: [
|
|
@@ -6118,21 +6096,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6118
6096
|
// ═══════════════════════════════════════════════════════════════
|
|
6119
6097
|
// Vigthoria server infrastructure models
|
|
6120
6098
|
// ═══════════════════════════════════════════════════════════════
|
|
6121
|
-
'fast': '
|
|
6099
|
+
'fast': 'Vigthoria-v4-Assistant-9B',
|
|
6122
6100
|
'mini': 'vigthoria-mini-0.6b',
|
|
6123
|
-
'balanced': '
|
|
6124
|
-
'balanced-4b': '
|
|
6125
|
-
'
|
|
6101
|
+
'balanced': 'Vigthoria-v4-Assistant-9B',
|
|
6102
|
+
'balanced-4b': 'Vigthoria-v4-Assistant-9B',
|
|
6103
|
+
'assistant': 'Vigthoria-v4-Assistant-9B',
|
|
6104
|
+
'creative': 'Vigthoria-v4-Creative-27B',
|
|
6105
|
+
'architect': 'Vigthoria-v4-Creative-27B',
|
|
6126
6106
|
// Code Models - 35B is the default powerhouse
|
|
6127
|
-
'code': '
|
|
6128
|
-
'code-30b': '
|
|
6129
|
-
'code-35b': '
|
|
6130
|
-
'code-8b': '
|
|
6131
|
-
'code-9b': '
|
|
6132
|
-
'pro': '
|
|
6133
|
-
'agent': '
|
|
6134
|
-
'vigthoria-code': '
|
|
6135
|
-
'vigthoria-agent': '
|
|
6107
|
+
'code': 'Vigthoria-v4-Code-27B',
|
|
6108
|
+
'code-30b': 'Vigthoria-v4-Code-27B',
|
|
6109
|
+
'code-35b': 'Vigthoria-v4-Code-27B',
|
|
6110
|
+
'code-8b': 'Vigthoria-v4-Assistant-9B',
|
|
6111
|
+
'code-9b': 'Vigthoria-v4-Assistant-9B',
|
|
6112
|
+
'pro': 'Vigthoria-v4-Code-27B',
|
|
6113
|
+
'agent': 'Vigthoria-v4-Code-27B',
|
|
6114
|
+
'vigthoria-code': 'Vigthoria-v4-Code-27B',
|
|
6115
|
+
'vigthoria-agent': 'Vigthoria-v4-Code-27B',
|
|
6136
6116
|
// ═══════════════════════════════════════════════════════════════
|
|
6137
6117
|
// VIGTHORIA CLOUD - current billing catalog aliases
|
|
6138
6118
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -6150,17 +6130,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6150
6130
|
'cloud-ultra': 'vigthoria-cloud-maximum',
|
|
6151
6131
|
};
|
|
6152
6132
|
// If already a full model ID, return as-is
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6133
|
+
const normalizedShortName = String(shortName || '').toLowerCase();
|
|
6134
|
+
if (normalizedShortName.includes('vigthoria') || shortName.includes('/') || shortName.includes(':')) {
|
|
6135
|
+
if (modelMap[normalizedShortName]) {
|
|
6136
|
+
return modelMap[normalizedShortName];
|
|
6156
6137
|
}
|
|
6157
6138
|
return shortName;
|
|
6158
6139
|
}
|
|
6159
|
-
return modelMap[
|
|
6140
|
+
return modelMap[normalizedShortName] || 'Vigthoria-v4-Code-27B';
|
|
6160
6141
|
}
|
|
6161
6142
|
async getCoderHealth() {
|
|
6162
6143
|
try {
|
|
6163
|
-
const response = await this.client.get('/api/health', { timeout:
|
|
6144
|
+
const response = await this.client.get('/api/health', { timeout: 12000 });
|
|
6164
6145
|
const ok = response.data?.status === 'ok' || response.data?.healthy === true;
|
|
6165
6146
|
return {
|
|
6166
6147
|
name: 'Coder API',
|
|
@@ -6335,7 +6316,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6335
6316
|
const candidates = ['/v1/models', '/models', '/api/models', '/api/tags'];
|
|
6336
6317
|
for (const endpoint of candidates) {
|
|
6337
6318
|
try {
|
|
6338
|
-
const response = await client.get(endpoint, { timeout:
|
|
6319
|
+
const response = await client.get(endpoint, { timeout: 12000 });
|
|
6339
6320
|
const modelCount = this.extractModelCount(response.data);
|
|
6340
6321
|
if (modelCount > 0) {
|
|
6341
6322
|
return { modelCount, endpoint };
|
|
@@ -6351,7 +6332,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6351
6332
|
const modelsApiUrl = this.config.get('modelsApiUrl');
|
|
6352
6333
|
try {
|
|
6353
6334
|
const [healthResponse, modelProbe] = await Promise.all([
|
|
6354
|
-
this.modelRouterClient.get('/health', { timeout:
|
|
6335
|
+
this.modelRouterClient.get('/health', { timeout: 12000 }),
|
|
6355
6336
|
this.probeModelList(this.modelRouterClient),
|
|
6356
6337
|
]);
|
|
6357
6338
|
const healthOk = this.isHealthyServicePayload(healthResponse.data);
|
|
@@ -6384,7 +6365,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6384
6365
|
}
|
|
6385
6366
|
try {
|
|
6386
6367
|
const [healthResponse, modelProbe] = await Promise.all([
|
|
6387
|
-
this.selfHostedModelRouterClient.get('/health', { timeout:
|
|
6368
|
+
this.selfHostedModelRouterClient.get('/health', { timeout: 12000 }),
|
|
6388
6369
|
this.probeModelList(this.selfHostedModelRouterClient),
|
|
6389
6370
|
]);
|
|
6390
6371
|
const healthOk = this.isHealthyServicePayload(healthResponse.data);
|
|
@@ -6422,7 +6403,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6422
6403
|
for (const endpoint of candidates) {
|
|
6423
6404
|
try {
|
|
6424
6405
|
const controller = new AbortController();
|
|
6425
|
-
const timer = setTimeout(() => controller.abort(),
|
|
6406
|
+
const timer = setTimeout(() => controller.abort(), 12000);
|
|
6426
6407
|
const response = await fetch(endpoint, {
|
|
6427
6408
|
method: 'GET',
|
|
6428
6409
|
headers,
|
|
@@ -6497,9 +6478,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6497
6478
|
const endpoint = process.env.VIGTHORIA_HYPERLOOP_URL || `${configuredApiUrl}/api/hyperloop/health`;
|
|
6498
6479
|
try {
|
|
6499
6480
|
const token = this.getAccessToken();
|
|
6481
|
+
const hyperLoopServiceKey = process.env.VIGTHORIA_HYPERLOOP_SERVICE_KEY || process.env.HYPERLOOP_SERVICE_KEY || '';
|
|
6500
6482
|
const response = await fetchWithServiceTimeout(endpoint, {
|
|
6501
6483
|
method: 'GET',
|
|
6502
|
-
headers:
|
|
6484
|
+
headers: {
|
|
6485
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6486
|
+
...(hyperLoopServiceKey ? { 'X-Service-Key': hyperLoopServiceKey } : {}),
|
|
6487
|
+
},
|
|
6503
6488
|
});
|
|
6504
6489
|
if (!response.ok) {
|
|
6505
6490
|
throw new Error(`Hyper Loop health ${response.status}`);
|
|
@@ -6527,13 +6512,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6527
6512
|
const endpoint = process.env.VIGTHORIA_HYPERLOOP_EXECUTE_URL || `${configuredApiUrl}/api/hyperloop/execute`;
|
|
6528
6513
|
const modulesEndpoint = process.env.VIGTHORIA_HYPERLOOP_MODULES_URL || `${configuredApiUrl}/api/hyperloop/modules`;
|
|
6529
6514
|
const token = this.getAccessToken();
|
|
6515
|
+
const hyperLoopServiceKey = process.env.VIGTHORIA_HYPERLOOP_SERVICE_KEY || process.env.HYPERLOOP_SERVICE_KEY || '';
|
|
6516
|
+
const hyperLoopHeaders = {
|
|
6517
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6518
|
+
...(hyperLoopServiceKey ? { 'X-Service-Key': hyperLoopServiceKey } : {}),
|
|
6519
|
+
};
|
|
6530
6520
|
const projectPath = this.resolveAgentTargetPath(context);
|
|
6531
6521
|
try {
|
|
6532
6522
|
const modulesResponse = await fetchWithServiceTimeout(modulesEndpoint, {
|
|
6533
6523
|
method: 'GET',
|
|
6534
|
-
headers:
|
|
6535
|
-
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6536
|
-
},
|
|
6524
|
+
headers: hyperLoopHeaders,
|
|
6537
6525
|
});
|
|
6538
6526
|
if (!modulesResponse.ok) {
|
|
6539
6527
|
throw new Error(`Repo memory modules ${modulesResponse.status}`);
|
|
@@ -6545,10 +6533,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6545
6533
|
try {
|
|
6546
6534
|
const probeResponse = await fetchWithServiceTimeout(endpoint, {
|
|
6547
6535
|
method: 'POST',
|
|
6548
|
-
headers: {
|
|
6549
|
-
'Content-Type': 'application/json',
|
|
6550
|
-
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6551
|
-
},
|
|
6536
|
+
headers: { 'Content-Type': 'application/json', ...hyperLoopHeaders },
|
|
6552
6537
|
body: JSON.stringify({
|
|
6553
6538
|
module: 'repo_context_compactor',
|
|
6554
6539
|
payload: {
|
|
@@ -6565,7 +6550,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6565
6550
|
});
|
|
6566
6551
|
if (probeResponse.ok) {
|
|
6567
6552
|
const probeData = await probeResponse.json();
|
|
6568
|
-
compactContextLength = String(probeData?.result?.compact_context
|
|
6553
|
+
compactContextLength = String(probeData?.result?.compact_context
|
|
6554
|
+
|| probeData?.result?.result?.compact_context
|
|
6555
|
+
|| '').length;
|
|
6569
6556
|
}
|
|
6570
6557
|
}
|
|
6571
6558
|
catch {
|
|
@@ -6682,12 +6669,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6682
6669
|
});
|
|
6683
6670
|
}
|
|
6684
6671
|
async getCapabilityTruthStatus(context = {}) {
|
|
6685
|
-
//
|
|
6686
|
-
//
|
|
6687
|
-
//
|
|
6672
|
+
// The public edge can legitimately take 5-10 seconds during cold routing.
|
|
6673
|
+
// Keep a finite ceiling, but do not turn a healthy slow edge into the old
|
|
6674
|
+
// hard 10-second preflight failure seen on external client machines.
|
|
6688
6675
|
const withTimeout = (p, name) => Promise.race([
|
|
6689
6676
|
p,
|
|
6690
|
-
new Promise(resolve => setTimeout(() => resolve({ name, endpoint: '', ok: false, error: 'Service not reachable (
|
|
6677
|
+
new Promise(resolve => setTimeout(() => resolve({ name, endpoint: '', ok: false, error: 'Service not reachable (15 s timeout)' }), 15000)),
|
|
6691
6678
|
]);
|
|
6692
6679
|
const [v3Agent, hyperLoop, repoMemory, devtoolsBridge] = await Promise.all([
|
|
6693
6680
|
withTimeout(this.getV3AgentHealth(), 'V3 Agent'),
|
package/dist/utils/config.js
CHANGED
|
@@ -195,11 +195,13 @@ export class Config {
|
|
|
195
195
|
// Vigthoria server infrastructure operational models
|
|
196
196
|
// ═══════════════════════════════════════════════════════════════
|
|
197
197
|
const models = [
|
|
198
|
-
{ id: '
|
|
199
|
-
{ id: 'code
|
|
200
|
-
{ id: '
|
|
201
|
-
{ id: '
|
|
202
|
-
{ id: '
|
|
198
|
+
{ id: 'architect', name: 'Vigthoria v4 Creative 27B', description: 'Architect, planning, deep reasoning, and creative systems work', tier: 'local', backendModel: 'Vigthoria-v4-Creative-27B' },
|
|
199
|
+
{ id: 'code', name: 'Vigthoria v4 Code 27B', description: 'Dense production executor for coding, debugging, and repository changes', tier: 'local', backendModel: 'Vigthoria-v4-Code-27B' },
|
|
200
|
+
{ id: 'assistant', name: 'Vigthoria v4 Assistant 9B', description: 'Low-latency FIM, completion, voice, and diagnostic model', tier: 'local', backendModel: 'Vigthoria-v4-Assistant-9B' },
|
|
201
|
+
{ id: 'code-35b', name: 'Vigthoria v4 Code 27B', description: 'Legacy selector mapped to the V4 executor', tier: 'local', backendModel: 'Vigthoria-v4-Code-27B' },
|
|
202
|
+
{ id: 'code-9b', name: 'Vigthoria v4 Assistant 9B', description: 'Legacy selector mapped to the V4 assistant', tier: 'local', backendModel: 'Vigthoria-v4-Assistant-9B' },
|
|
203
|
+
{ id: 'balanced', name: 'Vigthoria v4 Assistant 9B', description: 'Legacy selector mapped to the V4 assistant', tier: 'local', backendModel: 'Vigthoria-v4-Assistant-9B' },
|
|
204
|
+
{ id: 'balanced-4b', name: 'Vigthoria v4 Assistant 9B', description: 'Legacy selector mapped to the V4 assistant', tier: 'local', backendModel: 'Vigthoria-v4-Assistant-9B' },
|
|
203
205
|
];
|
|
204
206
|
if (this.hasCloudAccess()) {
|
|
205
207
|
models.push({ id: 'cloud-fast', name: 'Vigthoria Cloud Fast', description: 'Fast cloud responses for lighter work', tier: 'cloud', backendModel: 'vigthoria-cloud-fast' }, { id: 'cloud-balanced', name: 'Vigthoria Cloud Balanced', description: 'Default quality/cost balance for chat and coding', tier: 'cloud', backendModel: 'vigthoria-cloud-balanced' }, { id: 'cloud-code', name: 'Vigthoria Cloud Code', description: 'Economical cloud coding and completion', tier: 'cloud', backendModel: 'vigthoria-cloud-code' }, { id: 'cloud-power', name: 'Vigthoria Cloud Power', description: 'Premium general intelligence for demanding work', tier: 'cloud', backendModel: 'vigthoria-cloud-power' }, { id: 'cloud-maximum', name: 'Vigthoria Cloud Maximum', description: 'Maximum power for complex architecture and reviews', tier: 'cloud', backendModel: 'vigthoria-cloud-maximum' },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vigthoria
|
|
2
|
+
* Vigthoria v4 Assistant 9B — fast agent path classifier through the governed router.
|
|
3
3
|
* Regex/trivial detection always wins; LLM router refines ambiguous build prompts only.
|
|
4
4
|
*/
|
|
5
5
|
export type AgentRoutePath = 'template-instant' | 'v3-agent' | 'analysis-only';
|
|
@@ -23,7 +23,7 @@ export interface BalancedRouterResult {
|
|
|
23
23
|
}
|
|
24
24
|
export declare function parseBalancedRouterJson(raw: string): BalancedRouterJson | null;
|
|
25
25
|
/**
|
|
26
|
-
* Inference bases for
|
|
26
|
+
* Inference bases for the V4 Assistant routing lane only.
|
|
27
27
|
* Local developer machines must opt in (env) — avoids ~1.5s localhost probe on every Windows turn.
|
|
28
28
|
*/
|
|
29
29
|
export declare function getInferenceRouterBaseUrls(selfHostedUrl: string | null): string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vigthoria
|
|
2
|
+
* Vigthoria v4 Assistant 9B — fast agent path classifier through the governed router.
|
|
3
3
|
* Regex/trivial detection always wins; LLM router refines ambiguous build prompts only.
|
|
4
4
|
*/
|
|
5
5
|
const ROUTER_SYSTEM = `You are Vigthoria Agent Router. Reply with ONE JSON object only. No markdown, no HTML, no code fences.
|
|
@@ -14,8 +14,7 @@ fast_path: "template-instant" or null
|
|
|
14
14
|
|
|
15
15
|
Example: {"path":"template-instant","task_kind":"web-build","fast_path":"template-instant","confidence":0.95,"reason":"trivial html popup page"}`;
|
|
16
16
|
const INFERENCE_MODEL_IDS = [
|
|
17
|
-
'
|
|
18
|
-
'vigthoria-v3-balanced-4b',
|
|
17
|
+
'Vigthoria-v4-Assistant-9B',
|
|
19
18
|
];
|
|
20
19
|
function normalizePath(value) {
|
|
21
20
|
const p = String(value || '').trim().toLowerCase();
|
|
@@ -56,7 +55,7 @@ export function parseBalancedRouterJson(raw) {
|
|
|
56
55
|
return null;
|
|
57
56
|
}
|
|
58
57
|
/**
|
|
59
|
-
* Inference bases for
|
|
58
|
+
* Inference bases for the V4 Assistant routing lane only.
|
|
60
59
|
* Local developer machines must opt in (env) — avoids ~1.5s localhost probe on every Windows turn.
|
|
61
60
|
*/
|
|
62
61
|
export function getInferenceRouterBaseUrls(selfHostedUrl) {
|
|
@@ -69,7 +68,7 @@ export function getInferenceRouterBaseUrls(selfHostedUrl) {
|
|
|
69
68
|
|| process.env.VIGTHORIA_AGENT_LLM_ROUTER === '1'
|
|
70
69
|
|| process.platform === 'linux';
|
|
71
70
|
if (allowLocalhost) {
|
|
72
|
-
urls.push('http://127.0.0.1:
|
|
71
|
+
urls.push('http://127.0.0.1:4009');
|
|
73
72
|
}
|
|
74
73
|
return [...new Set(urls)];
|
|
75
74
|
}
|
package/dist/utils/session.d.ts
CHANGED
|
@@ -47,6 +47,24 @@ export interface Session {
|
|
|
47
47
|
agentMode: boolean;
|
|
48
48
|
operatorMode?: boolean;
|
|
49
49
|
lastAgentRunOutcome?: Record<string, unknown> | null;
|
|
50
|
+
activeAgentRun?: AgentExecutionCheckpoint | null;
|
|
51
|
+
}
|
|
52
|
+
export interface AgentExecutionCheckpoint {
|
|
53
|
+
executionId: string;
|
|
54
|
+
parentExecutionId?: string | null;
|
|
55
|
+
contextId: string;
|
|
56
|
+
prompt: string;
|
|
57
|
+
originalPrompt: string;
|
|
58
|
+
workspacePath: string;
|
|
59
|
+
userTier: string | null;
|
|
60
|
+
taskType: string;
|
|
61
|
+
workflowType: string;
|
|
62
|
+
status: 'submitted' | 'running' | 'completed' | 'failed';
|
|
63
|
+
submittedAt: string;
|
|
64
|
+
updatedAt: string;
|
|
65
|
+
failedTaskIds: string[];
|
|
66
|
+
unfinishedTaskIds: string[];
|
|
67
|
+
error?: string | null;
|
|
50
68
|
}
|
|
51
69
|
export declare class SessionManager {
|
|
52
70
|
private sessionsDir;
|
package/install.ps1
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
$ErrorActionPreference = "Stop"
|
|
6
6
|
|
|
7
7
|
# Configuration
|
|
8
|
-
$CLI_VERSION = "1.13.
|
|
8
|
+
$CLI_VERSION = "1.13.20"
|
|
9
9
|
$INSTALL_DIR = "$env:USERPROFILE\.vigthoria"
|
|
10
10
|
$NPM_PACKAGE = "vigthoria-cli"
|
|
11
11
|
$GIT_PACKAGE_URL = "git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
|
package/install.sh
CHANGED
|
@@ -26,7 +26,7 @@ else
|
|
|
26
26
|
fi
|
|
27
27
|
|
|
28
28
|
# Configuration
|
|
29
|
-
CLI_VERSION="1.13.
|
|
29
|
+
CLI_VERSION="1.13.20"
|
|
30
30
|
INSTALL_DIR="$HOME/.vigthoria"
|
|
31
31
|
REPO_URL="https://market.vigthoria.io/vigthoria/vigthoria-cli"
|
|
32
32
|
GIT_PACKAGE_URL="git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigthoria-cli",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.20",
|
|
4
4
|
"description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"test:v3-workspace-path": "npm run build && node scripts/test-v3-workspace-path.js",
|
|
75
75
|
"test:v3-server-tool-execution": "npm run build && node scripts/test-v3-server-tool-execution.js",
|
|
76
76
|
"test:session:project-match": "npm run build && node scripts/test-session-project-match.mjs",
|
|
77
|
+
"test:external-client-resume": "npm run build && node scripts/test-external-client-resume.mjs",
|
|
77
78
|
"test:v3-stream-mutation": "npm run build && node scripts/test-v3-stream-mutation.js",
|
|
78
79
|
"test:context:budget": "npm run build && node scripts/test-context-budget.js",
|
|
79
80
|
"test:v3-client-tool-quality": "npm run build && node scripts/test-v3-client-tool-quality.mjs",
|
|
@@ -88,7 +88,7 @@ python3 - << 'PY'
|
|
|
88
88
|
import json
|
|
89
89
|
j=json.load(open('/tmp/vig-balanced.json'))
|
|
90
90
|
assert j.get('success') is True
|
|
91
|
-
assert j.get('model') in ('vigthoria-balanced-4b', 'vigthoria-v3-balanced-4b'), j
|
|
91
|
+
assert j.get('model') in ('Vigthoria-v4-Assistant-9B', 'vigthoria-balanced-4b', 'vigthoria-v3-balanced-4b'), j
|
|
92
92
|
print('[pass] balanced-4b')
|
|
93
93
|
PY
|
|
94
94
|
|
|
@@ -125,6 +125,7 @@ ids={m.get('id','') for m in json.load(open('/tmp/vig-models.json')).get('data',
|
|
|
125
125
|
if ids:
|
|
126
126
|
has_router = any(
|
|
127
127
|
m in ids for m in (
|
|
128
|
+
'Vigthoria-v4-Assistant-9B',
|
|
128
129
|
'vigthoria-balanced-4b', 'vigthoria-balanced-4b:latest',
|
|
129
130
|
'vigthoria-v3-balanced-4b', 'vigthoria-v3-balanced-4b:latest',
|
|
130
131
|
'vigthoria-fast-9b', 'vigthoria-fast-9b:latest',
|
|
@@ -132,11 +133,12 @@ if ids:
|
|
|
132
133
|
)
|
|
133
134
|
has_creative = any(
|
|
134
135
|
m in ids for m in (
|
|
136
|
+
'Vigthoria-v4-Creative-27B',
|
|
135
137
|
'vigthoria-creative-9b-v4', 'vigthoria-creative-9b-v4:latest',
|
|
136
138
|
'vigthoria-fast-9b', 'vigthoria-fast-9b:latest',
|
|
137
139
|
)
|
|
138
140
|
)
|
|
139
|
-
has_code = any(re.search(r'^vigthoria-v3(?:\.\d+)?-code-35b(?:-|:|$)', i) for i in ids)
|
|
141
|
+
has_code = 'Vigthoria-v4-Code-27B' in ids or any(re.search(r'^vigthoria-v3(?:\.\d+)?-code-35b(?:-|:|$)', i) for i in ids)
|
|
140
142
|
assert has_router, f'missing router model in inventory: {sorted(ids)}'
|
|
141
143
|
assert has_creative, f'missing creative/fast model in inventory: {sorted(ids)}'
|
|
142
144
|
assert has_code, f'missing code model in inventory: {sorted(ids)}'
|
|
@@ -163,7 +165,7 @@ cat /tmp/vig-release-urls.txt
|
|
|
163
165
|
|
|
164
166
|
echo "[12.1] no-agent governance fallback"
|
|
165
167
|
for attempt in 1 2 3; do
|
|
166
|
-
if $CLI chat --no-agent --model creative --prompt "say ok" --json >/tmp/vig-creative.json; then
|
|
168
|
+
if $CLI chat --no-agent --model creative-v4 --prompt "say ok" --json >/tmp/vig-creative.json; then
|
|
167
169
|
break
|
|
168
170
|
fi
|
|
169
171
|
if [[ "$attempt" == "3" ]]; then
|
|
@@ -177,7 +179,7 @@ python3 - << 'PY'
|
|
|
177
179
|
import json
|
|
178
180
|
j=json.load(open('/tmp/vig-creative.json'))
|
|
179
181
|
assert j.get('success') is True
|
|
180
|
-
assert j.get('model') == '
|
|
182
|
+
assert j.get('model') == 'Vigthoria-v4-Code-27B', j
|
|
181
183
|
md=j.get('metadata') or {}
|
|
182
184
|
fb=md.get('modelFallback') or {}
|
|
183
185
|
assert fb.get('reason') == 'governance-blocked-model', j
|