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,64 @@
1
+ /**
2
+ * Interactive Chat Command for Vigthoria CLI
3
+ *
4
+ * Now with Claude Code-like agentic capabilities!
5
+ */
6
+ import { Config } from '../utils/config.js';
7
+ import { Logger } from '../utils/logger.js';
8
+ interface ChatOptions {
9
+ model: string;
10
+ project: string;
11
+ agent?: boolean;
12
+ autoApprove?: boolean;
13
+ resume?: boolean;
14
+ stream?: boolean;
15
+ local?: boolean;
16
+ }
17
+ export declare class ChatCommand {
18
+ private config;
19
+ private logger;
20
+ private api;
21
+ private messages;
22
+ private fileUtils;
23
+ private marked;
24
+ private tools;
25
+ private agentMode;
26
+ private rl;
27
+ private sessionManager;
28
+ private currentSession;
29
+ private streamMode;
30
+ private localMode;
31
+ constructor(config: Config, logger: Logger);
32
+ run(options: ChatOptions): Promise<void>;
33
+ private buildSystemPrompt;
34
+ private printWelcome;
35
+ private startRepl;
36
+ private chat;
37
+ /**
38
+ * Execute tool calls from AI response (Claude Code-like)
39
+ */
40
+ private executeToolCalls;
41
+ /**
42
+ * Format tool results for AI context
43
+ */
44
+ private formatToolResults;
45
+ /**
46
+ * Truncate long output for context management
47
+ */
48
+ private truncateOutput;
49
+ /**
50
+ * Ask user for permission to execute dangerous action
51
+ */
52
+ private askPermission;
53
+ private addFileToContext;
54
+ private startEditMode;
55
+ private showPendingDiff;
56
+ private applyChanges;
57
+ private printHelp;
58
+ private listSessions;
59
+ private showHistory;
60
+ private compactContext;
61
+ private printModels;
62
+ }
63
+ export {};
64
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAM5C,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,EAAE,CAAmC;IAC7C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,SAAS,CAAkB;gBAEvB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAYpC,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA+D9C,OAAO,CAAC,iBAAiB;IAqCzB,OAAO,CAAC,YAAY;YAmBN,SAAS;YAoMT,IAAI;IA+ClB;;OAEG;YACW,gBAAgB;IA+B9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;YACW,aAAa;YAgBb,gBAAgB;YAkBhB,aAAa;IAqB3B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,SAAS;IA4BjB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,WAAW;YAkBL,cAAc;IA6C5B,OAAO,CAAC,WAAW;CAUpB"}
@@ -0,0 +1,596 @@
1
+ "use strict";
2
+ /**
3
+ * Interactive Chat Command for Vigthoria CLI
4
+ *
5
+ * Now with Claude Code-like agentic capabilities!
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.ChatCommand = void 0;
45
+ const chalk_1 = __importDefault(require("chalk"));
46
+ const ora_1 = __importDefault(require("ora"));
47
+ const readline = __importStar(require("readline"));
48
+ const marked_1 = require("marked");
49
+ const marked_terminal_1 = require("marked-terminal");
50
+ const api_js_1 = require("../utils/api.js");
51
+ const files_js_1 = require("../utils/files.js");
52
+ const tools_js_1 = require("../utils/tools.js");
53
+ const session_js_1 = require("../utils/session.js");
54
+ class ChatCommand {
55
+ config;
56
+ logger;
57
+ api;
58
+ messages = [];
59
+ fileUtils;
60
+ marked;
61
+ tools = null;
62
+ agentMode = false;
63
+ rl = null;
64
+ sessionManager;
65
+ currentSession = null;
66
+ streamMode = true;
67
+ localMode = false;
68
+ constructor(config, logger) {
69
+ this.config = config;
70
+ this.logger = logger;
71
+ this.api = new api_js_1.APIClient(config, logger);
72
+ this.fileUtils = new files_js_1.FileUtils(process.cwd(), config.get('project').ignorePatterns);
73
+ this.sessionManager = new session_js_1.SessionManager();
74
+ // Setup marked for terminal rendering
75
+ this.marked = new marked_1.Marked();
76
+ this.marked.use((0, marked_terminal_1.markedTerminal)());
77
+ }
78
+ async run(options) {
79
+ // Check authentication (skip for local testing mode)
80
+ if (!options.local && !this.config.isAuthenticated()) {
81
+ this.logger.error('Not authenticated. Run: vigthoria login');
82
+ this.logger.info('Tip: Use --local flag to test with local Ollama models');
83
+ return;
84
+ }
85
+ if (!options.local && !this.config.hasValidSubscription()) {
86
+ this.logger.warn('Your subscription has expired. Some features may be limited.');
87
+ }
88
+ if (options.local) {
89
+ this.logger.info('Local mode: Using Ollama for AI responses');
90
+ }
91
+ // Setup agentic tools if enabled
92
+ this.agentMode = options.agent || false;
93
+ this.streamMode = options.stream !== false; // Default to true
94
+ this.localMode = options.local || false;
95
+ if (this.agentMode) {
96
+ this.tools = new tools_js_1.AgenticTools(this.logger, options.project, this.askPermission.bind(this), options.autoApprove || false);
97
+ }
98
+ // Try to resume previous session or create new one
99
+ if (options.resume) {
100
+ this.currentSession = this.sessionManager.getLatest(options.project);
101
+ if (this.currentSession) {
102
+ this.messages = [...this.currentSession.messages];
103
+ this.logger.success(`Resumed session: ${this.currentSession.id}`);
104
+ }
105
+ }
106
+ if (!this.currentSession) {
107
+ this.currentSession = this.sessionManager.create(options.project, options.model, this.agentMode);
108
+ }
109
+ // Get project context
110
+ const projectContext = await this.fileUtils.getProjectContext();
111
+ // Setup system message
112
+ const systemMessage = {
113
+ role: 'system',
114
+ content: this.buildSystemPrompt(projectContext, options),
115
+ };
116
+ this.messages.push(systemMessage);
117
+ this.printWelcome(options);
118
+ // Start REPL
119
+ await this.startRepl(options);
120
+ }
121
+ buildSystemPrompt(projectContext, options) {
122
+ let prompt = `You are Vigthoria, a premium AI coding assistant. You help developers write, understand, and improve code.
123
+
124
+ Project Context:
125
+ - Type: ${projectContext.type}
126
+ - Root: ${options.project}
127
+ - Key files: ${projectContext.files.slice(0, 10).join(', ')}
128
+ ${projectContext.type === 'node' ? `- Dependencies: ${Object.keys(projectContext.dependencies).slice(0, 15).join(', ')}` : ''}
129
+
130
+ Guidelines:
131
+ - Provide complete, production-ready code
132
+ - Use modern best practices (2024-2026 standards)
133
+ - Include proper error handling
134
+ - Explain your reasoning when helpful
135
+ - Be concise but thorough
136
+
137
+ Special Commands (user may use these):
138
+ - /file <path> - Read and include a file in context
139
+ - /edit <path> - Switch to file editing mode
140
+ - /diff - Show pending changes
141
+ - /apply - Apply pending changes
142
+ - /clear - Clear conversation history
143
+ - /model <name> - Switch AI model
144
+ - /agent - Toggle agentic mode (Claude Code-like autonomous actions)
145
+ - /help - Show available commands`;
146
+ // Add tool instructions if in agent mode
147
+ if (this.agentMode && this.tools) {
148
+ prompt += `\n\n${tools_js_1.AgenticTools.getToolsForPrompt()}`;
149
+ }
150
+ return prompt;
151
+ }
152
+ printWelcome(options) {
153
+ const sub = this.config.get('subscription');
154
+ console.log();
155
+ this.logger.box(`Model: ${chalk_1.default.cyan(options.model)}\n` +
156
+ `Plan: ${chalk_1.default.green(sub.plan || 'free')}\n` +
157
+ `Project: ${chalk_1.default.gray(options.project)}\n` +
158
+ `Agent Mode: ${this.agentMode ? chalk_1.default.green('ON ✓') : chalk_1.default.gray('OFF')}`, 'Vigthoria Chat');
159
+ console.log();
160
+ if (this.agentMode) {
161
+ console.log(chalk_1.default.yellow('🤖 Agent Mode: AI can read files, edit code, and run commands autonomously.'));
162
+ }
163
+ console.log(chalk_1.default.gray('Type your message or /help for commands. Press Ctrl+C to exit.'));
164
+ console.log();
165
+ }
166
+ async startRepl(options) {
167
+ this.rl = readline.createInterface({
168
+ input: process.stdin,
169
+ output: process.stdout,
170
+ prompt: chalk_1.default.cyan('you › '),
171
+ });
172
+ let currentModel = options.model;
173
+ let pendingChanges = null;
174
+ this.rl.prompt();
175
+ for await (const line of this.rl) {
176
+ const input = line.trim();
177
+ if (!input) {
178
+ this.rl.prompt();
179
+ continue;
180
+ }
181
+ // Handle special commands
182
+ if (input.startsWith('/')) {
183
+ const [cmd, ...args] = input.slice(1).split(' ');
184
+ switch (cmd) {
185
+ case 'help':
186
+ this.printHelp();
187
+ break;
188
+ case 'clear':
189
+ this.messages = [this.messages[0]]; // Keep system message
190
+ this.logger.success('Conversation cleared');
191
+ break;
192
+ case 'model':
193
+ if (args[0]) {
194
+ currentModel = args[0];
195
+ this.logger.success(`Model switched to: ${currentModel}`);
196
+ }
197
+ else {
198
+ this.printModels();
199
+ }
200
+ break;
201
+ case 'agent':
202
+ this.agentMode = !this.agentMode;
203
+ if (this.agentMode && !this.tools) {
204
+ this.tools = new tools_js_1.AgenticTools(this.logger, options.project, this.askPermission.bind(this), options.autoApprove || false);
205
+ }
206
+ // Rebuild system prompt with/without tools
207
+ this.messages[0] = {
208
+ role: 'system',
209
+ content: this.buildSystemPrompt(await this.fileUtils.getProjectContext(), { ...options, agent: this.agentMode }),
210
+ };
211
+ this.logger.success(`Agent mode: ${this.agentMode ? chalk_1.default.green('ON') : chalk_1.default.red('OFF')}`);
212
+ if (this.agentMode) {
213
+ console.log(chalk_1.default.yellow(' AI can now read files, edit code, and run commands.'));
214
+ }
215
+ break;
216
+ case 'approve':
217
+ if (this.tools) {
218
+ options.autoApprove = !options.autoApprove;
219
+ this.tools = new tools_js_1.AgenticTools(this.logger, options.project, this.askPermission.bind(this), options.autoApprove);
220
+ this.logger.success(`Auto-approve: ${options.autoApprove ? chalk_1.default.green('ON') : chalk_1.default.red('OFF')}`);
221
+ if (options.autoApprove) {
222
+ console.log(chalk_1.default.red(' ⚠️ AI actions will be executed without confirmation!'));
223
+ }
224
+ }
225
+ break;
226
+ case 'file':
227
+ if (args[0]) {
228
+ await this.addFileToContext(args[0]);
229
+ }
230
+ else {
231
+ this.logger.error('Usage: /file <path>');
232
+ }
233
+ break;
234
+ case 'edit':
235
+ if (args[0]) {
236
+ pendingChanges = await this.startEditMode(args[0], currentModel);
237
+ }
238
+ else {
239
+ this.logger.error('Usage: /edit <path>');
240
+ }
241
+ break;
242
+ case 'diff':
243
+ if (pendingChanges) {
244
+ this.showPendingDiff(pendingChanges);
245
+ }
246
+ else {
247
+ this.logger.info('No pending changes');
248
+ }
249
+ break;
250
+ case 'apply':
251
+ if (pendingChanges) {
252
+ this.applyChanges(pendingChanges);
253
+ pendingChanges = null;
254
+ }
255
+ else {
256
+ this.logger.info('No pending changes to apply');
257
+ }
258
+ break;
259
+ case 'sessions':
260
+ this.listSessions();
261
+ break;
262
+ case 'history':
263
+ this.showHistory();
264
+ break;
265
+ case 'save':
266
+ if (this.currentSession) {
267
+ this.sessionManager.save(this.currentSession);
268
+ this.logger.success(`Session saved: ${this.currentSession.id}`);
269
+ }
270
+ break;
271
+ case 'new':
272
+ // Start new session
273
+ this.currentSession = this.sessionManager.create(options.project, currentModel, this.agentMode);
274
+ this.messages = [this.messages[0]]; // Keep only system message
275
+ this.logger.success(`New session: ${this.currentSession.id}`);
276
+ break;
277
+ case 'compact':
278
+ // Compact context by summarizing older messages
279
+ await this.compactContext(currentModel);
280
+ break;
281
+ case 'undo':
282
+ // Undo last file operation
283
+ if (this.tools) {
284
+ const undoResult = await this.tools.undo();
285
+ if (undoResult.success) {
286
+ this.logger.success(undoResult.output || 'Undo completed');
287
+ if (undoResult.metadata?.remainingUndos !== undefined) {
288
+ console.log(chalk_1.default.gray(` ${undoResult.metadata.remainingUndos} more undo(s) available`));
289
+ }
290
+ }
291
+ else {
292
+ this.logger.error(undoResult.error || 'Nothing to undo');
293
+ }
294
+ }
295
+ else {
296
+ this.logger.info('Undo is only available in agent mode. Use /agent to enable.');
297
+ }
298
+ break;
299
+ case 'exit':
300
+ case 'quit':
301
+ // Auto-save session on exit
302
+ if (this.currentSession && this.messages.length > 1) {
303
+ this.sessionManager.save(this.currentSession);
304
+ console.log(chalk_1.default.gray(`Session saved: ${this.currentSession.id}`));
305
+ }
306
+ console.log(chalk_1.default.cyan('\nGoodbye! 👋\n'));
307
+ this.rl.close();
308
+ return;
309
+ default:
310
+ this.logger.warn(`Unknown command: /${cmd}`);
311
+ }
312
+ this.rl.prompt();
313
+ continue;
314
+ }
315
+ // Regular chat message
316
+ await this.chat(input, currentModel);
317
+ // Save message to session
318
+ if (this.currentSession) {
319
+ this.currentSession.messages = [...this.messages];
320
+ this.sessionManager.save(this.currentSession);
321
+ }
322
+ this.rl.prompt();
323
+ }
324
+ }
325
+ async chat(userInput, model) {
326
+ // Add user message (skip if empty - used for tool continuation)
327
+ if (userInput) {
328
+ this.messages.push({ role: 'user', content: userInput });
329
+ }
330
+ const spinner = (0, ora_1.default)({
331
+ text: chalk_1.default.gray('Thinking...'),
332
+ spinner: 'dots',
333
+ }).start();
334
+ try {
335
+ const response = await this.api.chat(this.messages, model, this.localMode);
336
+ spinner.stop();
337
+ // Add assistant message
338
+ this.messages.push({ role: 'assistant', content: response.message });
339
+ // Render markdown response
340
+ console.log();
341
+ console.log(chalk_1.default.cyan('vigthoria ›'));
342
+ console.log(this.marked.parse(response.message));
343
+ // Show token usage
344
+ if (response.usage) {
345
+ console.log(chalk_1.default.gray(`[${response.usage.total_tokens} tokens]`));
346
+ }
347
+ console.log();
348
+ // In agent mode, check for and execute tool calls
349
+ if (this.agentMode && this.tools) {
350
+ const toolCalls = tools_js_1.AgenticTools.parseToolCalls(response.message);
351
+ if (toolCalls.length > 0) {
352
+ await this.executeToolCalls(toolCalls, model);
353
+ }
354
+ }
355
+ }
356
+ catch (error) {
357
+ spinner.stop();
358
+ this.logger.error('Failed to get response:', error.message);
359
+ // Remove failed user message
360
+ this.messages.pop();
361
+ }
362
+ }
363
+ /**
364
+ * Execute tool calls from AI response (Claude Code-like)
365
+ */
366
+ async executeToolCalls(calls, model) {
367
+ const results = [];
368
+ for (const call of calls) {
369
+ console.log(chalk_1.default.yellow(`\n⚙ Executing: ${call.tool}`));
370
+ const result = await this.tools.execute(call);
371
+ results.push({ tool: call.tool, result });
372
+ if (result.success) {
373
+ this.logger.success(`${call.tool}: Success`);
374
+ if (result.output) {
375
+ console.log(chalk_1.default.gray(this.truncateOutput(result.output)));
376
+ }
377
+ }
378
+ else {
379
+ this.logger.error(`${call.tool}: ${result.error}`);
380
+ }
381
+ }
382
+ // Send tool results back to AI for continuation
383
+ const toolResultsMessage = {
384
+ role: 'user',
385
+ content: this.formatToolResults(results),
386
+ };
387
+ this.messages.push(toolResultsMessage);
388
+ // Get AI's follow-up response
389
+ console.log();
390
+ await this.chat('', model);
391
+ }
392
+ /**
393
+ * Format tool results for AI context
394
+ */
395
+ formatToolResults(results) {
396
+ let msg = 'Tool execution results:\n\n';
397
+ for (const { tool, result } of results) {
398
+ msg += `## ${tool}\n`;
399
+ msg += `Status: ${result.success ? 'Success' : 'Failed'}\n`;
400
+ if (result.output) {
401
+ msg += `Output:\n\`\`\`\n${this.truncateOutput(result.output)}\n\`\`\`\n`;
402
+ }
403
+ if (result.error) {
404
+ msg += `Error: ${result.error}\n`;
405
+ }
406
+ msg += '\n';
407
+ }
408
+ msg += 'Continue with your analysis or next steps.';
409
+ return msg;
410
+ }
411
+ /**
412
+ * Truncate long output for context management
413
+ */
414
+ truncateOutput(output, maxLines = 50) {
415
+ const lines = output.split('\n');
416
+ if (lines.length <= maxLines) {
417
+ return output;
418
+ }
419
+ return lines.slice(0, maxLines).join('\n') + `\n... (${lines.length - maxLines} more lines)`;
420
+ }
421
+ /**
422
+ * Ask user for permission to execute dangerous action
423
+ */
424
+ async askPermission(action) {
425
+ return new Promise((resolve) => {
426
+ console.log('\n' + action);
427
+ if (!this.rl) {
428
+ resolve(false);
429
+ return;
430
+ }
431
+ this.rl.question(chalk_1.default.yellow('Allow? [y/N] '), (answer) => {
432
+ const allowed = answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
433
+ resolve(allowed);
434
+ });
435
+ });
436
+ }
437
+ async addFileToContext(filePath) {
438
+ const file = this.fileUtils.readFile(filePath);
439
+ if (!file) {
440
+ this.logger.error(`File not found: ${filePath}`);
441
+ return;
442
+ }
443
+ // Add file content to messages
444
+ const fileMessage = {
445
+ role: 'user',
446
+ content: `Here is the content of ${file.relativePath} (${file.language}, ${file.lines} lines):\n\n\`\`\`${file.language}\n${file.content}\n\`\`\``,
447
+ };
448
+ this.messages.push(fileMessage);
449
+ this.logger.success(`Added ${file.relativePath} to context (${file.lines} lines)`);
450
+ }
451
+ async startEditMode(filePath, model) {
452
+ const file = this.fileUtils.readFile(filePath);
453
+ if (!file) {
454
+ this.logger.error(`File not found: ${filePath}`);
455
+ return null;
456
+ }
457
+ console.log();
458
+ this.logger.section(`Editing: ${file.relativePath}`);
459
+ console.log(chalk_1.default.gray('What changes would you like to make?'));
460
+ console.log();
461
+ // This would enter a sub-REPL for editing
462
+ // For now, return the file info
463
+ return { file: file.path, content: file.content };
464
+ }
465
+ showPendingDiff(changes) {
466
+ const file = this.fileUtils.readFile(changes.file);
467
+ if (!file)
468
+ return;
469
+ const diff = this.fileUtils.createDiff(file.content, changes.content);
470
+ this.logger.section('Pending Changes');
471
+ this.logger.diff(diff.added, diff.removed);
472
+ }
473
+ applyChanges(changes) {
474
+ // Backup first
475
+ const backup = this.fileUtils.backupFile(changes.file);
476
+ if (backup) {
477
+ this.logger.info(`Backup created: ${backup}`);
478
+ }
479
+ // Apply
480
+ if (this.fileUtils.writeFile(changes.file, changes.content)) {
481
+ this.logger.success(`Changes applied to ${changes.file}`);
482
+ }
483
+ else {
484
+ this.logger.error('Failed to apply changes');
485
+ }
486
+ }
487
+ printHelp() {
488
+ console.log();
489
+ this.logger.section('Available Commands');
490
+ console.log(chalk_1.default.cyan('/file <path>') + ' - Add file to conversation context');
491
+ console.log(chalk_1.default.cyan('/edit <path>') + ' - Start editing a file');
492
+ console.log(chalk_1.default.cyan('/diff') + ' - Show pending changes');
493
+ console.log(chalk_1.default.cyan('/apply') + ' - Apply pending changes');
494
+ console.log(chalk_1.default.cyan('/model <name>') + ' - Switch AI model');
495
+ console.log(chalk_1.default.cyan('/agent') + ' - Toggle agentic mode (Claude Code-like)');
496
+ console.log(chalk_1.default.cyan('/approve') + ' - Toggle auto-approve for agent actions');
497
+ console.log(chalk_1.default.cyan('/undo') + ' - Undo last file operation (agent mode)');
498
+ console.log(chalk_1.default.cyan('/clear') + ' - Clear conversation history');
499
+ console.log(chalk_1.default.cyan('/compact') + ' - Compact context (summarize older messages)');
500
+ console.log(chalk_1.default.cyan('/sessions') + ' - List saved sessions');
501
+ console.log(chalk_1.default.cyan('/history') + ' - Show conversation history');
502
+ console.log(chalk_1.default.cyan('/save') + ' - Save current session');
503
+ console.log(chalk_1.default.cyan('/new') + ' - Start new session');
504
+ console.log(chalk_1.default.cyan('/help') + ' - Show this help');
505
+ console.log(chalk_1.default.cyan('/exit') + ' - Exit Vigthoria (auto-saves)');
506
+ console.log();
507
+ if (this.agentMode) {
508
+ console.log(chalk_1.default.yellow('Agent Mode Tools:'));
509
+ console.log(chalk_1.default.gray(' read_file, write_file, edit_file, bash, grep, list_dir, glob, git'));
510
+ console.log();
511
+ }
512
+ }
513
+ listSessions() {
514
+ const sessions = this.sessionManager.list();
515
+ console.log();
516
+ this.logger.section('Saved Sessions');
517
+ if (sessions.length === 0) {
518
+ console.log(chalk_1.default.gray(' No saved sessions'));
519
+ }
520
+ else {
521
+ sessions.slice(0, 10).forEach(s => {
522
+ const current = this.currentSession?.id === s.id ? chalk_1.default.green(' (current)') : '';
523
+ const agent = s.agentMode ? chalk_1.default.yellow(' [agent]') : '';
524
+ console.log(chalk_1.default.cyan(s.id) + agent + current);
525
+ console.log(chalk_1.default.gray(` ${s.project} - ${new Date(s.updatedAt).toLocaleString()}`));
526
+ });
527
+ }
528
+ console.log();
529
+ }
530
+ showHistory() {
531
+ console.log();
532
+ this.logger.section('Conversation History');
533
+ const userMessages = this.messages.filter(m => m.role !== 'system');
534
+ if (userMessages.length === 0) {
535
+ console.log(chalk_1.default.gray(' No messages yet'));
536
+ }
537
+ else {
538
+ userMessages.forEach((m, i) => {
539
+ const role = m.role === 'user' ? chalk_1.default.cyan('you') : chalk_1.default.green('vigthoria');
540
+ const preview = m.content.substring(0, 60).replace(/\n/g, ' ');
541
+ console.log(`${i + 1}. ${role}: ${chalk_1.default.gray(preview)}...`);
542
+ });
543
+ }
544
+ console.log();
545
+ }
546
+ async compactContext(model) {
547
+ // If we have too many messages, summarize older ones
548
+ if (this.messages.length < 10) {
549
+ this.logger.info('Context is already compact');
550
+ return;
551
+ }
552
+ const spinner = (0, ora_1.default)({
553
+ text: chalk_1.default.gray('Compacting context...'),
554
+ spinner: 'dots',
555
+ }).start();
556
+ try {
557
+ // Keep system message and last 4 messages
558
+ const systemMessage = this.messages[0];
559
+ const recentMessages = this.messages.slice(-4);
560
+ const olderMessages = this.messages.slice(1, -4);
561
+ if (olderMessages.length === 0) {
562
+ spinner.stop();
563
+ this.logger.info('Nothing to compact');
564
+ return;
565
+ }
566
+ // Ask AI to summarize older conversation
567
+ const summaryResponse = await this.api.chat([
568
+ { role: 'system', content: 'Summarize this conversation in a concise way, preserving key context and decisions.' },
569
+ ...olderMessages,
570
+ ], model, this.localMode);
571
+ // Create compacted context
572
+ this.messages = [
573
+ systemMessage,
574
+ { role: 'system', content: `[Previous conversation summary]: ${summaryResponse.message}` },
575
+ ...recentMessages,
576
+ ];
577
+ spinner.stop();
578
+ this.logger.success(`Compacted ${olderMessages.length} messages into summary`);
579
+ }
580
+ catch (error) {
581
+ spinner.stop();
582
+ this.logger.error('Failed to compact context:', error.message);
583
+ }
584
+ }
585
+ printModels() {
586
+ const models = this.config.getAvailableModels();
587
+ console.log();
588
+ this.logger.section('Available Models');
589
+ models.forEach(m => {
590
+ console.log(chalk_1.default.cyan(m.id.padEnd(20)) + chalk_1.default.gray(m.description));
591
+ });
592
+ console.log();
593
+ }
594
+ }
595
+ exports.ChatCommand = ChatCommand;
596
+ //# sourceMappingURL=chat.js.map