vigthoria-cli 1.9.9 → 1.9.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/commands/auth.js +48 -65
- package/dist/commands/bridge.js +12 -19
- package/dist/commands/cancel.js +15 -22
- package/dist/commands/chat.d.ts +11 -0
- package/dist/commands/chat.js +404 -248
- package/dist/commands/config.js +31 -71
- package/dist/commands/deploy.js +83 -123
- package/dist/commands/device.d.ts +35 -0
- package/dist/commands/device.js +239 -0
- package/dist/commands/edit.js +32 -39
- package/dist/commands/explain.js +18 -25
- package/dist/commands/fork.js +22 -27
- package/dist/commands/generate.js +37 -44
- package/dist/commands/history.js +20 -25
- package/dist/commands/hub.js +95 -102
- package/dist/commands/index.js +41 -46
- package/dist/commands/legion.d.ts +1 -0
- package/dist/commands/legion.js +162 -209
- package/dist/commands/preview.js +60 -98
- package/dist/commands/replay.js +27 -32
- package/dist/commands/repo.js +103 -141
- package/dist/commands/review.js +29 -36
- package/dist/commands/security.js +5 -12
- package/dist/commands/update.js +15 -49
- package/dist/commands/workflow.d.ts +8 -1
- package/dist/commands/workflow.js +53 -19
- package/dist/index.js +409 -234
- package/dist/utils/api.d.ts +5 -0
- package/dist/utils/api.js +398 -176
- package/dist/utils/bridge-client.js +11 -52
- package/dist/utils/cli-state.d.ts +54 -0
- package/dist/utils/cli-state.js +185 -0
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +35 -14
- package/dist/utils/context-ranker.js +15 -21
- package/dist/utils/files.js +5 -42
- package/dist/utils/logger.js +42 -50
- package/dist/utils/post-write-validator.js +22 -29
- package/dist/utils/project-memory.d.ts +56 -0
- package/dist/utils/project-memory.js +289 -0
- package/dist/utils/session.d.ts +29 -3
- package/dist/utils/session.js +137 -85
- package/dist/utils/task-display.js +13 -20
- package/dist/utils/tools.d.ts +19 -0
- package/dist/utils/tools.js +84 -87
- package/dist/utils/workspace-cache.js +18 -26
- package/dist/utils/workspace-stream.js +26 -64
- package/install.ps1 +14 -0
- package/package.json +5 -3
- package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +1 -1
- package/scripts/release/validate-no-go-gates.sh +2 -2
package/dist/commands/legion.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Vigthoria CLI - Legion Parallel Orchestration
|
|
4
3
|
*
|
|
@@ -9,52 +8,14 @@
|
|
|
9
8
|
* vigthoria legion --workers List available Legion workers
|
|
10
9
|
* vigthoria legion --status Show Legion infrastructure status
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (k2 === undefined) k2 = k;
|
|
21
|
-
o[k2] = m[k];
|
|
22
|
-
}));
|
|
23
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
-
}) : function(o, v) {
|
|
26
|
-
o["default"] = v;
|
|
27
|
-
});
|
|
28
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
-
var ownKeys = function(o) {
|
|
30
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
-
var ar = [];
|
|
32
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
-
return ar;
|
|
34
|
-
};
|
|
35
|
-
return ownKeys(o);
|
|
36
|
-
};
|
|
37
|
-
return function (mod) {
|
|
38
|
-
if (mod && mod.__esModule) return mod;
|
|
39
|
-
var result = {};
|
|
40
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
-
__setModuleDefault(result, mod);
|
|
42
|
-
return result;
|
|
43
|
-
};
|
|
44
|
-
})();
|
|
45
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
-
};
|
|
48
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
-
exports.LegionCommand = void 0;
|
|
50
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
51
|
-
const fs = __importStar(require("fs"));
|
|
52
|
-
const path = __importStar(require("path"));
|
|
53
|
-
const readline = __importStar(require("readline/promises"));
|
|
54
|
-
const node_child_process_1 = require("node:child_process");
|
|
55
|
-
const node_util_1 = require("node:util");
|
|
56
|
-
const logger_js_1 = require("../utils/logger.js");
|
|
57
|
-
const api_js_1 = require("../utils/api.js");
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as readline from 'readline/promises';
|
|
15
|
+
import { exec as execCallback } from 'node:child_process';
|
|
16
|
+
import { promisify } from 'node:util';
|
|
17
|
+
import { createSpinner, CH } from '../utils/logger.js';
|
|
18
|
+
import { describeUpstreamStatus, isServerRuntime, propagateError } from '../utils/api.js';
|
|
58
19
|
// Hyper Loop / Legion runs on the Vigthoria backend only. Local user installs
|
|
59
20
|
// must never even attempt these endpoints, because fetch errors include the
|
|
60
21
|
// URL we tried (would leak internal infra to the user's terminal).
|
|
@@ -70,15 +31,15 @@ function buildServerHyperloopUrls() {
|
|
|
70
31
|
`http://${internalHost}:${port}${apiPath}`,
|
|
71
32
|
];
|
|
72
33
|
}
|
|
73
|
-
const HYPERLOOP_URLS =
|
|
34
|
+
const HYPERLOOP_URLS = isServerRuntime()
|
|
74
35
|
? buildServerHyperloopUrls()
|
|
75
36
|
: (process.env.VIGTHORIA_HYPERLOOP_URL ? [process.env.VIGTHORIA_HYPERLOOP_URL] : []);
|
|
76
37
|
const CORTEX_WARN_BUDGET_USD = 3.5;
|
|
77
38
|
const CORTEX_HARD_BUDGET_USD = 5.0;
|
|
78
39
|
const CORTEX_MAX_ROUNDS = 2;
|
|
79
40
|
const CORTEX_PLATFORM_FEE_PCT = 10;
|
|
80
|
-
const execAsync =
|
|
81
|
-
class LegionCommand {
|
|
41
|
+
const execAsync = promisify(execCallback);
|
|
42
|
+
export class LegionCommand {
|
|
82
43
|
config;
|
|
83
44
|
logger;
|
|
84
45
|
constructor(config, logger) {
|
|
@@ -95,7 +56,7 @@ class LegionCommand {
|
|
|
95
56
|
if (envUrl) {
|
|
96
57
|
urls.add(envUrl);
|
|
97
58
|
}
|
|
98
|
-
if (
|
|
59
|
+
if (isServerRuntime()) {
|
|
99
60
|
for (const internal of buildServerHyperloopUrls()) {
|
|
100
61
|
urls.add(internal.replace(/\/$/, ''));
|
|
101
62
|
}
|
|
@@ -121,7 +82,7 @@ class LegionCommand {
|
|
|
121
82
|
return await response.json();
|
|
122
83
|
}
|
|
123
84
|
catch (err) {
|
|
124
|
-
|
|
85
|
+
propagateError({
|
|
125
86
|
...((err && typeof err === 'object') ? err : { message: String(err) }),
|
|
126
87
|
message: `${context} returned invalid JSON: ${err?.message || String(err)}`,
|
|
127
88
|
statusCode: response.status,
|
|
@@ -139,7 +100,7 @@ class LegionCommand {
|
|
|
139
100
|
}
|
|
140
101
|
propagateLegionApiError(context, endpoint, err) {
|
|
141
102
|
const original = err && typeof err === 'object' ? err : { message: String(err) };
|
|
142
|
-
|
|
103
|
+
propagateError({
|
|
143
104
|
...original,
|
|
144
105
|
commandName: 'legion',
|
|
145
106
|
endpoint: original.endpoint || original?.config?.url || original?.details?.endpoint || endpoint || context,
|
|
@@ -165,27 +126,27 @@ class LegionCommand {
|
|
|
165
126
|
return;
|
|
166
127
|
}
|
|
167
128
|
if (!request) {
|
|
168
|
-
console.log(
|
|
169
|
-
console.log(
|
|
170
|
-
console.log(
|
|
171
|
-
console.log(
|
|
129
|
+
console.log(chalk.yellow('Usage: vigthoria legion "<task description>"'));
|
|
130
|
+
console.log(chalk.gray(' --workers List available Legion workers'));
|
|
131
|
+
console.log(chalk.gray(' --status Show Legion infrastructure status'));
|
|
132
|
+
console.log(chalk.gray(' --cortex Vigthoria Cortex: maximum intelligence execution'));
|
|
172
133
|
return;
|
|
173
134
|
}
|
|
174
135
|
await this.planAndExecute(request, options);
|
|
175
136
|
}
|
|
176
137
|
async runCortex(request, options) {
|
|
177
138
|
if (!request) {
|
|
178
|
-
console.log(
|
|
179
|
-
console.log(
|
|
180
|
-
console.log(
|
|
181
|
-
console.log(
|
|
182
|
-
console.log(
|
|
183
|
-
console.log(
|
|
184
|
-
console.log(
|
|
185
|
-
console.log(
|
|
186
|
-
console.log(
|
|
187
|
-
console.log(
|
|
188
|
-
console.log(
|
|
139
|
+
console.log(chalk.yellow('Usage: vigthoria legion --cortex "<task description>"'));
|
|
140
|
+
console.log(chalk.gray(' --plan-only Run calculator only (no execution)'));
|
|
141
|
+
console.log(chalk.gray(' --force-budget Allow execution above hard safe-stop budget'));
|
|
142
|
+
console.log(chalk.gray(' --ignore-preflight Bypass mandatory preflight checks (no warranty)'));
|
|
143
|
+
console.log(chalk.gray(' --speed Speed mode: optional role skip on convergence'));
|
|
144
|
+
console.log(chalk.gray(' --tier heavy|lite Model tier: heavy=strongest LLMs (default), lite=efficient+affordable'));
|
|
145
|
+
console.log(chalk.gray(' --repro-cmd <cmd> Run a local reproducibility command before spend'));
|
|
146
|
+
console.log(chalk.gray(' --expect-repro-fail Require repro command to fail before execution'));
|
|
147
|
+
console.log(chalk.gray(' --approve Skip initial confirmation prompt and execute'));
|
|
148
|
+
console.log(chalk.gray(' --auto-charge Attempt direct VigCoin top-up when balance is low'));
|
|
149
|
+
console.log(chalk.gray(' --timeout <sec> Abort remote execution if no result within timeout (default: 120)'));
|
|
189
150
|
return;
|
|
190
151
|
}
|
|
191
152
|
const workspace = options.project || process.cwd();
|
|
@@ -193,38 +154,38 @@ class LegionCommand {
|
|
|
193
154
|
if (!options.ignorePreflight) {
|
|
194
155
|
const preflight = await this.runMandatoryPreflight(workspace, options.reproCmd, options.expectReproFail === true);
|
|
195
156
|
if (!preflight.ok) {
|
|
196
|
-
console.log(
|
|
197
|
-
console.log(
|
|
198
|
-
console.log(
|
|
157
|
+
console.log(chalk.red('Cortex preflight failed.'));
|
|
158
|
+
console.log(chalk.red(` ${preflight.reason}`));
|
|
159
|
+
console.log(chalk.yellow('Execution halted before any cloud spend. Use --ignore-preflight to override (no warranty).'));
|
|
199
160
|
return;
|
|
200
161
|
}
|
|
201
|
-
console.log(
|
|
162
|
+
console.log(chalk.green('Preflight passed.'));
|
|
202
163
|
}
|
|
203
164
|
else {
|
|
204
|
-
console.log(
|
|
165
|
+
console.log(chalk.yellow('Preflight bypassed by --ignore-preflight (no warranty).'));
|
|
205
166
|
}
|
|
206
167
|
const tier = (options.tier === 'lite') ? 'lite' : 'heavy';
|
|
207
168
|
const selectedModels = this.resolveModelProfiles(options.models, tier);
|
|
208
169
|
const quote = this.buildRoleQuote(scan, selectedModels, tier);
|
|
209
170
|
const billingQuote = this.buildBillingQuote(quote, tier);
|
|
210
171
|
if (billingQuote.retryAdjustedUsd > CORTEX_WARN_BUDGET_USD) {
|
|
211
|
-
console.log(
|
|
172
|
+
console.log(chalk.yellow(`Estimated spend exceeds warning threshold ($${CORTEX_WARN_BUDGET_USD.toFixed(2)}).`));
|
|
212
173
|
}
|
|
213
174
|
let billingGate = await this.evaluateBillingGate(billingQuote);
|
|
214
175
|
this.printCortexQuote(workspace, scan, quote, billingQuote, billingGate);
|
|
215
176
|
if (billingQuote.retryAdjustedUsd > CORTEX_HARD_BUDGET_USD && !options.forceBudget && !billingGate.masterAdminFree) {
|
|
216
|
-
console.log(
|
|
217
|
-
console.log(
|
|
177
|
+
console.log(chalk.red(`Estimated spend exceeds hard budget ceiling (${CORTEX_HARD_BUDGET_USD.toFixed(2)}).`));
|
|
178
|
+
console.log(chalk.yellow('Re-run with --force-budget to continue.'));
|
|
218
179
|
return;
|
|
219
180
|
}
|
|
220
181
|
if (options.planOnly) {
|
|
221
|
-
console.log(
|
|
182
|
+
console.log(chalk.green('Cortex estimator complete (plan-only).'));
|
|
222
183
|
return;
|
|
223
184
|
}
|
|
224
185
|
const autoApprove = options.approve === true && options.noApprove !== true;
|
|
225
186
|
const approved = autoApprove ? true : await this.confirmExecution();
|
|
226
187
|
if (!approved) {
|
|
227
|
-
console.log(
|
|
188
|
+
console.log(chalk.yellow('Cortex cancelled by user.'));
|
|
228
189
|
return;
|
|
229
190
|
}
|
|
230
191
|
let round = 1;
|
|
@@ -235,19 +196,19 @@ class LegionCommand {
|
|
|
235
196
|
if (!billingGate.canProceed) {
|
|
236
197
|
const resolved = await this.resolveBillingInsufficientFunds(currentQuote, billingGate, options);
|
|
237
198
|
if (!resolved) {
|
|
238
|
-
console.log(
|
|
199
|
+
console.log(chalk.yellow('Cortex cancelled due to insufficient VigCoin balance.'));
|
|
239
200
|
return;
|
|
240
201
|
}
|
|
241
202
|
billingGate = await this.evaluateBillingGate(currentQuote);
|
|
242
203
|
if (!billingGate.canProceed) {
|
|
243
204
|
this.printBillingGateSummary(currentQuote, billingGate);
|
|
244
|
-
console.log(
|
|
205
|
+
console.log(chalk.red('Billing gate still blocked after charge attempt.'));
|
|
245
206
|
return;
|
|
246
207
|
}
|
|
247
208
|
}
|
|
248
209
|
const charged = await this.collectExecutionCharge(currentQuote, billingGate);
|
|
249
210
|
if (!charged) {
|
|
250
|
-
console.log(
|
|
211
|
+
console.log(chalk.yellow('Cortex cancelled because wallet charge was not completed.'));
|
|
251
212
|
return;
|
|
252
213
|
}
|
|
253
214
|
cumulativeUsd += currentQuote.finalUsd;
|
|
@@ -274,27 +235,27 @@ class LegionCommand {
|
|
|
274
235
|
}
|
|
275
236
|
const failedRole = String(execution.failedStepId || '').toLowerCase();
|
|
276
237
|
if (this.isCriticalRoleFailure(failedRole)) {
|
|
277
|
-
console.log(
|
|
238
|
+
console.log(chalk.red(`Fail-fast: critical role '${failedRole || 'unknown'}' failed. Manual correction required.`));
|
|
278
239
|
return;
|
|
279
240
|
}
|
|
280
241
|
if (!this.isOptionalRepairRoleFailure(failedRole)) {
|
|
281
|
-
console.log(
|
|
242
|
+
console.log(chalk.red('Execution failed and is not eligible for automatic optional-role repair.'));
|
|
282
243
|
return;
|
|
283
244
|
}
|
|
284
245
|
if (round >= CORTEX_MAX_ROUNDS) {
|
|
285
|
-
console.log(
|
|
246
|
+
console.log(chalk.red('Optional-role auto-repair budget exhausted.'));
|
|
286
247
|
return;
|
|
287
248
|
}
|
|
288
249
|
const nextQuote = this.estimateAdditionalLoopQuote(currentQuote, execution);
|
|
289
250
|
const projectedTotal = cumulativeUsd + nextQuote.retryAdjustedUsd;
|
|
290
251
|
if (projectedTotal > CORTEX_HARD_BUDGET_USD && !options.forceBudget) {
|
|
291
|
-
console.log(
|
|
292
|
-
console.log(
|
|
252
|
+
console.log(chalk.red(`Additional loop would exceed hard budget ceiling ($${CORTEX_HARD_BUDGET_USD.toFixed(2)}).`));
|
|
253
|
+
console.log(chalk.yellow('Re-run with --force-budget to allow paid continuation.'));
|
|
293
254
|
return;
|
|
294
255
|
}
|
|
295
256
|
const continueApproved = await this.confirmAdditionalLoopCharge(nextQuote, round + 1, execution);
|
|
296
257
|
if (!continueApproved) {
|
|
297
|
-
console.log(
|
|
258
|
+
console.log(chalk.yellow('Termination: user declined additional budget for next round.'));
|
|
298
259
|
return;
|
|
299
260
|
}
|
|
300
261
|
currentQuote = nextQuote;
|
|
@@ -337,10 +298,10 @@ class LegionCommand {
|
|
|
337
298
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
338
299
|
try {
|
|
339
300
|
console.log();
|
|
340
|
-
console.log(
|
|
341
|
-
console.log(
|
|
342
|
-
console.log(
|
|
343
|
-
console.log(
|
|
301
|
+
console.log(chalk.yellow('Budget depleted for current round. Additional paid loop required.'));
|
|
302
|
+
console.log(chalk.gray(` Next round: ${nextRound}`));
|
|
303
|
+
console.log(chalk.gray(` Failed step: ${execution.failedStepId || 'unknown'} (${execution.failedWorker || 'unknown'})`));
|
|
304
|
+
console.log(chalk.gray(` Additional estimate: $${nextQuote.finalUsd.toFixed(4)} / ${nextQuote.vigcoinRequired.toFixed(3)} VIG`));
|
|
344
305
|
const answer = (await rl.question('Confirm additional VigCoin deduction and continue? (y/N): ')).trim().toLowerCase();
|
|
345
306
|
return answer === 'y' || answer === 'yes';
|
|
346
307
|
}
|
|
@@ -679,23 +640,10 @@ class LegionCommand {
|
|
|
679
640
|
};
|
|
680
641
|
}
|
|
681
642
|
async evaluateBillingGate(billingQuote) {
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
if (hasServiceKey) {
|
|
687
|
-
return {
|
|
688
|
-
plan: forcedPlan || this.config.getNormalizedPlan() || 'service',
|
|
689
|
-
masterAdminFree: true,
|
|
690
|
-
canProceed: true,
|
|
691
|
-
wallet: {
|
|
692
|
-
available: true,
|
|
693
|
-
vigcoinBalance: null,
|
|
694
|
-
source: 'service_key_access',
|
|
695
|
-
purchaseUrl: null,
|
|
696
|
-
},
|
|
697
|
-
};
|
|
698
|
-
}
|
|
643
|
+
const forceFlagsEnabled = this.isCortexTestMode();
|
|
644
|
+
const forcedPlan = forceFlagsEnabled
|
|
645
|
+
? String(process.env.VIGTHORIA_CORTEX_FORCE_PLAN || process.env.VIGTHORIA_GODMODE_FORCE_PLAN || '').trim().toLowerCase()
|
|
646
|
+
: '';
|
|
699
647
|
const entitlement = await this.fetchCortexEntitlement();
|
|
700
648
|
const normalizedPlan = forcedPlan || entitlement.plan || this.config.getNormalizedPlan() || 'free';
|
|
701
649
|
const masterAdminFree = this.isMasterAdminFree(normalizedPlan, entitlement.masterAccess, entitlement.isMasterAdmin);
|
|
@@ -749,7 +697,7 @@ class LegionCommand {
|
|
|
749
697
|
return null;
|
|
750
698
|
}
|
|
751
699
|
async fetchCortexEntitlement() {
|
|
752
|
-
if (process.env.VIGTHORIA_CORTEX_FORCE_MASTER_ACCESS === '1' || process.env.VIGTHORIA_GODMODE_FORCE_MASTER_ACCESS === '1') {
|
|
700
|
+
if (this.isCortexTestMode() && (process.env.VIGTHORIA_CORTEX_FORCE_MASTER_ACCESS === '1' || process.env.VIGTHORIA_GODMODE_FORCE_MASTER_ACCESS === '1')) {
|
|
753
701
|
return { plan: this.config.getNormalizedPlan() || 'free', masterAccess: true, isMasterAdmin: true };
|
|
754
702
|
}
|
|
755
703
|
const baseUrl = this.getBillingBaseUrl();
|
|
@@ -823,6 +771,11 @@ class LegionCommand {
|
|
|
823
771
|
}
|
|
824
772
|
return plan === 'master_admin';
|
|
825
773
|
}
|
|
774
|
+
isCortexTestMode() {
|
|
775
|
+
return process.env.VIGTHORIA_CORTEX_TEST_MODE === '1'
|
|
776
|
+
|| process.env.VIGTHORIA_GODMODE_TEST_MODE === '1'
|
|
777
|
+
|| process.env.NODE_ENV === 'test';
|
|
778
|
+
}
|
|
826
779
|
getBillingBaseUrl() {
|
|
827
780
|
const configured = String(this.config.get('apiUrl') || '').trim().replace(/\/$/, '');
|
|
828
781
|
if (configured) {
|
|
@@ -885,8 +838,8 @@ class LegionCommand {
|
|
|
885
838
|
async fetchWalletState() {
|
|
886
839
|
const baseUrl = this.getBillingBaseUrl();
|
|
887
840
|
const headers = this.getHeaders();
|
|
888
|
-
const forcedLow = process.env.VIGTHORIA_CORTEX_FORCE_LOW_CREDIT === '1' || process.env.VIGTHORIA_GODMODE_FORCE_LOW_CREDIT === '1';
|
|
889
|
-
const forcedBalanceRaw = process.env.VIGTHORIA_CORTEX_FORCE_BALANCE || process.env.VIGTHORIA_GODMODE_FORCE_BALANCE;
|
|
841
|
+
const forcedLow = this.isCortexTestMode() && (process.env.VIGTHORIA_CORTEX_FORCE_LOW_CREDIT === '1' || process.env.VIGTHORIA_GODMODE_FORCE_LOW_CREDIT === '1');
|
|
842
|
+
const forcedBalanceRaw = this.isCortexTestMode() ? (process.env.VIGTHORIA_CORTEX_FORCE_BALANCE || process.env.VIGTHORIA_GODMODE_FORCE_BALANCE) : '';
|
|
890
843
|
if (forcedLow) {
|
|
891
844
|
return {
|
|
892
845
|
available: true,
|
|
@@ -955,10 +908,11 @@ class LegionCommand {
|
|
|
955
908
|
const baseUrl = this.getBillingBaseUrl();
|
|
956
909
|
const headers = this.getHeaders();
|
|
957
910
|
const amount = Math.max(1, Math.ceil(vigcoinNeeded));
|
|
911
|
+
const requestId = `cortex_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
958
912
|
const chargePayloads = [
|
|
959
|
-
{ endpoint: '/api/viagen6/vigcoin/charge', body: { amount, reason: 'cortex_legion' } },
|
|
960
|
-
{ endpoint: '/api/wallet/charge', body: { amount, currency: 'VIGCOIN', reason: 'cortex_legion' } },
|
|
961
|
-
{ endpoint: '/api/billing/topup', body: { vigcoin: amount, reason: 'cortex_legion' } },
|
|
913
|
+
{ endpoint: '/api/viagen6/vigcoin/charge', body: { amount, reason: 'cortex_legion', requestId } },
|
|
914
|
+
{ endpoint: '/api/wallet/charge', body: { amount, currency: 'VIGCOIN', reason: 'cortex_legion', requestId } },
|
|
915
|
+
{ endpoint: '/api/billing/topup', body: { vigcoin: amount, reason: 'cortex_legion', requestId } },
|
|
962
916
|
];
|
|
963
917
|
for (const attempt of chargePayloads) {
|
|
964
918
|
try {
|
|
@@ -1002,42 +956,42 @@ class LegionCommand {
|
|
|
1002
956
|
if (gate.masterAdminFree) {
|
|
1003
957
|
return true;
|
|
1004
958
|
}
|
|
1005
|
-
const spinner =
|
|
959
|
+
const spinner = createSpinner('Charging VigCoin wallet for Cortex execution...').start();
|
|
1006
960
|
const result = await this.attemptDirectCharge(billingQuote.vigcoinRequired);
|
|
1007
961
|
spinner.stop();
|
|
1008
962
|
if (!result.ok) {
|
|
1009
|
-
console.log(
|
|
1010
|
-
console.log(
|
|
963
|
+
console.log(chalk.red(result.note || 'Wallet charge failed.'));
|
|
964
|
+
console.log(chalk.yellow(`Complete purchase first: ${result.checkoutUrl || `${this.getBillingBaseUrl()}/music/store#vigcoins`}`));
|
|
1011
965
|
return false;
|
|
1012
966
|
}
|
|
1013
|
-
console.log(
|
|
967
|
+
console.log(chalk.green('Wallet charged for Cortex execution.'));
|
|
1014
968
|
return true;
|
|
1015
969
|
}
|
|
1016
970
|
async resolveBillingInsufficientFunds(billingQuote, gate, options) {
|
|
1017
971
|
this.printBillingGateSummary(billingQuote, gate);
|
|
1018
972
|
if (!gate.wallet.available) {
|
|
1019
|
-
console.log(
|
|
973
|
+
console.log(chalk.red('Unable to verify wallet balance from server. Execution is blocked.'));
|
|
1020
974
|
if (gate.wallet.purchaseUrl) {
|
|
1021
|
-
console.log(
|
|
975
|
+
console.log(chalk.gray(`Open billing portal: ${gate.wallet.purchaseUrl}`));
|
|
1022
976
|
}
|
|
1023
977
|
return false;
|
|
1024
978
|
}
|
|
1025
979
|
if (options.autoCharge) {
|
|
1026
|
-
const spinner =
|
|
980
|
+
const spinner = createSpinner('Attempting direct wallet charge...').start();
|
|
1027
981
|
const result = await this.attemptDirectCharge(billingQuote.vigcoinRequired - (gate.wallet.vigcoinBalance || 0));
|
|
1028
982
|
spinner.stop();
|
|
1029
983
|
if (result.ok) {
|
|
1030
|
-
console.log(
|
|
984
|
+
console.log(chalk.green('Direct charge succeeded. Re-checking wallet balance...'));
|
|
1031
985
|
return true;
|
|
1032
986
|
}
|
|
1033
|
-
console.log(
|
|
1034
|
-
console.log(
|
|
987
|
+
console.log(chalk.yellow(result.note || 'Direct charge did not complete.'));
|
|
988
|
+
console.log(chalk.yellow(`Complete purchase first: ${result.checkoutUrl || gate.wallet.purchaseUrl || `${this.getBillingBaseUrl()}/billing`}`));
|
|
1035
989
|
return false;
|
|
1036
990
|
}
|
|
1037
991
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1038
|
-
console.log(
|
|
992
|
+
console.log(chalk.yellow('Low balance detected in non-interactive mode. Re-run with --auto-charge or top up first.'));
|
|
1039
993
|
if (gate.wallet.purchaseUrl) {
|
|
1040
|
-
console.log(
|
|
994
|
+
console.log(chalk.gray(`Billing portal: ${gate.wallet.purchaseUrl}`));
|
|
1041
995
|
}
|
|
1042
996
|
return false;
|
|
1043
997
|
}
|
|
@@ -1045,19 +999,19 @@ class LegionCommand {
|
|
|
1045
999
|
try {
|
|
1046
1000
|
const answer = (await rl.question('VigCoin low. Choose action: [c]harge now, [p]urchase first, [n] cancel: ')).trim().toLowerCase();
|
|
1047
1001
|
if (answer === 'c' || answer === 'charge') {
|
|
1048
|
-
const spinner =
|
|
1002
|
+
const spinner = createSpinner('Attempting direct wallet charge...').start();
|
|
1049
1003
|
const result = await this.attemptDirectCharge(billingQuote.vigcoinRequired - (gate.wallet.vigcoinBalance || 0));
|
|
1050
1004
|
spinner.stop();
|
|
1051
1005
|
if (result.ok) {
|
|
1052
|
-
console.log(
|
|
1006
|
+
console.log(chalk.green('Direct charge succeeded. Re-checking wallet balance...'));
|
|
1053
1007
|
return true;
|
|
1054
1008
|
}
|
|
1055
|
-
console.log(
|
|
1056
|
-
console.log(
|
|
1009
|
+
console.log(chalk.yellow(result.note || 'Direct charge did not complete.'));
|
|
1010
|
+
console.log(chalk.yellow(`Complete purchase first: ${result.checkoutUrl || gate.wallet.purchaseUrl || `${this.getBillingBaseUrl()}/billing`}`));
|
|
1057
1011
|
return false;
|
|
1058
1012
|
}
|
|
1059
1013
|
if (answer === 'p' || answer === 'purchase') {
|
|
1060
|
-
console.log(
|
|
1014
|
+
console.log(chalk.yellow(`Purchase VigCoin first: ${gate.wallet.purchaseUrl || `${this.getBillingBaseUrl()}/billing`}`));
|
|
1061
1015
|
return false;
|
|
1062
1016
|
}
|
|
1063
1017
|
return false;
|
|
@@ -1067,68 +1021,68 @@ class LegionCommand {
|
|
|
1067
1021
|
}
|
|
1068
1022
|
}
|
|
1069
1023
|
printBillingGateSummary(billingQuote, gate) {
|
|
1070
|
-
console.log(
|
|
1071
|
-
console.log(
|
|
1024
|
+
console.log(chalk.white(' Billing gate:'));
|
|
1025
|
+
console.log(chalk.gray(` Plan: ${gate.plan}`));
|
|
1072
1026
|
if (gate.masterAdminFree) {
|
|
1073
|
-
console.log(
|
|
1027
|
+
console.log(chalk.green(' Free tier override applied (Master Admin).'));
|
|
1074
1028
|
return;
|
|
1075
1029
|
}
|
|
1076
|
-
console.log(
|
|
1077
|
-
console.log(
|
|
1078
|
-
console.log(
|
|
1079
|
-
console.log(
|
|
1030
|
+
console.log(chalk.gray(` Estimated total (USD): $${billingQuote.retryAdjustedUsd.toFixed(4)}`) + chalk.gray(' (retry-adjusted expected)'));
|
|
1031
|
+
console.log(chalk.gray(` Platform fee: +${billingQuote.platformFeePct.toFixed(0)}% (already included in all estimates)`));
|
|
1032
|
+
console.log(chalk.gray(` VigCoin rate: 1 VIG = $${billingQuote.vigcoinRateUsd.toFixed(4)}`));
|
|
1033
|
+
console.log(chalk.gray(` VigCoin required: ${billingQuote.vigcoinRequired.toFixed(3)}`));
|
|
1080
1034
|
if (gate.wallet.vigcoinBalance !== null) {
|
|
1081
|
-
const color = gate.wallet.vigcoinBalance >= billingQuote.vigcoinRequired ?
|
|
1082
|
-
console.log(
|
|
1035
|
+
const color = gate.wallet.vigcoinBalance >= billingQuote.vigcoinRequired ? chalk.green : chalk.red;
|
|
1036
|
+
console.log(chalk.gray(' Wallet balance: ') + color(gate.wallet.vigcoinBalance.toFixed(3)) + (gate.wallet.source ? chalk.gray(` (source: ${gate.wallet.source})`) : ''));
|
|
1083
1037
|
}
|
|
1084
1038
|
else {
|
|
1085
|
-
console.log(
|
|
1039
|
+
console.log(chalk.red(` Wallet balance: unavailable${gate.wallet.error ? ` (${gate.wallet.error})` : ''}`));
|
|
1086
1040
|
}
|
|
1087
1041
|
if (gate.wallet.purchaseUrl) {
|
|
1088
|
-
console.log(
|
|
1042
|
+
console.log(chalk.gray(` Purchase URL: ${gate.wallet.purchaseUrl}`));
|
|
1089
1043
|
}
|
|
1090
1044
|
}
|
|
1091
1045
|
printCortexQuote(workspace, scan, quote, billingQuote, gate) {
|
|
1092
1046
|
const tierLabel = billingQuote.tier === 'lite'
|
|
1093
|
-
?
|
|
1094
|
-
:
|
|
1047
|
+
? chalk.cyan('LITE') + chalk.gray(' — efficient (claude-sonnet/haiku, o4-mini, gemini-flash, deepseek-v3)')
|
|
1048
|
+
: chalk.magenta('HEAVY') + chalk.gray(' — strongest LLMs (gpt-5.5, opus-4.7, o3, gemini-2.5-pro)');
|
|
1095
1049
|
console.log();
|
|
1096
|
-
console.log(
|
|
1050
|
+
console.log(chalk.bold.white(` ${CH.hLine.repeat(3)} Vigthoria Cortex Estimator ${CH.hLine.repeat(31)}`));
|
|
1097
1051
|
console.log();
|
|
1098
|
-
console.log(
|
|
1099
|
-
console.log(
|
|
1100
|
-
console.log(
|
|
1101
|
-
console.log(
|
|
1102
|
-
console.log(
|
|
1052
|
+
console.log(chalk.gray(' Workspace: ') + chalk.white(workspace));
|
|
1053
|
+
console.log(chalk.gray(' Tier: ') + tierLabel);
|
|
1054
|
+
console.log(chalk.gray(' Files scanned: ') + chalk.white(String(scan.files)));
|
|
1055
|
+
console.log(chalk.gray(' Lines scanned: ') + chalk.white(String(scan.lines)));
|
|
1056
|
+
console.log(chalk.gray(' Dependency edges: ') + chalk.white(String(scan.importEdges)));
|
|
1103
1057
|
if (scan.topFiles.length > 0) {
|
|
1104
1058
|
console.log();
|
|
1105
|
-
console.log(
|
|
1059
|
+
console.log(chalk.white(' Top context files:'));
|
|
1106
1060
|
for (const f of scan.topFiles) {
|
|
1107
|
-
console.log(
|
|
1061
|
+
console.log(chalk.gray(` ${CH.bullet} ${f.file} (${f.lines} lines, ${f.imports} imports)`));
|
|
1108
1062
|
}
|
|
1109
1063
|
}
|
|
1110
1064
|
console.log();
|
|
1111
|
-
console.log(
|
|
1065
|
+
console.log(chalk.white(' Role assignment and estimated cost:'));
|
|
1112
1066
|
for (const row of quote) {
|
|
1113
1067
|
const publicModelLabel = row.requestedModel || row.model.replace(/^openrouter:/i, '').split('/').pop() || 'managed-model';
|
|
1114
1068
|
const roleEstWithFee = row.estCostUsd * (1 + (billingQuote.platformFeePct / 100));
|
|
1115
|
-
console.log(
|
|
1069
|
+
console.log(chalk.gray(` ${CH.bullet} ${row.role.padEnd(11)} ${publicModelLabel} $${roleEstWithFee.toFixed(4)}`));
|
|
1116
1070
|
}
|
|
1117
1071
|
console.log();
|
|
1118
|
-
console.log(
|
|
1119
|
-
console.log(
|
|
1120
|
-
console.log(
|
|
1121
|
-
console.log(
|
|
1122
|
-
console.log(
|
|
1123
|
-
console.log(
|
|
1124
|
-
console.log(
|
|
1072
|
+
console.log(chalk.yellow(` Cost range (single-pass best case): $${billingQuote.rangeMinUsd.toFixed(4)}`));
|
|
1073
|
+
console.log(chalk.yellow(` Cost range (expected with retries): $${billingQuote.retryAdjustedUsd.toFixed(4)}`) + chalk.gray(' ← use this for budget planning'));
|
|
1074
|
+
console.log(chalk.yellow(` Cost range (worst case, all retries): $${billingQuote.rangeMaxUsd.toFixed(4)}`));
|
|
1075
|
+
console.log(chalk.gray(' Retry model: 45% chance per critical role triggers quality-gate (+40% iterations per retry).'));
|
|
1076
|
+
console.log(chalk.gray(' A mid-run checkpoint will appear when 70% of the expected estimate is consumed.'));
|
|
1077
|
+
console.log(chalk.gray(' Flow: Estimate -> Isolation -> Parallel Attack -> Synthesis'));
|
|
1078
|
+
console.log(chalk.gray(` All displayed costs include platform fee (+${billingQuote.platformFeePct.toFixed(0)}%).`));
|
|
1125
1079
|
console.log();
|
|
1126
1080
|
this.printBillingGateSummary(billingQuote, gate);
|
|
1127
1081
|
console.log();
|
|
1128
1082
|
}
|
|
1129
1083
|
async confirmExecution() {
|
|
1130
1084
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1131
|
-
console.log(
|
|
1085
|
+
console.log(chalk.yellow('Non-interactive terminal detected. Re-run with --approve to continue execution.'));
|
|
1132
1086
|
return false;
|
|
1133
1087
|
}
|
|
1134
1088
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -1187,7 +1141,7 @@ class LegionCommand {
|
|
|
1187
1141
|
headers['Cookie'] = `vigthoria-auth-token=${token}`;
|
|
1188
1142
|
}
|
|
1189
1143
|
}
|
|
1190
|
-
const spinner =
|
|
1144
|
+
const spinner = createSpinner('Connecting to Legion SSE stream...').start();
|
|
1191
1145
|
const startTime = Date.now();
|
|
1192
1146
|
let response;
|
|
1193
1147
|
try {
|
|
@@ -1205,7 +1159,7 @@ class LegionCommand {
|
|
|
1205
1159
|
if (!response.ok) {
|
|
1206
1160
|
spinner.stop();
|
|
1207
1161
|
const errBody = await response.text().catch(() => '');
|
|
1208
|
-
this.logger.error(`Legion stream ${response.status}: ${
|
|
1162
|
+
this.logger.error(`Legion stream ${response.status}: ${describeUpstreamStatus(response.status)} — ${errBody.slice(0, 200)}`);
|
|
1209
1163
|
return { status: 'failed', plannedSteps: 0, completedSteps: 0 };
|
|
1210
1164
|
}
|
|
1211
1165
|
if (!response.body) {
|
|
@@ -1215,7 +1169,7 @@ class LegionCommand {
|
|
|
1215
1169
|
}
|
|
1216
1170
|
spinner.stop();
|
|
1217
1171
|
console.log();
|
|
1218
|
-
console.log(
|
|
1172
|
+
console.log(chalk.bold.white(` ${CH.hLine.repeat(3)} Legion Execution Report ${CH.hLine.repeat(34)}`));
|
|
1219
1173
|
console.log();
|
|
1220
1174
|
const decoder = new TextDecoder();
|
|
1221
1175
|
let buffer = '';
|
|
@@ -1265,18 +1219,18 @@ class LegionCommand {
|
|
|
1265
1219
|
switch (evt.event) {
|
|
1266
1220
|
case 'plan':
|
|
1267
1221
|
stepsTotal = evt.steps_total || 0;
|
|
1268
|
-
console.log(
|
|
1222
|
+
console.log(chalk.gray(` Planned workers: ${stepsTotal} steps queued`));
|
|
1269
1223
|
console.log();
|
|
1270
1224
|
break;
|
|
1271
1225
|
case 'batch_start':
|
|
1272
|
-
console.log(
|
|
1226
|
+
console.log(chalk.gray(` ▶ Running: ${evt.workers.join(', ')} (${evt.steps_done}/${evt.steps_total})`));
|
|
1273
1227
|
break;
|
|
1274
1228
|
case 'step_complete': {
|
|
1275
1229
|
stepsDone = Number(evt.steps_done) || 0;
|
|
1276
|
-
const icon = evt.status === 'completed' ?
|
|
1230
|
+
const icon = evt.status === 'completed' ? chalk.green(CH.success) : chalk.red(CH.error);
|
|
1277
1231
|
const stepSummaryRaw = String(evt.summary || '');
|
|
1278
|
-
const summarySnip = stepSummaryRaw ?
|
|
1279
|
-
console.log(` ${icon} ${
|
|
1232
|
+
const summarySnip = stepSummaryRaw ? chalk.gray(` — ${stepSummaryRaw.slice(0, 120)}`) : '';
|
|
1233
|
+
console.log(` ${icon} ${chalk.white(String(evt.step_id))} ${chalk.gray('[' + evt.worker + ']')}${summarySnip}`);
|
|
1280
1234
|
if (evt.status !== 'completed' && !failedStepId) {
|
|
1281
1235
|
failedStepId = String(evt.step_id || '');
|
|
1282
1236
|
failedWorker = String(evt.worker || '');
|
|
@@ -1299,18 +1253,18 @@ class LegionCommand {
|
|
|
1299
1253
|
.filter((q) => remainingRoles.includes(q.role))
|
|
1300
1254
|
.reduce((s, q) => s + (q.estCostUsd * (1 + CORTEX_PLATFORM_FEE_PCT / 100)), 0);
|
|
1301
1255
|
console.log();
|
|
1302
|
-
console.log(
|
|
1303
|
-
console.log(
|
|
1304
|
-
console.log(
|
|
1256
|
+
console.log(chalk.bold.yellow(' ━━━ Mid-Run Budget Checkpoint ━━━'));
|
|
1257
|
+
console.log(chalk.gray(` Consumed so far (estimated): $${accumulatedEstUsd.toFixed(4)}`));
|
|
1258
|
+
console.log(chalk.gray(` Estimated remaining: $${remainingEstUsd.toFixed(4)}`));
|
|
1305
1259
|
console.log();
|
|
1306
|
-
console.log(
|
|
1260
|
+
console.log(chalk.white(' Roles completed:'));
|
|
1307
1261
|
for (const c of completedRoleSummaries) {
|
|
1308
|
-
const roleIcon = c.status === 'completed' ?
|
|
1262
|
+
const roleIcon = c.status === 'completed' ? chalk.green('✔') : chalk.red('✘');
|
|
1309
1263
|
const roleSumSnip = c.summary ? ` — ${c.summary.slice(0, 100)}` : '';
|
|
1310
|
-
console.log(
|
|
1264
|
+
console.log(chalk.gray(` ${roleIcon} ${c.role.padEnd(11)}${roleSumSnip}`));
|
|
1311
1265
|
}
|
|
1312
1266
|
console.log();
|
|
1313
|
-
console.log(
|
|
1267
|
+
console.log(chalk.white(' Remaining roles: ') + chalk.gray(remainingRoles.join(', ') || 'none'));
|
|
1314
1268
|
console.log();
|
|
1315
1269
|
const checkpointRl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1316
1270
|
let continueRun = false;
|
|
@@ -1322,14 +1276,14 @@ class LegionCommand {
|
|
|
1322
1276
|
checkpointRl.close();
|
|
1323
1277
|
}
|
|
1324
1278
|
if (!continueRun) {
|
|
1325
|
-
console.log(
|
|
1326
|
-
console.log(
|
|
1279
|
+
console.log(chalk.yellow(' Cortex stopped by user at budget checkpoint.'));
|
|
1280
|
+
console.log(chalk.gray(` State: ${stepsDone} of ${stepsTotal} steps completed.`));
|
|
1327
1281
|
finalStatus = 'failed';
|
|
1328
1282
|
failedStepId = failedStepId || 'user_checkpoint_stop';
|
|
1329
1283
|
// Break out of the for-of lines loop; the outer while(true) will end when reader.read() drains.
|
|
1330
1284
|
break;
|
|
1331
1285
|
}
|
|
1332
|
-
console.log(
|
|
1286
|
+
console.log(chalk.green(' Continuing execution…'));
|
|
1333
1287
|
console.log();
|
|
1334
1288
|
}
|
|
1335
1289
|
break;
|
|
@@ -1351,19 +1305,19 @@ class LegionCommand {
|
|
|
1351
1305
|
if (evt.status === 'completed') {
|
|
1352
1306
|
finalStatus = 'completed';
|
|
1353
1307
|
console.log();
|
|
1354
|
-
console.log(
|
|
1308
|
+
console.log(chalk.green(` ${CH.success} Legion completed successfully`));
|
|
1355
1309
|
}
|
|
1356
1310
|
else if (evt.status === 'failed') {
|
|
1357
1311
|
finalStatus = 'failed';
|
|
1358
1312
|
console.log();
|
|
1359
|
-
console.log(
|
|
1313
|
+
console.log(chalk.red(` ${CH.error} Legion execution failed`));
|
|
1360
1314
|
if (evt.error)
|
|
1361
|
-
console.log(
|
|
1315
|
+
console.log(chalk.red(` Error: ${String(evt.error).slice(0, 300)}`));
|
|
1362
1316
|
}
|
|
1363
1317
|
break;
|
|
1364
1318
|
case 'error':
|
|
1365
1319
|
finalStatus = 'failed';
|
|
1366
|
-
console.log(
|
|
1320
|
+
console.log(chalk.red(` ${CH.error} Stream error: ${String(evt.error).slice(0, 300)}`));
|
|
1367
1321
|
break;
|
|
1368
1322
|
}
|
|
1369
1323
|
}
|
|
@@ -1375,16 +1329,16 @@ class LegionCommand {
|
|
|
1375
1329
|
}
|
|
1376
1330
|
const elapsedSec = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
1377
1331
|
if (stepsTotal > 0 && stepsDone < stepsTotal) {
|
|
1378
|
-
console.log(
|
|
1332
|
+
console.log(chalk.yellow(` ${CH.warn} Legion stream ended after ${stepsDone}/${stepsTotal} steps`));
|
|
1379
1333
|
}
|
|
1380
1334
|
console.log();
|
|
1381
|
-
console.log(
|
|
1335
|
+
console.log(chalk.gray(` Time: ${elapsedSec}s`));
|
|
1382
1336
|
const lastStepResult = finalResult?.final_output;
|
|
1383
1337
|
const summary = String(lastStepResult?.result?.summary || lastStepResult?.summary || '');
|
|
1384
1338
|
if (summary) {
|
|
1385
1339
|
console.log();
|
|
1386
|
-
console.log(
|
|
1387
|
-
console.log(
|
|
1340
|
+
console.log(chalk.white(' Final output:'));
|
|
1341
|
+
console.log(chalk.gray(` ${summary.slice(0, 600)}`));
|
|
1388
1342
|
}
|
|
1389
1343
|
if (cortexExecution) {
|
|
1390
1344
|
const report = this.buildCortexRunReport({
|
|
@@ -1400,8 +1354,8 @@ class LegionCommand {
|
|
|
1400
1354
|
finalSummary: summary,
|
|
1401
1355
|
}, streamEvents);
|
|
1402
1356
|
const files = this.writeCortexSummaryReport(report);
|
|
1403
|
-
console.log(
|
|
1404
|
-
console.log(
|
|
1357
|
+
console.log(chalk.gray(' Cortex summary: ' + files.markdownPath));
|
|
1358
|
+
console.log(chalk.gray(' Cortex report JSON: ' + files.jsonPath));
|
|
1405
1359
|
}
|
|
1406
1360
|
console.log();
|
|
1407
1361
|
return {
|
|
@@ -1487,7 +1441,7 @@ class LegionCommand {
|
|
|
1487
1441
|
return `${context} failed: ${message}${cause}`;
|
|
1488
1442
|
}
|
|
1489
1443
|
async showWorkers() {
|
|
1490
|
-
const spinner =
|
|
1444
|
+
const spinner = createSpinner('Fetching Legion worker catalog...').start();
|
|
1491
1445
|
let lastError = null;
|
|
1492
1446
|
for (const baseUrl of this.getHyperloopUrls()) {
|
|
1493
1447
|
try {
|
|
@@ -1500,34 +1454,34 @@ class LegionCommand {
|
|
|
1500
1454
|
this.logger.warn(this.formatLegionError(`worker catalog error body at ${baseUrl}`, err));
|
|
1501
1455
|
return '';
|
|
1502
1456
|
});
|
|
1503
|
-
lastError = `Legion worker catalog request at ${baseUrl} failed: ${response.status} ${
|
|
1457
|
+
lastError = `Legion worker catalog request at ${baseUrl} failed: ${response.status} ${describeUpstreamStatus(response.status)}${errBody ? ` — ${errBody.slice(0, 200)}` : ''}`;
|
|
1504
1458
|
continue;
|
|
1505
1459
|
}
|
|
1506
1460
|
const data = await this.readJsonResponse(response, `worker catalog request at ${baseUrl}`);
|
|
1507
1461
|
spinner.stop();
|
|
1508
1462
|
console.log();
|
|
1509
|
-
console.log(
|
|
1463
|
+
console.log(chalk.bold.white(` ${CH.hLine.repeat(3)} Legion Worker Catalog ${CH.hLine.repeat(37)}`));
|
|
1510
1464
|
console.log();
|
|
1511
1465
|
const workers = data.workers || data.catalog || data;
|
|
1512
1466
|
if (Array.isArray(workers)) {
|
|
1513
1467
|
for (const w of workers) {
|
|
1514
1468
|
const wObj = w;
|
|
1515
|
-
const statusColor = wObj.status === 'active' ?
|
|
1516
|
-
console.log(` ${statusColor(
|
|
1469
|
+
const statusColor = wObj.status === 'active' ? chalk.green : chalk.yellow;
|
|
1470
|
+
console.log(` ${statusColor(CH.bullet)} ${chalk.white(wObj.name || wObj.worker || 'unknown')} ${chalk.gray(wObj.description || '')}`);
|
|
1517
1471
|
if (wObj.status) {
|
|
1518
|
-
console.log(
|
|
1472
|
+
console.log(chalk.gray(` Status: ${wObj.status}`));
|
|
1519
1473
|
}
|
|
1520
1474
|
}
|
|
1521
1475
|
}
|
|
1522
1476
|
else if (typeof workers === 'object') {
|
|
1523
1477
|
for (const [name, info] of Object.entries(workers)) {
|
|
1524
1478
|
const infoObj = info;
|
|
1525
|
-
const statusColor = infoObj.maturity === 'active' ?
|
|
1526
|
-
console.log(` ${statusColor(
|
|
1479
|
+
const statusColor = infoObj.maturity === 'active' ? chalk.green : chalk.yellow;
|
|
1480
|
+
console.log(` ${statusColor(CH.bullet)} ${chalk.white(name)} ${chalk.gray(infoObj.description || '')}`);
|
|
1527
1481
|
if (infoObj.maturity)
|
|
1528
|
-
console.log(
|
|
1482
|
+
console.log(chalk.gray(` Maturity: ${infoObj.maturity}`));
|
|
1529
1483
|
if (infoObj.domains)
|
|
1530
|
-
console.log(
|
|
1484
|
+
console.log(chalk.gray(` Domains: ${Array.isArray(infoObj.domains) ? infoObj.domains.join(', ') : infoObj.domains}`));
|
|
1531
1485
|
}
|
|
1532
1486
|
}
|
|
1533
1487
|
console.log();
|
|
@@ -1542,7 +1496,7 @@ class LegionCommand {
|
|
|
1542
1496
|
this.logger.error(lastError || 'Could not reach Hyper Loop. Is vigthoria-hyper-loop running?');
|
|
1543
1497
|
}
|
|
1544
1498
|
async showStatus() {
|
|
1545
|
-
const spinner =
|
|
1499
|
+
const spinner = createSpinner('Checking Legion infrastructure...').start();
|
|
1546
1500
|
let lastError = null;
|
|
1547
1501
|
for (const baseUrl of this.getHyperloopUrls()) {
|
|
1548
1502
|
try {
|
|
@@ -1551,25 +1505,25 @@ class LegionCommand {
|
|
|
1551
1505
|
headers: this.getHeaders(),
|
|
1552
1506
|
});
|
|
1553
1507
|
if (!response.ok) {
|
|
1554
|
-
lastError = `Legion status check at ${baseUrl} failed: ${response.status} ${
|
|
1508
|
+
lastError = `Legion status check at ${baseUrl} failed: ${response.status} ${describeUpstreamStatus(response.status)}`;
|
|
1555
1509
|
continue;
|
|
1556
1510
|
}
|
|
1557
1511
|
const data = await this.readJsonResponse(response, `status check at ${baseUrl}`);
|
|
1558
1512
|
spinner.stop();
|
|
1559
1513
|
console.log();
|
|
1560
|
-
console.log(
|
|
1514
|
+
console.log(chalk.bold.white(` ${CH.hLine.repeat(3)} Legion Infrastructure ${CH.hLine.repeat(37)}`));
|
|
1561
1515
|
console.log();
|
|
1562
|
-
console.log(
|
|
1516
|
+
console.log(chalk.gray(` Hyper Loop: `) + chalk.green('online'));
|
|
1563
1517
|
if (data.workers || data.active_workers) {
|
|
1564
1518
|
const count = data.workers || data.active_workers;
|
|
1565
|
-
console.log(
|
|
1519
|
+
console.log(chalk.gray(` Active workers: `) + chalk.white(String(typeof count === 'number' ? count : Object.keys(count).length)));
|
|
1566
1520
|
}
|
|
1567
1521
|
if (data.remotes || data.infrastructure) {
|
|
1568
1522
|
const remotes = data.remotes || data.infrastructure;
|
|
1569
1523
|
if (typeof remotes === 'object') {
|
|
1570
1524
|
for (const [name, status] of Object.entries(remotes)) {
|
|
1571
|
-
const icon = status?.reachable ?
|
|
1572
|
-
console.log(` ${icon} ${
|
|
1525
|
+
const icon = status?.reachable ? chalk.green(CH.success) : chalk.red(CH.error);
|
|
1526
|
+
console.log(` ${icon} ${chalk.white(name)}`);
|
|
1573
1527
|
}
|
|
1574
1528
|
}
|
|
1575
1529
|
}
|
|
@@ -1583,11 +1537,10 @@ class LegionCommand {
|
|
|
1583
1537
|
}
|
|
1584
1538
|
spinner.stop();
|
|
1585
1539
|
console.log();
|
|
1586
|
-
console.log(
|
|
1540
|
+
console.log(chalk.gray(' Hyper Loop: ') + chalk.red('offline'));
|
|
1587
1541
|
if (lastError) {
|
|
1588
1542
|
this.logger.error(lastError);
|
|
1589
1543
|
}
|
|
1590
1544
|
console.log();
|
|
1591
1545
|
}
|
|
1592
1546
|
}
|
|
1593
|
-
exports.LegionCommand = LegionCommand;
|