vigthoria-cli 1.8.3 → 1.8.5

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.
@@ -75,6 +75,11 @@ export declare class ChatCommand {
75
75
  private v3ToolCallCount;
76
76
  private v3LastActivity;
77
77
  private v3StreamingStarted;
78
+ /**
79
+ * Strip server-internal path prefixes from tool output strings.
80
+ * Prevents exposing paths like /var/www/V3-Code-Agent/... to end users.
81
+ */
82
+ private sanitizeServerPath;
78
83
  private describeV3AgentTool;
79
84
  private updateV3AgentSpinner;
80
85
  private updateOperatorSpinner;
@@ -299,6 +299,20 @@ class ChatCommand {
299
299
  v3ToolCallCount = 0;
300
300
  v3LastActivity = Date.now();
301
301
  v3StreamingStarted = false;
302
+ /**
303
+ * Strip server-internal path prefixes from tool output strings.
304
+ * Prevents exposing paths like /var/www/V3-Code-Agent/... to end users.
305
+ */
306
+ sanitizeServerPath(text) {
307
+ if (!text)
308
+ return text;
309
+ // Strip common server path prefixes from output
310
+ return text
311
+ .replace(/\/var\/www\/V3-Code-Agent\//g, '')
312
+ .replace(/\/var\/www\/[a-zA-Z0-9_-]+\//g, '')
313
+ .replace(/\/tmp\/vig-remote-[a-zA-Z0-9_-]+\//g, '')
314
+ .replace(/\/opt\/vigthoria[a-zA-Z0-9_/-]*\//g, '');
315
+ }
302
316
  describeV3AgentTool(toolName) {
303
317
  const normalized = String(toolName || '').toLowerCase();
304
318
  if (/read|grep|search|list|find|glob/.test(normalized)) {
@@ -324,7 +338,8 @@ class ChatCommand {
324
338
  this.v3ToolCallCount += 1;
325
339
  const toolDesc = this.describeV3AgentTool(event.tool || event.name || event.tool_name);
326
340
  const toolTarget = event.arguments?.path || event.arguments?.file_path || event.arguments?.pattern || '';
327
- const shortTarget = toolTarget ? ` → ${String(toolTarget).split('/').slice(-2).join('/')}` : '';
341
+ const sanitizedTarget = this.sanitizeServerPath(String(toolTarget));
342
+ const shortTarget = sanitizedTarget ? ` → ${sanitizedTarget.replace(/\\/g, '/').split('/').slice(-2).join('/')}` : '';
328
343
  const stepLabel = chalk_1.default.cyan(` [${this.v3IterationCount}/${this.v3ToolCallCount}]`) + ` ${toolDesc}${shortTarget}`;
329
344
  if (spinner.isSpinning)
330
345
  spinner.stop();
@@ -350,10 +365,12 @@ class ChatCommand {
350
365
  if (spinner.isSpinning)
351
366
  spinner.stop();
352
367
  process.stderr.write(`${indicator} ${toolName}\n`);
353
- // Show output for failures, or brief summary for successes
354
- const output = typeof event.output === 'string' ? event.output.trim() : '';
368
+ // Show output for failures, or brief summary for successes — sanitize server paths
369
+ const rawOutput = typeof event.output === 'string' ? event.output.trim() : '';
370
+ const output = this.sanitizeServerPath(rawOutput);
355
371
  if (!success && output) {
356
- const lines = output.split('\n').slice(0, 4);
372
+ const sanitizedError = this.sanitizeServerPath(typeof event.error === 'string' ? event.error : output);
373
+ const lines = sanitizedError.split('\n').slice(0, 4);
357
374
  process.stderr.write(chalk_1.default.red(` ${lines.join('\n ')}\n`));
358
375
  }
359
376
  else if (success && output && output.length > 0) {
@@ -452,7 +469,8 @@ class ChatCommand {
452
469
  return;
453
470
  }
454
471
  if (event.type === 'file_mutation') {
455
- const filePath = typeof event.path === 'string' ? event.path.split('/').slice(-2).join('/') : '';
472
+ const rawPath = typeof event.path === 'string' ? this.sanitizeServerPath(event.path) : '';
473
+ const filePath = rawPath ? rawPath.replace(/\\/g, '/').split('/').slice(-2).join('/') : '';
456
474
  const action = event.action === 'delete' ? chalk_1.default.red('deleted') : chalk_1.default.green('wrote');
457
475
  if (filePath) {
458
476
  if (spinner.isSpinning)
@@ -1606,7 +1624,7 @@ class ChatCommand {
1606
1624
  clientSurface: 'cli',
1607
1625
  localMachineCapable: true,
1608
1626
  agentTimeoutMs: DEFAULT_V3_AGENT_TIMEOUT_MS,
1609
- agentIdleTimeoutMs: 0,
1627
+ agentIdleTimeoutMs: 90000,
1610
1628
  model: routingPolicy.selectedModel,
1611
1629
  requestedModel: this.currentModel,
1612
1630
  agentExecutionPolicy: routingPolicy,
@@ -1620,7 +1638,7 @@ class ChatCommand {
1620
1638
  ? Promise.race([
1621
1639
  workflowPromise,
1622
1640
  new Promise((_, reject) => {
1623
- setTimeout(() => reject(new Error('V3_SAAS_SOFT_TIMEOUT')), 3600000);
1641
+ setTimeout(() => reject(new Error('V3_SAAS_SOFT_TIMEOUT')), 240000);
1624
1642
  }),
1625
1643
  ])
1626
1644
  : workflowPromise);
@@ -81,6 +81,14 @@ export declare class RepoCommand {
81
81
  * Delete a project from Vigthoria Repository
82
82
  */
83
83
  delete(projectName: string): Promise<void>;
84
+ /**
85
+ * Open a project in a Vigthoria engine (shop, visual, game).
86
+ * Pushes to community if not yet there, then triggers engine import.
87
+ */
88
+ openIn(engine: 'shop' | 'visual' | 'game', projectName?: string, options?: {
89
+ browser?: boolean;
90
+ shopId?: string;
91
+ }): Promise<void>;
84
92
  /**
85
93
  * Clone a public project from Vigthoria Repository
86
94
  */
@@ -714,6 +714,64 @@ class RepoCommand {
714
714
  console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
715
715
  }
716
716
  }
717
+ /**
718
+ * Open a project in a Vigthoria engine (shop, visual, game).
719
+ * Pushes to community if not yet there, then triggers engine import.
720
+ */
721
+ async openIn(engine, projectName, options = {}) {
722
+ this.requireAuth();
723
+ const engineLabels = {
724
+ shop: 'Shop Engine',
725
+ visual: 'Visual Editor',
726
+ game: 'Gaming Engine'
727
+ };
728
+ const label = engineLabels[engine] || engine;
729
+ // Resolve project name from arg or current directory
730
+ const resolvedName = projectName || this.detectProjectInfo(process.cwd()).name;
731
+ const spinner = (0, logger_js_1.createSpinner)(`Opening "${resolvedName}" in ${label}...`).start();
732
+ try {
733
+ const response = await fetch(`${this.apiBase}/api/engine-import`, {
734
+ method: 'POST',
735
+ headers: this.getAuthHeaders(),
736
+ body: JSON.stringify({
737
+ engine,
738
+ projectName: resolvedName,
739
+ shopId: options.shopId || 'default',
740
+ source: 'repo'
741
+ })
742
+ });
743
+ if (!response.ok) {
744
+ const err = await response.json().catch(async () => ({ error: await response.text() }));
745
+ throw new Error(err.error || `Engine import failed (${response.status})`);
746
+ }
747
+ const data = await response.json();
748
+ spinner.succeed(chalk_1.default.green(`Project imported into ${label}!`));
749
+ console.log(chalk_1.default.cyan(`\n🚀 Open in browser:`));
750
+ console.log(chalk_1.default.bold(` ${data.url}\n`));
751
+ if (options.browser) {
752
+ try {
753
+ const { execSync } = await import('child_process');
754
+ const platform = process.platform;
755
+ if (platform === 'win32')
756
+ execSync(`start "" "${data.url}"`, { stdio: 'ignore' });
757
+ else if (platform === 'darwin')
758
+ execSync(`open "${data.url}"`, { stdio: 'ignore' });
759
+ else
760
+ execSync(`xdg-open "${data.url}"`, { stdio: 'ignore' });
761
+ }
762
+ catch { /* browser open is optional */ }
763
+ }
764
+ if (data.message) {
765
+ console.log(chalk_1.default.gray(` ${data.message}\n`));
766
+ }
767
+ }
768
+ catch (error) {
769
+ spinner.stop();
770
+ const errMsg = error instanceof Error ? error.message : 'Unknown error';
771
+ console.log(chalk_1.default.red(`\n❌ ${label} import failed: ${errMsg}\n`));
772
+ console.log(chalk_1.default.gray('Tip: Make sure your project is pushed first with `vigthoria repo push`\n'));
773
+ }
774
+ }
717
775
  /**
718
776
  * Clone a public project from Vigthoria Repository
719
777
  */
package/dist/index.js CHANGED
@@ -514,6 +514,8 @@ async function main() {
514
514
  .option('-d, --description <text>', 'Project description')
515
515
  .option('-f, --force', 'Overwrite existing project', false)
516
516
  .option('-y, --yes', 'Run non-interactively with provided/default values', false)
517
+ .option('--open-in <engine>', 'After push, open project in engine: shop, visual, game')
518
+ .option('--browser', 'Open result URL in default browser', false)
517
519
  .action(async (pathArg, options) => {
518
520
  const repo = new repo_js_1.RepoCommand(config, logger);
519
521
  await repo.push({
@@ -524,6 +526,15 @@ async function main() {
524
526
  force: options.force,
525
527
  yes: options.yes
526
528
  });
529
+ if (options.openIn) {
530
+ const engine = options.openIn;
531
+ if (!['shop', 'visual', 'game'].includes(engine)) {
532
+ logger.warn(`Unknown engine "${engine}". Use: shop, visual, game`);
533
+ }
534
+ else {
535
+ await repo.openIn(engine, options.name || undefined, { browser: options.browser });
536
+ }
537
+ }
527
538
  });
528
539
  repoCommand
529
540
  .command('pull <name>')
@@ -582,6 +593,27 @@ async function main() {
582
593
  force: options.force
583
594
  });
584
595
  });
596
+ repoCommand
597
+ .command('open-in <engine> [projectName]')
598
+ .description('Open a Vigthoria Repo project in the Shop Engine, Visual Editor, or Gaming Engine')
599
+ .option('--browser', 'Open result URL in default browser', false)
600
+ .option('--shop-id <id>', 'Target shop ID (for shop engine)', 'default')
601
+ .addHelpText('after', `
602
+ Examples:
603
+ vigthoria repo open-in shop my-store
604
+ vigthoria repo open-in visual my-website
605
+ vigthoria repo open-in game my-game --browser`)
606
+ .action(async (engine, projectName, options) => {
607
+ if (!['shop', 'visual', 'game'].includes(engine)) {
608
+ logger.error(`Unknown engine "${engine}". Valid options: shop, visual, game`);
609
+ process.exit(1);
610
+ }
611
+ const repo = new repo_js_1.RepoCommand(config, logger);
612
+ await repo.openIn(engine, projectName, {
613
+ browser: options.browser,
614
+ shopId: options.shopId
615
+ });
616
+ });
585
617
  // Default repo action shows help with available subcommands
586
618
  repoCommand.action(() => {
587
619
  repoCommand.outputHelp();
package/dist/utils/api.js CHANGED
@@ -100,9 +100,9 @@ const DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS = (() => {
100
100
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 90000;
101
101
  })();
102
102
  const DEFAULT_OPERATOR_TIMEOUT_MS = (() => {
103
- const rawValue = process.env.VIGTHORIA_OPERATOR_TIMEOUT_MS || process.env.OPERATOR_TIMEOUT_MS || '1800000';
103
+ const rawValue = process.env.VIGTHORIA_OPERATOR_TIMEOUT_MS || process.env.OPERATOR_TIMEOUT_MS || '300000';
104
104
  const parsed = Number.parseInt(rawValue, 10);
105
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 1800000;
105
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 300000;
106
106
  })();
107
107
  class APIClient {
108
108
  client;
@@ -2732,7 +2732,7 @@ document.addEventListener('DOMContentLoaded', () => {
2732
2732
  && context.localMachineCapable !== false;
2733
2733
  const rescueEligibleSaaS = preferLocalV3
2734
2734
  && /(saas|dashboard|analytics|billing|team management|activity feed|login screen)/i.test(message);
2735
- const timeoutMs = rescueEligibleSaaS ? Math.min(baseTimeoutMs, 3600000) : baseTimeoutMs;
2735
+ const timeoutMs = rescueEligibleSaaS ? Math.min(baseTimeoutMs, 210000) : baseTimeoutMs;
2736
2736
  const maxAttempts = preferLocalV3 ? 2 : 1;
2737
2737
  let lastErrors = [];
2738
2738
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.8.3",
3
+ "version": "1.8.5",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -43,7 +43,8 @@
43
43
  "test:repo:live": "npm run build && node scripts/test-live-repo-e2e.js",
44
44
  "test:game:live": "npm run build && node scripts/test-live-game-push.js",
45
45
  "proof:agent": "npm run build && node scripts/proof-agent-mode.js",
46
- "test:fresh-install": "node scripts/test-fresh-install.js"
46
+ "test:fresh-install": "node scripts/test-fresh-install.js",
47
+ "prepublishOnly": "npm run build && node scripts/verify-package-hygiene.js && node scripts/test-fresh-install.js"
47
48
  },
48
49
  "keywords": [
49
50
  "ai",