vigthoria-cli 1.13.13 → 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/background.d.ts +3 -0
- package/dist/commands/background.js +58 -1
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +121 -1
- package/dist/commands/config.js +10 -14
- package/dist/commands/legion.js +48 -13
- package/dist/index.js +107 -6
- package/dist/utils/api.d.ts +7 -0
- package/dist/utils/api.js +236 -55
- package/dist/utils/clientManifest.d.ts +9 -0
- package/dist/utils/clientManifest.js +11 -1
- package/dist/utils/command-menu.js +6 -0
- package/dist/utils/config.js +7 -5
- package/dist/utils/contextBudget.d.ts +5 -1
- package/dist/utils/contextBudget.js +7 -4
- package/dist/utils/fastAgentRouter.d.ts +2 -2
- package/dist/utils/fastAgentRouter.js +4 -5
- package/dist/utils/requestIntent.js +5 -4
- package/dist/utils/session.d.ts +18 -0
- package/dist/utils/v3-workspace-path.js +22 -2
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +3 -1
- package/scripts/release/validate-no-go-gates.sh +45 -7
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';
|
|
@@ -472,10 +473,10 @@ async function enforceGatewayAuthSession(config, logger, jsonOutputRequested) {
|
|
|
472
473
|
if (isLocalTestfarmMode()) {
|
|
473
474
|
return true;
|
|
474
475
|
}
|
|
475
|
-
|
|
476
|
+
const explicitEnvToken = Boolean(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN);
|
|
477
|
+
if (!config.isAuthenticated() && !explicitEnvToken) {
|
|
476
478
|
return true;
|
|
477
479
|
}
|
|
478
|
-
const explicitEnvToken = Boolean(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN);
|
|
479
480
|
// Offline mode disables every outbound preflight call.
|
|
480
481
|
if (isOfflineMode()) {
|
|
481
482
|
return true;
|
|
@@ -1317,6 +1318,7 @@ Examples:
|
|
|
1317
1318
|
.command('start <prompt...>')
|
|
1318
1319
|
.description('Start an Agent job in the background and return immediately')
|
|
1319
1320
|
.option('--workspace <path>', 'Local workspace path', process.cwd())
|
|
1321
|
+
.option('--model <model>', 'Execution lane: agent, cloud, cloud-reason, or ultra', 'agent')
|
|
1320
1322
|
.option('--json', 'Emit JSON output', false)
|
|
1321
1323
|
.action(async (prompt, options) => {
|
|
1322
1324
|
const bg = new BackgroundCommand(config, logger);
|
|
@@ -1357,6 +1359,15 @@ Examples:
|
|
|
1357
1359
|
const bg = new BackgroundCommand(config, logger);
|
|
1358
1360
|
await bg.cancel(jobId, options);
|
|
1359
1361
|
});
|
|
1362
|
+
backgroundCommand
|
|
1363
|
+
.command('approve <jobId> <approvalId>')
|
|
1364
|
+
.description('Resolve a pending two-stage command gate for a background job')
|
|
1365
|
+
.option('--deny', 'Deny the command instead of approving it', false)
|
|
1366
|
+
.option('--json', 'Emit JSON output', false)
|
|
1367
|
+
.action(async (jobId, approvalId, options) => {
|
|
1368
|
+
const bg = new BackgroundCommand(config, logger);
|
|
1369
|
+
await bg.approve(jobId, approvalId, options);
|
|
1370
|
+
});
|
|
1360
1371
|
backgroundCommand.action(() => {
|
|
1361
1372
|
backgroundCommand.outputHelp();
|
|
1362
1373
|
});
|
|
@@ -1598,9 +1609,57 @@ Examples:
|
|
|
1598
1609
|
: process.platform === 'win32' || process.platform === 'linux'
|
|
1599
1610
|
? 'supported-desktop'
|
|
1600
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;
|
|
1601
1658
|
const report = {
|
|
1602
1659
|
cliVersion: VERSION,
|
|
1603
1660
|
nodeVersion: process.version,
|
|
1661
|
+
nodeCompatible,
|
|
1662
|
+
runtimeDependencies: missingRuntimePackages.length === 0 ? 'complete' : `missing: ${missingRuntimePackages.join(', ')}`,
|
|
1604
1663
|
platform: `${process.platform} ${process.arch}`,
|
|
1605
1664
|
clientOs: resolveClientOsSlug(),
|
|
1606
1665
|
platformSupport,
|
|
@@ -1614,6 +1673,14 @@ Examples:
|
|
|
1614
1673
|
apiUrl,
|
|
1615
1674
|
modelsApiUrl,
|
|
1616
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
|
+
},
|
|
1617
1684
|
subscriptionPlan: subscription.plan || null,
|
|
1618
1685
|
subscriptionStatus: subscription.status || null,
|
|
1619
1686
|
offlineMode: offline,
|
|
@@ -1628,20 +1695,52 @@ Examples:
|
|
|
1628
1695
|
},
|
|
1629
1696
|
};
|
|
1630
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
|
+
}
|
|
1631
1711
|
try {
|
|
1632
|
-
const probe = await axios.get(`${apiUrl}/api/health`, { timeout:
|
|
1712
|
+
const probe = await axios.get(`${apiUrl}/api/health`, { timeout: 12000, validateStatus: () => true });
|
|
1633
1713
|
report.apiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
|
|
1634
1714
|
}
|
|
1635
1715
|
catch (error) {
|
|
1636
1716
|
report.apiHealth = `unreachable (${error.message})`;
|
|
1637
1717
|
}
|
|
1638
1718
|
try {
|
|
1639
|
-
const probe = await axios.get(`${modelsApiUrl}/health`, { timeout:
|
|
1640
|
-
|
|
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}`;
|
|
1641
1726
|
}
|
|
1642
1727
|
catch (error) {
|
|
1643
1728
|
report.modelsApiHealth = `unreachable (${error.message})`;
|
|
1644
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
|
+
}
|
|
1645
1744
|
}
|
|
1646
1745
|
if (options.json) {
|
|
1647
1746
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -1663,7 +1762,9 @@ Examples:
|
|
|
1663
1762
|
console.log(chalk.gray('\nTip: pass --check-api to verify API reachability.'));
|
|
1664
1763
|
}
|
|
1665
1764
|
}
|
|
1666
|
-
|
|
1765
|
+
const requiredLocalChecksPassed = nodeCompatible && missingRuntimePackages.length === 0 && sessionStorageWritable;
|
|
1766
|
+
const coderReachable = !options.checkApi || offline || report.apiHealth === 'online';
|
|
1767
|
+
process.exitCode = requiredLocalChecksPassed && coderReachable ? 0 : 1;
|
|
1667
1768
|
});
|
|
1668
1769
|
// Config command
|
|
1669
1770
|
program
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -261,6 +261,7 @@ export declare class APIClient {
|
|
|
261
261
|
getV3AgentRunUrl(baseUrl: string): string;
|
|
262
262
|
getV3AgentContinueUrl(baseUrl: string): string;
|
|
263
263
|
getV3AgentBackgroundUrl(baseUrl: string, suffix?: string): string;
|
|
264
|
+
getV3AgentApprovalUrl(baseUrl: string): string;
|
|
264
265
|
getOperatorBaseUrls(): string[];
|
|
265
266
|
getOperatorStreamUrl(baseUrl: string): string;
|
|
266
267
|
getMcpBaseUrls(): string[];
|
|
@@ -359,6 +360,11 @@ export declare class APIClient {
|
|
|
359
360
|
private buildPublicWorkspaceDescriptor;
|
|
360
361
|
private buildPublicRuntimeEnvironment;
|
|
361
362
|
private buildLocalWorkspaceSummary;
|
|
363
|
+
/**
|
|
364
|
+
* Build complete workspace hydration separately from model context.
|
|
365
|
+
* Context compaction must not become filesystem compaction.
|
|
366
|
+
*/
|
|
367
|
+
private buildOutOfBandWorkspaceFiles;
|
|
362
368
|
/**
|
|
363
369
|
* Collect text file contents from the workspace for V3 agent hydration.
|
|
364
370
|
* Budget: up to ~2 MB total, per-file cap 200 KB, skip binary extensions.
|
|
@@ -405,6 +411,7 @@ export declare class APIClient {
|
|
|
405
411
|
listV3BackgroundJobs(limit?: number): Promise<any[]>;
|
|
406
412
|
getV3BackgroundJob(jobId: string): Promise<any>;
|
|
407
413
|
cancelV3BackgroundJob(jobId: string): Promise<any>;
|
|
414
|
+
resolveV3BackgroundApproval(jobId: string, approvalId: string, approved: boolean, allowMode?: string): Promise<any>;
|
|
408
415
|
getV3BackgroundJobFiles(jobId: string): Promise<{
|
|
409
416
|
status: string;
|
|
410
417
|
files: Record<string, string>;
|