vigthoria-cli 1.9.2 → 1.9.8

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.
@@ -47,7 +47,7 @@ const defaultConfig = {
47
47
  };
48
48
  class Config {
49
49
  store;
50
- static OPERATOR_PLANS = new Set(['enterprise', 'admin', 'master_admin']);
50
+ static OPERATOR_PLANS = new Set(['pro', 'professional', 'ultra', 'enterprise', 'admin', 'master_admin']);
51
51
  static CLOUD_PLANS = new Set(['pro', 'professional', 'ultra', 'enterprise', 'master_admin', 'admin']);
52
52
  constructor() {
53
53
  this.store = new conf_1.default({
@@ -14,6 +14,17 @@
14
14
  * @author Vigthoria Labs
15
15
  */
16
16
  import { Logger } from './logger.js';
17
+ export type StreamChunk = {
18
+ type: 'text' | 'delta' | 'error';
19
+ content: string;
20
+ };
21
+ export type UpdateInstallerResult = {
22
+ success: boolean;
23
+ platform: string;
24
+ error?: string;
25
+ };
26
+ export declare function installUpdateWindows(): Promise<UpdateInstallerResult>;
27
+ export declare function robustifyStreamResponse(res: any): AsyncIterable<StreamChunk>;
17
28
  export type RiskLevel = 'low' | 'medium' | 'high' | 'critical';
18
29
  export type SearchStatus = 'search_matches_found' | 'search_no_matches' | 'search_failed';
19
30
  export interface ToolResult {
@@ -52,12 +52,245 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
52
52
  };
53
53
  Object.defineProperty(exports, "__esModule", { value: true });
54
54
  exports.AgenticTools = exports.ToolErrorType = void 0;
55
+ exports.installUpdateWindows = installUpdateWindows;
56
+ exports.robustifyStreamResponse = robustifyStreamResponse;
55
57
  const fs = __importStar(require("fs"));
56
58
  const path = __importStar(require("path"));
57
59
  const child_process_1 = require("child_process");
58
60
  const chalk_1 = __importDefault(require("chalk"));
59
61
  const logger_js_1 = require("./logger.js");
60
62
  const api_js_1 = require("./api.js");
63
+ const STREAM_RESPONSE_MAX_YIELD_CHARS = 32 * 1024;
64
+ const POWERSHELL_SAFE_PATH_PATTERN = /^[A-Za-z0-9_:\\/.\-\s]+$/;
65
+ const POWERSHELL_SAFE_INCLUDE_PATTERN = /^[A-Za-z0-9_*?.\-]+$/;
66
+ const SSH_SAFE_HOST_PATTERN = /^[A-Za-z0-9.-]+$/;
67
+ function getSshAllowedHosts() {
68
+ const configured = String(process.env.VIGTHORIA_SSH_ALLOWED_HOSTS || '')
69
+ .split(',')
70
+ .map((v) => v.trim().toLowerCase())
71
+ .filter(Boolean);
72
+ const defaults = ['vigthoria-server', 'localhost', '127.0.0.1'];
73
+ return new Set([...defaults, ...configured]);
74
+ }
75
+ function isNodeError(error) {
76
+ return error instanceof Error && 'code' in error;
77
+ }
78
+ function resolveWindowsInstallerPath() {
79
+ const configuredPath = process.env.VIGTHORIA_WINDOWS_INSTALLER || process.env.VIGTHORIA_UPDATE_INSTALLER;
80
+ if (configuredPath && configuredPath.trim().length > 0) {
81
+ return path.resolve(configuredPath);
82
+ }
83
+ const executableDir = path.dirname(process.execPath);
84
+ const cwd = process.cwd();
85
+ const candidates = [
86
+ path.resolve(cwd, 'dist', 'VigthoriaSetup.exe'),
87
+ path.resolve(cwd, 'release', 'VigthoriaSetup.exe'),
88
+ path.resolve(cwd, 'VigthoriaSetup.exe'),
89
+ path.resolve(executableDir, 'VigthoriaSetup.exe'),
90
+ path.resolve(executableDir, '..', 'VigthoriaSetup.exe'),
91
+ ];
92
+ return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0];
93
+ }
94
+ async function installUpdateWindows() {
95
+ const installerPath = resolveWindowsInstallerPath();
96
+ try {
97
+ if (!fs.existsSync(installerPath)) {
98
+ return { success: false, platform: 'windows', error: 'ENOENT' };
99
+ }
100
+ await fs.promises.access(installerPath, fs.constants.F_OK);
101
+ await new Promise((resolve, reject) => {
102
+ const child = (0, child_process_1.spawn)(installerPath, [], {
103
+ cwd: path.dirname(installerPath),
104
+ detached: true,
105
+ stdio: 'ignore',
106
+ windowsHide: false,
107
+ });
108
+ child.once('error', reject);
109
+ child.once('spawn', () => {
110
+ child.unref();
111
+ resolve();
112
+ });
113
+ });
114
+ return { success: true, platform: 'windows' };
115
+ }
116
+ catch (error) {
117
+ if (isNodeError(error) && error.code === 'ENOENT') {
118
+ return { success: false, platform: 'windows', error: 'ENOENT' };
119
+ }
120
+ const message = error instanceof Error ? error.message : String(error);
121
+ return { success: false, platform: 'windows', error: message };
122
+ }
123
+ }
124
+ async function* robustifyStreamResponse(res) {
125
+ const MAX_YIELD_CHARS = STREAM_RESPONSE_MAX_YIELD_CHARS;
126
+ const MAX_BUFFER_CHARS = 256 * 1024;
127
+ const body = res?.body ?? res;
128
+ const decoder = new TextDecoder('utf-8');
129
+ let reader = null;
130
+ let lineBuffer = '';
131
+ const emitContent = async function* (type, content) {
132
+ for (let offset = 0; offset < content.length; offset += MAX_YIELD_CHARS) {
133
+ const part = content.slice(offset, offset + MAX_YIELD_CHARS);
134
+ if (part.length > 0) {
135
+ yield { type, content: part };
136
+ }
137
+ }
138
+ };
139
+ const textFromObject = (value) => {
140
+ if (!value || typeof value !== 'object')
141
+ return '';
142
+ if (typeof value.content === 'string')
143
+ return value.content;
144
+ if (typeof value.text === 'string')
145
+ return value.text;
146
+ if (typeof value.delta === 'string')
147
+ return value.delta;
148
+ if (typeof value.delta?.text === 'string')
149
+ return value.delta.text;
150
+ if (typeof value.message?.content === 'string')
151
+ return value.message.content;
152
+ if (typeof value.choices?.[0]?.delta?.content === 'string')
153
+ return value.choices[0].delta.content;
154
+ if (typeof value.choices?.[0]?.message?.content === 'string')
155
+ return value.choices[0].message.content;
156
+ if (typeof value.error === 'string')
157
+ return value.error;
158
+ if (typeof value.error?.message === 'string')
159
+ return value.error.message;
160
+ return '';
161
+ };
162
+ const stringifyChunk = (chunk) => {
163
+ if (typeof chunk === 'string')
164
+ return chunk;
165
+ if (Buffer.isBuffer(chunk))
166
+ return chunk.toString('utf8');
167
+ if (chunk instanceof Uint8Array)
168
+ return Buffer.from(chunk).toString('utf8');
169
+ if (chunk instanceof ArrayBuffer)
170
+ return Buffer.from(chunk).toString('utf8');
171
+ if (chunk === null || chunk === undefined)
172
+ return '';
173
+ const objectText = textFromObject(chunk);
174
+ return objectText || String(chunk);
175
+ };
176
+ const decodeLine = (line) => {
177
+ const trimmed = line.trim();
178
+ if (!trimmed || trimmed === 'event: ping' || trimmed === ':' || trimmed === 'data: [DONE]' || trimmed === '[DONE]') {
179
+ return null;
180
+ }
181
+ const payload = trimmed.startsWith('data:') ? trimmed.slice(5).trimStart() : trimmed;
182
+ if (!payload || payload === '[DONE]')
183
+ return null;
184
+ if ((payload.startsWith('{') && payload.endsWith('}')) || (payload.startsWith('[') && payload.endsWith(']'))) {
185
+ try {
186
+ const parsed = JSON.parse(payload);
187
+ const parsedText = textFromObject(parsed);
188
+ if (parsedText) {
189
+ const type = parsed.error ? 'error' : 'delta';
190
+ return { type, content: parsedText };
191
+ }
192
+ }
193
+ catch (error) {
194
+ console.debug(`Stream JSON fragment preserved as text: ${error instanceof Error ? error.message : String(error)}`);
195
+ }
196
+ }
197
+ if (payload.startsWith('event:') || payload.startsWith('id:') || payload.startsWith('retry:')) {
198
+ return null;
199
+ }
200
+ return { type: 'delta', content: payload };
201
+ };
202
+ const consumeText = async function* (text, flush = false) {
203
+ if (text) {
204
+ lineBuffer += text;
205
+ }
206
+ while (lineBuffer.length > MAX_BUFFER_CHARS) {
207
+ const newlineIndex = lineBuffer.indexOf('\n', Math.max(0, MAX_BUFFER_CHARS - MAX_YIELD_CHARS));
208
+ const cutIndex = newlineIndex >= 0 ? newlineIndex + 1 : MAX_BUFFER_CHARS;
209
+ const overflow = lineBuffer.slice(0, cutIndex);
210
+ lineBuffer = lineBuffer.slice(cutIndex);
211
+ const decoded = decodeLine(overflow);
212
+ if (decoded) {
213
+ yield* emitContent(decoded.type, decoded.content);
214
+ }
215
+ else {
216
+ yield* emitContent('delta', overflow);
217
+ }
218
+ }
219
+ const lines = lineBuffer.split(/\r?\n/);
220
+ const partialLine = lines.pop() ?? '';
221
+ for (const line of lines) {
222
+ const decoded = decodeLine(line);
223
+ if (decoded) {
224
+ yield* emitContent(decoded.type, decoded.content);
225
+ }
226
+ }
227
+ if (flush) {
228
+ lineBuffer = '';
229
+ if (partialLine) {
230
+ const decoded = decodeLine(partialLine);
231
+ if (decoded) {
232
+ yield* emitContent(decoded.type, decoded.content);
233
+ }
234
+ }
235
+ }
236
+ else {
237
+ lineBuffer = partialLine;
238
+ }
239
+ };
240
+ try {
241
+ if (!body) {
242
+ return;
243
+ }
244
+ if (typeof body.getReader === 'function') {
245
+ reader = body.getReader();
246
+ const streamReader = reader;
247
+ const decoder = new TextDecoder();
248
+ while (true) {
249
+ const { done, value } = await streamReader.read();
250
+ if (done)
251
+ break;
252
+ const content = decoder.decode(value, { stream: true });
253
+ if (content.length > 0) {
254
+ yield* consumeText(content);
255
+ }
256
+ }
257
+ const tail = decoder.decode();
258
+ if (tail.length > 0) {
259
+ yield* consumeText(tail);
260
+ }
261
+ yield* consumeText('', true);
262
+ return;
263
+ }
264
+ if (typeof body[Symbol.asyncIterator] === 'function') {
265
+ for await (const chunk of body) {
266
+ const content = stringifyChunk(chunk);
267
+ if (content.length > 0) {
268
+ yield* consumeText(content);
269
+ }
270
+ }
271
+ yield* consumeText('', true);
272
+ return;
273
+ }
274
+ const content = stringifyChunk(body);
275
+ if (content.length > 0) {
276
+ yield* emitContent('text', content);
277
+ }
278
+ }
279
+ catch (error) {
280
+ const content = error instanceof Error ? error.message : String(error);
281
+ yield { type: 'error', content };
282
+ }
283
+ finally {
284
+ lineBuffer = '';
285
+ try {
286
+ reader?.releaseLock();
287
+ }
288
+ catch (error) {
289
+ const message = error instanceof Error ? error.message : String(error);
290
+ console.debug(`Stream reader release failed: ${message}`);
291
+ }
292
+ }
293
+ }
61
294
  const TOOL_ARG_ALIASES = {
62
295
  read_file: {
63
296
  path: ['file', 'filePath', 'filepath', 'target', 'targetPath'],
@@ -1576,9 +1809,14 @@ class AgenticTools {
1576
1809
  grepWithSelectString(args, searchPath) {
1577
1810
  // Normalize path for PowerShell
1578
1811
  const psPath = searchPath.replace(/\//g, '\\');
1579
- const includeFilter = args.include
1580
- ? `-Include "${args.include}"`
1581
- : `-Include *`;
1812
+ if (!POWERSHELL_SAFE_PATH_PATTERN.test(psPath)) {
1813
+ return this.createErrorResult(ToolErrorType.INVALID_ARGS, 'Unsafe search path for PowerShell backend', 'Use a normal workspace path containing only letters, numbers, separators, dot, dash, and spaces.');
1814
+ }
1815
+ const includeArg = args.include ? String(args.include) : '*';
1816
+ if (!POWERSHELL_SAFE_INCLUDE_PATTERN.test(includeArg)) {
1817
+ return this.createErrorResult(ToolErrorType.INVALID_ARGS, 'Unsafe include filter for PowerShell backend', 'Use simple wildcard filters like *.ts or *.py.');
1818
+ }
1819
+ const includeFilter = `-Include "${includeArg}"`;
1582
1820
  const escapedPattern = args.pattern.replace(/'/g, "''");
1583
1821
  const cmd = `powershell -NoProfile -Command "Get-ChildItem -Path '${psPath}' -Recurse -File ${includeFilter} | Select-String -Pattern '${escapedPattern}' | ForEach-Object { $_.Path + ':' + $_.LineNumber + ':' + $_.Line }"`;
1584
1822
  try {
@@ -2231,6 +2469,14 @@ class AgenticTools {
2231
2469
  const command = args.command;
2232
2470
  const host = args.host || 'vigthoria-server';
2233
2471
  const timeout = args.timeout ? parseInt(args.timeout) * 1000 : 60000;
2472
+ const normalizedHost = String(host).trim().toLowerCase();
2473
+ if (!SSH_SAFE_HOST_PATTERN.test(normalizedHost)) {
2474
+ return this.createErrorResult(ToolErrorType.INVALID_ARGS, 'Invalid SSH host format', 'Host can only include letters, numbers, dots, and dashes.');
2475
+ }
2476
+ const allowedHosts = getSshAllowedHosts();
2477
+ if (!allowedHosts.has(normalizedHost)) {
2478
+ return this.createErrorResult(ToolErrorType.PERMISSION_DENIED, `SSH host is not allowlisted: ${host}`, 'Add the host to VIGTHORIA_SSH_ALLOWED_HOSTS to permit access.');
2479
+ }
2234
2480
  // Security checks for SSH commands
2235
2481
  const blockedPatterns = [
2236
2482
  /\brm\s+-rf?\s+\//i, // Dangerous rm commands
@@ -2256,12 +2502,12 @@ class AgenticTools {
2256
2502
  };
2257
2503
  if (platform === 'win32') {
2258
2504
  // On Windows, use the ssh command from OpenSSH
2259
- sshCommand = `ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=10 ${host} "${command.replace(/"/g, '\\"')}"`;
2505
+ sshCommand = `ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 ${host} "${command.replace(/"/g, '\\"')}"`;
2260
2506
  execOptions.shell = true;
2261
2507
  }
2262
2508
  else {
2263
2509
  // On Unix-like systems
2264
- sshCommand = `ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=10 ${host} '${command.replace(/'/g, "'\\''")}'`;
2510
+ sshCommand = `ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 ${host} '${command.replace(/'/g, "'\\''")}'`;
2265
2511
  execOptions.shell = '/bin/sh';
2266
2512
  }
2267
2513
  const output = (0, child_process_1.execSync)(sshCommand, execOptions);
package/install.ps1 ADDED
@@ -0,0 +1,322 @@
1
+ # Vigthoria CLI Installer for Windows
2
+ # Usage: irm https://cli.vigthoria.io/install.ps1 | iex
3
+ # Alternative: PowerShell -ExecutionPolicy Bypass -File install.ps1
4
+
5
+ $ErrorActionPreference = "Stop"
6
+
7
+ # Configuration
8
+ $CLI_VERSION = "1.9.1"
9
+ $INSTALL_DIR = "$env:USERPROFILE\.vigthoria"
10
+ $NPM_PACKAGE = "vigthoria-cli"
11
+ $GIT_PACKAGE_URL = "git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
12
+ $HOSTED_TARBALL_URL = "https://coder.vigthoria.io/releases/vigthoria-cli-$CLI_VERSION.tgz"
13
+
14
+ function Write-Banner {
15
+ Write-Host ""
16
+ Write-Host " ╔═══════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
17
+ Write-Host " ║ ║" -ForegroundColor Cyan
18
+ Write-Host " ║ VIGTHORIA CLI INSTALLER v$CLI_VERSION ║" -ForegroundColor Cyan
19
+ Write-Host " ║ AI-Powered Terminal Coding Assistant ║" -ForegroundColor Cyan
20
+ Write-Host " ║ ║" -ForegroundColor Cyan
21
+ Write-Host " ╚═══════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
22
+ Write-Host ""
23
+ }
24
+
25
+ function Test-NetworkConnectivity {
26
+ Write-Host "🔍 Checking network connectivity..." -ForegroundColor Yellow
27
+
28
+ try {
29
+ $response = Invoke-WebRequest -Uri $HOSTED_TARBALL_URL -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
30
+ Write-Host "✓ hosted CLI package is reachable" -ForegroundColor Green
31
+ return $true
32
+ }
33
+ catch {
34
+ Write-Host "⚠ Hosted package unavailable, checking npm registry..." -ForegroundColor Yellow
35
+ }
36
+
37
+ try {
38
+ $response = Invoke-WebRequest -Uri "https://registry.npmjs.org/vigthoria-cli" -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
39
+ Write-Host "✓ npm registry is reachable" -ForegroundColor Green
40
+ return $true
41
+ }
42
+ catch {
43
+ Write-Host "✗ Cannot reach hosted package or npm registry" -ForegroundColor Red
44
+ return $false
45
+ }
46
+ }
47
+
48
+ function Test-Prerequisites {
49
+ Write-Host "🔍 Checking prerequisites..." -ForegroundColor Yellow
50
+
51
+ # Check Node.js
52
+ try {
53
+ $nodeVersion = node -v 2>$null
54
+ if ($nodeVersion) {
55
+ $major = [int]($nodeVersion -replace 'v(\d+)\..*', '$1')
56
+ if ($major -ge 18) {
57
+ Write-Host "✓ Node.js $nodeVersion" -ForegroundColor Green
58
+ } else {
59
+ Write-Host "✗ Node.js 18+ required (found $nodeVersion)" -ForegroundColor Red
60
+ Write-Host " Download from: https://nodejs.org/" -ForegroundColor Yellow
61
+ return $false
62
+ }
63
+ }
64
+ }
65
+ catch {
66
+ Write-Host "✗ Node.js is not installed" -ForegroundColor Red
67
+ Write-Host ""
68
+ Write-Host "Please install Node.js first:" -ForegroundColor Yellow
69
+ Write-Host " Option 1: winget install OpenJS.NodeJS" -ForegroundColor White
70
+ Write-Host " Option 2: Download from https://nodejs.org/" -ForegroundColor White
71
+ Write-Host ""
72
+ return $false
73
+ }
74
+
75
+ # Check npm
76
+ try {
77
+ $npmVersion = npm -v 2>$null
78
+ if ($npmVersion) {
79
+ Write-Host "✓ npm v$npmVersion" -ForegroundColor Green
80
+ }
81
+ }
82
+ catch {
83
+ Write-Host "✗ npm is not installed" -ForegroundColor Red
84
+ return $false
85
+ }
86
+
87
+ return $true
88
+ }
89
+
90
+ function Install-VigthoriaCLI-NPM {
91
+ Write-Host ""
92
+ Write-Host "📦 Installing Vigthoria CLI..." -ForegroundColor Cyan
93
+
94
+ try {
95
+ npm install -g $HOSTED_TARBALL_URL
96
+ Write-Host "✓ Vigthoria CLI installed successfully!" -ForegroundColor Green
97
+ return $true
98
+ }
99
+ catch {
100
+ Write-Host "⚠ Hosted package install failed, trying npm registry..." -ForegroundColor Yellow
101
+ }
102
+
103
+ try {
104
+ npm install -g vigthoria-cli
105
+ Write-Host "✓ Vigthoria CLI installed successfully!" -ForegroundColor Green
106
+ return $true
107
+ }
108
+ catch {
109
+ Write-Host "⚠ npm registry install failed, trying git package..." -ForegroundColor Yellow
110
+ }
111
+
112
+ try {
113
+ npm install -g $GIT_PACKAGE_URL
114
+ Write-Host "✓ Vigthoria CLI installed successfully from git package!" -ForegroundColor Green
115
+ return $true
116
+ }
117
+ catch {
118
+ Write-Host "✗ install failed (hosted package + npm registry + git package): $_" -ForegroundColor Red
119
+ return $false
120
+ }
121
+ }
122
+
123
+ function Install-VigthoriaCLI-Direct {
124
+ Write-Host ""
125
+ Write-Host "📦 Installing Vigthoria CLI (Direct Download)..." -ForegroundColor Cyan
126
+
127
+ # Create install directory
128
+ if (-not (Test-Path $INSTALL_DIR)) {
129
+ New-Item -ItemType Directory -Path $INSTALL_DIR -Force | Out-Null
130
+ }
131
+
132
+ $tarballUrl = $HOSTED_TARBALL_URL
133
+ $tarballPath = "$INSTALL_DIR\vigthoria-cli.tgz"
134
+ $extractPath = "$INSTALL_DIR\cli"
135
+
136
+ try {
137
+ # Download tarball
138
+ Write-Host " Downloading from $tarballUrl..." -ForegroundColor Gray
139
+ Invoke-WebRequest -Uri $tarballUrl -OutFile $tarballPath -UseBasicParsing
140
+
141
+ # Extract
142
+ Write-Host " Extracting..." -ForegroundColor Gray
143
+ if (Test-Path $extractPath) {
144
+ Remove-Item -Recurse -Force $extractPath
145
+ }
146
+ New-Item -ItemType Directory -Path $extractPath -Force | Out-Null
147
+
148
+ # Use tar to extract (available in Windows 10+)
149
+ tar -xzf $tarballPath -C $extractPath
150
+
151
+ # The tarball extracts to a 'package' folder
152
+ $packagePath = "$extractPath\package"
153
+
154
+ # Install dependencies
155
+ Write-Host " Installing dependencies..." -ForegroundColor Gray
156
+ Push-Location $packagePath
157
+ npm install --production
158
+ Pop-Location
159
+
160
+ # Create batch file wrapper
161
+ $batContent = @"
162
+ @echo off
163
+ node "$packagePath\dist\index.js" %*
164
+ "@
165
+ Set-Content -Path "$INSTALL_DIR\vigthoria.bat" -Value $batContent
166
+ Set-Content -Path "$INSTALL_DIR\vig.bat" -Value $batContent
167
+
168
+ # Add to PATH if not already there
169
+ $userPath = [Environment]::GetEnvironmentVariable("PATH", "User")
170
+ if ($userPath -notlike "*$INSTALL_DIR*") {
171
+ [Environment]::SetEnvironmentVariable("PATH", "$userPath;$INSTALL_DIR", "User")
172
+ Write-Host " Added $INSTALL_DIR to PATH" -ForegroundColor Gray
173
+ }
174
+
175
+ # Cleanup
176
+ Remove-Item $tarballPath -Force
177
+
178
+ Write-Host "✓ Vigthoria CLI installed successfully!" -ForegroundColor Green
179
+ return $true
180
+ }
181
+ catch {
182
+ Write-Host "✗ Direct install failed: $_" -ForegroundColor Red
183
+ return $false
184
+ }
185
+ }
186
+
187
+ function Install-VigthoriaCLI-GitHub {
188
+ Write-Host ""
189
+ Write-Host "📦 Installing Vigthoria CLI (from Vigthoria Market)..." -ForegroundColor Cyan
190
+
191
+ # Create install directory
192
+ if (-not (Test-Path $INSTALL_DIR)) {
193
+ New-Item -ItemType Directory -Path $INSTALL_DIR -Force | Out-Null
194
+ }
195
+
196
+ $clonePath = "$INSTALL_DIR\cli"
197
+
198
+ try {
199
+ # Check if git is available
200
+ $gitVersion = git --version 2>$null
201
+ if (-not $gitVersion) {
202
+ Write-Host "✗ Git is not installed" -ForegroundColor Red
203
+ return $false
204
+ }
205
+
206
+ # Clone repository
207
+ if (Test-Path $clonePath) {
208
+ Remove-Item -Recurse -Force $clonePath
209
+ }
210
+
211
+ Write-Host " Cloning from Vigthoria Market..." -ForegroundColor Gray
212
+ git clone --depth 1 https://market.vigthoria.io/vigthoria/vigthoria-cli.git $clonePath
213
+
214
+ # Install and build
215
+ Push-Location $clonePath
216
+ Write-Host " Installing dependencies..." -ForegroundColor Gray
217
+ npm install
218
+ Write-Host " Building..." -ForegroundColor Gray
219
+ npm run build
220
+ Write-Host " Linking globally..." -ForegroundColor Gray
221
+ npm link
222
+ Pop-Location
223
+
224
+ Write-Host "✓ Vigthoria CLI installed successfully!" -ForegroundColor Green
225
+ return $true
226
+ }
227
+ catch {
228
+ Write-Host "✗ GitHub install failed: $_" -ForegroundColor Red
229
+ return $false
230
+ }
231
+ }
232
+
233
+ function Show-NetworkTroubleshooting {
234
+ Write-Host ""
235
+ Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Yellow
236
+ Write-Host " NETWORK TROUBLESHOOTING" -ForegroundColor Yellow
237
+ Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Yellow
238
+ Write-Host ""
239
+ Write-Host "The hosted package and npm registry could not be reached. Try these solutions:" -ForegroundColor White
240
+ Write-Host ""
241
+ Write-Host "1. Check your internet connection" -ForegroundColor Cyan
242
+ Write-Host " ping registry.npmjs.org" -ForegroundColor Gray
243
+ Write-Host ""
244
+ Write-Host "2. If behind a corporate proxy, configure npm:" -ForegroundColor Cyan
245
+ Write-Host " npm config set proxy http://proxy.company.com:8080" -ForegroundColor Gray
246
+ Write-Host " npm config set https-proxy http://proxy.company.com:8080" -ForegroundColor Gray
247
+ Write-Host ""
248
+ Write-Host "3. Try a different npm registry:" -ForegroundColor Cyan
249
+ Write-Host " npm config set registry https://registry.npmmirror.com" -ForegroundColor Gray
250
+ Write-Host ""
251
+ Write-Host "4. Check Windows Firewall/Antivirus settings" -ForegroundColor Cyan
252
+ Write-Host ""
253
+ Write-Host "5. Try using a VPN" -ForegroundColor Cyan
254
+ Write-Host ""
255
+ Write-Host "6. Manual download alternatives:" -ForegroundColor Cyan
256
+ Write-Host " Hosted package: $HOSTED_TARBALL_URL" -ForegroundColor Gray
257
+ Write-Host " npm package: https://www.npmjs.com/package/vigthoria-cli" -ForegroundColor Gray
258
+ Write-Host " git package: $GIT_PACKAGE_URL" -ForegroundColor Gray
259
+ Write-Host ""
260
+ }
261
+
262
+ function Show-Success {
263
+ Write-Host ""
264
+ Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Green
265
+ Write-Host " INSTALLATION COMPLETE!" -ForegroundColor Green
266
+ Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Green
267
+ Write-Host ""
268
+ Write-Host " Get started:" -ForegroundColor White
269
+ Write-Host " 1. Open a new terminal" -ForegroundColor Gray
270
+ Write-Host " 2. Login: vigthoria login" -ForegroundColor Gray
271
+ Write-Host " 3. Start: vigthoria chat" -ForegroundColor Gray
272
+ Write-Host " Or local project start: npx vigthoria-chat" -ForegroundColor Gray
273
+ Write-Host ""
274
+ Write-Host " Commands:" -ForegroundColor White
275
+ Write-Host " vigthoria chat - Start AI chat" -ForegroundColor Gray
276
+ Write-Host " vigthoria-chat - Start chat directly" -ForegroundColor Gray
277
+ Write-Host " vigthoria edit - Edit files with AI" -ForegroundColor Gray
278
+ Write-Host " vigthoria repo - Manage cloud repos" -ForegroundColor Gray
279
+ Write-Host " vig --help - Show all commands" -ForegroundColor Gray
280
+ Write-Host ""
281
+ Write-Host " Documentation: https://docs.vigthoria.io/cli" -ForegroundColor Cyan
282
+ Write-Host ""
283
+ }
284
+
285
+ # Main installation flow
286
+ Write-Banner
287
+
288
+ if (-not (Test-Prerequisites)) {
289
+ exit 1
290
+ }
291
+
292
+ $networkOk = Test-NetworkConnectivity
293
+
294
+ if ($networkOk) {
295
+ # Try npm install first
296
+ if (Install-VigthoriaCLI-NPM) {
297
+ Show-Success
298
+ exit 0
299
+ }
300
+ }
301
+
302
+ # Network failed or npm install failed
303
+ Show-NetworkTroubleshooting
304
+
305
+ Write-Host "Would you like to try alternative installation methods?" -ForegroundColor Yellow
306
+ $choice = Read-Host "Enter 'y' to try direct download, 'g' for git clone, or 'n' to exit"
307
+
308
+ switch ($choice.ToLower()) {
309
+ 'y' {
310
+ if (Install-VigthoriaCLI-Direct) {
311
+ Show-Success
312
+ }
313
+ }
314
+ 'g' {
315
+ if (Install-VigthoriaCLI-GitHub) {
316
+ Show-Success
317
+ }
318
+ }
319
+ default {
320
+ Write-Host "Installation cancelled." -ForegroundColor Gray
321
+ }
322
+ }