vigthoria-cli 1.13.20 → 1.13.22
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/completions/_vigthoria +49 -0
- package/completions/vigthoria.bash +6 -0
- package/completions/vigthoria.fish +41 -0
- package/dist/commands/auth.d.ts +1 -0
- package/dist/commands/auth.js +63 -128
- package/dist/commands/background.d.ts +0 -2
- package/dist/commands/background.js +26 -34
- package/dist/commands/bridge.js +45 -41
- package/dist/commands/cancel.d.ts +1 -0
- package/dist/commands/cancel.js +22 -16
- package/dist/commands/chat.d.ts +3 -42
- package/dist/commands/chat.js +378 -1123
- package/dist/commands/coding-registration.d.ts +4 -0
- package/dist/commands/coding-registration.js +24 -0
- package/dist/commands/config.js +23 -29
- package/dist/commands/conversation-registration.d.ts +4 -0
- package/dist/commands/conversation-registration.js +122 -0
- package/dist/commands/deploy.d.ts +8 -2
- package/dist/commands/deploy.js +92 -90
- package/dist/commands/device.d.ts +1 -2
- package/dist/commands/device.js +37 -21
- package/dist/commands/doctor-registration.d.ts +4 -0
- package/dist/commands/doctor-registration.js +200 -0
- package/dist/commands/edit.js +22 -33
- package/dist/commands/explain.js +7 -10
- package/dist/commands/fork.d.ts +1 -2
- package/dist/commands/fork.js +72 -22
- package/dist/commands/game.d.ts +1 -1
- package/dist/commands/game.js +17 -6
- package/dist/commands/generate.js +7 -9
- package/dist/commands/history.js +11 -7
- package/dist/commands/hub.d.ts +2 -2
- package/dist/commands/hub.js +34 -35
- package/dist/commands/legion.d.ts +0 -1
- package/dist/commands/legion.js +62 -79
- package/dist/commands/music.d.ts +1 -2
- package/dist/commands/music.js +62 -27
- package/dist/commands/platform-registration.d.ts +4 -0
- package/dist/commands/platform-registration.js +45 -0
- package/dist/commands/preview.d.ts +0 -1
- package/dist/commands/preview.js +82 -35
- package/dist/commands/product-run-registration.d.ts +4 -0
- package/dist/commands/product-run-registration.js +490 -0
- package/dist/commands/replay.d.ts +1 -2
- package/dist/commands/replay.js +15 -11
- package/dist/commands/repo.d.ts +14 -7
- package/dist/commands/repo.js +245 -196
- package/dist/commands/review.js +9 -12
- package/dist/commands/security.d.ts +1 -2
- package/dist/commands/security.js +12 -6
- package/dist/commands/update-registration.d.ts +3 -0
- package/dist/commands/update-registration.js +338 -0
- package/dist/commands/v4-registration.d.ts +4 -0
- package/dist/commands/v4-registration.js +24 -0
- package/dist/commands/v4.d.ts +1 -1
- package/dist/commands/v4.js +46 -8
- package/dist/commands/wallet.d.ts +1 -3
- package/dist/commands/wallet.js +18 -45
- package/dist/commands/workflow.d.ts +2 -0
- package/dist/commands/workflow.js +52 -39
- package/dist/index.js +122 -1589
- package/dist/utils/agent-stream-state.d.ts +27 -0
- package/dist/utils/agent-stream-state.js +93 -0
- package/dist/utils/agentRoute.d.ts +2 -1
- package/dist/utils/agentRoute.js +22 -9
- package/dist/utils/agentRunOutcome.d.ts +16 -0
- package/dist/utils/agentRunOutcome.js +37 -2
- package/dist/utils/api-client-factory.d.ts +8 -0
- package/dist/utils/api-client-factory.js +8 -0
- package/dist/utils/api.d.ts +44 -266
- package/dist/utils/api.js +647 -3180
- package/dist/utils/auth-session.d.ts +41 -0
- package/dist/utils/auth-session.js +224 -0
- package/dist/utils/brain-hub-client.d.ts +0 -4
- package/dist/utils/brain-hub-client.js +6 -3
- package/dist/utils/bridge-client.js +2 -0
- package/dist/utils/capability-health-service.d.ts +48 -0
- package/dist/utils/capability-health-service.js +64 -0
- package/dist/utils/chat-prompt-policy.d.ts +18 -0
- package/dist/utils/chat-prompt-policy.js +61 -0
- package/dist/utils/chat-tool-call-parser.d.ts +11 -0
- package/dist/utils/chat-tool-call-parser.js +71 -0
- package/dist/utils/cli-state.d.ts +22 -4
- package/dist/utils/cli-state.js +105 -47
- package/dist/utils/code-operations-service.d.ts +104 -0
- package/dist/utils/code-operations-service.js +837 -0
- package/dist/utils/codebase-indexer.d.ts +1 -0
- package/dist/utils/codebase-indexer.js +28 -8
- package/dist/utils/command-contract.d.ts +61 -0
- package/dist/utils/command-contract.js +149 -0
- package/dist/utils/command-policy.d.ts +10 -0
- package/dist/utils/command-policy.js +54 -0
- package/dist/utils/config.d.ts +13 -5
- package/dist/utils/config.js +220 -94
- package/dist/utils/context-ranker.js +11 -2
- package/dist/utils/context-state.d.ts +39 -0
- package/dist/utils/context-state.js +52 -0
- package/dist/utils/deckEvents.d.ts +0 -5
- package/dist/utils/deckEvents.js +3 -2
- package/dist/utils/desktop-bridge-client.js +2 -0
- package/dist/utils/direct-output-policy.d.ts +3 -0
- package/dist/utils/direct-output-policy.js +76 -0
- package/dist/utils/durable-json.d.ts +57 -0
- package/dist/utils/durable-json.js +319 -0
- package/dist/utils/fastAgentRouter.d.ts +5 -6
- package/dist/utils/fastAgentRouter.js +17 -25
- package/dist/utils/files.js +21 -13
- package/dist/utils/frontend-preview-service.d.ts +76 -0
- package/dist/utils/frontend-preview-service.js +482 -0
- package/dist/utils/goaEvents.d.ts +0 -4
- package/dist/utils/goaEvents.js +5 -2
- package/dist/utils/logger.d.ts +2 -1
- package/dist/utils/logger.js +27 -20
- package/dist/utils/mcp-context-client.d.ts +24 -0
- package/dist/utils/mcp-context-client.js +58 -0
- package/dist/utils/model-governance.d.ts +18 -0
- package/dist/utils/model-governance.js +75 -0
- package/dist/utils/model-transport-service.d.ts +44 -0
- package/dist/utils/model-transport-service.js +111 -0
- package/dist/utils/mutation-journal.d.ts +42 -0
- package/dist/utils/mutation-journal.js +387 -0
- package/dist/utils/network-policy.d.ts +24 -0
- package/dist/utils/network-policy.js +202 -0
- package/dist/utils/operator-client.d.ts +45 -0
- package/dist/utils/operator-client.js +159 -0
- package/dist/utils/post-write-validator.js +7 -9
- package/dist/utils/preview-screenshot-adapter.d.ts +13 -0
- package/dist/utils/preview-screenshot-adapter.js +36 -0
- package/dist/utils/process-policy.d.ts +23 -0
- package/dist/utils/process-policy.js +284 -0
- package/dist/utils/project-memory.d.ts +13 -3
- package/dist/utils/project-memory.js +70 -17
- package/dist/utils/prompt-workspace-resolver.d.ts +14 -0
- package/dist/utils/prompt-workspace-resolver.js +64 -0
- package/dist/utils/release-install.d.ts +11 -0
- package/dist/utils/release-install.js +155 -0
- package/dist/utils/release-policy.d.ts +64 -0
- package/dist/utils/release-policy.js +293 -0
- package/dist/utils/requestIntent.js +22 -3
- package/dist/utils/runtime-capability.d.ts +8 -0
- package/dist/utils/runtime-capability.js +16 -0
- package/dist/utils/secret-policy.d.ts +20 -0
- package/dist/utils/secret-policy.js +160 -0
- package/dist/utils/session.d.ts +17 -3
- package/dist/utils/session.js +354 -110
- package/dist/utils/tool-approval-service.d.ts +17 -0
- package/dist/utils/tool-approval-service.js +78 -0
- package/dist/utils/tool-capability-providers.d.ts +57 -0
- package/dist/utils/tool-capability-providers.js +57 -0
- package/dist/utils/tools.d.ts +2 -23
- package/dist/utils/tools.js +216 -508
- package/dist/utils/update-policy.d.ts +18 -0
- package/dist/utils/update-policy.js +137 -0
- package/dist/utils/v3-agent-client.d.ts +40 -0
- package/dist/utils/v3-agent-client.js +165 -0
- package/dist/utils/v3-workspace-service.d.ts +28 -0
- package/dist/utils/v3-workspace-service.js +279 -0
- package/dist/utils/vigflow-client.d.ts +95 -0
- package/dist/utils/vigflow-client.js +105 -0
- package/dist/utils/workspace-boundary.d.ts +45 -0
- package/dist/utils/workspace-boundary.js +377 -0
- package/dist/utils/workspace-brain-service.d.ts +2 -0
- package/dist/utils/workspace-brain-service.js +11 -1
- package/dist/utils/workspace-cache.js +37 -15
- package/dist/utils/workspace-stream.js +35 -10
- package/install.ps1 +85 -142
- package/install.sh +75 -80
- package/package.json +43 -9
- package/release-policy.json +43 -0
- package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +1 -1
- package/scripts/release/generate-completions.mjs +24 -0
- package/scripts/release/install-release.mjs +10 -0
- package/scripts/release/publish-cli-release.mjs +116 -0
- package/scripts/release/publish-cli-release.sh +2 -70
- package/scripts/release/resolve-release-manifest.mjs +26 -0
- package/scripts/release/test-balanced-model-live.sh +42 -0
- package/scripts/release/validate-live-service-gates.sh +90 -0
- package/scripts/release/validate-no-go-gates.sh +135 -174
- package/scripts/release/verify-runtime-consistency.mjs +4 -1
- package/dist/commands/index.d.ts +0 -12
- package/dist/commands/index.js +0 -194
- package/dist/commands/update.d.ts +0 -9
- package/dist/commands/update.js +0 -301
- package/dist/utils/templateInstantPath.d.ts +0 -18
- package/dist/utils/templateInstantPath.js +0 -228
package/dist/commands/device.js
CHANGED
|
@@ -5,12 +5,11 @@ import * as path from 'path';
|
|
|
5
5
|
import { execFile, spawn } from 'child_process';
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
import { CH } from '../utils/logger.js';
|
|
8
|
+
import { safeChildProcessEnv } from '../utils/secret-policy.js';
|
|
9
|
+
import { CliCommandError, formatSuccessJson } from '../utils/command-contract.js';
|
|
8
10
|
const execFileAsync = promisify(execFile);
|
|
9
11
|
export class DeviceCommand {
|
|
10
|
-
|
|
11
|
-
constructor(_config, logger) {
|
|
12
|
-
this.logger = logger;
|
|
13
|
-
}
|
|
12
|
+
constructor(_config, _logger) { }
|
|
14
13
|
async status(options = {}) {
|
|
15
14
|
const adbPath = this.findAdbPath();
|
|
16
15
|
const devices = adbPath ? await this.getDevices(adbPath) : [];
|
|
@@ -21,7 +20,7 @@ export class DeviceCommand {
|
|
|
21
20
|
devices,
|
|
22
21
|
};
|
|
23
22
|
if (options.json) {
|
|
24
|
-
console.log(
|
|
23
|
+
console.log(formatSuccessJson('device status', payload));
|
|
25
24
|
return;
|
|
26
25
|
}
|
|
27
26
|
console.log();
|
|
@@ -49,7 +48,7 @@ export class DeviceCommand {
|
|
|
49
48
|
const adbPath = this.requireAdbPath();
|
|
50
49
|
const devices = await this.getDevices(adbPath);
|
|
51
50
|
if (options.json) {
|
|
52
|
-
console.log(
|
|
51
|
+
console.log(formatSuccessJson('device list', { devices }));
|
|
53
52
|
return;
|
|
54
53
|
}
|
|
55
54
|
if (devices.length === 0) {
|
|
@@ -65,7 +64,7 @@ export class DeviceCommand {
|
|
|
65
64
|
const deviceId = await this.resolveDeviceId(adbPath, options.device);
|
|
66
65
|
const output = path.resolve(options.output || `vigthoria-android-screenshot-${this.timestamp()}.png`);
|
|
67
66
|
const args = this.withDevice(deviceId, ['exec-out', 'screencap', '-p']);
|
|
68
|
-
const result = await execFileAsync(adbPath, args, { encoding: 'buffer', maxBuffer: 20 * 1024 * 1024 });
|
|
67
|
+
const result = await execFileAsync(adbPath, args, { encoding: 'buffer', maxBuffer: 20 * 1024 * 1024, env: safeChildProcessEnv() });
|
|
69
68
|
fs.writeFileSync(output, result.stdout);
|
|
70
69
|
console.log(chalk.green(`Saved screenshot: ${output}`));
|
|
71
70
|
}
|
|
@@ -78,7 +77,7 @@ export class DeviceCommand {
|
|
|
78
77
|
const adbPath = this.requireAdbPath();
|
|
79
78
|
const deviceId = await this.resolveDeviceId(adbPath, options.device);
|
|
80
79
|
const result = await this.runAdb(adbPath, this.withDevice(deviceId, ['install', '-r', resolvedApk]), 120000);
|
|
81
|
-
this.printResult(result, options.json);
|
|
80
|
+
this.printResult('device install', result, options.json);
|
|
82
81
|
}
|
|
83
82
|
async launch(packageName, options = {}) {
|
|
84
83
|
if (!packageName)
|
|
@@ -89,7 +88,7 @@ export class DeviceCommand {
|
|
|
89
88
|
? ['shell', 'am', 'start', '-n', `${packageName}/${options.activity}`]
|
|
90
89
|
: ['shell', 'monkey', '-p', packageName, '-c', 'android.intent.category.LAUNCHER', '1'];
|
|
91
90
|
const result = await this.runAdb(adbPath, this.withDevice(deviceId, args));
|
|
92
|
-
this.printResult(result, options.json);
|
|
91
|
+
this.printResult('device launch', result, options.json);
|
|
93
92
|
}
|
|
94
93
|
async logs(options = {}) {
|
|
95
94
|
const adbPath = this.requireAdbPath();
|
|
@@ -98,10 +97,23 @@ export class DeviceCommand {
|
|
|
98
97
|
const args = this.withDevice(deviceId, options.follow ? ['logcat'] : ['logcat', '-d', '-t', lines]);
|
|
99
98
|
if (options.follow) {
|
|
100
99
|
await new Promise((resolve, reject) => {
|
|
101
|
-
const child = spawn(adbPath, args, { stdio: 'inherit' });
|
|
102
|
-
|
|
100
|
+
const child = spawn(adbPath, args, { stdio: 'inherit', env: safeChildProcessEnv() });
|
|
101
|
+
let interrupted = false;
|
|
102
|
+
const onInterrupt = () => {
|
|
103
|
+
interrupted = true;
|
|
104
|
+
child.kill('SIGINT');
|
|
105
|
+
};
|
|
106
|
+
process.once('SIGINT', onInterrupt);
|
|
107
|
+
const finish = () => process.removeListener('SIGINT', onInterrupt);
|
|
108
|
+
child.on('error', (error) => {
|
|
109
|
+
finish();
|
|
110
|
+
reject(error);
|
|
111
|
+
});
|
|
103
112
|
child.on('exit', (code) => {
|
|
104
|
-
|
|
113
|
+
finish();
|
|
114
|
+
if (interrupted)
|
|
115
|
+
reject(new CliCommandError('Device log stream cancelled by user.', { code: 'DEVICE_LOGS_CANCELLED', category: 'cancelled' }));
|
|
116
|
+
else if (code && code !== 0)
|
|
105
117
|
reject(new Error(`adb logcat exited with code ${code}`));
|
|
106
118
|
else
|
|
107
119
|
resolve();
|
|
@@ -110,26 +122,26 @@ export class DeviceCommand {
|
|
|
110
122
|
return;
|
|
111
123
|
}
|
|
112
124
|
const result = await this.runAdb(adbPath, args, 30000, 8 * 1024 * 1024);
|
|
113
|
-
this.printResult(result, options.json);
|
|
125
|
+
this.printResult('device logs', result, options.json);
|
|
114
126
|
}
|
|
115
127
|
async tcpip(options = {}) {
|
|
116
128
|
const adbPath = this.requireAdbPath();
|
|
117
129
|
const deviceId = await this.resolveDeviceId(adbPath, options.device);
|
|
118
130
|
const port = String(options.port || '5555');
|
|
119
131
|
const result = await this.runAdb(adbPath, this.withDevice(deviceId, ['tcpip', port]));
|
|
120
|
-
this.printResult(result, options.json);
|
|
132
|
+
this.printResult('device tcpip', result, options.json);
|
|
121
133
|
}
|
|
122
134
|
async connect(address, options = {}) {
|
|
123
135
|
if (!address)
|
|
124
136
|
throw new Error('Device address is required, for example 192.168.1.30:5555.');
|
|
125
137
|
const adbPath = this.requireAdbPath();
|
|
126
138
|
const result = await this.runAdb(adbPath, ['connect', address]);
|
|
127
|
-
this.printResult(result, options.json);
|
|
139
|
+
this.printResult('device connect', result, options.json);
|
|
128
140
|
}
|
|
129
141
|
async disconnect(address, options = {}) {
|
|
130
142
|
const adbPath = this.requireAdbPath();
|
|
131
143
|
const result = await this.runAdb(adbPath, address ? ['disconnect', address] : ['disconnect']);
|
|
132
|
-
this.printResult(result, options.json);
|
|
144
|
+
this.printResult('device disconnect', result, options.json);
|
|
133
145
|
}
|
|
134
146
|
async getDevices(adbPath) {
|
|
135
147
|
const result = await this.runAdb(adbPath, ['devices', '-l']);
|
|
@@ -176,7 +188,7 @@ export class DeviceCommand {
|
|
|
176
188
|
}
|
|
177
189
|
async runAdb(adbPath, args, timeout = 30000, maxBuffer = 1024 * 1024) {
|
|
178
190
|
try {
|
|
179
|
-
const result = await execFileAsync(adbPath, args, { timeout, maxBuffer });
|
|
191
|
+
const result = await execFileAsync(adbPath, args, { timeout, maxBuffer, env: safeChildProcessEnv() });
|
|
180
192
|
return { success: true, stdout: String(result.stdout || '').trim(), stderr: String(result.stderr || '').trim() };
|
|
181
193
|
}
|
|
182
194
|
catch (error) {
|
|
@@ -188,17 +200,21 @@ export class DeviceCommand {
|
|
|
188
200
|
};
|
|
189
201
|
}
|
|
190
202
|
}
|
|
191
|
-
printResult(result, json = false) {
|
|
203
|
+
printResult(command, result, json = false) {
|
|
204
|
+
if (!result.success) {
|
|
205
|
+
throw new CliCommandError(result.stderr || `${command} failed`, {
|
|
206
|
+
code: 'DEVICE_COMMAND_FAILED',
|
|
207
|
+
details: { command, stdout: result.stdout },
|
|
208
|
+
});
|
|
209
|
+
}
|
|
192
210
|
if (json) {
|
|
193
|
-
console.log(
|
|
211
|
+
console.log(formatSuccessJson(command, result));
|
|
194
212
|
return;
|
|
195
213
|
}
|
|
196
214
|
if (result.stdout)
|
|
197
215
|
console.log(result.stdout);
|
|
198
216
|
if (result.stderr)
|
|
199
217
|
console.error(result.success ? chalk.gray(result.stderr) : chalk.red(result.stderr));
|
|
200
|
-
if (!result.success)
|
|
201
|
-
process.exitCode = 1;
|
|
202
218
|
}
|
|
203
219
|
requireAdbPath() {
|
|
204
220
|
const adbPath = this.findAdbPath();
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { isIOSEnvironment, resolveClientOsSlug } from '../utils/clientManifest.js';
|
|
8
|
+
import { createAPIClient } from '../utils/api-client-factory.js';
|
|
9
|
+
import { sanitizeUserFacingErrorText } from '../utils/api.js';
|
|
10
|
+
import { getCliStateFile, isOfflineMode, isUpdateCheckSuppressed } from '../utils/cli-state.js';
|
|
11
|
+
import { CliCommandError, formatSuccessJson } from '../utils/command-contract.js';
|
|
12
|
+
export function registerDoctorCommand(program, config, logger, version) {
|
|
13
|
+
program
|
|
14
|
+
.command('doctor')
|
|
15
|
+
.description('Run local Vigthoria CLI diagnostics (no network calls unless --check-api)')
|
|
16
|
+
.option('--check-api', 'Also probe Vigthoria API reachability', false)
|
|
17
|
+
.option('--json', 'Emit machine-readable JSON output', false)
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const apiUrl = String(config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
|
|
20
|
+
const modelsApiUrl = String(config.get('modelsApiUrl') || 'https://api.vigthoria.io').replace(/\/$/, '');
|
|
21
|
+
const offline = isOfflineMode();
|
|
22
|
+
const updateSuppressed = isUpdateCheckSuppressed();
|
|
23
|
+
const subscription = config.get('subscription') || { plan: null, status: null, expiresAt: null };
|
|
24
|
+
const iosSandbox = isIOSEnvironment();
|
|
25
|
+
const platformSupport = iosSandbox
|
|
26
|
+
? 'experimental-mobile-terminal-sandbox'
|
|
27
|
+
: process.platform === 'darwin'
|
|
28
|
+
? 'supported-macos-desktop'
|
|
29
|
+
: process.platform === 'win32' || process.platform === 'linux'
|
|
30
|
+
? 'supported-desktop'
|
|
31
|
+
: 'unsupported';
|
|
32
|
+
const nodeMatch = process.versions.node.match(/^(\d+)\.(\d+)/);
|
|
33
|
+
const nodeCompatible = Boolean(nodeMatch && (Number(nodeMatch[1]) > 20
|
|
34
|
+
|| (Number(nodeMatch[1]) === 20 && Number(nodeMatch[2]) >= 19)));
|
|
35
|
+
const runtimeRequire = createRequire(import.meta.url);
|
|
36
|
+
const requiredRuntimePackages = ['axios', 'commander', 'inquirer', 'ws'];
|
|
37
|
+
const missingRuntimePackages = requiredRuntimePackages.filter((name) => {
|
|
38
|
+
try {
|
|
39
|
+
runtimeRequire.resolve(name);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const sessionsDir = path.join(os.homedir(), '.vigthoria', 'sessions');
|
|
47
|
+
let sessionStorageWritable = false;
|
|
48
|
+
let latestCheckpoint = null;
|
|
49
|
+
try {
|
|
50
|
+
fs.mkdirSync(sessionsDir, { recursive: true, mode: 0o700 });
|
|
51
|
+
const probePath = path.join(sessionsDir, `.doctor-${process.pid}-${Date.now()}.tmp`);
|
|
52
|
+
fs.writeFileSync(probePath, '{}', { encoding: 'utf8', mode: 0o600 });
|
|
53
|
+
fs.unlinkSync(probePath);
|
|
54
|
+
sessionStorageWritable = true;
|
|
55
|
+
const latestSessionFile = fs.readdirSync(sessionsDir)
|
|
56
|
+
.filter((name) => name.endsWith('.json') && name !== 'index.json')
|
|
57
|
+
.map((name) => ({ name, mtime: fs.statSync(path.join(sessionsDir, name)).mtimeMs }))
|
|
58
|
+
.sort((left, right) => right.mtime - left.mtime)[0]?.name;
|
|
59
|
+
if (latestSessionFile) {
|
|
60
|
+
const document = JSON.parse(fs.readFileSync(path.join(sessionsDir, latestSessionFile), 'utf8'));
|
|
61
|
+
const persisted = document?.data && typeof document.data === 'object' ? document.data : document;
|
|
62
|
+
const checkpoint = persisted?.activeAgentRun;
|
|
63
|
+
if (checkpoint && typeof checkpoint === 'object') {
|
|
64
|
+
latestCheckpoint = {
|
|
65
|
+
executionId: checkpoint.executionId || null,
|
|
66
|
+
status: checkpoint.status || null,
|
|
67
|
+
updatedAt: checkpoint.updatedAt || null,
|
|
68
|
+
resumable: ['submitted', 'running', 'failed'].includes(String(checkpoint.status || '')),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
sessionStorageWritable = false;
|
|
75
|
+
}
|
|
76
|
+
const envToken = String(process.env.VIGTHORIA_AUTH_TOKEN || process.env.VIGTHORIA_TOKEN || '').trim();
|
|
77
|
+
const configuredToken = envToken || String(config.get('authToken') || '').trim();
|
|
78
|
+
const tokenSegments = configuredToken ? configuredToken.split('.').length : 0;
|
|
79
|
+
const report = {
|
|
80
|
+
cliVersion: version,
|
|
81
|
+
nodeVersion: process.version,
|
|
82
|
+
nodeCompatible,
|
|
83
|
+
runtimeDependencies: missingRuntimePackages.length === 0 ? 'complete' : `missing: ${missingRuntimePackages.join(', ')}`,
|
|
84
|
+
platform: `${process.platform} ${process.arch}`,
|
|
85
|
+
clientOs: resolveClientOsSlug(),
|
|
86
|
+
platformSupport,
|
|
87
|
+
platformLimitations: iosSandbox
|
|
88
|
+
? 'Not a native iOS app. Requires an iSH-like Linux terminal with Node.js >=20.19, npm and filesystem access; Workbench and device tooling are unavailable.'
|
|
89
|
+
: null,
|
|
90
|
+
cwd: process.cwd(),
|
|
91
|
+
homeDir: os.homedir(),
|
|
92
|
+
configPath: config.getConfigPath(),
|
|
93
|
+
stateFile: getCliStateFile(),
|
|
94
|
+
apiUrl,
|
|
95
|
+
modelsApiUrl,
|
|
96
|
+
loggedIn: config.isAuthenticated(),
|
|
97
|
+
authToken: configuredToken
|
|
98
|
+
? { present: true, source: envToken ? 'environment' : 'secure-config', structure: tokenSegments === 3 ? 'jwt' : 'opaque' }
|
|
99
|
+
: { present: false, source: null, structure: null },
|
|
100
|
+
sessionPersistence: {
|
|
101
|
+
directory: sessionsDir,
|
|
102
|
+
writable: sessionStorageWritable,
|
|
103
|
+
latestCheckpoint,
|
|
104
|
+
},
|
|
105
|
+
subscriptionPlan: subscription.plan || null,
|
|
106
|
+
subscriptionStatus: subscription.status || null,
|
|
107
|
+
offlineMode: offline,
|
|
108
|
+
updateCheckSuppressed: updateSuppressed,
|
|
109
|
+
envOverrides: {
|
|
110
|
+
VIGTHORIA_API_URL: process.env.VIGTHORIA_API_URL || null,
|
|
111
|
+
VIGTHORIA_V3_AGENT_URL: process.env.VIGTHORIA_V3_AGENT_URL || null,
|
|
112
|
+
VIGTHORIA_OFFLINE: process.env.VIGTHORIA_OFFLINE || null,
|
|
113
|
+
VIGTHORIA_TOKEN: process.env.VIGTHORIA_TOKEN ? '<set>' : null,
|
|
114
|
+
HYPERLOOP_SERVICE_KEY: process.env.HYPERLOOP_SERVICE_KEY ? '<set>' : null,
|
|
115
|
+
V3_SERVICE_KEY: process.env.V3_SERVICE_KEY ? '<set>' : null,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
if (options.checkApi && !offline) {
|
|
119
|
+
const api = createAPIClient(config, logger);
|
|
120
|
+
if (configuredToken) {
|
|
121
|
+
try {
|
|
122
|
+
const tokenCheck = await api.validateToken({ allowNetworkFailOpen: false, enforceTokenShape: true });
|
|
123
|
+
report.authValidation = tokenCheck.valid ? 'authenticated' : `failed (${tokenCheck.error || 'invalid token'})`;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
report.authValidation = `unreachable (${sanitizeUserFacingErrorText(error.message)})`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
report.authValidation = 'not checked (login required)';
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const probe = await axios.get(`${apiUrl}/api/health`, { timeout: 12000, validateStatus: () => true });
|
|
134
|
+
report.apiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
report.apiHealth = `unreachable (${error.message})`;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const probe = await axios.get(`${modelsApiUrl}/health`, { timeout: 12000, validateStatus: () => true });
|
|
141
|
+
const body = typeof probe.data === 'string' ? probe.data : JSON.stringify(probe.data || {});
|
|
142
|
+
report.modelsApiHealth = probe.status >= 200 && probe.status < 400
|
|
143
|
+
? 'online'
|
|
144
|
+
: probe.status === 503 && /pre-release validation|closed/i.test(body)
|
|
145
|
+
? 'pre-release-closed (Agent mode uses the Coder gateway)'
|
|
146
|
+
: `status ${probe.status}`;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
report.modelsApiHealth = `unreachable (${error.message})`;
|
|
150
|
+
}
|
|
151
|
+
if (configuredToken) {
|
|
152
|
+
try {
|
|
153
|
+
const capabilities = await api.getCapabilityTruthStatus({ workspacePath: process.cwd() });
|
|
154
|
+
report.agentInfrastructure = {
|
|
155
|
+
overall: capabilities.overallOk ? 'online' : 'degraded',
|
|
156
|
+
v3Agent: capabilities.v3Agent.ok ? 'online' : capabilities.v3Agent.error || 'offline',
|
|
157
|
+
hyperLoop: capabilities.hyperLoop.ok ? 'online' : capabilities.hyperLoop.error || 'offline',
|
|
158
|
+
repoMemory: capabilities.repoMemory.ok ? 'online' : capabilities.repoMemory.error || 'offline',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
report.agentInfrastructure = `unreachable (${sanitizeUserFacingErrorText(error.message)})`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const printHumanReport = () => {
|
|
167
|
+
console.log(chalk.bold('Vigthoria CLI diagnostics'));
|
|
168
|
+
for (const [key, value] of Object.entries(report)) {
|
|
169
|
+
if (value && typeof value === 'object') {
|
|
170
|
+
console.log(chalk.gray(`- ${key}:`));
|
|
171
|
+
for (const [subKey, subVal] of Object.entries(value)) {
|
|
172
|
+
console.log(chalk.gray(` - ${subKey}: ${subVal ?? '(none)'}`));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(chalk.gray(`- ${key}: ${value ?? '(none)'}`));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (!options.checkApi) {
|
|
180
|
+
console.log(chalk.gray('\nTip: pass --check-api to verify API reachability.'));
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const requiredLocalChecksPassed = nodeCompatible && missingRuntimePackages.length === 0 && sessionStorageWritable;
|
|
184
|
+
const coderReachable = !options.checkApi || offline || report.apiHealth === 'online';
|
|
185
|
+
if (!requiredLocalChecksPassed || !coderReachable) {
|
|
186
|
+
if (!options.json)
|
|
187
|
+
printHumanReport();
|
|
188
|
+
throw new CliCommandError('One or more required doctor checks failed.', {
|
|
189
|
+
code: 'DOCTOR_CHECK_FAILED',
|
|
190
|
+
details: report,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (options.json) {
|
|
194
|
+
console.log(formatSuccessJson('doctor', report));
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
printHumanReport();
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
package/dist/commands/edit.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import { createSpinner } from '../utils/logger.js';
|
|
7
|
-
import {
|
|
7
|
+
import { createAPIClient } from '../utils/api-client-factory.js';
|
|
8
8
|
import { FileUtils } from '../utils/files.js';
|
|
9
|
+
import { CliCommandError, commandFailure } from '../utils/command-contract.js';
|
|
9
10
|
export class EditCommand {
|
|
10
11
|
config;
|
|
11
12
|
logger;
|
|
@@ -14,26 +15,23 @@ export class EditCommand {
|
|
|
14
15
|
constructor(config, logger) {
|
|
15
16
|
this.config = config;
|
|
16
17
|
this.logger = logger;
|
|
17
|
-
this.api =
|
|
18
|
+
this.api = createAPIClient(config, logger);
|
|
18
19
|
this.fileUtils = new FileUtils(process.cwd(), config.get('project').ignorePatterns);
|
|
19
20
|
}
|
|
20
21
|
async run(filePath, options) {
|
|
21
22
|
// Check auth
|
|
22
23
|
if (!this.config.isAuthenticated()) {
|
|
23
|
-
|
|
24
|
-
return;
|
|
24
|
+
throw new CliCommandError('Not authenticated. Run: vigthoria login', { code: 'AUTH_REQUIRED', category: 'authentication' });
|
|
25
25
|
}
|
|
26
26
|
// Server-side token validation — fail fast instead of waiting for 401
|
|
27
27
|
const tokenCheck = await this.api.validateToken();
|
|
28
28
|
if (!tokenCheck.valid) {
|
|
29
|
-
|
|
30
|
-
return;
|
|
29
|
+
throw new CliCommandError(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login', { code: 'AUTH_SESSION_INVALID', category: 'authentication' });
|
|
31
30
|
}
|
|
32
31
|
// Read file
|
|
33
32
|
const file = this.fileUtils.readFile(filePath);
|
|
34
33
|
if (!file) {
|
|
35
|
-
|
|
36
|
-
return;
|
|
34
|
+
throw new CliCommandError(`File not found: ${filePath}`, { code: 'FILE_NOT_FOUND', category: 'configuration' });
|
|
37
35
|
}
|
|
38
36
|
this.logger.section(`Editing: ${file.relativePath}`);
|
|
39
37
|
console.log(chalk.gray(`Language: ${file.language} | Lines: ${file.lines}`));
|
|
@@ -43,13 +41,11 @@ export class EditCommand {
|
|
|
43
41
|
if (!instruction) {
|
|
44
42
|
// --apply requires --instruction to avoid hanging on non-interactive terminals
|
|
45
43
|
if (options.apply) {
|
|
46
|
-
|
|
47
|
-
return;
|
|
44
|
+
throw new CliCommandError('The --apply flag requires --instruction. Example: vigthoria edit file.ts --apply --instruction "fix the bug"', { code: 'INVALID_OPTION_COMBINATION', category: 'usage' });
|
|
48
45
|
}
|
|
49
46
|
// Non-TTY stdin cannot prompt interactively
|
|
50
47
|
if (!process.stdin.isTTY) {
|
|
51
|
-
|
|
52
|
-
return;
|
|
48
|
+
throw new CliCommandError('No --instruction provided and stdin is not interactive. Use: vigthoria edit file.ts --instruction "..."', { code: 'INSTRUCTION_REQUIRED', category: 'usage' });
|
|
53
49
|
}
|
|
54
50
|
const answer = await inquirer.prompt([
|
|
55
51
|
{
|
|
@@ -100,15 +96,14 @@ Return the complete modified file content:`,
|
|
|
100
96
|
// Extract code from response
|
|
101
97
|
let modifiedCode = this.extractCode(response.message, file.language);
|
|
102
98
|
if (!modifiedCode) {
|
|
103
|
-
|
|
104
|
-
return;
|
|
99
|
+
throw new CliCommandError('Failed to generate valid code changes', { code: 'EDIT_RESPONSE_INVALID' });
|
|
105
100
|
}
|
|
106
101
|
// Always deduplicate — extractCode only dedupes on the no-fence
|
|
107
102
|
// fallback path, so fenced responses (the common case) need this.
|
|
108
103
|
modifiedCode = this.deduplicateCode(modifiedCode);
|
|
109
104
|
// Show diff and apply
|
|
110
105
|
if (options.apply) {
|
|
111
|
-
await this.applyFix(file.path,
|
|
106
|
+
await this.applyFix(file.path, modifiedCode);
|
|
112
107
|
}
|
|
113
108
|
else {
|
|
114
109
|
await this.showDiffAndConfirm(file.path, file.content, modifiedCode);
|
|
@@ -116,27 +111,23 @@ Return the complete modified file content:`,
|
|
|
116
111
|
}
|
|
117
112
|
catch (error) {
|
|
118
113
|
spinner.stop();
|
|
119
|
-
|
|
120
|
-
this.logger.error(formatCLIError(cliErr));
|
|
114
|
+
throw commandFailure(error, { code: 'EDIT_FAILED' });
|
|
121
115
|
}
|
|
122
116
|
}
|
|
123
117
|
async fix(filePath, options) {
|
|
124
118
|
// Check auth
|
|
125
119
|
if (!this.config.isAuthenticated()) {
|
|
126
|
-
|
|
127
|
-
return;
|
|
120
|
+
throw new CliCommandError('Not authenticated. Run: vigthoria login', { code: 'AUTH_REQUIRED', category: 'authentication' });
|
|
128
121
|
}
|
|
129
122
|
// Server-side token validation — fail fast instead of waiting for 401
|
|
130
123
|
const tokenCheck = await this.api.validateToken();
|
|
131
124
|
if (!tokenCheck.valid) {
|
|
132
|
-
|
|
133
|
-
return;
|
|
125
|
+
throw new CliCommandError(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login', { code: 'AUTH_SESSION_INVALID', category: 'authentication' });
|
|
134
126
|
}
|
|
135
127
|
// Read file
|
|
136
128
|
const file = this.fileUtils.readFile(filePath);
|
|
137
129
|
if (!file) {
|
|
138
|
-
|
|
139
|
-
return;
|
|
130
|
+
throw new CliCommandError(`File not found: ${filePath}`, { code: 'FILE_NOT_FOUND', category: 'configuration' });
|
|
140
131
|
}
|
|
141
132
|
this.logger.section(`Fixing: ${file.relativePath}`);
|
|
142
133
|
console.log(chalk.gray(`Fix type: ${options.type} | Language: ${file.language}`));
|
|
@@ -159,7 +150,7 @@ Return the complete modified file content:`,
|
|
|
159
150
|
console.log(chalk.yellow('1. Operator/character-level fix detected'));
|
|
160
151
|
console.log();
|
|
161
152
|
if (options.apply) {
|
|
162
|
-
await this.applyFix(file.path,
|
|
153
|
+
await this.applyFix(file.path, result.fixed);
|
|
163
154
|
}
|
|
164
155
|
else {
|
|
165
156
|
await this.showDiffAndConfirm(file.path, file.content, result.fixed);
|
|
@@ -180,7 +171,7 @@ Return the complete modified file content:`,
|
|
|
180
171
|
});
|
|
181
172
|
// Apply or confirm
|
|
182
173
|
if (options.apply) {
|
|
183
|
-
await this.applyFix(file.path,
|
|
174
|
+
await this.applyFix(file.path, result.fixed);
|
|
184
175
|
}
|
|
185
176
|
else {
|
|
186
177
|
await this.showDiffAndConfirm(file.path, file.content, result.fixed);
|
|
@@ -188,8 +179,7 @@ Return the complete modified file content:`,
|
|
|
188
179
|
}
|
|
189
180
|
catch (error) {
|
|
190
181
|
spinner.stop();
|
|
191
|
-
|
|
192
|
-
this.logger.error(formatCLIError(cliErr));
|
|
182
|
+
throw commandFailure(error, { code: 'FIX_FAILED' });
|
|
193
183
|
}
|
|
194
184
|
}
|
|
195
185
|
extractCode(response, language) {
|
|
@@ -359,10 +349,9 @@ Return the complete modified file content:`,
|
|
|
359
349
|
});
|
|
360
350
|
console.log();
|
|
361
351
|
// Confirm
|
|
362
|
-
const showDiffs = this.config.get('preferences').showDiffs;
|
|
363
352
|
const autoApply = this.config.get('preferences').autoApplyFixes;
|
|
364
353
|
if (autoApply) {
|
|
365
|
-
await this.applyFix(filePath,
|
|
354
|
+
await this.applyFix(filePath, modified);
|
|
366
355
|
return;
|
|
367
356
|
}
|
|
368
357
|
// Non-TTY: show the diff but don't try to prompt — re-run with --apply
|
|
@@ -384,7 +373,7 @@ Return the complete modified file content:`,
|
|
|
384
373
|
]);
|
|
385
374
|
switch (action) {
|
|
386
375
|
case 'apply':
|
|
387
|
-
await this.applyFix(filePath,
|
|
376
|
+
await this.applyFix(filePath, modified);
|
|
388
377
|
break;
|
|
389
378
|
case 'view':
|
|
390
379
|
this.showFullDiff(original, modified);
|
|
@@ -397,7 +386,7 @@ Return the complete modified file content:`,
|
|
|
397
386
|
},
|
|
398
387
|
]);
|
|
399
388
|
if (confirm) {
|
|
400
|
-
await this.applyFix(filePath,
|
|
389
|
+
await this.applyFix(filePath, modified);
|
|
401
390
|
}
|
|
402
391
|
break;
|
|
403
392
|
case 'discard':
|
|
@@ -463,7 +452,7 @@ Return the complete modified file content:`,
|
|
|
463
452
|
console.log(chalk.gray('─'.repeat(60)));
|
|
464
453
|
console.log();
|
|
465
454
|
}
|
|
466
|
-
async applyFix(filePath,
|
|
455
|
+
async applyFix(filePath, modified) {
|
|
467
456
|
// Create backup
|
|
468
457
|
const backup = this.fileUtils.backupFile(filePath);
|
|
469
458
|
if (backup) {
|
|
@@ -474,7 +463,7 @@ Return the complete modified file content:`,
|
|
|
474
463
|
this.logger.success(`Changes applied to ${filePath}`);
|
|
475
464
|
}
|
|
476
465
|
else {
|
|
477
|
-
|
|
466
|
+
throw new CliCommandError(`Failed to write changes to ${filePath}`, { code: 'FILE_WRITE_FAILED' });
|
|
478
467
|
}
|
|
479
468
|
}
|
|
480
469
|
}
|
package/dist/commands/explain.js
CHANGED
|
@@ -5,8 +5,9 @@ import chalk from 'chalk';
|
|
|
5
5
|
import { Marked } from 'marked';
|
|
6
6
|
import { markedTerminal } from 'marked-terminal';
|
|
7
7
|
import { createSpinner } from '../utils/logger.js';
|
|
8
|
-
import {
|
|
8
|
+
import { createAPIClient } from '../utils/api-client-factory.js';
|
|
9
9
|
import { FileUtils } from '../utils/files.js';
|
|
10
|
+
import { CliCommandError, commandFailure } from '../utils/command-contract.js';
|
|
10
11
|
export class ExplainCommand {
|
|
11
12
|
config;
|
|
12
13
|
logger;
|
|
@@ -16,7 +17,7 @@ export class ExplainCommand {
|
|
|
16
17
|
constructor(config, logger) {
|
|
17
18
|
this.config = config;
|
|
18
19
|
this.logger = logger;
|
|
19
|
-
this.api =
|
|
20
|
+
this.api = createAPIClient(config, logger);
|
|
20
21
|
this.fileUtils = new FileUtils(process.cwd(), config.get('project').ignorePatterns);
|
|
21
22
|
this.marked = new Marked();
|
|
22
23
|
this.marked.use(markedTerminal({
|
|
@@ -29,20 +30,17 @@ export class ExplainCommand {
|
|
|
29
30
|
async run(filePath, options) {
|
|
30
31
|
// Check auth
|
|
31
32
|
if (!this.config.isAuthenticated()) {
|
|
32
|
-
|
|
33
|
-
return;
|
|
33
|
+
throw new CliCommandError('Not authenticated. Run: vigthoria login', { code: 'AUTH_REQUIRED', category: 'authentication' });
|
|
34
34
|
}
|
|
35
35
|
// Server-side token validation — fail fast instead of waiting for 401
|
|
36
36
|
const tokenCheck = await this.api.validateToken();
|
|
37
37
|
if (!tokenCheck.valid) {
|
|
38
|
-
|
|
39
|
-
return;
|
|
38
|
+
throw new CliCommandError(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login', { code: 'AUTH_SESSION_INVALID', category: 'authentication' });
|
|
40
39
|
}
|
|
41
40
|
// Read file
|
|
42
41
|
const file = this.fileUtils.readFile(filePath);
|
|
43
42
|
if (!file) {
|
|
44
|
-
|
|
45
|
-
return;
|
|
43
|
+
throw new CliCommandError(`File not found: ${filePath}`, { code: 'FILE_NOT_FOUND', category: 'configuration' });
|
|
46
44
|
}
|
|
47
45
|
// Get code to explain
|
|
48
46
|
let codeToExplain = file.content;
|
|
@@ -80,8 +78,7 @@ export class ExplainCommand {
|
|
|
80
78
|
}
|
|
81
79
|
catch (error) {
|
|
82
80
|
spinner.stop();
|
|
83
|
-
|
|
84
|
-
this.logger.error(formatCLIError(cliErr));
|
|
81
|
+
throw commandFailure(error, { code: 'EXPLAIN_FAILED' });
|
|
85
82
|
}
|
|
86
83
|
}
|
|
87
84
|
/**
|
package/dist/commands/fork.d.ts
CHANGED
|
@@ -7,8 +7,7 @@ interface ForkOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export declare class ForkCommand {
|
|
9
9
|
private config;
|
|
10
|
-
|
|
11
|
-
constructor(config: Config, logger: Logger);
|
|
10
|
+
constructor(config: Config, _logger: Logger);
|
|
12
11
|
private getHeaders;
|
|
13
12
|
private getBaseUrl;
|
|
14
13
|
private resolveWorkspaceRoot;
|