vigthoria-cli 1.0.0

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 (75) hide show
  1. package/README.md +413 -0
  2. package/dist/commands/auth.d.ts +24 -0
  3. package/dist/commands/auth.d.ts.map +1 -0
  4. package/dist/commands/auth.js +194 -0
  5. package/dist/commands/auth.js.map +1 -0
  6. package/dist/commands/chat.d.ts +64 -0
  7. package/dist/commands/chat.d.ts.map +1 -0
  8. package/dist/commands/chat.js +596 -0
  9. package/dist/commands/chat.js.map +1 -0
  10. package/dist/commands/config.d.ts +25 -0
  11. package/dist/commands/config.d.ts.map +1 -0
  12. package/dist/commands/config.js +291 -0
  13. package/dist/commands/config.js.map +1 -0
  14. package/dist/commands/edit.d.ts +28 -0
  15. package/dist/commands/edit.d.ts.map +1 -0
  16. package/dist/commands/edit.js +257 -0
  17. package/dist/commands/edit.js.map +1 -0
  18. package/dist/commands/explain.d.ts +21 -0
  19. package/dist/commands/explain.d.ts.map +1 -0
  20. package/dist/commands/explain.js +98 -0
  21. package/dist/commands/explain.js.map +1 -0
  22. package/dist/commands/generate.d.ts +25 -0
  23. package/dist/commands/generate.d.ts.map +1 -0
  24. package/dist/commands/generate.js +155 -0
  25. package/dist/commands/generate.js.map +1 -0
  26. package/dist/commands/review.d.ts +24 -0
  27. package/dist/commands/review.d.ts.map +1 -0
  28. package/dist/commands/review.js +153 -0
  29. package/dist/commands/review.js.map +1 -0
  30. package/dist/index.d.ts +16 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +205 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/utils/api.d.ts +88 -0
  35. package/dist/utils/api.d.ts.map +1 -0
  36. package/dist/utils/api.js +431 -0
  37. package/dist/utils/api.js.map +1 -0
  38. package/dist/utils/config.d.ts +57 -0
  39. package/dist/utils/config.d.ts.map +1 -0
  40. package/dist/utils/config.js +167 -0
  41. package/dist/utils/config.js.map +1 -0
  42. package/dist/utils/files.d.ts +31 -0
  43. package/dist/utils/files.d.ts.map +1 -0
  44. package/dist/utils/files.js +217 -0
  45. package/dist/utils/files.js.map +1 -0
  46. package/dist/utils/logger.d.ts +23 -0
  47. package/dist/utils/logger.d.ts.map +1 -0
  48. package/dist/utils/logger.js +104 -0
  49. package/dist/utils/logger.js.map +1 -0
  50. package/dist/utils/session.d.ts +61 -0
  51. package/dist/utils/session.d.ts.map +1 -0
  52. package/dist/utils/session.js +172 -0
  53. package/dist/utils/session.js.map +1 -0
  54. package/dist/utils/tools.d.ts +145 -0
  55. package/dist/utils/tools.d.ts.map +1 -0
  56. package/dist/utils/tools.js +781 -0
  57. package/dist/utils/tools.js.map +1 -0
  58. package/install.sh +248 -0
  59. package/package.json +52 -0
  60. package/src/commands/auth.ts +225 -0
  61. package/src/commands/chat.ts +690 -0
  62. package/src/commands/config.ts +297 -0
  63. package/src/commands/edit.ts +310 -0
  64. package/src/commands/explain.ts +115 -0
  65. package/src/commands/generate.ts +177 -0
  66. package/src/commands/review.ts +186 -0
  67. package/src/index.ts +221 -0
  68. package/src/types/marked-terminal.d.ts +31 -0
  69. package/src/utils/api.ts +531 -0
  70. package/src/utils/config.ts +224 -0
  71. package/src/utils/files.ts +212 -0
  72. package/src/utils/logger.ts +125 -0
  73. package/src/utils/session.ts +167 -0
  74. package/src/utils/tools.ts +933 -0
  75. package/tsconfig.json +20 -0
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Configuration Manager for Vigthoria CLI
3
+ */
4
+
5
+ import Conf from 'conf';
6
+ import * as path from 'path';
7
+ import * as os from 'os';
8
+
9
+ export interface VigthoriaCLIConfig {
10
+ apiUrl: string;
11
+ wsUrl: string;
12
+ authToken: string | null;
13
+ refreshToken: string | null;
14
+ userId: string | null;
15
+ email: string | null;
16
+ subscription: {
17
+ plan: string | null;
18
+ status: string | null;
19
+ expiresAt: string | null;
20
+ };
21
+ preferences: {
22
+ defaultModel: string;
23
+ theme: 'dark' | 'light';
24
+ autoApplyFixes: boolean;
25
+ showDiffs: boolean;
26
+ contextLines: number;
27
+ maxTokens: number;
28
+ };
29
+ project: {
30
+ rootPath: string | null;
31
+ ignorePatterns: string[];
32
+ };
33
+ }
34
+
35
+ const defaultConfig: VigthoriaCLIConfig = {
36
+ apiUrl: 'https://coder.vigthoria.io',
37
+ wsUrl: 'wss://coder.vigthoria.io/ws',
38
+ authToken: null,
39
+ refreshToken: null,
40
+ userId: null,
41
+ email: null,
42
+ subscription: {
43
+ plan: null,
44
+ status: null,
45
+ expiresAt: null,
46
+ },
47
+ preferences: {
48
+ defaultModel: 'vigthoria-code',
49
+ theme: 'dark',
50
+ autoApplyFixes: false,
51
+ showDiffs: true,
52
+ contextLines: 3,
53
+ maxTokens: 4096,
54
+ },
55
+ project: {
56
+ rootPath: null,
57
+ ignorePatterns: [
58
+ 'node_modules',
59
+ '.git',
60
+ 'dist',
61
+ 'build',
62
+ '__pycache__',
63
+ '.venv',
64
+ 'venv',
65
+ '.env',
66
+ '*.log',
67
+ ],
68
+ },
69
+ };
70
+
71
+ export class Config {
72
+ private store: Conf<VigthoriaCLIConfig>;
73
+
74
+ constructor() {
75
+ this.store = new Conf<VigthoriaCLIConfig>({
76
+ projectName: 'vigthoria-cli',
77
+ defaults: defaultConfig,
78
+ schema: {
79
+ apiUrl: { type: 'string' },
80
+ wsUrl: { type: 'string' },
81
+ authToken: { type: ['string', 'null'] },
82
+ refreshToken: { type: ['string', 'null'] },
83
+ userId: { type: ['string', 'null'] },
84
+ email: { type: ['string', 'null'] },
85
+ subscription: {
86
+ type: 'object',
87
+ properties: {
88
+ plan: { type: ['string', 'null'] },
89
+ status: { type: ['string', 'null'] },
90
+ expiresAt: { type: ['string', 'null'] },
91
+ },
92
+ },
93
+ preferences: {
94
+ type: 'object',
95
+ properties: {
96
+ defaultModel: { type: 'string' },
97
+ theme: { type: 'string', enum: ['dark', 'light'] },
98
+ autoApplyFixes: { type: 'boolean' },
99
+ showDiffs: { type: 'boolean' },
100
+ contextLines: { type: 'number' },
101
+ maxTokens: { type: 'number' },
102
+ },
103
+ },
104
+ project: {
105
+ type: 'object',
106
+ properties: {
107
+ rootPath: { type: ['string', 'null'] },
108
+ ignorePatterns: { type: 'array', items: { type: 'string' } },
109
+ },
110
+ },
111
+ },
112
+ });
113
+ }
114
+
115
+ get<K extends keyof VigthoriaCLIConfig>(key: K): VigthoriaCLIConfig[K] {
116
+ return this.store.get(key);
117
+ }
118
+
119
+ set<K extends keyof VigthoriaCLIConfig>(key: K, value: VigthoriaCLIConfig[K]): void {
120
+ this.store.set(key, value);
121
+ }
122
+
123
+ getAll(): VigthoriaCLIConfig {
124
+ return this.store.store;
125
+ }
126
+
127
+ reset(): void {
128
+ this.store.clear();
129
+ }
130
+
131
+ isAuthenticated(): boolean {
132
+ return this.store.get('authToken') !== null;
133
+ }
134
+
135
+ hasValidSubscription(): boolean {
136
+ const sub = this.store.get('subscription');
137
+ if (!sub.status || sub.status !== 'active') return false;
138
+ if (sub.expiresAt) {
139
+ const expires = new Date(sub.expiresAt);
140
+ return expires > new Date();
141
+ }
142
+ return true;
143
+ }
144
+
145
+ getConfigPath(): string {
146
+ return this.store.path;
147
+ }
148
+
149
+ // Auth helpers
150
+ setAuth(data: {
151
+ token: string;
152
+ refreshToken?: string;
153
+ userId: string;
154
+ email: string;
155
+ }): void {
156
+ this.store.set('authToken', data.token);
157
+ if (data.refreshToken) {
158
+ this.store.set('refreshToken', data.refreshToken);
159
+ }
160
+ this.store.set('userId', data.userId);
161
+ this.store.set('email', data.email);
162
+ }
163
+
164
+ clearAuth(): void {
165
+ this.store.set('authToken', null);
166
+ this.store.set('refreshToken', null);
167
+ this.store.set('userId', null);
168
+ this.store.set('email', null);
169
+ this.store.set('subscription', {
170
+ plan: null,
171
+ status: null,
172
+ expiresAt: null,
173
+ });
174
+ }
175
+
176
+ setSubscription(data: {
177
+ plan: string;
178
+ status: string;
179
+ expiresAt?: string;
180
+ }): void {
181
+ this.store.set('subscription', {
182
+ plan: data.plan,
183
+ status: data.status,
184
+ expiresAt: data.expiresAt || null,
185
+ });
186
+ }
187
+
188
+ // Model selection - Native Vigthoria Models
189
+ getAvailableModels(): { id: string; name: string; description: string }[] {
190
+ const sub = this.store.get('subscription');
191
+
192
+ // All users get access to fast models
193
+ const models = [
194
+ { id: 'mini', name: 'Vigthoria Mini 0.6B', description: 'Ultra-fast, simple tasks' },
195
+ { id: 'fast', name: 'Vigthoria Fast 1.7B', description: 'Quick responses, streaming' },
196
+ ];
197
+
198
+ // Developer+ plans get balanced model
199
+ if (sub.plan && sub.plan !== 'free') {
200
+ models.push(
201
+ { id: 'balanced', name: 'Vigthoria Balanced 4B', description: 'General purpose' },
202
+ { id: 'music', name: 'Vigthoria Music 4B', description: 'Music production & theory' },
203
+ );
204
+ }
205
+
206
+ // Pro plans get code and creative models
207
+ if (sub.plan === 'developer' || sub.plan === 'pro' || sub.plan === 'ultra' || sub.plan === 'enterprise') {
208
+ models.push(
209
+ { id: 'code', name: 'Vigthoria Code v2 8B', description: 'Code specialist (training)' },
210
+ { id: 'creative', name: 'Vigthoria Creative 9B v4', description: 'Creative writing, lyrics' },
211
+ );
212
+ }
213
+
214
+ // External model aliases
215
+ if (sub.plan === 'pro' || sub.plan === 'ultra' || sub.plan === 'enterprise') {
216
+ models.push(
217
+ { id: 'qwen-coder', name: 'Qwen 2.5 Coder 7B', description: 'External code model' },
218
+ { id: 'deepseek', name: 'DeepSeek Coder v2', description: 'External code model' },
219
+ );
220
+ }
221
+
222
+ return models;
223
+ }
224
+ }
@@ -0,0 +1,212 @@
1
+ /**
2
+ * File utilities for Vigthoria CLI
3
+ */
4
+
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { glob } from 'glob';
8
+
9
+ export interface FileInfo {
10
+ path: string;
11
+ relativePath: string;
12
+ content: string;
13
+ language: string;
14
+ lines: number;
15
+ }
16
+
17
+ export class FileUtils {
18
+ private projectRoot: string;
19
+ private ignorePatterns: string[];
20
+
21
+ constructor(projectRoot: string, ignorePatterns: string[] = []) {
22
+ this.projectRoot = projectRoot;
23
+ this.ignorePatterns = ignorePatterns;
24
+ }
25
+
26
+ // Read file with metadata
27
+ readFile(filePath: string): FileInfo | null {
28
+ try {
29
+ const absolutePath = path.isAbsolute(filePath)
30
+ ? filePath
31
+ : path.join(this.projectRoot, filePath);
32
+
33
+ const content = fs.readFileSync(absolutePath, 'utf-8');
34
+ const relativePath = path.relative(this.projectRoot, absolutePath);
35
+
36
+ return {
37
+ path: absolutePath,
38
+ relativePath,
39
+ content,
40
+ language: this.detectLanguage(absolutePath),
41
+ lines: content.split('\n').length,
42
+ };
43
+ } catch (error) {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ // Read specific lines
49
+ readLines(filePath: string, start: number, end: number): string | null {
50
+ const file = this.readFile(filePath);
51
+ if (!file) return null;
52
+
53
+ const lines = file.content.split('\n');
54
+ return lines.slice(start - 1, end).join('\n');
55
+ }
56
+
57
+ // Write file
58
+ writeFile(filePath: string, content: string): boolean {
59
+ try {
60
+ const absolutePath = path.isAbsolute(filePath)
61
+ ? filePath
62
+ : path.join(this.projectRoot, filePath);
63
+
64
+ // Create directory if needed
65
+ const dir = path.dirname(absolutePath);
66
+ if (!fs.existsSync(dir)) {
67
+ fs.mkdirSync(dir, { recursive: true });
68
+ }
69
+
70
+ fs.writeFileSync(absolutePath, content, 'utf-8');
71
+ return true;
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
76
+
77
+ // Backup file
78
+ backupFile(filePath: string): string | null {
79
+ const file = this.readFile(filePath);
80
+ if (!file) return null;
81
+
82
+ const backupPath = `${file.path}.bak.${Date.now()}`;
83
+ if (this.writeFile(backupPath, file.content)) {
84
+ return backupPath;
85
+ }
86
+ return null;
87
+ }
88
+
89
+ // List project files
90
+ async listFiles(pattern: string = '**/*'): Promise<string[]> {
91
+ const files = await glob(pattern, {
92
+ cwd: this.projectRoot,
93
+ ignore: this.ignorePatterns,
94
+ nodir: true,
95
+ });
96
+
97
+ return files;
98
+ }
99
+
100
+ // Detect language from file extension
101
+ detectLanguage(filePath: string): string {
102
+ const ext = path.extname(filePath).toLowerCase();
103
+ const languageMap: Record<string, string> = {
104
+ '.ts': 'typescript',
105
+ '.tsx': 'typescript',
106
+ '.js': 'javascript',
107
+ '.jsx': 'javascript',
108
+ '.py': 'python',
109
+ '.rs': 'rust',
110
+ '.go': 'go',
111
+ '.java': 'java',
112
+ '.c': 'c',
113
+ '.cpp': 'cpp',
114
+ '.h': 'c',
115
+ '.hpp': 'cpp',
116
+ '.cs': 'csharp',
117
+ '.rb': 'ruby',
118
+ '.php': 'php',
119
+ '.swift': 'swift',
120
+ '.kt': 'kotlin',
121
+ '.scala': 'scala',
122
+ '.sql': 'sql',
123
+ '.html': 'html',
124
+ '.css': 'css',
125
+ '.scss': 'scss',
126
+ '.less': 'less',
127
+ '.json': 'json',
128
+ '.yaml': 'yaml',
129
+ '.yml': 'yaml',
130
+ '.xml': 'xml',
131
+ '.md': 'markdown',
132
+ '.sh': 'bash',
133
+ '.bash': 'bash',
134
+ '.zsh': 'zsh',
135
+ '.dockerfile': 'dockerfile',
136
+ '.vue': 'vue',
137
+ '.svelte': 'svelte',
138
+ };
139
+
140
+ return languageMap[ext] || 'text';
141
+ }
142
+
143
+ // Get project context
144
+ async getProjectContext(maxFiles: number = 20): Promise<{
145
+ type: string;
146
+ files: string[];
147
+ dependencies: Record<string, string>;
148
+ }> {
149
+ const context = {
150
+ type: 'unknown',
151
+ files: [] as string[],
152
+ dependencies: {} as Record<string, string>,
153
+ };
154
+
155
+ // Detect project type
156
+ if (fs.existsSync(path.join(this.projectRoot, 'package.json'))) {
157
+ context.type = 'node';
158
+ const pkg = JSON.parse(fs.readFileSync(
159
+ path.join(this.projectRoot, 'package.json'),
160
+ 'utf-8'
161
+ ));
162
+ context.dependencies = {
163
+ ...pkg.dependencies,
164
+ ...pkg.devDependencies,
165
+ };
166
+ } else if (fs.existsSync(path.join(this.projectRoot, 'requirements.txt'))) {
167
+ context.type = 'python';
168
+ } else if (fs.existsSync(path.join(this.projectRoot, 'Cargo.toml'))) {
169
+ context.type = 'rust';
170
+ } else if (fs.existsSync(path.join(this.projectRoot, 'go.mod'))) {
171
+ context.type = 'go';
172
+ } else if (fs.existsSync(path.join(this.projectRoot, 'pom.xml'))) {
173
+ context.type = 'java-maven';
174
+ } else if (fs.existsSync(path.join(this.projectRoot, 'build.gradle'))) {
175
+ context.type = 'java-gradle';
176
+ }
177
+
178
+ // Get relevant files
179
+ const allFiles = await this.listFiles();
180
+ context.files = allFiles.slice(0, maxFiles);
181
+
182
+ return context;
183
+ }
184
+
185
+ // Create diff
186
+ createDiff(original: string, modified: string): { added: string[]; removed: string[] } {
187
+ const originalLines = original.split('\n');
188
+ const modifiedLines = modified.split('\n');
189
+
190
+ const added: string[] = [];
191
+ const removed: string[] = [];
192
+
193
+ // Simple diff - for display purposes
194
+ const maxLen = Math.max(originalLines.length, modifiedLines.length);
195
+
196
+ for (let i = 0; i < maxLen; i++) {
197
+ const origLine = originalLines[i];
198
+ const modLine = modifiedLines[i];
199
+
200
+ if (origLine !== modLine) {
201
+ if (origLine !== undefined) {
202
+ removed.push(`${i + 1}: ${origLine}`);
203
+ }
204
+ if (modLine !== undefined) {
205
+ added.push(`${i + 1}: ${modLine}`);
206
+ }
207
+ }
208
+ }
209
+
210
+ return { added, removed };
211
+ }
212
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Logger utility for Vigthoria CLI
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+
7
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'success';
8
+
9
+ export class Logger {
10
+ private verbose: boolean = false;
11
+
12
+ setVerbose(verbose: boolean): void {
13
+ this.verbose = verbose;
14
+ }
15
+
16
+ debug(...args: unknown[]): void {
17
+ if (this.verbose) {
18
+ console.log(chalk.gray('[DEBUG]'), ...args);
19
+ }
20
+ }
21
+
22
+ info(...args: unknown[]): void {
23
+ console.log(chalk.blue('ℹ'), ...args);
24
+ }
25
+
26
+ warn(...args: unknown[]): void {
27
+ console.log(chalk.yellow('⚠'), ...args);
28
+ }
29
+
30
+ error(...args: unknown[]): void {
31
+ console.error(chalk.red('✗'), ...args);
32
+ }
33
+
34
+ success(...args: unknown[]): void {
35
+ console.log(chalk.green('✓'), ...args);
36
+ }
37
+
38
+ // AI response formatting
39
+ ai(message: string): void {
40
+ console.log(chalk.cyan('🤖'), message);
41
+ }
42
+
43
+ // User input formatting
44
+ user(message: string): void {
45
+ console.log(chalk.white('👤'), message);
46
+ }
47
+
48
+ // Code block
49
+ code(code: string, language?: string): void {
50
+ console.log(chalk.gray('─'.repeat(60)));
51
+ console.log(chalk.yellow(code));
52
+ console.log(chalk.gray('─'.repeat(60)));
53
+ }
54
+
55
+ // Diff output
56
+ diff(added: string[], removed: string[]): void {
57
+ removed.forEach(line => console.log(chalk.red(`- ${line}`)));
58
+ added.forEach(line => console.log(chalk.green(`+ ${line}`)));
59
+ }
60
+
61
+ // Section header
62
+ section(title: string): void {
63
+ console.log();
64
+ console.log(chalk.bold.cyan(`═══ ${title} ═══`));
65
+ console.log();
66
+ }
67
+
68
+ // Progress
69
+ progress(message: string): void {
70
+ process.stdout.write(chalk.gray(`${message}\r`));
71
+ }
72
+
73
+ // Clear line
74
+ clearLine(): void {
75
+ process.stdout.write('\r\x1b[K');
76
+ }
77
+
78
+ // Box output
79
+ box(content: string, title?: string): void {
80
+ const lines = content.split('\n');
81
+ const maxLen = Math.max(...lines.map(l => l.length), title?.length || 0);
82
+ const width = maxLen + 4;
83
+
84
+ console.log(chalk.cyan('┌' + '─'.repeat(width - 2) + '┐'));
85
+ if (title) {
86
+ console.log(chalk.cyan('│ ') + chalk.bold.white(title.padEnd(width - 4)) + chalk.cyan(' │'));
87
+ console.log(chalk.cyan('├' + '─'.repeat(width - 2) + '┤'));
88
+ }
89
+ lines.forEach(line => {
90
+ console.log(chalk.cyan('│ ') + line.padEnd(width - 4) + chalk.cyan(' │'));
91
+ });
92
+ console.log(chalk.cyan('└' + '─'.repeat(width - 2) + '┘'));
93
+ }
94
+
95
+ // Table output
96
+ table(headers: string[], rows: string[][]): void {
97
+ const colWidths = headers.map((h, i) => {
98
+ const maxData = Math.max(...rows.map(r => (r[i] || '').length));
99
+ return Math.max(h.length, maxData);
100
+ });
101
+
102
+ // Header
103
+ console.log(
104
+ chalk.gray('│ ') +
105
+ headers.map((h, i) => chalk.bold(h.padEnd(colWidths[i]))).join(chalk.gray(' │ ')) +
106
+ chalk.gray(' │')
107
+ );
108
+
109
+ // Separator
110
+ console.log(
111
+ chalk.gray('├─') +
112
+ colWidths.map(w => '─'.repeat(w)).join(chalk.gray('─┼─')) +
113
+ chalk.gray('─┤')
114
+ );
115
+
116
+ // Rows
117
+ rows.forEach(row => {
118
+ console.log(
119
+ chalk.gray('│ ') +
120
+ row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(chalk.gray(' │ ')) +
121
+ chalk.gray(' │')
122
+ );
123
+ });
124
+ }
125
+ }