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
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EditCommand } from './edit.js';
|
|
2
|
+
import { ExplainCommand } from './explain.js';
|
|
3
|
+
import { GenerateCommand } from './generate.js';
|
|
4
|
+
import { ReviewCommand } from './review.js';
|
|
5
|
+
export function registerCodingCommands(program, config, logger) {
|
|
6
|
+
program.command('edit <file>').alias('e').description('Edit a file with AI assistance')
|
|
7
|
+
.option('-i, --instruction <text>', 'Editing instruction').option('-m, --model <model>', 'Select AI model', 'code')
|
|
8
|
+
.option('--apply', 'Automatically apply changes without confirmation', false)
|
|
9
|
+
.action(async (file, options) => new EditCommand(config, logger).run(file, options));
|
|
10
|
+
program.command('generate <description>').alias('g').description('Generate code from description')
|
|
11
|
+
.option('-l, --language <lang>', 'Target language (auto-detected from description, or specify: javascript, typescript, python, html, etc.)')
|
|
12
|
+
.option('-o, --output <file>', 'Output file path').option('-m, --model <model>', 'Select AI model', 'code')
|
|
13
|
+
.option('-p, --pro', 'Senior Developer Mode: plan, generate, quality check (recommended)', false)
|
|
14
|
+
.action(async (description, options) => new GenerateCommand(config, logger).run(description, options));
|
|
15
|
+
program.command('explain <file>').alias('x').description('Explain code in a file')
|
|
16
|
+
.option('-l, --lines <range>', 'Line range (e.g., 1-50)').option('-d, --detail <level>', 'Detail level (brief, normal, detailed)', 'normal')
|
|
17
|
+
.action(async (file, options) => new ExplainCommand(config, logger).run(file, options));
|
|
18
|
+
program.command('fix <file>').alias('f').description('Fix issues in a file')
|
|
19
|
+
.option('-t, --type <type>', 'Fix type (bugs, style, security, performance)', 'bugs').option('--apply', 'Automatically apply fixes', false)
|
|
20
|
+
.action(async (file, options) => new EditCommand(config, logger).fix(file, options));
|
|
21
|
+
program.command('review <file>').alias('r').description('Review code quality')
|
|
22
|
+
.option('-f, --format <format>', 'Output format (text, json, markdown)', 'text')
|
|
23
|
+
.action(async (file, options) => new ReviewCommand(config, logger).run(file, options));
|
|
24
|
+
}
|
package/dist/commands/config.js
CHANGED
|
@@ -6,7 +6,9 @@ import inquirer from 'inquirer';
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { normalizePersonaMode } from '../utils/persona.js';
|
|
9
|
+
import { assertTrustedEndpoint, assertTrustedWebSocketEndpoint } from '../utils/network-policy.js';
|
|
9
10
|
import { CH } from '../utils/logger.js';
|
|
11
|
+
import { CliCommandError } from '../utils/command-contract.js';
|
|
10
12
|
export class ConfigCommand {
|
|
11
13
|
config;
|
|
12
14
|
logger;
|
|
@@ -49,8 +51,9 @@ export class ConfigCommand {
|
|
|
49
51
|
if (fs.existsSync(configFile)) {
|
|
50
52
|
if (nonInteractive) {
|
|
51
53
|
if (!options.yes) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
throw new CliCommandError('.vigthoria.json already exists. Re-run with --yes to overwrite in non-interactive mode.', {
|
|
55
|
+
code: 'PROJECT_ALREADY_INITIALIZED', category: 'usage',
|
|
56
|
+
});
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
else {
|
|
@@ -79,9 +82,9 @@ export class ConfigCommand {
|
|
|
79
82
|
const defaults = profileDefaults[profile];
|
|
80
83
|
const model = options.model || defaults.defaultModel;
|
|
81
84
|
if (!allowedModels.has(model)) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
throw new CliCommandError(`Invalid --model: ${model}. Allowed values: architect, code, assistant, code-35b, code-9b, balanced, balanced-4b.`, {
|
|
86
|
+
code: 'INVALID_MODEL', category: 'usage',
|
|
87
|
+
});
|
|
85
88
|
}
|
|
86
89
|
settings = {
|
|
87
90
|
defaultModel: model,
|
|
@@ -149,8 +152,9 @@ export class ConfigCommand {
|
|
|
149
152
|
const [key, ...valueParts] = keyValue.split('=');
|
|
150
153
|
const value = valueParts.join('=');
|
|
151
154
|
if (!key || value === undefined) {
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
throw new CliCommandError('Invalid format. Use: vigthoria config --set key=value', {
|
|
156
|
+
code: 'INVALID_CONFIG_ASSIGNMENT', category: 'usage',
|
|
157
|
+
});
|
|
154
158
|
}
|
|
155
159
|
const configMap = {
|
|
156
160
|
'model': (v) => this.config.set('preferences', { ...this.config.get('preferences'), defaultModel: v }),
|
|
@@ -158,10 +162,10 @@ export class ConfigCommand {
|
|
|
158
162
|
'autoApply': (v) => this.config.set('preferences', { ...this.config.get('preferences'), autoApplyFixes: v === 'true' }),
|
|
159
163
|
'showDiffs': (v) => this.config.set('preferences', { ...this.config.get('preferences'), showDiffs: v === 'true' }),
|
|
160
164
|
'maxTokens': (v) => this.config.set('preferences', { ...this.config.get('preferences'), maxTokens: parseInt(v, 10) }),
|
|
161
|
-
'apiUrl': (v) => this.config.set('apiUrl', v),
|
|
162
|
-
'modelsApiUrl': (v) => this.config.set('modelsApiUrl', v),
|
|
163
|
-
'wsUrl': (v) => this.config.set('wsUrl', v),
|
|
164
|
-
'selfHostedModelsApiUrl': (v) => this.config.set('selfHostedModelsApiUrl', v === 'null' || v === 'off' ? null : v),
|
|
165
|
+
'apiUrl': (v) => this.config.set('apiUrl', assertTrustedEndpoint(v, { audience: 'coder' }).toString().replace(/\/$/, '')),
|
|
166
|
+
'modelsApiUrl': (v) => this.config.set('modelsApiUrl', assertTrustedEndpoint(v, { audience: 'models' }).toString().replace(/\/$/, '')),
|
|
167
|
+
'wsUrl': (v) => this.config.set('wsUrl', assertTrustedWebSocketEndpoint(v, 'coder').toString().replace(/\/$/, '')),
|
|
168
|
+
'selfHostedModelsApiUrl': (v) => this.config.set('selfHostedModelsApiUrl', v === 'null' || v === 'off' ? null : assertTrustedEndpoint(v, { audience: 'models' }).toString().replace(/\/$/, '')),
|
|
165
169
|
'persona': (v) => {
|
|
166
170
|
const mode = normalizePersonaMode(v);
|
|
167
171
|
if (!mode)
|
|
@@ -174,8 +178,9 @@ export class ConfigCommand {
|
|
|
174
178
|
this.logger.success(`Set ${key} = ${this.formatConfigValueForDisplay(key, value)}`);
|
|
175
179
|
}
|
|
176
180
|
else {
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
throw new CliCommandError(`Unknown config key: ${key}. Available keys: model, theme, autoApply, showDiffs, maxTokens, persona, apiUrl, modelsApiUrl, wsUrl, selfHostedModelsApiUrl.`, {
|
|
182
|
+
code: 'UNKNOWN_CONFIG_KEY', category: 'usage',
|
|
183
|
+
});
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
formatConfigValueForDisplay(key, value) {
|
|
@@ -224,7 +229,7 @@ export class ConfigCommand {
|
|
|
224
229
|
console.log(flatConfig[key]);
|
|
225
230
|
}
|
|
226
231
|
else {
|
|
227
|
-
|
|
232
|
+
throw new CliCommandError(`Unknown config key: ${key}`, { code: 'UNKNOWN_CONFIG_KEY', category: 'usage' });
|
|
228
233
|
}
|
|
229
234
|
}
|
|
230
235
|
listConfig() {
|
|
@@ -262,21 +267,10 @@ export class ConfigCommand {
|
|
|
262
267
|
},
|
|
263
268
|
]);
|
|
264
269
|
if (confirm) {
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const email = this.config.get('email');
|
|
270
|
-
const subscription = this.config.get('subscription');
|
|
271
|
-
this.config.reset();
|
|
272
|
-
// Restore auth
|
|
273
|
-
if (authToken) {
|
|
274
|
-
this.config.set('authToken', authToken);
|
|
275
|
-
this.config.set('refreshToken', refreshToken);
|
|
276
|
-
this.config.set('userId', userId);
|
|
277
|
-
this.config.set('email', email);
|
|
278
|
-
this.config.set('subscription', subscription);
|
|
279
|
-
}
|
|
270
|
+
// Reset preferences and endpoints in one durable transaction while
|
|
271
|
+
// preserving the complete credential bundle. Separate reset/set writes
|
|
272
|
+
// can leave a partially restored login after interruption.
|
|
273
|
+
this.config.resetPreservingAuth();
|
|
280
274
|
this.logger.success('Configuration reset to defaults');
|
|
281
275
|
}
|
|
282
276
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { ChatCommand } from './chat.js';
|
|
2
|
+
function projectWasProvided(project) {
|
|
3
|
+
return typeof project === 'string' && project.trim().length > 0;
|
|
4
|
+
}
|
|
5
|
+
export function registerConversationCommands(program, config, logger) {
|
|
6
|
+
program
|
|
7
|
+
.command('chat')
|
|
8
|
+
.alias('c')
|
|
9
|
+
.description('Start interactive chat with Vigthoria AI')
|
|
10
|
+
.option('-m, --model <model>', 'Select AI model (agent, code, code-35b, code-9b, balanced, balanced-4b, cloud, ultra)')
|
|
11
|
+
.option('-p, --project <path>', 'Set project context path')
|
|
12
|
+
.option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
|
|
13
|
+
.option('-a, --agent', 'Enable agentic mode (default: true for best quality)', true)
|
|
14
|
+
.option('--no-agent', 'Disable agentic mode (simple chat only)')
|
|
15
|
+
.option('-r, --resume', 'Resume last session for this project', false)
|
|
16
|
+
.option('--prompt <text>', 'Run a single prompt directly and exit')
|
|
17
|
+
.option('-w, --workflow <selector>', 'Route prompts through a named or explicit VigFlow workflow target')
|
|
18
|
+
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
19
|
+
.option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
|
|
20
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
await new ChatCommand(config, logger, program).run({
|
|
23
|
+
model: options.model,
|
|
24
|
+
project: options.project,
|
|
25
|
+
projectProvided: projectWasProvided(options.project),
|
|
26
|
+
newProject: options.newProject,
|
|
27
|
+
agent: options.agent,
|
|
28
|
+
workflow: options.workflow,
|
|
29
|
+
json: options.json,
|
|
30
|
+
autoApprove: options.autoApprove,
|
|
31
|
+
resume: options.resume,
|
|
32
|
+
prompt: options.prompt,
|
|
33
|
+
bridge: options.bridge,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
program
|
|
37
|
+
.command('chat-resume')
|
|
38
|
+
.description('Resume the latest chat session for the current or specified project')
|
|
39
|
+
.option('-m, --model <model>', 'Select AI model (agent, code, code-35b, code-9b, balanced, balanced-4b, cloud, ultra)')
|
|
40
|
+
.option('-p, --project <path>', 'Set project context path')
|
|
41
|
+
.option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
|
|
42
|
+
.option('-a, --agent', 'Enable agentic mode (default: true for best quality)', true)
|
|
43
|
+
.option('--no-agent', 'Disable agentic mode (simple chat only)')
|
|
44
|
+
.option('--prompt <text>', 'Run a single prompt directly and exit after resuming context')
|
|
45
|
+
.option('-w, --workflow <selector>', 'Route prompts through a named or explicit VigFlow workflow target')
|
|
46
|
+
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
47
|
+
.option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
|
|
48
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
49
|
+
.action(async (options) => {
|
|
50
|
+
await new ChatCommand(config, logger, program).run({
|
|
51
|
+
model: options.model,
|
|
52
|
+
project: options.project,
|
|
53
|
+
projectProvided: projectWasProvided(options.project),
|
|
54
|
+
newProject: options.newProject,
|
|
55
|
+
agent: options.agent,
|
|
56
|
+
workflow: options.workflow,
|
|
57
|
+
json: options.json,
|
|
58
|
+
autoApprove: options.autoApprove,
|
|
59
|
+
resume: true,
|
|
60
|
+
prompt: options.prompt,
|
|
61
|
+
bridge: options.bridge,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
program
|
|
65
|
+
.command('agent')
|
|
66
|
+
.alias('a')
|
|
67
|
+
.description('Start agentic mode - AI can read/write files, run commands')
|
|
68
|
+
.option('-m, --model <model>', 'Select AI model (agent, code, cloud, ultra)')
|
|
69
|
+
.option('-p, --project <path>', 'Set project context path')
|
|
70
|
+
.option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
|
|
71
|
+
.option('--prompt <text>', 'Run a single agent prompt directly and exit')
|
|
72
|
+
.option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
|
|
73
|
+
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
74
|
+
.option('--retry', 'Retry failed tasks from the last agent run in this workspace session', false)
|
|
75
|
+
.option('--continue', 'Continue unfinished tasks from the last agent run in this workspace session', false)
|
|
76
|
+
.option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
|
|
77
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
78
|
+
.action(async (options) => {
|
|
79
|
+
await new ChatCommand(config, logger, program).run({
|
|
80
|
+
model: options.model,
|
|
81
|
+
project: options.project,
|
|
82
|
+
projectProvided: projectWasProvided(options.project),
|
|
83
|
+
newProject: options.newProject,
|
|
84
|
+
agent: true,
|
|
85
|
+
operator: false,
|
|
86
|
+
workflow: options.workflow,
|
|
87
|
+
json: options.json,
|
|
88
|
+
autoApprove: options.autoApprove,
|
|
89
|
+
prompt: options.prompt,
|
|
90
|
+
bridge: options.bridge,
|
|
91
|
+
retry: options.retry,
|
|
92
|
+
continue: options.continue,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
program
|
|
96
|
+
.command('operator')
|
|
97
|
+
.alias('op')
|
|
98
|
+
.description('Start BMAD operator mode for infrastructure and system workflows')
|
|
99
|
+
.option('-m, --model <model>', 'Select operator model (code, agent, cloud)')
|
|
100
|
+
.option('-p, --project <path>', 'Set project context path')
|
|
101
|
+
.option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
|
|
102
|
+
.option('--prompt <text>', 'Run a single operator prompt directly and exit')
|
|
103
|
+
.option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
|
|
104
|
+
.option('--save-plan', 'Save the completed BMAD plan into VigFlow for rerun and audit', false)
|
|
105
|
+
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
106
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
107
|
+
.action(async (options) => {
|
|
108
|
+
await new ChatCommand(config, logger, program).run({
|
|
109
|
+
model: options.model,
|
|
110
|
+
project: options.project,
|
|
111
|
+
projectProvided: projectWasProvided(options.project),
|
|
112
|
+
newProject: options.newProject,
|
|
113
|
+
agent: false,
|
|
114
|
+
operator: true,
|
|
115
|
+
workflow: options.workflow,
|
|
116
|
+
savePlan: options.savePlan,
|
|
117
|
+
json: options.json,
|
|
118
|
+
prompt: options.prompt,
|
|
119
|
+
bridge: options.bridge,
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -21,12 +21,18 @@ interface DeployOptions {
|
|
|
21
21
|
}
|
|
22
22
|
export declare class DeployCommand {
|
|
23
23
|
private config;
|
|
24
|
-
private logger;
|
|
25
24
|
private apiBase;
|
|
26
|
-
constructor(config: Config,
|
|
25
|
+
constructor(config: Config, _logger: Logger);
|
|
27
26
|
private getAuthHeaders;
|
|
28
27
|
private isAuthenticated;
|
|
29
28
|
private requireAuth;
|
|
29
|
+
/**
|
|
30
|
+
* Deployment is a Coder-server operation. A client-local absolute path is
|
|
31
|
+
* neither portable nor a valid remote workspace binding, so resolve the
|
|
32
|
+
* validated local project to an existing server-owned project identifier
|
|
33
|
+
* before starting a deployment mutation.
|
|
34
|
+
*/
|
|
35
|
+
private resolveServerProject;
|
|
30
36
|
/**
|
|
31
37
|
* Interactive deploy wizard
|
|
32
38
|
*/
|
package/dist/commands/deploy.js
CHANGED
|
@@ -15,33 +15,67 @@ import chalk from 'chalk';
|
|
|
15
15
|
import * as fs from 'fs';
|
|
16
16
|
import * as path from 'path';
|
|
17
17
|
import { createSpinner, CH } from '../utils/logger.js';
|
|
18
|
+
import { validateExtractedWorkspace } from '../utils/workspace-boundary.js';
|
|
19
|
+
import { guardedFetch } from '../utils/network-policy.js';
|
|
20
|
+
import { CliCommandError, commandFailure } from '../utils/command-contract.js';
|
|
18
21
|
import inquirer from 'inquirer';
|
|
19
22
|
export class DeployCommand {
|
|
20
23
|
config;
|
|
21
|
-
logger;
|
|
22
24
|
apiBase;
|
|
23
|
-
constructor(config,
|
|
25
|
+
constructor(config, _logger) {
|
|
24
26
|
this.config = config;
|
|
25
|
-
this.logger = logger;
|
|
26
27
|
this.apiBase = this.config.get('apiUrl') || 'https://coder.vigthoria.io';
|
|
27
28
|
}
|
|
28
29
|
getAuthHeaders() {
|
|
29
|
-
const token = this.config.get('authToken');
|
|
30
|
-
return
|
|
31
|
-
'Authorization': `Bearer ${token}`,
|
|
32
|
-
'Content-Type': 'application/json'
|
|
33
|
-
};
|
|
30
|
+
const token = process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN || this.config.get('authToken');
|
|
31
|
+
return token
|
|
32
|
+
? { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
|
|
33
|
+
: { 'Content-Type': 'application/json' };
|
|
34
34
|
}
|
|
35
35
|
isAuthenticated() {
|
|
36
|
-
return !!this.config.get('authToken');
|
|
36
|
+
return !!(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN || this.config.get('authToken'));
|
|
37
37
|
}
|
|
38
38
|
requireAuth() {
|
|
39
39
|
if (!this.isAuthenticated()) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
throw new CliCommandError('Authentication required. Run `vigthoria login` first.', {
|
|
41
|
+
code: 'AUTH_REQUIRED', category: 'authentication',
|
|
42
|
+
});
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Deployment is a Coder-server operation. A client-local absolute path is
|
|
47
|
+
* neither portable nor a valid remote workspace binding, so resolve the
|
|
48
|
+
* validated local project to an existing server-owned project identifier
|
|
49
|
+
* before starting a deployment mutation.
|
|
50
|
+
*/
|
|
51
|
+
async resolveServerProject(projectPath) {
|
|
52
|
+
const projectDir = fs.realpathSync(projectPath || process.cwd());
|
|
53
|
+
validateExtractedWorkspace(projectDir, { ignoreNames: ['node_modules', '.git', 'dist', 'build'] });
|
|
54
|
+
const projectInfo = this.detectProjectInfo(projectDir);
|
|
55
|
+
const response = await guardedFetch(`${this.apiBase}/api/projects`, {
|
|
56
|
+
headers: this.getAuthHeaders(),
|
|
57
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error('Unable to resolve the project in Coder before deployment');
|
|
60
|
+
}
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
const localNames = new Set([
|
|
63
|
+
projectInfo.name.trim().toLowerCase(),
|
|
64
|
+
path.basename(projectDir).trim().toLowerCase(),
|
|
65
|
+
].filter(Boolean));
|
|
66
|
+
const match = (data.projects || []).find((project) => {
|
|
67
|
+
const remoteName = String(project.project_name || project.name || '').trim().toLowerCase();
|
|
68
|
+
return localNames.has(remoteName);
|
|
69
|
+
});
|
|
70
|
+
const projectId = match?.id ?? match?.project_id;
|
|
71
|
+
if (projectId === undefined || projectId === null || String(projectId).trim() === '') {
|
|
72
|
+
throw new Error(`Project "${projectInfo.name}" is not synchronized with Coder. Upload or create it in Coder before deploying.`);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
projectId: typeof projectId === 'number' ? projectId : String(projectId),
|
|
76
|
+
projectName: String(match?.project_name || match?.name || projectInfo.name),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
45
79
|
/**
|
|
46
80
|
* Interactive deploy wizard
|
|
47
81
|
*/
|
|
@@ -91,16 +125,15 @@ export class DeployCommand {
|
|
|
91
125
|
this.requireAuth();
|
|
92
126
|
const spinner = createSpinner('Deploying to preview...').start();
|
|
93
127
|
try {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
const response = await fetch(`${this.apiBase}/api/hosting/deploy/preview`, {
|
|
128
|
+
const project = await this.resolveServerProject(projectPath);
|
|
129
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/deploy/preview`, {
|
|
97
130
|
method: 'POST',
|
|
98
131
|
headers: this.getAuthHeaders(),
|
|
99
132
|
body: JSON.stringify({
|
|
100
|
-
|
|
101
|
-
|
|
133
|
+
projectId: project.projectId,
|
|
134
|
+
projectName: project.projectName,
|
|
102
135
|
})
|
|
103
|
-
});
|
|
136
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
104
137
|
if (!response.ok) {
|
|
105
138
|
const error = await response.json();
|
|
106
139
|
throw new Error(error.error || 'Failed to deploy');
|
|
@@ -114,49 +147,40 @@ export class DeployCommand {
|
|
|
114
147
|
}
|
|
115
148
|
catch (error) {
|
|
116
149
|
spinner.stop();
|
|
117
|
-
|
|
118
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
119
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
120
|
-
process.exitCode = 1;
|
|
150
|
+
throw commandFailure(error, { code: 'DEPLOY_PREVIEW_FAILED' });
|
|
121
151
|
}
|
|
122
152
|
}
|
|
123
153
|
/**
|
|
124
154
|
* Deploy to Vigthoria subdomain
|
|
125
155
|
*/
|
|
126
156
|
async deployToSubdomain(subdomain, projectPath) {
|
|
157
|
+
this.requireAuth();
|
|
127
158
|
const spinner = createSpinner(`Deploying to ${subdomain}.vigthoria.io...`).start();
|
|
128
159
|
try {
|
|
129
160
|
// Validate subdomain format
|
|
130
161
|
if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(subdomain) || subdomain.length < 3) {
|
|
131
|
-
throw new
|
|
162
|
+
throw new CliCommandError('Subdomain must be 3+ chars, lowercase alphanumeric with hyphens', {
|
|
163
|
+
code: 'SUBDOMAIN_INVALID', category: 'usage',
|
|
164
|
+
});
|
|
132
165
|
}
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
const response = await fetch(`${this.apiBase}/api/hosting/deploy/subdomain`, {
|
|
166
|
+
const project = await this.resolveServerProject(projectPath);
|
|
167
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/deploy/subdomain`, {
|
|
136
168
|
method: 'POST',
|
|
137
169
|
headers: this.getAuthHeaders(),
|
|
138
170
|
body: JSON.stringify({
|
|
139
171
|
subdomain,
|
|
140
|
-
|
|
141
|
-
|
|
172
|
+
projectId: project.projectId,
|
|
173
|
+
projectName: project.projectName,
|
|
142
174
|
})
|
|
143
|
-
});
|
|
175
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
144
176
|
const data = await response.json();
|
|
145
177
|
if (!response.ok || !data.success) {
|
|
146
178
|
if (data.requiresSubscription) {
|
|
147
179
|
spinner.stop();
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
message: 'Would you like to subscribe now?',
|
|
153
|
-
default: true
|
|
154
|
-
}]);
|
|
155
|
-
if (proceed && data.checkoutUrl) {
|
|
156
|
-
console.log(chalk.cyan(`\nš Opening checkout: ${data.checkoutUrl}`));
|
|
157
|
-
console.log(chalk.gray('Please open this URL in your browser to subscribe.\n'));
|
|
158
|
-
}
|
|
159
|
-
return;
|
|
180
|
+
throw new CliCommandError('Subdomain hosting requires a subscription (ā¬4.99/mo)', {
|
|
181
|
+
code: 'DEPLOY_SUBSCRIPTION_REQUIRED', category: 'authorization',
|
|
182
|
+
details: data.checkoutUrl ? { checkoutUrl: data.checkoutUrl } : undefined,
|
|
183
|
+
});
|
|
160
184
|
}
|
|
161
185
|
throw new Error(data.error || 'Failed to deploy');
|
|
162
186
|
}
|
|
@@ -169,44 +193,34 @@ export class DeployCommand {
|
|
|
169
193
|
}
|
|
170
194
|
catch (error) {
|
|
171
195
|
spinner.stop();
|
|
172
|
-
|
|
173
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
174
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
196
|
+
throw commandFailure(error, { code: 'DEPLOY_SUBDOMAIN_FAILED' });
|
|
175
197
|
}
|
|
176
198
|
}
|
|
177
199
|
/**
|
|
178
200
|
* Deploy to custom domain
|
|
179
201
|
*/
|
|
180
202
|
async deployToCustomDomain(domain, projectPath) {
|
|
203
|
+
this.requireAuth();
|
|
181
204
|
const spinner = createSpinner(`Setting up ${domain}...`).start();
|
|
182
205
|
try {
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
const response = await fetch(`${this.apiBase}/api/hosting/deploy/custom`, {
|
|
206
|
+
const project = await this.resolveServerProject(projectPath);
|
|
207
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/deploy/custom`, {
|
|
186
208
|
method: 'POST',
|
|
187
209
|
headers: this.getAuthHeaders(),
|
|
188
210
|
body: JSON.stringify({
|
|
189
211
|
domain,
|
|
190
|
-
|
|
191
|
-
|
|
212
|
+
projectId: project.projectId,
|
|
213
|
+
projectName: project.projectName,
|
|
192
214
|
})
|
|
193
|
-
});
|
|
215
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
194
216
|
const data = await response.json();
|
|
195
217
|
if (!response.ok || !data.success) {
|
|
196
218
|
if (data.requiresSubscription) {
|
|
197
219
|
spinner.stop();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
message: 'Would you like to subscribe now?',
|
|
203
|
-
default: true
|
|
204
|
-
}]);
|
|
205
|
-
if (proceed && data.checkoutUrl) {
|
|
206
|
-
console.log(chalk.cyan(`\nš Checkout URL: ${data.checkoutUrl}`));
|
|
207
|
-
console.log(chalk.gray('Please open this URL in your browser to subscribe.\n'));
|
|
208
|
-
}
|
|
209
|
-
return;
|
|
220
|
+
throw new CliCommandError('Custom domain hosting requires a subscription (ā¬9.99/mo)', {
|
|
221
|
+
code: 'DEPLOY_SUBSCRIPTION_REQUIRED', category: 'authorization',
|
|
222
|
+
details: data.checkoutUrl ? { checkoutUrl: data.checkoutUrl } : undefined,
|
|
223
|
+
});
|
|
210
224
|
}
|
|
211
225
|
throw new Error(data.error || 'Failed to deploy');
|
|
212
226
|
}
|
|
@@ -224,9 +238,7 @@ export class DeployCommand {
|
|
|
224
238
|
}
|
|
225
239
|
catch (error) {
|
|
226
240
|
spinner.stop();
|
|
227
|
-
|
|
228
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
229
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
241
|
+
throw commandFailure(error, { code: 'DEPLOY_CUSTOM_DOMAIN_FAILED' });
|
|
230
242
|
}
|
|
231
243
|
}
|
|
232
244
|
/**
|
|
@@ -271,9 +283,9 @@ export class DeployCommand {
|
|
|
271
283
|
async showPlans() {
|
|
272
284
|
const spinner = createSpinner('Fetching hosting plans...').start();
|
|
273
285
|
try {
|
|
274
|
-
const response = await
|
|
286
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/plans`, {
|
|
275
287
|
headers: this.getAuthHeaders()
|
|
276
|
-
});
|
|
288
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
277
289
|
if (!response.ok) {
|
|
278
290
|
throw new Error('Failed to fetch plans');
|
|
279
291
|
}
|
|
@@ -301,9 +313,7 @@ export class DeployCommand {
|
|
|
301
313
|
}
|
|
302
314
|
catch (error) {
|
|
303
315
|
spinner.stop();
|
|
304
|
-
|
|
305
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
306
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
316
|
+
throw commandFailure(error, { code: 'DEPLOY_PLANS_FAILED' });
|
|
307
317
|
}
|
|
308
318
|
}
|
|
309
319
|
/**
|
|
@@ -313,9 +323,9 @@ export class DeployCommand {
|
|
|
313
323
|
this.requireAuth();
|
|
314
324
|
const spinner = createSpinner('Fetching deployments...').start();
|
|
315
325
|
try {
|
|
316
|
-
const response = await
|
|
326
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/domains`, {
|
|
317
327
|
headers: this.getAuthHeaders()
|
|
318
|
-
});
|
|
328
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
319
329
|
if (!response.ok) {
|
|
320
330
|
throw new Error('Failed to fetch deployments');
|
|
321
331
|
}
|
|
@@ -342,9 +352,7 @@ export class DeployCommand {
|
|
|
342
352
|
}
|
|
343
353
|
catch (error) {
|
|
344
354
|
spinner.stop();
|
|
345
|
-
|
|
346
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
347
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
355
|
+
throw commandFailure(error, { code: 'DEPLOY_LIST_FAILED' });
|
|
348
356
|
}
|
|
349
357
|
}
|
|
350
358
|
/**
|
|
@@ -357,9 +365,9 @@ export class DeployCommand {
|
|
|
357
365
|
const endpoint = domain
|
|
358
366
|
? `${this.apiBase}/api/hosting/domain/${encodeURIComponent(domain)}/status`
|
|
359
367
|
: `${this.apiBase}/api/hosting/status`;
|
|
360
|
-
const response = await
|
|
368
|
+
const response = await guardedFetch(endpoint, {
|
|
361
369
|
headers: this.getAuthHeaders()
|
|
362
|
-
});
|
|
370
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
363
371
|
if (!response.ok) {
|
|
364
372
|
throw new Error('Failed to fetch status');
|
|
365
373
|
}
|
|
@@ -370,9 +378,7 @@ export class DeployCommand {
|
|
|
370
378
|
}
|
|
371
379
|
catch (error) {
|
|
372
380
|
spinner.stop();
|
|
373
|
-
|
|
374
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
375
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
381
|
+
throw commandFailure(error, { code: 'DEPLOY_STATUS_FAILED' });
|
|
376
382
|
}
|
|
377
383
|
}
|
|
378
384
|
/**
|
|
@@ -382,11 +388,11 @@ export class DeployCommand {
|
|
|
382
388
|
this.requireAuth();
|
|
383
389
|
const spinner = createSpinner(`Verifying DNS for ${domain}...`).start();
|
|
384
390
|
try {
|
|
385
|
-
const response = await
|
|
391
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/domain/verify`, {
|
|
386
392
|
method: 'POST',
|
|
387
393
|
headers: this.getAuthHeaders(),
|
|
388
394
|
body: JSON.stringify({ domain })
|
|
389
|
-
});
|
|
395
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
390
396
|
const data = await response.json();
|
|
391
397
|
if (!response.ok || !data.success) {
|
|
392
398
|
throw new Error(data.error || 'Verification failed');
|
|
@@ -404,9 +410,7 @@ export class DeployCommand {
|
|
|
404
410
|
}
|
|
405
411
|
catch (error) {
|
|
406
412
|
spinner.stop();
|
|
407
|
-
|
|
408
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
409
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
413
|
+
throw commandFailure(error, { code: 'DEPLOY_VERIFY_FAILED' });
|
|
410
414
|
}
|
|
411
415
|
}
|
|
412
416
|
/**
|
|
@@ -426,10 +430,10 @@ export class DeployCommand {
|
|
|
426
430
|
}
|
|
427
431
|
const spinner = createSpinner(`Removing ${domain}...`).start();
|
|
428
432
|
try {
|
|
429
|
-
const response = await
|
|
433
|
+
const response = await guardedFetch(`${this.apiBase}/api/hosting/domain/${encodeURIComponent(domain)}`, {
|
|
430
434
|
method: 'DELETE',
|
|
431
435
|
headers: this.getAuthHeaders()
|
|
432
|
-
});
|
|
436
|
+
}, { audience: 'coder', maxRedirects: 0 });
|
|
433
437
|
if (!response.ok) {
|
|
434
438
|
const error = await response.json();
|
|
435
439
|
throw new Error(error.error || 'Failed to remove');
|
|
@@ -439,9 +443,7 @@ export class DeployCommand {
|
|
|
439
443
|
}
|
|
440
444
|
catch (error) {
|
|
441
445
|
spinner.stop();
|
|
442
|
-
|
|
443
|
-
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
444
|
-
console.log(chalk.red(`\nā Error: ${errMsg}\n`));
|
|
446
|
+
throw commandFailure(error, { code: 'DEPLOY_REMOVE_FAILED' });
|
|
445
447
|
}
|
|
446
448
|
}
|
|
447
449
|
/**
|
|
@@ -9,8 +9,7 @@ type DeviceOptions = {
|
|
|
9
9
|
port?: string;
|
|
10
10
|
};
|
|
11
11
|
export declare class DeviceCommand {
|
|
12
|
-
|
|
13
|
-
constructor(_config: Config, logger: Logger);
|
|
12
|
+
constructor(_config: Config, _logger: Logger);
|
|
14
13
|
status(options?: DeviceOptions): Promise<void>;
|
|
15
14
|
list(options?: DeviceOptions): Promise<void>;
|
|
16
15
|
screenshot(options?: DeviceOptions): Promise<void>;
|