prab-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.
@@ -0,0 +1,374 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const LOG_DIR = path_1.default.join(os_1.default.homedir(), '.config', 'groq-cli-tool', 'logs');
12
+ // ═══════════════════════════════════════════════════════════════════════════════
13
+ // STYLING
14
+ // ═══════════════════════════════════════════════════════════════════════════════
15
+ const ICONS = {
16
+ SESSION_START: '🚀',
17
+ PROMPT_RECEIVED: '💬',
18
+ API_REQUEST: '📡',
19
+ API_RESPONSE: '📥',
20
+ API_ERROR: '💥',
21
+ AI_RESPONSE: '🤖',
22
+ AI_TOOL_DECISION: '🧠',
23
+ TOOL_START: '⚙️ ',
24
+ TOOL_SUCCESS: '✅',
25
+ TOOL_ERROR: '❌',
26
+ TOOL_CANCELLED: '🚫',
27
+ MODEL_INIT: '🔌',
28
+ MODEL_SWITCH: '🔄',
29
+ PROMPT_COMPLETE: '✨',
30
+ PROMPT_FAILED: '💔',
31
+ STREAM_CHUNK: '📦',
32
+ ITERATION: '🔁',
33
+ CONTEXT_ATTACHED: '📎',
34
+ DEBUG: '🔍',
35
+ WARNING: '⚠️ ',
36
+ ERROR: '🔥',
37
+ };
38
+ const COLORS = {
39
+ info: chalk_1.default.blue,
40
+ success: chalk_1.default.green,
41
+ error: chalk_1.default.red,
42
+ warn: chalk_1.default.yellow,
43
+ debug: chalk_1.default.gray,
44
+ api: chalk_1.default.magenta,
45
+ ai: chalk_1.default.cyan,
46
+ };
47
+ const BOX = {
48
+ topLeft: '╭',
49
+ topRight: '╮',
50
+ bottomLeft: '╰',
51
+ bottomRight: '╯',
52
+ horizontal: '─',
53
+ vertical: '│',
54
+ cross: '┼',
55
+ };
56
+ // ═══════════════════════════════════════════════════════════════════════════════
57
+ // FORMATTING
58
+ // ═══════════════════════════════════════════════════════════════════════════════
59
+ function formatTime(timestamp) {
60
+ const date = new Date(timestamp);
61
+ const time = date.toLocaleTimeString('en-US', {
62
+ hour12: false,
63
+ hour: '2-digit',
64
+ minute: '2-digit',
65
+ second: '2-digit'
66
+ });
67
+ const ms = String(date.getMilliseconds()).padStart(3, '0');
68
+ return chalk_1.default.dim(`${time}.${ms}`);
69
+ }
70
+ function formatDuration(ms) {
71
+ if (ms < 1000)
72
+ return chalk_1.default.dim(`${ms}ms`);
73
+ return chalk_1.default.dim(`${(ms / 1000).toFixed(2)}s`);
74
+ }
75
+ function formatEntry(entry, verbose) {
76
+ const lines = [];
77
+ const icon = ICONS[entry.event] || '•';
78
+ const color = COLORS[entry.level] || chalk_1.default.white;
79
+ const time = formatTime(entry.timestamp);
80
+ const duration = entry.duration ? ` ${formatDuration(entry.duration)}` : '';
81
+ // Main line
82
+ const mainLine = `${time} ${icon} ${color(entry.message)}${duration}`;
83
+ lines.push(mainLine);
84
+ // Add details for important events
85
+ if (verbose && entry.data) {
86
+ const indent = ' ';
87
+ switch (entry.event) {
88
+ case 'PROMPT_RECEIVED':
89
+ if (entry.data.prompt && entry.data.prompt.length > 100) {
90
+ lines.push(chalk_1.default.dim(`${indent}Full prompt: "${entry.data.prompt.substring(0, 300)}..."`));
91
+ }
92
+ break;
93
+ case 'AI_TOOL_DECISION':
94
+ if (entry.data.toolCalls) {
95
+ entry.data.toolCalls.forEach((tc) => {
96
+ const argsStr = JSON.stringify(tc.args || {});
97
+ lines.push(chalk_1.default.dim(`${indent}→ ${chalk_1.default.cyan(tc.name)}(${argsStr.substring(0, 80)}${argsStr.length > 80 ? '...' : ''})`));
98
+ });
99
+ }
100
+ break;
101
+ case 'TOOL_START':
102
+ if (entry.data.args && Object.keys(entry.data.args).length > 0) {
103
+ const argsStr = JSON.stringify(entry.data.args);
104
+ lines.push(chalk_1.default.dim(`${indent}Args: ${argsStr.substring(0, 100)}${argsStr.length > 100 ? '...' : ''}`));
105
+ }
106
+ break;
107
+ case 'TOOL_SUCCESS':
108
+ if (entry.data.outputPreview) {
109
+ const preview = entry.data.outputPreview.replace(/\n/g, ' ').substring(0, 80);
110
+ lines.push(chalk_1.default.dim(`${indent}Output: "${preview}${entry.data.outputLength > 80 ? '...' : ''}"`));
111
+ }
112
+ break;
113
+ case 'TOOL_ERROR':
114
+ if (entry.data.error || entry.data.errorMessage) {
115
+ lines.push(chalk_1.default.red(`${indent}Error: ${entry.data.errorMessage || entry.data.error}`));
116
+ }
117
+ if (entry.data.args) {
118
+ const argsStr = JSON.stringify(entry.data.args);
119
+ lines.push(chalk_1.default.dim(`${indent}Args: ${argsStr.substring(0, 150)}${argsStr.length > 150 ? '...' : ''}`));
120
+ }
121
+ break;
122
+ case 'API_ERROR':
123
+ case 'PROMPT_FAILED':
124
+ if (entry.data.error) {
125
+ lines.push(chalk_1.default.red(`${indent}Error: ${entry.data.error}`));
126
+ }
127
+ if (entry.data.stack) {
128
+ const stackLines = entry.data.stack.split('\n').slice(0, 3);
129
+ stackLines.forEach((line) => {
130
+ lines.push(chalk_1.default.dim(`${indent}${line.trim()}`));
131
+ });
132
+ }
133
+ break;
134
+ case 'API_REQUEST':
135
+ lines.push(chalk_1.default.dim(`${indent}Model: ${entry.data.model}, Messages: ${entry.data.messageCount}, Tools: ${entry.data.toolCount}`));
136
+ break;
137
+ case 'API_RESPONSE':
138
+ lines.push(chalk_1.default.dim(`${indent}Content: ${entry.data.hasContent}, Tool calls: ${entry.data.toolCallCount}`));
139
+ break;
140
+ case 'AI_RESPONSE':
141
+ if (entry.data.content && entry.data.length > 150) {
142
+ lines.push(chalk_1.default.dim(`${indent}(${entry.data.length} chars total)`));
143
+ }
144
+ break;
145
+ }
146
+ }
147
+ return lines;
148
+ }
149
+ // ═══════════════════════════════════════════════════════════════════════════════
150
+ // DISPLAY
151
+ // ═══════════════════════════════════════════════════════════════════════════════
152
+ function displayBanner() {
153
+ console.clear();
154
+ console.log('');
155
+ console.log(chalk_1.default.cyan.bold(' ╭─────────────────────────────────────────────────────────────╮'));
156
+ console.log(chalk_1.default.cyan.bold(' │') + chalk_1.default.white.bold(' GROQ CLI - Real-time Logger ') + chalk_1.default.cyan.bold('│'));
157
+ console.log(chalk_1.default.cyan.bold(' │') + chalk_1.default.dim(' Watching all CLI events live ') + chalk_1.default.cyan.bold('│'));
158
+ console.log(chalk_1.default.cyan.bold(' ╰─────────────────────────────────────────────────────────────╯'));
159
+ console.log('');
160
+ }
161
+ function displayWaiting(logFile) {
162
+ const fileName = path_1.default.basename(logFile);
163
+ console.log(chalk_1.default.dim(` Watching: ${fileName}`));
164
+ console.log(chalk_1.default.dim(' Waiting for events... (Press Ctrl+C to exit)'));
165
+ console.log('');
166
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(60)));
167
+ console.log('');
168
+ }
169
+ function displayStats(stats) {
170
+ console.log('');
171
+ console.log(chalk_1.default.cyan.bold(' ╭─────────────────────────────────────────────────────────────╮'));
172
+ console.log(chalk_1.default.cyan.bold(' │') + chalk_1.default.white.bold(' SESSION SUMMARY ') + chalk_1.default.cyan.bold('│'));
173
+ console.log(chalk_1.default.cyan.bold(' ├─────────────────────────────────────────────────────────────┤'));
174
+ console.log(chalk_1.default.cyan.bold(' │') + ` 💬 Prompts: ${String(stats.prompts).padStart(5)} ` + chalk_1.default.cyan.bold('│'));
175
+ console.log(chalk_1.default.cyan.bold(' │') + ` 📡 API Requests: ${String(stats.apiRequests).padStart(5)} ` + chalk_1.default.cyan.bold('│'));
176
+ console.log(chalk_1.default.cyan.bold(' │') + ` 🤖 AI Responses: ${String(stats.aiResponses).padStart(5)} ` + chalk_1.default.cyan.bold('│'));
177
+ console.log(chalk_1.default.cyan.bold(' │') + ` ⚙️ Tool Calls: ${String(stats.toolCalls).padStart(5)} ` + chalk_1.default.cyan.bold('│'));
178
+ console.log(chalk_1.default.cyan.bold(' │') + ` ${stats.errors > 0 ? chalk_1.default.red('❌') : '✅'} Errors: ${String(stats.errors).padStart(5)} ` + chalk_1.default.cyan.bold('│'));
179
+ console.log(chalk_1.default.cyan.bold(' ╰─────────────────────────────────────────────────────────────╯'));
180
+ console.log('');
181
+ }
182
+ function displayHelp() {
183
+ console.log('');
184
+ console.log(chalk_1.default.cyan.bold(' GROQ CLI - Real-time Logger'));
185
+ console.log('');
186
+ console.log(chalk_1.default.white(' Usage:'));
187
+ console.log(chalk_1.default.dim(' npm run log ') + 'Watch latest session (real-time)');
188
+ console.log(chalk_1.default.dim(' npm run log -- -v ') + 'Verbose mode (show details)');
189
+ console.log(chalk_1.default.dim(' npm run log:list ') + 'List all sessions');
190
+ console.log(chalk_1.default.dim(' npm run log:help ') + 'Show this help');
191
+ console.log('');
192
+ console.log(chalk_1.default.white(' Legend:'));
193
+ console.log(` ${ICONS.PROMPT_RECEIVED} User prompt ${ICONS.API_REQUEST} API request ${ICONS.AI_RESPONSE} AI response`);
194
+ console.log(` ${ICONS.AI_TOOL_DECISION} AI decision ${ICONS.TOOL_START} Tool start ${ICONS.TOOL_SUCCESS} Tool success`);
195
+ console.log(` ${ICONS.TOOL_ERROR} Tool error ${ICONS.MODEL_SWITCH} Model switch ${ICONS.PROMPT_COMPLETE} Complete`);
196
+ console.log('');
197
+ console.log(chalk_1.default.white(' Run in two terminals:'));
198
+ console.log(chalk_1.default.dim(' Terminal 1: ') + chalk_1.default.green('npm run dev'));
199
+ console.log(chalk_1.default.dim(' Terminal 2: ') + chalk_1.default.green('npm run log'));
200
+ console.log('');
201
+ }
202
+ function displaySessions() {
203
+ if (!fs_1.default.existsSync(LOG_DIR)) {
204
+ console.log(chalk_1.default.yellow('\n No log directory found. Start the CLI first.\n'));
205
+ return;
206
+ }
207
+ const files = fs_1.default.readdirSync(LOG_DIR)
208
+ .filter(f => f.endsWith('.jsonl'))
209
+ .map(f => ({
210
+ name: f,
211
+ path: path_1.default.join(LOG_DIR, f),
212
+ stat: fs_1.default.statSync(path_1.default.join(LOG_DIR, f))
213
+ }))
214
+ .sort((a, b) => b.stat.mtime.getTime() - a.stat.mtime.getTime());
215
+ console.log('');
216
+ console.log(chalk_1.default.cyan.bold(' Recent Sessions'));
217
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(50)));
218
+ console.log('');
219
+ if (files.length === 0) {
220
+ console.log(chalk_1.default.yellow(' No sessions found. Start the CLI with `npm run dev`'));
221
+ }
222
+ else {
223
+ files.slice(0, 10).forEach((file, index) => {
224
+ const name = file.name.replace('session-', '').replace('.jsonl', '');
225
+ const date = file.stat.mtime.toLocaleString();
226
+ const size = (file.stat.size / 1024).toFixed(1);
227
+ const latest = index === 0 ? chalk_1.default.green(' (latest)') : '';
228
+ console.log(` ${chalk_1.default.cyan((index + 1) + '.')} ${name}${latest}`);
229
+ console.log(chalk_1.default.dim(` ${date} - ${size} KB`));
230
+ });
231
+ }
232
+ console.log('');
233
+ }
234
+ // ═══════════════════════════════════════════════════════════════════════════════
235
+ // MAIN WATCHER
236
+ // ═══════════════════════════════════════════════════════════════════════════════
237
+ async function watchLogs(verbose) {
238
+ // Find latest log file
239
+ if (!fs_1.default.existsSync(LOG_DIR)) {
240
+ fs_1.default.mkdirSync(LOG_DIR, { recursive: true });
241
+ }
242
+ const files = fs_1.default.readdirSync(LOG_DIR)
243
+ .filter(f => f.endsWith('.jsonl'))
244
+ .map(f => ({
245
+ name: f,
246
+ path: path_1.default.join(LOG_DIR, f),
247
+ mtime: fs_1.default.statSync(path_1.default.join(LOG_DIR, f)).mtime.getTime()
248
+ }))
249
+ .sort((a, b) => b.mtime - a.mtime);
250
+ let logFile = files.length > 0 ? files[0].path : null;
251
+ let lastSize = logFile && fs_1.default.existsSync(logFile) ? fs_1.default.statSync(logFile).size : 0;
252
+ const stats = {
253
+ prompts: 0,
254
+ toolCalls: 0,
255
+ apiRequests: 0,
256
+ errors: 0,
257
+ aiResponses: 0
258
+ };
259
+ displayBanner();
260
+ if (logFile) {
261
+ displayWaiting(logFile);
262
+ // Read existing entries
263
+ const content = fs_1.default.readFileSync(logFile, 'utf-8');
264
+ const lines = content.trim().split('\n').filter(l => l.trim());
265
+ // Show last 15 entries
266
+ const recentLines = lines.slice(-15);
267
+ recentLines.forEach(line => {
268
+ try {
269
+ const entry = JSON.parse(line);
270
+ updateStats(stats, entry);
271
+ formatEntry(entry, verbose).forEach(l => console.log(l));
272
+ }
273
+ catch { }
274
+ });
275
+ if (lines.length > 15) {
276
+ console.log(chalk_1.default.dim(`\n ... ${lines.length - 15} earlier entries hidden\n`));
277
+ }
278
+ }
279
+ else {
280
+ console.log(chalk_1.default.dim(' Waiting for CLI to start...\n'));
281
+ }
282
+ // Watch for new entries
283
+ const interval = setInterval(() => {
284
+ // Check for new log files
285
+ const currentFiles = fs_1.default.readdirSync(LOG_DIR)
286
+ .filter(f => f.endsWith('.jsonl'))
287
+ .map(f => ({
288
+ name: f,
289
+ path: path_1.default.join(LOG_DIR, f),
290
+ mtime: fs_1.default.statSync(path_1.default.join(LOG_DIR, f)).mtime.getTime()
291
+ }))
292
+ .sort((a, b) => b.mtime - a.mtime);
293
+ if (currentFiles.length > 0) {
294
+ const latestFile = currentFiles[0].path;
295
+ // If new session started
296
+ if (latestFile !== logFile) {
297
+ logFile = latestFile;
298
+ lastSize = 0;
299
+ console.log('');
300
+ console.log(chalk_1.default.cyan.bold(' ═══ New Session Started ═══'));
301
+ console.log('');
302
+ }
303
+ // Read new content
304
+ if (logFile && fs_1.default.existsSync(logFile)) {
305
+ const stat = fs_1.default.statSync(logFile);
306
+ if (stat.size > lastSize) {
307
+ const content = fs_1.default.readFileSync(logFile, 'utf-8');
308
+ const allLines = content.split('\n').filter(l => l.trim());
309
+ // Calculate how many new lines
310
+ const oldContent = content.substring(0, lastSize);
311
+ const oldLineCount = oldContent.split('\n').filter(l => l.trim()).length;
312
+ const newLines = allLines.slice(oldLineCount);
313
+ newLines.forEach(line => {
314
+ try {
315
+ const entry = JSON.parse(line);
316
+ updateStats(stats, entry);
317
+ formatEntry(entry, verbose).forEach(l => console.log(l));
318
+ }
319
+ catch { }
320
+ });
321
+ lastSize = stat.size;
322
+ }
323
+ }
324
+ }
325
+ }, 200);
326
+ // Handle exit
327
+ process.on('SIGINT', () => {
328
+ clearInterval(interval);
329
+ displayStats(stats);
330
+ console.log(chalk_1.default.dim(' Logger stopped.\n'));
331
+ process.exit(0);
332
+ });
333
+ // Keep alive
334
+ await new Promise(() => { });
335
+ }
336
+ function updateStats(stats, entry) {
337
+ switch (entry.event) {
338
+ case 'PROMPT_RECEIVED':
339
+ stats.prompts++;
340
+ break;
341
+ case 'API_REQUEST':
342
+ stats.apiRequests++;
343
+ break;
344
+ case 'AI_RESPONSE':
345
+ stats.aiResponses++;
346
+ break;
347
+ case 'TOOL_START':
348
+ stats.toolCalls++;
349
+ break;
350
+ case 'TOOL_ERROR':
351
+ case 'API_ERROR':
352
+ case 'PROMPT_FAILED':
353
+ case 'ERROR':
354
+ stats.errors++;
355
+ break;
356
+ }
357
+ }
358
+ // ═══════════════════════════════════════════════════════════════════════════════
359
+ // ENTRY POINT
360
+ // ═══════════════════════════════════════════════════════════════════════════════
361
+ async function main() {
362
+ const args = process.argv.slice(2);
363
+ if (args.includes('help') || args.includes('-h') || args.includes('--help')) {
364
+ displayHelp();
365
+ return;
366
+ }
367
+ if (args.includes('list') || args.includes('-l')) {
368
+ displaySessions();
369
+ return;
370
+ }
371
+ const verbose = args.includes('-v') || args.includes('--verbose');
372
+ await watchLogs(verbose);
373
+ }
374
+ main().catch(console.error);
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.z = void 0;
4
+ const zod_1 = require("zod");
5
+ Object.defineProperty(exports, "z", { enumerable: true, get: function () { return zod_1.z; } });
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "prab-cli",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered coding assistant for your terminal. Built with Groq's lightning-fast LLMs, featuring autonomous tool execution, syntax-highlighted output, and git integration.",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "prab-cli": "./dist/index.js",
8
+ "groq-cli": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "dev": "ts-node src/index.ts",
14
+ "dev:watch": "nodemon --exec ts-node src/index.ts",
15
+ "log": "ts-node src/log-viewer.ts",
16
+ "log:list": "ts-node src/log-viewer.ts list",
17
+ "log:help": "ts-node src/log-viewer.ts help",
18
+ "prepublishOnly": "npm run build",
19
+ "test": "echo \"Error: no test specified\" && exit 1"
20
+ },
21
+ "keywords": [
22
+ "cli",
23
+ "ai",
24
+ "groq",
25
+ "llm",
26
+ "coding-assistant",
27
+ "terminal",
28
+ "developer-tools",
29
+ "git",
30
+ "code-generation",
31
+ "langchain"
32
+ ],
33
+ "author": "Prabhanjan Sharma",
34
+ "license": "ISC",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/prab002/prab-cli.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/prab002/prab-cli/issues"
41
+ },
42
+ "homepage": "https://github.com/prab002/prab-cli#readme",
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "README.md",
49
+ "LICENSE"
50
+ ],
51
+ "dependencies": {
52
+ "@langchain/core": "^1.1.11",
53
+ "@langchain/groq": "^1.0.2",
54
+ "@langchain/openai": "^1.2.2",
55
+ "chalk": "^5.6.2",
56
+ "commander": "^14.0.2",
57
+ "diff": "^8.0.2",
58
+ "dotenv": "^17.2.3",
59
+ "glob": "^13.0.0",
60
+ "groq-sdk": "^0.37.0",
61
+ "inquirer": "^13.1.0",
62
+ "ora": "^9.0.0",
63
+ "simple-git": "^3.30.0",
64
+ "zod": "^4.3.5"
65
+ },
66
+ "devDependencies": {
67
+ "@types/diff": "^7.0.2",
68
+ "@types/glob": "^8.1.0",
69
+ "@types/inquirer": "^9.0.9",
70
+ "@types/node": "^25.0.3",
71
+ "nodemon": "^3.1.11",
72
+ "ts-node": "^10.9.2",
73
+ "typescript": "^5.9.3"
74
+ }
75
+ }