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/legion.js
CHANGED
|
@@ -15,7 +15,9 @@ import * as readline from 'readline/promises';
|
|
|
15
15
|
import { exec as execCallback } from 'node:child_process';
|
|
16
16
|
import { promisify } from 'node:util';
|
|
17
17
|
import { createSpinner, CH } from '../utils/logger.js';
|
|
18
|
-
import { describeUpstreamStatus,
|
|
18
|
+
import { describeUpstreamStatus, propagateError } from '../utils/api.js';
|
|
19
|
+
import { hasLoopbackServiceCapability } from '../utils/runtime-capability.js';
|
|
20
|
+
import { CliCommandError } from '../utils/command-contract.js';
|
|
19
21
|
// Hyper Loop / Legion runs on the Vigthoria backend only. Local user installs
|
|
20
22
|
// must never even attempt these endpoints, because fetch errors include the
|
|
21
23
|
// URL we tried (would leak internal infra to the user's terminal).
|
|
@@ -31,9 +33,6 @@ function buildServerHyperloopUrls() {
|
|
|
31
33
|
`http://${internalHost}:${port}${apiPath}`,
|
|
32
34
|
];
|
|
33
35
|
}
|
|
34
|
-
const HYPERLOOP_URLS = isServerRuntime()
|
|
35
|
-
? buildServerHyperloopUrls()
|
|
36
|
-
: (process.env.VIGTHORIA_HYPERLOOP_URL ? [process.env.VIGTHORIA_HYPERLOOP_URL] : []);
|
|
37
36
|
const CORTEX_WARN_BUDGET_USD = 3.5;
|
|
38
37
|
const CORTEX_HARD_BUDGET_USD = 5.0;
|
|
39
38
|
const CORTEX_MAX_ROUNDS = 2;
|
|
@@ -57,7 +56,7 @@ export class LegionCommand {
|
|
|
57
56
|
};
|
|
58
57
|
// On-server checks must try loopback first. The former configured 10.0.0.2
|
|
59
58
|
// route could consume the entire timeout while the same node was healthy.
|
|
60
|
-
if (
|
|
59
|
+
if (hasLoopbackServiceCapability()) {
|
|
61
60
|
for (const internal of buildServerHyperloopUrls()) {
|
|
62
61
|
const normalized = normalizeBase(internal);
|
|
63
62
|
if (normalized)
|
|
@@ -109,20 +108,6 @@ export class LegionCommand {
|
|
|
109
108
|
});
|
|
110
109
|
}
|
|
111
110
|
}
|
|
112
|
-
propagateLegionApiError(context, endpoint, err) {
|
|
113
|
-
const original = err && typeof err === 'object' ? err : { message: String(err) };
|
|
114
|
-
propagateError({
|
|
115
|
-
...original,
|
|
116
|
-
commandName: 'legion',
|
|
117
|
-
endpoint: original.endpoint || original?.config?.url || original?.details?.endpoint || endpoint || context,
|
|
118
|
-
details: {
|
|
119
|
-
...(original.details && typeof original.details === 'object' ? original.details : {}),
|
|
120
|
-
command: 'legion',
|
|
121
|
-
endpoint: original.endpoint || original?.config?.url || original?.details?.endpoint || endpoint || context,
|
|
122
|
-
context,
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
111
|
async run(request, options) {
|
|
127
112
|
if (options.cortex) {
|
|
128
113
|
await this.runCortex(request, options);
|
|
@@ -137,38 +122,32 @@ export class LegionCommand {
|
|
|
137
122
|
return;
|
|
138
123
|
}
|
|
139
124
|
if (!request) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
125
|
+
throw new CliCommandError('Usage: vigthoria legion "<task description>" (or use --workers, --status, or --cortex).', {
|
|
126
|
+
code: 'LEGION_REQUEST_REQUIRED', category: 'usage',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const execution = await this.planAndExecute(request, options);
|
|
130
|
+
if (execution.status !== 'completed') {
|
|
131
|
+
throw new CliCommandError(execution.finalSummary || 'Legion execution failed.', {
|
|
132
|
+
code: 'LEGION_EXECUTION_FAILED',
|
|
133
|
+
details: execution,
|
|
134
|
+
});
|
|
145
135
|
}
|
|
146
|
-
await this.planAndExecute(request, options);
|
|
147
136
|
}
|
|
148
137
|
async runCortex(request, options) {
|
|
149
138
|
if (!request) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
console.log(chalk.gray(' --ignore-preflight Bypass mandatory preflight checks (no warranty)'));
|
|
154
|
-
console.log(chalk.gray(' --speed Speed mode: optional role skip on convergence'));
|
|
155
|
-
console.log(chalk.gray(' --tier heavy|lite Model tier: heavy=strongest LLMs (default), lite=efficient+affordable'));
|
|
156
|
-
console.log(chalk.gray(' --repro-cmd <cmd> Run a local reproducibility command before spend'));
|
|
157
|
-
console.log(chalk.gray(' --expect-repro-fail Require repro command to fail before execution'));
|
|
158
|
-
console.log(chalk.gray(' --approve Skip initial confirmation prompt and execute'));
|
|
159
|
-
console.log(chalk.gray(' --auto-charge Charge the canonical PAYG wallet when balance is sufficient'));
|
|
160
|
-
console.log(chalk.gray(' --timeout <sec> Abort remote execution if no result within timeout (default: 120)'));
|
|
161
|
-
return;
|
|
139
|
+
throw new CliCommandError('Usage: vigthoria legion --cortex "<task description>".', {
|
|
140
|
+
code: 'CORTEX_REQUEST_REQUIRED', category: 'usage',
|
|
141
|
+
});
|
|
162
142
|
}
|
|
163
143
|
const workspace = options.project || process.cwd();
|
|
164
144
|
const scan = this.scanProject(workspace);
|
|
165
145
|
if (!options.ignorePreflight) {
|
|
166
146
|
const preflight = await this.runMandatoryPreflight(workspace, options.reproCmd, options.expectReproFail === true);
|
|
167
147
|
if (!preflight.ok) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return;
|
|
148
|
+
throw new CliCommandError(`Cortex preflight failed: ${preflight.reason}`, {
|
|
149
|
+
code: 'CORTEX_PREFLIGHT_FAILED', details: preflight,
|
|
150
|
+
});
|
|
172
151
|
}
|
|
173
152
|
console.log(chalk.green('Preflight passed.'));
|
|
174
153
|
}
|
|
@@ -185,9 +164,9 @@ export class LegionCommand {
|
|
|
185
164
|
let billingGate = await this.evaluateBillingGate(billingQuote);
|
|
186
165
|
this.printCortexQuote(workspace, scan, quote, billingQuote, billingGate);
|
|
187
166
|
if (billingQuote.retryAdjustedUsd > CORTEX_HARD_BUDGET_USD && !options.forceBudget && !billingGate.masterAdminFree) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
167
|
+
throw new CliCommandError(`Estimated spend exceeds hard budget ceiling (${CORTEX_HARD_BUDGET_USD.toFixed(2)}). Re-run with --force-budget to continue.`, {
|
|
168
|
+
code: 'CORTEX_BUDGET_EXCEEDED', category: 'authorization', details: billingQuote,
|
|
169
|
+
});
|
|
191
170
|
}
|
|
192
171
|
if (options.planOnly) {
|
|
193
172
|
console.log(chalk.green('Cortex estimator complete (plan-only).'));
|
|
@@ -196,8 +175,7 @@ export class LegionCommand {
|
|
|
196
175
|
const autoApprove = options.approve === true && options.noApprove !== true;
|
|
197
176
|
const approved = autoApprove ? true : await this.confirmExecution();
|
|
198
177
|
if (!approved) {
|
|
199
|
-
|
|
200
|
-
return;
|
|
178
|
+
throw new CliCommandError('Cortex cancelled by user.', { code: 'CORTEX_CANCELLED', category: 'cancelled' });
|
|
201
179
|
}
|
|
202
180
|
let round = 1;
|
|
203
181
|
let cumulativeUsd = 0;
|
|
@@ -207,20 +185,23 @@ export class LegionCommand {
|
|
|
207
185
|
if (!billingGate.canProceed) {
|
|
208
186
|
const resolved = await this.resolveBillingInsufficientFunds(currentQuote, billingGate, options);
|
|
209
187
|
if (!resolved) {
|
|
210
|
-
|
|
211
|
-
|
|
188
|
+
throw new CliCommandError('Cortex blocked by insufficient PAYG credit balance.', {
|
|
189
|
+
code: 'CORTEX_INSUFFICIENT_CREDIT', category: 'authorization', details: billingGate,
|
|
190
|
+
});
|
|
212
191
|
}
|
|
213
192
|
billingGate = await this.evaluateBillingGate(currentQuote);
|
|
214
193
|
if (!billingGate.canProceed) {
|
|
215
194
|
this.printBillingGateSummary(currentQuote, billingGate);
|
|
216
|
-
|
|
217
|
-
|
|
195
|
+
throw new CliCommandError('Billing gate remains blocked after the charge attempt.', {
|
|
196
|
+
code: 'CORTEX_BILLING_BLOCKED', category: 'authorization', details: billingGate,
|
|
197
|
+
});
|
|
218
198
|
}
|
|
219
199
|
}
|
|
220
200
|
const charged = await this.collectExecutionCharge(currentQuote, billingGate);
|
|
221
201
|
if (!charged) {
|
|
222
|
-
|
|
223
|
-
|
|
202
|
+
throw new CliCommandError('Cortex wallet charge was not completed.', {
|
|
203
|
+
code: 'CORTEX_CHARGE_INCOMPLETE', category: 'authorization',
|
|
204
|
+
});
|
|
224
205
|
}
|
|
225
206
|
cumulativeUsd += currentQuote.finalUsd;
|
|
226
207
|
const enrichedRequest = [
|
|
@@ -246,28 +227,32 @@ export class LegionCommand {
|
|
|
246
227
|
}
|
|
247
228
|
const failedRole = String(execution.failedStepId || '').toLowerCase();
|
|
248
229
|
if (this.isCriticalRoleFailure(failedRole)) {
|
|
249
|
-
|
|
250
|
-
|
|
230
|
+
throw new CliCommandError(`Critical Cortex role '${failedRole || 'unknown'}' failed. Manual correction is required.`, {
|
|
231
|
+
code: 'CORTEX_CRITICAL_ROLE_FAILED', details: execution,
|
|
232
|
+
});
|
|
251
233
|
}
|
|
252
234
|
if (!this.isOptionalRepairRoleFailure(failedRole)) {
|
|
253
|
-
|
|
254
|
-
|
|
235
|
+
throw new CliCommandError('Cortex execution failed and is not eligible for automatic optional-role repair.', {
|
|
236
|
+
code: 'CORTEX_EXECUTION_FAILED', details: execution,
|
|
237
|
+
});
|
|
255
238
|
}
|
|
256
239
|
if (round >= CORTEX_MAX_ROUNDS) {
|
|
257
|
-
|
|
258
|
-
|
|
240
|
+
throw new CliCommandError('Cortex optional-role auto-repair budget is exhausted.', {
|
|
241
|
+
code: 'CORTEX_REPAIR_EXHAUSTED', details: execution,
|
|
242
|
+
});
|
|
259
243
|
}
|
|
260
244
|
const nextQuote = this.estimateAdditionalLoopQuote(currentQuote, execution);
|
|
261
245
|
const projectedTotal = cumulativeUsd + nextQuote.retryAdjustedUsd;
|
|
262
246
|
if (projectedTotal > CORTEX_HARD_BUDGET_USD && !options.forceBudget) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
247
|
+
throw new CliCommandError(`Additional Cortex loop would exceed hard budget ceiling ($${CORTEX_HARD_BUDGET_USD.toFixed(2)}).`, {
|
|
248
|
+
code: 'CORTEX_BUDGET_EXCEEDED', category: 'authorization', details: { projectedTotal },
|
|
249
|
+
});
|
|
266
250
|
}
|
|
267
251
|
const continueApproved = await this.confirmAdditionalLoopCharge(nextQuote, round + 1, execution);
|
|
268
252
|
if (!continueApproved) {
|
|
269
|
-
|
|
270
|
-
|
|
253
|
+
throw new CliCommandError('Cortex cancelled because the user declined additional budget.', {
|
|
254
|
+
code: 'CORTEX_CANCELLED', category: 'cancelled',
|
|
255
|
+
});
|
|
271
256
|
}
|
|
272
257
|
currentQuote = nextQuote;
|
|
273
258
|
billingGate = await this.evaluateBillingGate(currentQuote);
|
|
@@ -1105,7 +1090,7 @@ export class LegionCommand {
|
|
|
1105
1090
|
const envOverride = String(process.env.VIGTHORIA_HYPERLOOP_URL || '').trim();
|
|
1106
1091
|
if (envOverride)
|
|
1107
1092
|
return `${normalizeBase(envOverride)}/legion/stream`;
|
|
1108
|
-
if (
|
|
1093
|
+
if (hasLoopbackServiceCapability()) {
|
|
1109
1094
|
return 'http://localhost:8020/api/hyperloop/legion/stream';
|
|
1110
1095
|
}
|
|
1111
1096
|
const configuredApiUrl = String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').trim();
|
|
@@ -1151,27 +1136,26 @@ export class LegionCommand {
|
|
|
1151
1136
|
const startTime = Date.now();
|
|
1152
1137
|
let response;
|
|
1153
1138
|
try {
|
|
1139
|
+
const executionTimeoutMs = Math.max(1, Number(options.timeoutSec || 120)) * 1000;
|
|
1154
1140
|
response = await fetch(streamUrl, {
|
|
1155
1141
|
method: 'POST',
|
|
1156
1142
|
headers,
|
|
1157
1143
|
body: JSON.stringify(body),
|
|
1144
|
+
signal: AbortSignal.timeout(executionTimeoutMs),
|
|
1158
1145
|
});
|
|
1159
1146
|
}
|
|
1160
1147
|
catch (connErr) {
|
|
1161
1148
|
spinner.stop();
|
|
1162
|
-
|
|
1163
|
-
return { status: 'failed', plannedSteps: 0, completedSteps: 0 };
|
|
1149
|
+
return { status: 'failed', plannedSteps: 0, completedSteps: 0, finalSummary: `Cannot connect to Hyper Loop: ${connErr?.message || connErr}` };
|
|
1164
1150
|
}
|
|
1165
1151
|
if (!response.ok) {
|
|
1166
1152
|
spinner.stop();
|
|
1167
1153
|
const errBody = await response.text().catch(() => '');
|
|
1168
|
-
|
|
1169
|
-
return { status: 'failed', plannedSteps: 0, completedSteps: 0 };
|
|
1154
|
+
return { status: 'failed', plannedSteps: 0, completedSteps: 0, finalSummary: `Legion stream ${response.status}: ${describeUpstreamStatus(response.status)} — ${errBody.slice(0, 200)}` };
|
|
1170
1155
|
}
|
|
1171
1156
|
if (!response.body) {
|
|
1172
1157
|
spinner.stop();
|
|
1173
|
-
|
|
1174
|
-
return { status: 'failed', plannedSteps: 0, completedSteps: 0 };
|
|
1158
|
+
return { status: 'failed', plannedSteps: 0, completedSteps: 0, finalSummary: 'Legion stream returned no response body' };
|
|
1175
1159
|
}
|
|
1176
1160
|
spinner.stop();
|
|
1177
1161
|
console.log();
|
|
@@ -1330,8 +1314,8 @@ export class LegionCommand {
|
|
|
1330
1314
|
}
|
|
1331
1315
|
}
|
|
1332
1316
|
catch (streamErr) {
|
|
1333
|
-
this.logger.error(`Legion stream read error: ${streamErr?.message || streamErr}`);
|
|
1334
1317
|
finalStatus = 'failed';
|
|
1318
|
+
finalResult = { ...(finalResult || {}), stream_error: String(streamErr?.message || streamErr) };
|
|
1335
1319
|
}
|
|
1336
1320
|
const elapsedSec = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
1337
1321
|
if (stepsTotal > 0 && stepsDone < stepsTotal) {
|
|
@@ -1370,7 +1354,7 @@ export class LegionCommand {
|
|
|
1370
1354
|
completedSteps: stepsDone,
|
|
1371
1355
|
failedStepId: failedStepId || undefined,
|
|
1372
1356
|
failedWorker: failedWorker || undefined,
|
|
1373
|
-
finalSummary: summary || undefined,
|
|
1357
|
+
finalSummary: summary || String(finalResult?.stream_error || '') || undefined,
|
|
1374
1358
|
};
|
|
1375
1359
|
}
|
|
1376
1360
|
buildCortexRunReport(base, streamEvents) {
|
|
@@ -1499,7 +1483,9 @@ export class LegionCommand {
|
|
|
1499
1483
|
}
|
|
1500
1484
|
}
|
|
1501
1485
|
spinner.stop();
|
|
1502
|
-
|
|
1486
|
+
throw new CliCommandError(lastError || 'Could not reach Hyper Loop.', {
|
|
1487
|
+
code: 'LEGION_WORKERS_UNAVAILABLE', category: 'network',
|
|
1488
|
+
});
|
|
1503
1489
|
}
|
|
1504
1490
|
async showStatus() {
|
|
1505
1491
|
const spinner = createSpinner('Checking Legion infrastructure...').start();
|
|
@@ -1565,11 +1551,8 @@ export class LegionCommand {
|
|
|
1565
1551
|
}
|
|
1566
1552
|
}
|
|
1567
1553
|
spinner.stop();
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
this.logger.error(lastError);
|
|
1572
|
-
}
|
|
1573
|
-
console.log();
|
|
1554
|
+
throw new CliCommandError(lastError || 'Hyper Loop is offline.', {
|
|
1555
|
+
code: 'LEGION_STATUS_UNAVAILABLE', category: 'network',
|
|
1556
|
+
});
|
|
1574
1557
|
}
|
|
1575
1558
|
}
|
package/dist/commands/music.d.ts
CHANGED
|
@@ -18,8 +18,7 @@ type MusicStatusOptions = {
|
|
|
18
18
|
};
|
|
19
19
|
export declare class MusicCommand {
|
|
20
20
|
private config;
|
|
21
|
-
|
|
22
|
-
constructor(config: Config, logger: Logger);
|
|
21
|
+
constructor(config: Config, _logger: Logger);
|
|
23
22
|
private apiBase;
|
|
24
23
|
private authHeaders;
|
|
25
24
|
private request;
|
package/dist/commands/music.js
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
+
import { guardedFetch } from '../utils/network-policy.js';
|
|
5
|
+
import { CliCommandError, commandFailure, formatSuccessJson } from '../utils/command-contract.js';
|
|
6
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
4
7
|
export class MusicCommand {
|
|
5
8
|
config;
|
|
6
|
-
|
|
7
|
-
constructor(config, logger) {
|
|
9
|
+
constructor(config, _logger) {
|
|
8
10
|
this.config = config;
|
|
9
|
-
this.logger = logger;
|
|
10
11
|
}
|
|
11
12
|
apiBase() {
|
|
12
13
|
const configured = String(this.config.getAll().musicApiUrl || '').trim();
|
|
13
14
|
return (process.env.VIGTHORIA_MUSIC_API_URL || configured || 'https://music.vigthoria.io').replace(/\/+$/, '');
|
|
14
15
|
}
|
|
15
16
|
authHeaders() {
|
|
16
|
-
const token = this.config.get('authToken');
|
|
17
|
+
const token = process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN || this.config.get('authToken');
|
|
17
18
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
18
19
|
}
|
|
19
20
|
async request(endpoint, init = {}) {
|
|
20
|
-
const response = await
|
|
21
|
+
const response = await guardedFetch(`${this.apiBase()}${endpoint}`, {
|
|
21
22
|
...init,
|
|
22
23
|
headers: {
|
|
23
24
|
...this.authHeaders(),
|
|
24
25
|
...init.headers,
|
|
25
26
|
},
|
|
26
|
-
});
|
|
27
|
+
}, { audience: 'music' });
|
|
27
28
|
const text = await response.text();
|
|
28
29
|
let data = {};
|
|
29
30
|
try {
|
|
@@ -58,7 +59,7 @@ export class MusicCommand {
|
|
|
58
59
|
async generate(promptArg, options) {
|
|
59
60
|
const prompt = String(promptArg || options.prompt || '').trim();
|
|
60
61
|
if (!prompt) {
|
|
61
|
-
throw new
|
|
62
|
+
throw new CliCommandError('Music generation requires a prompt.', { code: 'MUSIC_PROMPT_REQUIRED', category: 'usage' });
|
|
62
63
|
}
|
|
63
64
|
let referenceAudioPath = '';
|
|
64
65
|
if (options.voice) {
|
|
@@ -88,10 +89,7 @@ export class MusicCommand {
|
|
|
88
89
|
body: JSON.stringify(payload),
|
|
89
90
|
});
|
|
90
91
|
const taskId = String(data.task_id || data.session_id || '').trim();
|
|
91
|
-
if (options.json) {
|
|
92
|
-
console.log(JSON.stringify({ ...data, task_id: taskId || data.task_id }, null, 2));
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
92
|
+
if (!options.json) {
|
|
95
93
|
console.log(chalk.green('Music generation queued.'));
|
|
96
94
|
console.log(chalk.cyan('Task ID: ') + (taskId || '(pending)'));
|
|
97
95
|
if (data.queue_position)
|
|
@@ -100,13 +98,18 @@ export class MusicCommand {
|
|
|
100
98
|
console.log(chalk.gray(`Estimated wait: ${data.estimated_wait_seconds}s`));
|
|
101
99
|
}
|
|
102
100
|
if (options.wait && taskId) {
|
|
103
|
-
await this.waitForStatus(taskId, Number(options.pollInterval || 5),
|
|
101
|
+
const terminal = await this.waitForStatus(taskId, Number(options.pollInterval || 5), options.json === true);
|
|
102
|
+
if (options.json)
|
|
103
|
+
console.log(formatSuccessJson('music generate', terminal, { stage: 'terminal' }));
|
|
104
|
+
return;
|
|
104
105
|
}
|
|
106
|
+
if (options.json)
|
|
107
|
+
console.log(formatSuccessJson('music generate', { ...data, task_id: taskId || data.task_id }, { stage: 'queued' }));
|
|
105
108
|
}
|
|
106
109
|
async status(taskId, options = {}) {
|
|
107
110
|
const data = await this.request(`/api/status/${encodeURIComponent(taskId)}`);
|
|
108
111
|
if (options.json) {
|
|
109
|
-
console.log(
|
|
112
|
+
console.log(formatSuccessJson('music status', data));
|
|
110
113
|
return;
|
|
111
114
|
}
|
|
112
115
|
console.log(chalk.cyan(`Music task ${taskId}`));
|
|
@@ -117,21 +120,53 @@ export class MusicCommand {
|
|
|
117
120
|
if (downloadUrl)
|
|
118
121
|
console.log(`Download: ${downloadUrl}`);
|
|
119
122
|
}
|
|
120
|
-
async waitForStatus(taskId, intervalSeconds,
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
123
|
+
async waitForStatus(taskId, intervalSeconds, quiet) {
|
|
124
|
+
const pollDelayMs = Math.max(1, intervalSeconds) * 1000;
|
|
125
|
+
const configuredTimeout = Number.parseInt(process.env.VIGTHORIA_MUSIC_WAIT_TIMEOUT_MS || '', 10);
|
|
126
|
+
const timeoutMs = Number.isFinite(configuredTimeout) && configuredTimeout > 0 ? configuredTimeout : 30 * 60_000;
|
|
127
|
+
const deadline = Date.now() + timeoutMs;
|
|
128
|
+
const cancellation = new AbortController();
|
|
129
|
+
let interrupted = false;
|
|
130
|
+
const onInterrupt = () => {
|
|
131
|
+
interrupted = true;
|
|
132
|
+
cancellation.abort();
|
|
133
|
+
};
|
|
134
|
+
process.once('SIGINT', onInterrupt);
|
|
135
|
+
try {
|
|
136
|
+
for (;;) {
|
|
137
|
+
if (Date.now() >= deadline) {
|
|
138
|
+
throw new CliCommandError(`Music generation did not finish within ${timeoutMs}ms.`, {
|
|
139
|
+
code: 'MUSIC_WAIT_TIMEOUT', category: 'network', details: { taskId, timeoutMs },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
await delay(Math.min(pollDelayMs, Math.max(1, deadline - Date.now())), undefined, { signal: cancellation.signal });
|
|
143
|
+
const data = await this.request(`/api/status/${encodeURIComponent(taskId)}`, { signal: cancellation.signal });
|
|
144
|
+
const status = String(data.status || '').toLowerCase();
|
|
145
|
+
if (!quiet) {
|
|
146
|
+
const progress = data.progress !== undefined ? ` (${data.progress}%)` : '';
|
|
147
|
+
console.log(chalk.gray(`Status: ${status || 'unknown'}${progress}`));
|
|
148
|
+
}
|
|
149
|
+
if (['failed', 'error'].includes(status)) {
|
|
150
|
+
throw new CliCommandError(String(data.error || data.message || 'Music generation failed.'), {
|
|
151
|
+
code: 'MUSIC_GENERATION_FAILED', details: data,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (status === 'cancelled') {
|
|
155
|
+
throw new CliCommandError('Music generation was cancelled.', {
|
|
156
|
+
code: 'MUSIC_GENERATION_CANCELLED', category: 'cancelled', details: data,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (['completed', 'complete', 'finished'].includes(status))
|
|
160
|
+
return data;
|
|
134
161
|
}
|
|
135
162
|
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (interrupted)
|
|
165
|
+
throw new CliCommandError('Music wait cancelled by user.', { code: 'MUSIC_WAIT_CANCELLED', category: 'cancelled', cause: error });
|
|
166
|
+
throw commandFailure(error, { code: 'MUSIC_WAIT_FAILED' });
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
process.removeListener('SIGINT', onInterrupt);
|
|
170
|
+
}
|
|
136
171
|
}
|
|
137
172
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BridgeCommand } from './bridge.js';
|
|
2
|
+
import { DeviceCommand } from './device.js';
|
|
3
|
+
import { SecurityCommand } from './security.js';
|
|
4
|
+
export function registerPlatformCommands(program, config, logger) {
|
|
5
|
+
program.command('bridge').description('Inspect local DevTools Bridge availability for browser debugging tasks')
|
|
6
|
+
.command('status').description('Show live DevTools Bridge status')
|
|
7
|
+
.action(async () => new BridgeCommand(config, logger).status());
|
|
8
|
+
const device = program.command('device').alias('adb').description('Android Developer Bridge commands via local ADB');
|
|
9
|
+
device.command('status').description('Show ADB availability and connected Android devices').option('--json', 'Emit JSON output', false)
|
|
10
|
+
.action(async (options) => new DeviceCommand(config, logger).status(options));
|
|
11
|
+
device.command('list').description('List connected Android devices').option('--json', 'Emit JSON output', false)
|
|
12
|
+
.action(async (options) => new DeviceCommand(config, logger).list(options));
|
|
13
|
+
device.command('screenshot').description('Capture a screenshot from an Android device')
|
|
14
|
+
.option('-d, --device <id>', 'ADB device id').option('-o, --output <path>', 'Output PNG path')
|
|
15
|
+
.action(async (options) => new DeviceCommand(config, logger).screenshot(options));
|
|
16
|
+
device.command('install <apk>').description('Install or update an APK on an Android device')
|
|
17
|
+
.option('-d, --device <id>', 'ADB device id').option('--json', 'Emit JSON output', false)
|
|
18
|
+
.action(async (apk, options) => new DeviceCommand(config, logger).install(apk, options));
|
|
19
|
+
device.command('launch <package>').description('Launch an Android app by package name')
|
|
20
|
+
.option('-d, --device <id>', 'ADB device id').option('-a, --activity <activity>', 'Activity class, for example .MainActivity')
|
|
21
|
+
.option('--json', 'Emit JSON output', false)
|
|
22
|
+
.action(async (packageName, options) => new DeviceCommand(config, logger).launch(packageName, options));
|
|
23
|
+
device.command('logs').description('Read Android logcat output').option('-d, --device <id>', 'ADB device id')
|
|
24
|
+
.option('-n, --lines <count>', 'Number of log lines for snapshot mode', '250').option('-f, --follow', 'Follow logcat until interrupted', false)
|
|
25
|
+
.option('--json', 'Emit JSON output for snapshot mode', false)
|
|
26
|
+
.action(async (options) => new DeviceCommand(config, logger).logs(options));
|
|
27
|
+
device.command('tcpip').description('Enable wireless ADB tcpip mode on the selected USB-connected device')
|
|
28
|
+
.option('-d, --device <id>', 'ADB device id').option('-p, --port <port>', 'Wireless ADB port', '5555')
|
|
29
|
+
.option('--json', 'Emit JSON output', false).action(async (options) => new DeviceCommand(config, logger).tcpip(options));
|
|
30
|
+
device.command('connect <address>').description('Connect to a wireless ADB device, for example 192.168.1.30:5555')
|
|
31
|
+
.option('--json', 'Emit JSON output', false).action(async (address, options) => new DeviceCommand(config, logger).connect(address, options));
|
|
32
|
+
device.command('disconnect [address]').description('Disconnect a wireless ADB device')
|
|
33
|
+
.option('--json', 'Emit JSON output', false).action(async (address, options) => new DeviceCommand(config, logger).disconnect(address, options));
|
|
34
|
+
device.action(async () => new DeviceCommand(config, logger).status({}));
|
|
35
|
+
const security = program.command('security').alias('vsec')
|
|
36
|
+
.description('Run security scans, scores, and fix plans via Vigthoria MCP security tools');
|
|
37
|
+
security.command('scan').description('Scan project for security issues').option('-d, --dir <path>', 'Directory to scan (default: current directory)')
|
|
38
|
+
.option('--json', 'Emit JSON output', false).action(async (options) => new SecurityCommand(config, logger).scan({ dir: options.dir, json: options.json }));
|
|
39
|
+
security.command('score').description('Calculate project security score').option('-d, --dir <path>', 'Directory to score (default: current directory)')
|
|
40
|
+
.option('--json', 'Emit JSON output', false).action(async (options) => new SecurityCommand(config, logger).score({ dir: options.dir, json: options.json }));
|
|
41
|
+
security.command('fix').description('Generate security fix plan').option('-d, --dir <path>', 'Directory to inspect (default: current directory)')
|
|
42
|
+
.option('-i, --issue-id <id>', 'Single issue id to target').option('--apply', 'Request auto-apply mode (safe mode still requires explicit patching)', false)
|
|
43
|
+
.option('--json', 'Emit JSON output', false)
|
|
44
|
+
.action(async (options) => new SecurityCommand(config, logger).fix({ dir: options.dir, issueId: options.issueId, apply: options.apply, json: options.json }));
|
|
45
|
+
}
|