vigthoria-cli 1.13.11 → 1.13.13
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/legion.d.ts +3 -2
- package/dist/commands/legion.js +18 -5
- package/dist/utils/fastAgentRouter.js +75 -22
- package/dist/utils/localTestMode.js +3 -3
- package/install.ps1 +36 -36
- package/install.sh +44 -11
- package/package.json +1 -1
|
@@ -57,8 +57,9 @@ export declare class LegionCommand {
|
|
|
57
57
|
private confirmExecution;
|
|
58
58
|
/**
|
|
59
59
|
* SSE streaming URL for the Legion execution endpoint.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
60
|
+
* Server installs use the loopback service credential. User installations
|
|
61
|
+
* must use the authenticated Coder gateway; localhost:8020 on a customer's
|
|
62
|
+
* machine is not Vigthoria infrastructure.
|
|
62
63
|
*/
|
|
63
64
|
private getLegionStreamUrl;
|
|
64
65
|
private getLegionServiceKey;
|
package/dist/commands/legion.js
CHANGED
|
@@ -1077,14 +1077,27 @@ export class LegionCommand {
|
|
|
1077
1077
|
}
|
|
1078
1078
|
/**
|
|
1079
1079
|
* SSE streaming URL for the Legion execution endpoint.
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1080
|
+
* Server installs use the loopback service credential. User installations
|
|
1081
|
+
* must use the authenticated Coder gateway; localhost:8020 on a customer's
|
|
1082
|
+
* machine is not Vigthoria infrastructure.
|
|
1082
1083
|
*/
|
|
1083
1084
|
getLegionStreamUrl() {
|
|
1084
|
-
const
|
|
1085
|
+
const normalizeBase = (raw) => {
|
|
1086
|
+
let base = raw.trim().replace(/\/$/, '');
|
|
1087
|
+
base = base.replace(/\/api\/hyperloop\/(?:health|modules|execute)$/i, '/api/hyperloop');
|
|
1088
|
+
if (!/\/api\/hyperloop$/i.test(base)) {
|
|
1089
|
+
base += '/api/hyperloop';
|
|
1090
|
+
}
|
|
1091
|
+
return base;
|
|
1092
|
+
};
|
|
1093
|
+
const envOverride = String(process.env.VIGTHORIA_HYPERLOOP_URL || '').trim();
|
|
1085
1094
|
if (envOverride)
|
|
1086
|
-
return `${envOverride}/legion/stream`;
|
|
1087
|
-
|
|
1095
|
+
return `${normalizeBase(envOverride)}/legion/stream`;
|
|
1096
|
+
if (isServerRuntime()) {
|
|
1097
|
+
return 'http://localhost:8020/api/hyperloop/legion/stream';
|
|
1098
|
+
}
|
|
1099
|
+
const configuredApiUrl = String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').trim();
|
|
1100
|
+
return `${normalizeBase(configuredApiUrl)}/legion/stream`;
|
|
1088
1101
|
}
|
|
1089
1102
|
getLegionServiceKey() {
|
|
1090
1103
|
// Service key lets on-server CLI calls bypass gateway JWT validation
|
|
@@ -74,41 +74,93 @@ export function getInferenceRouterBaseUrls(selfHostedUrl) {
|
|
|
74
74
|
return [...new Set(urls)];
|
|
75
75
|
}
|
|
76
76
|
let inferenceHealthCache = null;
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
return
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
function modelIdsFromPayload(payload) {
|
|
78
|
+
if (!payload || typeof payload !== 'object')
|
|
79
|
+
return [];
|
|
80
|
+
const body = payload;
|
|
81
|
+
const values = [
|
|
82
|
+
body.available_models,
|
|
83
|
+
body.loaded_models,
|
|
84
|
+
body.models,
|
|
85
|
+
body.data,
|
|
86
|
+
].filter(Array.isArray).flat();
|
|
87
|
+
return values.map((entry) => {
|
|
88
|
+
if (typeof entry === 'string')
|
|
89
|
+
return entry;
|
|
90
|
+
if (entry && typeof entry === 'object') {
|
|
91
|
+
const model = entry;
|
|
92
|
+
return String(model.id || model.model || model.name || '');
|
|
93
|
+
}
|
|
94
|
+
return '';
|
|
95
|
+
}).filter(Boolean);
|
|
96
|
+
}
|
|
97
|
+
function includesBalancedRouterModel(modelIds) {
|
|
98
|
+
const allowed = new Set(INFERENCE_MODEL_IDS);
|
|
99
|
+
return modelIds.some((id) => allowed.has(String(id).trim().toLowerCase().replace(/:latest$/, '')));
|
|
100
|
+
}
|
|
101
|
+
async function probeBalancedRouterBase(base, timeoutMs) {
|
|
102
|
+
const fetchJson = async (path) => {
|
|
86
103
|
const controller = new AbortController();
|
|
87
104
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
88
105
|
try {
|
|
89
|
-
const response = await fetch(`${base}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
inferenceHealthCache = { ok: true, checkedAt: now };
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
106
|
+
const response = await fetch(`${base}${path}`, { signal: controller.signal });
|
|
107
|
+
const payload = await response.json().catch(() => null);
|
|
108
|
+
return { ok: response.ok, payload };
|
|
95
109
|
}
|
|
96
110
|
catch {
|
|
111
|
+
return { ok: false, payload: null };
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
97
114
|
clearTimeout(timer);
|
|
98
115
|
}
|
|
116
|
+
};
|
|
117
|
+
const health = await fetchJson('/health');
|
|
118
|
+
if (!health.ok)
|
|
119
|
+
return false;
|
|
120
|
+
const advertisedByHealth = modelIdsFromPayload(health.payload);
|
|
121
|
+
if (advertisedByHealth.length > 0) {
|
|
122
|
+
return includesBalancedRouterModel(advertisedByHealth);
|
|
123
|
+
}
|
|
124
|
+
// Older inference nodes only expose capabilities on /v1/models.
|
|
125
|
+
const catalog = await fetchJson('/v1/models');
|
|
126
|
+
return catalog.ok && includesBalancedRouterModel(modelIdsFromPayload(catalog.payload));
|
|
127
|
+
}
|
|
128
|
+
async function compatibleInferenceRouterBases(selfHostedUrl, timeoutMs) {
|
|
129
|
+
const bases = getInferenceRouterBaseUrls(selfHostedUrl);
|
|
130
|
+
const key = bases.join('|');
|
|
131
|
+
const now = Date.now();
|
|
132
|
+
if (inferenceHealthCache
|
|
133
|
+
&& inferenceHealthCache.key === key
|
|
134
|
+
&& now - inferenceHealthCache.checkedAt < 60_000) {
|
|
135
|
+
return inferenceHealthCache.compatibleBases;
|
|
136
|
+
}
|
|
137
|
+
const compatibleBases = [];
|
|
138
|
+
for (const base of bases) {
|
|
139
|
+
if (await probeBalancedRouterBase(base, timeoutMs)) {
|
|
140
|
+
compatibleBases.push(base);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
inferenceHealthCache = { key, compatibleBases, checkedAt: now };
|
|
144
|
+
return compatibleBases;
|
|
145
|
+
}
|
|
146
|
+
export async function isFastInferenceRouterAvailable(selfHostedUrl, timeoutMs = 400) {
|
|
147
|
+
if (process.env.VIGTHORIA_AGENT_LLM_ROUTER === '0') {
|
|
148
|
+
return false;
|
|
99
149
|
}
|
|
100
|
-
|
|
101
|
-
return false;
|
|
150
|
+
return (await compatibleInferenceRouterBases(selfHostedUrl, timeoutMs)).length > 0;
|
|
102
151
|
}
|
|
103
152
|
export async function routeWithBalanced4b(prompt, selfHostedUrl, options = {}) {
|
|
104
153
|
const timeoutMs = options.timeoutMs ?? Number.parseInt(process.env.VIGTHORIA_AGENT_ROUTER_TIMEOUT_MS || '8000', 10);
|
|
105
|
-
const bases =
|
|
154
|
+
const bases = await compatibleInferenceRouterBases(selfHostedUrl, Math.min(timeoutMs, 1500));
|
|
106
155
|
let lastError = 'Inference router unreachable';
|
|
156
|
+
if (bases.length === 0) {
|
|
157
|
+
return { ok: false, error: 'No compatible Balanced 4B inference endpoint is available' };
|
|
158
|
+
}
|
|
107
159
|
for (const base of bases) {
|
|
108
|
-
const controller = new AbortController();
|
|
109
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
110
160
|
const started = Date.now();
|
|
111
161
|
for (const model of INFERENCE_MODEL_IDS) {
|
|
162
|
+
const controller = new AbortController();
|
|
163
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
112
164
|
try {
|
|
113
165
|
const response = await fetch(`${base}/v1/chat/completions`, {
|
|
114
166
|
method: 'POST',
|
|
@@ -125,7 +177,6 @@ export async function routeWithBalanced4b(prompt, selfHostedUrl, options = {}) {
|
|
|
125
177
|
}),
|
|
126
178
|
signal: controller.signal,
|
|
127
179
|
});
|
|
128
|
-
clearTimeout(timer);
|
|
129
180
|
const payload = await response.json().catch(() => null);
|
|
130
181
|
if (!response.ok) {
|
|
131
182
|
lastError = `HTTP ${response.status} from ${base}`;
|
|
@@ -149,8 +200,10 @@ export async function routeWithBalanced4b(prompt, selfHostedUrl, options = {}) {
|
|
|
149
200
|
catch (err) {
|
|
150
201
|
lastError = err instanceof Error ? err.message : String(err);
|
|
151
202
|
}
|
|
203
|
+
finally {
|
|
204
|
+
clearTimeout(timer);
|
|
205
|
+
}
|
|
152
206
|
}
|
|
153
|
-
clearTimeout(timer);
|
|
154
207
|
}
|
|
155
208
|
return { ok: false, error: lastError };
|
|
156
209
|
}
|
|
@@ -17,9 +17,9 @@ export function applyLocalTestfarmDefaults() {
|
|
|
17
17
|
process.env.VIGTHORIA_ALLOW_LOCAL_SERVICES ??= '1';
|
|
18
18
|
process.env.VIGTHORIA_ALLOW_LOCAL_V3_AGENT ??= '1';
|
|
19
19
|
process.env.VIGTHORIA_SELF_HOSTED_MODELS_API_URL ??= 'http://127.0.0.1:4009';
|
|
20
|
-
process.env.VIGTHORIA_HYPERLOOP_URL ??= 'http://127.0.0.1:8020';
|
|
21
|
-
process.env.VIGTHORIA_HYPERLOOP_EXECUTE_URL ??= 'http://127.0.0.1:8020/execute';
|
|
22
|
-
process.env.VIGTHORIA_HYPERLOOP_MODULES_URL ??= 'http://127.0.0.1:8020/modules';
|
|
20
|
+
process.env.VIGTHORIA_HYPERLOOP_URL ??= 'http://127.0.0.1:8020/api/hyperloop/health';
|
|
21
|
+
process.env.VIGTHORIA_HYPERLOOP_EXECUTE_URL ??= 'http://127.0.0.1:8020/api/hyperloop/execute';
|
|
22
|
+
process.env.VIGTHORIA_HYPERLOOP_MODULES_URL ??= 'http://127.0.0.1:8020/api/hyperloop/modules';
|
|
23
23
|
process.env.VIGTHORIA_V3_AGENT_URL ??= 'http://127.0.0.1:8030';
|
|
24
24
|
process.env.VIGTHORIA_TEMPLATE_SERVICE_URL ??= 'http://127.0.0.1:4011';
|
|
25
25
|
process.env.VIGTHORIA_HYPERLOOP_TIMEOUT_MS ??= '180000';
|
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.13"
|
|
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"
|
|
@@ -35,40 +35,40 @@ Resolve-ReleaseManifest
|
|
|
35
35
|
|
|
36
36
|
function Write-Banner {
|
|
37
37
|
Write-Host ""
|
|
38
|
-
Write-Host "
|
|
39
|
-
Write-Host "
|
|
40
|
-
Write-Host "
|
|
41
|
-
Write-Host "
|
|
42
|
-
Write-Host "
|
|
43
|
-
Write-Host "
|
|
38
|
+
Write-Host " +-----------------------------------------------------------+" -ForegroundColor Cyan
|
|
39
|
+
Write-Host " | |" -ForegroundColor Cyan
|
|
40
|
+
Write-Host " | VIGTHORIA CLI INSTALLER v$CLI_VERSION |" -ForegroundColor Cyan
|
|
41
|
+
Write-Host " | AI-Powered Terminal Coding Assistant |" -ForegroundColor Cyan
|
|
42
|
+
Write-Host " | |" -ForegroundColor Cyan
|
|
43
|
+
Write-Host " +-----------------------------------------------------------+" -ForegroundColor Cyan
|
|
44
44
|
Write-Host ""
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
function Test-NetworkConnectivity {
|
|
48
|
-
Write-Host "
|
|
48
|
+
Write-Host "[CHECK] Checking network connectivity..." -ForegroundColor Yellow
|
|
49
49
|
|
|
50
50
|
try {
|
|
51
51
|
$response = Invoke-WebRequest -Uri $HOSTED_TARBALL_URL -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
|
|
52
|
-
Write-Host "
|
|
52
|
+
Write-Host "[OK] Hosted CLI package is reachable" -ForegroundColor Green
|
|
53
53
|
return $true
|
|
54
54
|
}
|
|
55
55
|
catch {
|
|
56
|
-
Write-Host "
|
|
56
|
+
Write-Host "[WARN] Hosted package unavailable, checking npm registry..." -ForegroundColor Yellow
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
try {
|
|
60
60
|
$response = Invoke-WebRequest -Uri "https://registry.npmjs.org/vigthoria-cli" -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
|
|
61
|
-
Write-Host "
|
|
61
|
+
Write-Host "[OK] npm registry is reachable" -ForegroundColor Green
|
|
62
62
|
return $true
|
|
63
63
|
}
|
|
64
64
|
catch {
|
|
65
|
-
Write-Host "
|
|
65
|
+
Write-Host "[ERROR] Cannot reach hosted package or npm registry" -ForegroundColor Red
|
|
66
66
|
return $false
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function Test-Prerequisites {
|
|
71
|
-
Write-Host "
|
|
71
|
+
Write-Host "[CHECK] Checking prerequisites..." -ForegroundColor Yellow
|
|
72
72
|
|
|
73
73
|
# Check Node.js
|
|
74
74
|
try {
|
|
@@ -77,16 +77,16 @@ function Test-Prerequisites {
|
|
|
77
77
|
$versionText = $nodeVersion.TrimStart('v')
|
|
78
78
|
$parsedVersion = [version]$versionText
|
|
79
79
|
if ($parsedVersion -ge [version]"20.19.0") {
|
|
80
|
-
Write-Host "
|
|
80
|
+
Write-Host "[OK] Node.js $nodeVersion" -ForegroundColor Green
|
|
81
81
|
} else {
|
|
82
|
-
Write-Host "
|
|
82
|
+
Write-Host "[ERROR] Node.js 20.19+ required (found $nodeVersion)" -ForegroundColor Red
|
|
83
83
|
Write-Host " Download from: https://nodejs.org/" -ForegroundColor Yellow
|
|
84
84
|
return $false
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
catch {
|
|
89
|
-
Write-Host "
|
|
89
|
+
Write-Host "[ERROR] Node.js is not installed" -ForegroundColor Red
|
|
90
90
|
Write-Host ""
|
|
91
91
|
Write-Host "Please install Node.js first:" -ForegroundColor Yellow
|
|
92
92
|
Write-Host " Option 1: winget install OpenJS.NodeJS" -ForegroundColor White
|
|
@@ -99,11 +99,11 @@ function Test-Prerequisites {
|
|
|
99
99
|
try {
|
|
100
100
|
$npmVersion = npm -v 2>$null
|
|
101
101
|
if ($npmVersion) {
|
|
102
|
-
Write-Host "
|
|
102
|
+
Write-Host "[OK] npm v$npmVersion" -ForegroundColor Green
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
catch {
|
|
106
|
-
Write-Host "
|
|
106
|
+
Write-Host "[ERROR] npm is not installed" -ForegroundColor Red
|
|
107
107
|
return $false
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -112,40 +112,40 @@ function Test-Prerequisites {
|
|
|
112
112
|
|
|
113
113
|
function Install-VigthoriaCLI-NPM {
|
|
114
114
|
Write-Host ""
|
|
115
|
-
Write-Host "
|
|
115
|
+
Write-Host "[INSTALL] Installing Vigthoria CLI..." -ForegroundColor Cyan
|
|
116
116
|
|
|
117
117
|
try {
|
|
118
118
|
npm install -g $HOSTED_TARBALL_URL
|
|
119
|
-
Write-Host "
|
|
119
|
+
Write-Host "[OK] Vigthoria CLI installed successfully!" -ForegroundColor Green
|
|
120
120
|
return $true
|
|
121
121
|
}
|
|
122
122
|
catch {
|
|
123
|
-
Write-Host "
|
|
123
|
+
Write-Host "[WARN] Hosted package install failed, trying npm registry..." -ForegroundColor Yellow
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
try {
|
|
127
127
|
npm install -g vigthoria-cli
|
|
128
|
-
Write-Host "
|
|
128
|
+
Write-Host "[OK] Vigthoria CLI installed successfully!" -ForegroundColor Green
|
|
129
129
|
return $true
|
|
130
130
|
}
|
|
131
131
|
catch {
|
|
132
|
-
Write-Host "
|
|
132
|
+
Write-Host "[WARN] npm registry install failed, trying git package..." -ForegroundColor Yellow
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
try {
|
|
136
136
|
npm install -g $GIT_PACKAGE_URL
|
|
137
|
-
Write-Host "
|
|
137
|
+
Write-Host "[OK] Vigthoria CLI installed successfully from git package!" -ForegroundColor Green
|
|
138
138
|
return $true
|
|
139
139
|
}
|
|
140
140
|
catch {
|
|
141
|
-
Write-Host "
|
|
141
|
+
Write-Host "[ERROR] Install failed (hosted package + npm registry + git package): $_" -ForegroundColor Red
|
|
142
142
|
return $false
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
function Install-VigthoriaCLI-Direct {
|
|
147
147
|
Write-Host ""
|
|
148
|
-
Write-Host "
|
|
148
|
+
Write-Host "[INSTALL] Installing Vigthoria CLI (Direct Download)..." -ForegroundColor Cyan
|
|
149
149
|
|
|
150
150
|
# Create install directory
|
|
151
151
|
if (-not (Test-Path $INSTALL_DIR)) {
|
|
@@ -198,18 +198,18 @@ node "$packagePath\dist\index.js" %*
|
|
|
198
198
|
# Cleanup
|
|
199
199
|
Remove-Item $tarballPath -Force
|
|
200
200
|
|
|
201
|
-
Write-Host "
|
|
201
|
+
Write-Host "[OK] Vigthoria CLI installed successfully!" -ForegroundColor Green
|
|
202
202
|
return $true
|
|
203
203
|
}
|
|
204
204
|
catch {
|
|
205
|
-
Write-Host "
|
|
205
|
+
Write-Host "[ERROR] Direct install failed: $_" -ForegroundColor Red
|
|
206
206
|
return $false
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function Install-VigthoriaCLI-GitHub {
|
|
211
211
|
Write-Host ""
|
|
212
|
-
Write-Host "
|
|
212
|
+
Write-Host "[INSTALL] Installing Vigthoria CLI (from Vigthoria Market)..." -ForegroundColor Cyan
|
|
213
213
|
|
|
214
214
|
# Create install directory
|
|
215
215
|
if (-not (Test-Path $INSTALL_DIR)) {
|
|
@@ -222,7 +222,7 @@ function Install-VigthoriaCLI-GitHub {
|
|
|
222
222
|
# Check if git is available
|
|
223
223
|
$gitVersion = git --version 2>$null
|
|
224
224
|
if (-not $gitVersion) {
|
|
225
|
-
Write-Host "
|
|
225
|
+
Write-Host "[ERROR] Git is not installed" -ForegroundColor Red
|
|
226
226
|
return $false
|
|
227
227
|
}
|
|
228
228
|
|
|
@@ -244,20 +244,20 @@ function Install-VigthoriaCLI-GitHub {
|
|
|
244
244
|
npm link
|
|
245
245
|
Pop-Location
|
|
246
246
|
|
|
247
|
-
Write-Host "
|
|
247
|
+
Write-Host "[OK] Vigthoria CLI installed successfully!" -ForegroundColor Green
|
|
248
248
|
return $true
|
|
249
249
|
}
|
|
250
250
|
catch {
|
|
251
|
-
Write-Host "
|
|
251
|
+
Write-Host "[ERROR] Git install failed: $_" -ForegroundColor Red
|
|
252
252
|
return $false
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
function Show-NetworkTroubleshooting {
|
|
257
257
|
Write-Host ""
|
|
258
|
-
Write-Host "
|
|
258
|
+
Write-Host "===============================================================" -ForegroundColor Yellow
|
|
259
259
|
Write-Host " NETWORK TROUBLESHOOTING" -ForegroundColor Yellow
|
|
260
|
-
Write-Host "
|
|
260
|
+
Write-Host "===============================================================" -ForegroundColor Yellow
|
|
261
261
|
Write-Host ""
|
|
262
262
|
Write-Host "The hosted package and npm registry could not be reached. Try these solutions:" -ForegroundColor White
|
|
263
263
|
Write-Host ""
|
|
@@ -284,9 +284,9 @@ function Show-NetworkTroubleshooting {
|
|
|
284
284
|
|
|
285
285
|
function Show-Success {
|
|
286
286
|
Write-Host ""
|
|
287
|
-
Write-Host "
|
|
287
|
+
Write-Host "===============================================================" -ForegroundColor Green
|
|
288
288
|
Write-Host " INSTALLATION COMPLETE!" -ForegroundColor Green
|
|
289
|
-
Write-Host "
|
|
289
|
+
Write-Host "===============================================================" -ForegroundColor Green
|
|
290
290
|
Write-Host ""
|
|
291
291
|
Write-Host " Get started:" -ForegroundColor White
|
|
292
292
|
Write-Host " 1. Open a new terminal" -ForegroundColor Gray
|
package/install.sh
CHANGED
|
@@ -26,12 +26,13 @@ else
|
|
|
26
26
|
fi
|
|
27
27
|
|
|
28
28
|
# Configuration
|
|
29
|
-
CLI_VERSION="1.13.
|
|
29
|
+
CLI_VERSION="1.13.13"
|
|
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"
|
|
33
33
|
MANIFEST_URL="${VIGTHORIA_UPDATE_MANIFEST_URL:-https://extension.vigthoria.io/downloads/manifest.json}"
|
|
34
34
|
HOSTED_TARBALL_URL="https://extension.vigthoria.io/downloads/vigthoria-cli-${CLI_VERSION}.tgz"
|
|
35
|
+
HOSTED_TARBALL_SHA256=""
|
|
35
36
|
|
|
36
37
|
resolve_release_manifest() {
|
|
37
38
|
if ! command -v curl >/dev/null 2>&1 || ! command -v python3 >/dev/null 2>&1; then
|
|
@@ -52,24 +53,34 @@ try:
|
|
|
52
53
|
stable = (data.get('channels') or {}).get('stable') or {}
|
|
53
54
|
version = str(stable.get('version') or '').strip()
|
|
54
55
|
url = str(stable.get('url') or '').strip()
|
|
56
|
+
sha256 = str(stable.get('sha256') or '').strip().lower()
|
|
55
57
|
if version:
|
|
56
58
|
print(version)
|
|
57
59
|
if url:
|
|
58
60
|
print(url)
|
|
61
|
+
if sha256:
|
|
62
|
+
print(sha256)
|
|
59
63
|
except Exception:
|
|
60
64
|
pass
|
|
61
65
|
" 2>/dev/null || true)"
|
|
62
66
|
|
|
63
67
|
if [[ -n "$resolved" ]]; then
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
# macOS ships Bash 3.2, which does not provide mapfile/readarray.
|
|
69
|
+
# Parse the two-line response with POSIX sed instead.
|
|
70
|
+
manifest_version="$(printf '%s\n' "$resolved" | sed -n '1p')"
|
|
71
|
+
manifest_url="$(printf '%s\n' "$resolved" | sed -n '2p')"
|
|
72
|
+
manifest_sha256="$(printf '%s\n' "$resolved" | sed -n '3p')"
|
|
73
|
+
if [[ -n "$manifest_version" ]]; then
|
|
74
|
+
CLI_VERSION="$manifest_version"
|
|
67
75
|
fi
|
|
68
|
-
if [[ -n "$
|
|
69
|
-
HOSTED_TARBALL_URL="$
|
|
70
|
-
elif [[ -n "$
|
|
76
|
+
if [[ -n "$manifest_url" ]]; then
|
|
77
|
+
HOSTED_TARBALL_URL="$manifest_url"
|
|
78
|
+
elif [[ -n "$manifest_version" ]]; then
|
|
71
79
|
HOSTED_TARBALL_URL="https://extension.vigthoria.io/downloads/vigthoria-cli-${CLI_VERSION}.tgz"
|
|
72
80
|
fi
|
|
81
|
+
if [[ "$manifest_sha256" =~ ^[a-f0-9]{64}$ ]]; then
|
|
82
|
+
HOSTED_TARBALL_SHA256="$manifest_sha256"
|
|
83
|
+
fi
|
|
73
84
|
fi
|
|
74
85
|
}
|
|
75
86
|
|
|
@@ -177,10 +188,32 @@ install_cli() {
|
|
|
177
188
|
# Create install directory
|
|
178
189
|
mkdir -p "$INSTALL_DIR"
|
|
179
190
|
|
|
180
|
-
# Option 1:
|
|
181
|
-
if
|
|
182
|
-
echo "
|
|
183
|
-
|
|
191
|
+
# Option 1: Download and verify the exact hosted release package.
|
|
192
|
+
if [[ -n "$HOSTED_TARBALL_SHA256" ]]; then
|
|
193
|
+
echo "Downloading checksum-verified hosted release package..."
|
|
194
|
+
RELEASE_TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/vigthoria-cli-install.XXXXXX")"
|
|
195
|
+
RELEASE_ARCHIVE="$RELEASE_TMP_DIR/vigthoria-cli-${CLI_VERSION}.tgz"
|
|
196
|
+
if ! curl -fsSL "$HOSTED_TARBALL_URL" -o "$RELEASE_ARCHIVE"; then
|
|
197
|
+
rm -rf "$RELEASE_TMP_DIR"
|
|
198
|
+
echo -e "${RED}✗ Failed to download verified release package${NC}"
|
|
199
|
+
exit 1
|
|
200
|
+
fi
|
|
201
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
202
|
+
ACTUAL_SHA256="$(shasum -a 256 "$RELEASE_ARCHIVE" | awk '{print $1}')"
|
|
203
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
204
|
+
ACTUAL_SHA256="$(sha256sum "$RELEASE_ARCHIVE" | awk '{print $1}')"
|
|
205
|
+
else
|
|
206
|
+
rm -rf "$RELEASE_TMP_DIR"
|
|
207
|
+
echo -e "${RED}✗ SHA-256 verification tool is unavailable${NC}"
|
|
208
|
+
exit 1
|
|
209
|
+
fi
|
|
210
|
+
if [[ "$ACTUAL_SHA256" != "$HOSTED_TARBALL_SHA256" ]]; then
|
|
211
|
+
rm -rf "$RELEASE_TMP_DIR"
|
|
212
|
+
echo -e "${RED}✗ Release checksum verification failed${NC}"
|
|
213
|
+
exit 1
|
|
214
|
+
fi
|
|
215
|
+
npm install -g --force "$RELEASE_ARCHIVE"
|
|
216
|
+
rm -rf "$RELEASE_TMP_DIR"
|
|
184
217
|
elif npm view vigthoria-cli version &> /dev/null; then
|
|
185
218
|
echo "Installing from npm registry..."
|
|
186
219
|
npm install -g --force vigthoria-cli
|