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.
Files changed (52) hide show
  1. package/README.md +5 -5
  2. package/dist/commands/auth.js +48 -65
  3. package/dist/commands/bridge.js +12 -19
  4. package/dist/commands/cancel.js +15 -22
  5. package/dist/commands/chat.d.ts +11 -0
  6. package/dist/commands/chat.js +404 -248
  7. package/dist/commands/config.js +31 -71
  8. package/dist/commands/deploy.js +83 -123
  9. package/dist/commands/device.d.ts +35 -0
  10. package/dist/commands/device.js +239 -0
  11. package/dist/commands/edit.js +32 -39
  12. package/dist/commands/explain.js +18 -25
  13. package/dist/commands/fork.js +22 -27
  14. package/dist/commands/generate.js +37 -44
  15. package/dist/commands/history.js +20 -25
  16. package/dist/commands/hub.js +95 -102
  17. package/dist/commands/index.js +41 -46
  18. package/dist/commands/legion.d.ts +1 -0
  19. package/dist/commands/legion.js +162 -209
  20. package/dist/commands/preview.js +60 -98
  21. package/dist/commands/replay.js +27 -32
  22. package/dist/commands/repo.js +103 -141
  23. package/dist/commands/review.js +29 -36
  24. package/dist/commands/security.js +5 -12
  25. package/dist/commands/update.js +15 -49
  26. package/dist/commands/workflow.d.ts +8 -1
  27. package/dist/commands/workflow.js +53 -19
  28. package/dist/index.js +409 -234
  29. package/dist/utils/api.d.ts +5 -0
  30. package/dist/utils/api.js +398 -176
  31. package/dist/utils/bridge-client.js +11 -52
  32. package/dist/utils/cli-state.d.ts +54 -0
  33. package/dist/utils/cli-state.js +185 -0
  34. package/dist/utils/config.d.ts +5 -0
  35. package/dist/utils/config.js +35 -14
  36. package/dist/utils/context-ranker.js +15 -21
  37. package/dist/utils/files.js +5 -42
  38. package/dist/utils/logger.js +42 -50
  39. package/dist/utils/post-write-validator.js +22 -29
  40. package/dist/utils/project-memory.d.ts +56 -0
  41. package/dist/utils/project-memory.js +289 -0
  42. package/dist/utils/session.d.ts +29 -3
  43. package/dist/utils/session.js +137 -85
  44. package/dist/utils/task-display.js +13 -20
  45. package/dist/utils/tools.d.ts +19 -0
  46. package/dist/utils/tools.js +84 -87
  47. package/dist/utils/workspace-cache.js +18 -26
  48. package/dist/utils/workspace-stream.js +26 -64
  49. package/install.ps1 +14 -0
  50. package/package.json +5 -3
  51. package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +1 -1
  52. package/scripts/release/validate-no-go-gates.sh +2 -2
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
2
  /**
4
3
  * Vigthoria CLI - AI-Powered Terminal Coding Assistant
5
4
  *
@@ -16,76 +15,43 @@
16
15
  * vigthoria workflow - Manage repeatable VigFlow workflows
17
16
  * vigthoria operator - Start BMAD operator mode
18
17
  */
19
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
- if (k2 === undefined) k2 = k;
21
- var desc = Object.getOwnPropertyDescriptor(m, k);
22
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
- desc = { enumerable: true, get: function() { return m[k]; } };
24
- }
25
- Object.defineProperty(o, k2, desc);
26
- }) : (function(o, m, k, k2) {
27
- if (k2 === undefined) k2 = k;
28
- o[k2] = m[k];
29
- }));
30
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
- Object.defineProperty(o, "default", { enumerable: true, value: v });
32
- }) : function(o, v) {
33
- o["default"] = v;
34
- });
35
- var __importStar = (this && this.__importStar) || (function () {
36
- var ownKeys = function(o) {
37
- ownKeys = Object.getOwnPropertyNames || function (o) {
38
- var ar = [];
39
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
- return ar;
41
- };
42
- return ownKeys(o);
43
- };
44
- return function (mod) {
45
- if (mod && mod.__esModule) return mod;
46
- var result = {};
47
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
- __setModuleDefault(result, mod);
49
- return result;
50
- };
51
- })();
52
- var __importDefault = (this && this.__importDefault) || function (mod) {
53
- return (mod && mod.__esModule) ? mod : { "default": mod };
54
- };
55
- Object.defineProperty(exports, "__esModule", { value: true });
56
- exports.__cliErrorHandlingReady = void 0;
57
- exports.validateReleaseMetadata = validateReleaseMetadata;
58
- exports.setupErrorHandlers = setupErrorHandlers;
59
- exports.main = main;
60
- const commander_1 = require("commander");
61
- const chat_js_1 = require("./commands/chat.js");
62
- const edit_js_1 = require("./commands/edit.js");
63
- const generate_js_1 = require("./commands/generate.js");
64
- const explain_js_1 = require("./commands/explain.js");
65
- const auth_js_1 = require("./commands/auth.js");
66
- const config_js_1 = require("./commands/config.js");
67
- const review_js_1 = require("./commands/review.js");
68
- const hub_js_1 = require("./commands/hub.js");
69
- const repo_js_1 = require("./commands/repo.js");
70
- const deploy_js_1 = require("./commands/deploy.js");
71
- const bridge_js_1 = require("./commands/bridge.js");
72
- const workflow_js_1 = require("./commands/workflow.js");
73
- const preview_js_1 = require("./commands/preview.js");
74
- const legion_js_1 = require("./commands/legion.js");
75
- const history_js_1 = require("./commands/history.js");
76
- const replay_js_1 = require("./commands/replay.js");
77
- const fork_js_1 = require("./commands/fork.js");
78
- const cancel_js_1 = require("./commands/cancel.js");
79
- const security_js_1 = require("./commands/security.js");
80
- const config_js_2 = require("./utils/config.js");
81
- const logger_js_1 = require("./utils/logger.js");
82
- const chalk_1 = __importDefault(require("chalk"));
83
- const fs = __importStar(require("fs"));
84
- const path = __importStar(require("path"));
85
- const os = __importStar(require("os"));
86
- const crypto_1 = require("crypto");
87
- const axios_1 = __importDefault(require("axios"));
88
- const api_js_1 = require("./utils/api.js");
18
+ import { Command } from 'commander';
19
+ import { ChatCommand } from './commands/chat.js';
20
+ import { EditCommand } from './commands/edit.js';
21
+ import { GenerateCommand } from './commands/generate.js';
22
+ import { ExplainCommand } from './commands/explain.js';
23
+ import { handleLogin, handleLogout, statusAction } from './commands/auth.js';
24
+ import { ConfigCommand } from './commands/config.js';
25
+ import { ReviewCommand } from './commands/review.js';
26
+ import { HubCommand } from './commands/hub.js';
27
+ import { RepoCommand } from './commands/repo.js';
28
+ import { DeployCommand } from './commands/deploy.js';
29
+ import { BridgeCommand } from './commands/bridge.js';
30
+ import { DeviceCommand } from './commands/device.js';
31
+ import { WorkflowCommand } from './commands/workflow.js';
32
+ import { PreviewCommand } from './commands/preview.js';
33
+ import { LegionCommand } from './commands/legion.js';
34
+ import { HistoryCommand } from './commands/history.js';
35
+ import { ReplayCommand } from './commands/replay.js';
36
+ import { ForkCommand } from './commands/fork.js';
37
+ import { CancelCommand } from './commands/cancel.js';
38
+ import { SecurityCommand } from './commands/security.js';
39
+ import { Config } from './utils/config.js';
40
+ import { Logger, CH } from './utils/logger.js';
41
+ import chalk from 'chalk';
42
+ import * as fs from 'fs';
43
+ import * as path from 'path';
44
+ import * as os from 'os';
45
+ import { fileURLToPath } from 'url';
46
+ import { createHash } from 'crypto';
47
+ import axios from 'axios';
48
+ // ESM shim — TypeScript emits ESM under "type": "module", so __dirname
49
+ // is not available natively. Restore the CommonJS-style helper so the
50
+ // pre-existing package-discovery logic continues to work unchanged.
51
+ const __filename = fileURLToPath(import.meta.url);
52
+ const __dirname = path.dirname(__filename);
53
+ import { APIClient, sanitizeUserFacingErrorText } from './utils/api.js';
54
+ import { getCliStateFile, isOfflineMode, isSafeNpmPackageSpec, isUpdateCheckSuppressed, readCachedLatestVersion, readGatewayPreflightCache, writeCachedLatestVersion, writeGatewayPreflightCache, } from './utils/cli-state.js';
89
55
  function isApiError(error) {
90
56
  return Boolean(error &&
91
57
  typeof error === 'object' &&
@@ -122,12 +88,12 @@ function getVersion() {
122
88
  catch (e) {
123
89
  const message = e instanceof Error ? e.message : String(e);
124
90
  if (process.env.VIGTHORIA_DEBUG_VERSION === '1') {
125
- console.error(chalk_1.default.gray(`Unable to read package version: ${message}`));
91
+ console.error(chalk.gray(`Unable to read package version: ${message}`));
126
92
  }
127
93
  }
128
94
  return '0.0.0';
129
95
  }
130
- function validateReleaseMetadata() {
96
+ export function validateReleaseMetadata() {
131
97
  try {
132
98
  const packagePath = getPackageMetadataPaths().find((candidate) => fs.existsSync(candidate));
133
99
  if (!packagePath) {
@@ -164,7 +130,7 @@ function validateReleaseMetadata() {
164
130
  catch (error) {
165
131
  const message = error instanceof Error ? error.message : String(error);
166
132
  if (process.env.VIGTHORIA_DEBUG_VERSION === '1') {
167
- console.error(chalk_1.default.gray(`Release metadata validation failed: ${message}`));
133
+ console.error(chalk.gray(`Release metadata validation failed: ${message}`));
168
134
  }
169
135
  return false;
170
136
  }
@@ -204,7 +170,7 @@ function resolveManifestEntry(manifest, channel) {
204
170
  return null;
205
171
  }
206
172
  async function downloadFile(url, targetPath) {
207
- const response = await axios_1.default.get(url, {
173
+ const response = await axios.get(url, {
208
174
  responseType: 'arraybuffer',
209
175
  timeout: 20000,
210
176
  maxRedirects: 5,
@@ -213,7 +179,7 @@ async function downloadFile(url, targetPath) {
213
179
  fs.writeFileSync(targetPath, Buffer.from(response.data));
214
180
  }
215
181
  function sha256File(filePath) {
216
- const hash = (0, crypto_1.createHash)('sha256');
182
+ const hash = createHash('sha256');
217
183
  const data = fs.readFileSync(filePath);
218
184
  hash.update(data);
219
185
  return hash.digest('hex');
@@ -287,7 +253,7 @@ async function installGlobalPackageWithNpm(packageSpec) {
287
253
  let lastError = null;
288
254
  for (const attempt of attempts) {
289
255
  try {
290
- console.log(chalk_1.default.gray(`[update] installer executable: ${attempt.command}${attempt.shell ? ' (shell)' : ''}`));
256
+ console.log(chalk.gray(`[update] installer executable: ${attempt.command}${attempt.shell ? ' (shell)' : ''}`));
291
257
  execFileSync(attempt.command, attempt.args, {
292
258
  stdio: 'inherit',
293
259
  windowsHide: true,
@@ -298,40 +264,57 @@ async function installGlobalPackageWithNpm(packageSpec) {
298
264
  catch (error) {
299
265
  lastError = error;
300
266
  const code = error?.code || error?.status || 'unknown';
301
- console.error(chalk_1.default.yellow(`[update] install attempt failed via ${attempt.label}: ${code}`));
267
+ console.error(chalk.yellow(`[update] install attempt failed via ${attempt.label}: ${code}`));
302
268
  }
303
269
  }
304
270
  const finalCode = lastError?.code || lastError?.status || 'unknown';
305
271
  throw new Error(`Unable to launch npm installer after ${attempts.length} attempt(s). Last error: ${finalCode}`);
306
272
  }
307
- // Check for updates silently on startup (non-blocking)
273
+ function renderUpdateBanner(latestVersion) {
274
+ if (compareVersions(latestVersion, '1.4.0') >= 0 && compareVersions(VERSION, '1.4.0') < 0) {
275
+ console.log(chalk.red.bold(`\n${CH.warnEmoji} SECURITY UPDATE AVAILABLE`));
276
+ console.log(chalk.red(` Version ${VERSION} has security vulnerabilities.`));
277
+ console.log(chalk.yellow(` Please update to ${latestVersion} immediately:`));
278
+ console.log(chalk.white.bold(' npm install -g vigthoria-cli@latest\n'));
279
+ }
280
+ else {
281
+ console.log(chalk.yellow(`\n${CH.warnEmoji} Update available: ${VERSION} -> ${latestVersion}`));
282
+ console.log(chalk.gray(' Run `vigthoria update` to install\n'));
283
+ }
284
+ }
285
+ // Check for updates quietly on startup. Cached (24 h) so we never block
286
+ // startup on `npm view`. Honours VIGTHORIA_OFFLINE / VIGTHORIA_NO_UPDATE_CHECK.
308
287
  async function checkForUpdatesQuietly() {
288
+ if (isUpdateCheckSuppressed()) {
289
+ return;
290
+ }
291
+ const cached = readCachedLatestVersion();
292
+ if (cached) {
293
+ if (compareVersions(cached, VERSION) > 0) {
294
+ renderUpdateBanner(cached);
295
+ }
296
+ return;
297
+ }
298
+ // Cache miss: probe npm registry in the background, with a hard 5 s
299
+ // timeout. Result is cached for 24 h so subsequent runs are instant.
309
300
  try {
310
301
  const { execSync } = await import('child_process');
311
- // Cross-platform: use stdio: 'pipe' to suppress output on Windows
312
302
  const npmVersion = execSync('npm view vigthoria-cli version', {
313
303
  encoding: 'utf8',
314
304
  timeout: 5000,
315
- stdio: ['pipe', 'pipe', 'pipe'], // Suppress stderr on all platforms
305
+ stdio: ['pipe', 'pipe', 'pipe'],
316
306
  windowsHide: true,
317
307
  }).trim();
318
- // Only show update message if npm version is NEWER than current (not older)
319
- if (npmVersion && compareVersions(npmVersion, VERSION) > 0) {
320
- // Check if this is a security update (1.4.0+)
321
- if (compareVersions(npmVersion, '1.4.0') >= 0 && compareVersions(VERSION, '1.4.0') < 0) {
322
- console.log(chalk_1.default.red.bold(`\n${logger_js_1.CH.warnEmoji} SECURITY UPDATE AVAILABLE`));
323
- console.log(chalk_1.default.red(` Version ${VERSION} has security vulnerabilities.`));
324
- console.log(chalk_1.default.yellow(` Please update to ${npmVersion} immediately:`));
325
- console.log(chalk_1.default.white.bold(' npm install -g vigthoria-cli@latest\n'));
326
- }
327
- else {
328
- console.log(chalk_1.default.yellow(`\n📦 Update available: ${VERSION} → ${npmVersion}`));
329
- console.log(chalk_1.default.gray(' Run `vigthoria update` to install\n'));
330
- }
308
+ if (!npmVersion) {
309
+ return;
310
+ }
311
+ writeCachedLatestVersion(npmVersion);
312
+ if (compareVersions(npmVersion, VERSION) > 0) {
313
+ renderUpdateBanner(npmVersion);
331
314
  }
332
315
  }
333
316
  catch {
334
- // Silently ignore - network issues shouldn't block CLI
317
+ // Network or npm failure should never block CLI; do not cache failure.
335
318
  }
336
319
  }
337
320
  const VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE = 'Vigthoria Gate way user authentification failed. Please log out and login again.';
@@ -349,7 +332,7 @@ function isAuthProtectedCommand(command) {
349
332
  'chat', 'c', 'chat-resume',
350
333
  'agent', 'a', 'operator', 'op',
351
334
  'edit', 'e', 'generate', 'g', 'explain', 'x', 'fix', 'f', 'review', 'r',
352
- 'workflow', 'flow', 'hub', 'marketplace', 'deploy', 'host', 'preview',
335
+ 'workflow', 'flow', 'hub', 'marketplace', 'deploy', 'host', 'preview', 'device',
353
336
  'legion', 'history', 'runs', 'replay', 'fork', 'cancel',
354
337
  'repo', 'repository',
355
338
  ]);
@@ -359,19 +342,30 @@ async function enforceGatewayAuthSession(config, logger, jsonOutputRequested) {
359
342
  if (!config.isAuthenticated()) {
360
343
  return true;
361
344
  }
362
- const api = new api_js_1.APIClient(config, logger);
345
+ // Offline mode disables every outbound preflight call.
346
+ if (isOfflineMode()) {
347
+ return true;
348
+ }
349
+ // Short-lived cache so back-to-back CLI invocations don't re-probe.
350
+ const cached = readGatewayPreflightCache();
351
+ if (cached === true) {
352
+ return true;
353
+ }
354
+ const api = new APIClient(config, logger);
363
355
  try {
364
356
  const tokenCheck = await api.validateToken();
365
357
  if (!tokenCheck.valid) {
358
+ writeGatewayPreflightCache(false);
366
359
  if (jsonOutputRequested) {
367
360
  process.exitCode = 1;
368
361
  console.log(JSON.stringify({ success: false, error: VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE }, null, 2));
369
362
  }
370
363
  else {
371
- console.log(chalk_1.default.red(VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE));
364
+ console.log(chalk.red(VIGTHORIA_GATEWAY_AUTH_FAILURE_MESSAGE));
372
365
  }
373
366
  return false;
374
367
  }
368
+ writeGatewayPreflightCache(true);
375
369
  return true;
376
370
  }
377
371
  catch {
@@ -382,6 +376,14 @@ async function enforceGatewayAuthSession(config, logger, jsonOutputRequested) {
382
376
  api.destroy();
383
377
  }
384
378
  }
379
+ function scrubMessageForUser(message) {
380
+ try {
381
+ return sanitizeUserFacingErrorText(message) || message;
382
+ }
383
+ catch {
384
+ return message;
385
+ }
386
+ }
385
387
  function normalizeCliError(error) {
386
388
  if (error instanceof Error) {
387
389
  const extended = error;
@@ -390,8 +392,9 @@ function normalizeCliError(error) {
390
392
  : typeof extended.response?.data?.message === 'string'
391
393
  ? extended.response.data.message
392
394
  : undefined;
395
+ const rawMessage = responseMessage || extended.message || 'An unexpected CLI error occurred.';
393
396
  return {
394
- message: responseMessage || extended.message || 'An unexpected CLI error occurred.',
397
+ message: scrubMessageForUser(rawMessage),
395
398
  code: extended.code,
396
399
  status: extended.status || extended.statusCode || extended.response?.status,
397
400
  details: extended.details || extended.response?.data,
@@ -399,15 +402,17 @@ function normalizeCliError(error) {
399
402
  }
400
403
  if (error && typeof error === 'object') {
401
404
  const value = error;
405
+ const rawMessage = typeof value.message === 'string' && value.message.trim() ? value.message : 'An unexpected CLI error occurred.';
402
406
  return {
403
- message: typeof value.message === 'string' && value.message.trim() ? value.message : 'An unexpected CLI error occurred.',
407
+ message: scrubMessageForUser(rawMessage),
404
408
  code: typeof value.code === 'string' || typeof value.code === 'number' ? value.code : undefined,
405
409
  status: typeof value.status === 'number' ? value.status : undefined,
406
410
  details: value.details,
407
411
  };
408
412
  }
413
+ const rawMessage = typeof error === 'string' && error.trim() ? error : 'An unexpected CLI error occurred.';
409
414
  return {
410
- message: typeof error === 'string' && error.trim() ? error : 'An unexpected CLI error occurred.',
415
+ message: scrubMessageForUser(rawMessage),
411
416
  };
412
417
  }
413
418
  function formatCliError(error, jsonOutputRequested = false) {
@@ -415,11 +420,11 @@ function formatCliError(error, jsonOutputRequested = false) {
415
420
  if (jsonOutputRequested) {
416
421
  return JSON.stringify({ success: false, error: normalized.message, code: normalized.code, status: normalized.status, details: normalized.details }, null, 2);
417
422
  }
418
- const parts = [chalk_1.default.red('Error:'), normalized.message];
423
+ const parts = [chalk.red('Error:'), normalized.message];
419
424
  if (normalized.code)
420
- parts.push(chalk_1.default.gray(`[${normalized.code}]`));
425
+ parts.push(chalk.gray(`[${normalized.code}]`));
421
426
  if (normalized.status)
422
- parts.push(chalk_1.default.gray(`(HTTP ${normalized.status})`));
427
+ parts.push(chalk.gray(`(HTTP ${normalized.status})`));
423
428
  return parts.join(' ');
424
429
  }
425
430
  function reportCliError(error, jsonOutputRequested = false) {
@@ -436,7 +441,7 @@ function handleFatalCliError(error, jsonOutputRequested = false) {
436
441
  process.exitCode = 1;
437
442
  }
438
443
  let errorHandlersInstalled = false;
439
- function setupErrorHandlers() {
444
+ export function setupErrorHandlers() {
440
445
  if (errorHandlersInstalled) {
441
446
  return;
442
447
  }
@@ -455,20 +460,22 @@ function setupErrorHandlers() {
455
460
  }
456
461
  });
457
462
  }
458
- async function main(args) {
459
- const program = new commander_1.Command();
460
- const config = new config_js_2.Config();
461
- const logger = new logger_js_1.Logger();
463
+ export async function main(args) {
464
+ const program = new Command();
465
+ const config = new Config();
466
+ const logger = new Logger();
462
467
  const invokedBinaryName = getInvokedBinaryName();
463
468
  const argv = [...args];
464
469
  const firstArg = argv[2];
465
470
  const jsonOutputRequested = argv.includes('--json');
466
471
  const directPromptRequested = argv.includes('--prompt') || argv.includes('-P');
472
+ const helpOrVersionRequested = argv.some((token) => token === '--help' || token === '-h' || token === '--version' || token === '-V' ||
473
+ token === 'help' || token === 'version');
467
474
  const isLegionCortexRequest = invokedBinaryName === 'vigthoria' && argv[2] === 'legion' && argv.includes('--cortex');
468
475
  if (invokedBinaryName === 'vigthoria-chat') {
469
476
  const knownCommands = new Set([
470
477
  'chat', 'chat-resume', 'agent', 'edit', 'generate', 'explain', 'fix', 'review', 'cancel',
471
- 'hub', 'repo', 'deploy', 'operator', 'workflow', 'flow', 'security', 'vsec', 'login', 'logout', 'status', 'config', 'update',
478
+ 'hub', 'repo', 'deploy', 'operator', 'workflow', 'flow', 'device', 'security', 'vsec', 'login', 'logout', 'status', 'config', 'update',
472
479
  '--help', '-h', '--version', '-V', 'help', 'version',
473
480
  ]);
474
481
  if (!firstArg || firstArg.startsWith('-') || !knownCommands.has(firstArg)) {
@@ -494,18 +501,25 @@ async function main(args) {
494
501
  // Calculate padding for centering
495
502
  const titlePad = Math.floor((boxWidth - 4 - titleText.length) / 2);
496
503
  const versionPad = Math.floor((boxWidth - 4 - versionText.length) / 2);
497
- if (process.env.VIGTHORIA_NO_BANNER !== '1' && !jsonOutputRequested && !directPromptRequested) {
498
- console.log(chalk_1.default.cyan(logger_js_1.CH.dTl + logger_js_1.CH.dH.repeat(boxWidth) + logger_js_1.CH.dTr));
499
- console.log(chalk_1.default.cyan(logger_js_1.CH.dV + ' '.repeat(boxWidth) + logger_js_1.CH.dV));
500
- console.log(chalk_1.default.cyan(logger_js_1.CH.dV) + ' '.repeat(titlePad) + chalk_1.default.bold.white('VIGTHORIA CLI') + chalk_1.default.cyan(' - AI-Powered Coding Assistant') + ' '.repeat(boxWidth - titlePad - titleText.length) + chalk_1.default.cyan(logger_js_1.CH.dV));
501
- console.log(chalk_1.default.cyan(logger_js_1.CH.dV) + ' '.repeat(versionPad) + chalk_1.default.gray(versionText) + ' '.repeat(boxWidth - versionPad - versionText.length) + chalk_1.default.cyan(logger_js_1.CH.dV));
502
- console.log(chalk_1.default.cyan(logger_js_1.CH.dV + ' '.repeat(boxWidth) + logger_js_1.CH.dV));
503
- console.log(chalk_1.default.cyan(logger_js_1.CH.dBl + logger_js_1.CH.dH.repeat(boxWidth) + logger_js_1.CH.dBr));
504
+ if (process.env.VIGTHORIA_NO_BANNER !== '1' &&
505
+ !jsonOutputRequested &&
506
+ !directPromptRequested &&
507
+ !helpOrVersionRequested) {
508
+ console.log(chalk.cyan(CH.dTl + CH.dH.repeat(boxWidth) + CH.dTr));
509
+ console.log(chalk.cyan(CH.dV + ' '.repeat(boxWidth) + CH.dV));
510
+ console.log(chalk.cyan(CH.dV) + ' '.repeat(titlePad) + chalk.bold.white('VIGTHORIA CLI') + chalk.cyan(' - AI-Powered Coding Assistant') + ' '.repeat(boxWidth - titlePad - titleText.length) + chalk.cyan(CH.dV));
511
+ console.log(chalk.cyan(CH.dV) + ' '.repeat(versionPad) + chalk.gray(versionText) + ' '.repeat(boxWidth - versionPad - versionText.length) + chalk.cyan(CH.dV));
512
+ console.log(chalk.cyan(CH.dV + ' '.repeat(boxWidth) + CH.dV));
513
+ console.log(chalk.cyan(CH.dBl + CH.dH.repeat(boxWidth) + CH.dBr));
504
514
  console.log();
505
515
  }
506
- // Check for updates in background (don't wait)
507
- if (process.env.VIGTHORIA_NO_UPDATE_CHECK !== '1' && !jsonOutputRequested && !directPromptRequested) {
508
- checkForUpdatesQuietly();
516
+ // Check for updates in background (don't wait). Skip for JSON / direct
517
+ // prompt / help / version invocations to keep them deterministic.
518
+ if (!isUpdateCheckSuppressed() &&
519
+ !jsonOutputRequested &&
520
+ !directPromptRequested &&
521
+ !helpOrVersionRequested) {
522
+ void checkForUpdatesQuietly();
509
523
  }
510
524
  program
511
525
  .name(invokedBinaryName === 'vigthoria-chat' ? 'vigthoria-chat' : 'vigthoria')
@@ -528,7 +542,7 @@ async function main(args) {
528
542
  .option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
529
543
  .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
530
544
  .action(async (options) => {
531
- const chat = new chat_js_1.ChatCommand(config, logger);
545
+ const chat = new ChatCommand(config, logger);
532
546
  await chat.run({
533
547
  model: options.model,
534
548
  project: options.project,
@@ -557,7 +571,7 @@ async function main(args) {
557
571
  .option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
558
572
  .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
559
573
  .action(async (options) => {
560
- const chat = new chat_js_1.ChatCommand(config, logger);
574
+ const chat = new ChatCommand(config, logger);
561
575
  await chat.run({
562
576
  model: options.model,
563
577
  project: options.project,
@@ -587,7 +601,7 @@ async function main(args) {
587
601
  .option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
588
602
  .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
589
603
  .action(async (options) => {
590
- const chat = new chat_js_1.ChatCommand(config, logger);
604
+ const chat = new ChatCommand(config, logger);
591
605
  await chat.run({
592
606
  model: options.model,
593
607
  project: options.project,
@@ -615,7 +629,7 @@ async function main(args) {
615
629
  .option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
616
630
  .option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
617
631
  .action(async (options) => {
618
- const chat = new chat_js_1.ChatCommand(config, logger);
632
+ const chat = new ChatCommand(config, logger);
619
633
  await chat.run({
620
634
  model: options.model,
621
635
  project: options.project,
@@ -636,9 +650,98 @@ async function main(args) {
636
650
  .command('status')
637
651
  .description('Show live DevTools Bridge status')
638
652
  .action(async () => {
639
- const bridge = new bridge_js_1.BridgeCommand(config, logger);
653
+ const bridge = new BridgeCommand(config, logger);
640
654
  await bridge.status();
641
655
  });
656
+ const deviceCommand = program
657
+ .command('device')
658
+ .alias('adb')
659
+ .description('Android Developer Bridge commands via local ADB');
660
+ deviceCommand
661
+ .command('status')
662
+ .description('Show ADB availability and connected Android devices')
663
+ .option('--json', 'Emit JSON output', false)
664
+ .action(async (options) => {
665
+ const device = new DeviceCommand(config, logger);
666
+ await device.status(options);
667
+ });
668
+ deviceCommand
669
+ .command('list')
670
+ .description('List connected Android devices')
671
+ .option('--json', 'Emit JSON output', false)
672
+ .action(async (options) => {
673
+ const device = new DeviceCommand(config, logger);
674
+ await device.list(options);
675
+ });
676
+ deviceCommand
677
+ .command('screenshot')
678
+ .description('Capture a screenshot from an Android device')
679
+ .option('-d, --device <id>', 'ADB device id')
680
+ .option('-o, --output <path>', 'Output PNG path')
681
+ .action(async (options) => {
682
+ const device = new DeviceCommand(config, logger);
683
+ await device.screenshot(options);
684
+ });
685
+ deviceCommand
686
+ .command('install <apk>')
687
+ .description('Install or update an APK on an Android device')
688
+ .option('-d, --device <id>', 'ADB device id')
689
+ .option('--json', 'Emit JSON output', false)
690
+ .action(async (apk, options) => {
691
+ const device = new DeviceCommand(config, logger);
692
+ await device.install(apk, options);
693
+ });
694
+ deviceCommand
695
+ .command('launch <package>')
696
+ .description('Launch an Android app by package name')
697
+ .option('-d, --device <id>', 'ADB device id')
698
+ .option('-a, --activity <activity>', 'Activity class, for example .MainActivity')
699
+ .option('--json', 'Emit JSON output', false)
700
+ .action(async (packageName, options) => {
701
+ const device = new DeviceCommand(config, logger);
702
+ await device.launch(packageName, options);
703
+ });
704
+ deviceCommand
705
+ .command('logs')
706
+ .description('Read Android logcat output')
707
+ .option('-d, --device <id>', 'ADB device id')
708
+ .option('-n, --lines <count>', 'Number of log lines for snapshot mode', '250')
709
+ .option('-f, --follow', 'Follow logcat until interrupted', false)
710
+ .option('--json', 'Emit JSON output for snapshot mode', false)
711
+ .action(async (options) => {
712
+ const device = new DeviceCommand(config, logger);
713
+ await device.logs(options);
714
+ });
715
+ deviceCommand
716
+ .command('tcpip')
717
+ .description('Enable wireless ADB tcpip mode on the selected USB-connected device')
718
+ .option('-d, --device <id>', 'ADB device id')
719
+ .option('-p, --port <port>', 'Wireless ADB port', '5555')
720
+ .option('--json', 'Emit JSON output', false)
721
+ .action(async (options) => {
722
+ const device = new DeviceCommand(config, logger);
723
+ await device.tcpip(options);
724
+ });
725
+ deviceCommand
726
+ .command('connect <address>')
727
+ .description('Connect to a wireless ADB device, for example 192.168.1.30:5555')
728
+ .option('--json', 'Emit JSON output', false)
729
+ .action(async (address, options) => {
730
+ const device = new DeviceCommand(config, logger);
731
+ await device.connect(address, options);
732
+ });
733
+ deviceCommand
734
+ .command('disconnect [address]')
735
+ .description('Disconnect a wireless ADB device')
736
+ .option('--json', 'Emit JSON output', false)
737
+ .action(async (address, options) => {
738
+ const device = new DeviceCommand(config, logger);
739
+ await device.disconnect(address, options);
740
+ });
741
+ deviceCommand.action(async () => {
742
+ const device = new DeviceCommand(config, logger);
743
+ await device.status({});
744
+ });
642
745
  // Security command group - Security DevOps scans and fix plans
643
746
  const securityCommand = program
644
747
  .command('security')
@@ -650,7 +753,7 @@ async function main(args) {
650
753
  .option('-d, --dir <path>', 'Directory to scan (default: current directory)')
651
754
  .option('--json', 'Emit JSON output', false)
652
755
  .action(async (options) => {
653
- const security = new security_js_1.SecurityCommand(config, logger);
756
+ const security = new SecurityCommand(config, logger);
654
757
  await security.scan({ dir: options.dir, json: options.json });
655
758
  });
656
759
  securityCommand
@@ -659,7 +762,7 @@ async function main(args) {
659
762
  .option('-d, --dir <path>', 'Directory to score (default: current directory)')
660
763
  .option('--json', 'Emit JSON output', false)
661
764
  .action(async (options) => {
662
- const security = new security_js_1.SecurityCommand(config, logger);
765
+ const security = new SecurityCommand(config, logger);
663
766
  await security.score({ dir: options.dir, json: options.json });
664
767
  });
665
768
  securityCommand
@@ -670,7 +773,7 @@ async function main(args) {
670
773
  .option('--apply', 'Request auto-apply mode (safe mode still requires explicit patching)', false)
671
774
  .option('--json', 'Emit JSON output', false)
672
775
  .action(async (options) => {
673
- const security = new security_js_1.SecurityCommand(config, logger);
776
+ const security = new SecurityCommand(config, logger);
674
777
  await security.fix({ dir: options.dir, issueId: options.issueId, apply: options.apply, json: options.json });
675
778
  });
676
779
  // Edit command - Edit files with AI
@@ -682,7 +785,7 @@ async function main(args) {
682
785
  .option('-m, --model <model>', 'Select AI model', 'code')
683
786
  .option('--apply', 'Automatically apply changes without confirmation', false)
684
787
  .action(async (file, options) => {
685
- const edit = new edit_js_1.EditCommand(config, logger);
788
+ const edit = new EditCommand(config, logger);
686
789
  await edit.run(file, options);
687
790
  });
688
791
  // Generate command - Generate code
@@ -695,7 +798,7 @@ async function main(args) {
695
798
  .option('-m, --model <model>', 'Select AI model', 'code')
696
799
  .option('-p, --pro', 'Senior Developer Mode: plan, generate, quality check (recommended)', false)
697
800
  .action(async (description, options) => {
698
- const generate = new generate_js_1.GenerateCommand(config, logger);
801
+ const generate = new GenerateCommand(config, logger);
699
802
  await generate.run(description, options);
700
803
  });
701
804
  // Explain command - Explain code
@@ -706,7 +809,7 @@ async function main(args) {
706
809
  .option('-l, --lines <range>', 'Line range (e.g., 1-50)')
707
810
  .option('-d, --detail <level>', 'Detail level (brief, normal, detailed)', 'normal')
708
811
  .action(async (file, options) => {
709
- const explain = new explain_js_1.ExplainCommand(config, logger);
812
+ const explain = new ExplainCommand(config, logger);
710
813
  await explain.run(file, options);
711
814
  });
712
815
  // Fix command - Fix code issues
@@ -722,7 +825,7 @@ async function main(args) {
722
825
  process.exitCode = 1;
723
826
  return;
724
827
  }
725
- const edit = new edit_js_1.EditCommand(config, logger);
828
+ const edit = new EditCommand(config, logger);
726
829
  await edit.fix(file, options);
727
830
  });
728
831
  // Review command - Code review
@@ -732,7 +835,7 @@ async function main(args) {
732
835
  .description('Review code quality')
733
836
  .option('-f, --format <format>', 'Output format (text, json, markdown)', 'text')
734
837
  .action(async (file, options) => {
735
- const review = new review_js_1.ReviewCommand(config, logger);
838
+ const review = new ReviewCommand(config, logger);
736
839
  await review.run(file, options);
737
840
  });
738
841
  const workflowCommand = program
@@ -747,7 +850,7 @@ async function main(args) {
747
850
  .option('-s, --search <query>', 'Search template names, descriptions, and tags')
748
851
  .option('--json', 'Emit machine-readable JSON output', false)
749
852
  .action(async (options) => {
750
- const workflow = new workflow_js_1.WorkflowCommand(config, logger);
853
+ const workflow = new WorkflowCommand(config, logger);
751
854
  await workflow.templates(options);
752
855
  });
753
856
  workflowCommand
@@ -756,7 +859,7 @@ async function main(args) {
756
859
  .description('List workflows created for the current account')
757
860
  .option('--json', 'Emit machine-readable JSON output', false)
758
861
  .action(async (options) => {
759
- const workflow = new workflow_js_1.WorkflowCommand(config, logger);
862
+ const workflow = new WorkflowCommand(config, logger);
760
863
  await workflow.list(options);
761
864
  });
762
865
  workflowCommand
@@ -766,28 +869,30 @@ async function main(args) {
766
869
  .option('-v, --variables <json>', 'Template variables as a JSON object')
767
870
  .option('--json', 'Emit machine-readable JSON output', false)
768
871
  .action(async (templateId, options) => {
769
- const workflow = new workflow_js_1.WorkflowCommand(config, logger);
872
+ const workflow = new WorkflowCommand(config, logger);
770
873
  await workflow.useTemplate(templateId, options);
771
874
  });
772
875
  workflowCommand
773
876
  .command('run <workflowId>')
774
877
  .description('Run a workflow immediately')
775
878
  .option('-d, --data <json>', 'Execution input data as a JSON object')
879
+ .option('--no-brain', 'Do not attach local Project Brain context to this workflow run')
776
880
  .option('--json', 'Emit machine-readable JSON output', false)
777
881
  .action(async (workflowId, options) => {
778
- const workflow = new workflow_js_1.WorkflowCommand(config, logger);
882
+ const workflow = new WorkflowCommand(config, logger);
779
883
  await workflow.run(workflowId, options);
780
884
  });
781
885
  workflowCommand
782
886
  .command('status <executionId>')
783
887
  .description('Get the current or final status of a workflow execution')
888
+ .option('--no-brain', 'Do not remember this workflow status in local Project Brain')
784
889
  .option('--json', 'Emit machine-readable JSON output', false)
785
890
  .action(async (executionId, options) => {
786
- const workflow = new workflow_js_1.WorkflowCommand(config, logger);
891
+ const workflow = new WorkflowCommand(config, logger);
787
892
  await workflow.status(executionId, options);
788
893
  });
789
894
  workflowCommand.action(async () => {
790
- const workflow = new workflow_js_1.WorkflowCommand(config, logger);
895
+ const workflow = new WorkflowCommand(config, logger);
791
896
  await workflow.templates({});
792
897
  });
793
898
  // ==================== HUB / MARKETPLACE COMMANDS ====================
@@ -801,7 +906,7 @@ async function main(args) {
801
906
  .alias('d')
802
907
  .description('Interactive module discovery - find the right APIs for your project')
803
908
  .action(async () => {
804
- const hub = new hub_js_1.HubCommand(config, logger);
909
+ const hub = new HubCommand(config, logger);
805
910
  await hub.discover();
806
911
  });
807
912
  hubCommand
@@ -810,7 +915,7 @@ async function main(args) {
810
915
  .description('List all available API modules')
811
916
  .option('-c, --category <category>', 'Filter by category (payments, communication, ai, creative, media)')
812
917
  .action(async (options) => {
813
- const hub = new hub_js_1.HubCommand(config, logger);
918
+ const hub = new HubCommand(config, logger);
814
919
  await hub.list(options);
815
920
  });
816
921
  hubCommand
@@ -818,7 +923,7 @@ async function main(args) {
818
923
  .alias('find')
819
924
  .description('Semantic search for modules (e.g., "generate background music for my app")')
820
925
  .action(async (query) => {
821
- const hub = new hub_js_1.HubCommand(config, logger);
926
+ const hub = new HubCommand(config, logger);
822
927
  await hub.search(query);
823
928
  });
824
929
  hubCommand
@@ -826,14 +931,14 @@ async function main(args) {
826
931
  .alias('enable')
827
932
  .description('Activate a module for your API key (enables pay-as-you-go)')
828
933
  .action(async (module) => {
829
- const hub = new hub_js_1.HubCommand(config, logger);
934
+ const hub = new HubCommand(config, logger);
830
935
  await hub.activate(module);
831
936
  });
832
937
  hubCommand
833
938
  .command('active')
834
939
  .description('Show your currently active modules')
835
940
  .action(async () => {
836
- const hub = new hub_js_1.HubCommand(config, logger);
941
+ const hub = new HubCommand(config, logger);
837
942
  await hub.active();
838
943
  });
839
944
  hubCommand
@@ -841,12 +946,12 @@ async function main(args) {
841
946
  .alias('details')
842
947
  .description('Get detailed information about a module')
843
948
  .action(async (module) => {
844
- const hub = new hub_js_1.HubCommand(config, logger);
949
+ const hub = new HubCommand(config, logger);
845
950
  await hub.info(module);
846
951
  });
847
952
  // Default hub action shows discover
848
953
  hubCommand.action(async () => {
849
- const hub = new hub_js_1.HubCommand(config, logger);
954
+ const hub = new HubCommand(config, logger);
850
955
  await hub.discover();
851
956
  });
852
957
  // ==================== REPO COMMANDS ====================
@@ -867,7 +972,7 @@ async function main(args) {
867
972
  .option('--open-in <engine>', 'After push, open project in engine: shop, visual, game')
868
973
  .option('--browser', 'Open result URL in default browser', false)
869
974
  .action(async (pathArg, options) => {
870
- const repo = new repo_js_1.RepoCommand(config, logger);
975
+ const repo = new RepoCommand(config, logger);
871
976
  await repo.push({
872
977
  path: pathArg,
873
978
  name: options.name,
@@ -893,7 +998,7 @@ async function main(args) {
893
998
  .option('-o, --output <path>', 'Output directory path')
894
999
  .option('-f, --force', 'Overwrite existing directory', false)
895
1000
  .action(async (name, options) => {
896
- const repo = new repo_js_1.RepoCommand(config, logger);
1001
+ const repo = new RepoCommand(config, logger);
897
1002
  await repo.pull(name, {
898
1003
  output: options.output,
899
1004
  force: options.force
@@ -905,14 +1010,14 @@ async function main(args) {
905
1010
  .description('List all your projects in Vigthoria Repo')
906
1011
  .option('-v, --visibility <type>', 'Filter by visibility (private, restricted, public)')
907
1012
  .action(async (options) => {
908
- const repo = new repo_js_1.RepoCommand(config, logger);
1013
+ const repo = new RepoCommand(config, logger);
909
1014
  await repo.list({ visibility: options.visibility });
910
1015
  });
911
1016
  repoCommand
912
1017
  .command('status')
913
1018
  .description('Show sync status of current project')
914
1019
  .action(async () => {
915
- const repo = new repo_js_1.RepoCommand(config, logger);
1020
+ const repo = new RepoCommand(config, logger);
916
1021
  await repo.status();
917
1022
  });
918
1023
  repoCommand
@@ -920,7 +1025,7 @@ async function main(args) {
920
1025
  .description('Generate a shareable link for a project')
921
1026
  .option('-e, --expires <duration>', 'Link expiration (e.g., 7d, 24h, 30m)', '7d')
922
1027
  .action(async (name, options) => {
923
- const repo = new repo_js_1.RepoCommand(config, logger);
1028
+ const repo = new RepoCommand(config, logger);
924
1029
  await repo.share(name, { expires: options.expires });
925
1030
  });
926
1031
  repoCommand
@@ -928,7 +1033,7 @@ async function main(args) {
928
1033
  .alias('rm')
929
1034
  .description('Remove a project from your Vigthoria Repo')
930
1035
  .action(async (name) => {
931
- const repo = new repo_js_1.RepoCommand(config, logger);
1036
+ const repo = new RepoCommand(config, logger);
932
1037
  await repo.delete(name);
933
1038
  });
934
1039
  repoCommand
@@ -937,7 +1042,7 @@ async function main(args) {
937
1042
  .option('-o, --output <path>', 'Output directory path')
938
1043
  .option('-f, --force', 'Overwrite existing directory', false)
939
1044
  .action(async (url, options) => {
940
- const repo = new repo_js_1.RepoCommand(config, logger);
1045
+ const repo = new RepoCommand(config, logger);
941
1046
  await repo.clone(url, {
942
1047
  output: options.output,
943
1048
  force: options.force
@@ -958,7 +1063,7 @@ Examples:
958
1063
  logger.error(`Unknown engine "${engine}". Valid options: shop, visual, game`);
959
1064
  process.exit(1);
960
1065
  }
961
- const repo = new repo_js_1.RepoCommand(config, logger);
1066
+ const repo = new RepoCommand(config, logger);
962
1067
  await repo.openIn(engine, projectName, {
963
1068
  browser: options.browser,
964
1069
  shopId: options.shopId
@@ -979,7 +1084,7 @@ Examples:
979
1084
  .description('Deploy to free preview URL')
980
1085
  .option('-p, --project <path>', 'Project directory path', process.cwd())
981
1086
  .action(async (options) => {
982
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1087
+ const deploy = new DeployCommand(config, logger);
983
1088
  await deploy.deployToPreview(options.project);
984
1089
  });
985
1090
  deployCommand
@@ -987,7 +1092,7 @@ Examples:
987
1092
  .description('Deploy to yourname.vigthoria.io')
988
1093
  .option('-p, --project <path>', 'Project directory path', process.cwd())
989
1094
  .action(async (name, options) => {
990
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1095
+ const deploy = new DeployCommand(config, logger);
991
1096
  await deploy.deployToSubdomain(name, options.project);
992
1097
  });
993
1098
  deployCommand
@@ -995,7 +1100,7 @@ Examples:
995
1100
  .description('Deploy to your custom domain')
996
1101
  .option('-p, --project <path>', 'Project directory path', process.cwd())
997
1102
  .action(async (domain, options) => {
998
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1103
+ const deploy = new DeployCommand(config, logger);
999
1104
  await deploy.deployToCustomDomain(domain, options.project);
1000
1105
  });
1001
1106
  deployCommand
@@ -1003,28 +1108,28 @@ Examples:
1003
1108
  .alias('ls')
1004
1109
  .description('List all your deployments')
1005
1110
  .action(async () => {
1006
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1111
+ const deploy = new DeployCommand(config, logger);
1007
1112
  await deploy.list();
1008
1113
  });
1009
1114
  deployCommand
1010
1115
  .command('plans')
1011
1116
  .description('Show hosting plans and pricing')
1012
1117
  .action(async () => {
1013
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1118
+ const deploy = new DeployCommand(config, logger);
1014
1119
  await deploy.showPlans();
1015
1120
  });
1016
1121
  deployCommand
1017
1122
  .command('status [domain]')
1018
1123
  .description('Check deployment status')
1019
1124
  .action(async (domain) => {
1020
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1125
+ const deploy = new DeployCommand(config, logger);
1021
1126
  await deploy.status(domain);
1022
1127
  });
1023
1128
  deployCommand
1024
1129
  .command('verify <domain>')
1025
1130
  .description('Verify DNS configuration for custom domain')
1026
1131
  .action(async (domain) => {
1027
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1132
+ const deploy = new DeployCommand(config, logger);
1028
1133
  await deploy.verify(domain);
1029
1134
  });
1030
1135
  deployCommand
@@ -1032,7 +1137,7 @@ Examples:
1032
1137
  .alias('rm')
1033
1138
  .description('Remove a deployment')
1034
1139
  .action(async (domain) => {
1035
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1140
+ const deploy = new DeployCommand(config, logger);
1036
1141
  await deploy.remove(domain);
1037
1142
  });
1038
1143
  // Default deploy action shows interactive wizard
@@ -1041,7 +1146,7 @@ Examples:
1041
1146
  .option('-d, --domain <domain>', 'Deploy to custom domain')
1042
1147
  .option('-p, --project <path>', 'Project directory path', process.cwd())
1043
1148
  .action(async (options) => {
1044
- const deploy = new deploy_js_1.DeployCommand(config, logger);
1149
+ const deploy = new DeployCommand(config, logger);
1045
1150
  await deploy.deploy({
1046
1151
  subdomain: options.subdomain,
1047
1152
  domain: options.domain,
@@ -1060,7 +1165,7 @@ Examples:
1060
1165
  .option('--proof', 'Run Template Service preview gate and persist proof bundle')
1061
1166
  .option('--screenshot', 'Capture screenshot via Puppeteer')
1062
1167
  .action(async (options) => {
1063
- const preview = new preview_js_1.PreviewCommand(config, logger);
1168
+ const preview = new PreviewCommand(config, logger);
1064
1169
  await preview.run({
1065
1170
  project: options.project,
1066
1171
  entry: options.entry,
@@ -1092,7 +1197,7 @@ Examples:
1092
1197
  .option('-w, --worker <name>', 'Execute a specific worker')
1093
1198
  .option('-p, --project <path>', 'Project directory', process.cwd())
1094
1199
  .action(async (request, options) => {
1095
- const legion = new legion_js_1.LegionCommand(config, logger);
1200
+ const legion = new LegionCommand(config, logger);
1096
1201
  const parsedTimeout = Number.parseInt(String(options.timeout || ''), 10);
1097
1202
  await legion.run(request, {
1098
1203
  workers: options.workers,
@@ -1122,7 +1227,7 @@ Examples:
1122
1227
  .option('-p, --project <path>', 'Project directory', process.cwd())
1123
1228
  .option('--json', 'Machine-readable JSON output', false)
1124
1229
  .action(async (options) => {
1125
- const history = new history_js_1.HistoryCommand(config, logger);
1230
+ const history = new HistoryCommand(config, logger);
1126
1231
  await history.run({ limit: parseInt(options.limit, 10) || 20, json: options.json, project: options.project });
1127
1232
  });
1128
1233
  program
@@ -1132,7 +1237,7 @@ Examples:
1132
1237
  .option('-p, --project <path>', 'Project directory', process.cwd())
1133
1238
  .option('--json', 'Machine-readable JSON output', false)
1134
1239
  .action(async (runId, options) => {
1135
- const replay = new replay_js_1.ReplayCommand(config, logger);
1240
+ const replay = new ReplayCommand(config, logger);
1136
1241
  await replay.run(runId, { speed: parseInt(options.speed, 10) || 200, json: options.json, project: options.project });
1137
1242
  });
1138
1243
  program
@@ -1142,7 +1247,7 @@ Examples:
1142
1247
  .option('-p, --project <path>', 'Project directory', process.cwd())
1143
1248
  .option('--json', 'Machine-readable JSON output', false)
1144
1249
  .action(async (runId, message, options) => {
1145
- const fork = new fork_js_1.ForkCommand(config, logger);
1250
+ const fork = new ForkCommand(config, logger);
1146
1251
  await fork.run(runId, message || '', { eventIndex: parseInt(options.eventIndex, 10) || 0, project: options.project, json: options.json });
1147
1252
  });
1148
1253
  program
@@ -1152,7 +1257,7 @@ Examples:
1152
1257
  .option('-l, --list', 'List active runs without cancelling', false)
1153
1258
  .option('--json', 'Machine-readable JSON output', false)
1154
1259
  .action(async (contextId, options) => {
1155
- const cancel = new cancel_js_1.CancelCommand(config, logger);
1260
+ const cancel = new CancelCommand(config, logger);
1156
1261
  await cancel.run(contextId, { all: options.all, list: options.list, json: options.json });
1157
1262
  });
1158
1263
  // ==================== AUTH COMMANDS ====================
@@ -1165,32 +1270,90 @@ Examples:
1165
1270
  .option('-p, --password <password>', 'Account password for credential-based login')
1166
1271
  .option('--device', 'Use OAuth device flow (requires server support)')
1167
1272
  .action(async (options) => {
1168
- await (0, auth_js_1.handleLogin)(options);
1273
+ await handleLogin(options);
1169
1274
  });
1170
1275
  program
1171
1276
  .command('logout')
1172
1277
  .description('Logout from Vigthoria Coder')
1173
1278
  .action(async () => {
1174
- await (0, auth_js_1.handleLogout)(null);
1279
+ await handleLogout(null);
1175
1280
  });
1176
1281
  program
1177
1282
  .command('status')
1178
1283
  .description('Show authentication and subscription status')
1179
1284
  .action(async () => {
1180
- await (0, auth_js_1.statusAction)();
1285
+ await statusAction();
1181
1286
  });
1182
1287
  program
1183
1288
  .command('doctor')
1184
- .description('Run local Vigthoria CLI diagnostics')
1185
- .action(() => {
1186
- const checks = [
1187
- ['Node.js', process.version],
1188
- ['Platform', `${process.platform} ${process.arch}`],
1189
- ['Working directory', process.cwd()],
1190
- ];
1191
- console.log('Vigthoria CLI diagnostics');
1192
- for (const [label, value] of checks) {
1193
- console.log(`- ${label}: ${value}`);
1289
+ .description('Run local Vigthoria CLI diagnostics (no network calls unless --check-api)')
1290
+ .option('--check-api', 'Also probe Vigthoria API reachability', false)
1291
+ .option('--json', 'Emit machine-readable JSON output', false)
1292
+ .action(async (options) => {
1293
+ const apiUrl = String(config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
1294
+ const modelsApiUrl = String(config.get('modelsApiUrl') || 'https://api.vigthoria.io').replace(/\/$/, '');
1295
+ const offline = isOfflineMode();
1296
+ const updateSuppressed = isUpdateCheckSuppressed();
1297
+ const subscription = config.get('subscription') || { plan: null, status: null, expiresAt: null };
1298
+ const report = {
1299
+ cliVersion: VERSION,
1300
+ nodeVersion: process.version,
1301
+ platform: `${process.platform} ${process.arch}`,
1302
+ cwd: process.cwd(),
1303
+ homeDir: os.homedir(),
1304
+ configPath: config.getConfigPath(),
1305
+ stateFile: getCliStateFile(),
1306
+ apiUrl,
1307
+ modelsApiUrl,
1308
+ loggedIn: config.isAuthenticated(),
1309
+ subscriptionPlan: subscription.plan || null,
1310
+ subscriptionStatus: subscription.status || null,
1311
+ offlineMode: offline,
1312
+ updateCheckSuppressed: updateSuppressed,
1313
+ envOverrides: {
1314
+ VIGTHORIA_API_URL: process.env.VIGTHORIA_API_URL || null,
1315
+ VIGTHORIA_V3_AGENT_URL: process.env.VIGTHORIA_V3_AGENT_URL || null,
1316
+ VIGTHORIA_OFFLINE: process.env.VIGTHORIA_OFFLINE || null,
1317
+ VIGTHORIA_TOKEN: process.env.VIGTHORIA_TOKEN ? '<set>' : null,
1318
+ HYPERLOOP_SERVICE_KEY: process.env.HYPERLOOP_SERVICE_KEY ? '<set>' : null,
1319
+ V3_SERVICE_KEY: process.env.V3_SERVICE_KEY ? '<set>' : null,
1320
+ },
1321
+ };
1322
+ if (options.checkApi && !offline) {
1323
+ try {
1324
+ const probe = await axios.get(`${apiUrl}/api/health`, { timeout: 4000, validateStatus: () => true });
1325
+ report.apiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
1326
+ }
1327
+ catch (error) {
1328
+ report.apiHealth = `unreachable (${error.message})`;
1329
+ }
1330
+ try {
1331
+ const probe = await axios.get(`${modelsApiUrl}/health`, { timeout: 4000, validateStatus: () => true });
1332
+ report.modelsApiHealth = probe.status >= 200 && probe.status < 400 ? 'online' : `status ${probe.status}`;
1333
+ }
1334
+ catch (error) {
1335
+ report.modelsApiHealth = `unreachable (${error.message})`;
1336
+ }
1337
+ }
1338
+ if (options.json) {
1339
+ console.log(JSON.stringify(report, null, 2));
1340
+ }
1341
+ else {
1342
+ console.log(chalk.bold('Vigthoria CLI diagnostics'));
1343
+ for (const [key, value] of Object.entries(report)) {
1344
+ if (value && typeof value === 'object') {
1345
+ console.log(chalk.gray(`- ${key}:`));
1346
+ for (const [subKey, subVal] of Object.entries(value)) {
1347
+ console.log(chalk.gray(` - ${subKey}: ${subVal ?? '(none)'}`));
1348
+ }
1349
+ }
1350
+ else {
1351
+ console.log(chalk.gray(`- ${key}: ${value ?? '(none)'}`));
1352
+ }
1353
+ }
1354
+ if (!options.checkApi) {
1355
+ console.log(chalk.gray('\nTip: pass --check-api to verify API reachability.'));
1356
+ }
1194
1357
  }
1195
1358
  process.exitCode = 0;
1196
1359
  });
@@ -1203,7 +1366,7 @@ Examples:
1203
1366
  .option('-l, --list', 'List all settings')
1204
1367
  .option('-r, --reset', 'Reset to defaults')
1205
1368
  .action(async (options) => {
1206
- const configCmd = new config_js_1.ConfigCommand(config, logger);
1369
+ const configCmd = new ConfigCommand(config, logger);
1207
1370
  await configCmd.run(options);
1208
1371
  });
1209
1372
  // Update command - Check for and install updates
@@ -1224,77 +1387,89 @@ Examples:
1224
1387
  const allowDowngrade = !!options.allowDowngrade;
1225
1388
  const gitPackageSpec = 'git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git';
1226
1389
  if (updateTarget) {
1390
+ if (!isSafeNpmPackageSpec(updateTarget)) {
1391
+ console.error(chalk.red('Refusing to run installer with unsafe package spec.'));
1392
+ console.error(chalk.gray('Allowed characters: A-Z a-z 0-9 . _ - / @ : + \\ ='));
1393
+ process.exitCode = 1;
1394
+ return;
1395
+ }
1227
1396
  try {
1228
1397
  if (options.check) {
1229
- console.log(chalk_1.default.cyan(`Update source configured: ${updateTarget}`));
1230
- console.log(chalk_1.default.gray('Run `vigthoria update --from <target>` to install from this source'));
1398
+ console.log(chalk.cyan(`Update source configured: ${updateTarget}`));
1399
+ console.log(chalk.gray('Run `vigthoria update --from <target>` to install from this source'));
1231
1400
  return;
1232
1401
  }
1233
- console.log(chalk_1.default.cyan(`Installing update from ${updateTarget}...`));
1402
+ console.log(chalk.cyan(`Installing update from ${updateTarget}...`));
1234
1403
  await installGlobalPackageWithNpm(updateTarget);
1235
- console.log(chalk_1.default.green('Update installed successfully'));
1236
- console.log(chalk_1.default.gray('Please restart the CLI to use the new version'));
1404
+ console.log(chalk.green('Update installed successfully'));
1405
+ console.log(chalk.gray('Please restart the CLI to use the new version'));
1237
1406
  return;
1238
1407
  }
1239
1408
  catch (error) {
1240
- console.error(chalk_1.default.red('Failed to install update from target:'), error.message);
1241
- console.log(chalk_1.default.gray(`Try manually: npm install -g ${updateTarget}`));
1409
+ console.error(chalk.red('Failed to install update from target:'), error.message);
1410
+ console.log(chalk.gray(`Try manually: npm install -g ${updateTarget}`));
1242
1411
  process.exitCode = 1;
1243
1412
  return;
1244
1413
  }
1245
1414
  }
1246
1415
  if (manifestUrl) {
1416
+ if (isOfflineMode()) {
1417
+ console.log(chalk.yellow('Offline mode (VIGTHORIA_OFFLINE=1): skipping manifest update.'));
1418
+ return;
1419
+ }
1247
1420
  try {
1248
- console.log(chalk_1.default.cyan(`Checking manifest channel ${channel}...`));
1249
- const response = await axios_1.default.get(manifestUrl, {
1421
+ console.log(chalk.cyan(`Checking manifest channel ${channel}...`));
1422
+ const response = await axios.get(manifestUrl, {
1250
1423
  timeout: 10000,
1251
1424
  maxRedirects: 5,
1252
1425
  validateStatus: (status) => status >= 200 && status < 300,
1253
1426
  });
1254
1427
  const entry = resolveManifestEntry(response.data || {}, channel);
1255
1428
  if (!entry || !entry.version || !entry.url) {
1256
- console.error(chalk_1.default.red(`Manifest missing valid release entry for channel: ${channel}`));
1257
- console.log(chalk_1.default.gray('Expected: channels.<channel>.version and channels.<channel>.url'));
1429
+ console.error(chalk.red(`Manifest missing valid release entry for channel: ${channel}`));
1430
+ console.log(chalk.gray('Expected: channels.<channel>.version and channels.<channel>.url'));
1258
1431
  process.exitCode = 1;
1259
1432
  return;
1260
1433
  }
1261
1434
  const currentVersion = VERSION;
1262
1435
  const comparison = compareVersions(entry.version, currentVersion);
1263
1436
  if (!allowDowngrade && comparison <= 0) {
1264
- console.log(chalk_1.default.green(`You are running the latest version for channel ${channel} (${currentVersion})`));
1437
+ console.log(chalk.green(`You are running the latest version for channel ${channel} (${currentVersion})`));
1265
1438
  return;
1266
1439
  }
1267
- console.log(chalk_1.default.yellow(`Update available from manifest: ${currentVersion} -> ${entry.version} (${channel})`));
1440
+ console.log(chalk.yellow(`Update available from manifest: ${currentVersion} -> ${entry.version} (${channel})`));
1268
1441
  if (entry.notes) {
1269
- console.log(chalk_1.default.gray(` ${entry.notes}`));
1442
+ console.log(chalk.gray(` ${entry.notes}`));
1270
1443
  }
1271
1444
  if (options.check) {
1272
- console.log(chalk_1.default.gray(`Install with: vigthoria update --manifest ${manifestUrl} --channel ${channel}`));
1445
+ console.log(chalk.gray(`Install with: vigthoria update --manifest ${manifestUrl} --channel ${channel}`));
1273
1446
  return;
1274
1447
  }
1275
1448
  const tmpFile = path.join(os.tmpdir(), `vigthoria-update-${Date.now()}.tgz`);
1276
1449
  try {
1277
- console.log(chalk_1.default.cyan('Downloading release package...'));
1450
+ console.log(chalk.cyan('Downloading release package...'));
1278
1451
  await downloadFile(entry.url, tmpFile);
1279
1452
  if (entry.sha256) {
1280
1453
  const expected = entry.sha256.toLowerCase();
1281
1454
  const actual = sha256File(tmpFile).toLowerCase();
1282
1455
  if (actual !== expected) {
1283
- console.error(chalk_1.default.red('Release checksum verification failed'));
1284
- console.error(chalk_1.default.red(`Expected: ${expected}`));
1285
- console.error(chalk_1.default.red(`Actual: ${actual}`));
1456
+ console.error(chalk.red('Release checksum verification failed'));
1457
+ console.error(chalk.red(`Expected: ${expected}`));
1458
+ console.error(chalk.red(`Actual: ${actual}`));
1286
1459
  process.exitCode = 1;
1287
1460
  return;
1288
1461
  }
1289
- console.log(chalk_1.default.green('Checksum verification passed'));
1462
+ console.log(chalk.green('Checksum verification passed'));
1290
1463
  }
1291
1464
  else {
1292
- console.log(chalk_1.default.yellow('Manifest entry has no sha256; install proceeded without checksum verification'));
1465
+ console.log(chalk.yellow.bold('WARNING: manifest entry has no sha256.'));
1466
+ console.log(chalk.yellow(' The release artifact will be installed without integrity verification.'));
1467
+ console.log(chalk.gray(' Set --manifest to a trusted source, or supply sha256 in the manifest entry.'));
1293
1468
  }
1294
- console.log(chalk_1.default.cyan('Installing update...'));
1469
+ console.log(chalk.cyan('Installing update...'));
1295
1470
  await installGlobalPackageWithNpm(tmpFile);
1296
- console.log(chalk_1.default.green(`Updated to version ${entry.version}`));
1297
- console.log(chalk_1.default.gray('Please restart the CLI to use the new version'));
1471
+ console.log(chalk.green(`Updated to version ${entry.version}`));
1472
+ console.log(chalk.gray('Please restart the CLI to use the new version'));
1298
1473
  return;
1299
1474
  }
1300
1475
  finally {
@@ -1307,11 +1482,15 @@ Examples:
1307
1482
  }
1308
1483
  }
1309
1484
  catch (error) {
1310
- console.error(chalk_1.default.red('Failed to process manifest update:'), error.message);
1311
- console.log(chalk_1.default.gray('Falling back to npm/git update channels...'));
1485
+ console.error(chalk.red('Failed to process manifest update:'), error.message);
1486
+ console.log(chalk.gray('Falling back to npm/git update channels...'));
1312
1487
  }
1313
1488
  }
1314
- console.log(chalk_1.default.cyan('Checking for updates...'));
1489
+ if (isOfflineMode()) {
1490
+ console.log(chalk.yellow('Offline mode (VIGTHORIA_OFFLINE=1): skipping update check.'));
1491
+ return;
1492
+ }
1493
+ console.log(chalk.cyan('Checking for updates...'));
1315
1494
  try {
1316
1495
  // Get latest version from npm - cross-platform
1317
1496
  const latestVersion = execSync('npm view vigthoria-cli version', {
@@ -1323,35 +1502,35 @@ Examples:
1323
1502
  // Use semantic version comparison (1.6.0 > 1.5.9)
1324
1503
  const comparison = compareVersions(latestVersion, currentVersion);
1325
1504
  if (comparison <= 0) {
1326
- console.log(chalk_1.default.green(`You are running the latest version (${currentVersion})`));
1505
+ console.log(chalk.green(`You are running the latest version (${currentVersion})`));
1327
1506
  return;
1328
1507
  }
1329
- console.log(chalk_1.default.yellow(`Update available: ${currentVersion} -> ${latestVersion}`));
1508
+ console.log(chalk.yellow(`Update available: ${currentVersion} -> ${latestVersion}`));
1330
1509
  if (options.check) {
1331
- console.log(chalk_1.default.gray('Run `vigthoria update` to install the update'));
1510
+ console.log(chalk.gray('Run `vigthoria update` to install the update'));
1332
1511
  return;
1333
1512
  }
1334
- console.log(chalk_1.default.cyan('Installing update from npm registry...'));
1513
+ console.log(chalk.cyan('Installing update from npm registry...'));
1335
1514
  await installGlobalPackageWithNpm('vigthoria-cli@latest');
1336
- console.log(chalk_1.default.green(`Updated to version ${latestVersion}`));
1337
- console.log(chalk_1.default.gray('Please restart the CLI to use the new version'));
1515
+ console.log(chalk.green(`Updated to version ${latestVersion}`));
1516
+ console.log(chalk.gray('Please restart the CLI to use the new version'));
1338
1517
  }
1339
1518
  catch (error) {
1340
- console.error(chalk_1.default.red('Failed to check/install via npm registry:'), error.message);
1519
+ console.error(chalk.red('Failed to check/install via npm registry:'), error.message);
1341
1520
  if (options.check) {
1342
- console.log(chalk_1.default.gray(`npm registry check failed; fallback install target is ${gitPackageSpec}`));
1521
+ console.log(chalk.gray(`npm registry check failed; fallback install target is ${gitPackageSpec}`));
1343
1522
  return;
1344
1523
  }
1345
1524
  try {
1346
- console.log(chalk_1.default.cyan('Attempting git package fallback...'));
1525
+ console.log(chalk.cyan('Attempting git package fallback...'));
1347
1526
  await installGlobalPackageWithNpm(gitPackageSpec);
1348
- console.log(chalk_1.default.green('Updated via git package fallback'));
1349
- console.log(chalk_1.default.gray('Please restart the CLI to use the new version'));
1527
+ console.log(chalk.green('Updated via git package fallback'));
1528
+ console.log(chalk.gray('Please restart the CLI to use the new version'));
1350
1529
  }
1351
1530
  catch (fallbackError) {
1352
- console.error(chalk_1.default.red('Fallback update also failed:'), fallbackError.message);
1353
- console.log(chalk_1.default.gray('Try manually: npm install -g vigthoria-cli@latest'));
1354
- console.log(chalk_1.default.gray(`Or: npm install -g ${gitPackageSpec}`));
1531
+ console.error(chalk.red('Fallback update also failed:'), fallbackError.message);
1532
+ console.log(chalk.gray('Try manually: npm install -g vigthoria-cli@latest'));
1533
+ console.log(chalk.gray(`Or: npm install -g ${gitPackageSpec}`));
1355
1534
  process.exitCode = 1;
1356
1535
  }
1357
1536
  }
@@ -1363,7 +1542,7 @@ Examples:
1363
1542
  .command('status')
1364
1543
  .description('Show Hyper Loop Legion infrastructure status')
1365
1544
  .action(async () => {
1366
- const legion = new legion_js_1.LegionCommand(config, logger);
1545
+ const legion = new LegionCommand(config, logger);
1367
1546
  await legion.run(undefined, {
1368
1547
  status: true,
1369
1548
  workers: false,
@@ -1383,7 +1562,7 @@ Examples:
1383
1562
  .command('connect')
1384
1563
  .description('Connect to DevTools Bridge')
1385
1564
  .action(async () => {
1386
- const bridge = new bridge_js_1.BridgeCommand(config, logger);
1565
+ const bridge = new BridgeCommand(config, logger);
1387
1566
  await bridge.status();
1388
1567
  });
1389
1568
  // Init command - Initialize project
@@ -1391,7 +1570,7 @@ Examples:
1391
1570
  .command('init')
1392
1571
  .description('Initialize Vigthoria in current project')
1393
1572
  .action(async () => {
1394
- const configCmd = new config_js_1.ConfigCommand(config, logger);
1573
+ const configCmd = new ConfigCommand(config, logger);
1395
1574
  await configCmd.init();
1396
1575
  });
1397
1576
  const codingCommandDefinitions = [
@@ -1410,7 +1589,7 @@ Examples:
1410
1589
  .option('-p, --project <path>', 'Project directory', process.cwd())
1411
1590
  .action(async (requestParts = [], options) => {
1412
1591
  const requestText = requestParts.join(' ').trim();
1413
- const chat = new chat_js_1.ChatCommand(config, logger);
1592
+ const chat = new ChatCommand(config, logger);
1414
1593
  await chat.run({
1415
1594
  model: options.model || 'code',
1416
1595
  project: options.project || process.cwd(),
@@ -1421,7 +1600,7 @@ Examples:
1421
1600
  try {
1422
1601
  // Default to chat if no command
1423
1602
  if (args.length === 2) {
1424
- const chat = new chat_js_1.ChatCommand(config, logger);
1603
+ const chat = new ChatCommand(config, logger);
1425
1604
  await chat.run({ model: 'code', project: process.cwd() });
1426
1605
  process.exitCode = 0;
1427
1606
  return;
@@ -1437,10 +1616,6 @@ Examples:
1437
1616
  }
1438
1617
  }
1439
1618
  setupErrorHandlers();
1440
- process.on('unhandledRejection', (reason) => {
1441
- handleFatalCliError(reason, process.argv.includes('--json'));
1442
- process.exit(1);
1443
- });
1444
1619
  async function bootstrapCli() {
1445
1620
  try {
1446
1621
  await main(process.argv);
@@ -1459,4 +1634,4 @@ void (async () => {
1459
1634
  process.exit(1);
1460
1635
  }
1461
1636
  })();
1462
- exports.__cliErrorHandlingReady = true;
1637
+ export const __cliErrorHandlingReady = true;