prab-cli 1.1.0 → 1.2.1

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.
package/dist/lib/ui.js CHANGED
@@ -6,6 +6,64 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.StreamFormatter = exports.formatMarkdown = exports.showToolProgress = exports.showTodoList = exports.showDiff = exports.banner = exports.log = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
8
  const diff_1 = require("diff");
9
+ // Simple ASCII art letters for custom banners
10
+ const ASCII_LETTERS = {
11
+ A: [" █ ", " █ █ ", "█████", "█ █", "█ █"],
12
+ B: ["████ ", "█ █", "████ ", "█ █", "████ "],
13
+ C: [" ████", "█ ", "█ ", "█ ", " ████"],
14
+ D: ["████ ", "█ █", "█ █", "█ █", "████ "],
15
+ E: ["█████", "█ ", "████ ", "█ ", "█████"],
16
+ F: ["█████", "█ ", "████ ", "█ ", "█ "],
17
+ G: [" ████", "█ ", "█ ██", "█ █", " ████"],
18
+ H: ["█ █", "█ █", "█████", "█ █", "█ █"],
19
+ I: ["█████", " █ ", " █ ", " █ ", "█████"],
20
+ J: ["█████", " █ ", " █ ", "█ █ ", " ██ "],
21
+ K: ["█ █", "█ █ ", "███ ", "█ █ ", "█ █"],
22
+ L: ["█ ", "█ ", "█ ", "█ ", "█████"],
23
+ M: ["█ █", "██ ██", "█ █ █", "█ █", "█ █"],
24
+ N: ["█ █", "██ █", "█ █ █", "█ ██", "█ █"],
25
+ O: [" ███ ", "█ █", "█ █", "█ █", " ███ "],
26
+ P: ["████ ", "█ █", "████ ", "█ ", "█ "],
27
+ Q: [" ███ ", "█ █", "█ █ █", "█ █ ", " ██ █"],
28
+ R: ["████ ", "█ █", "████ ", "█ █ ", "█ █"],
29
+ S: [" ████", "█ ", " ███ ", " █", "████ "],
30
+ T: ["█████", " █ ", " █ ", " █ ", " █ "],
31
+ U: ["█ █", "█ █", "█ █", "█ █", " ███ "],
32
+ V: ["█ █", "█ █", "█ █", " █ █ ", " █ "],
33
+ W: ["█ █", "█ █", "█ █ █", "██ ██", "█ █"],
34
+ X: ["█ █", " █ █ ", " █ ", " █ █ ", "█ █"],
35
+ Y: ["█ █", " █ █ ", " █ ", " █ ", " █ "],
36
+ Z: ["█████", " █ ", " █ ", " █ ", "█████"],
37
+ " ": [" ", " ", " ", " ", " "],
38
+ "-": [" ", " ", "█████", " ", " "],
39
+ _: [" ", " ", " ", " ", "█████"],
40
+ ".": [" ", " ", " ", " ", " █ "],
41
+ "!": [" █ ", " █ ", " █ ", " ", " █ "],
42
+ "0": [" ███ ", "█ █", "█ █", "█ █", " ███ "],
43
+ "1": [" █ ", " ██ ", " █ ", " █ ", " ███ "],
44
+ "2": [" ███ ", "█ █", " ██ ", " █ ", "█████"],
45
+ "3": ["████ ", " █", " ███ ", " █", "████ "],
46
+ "4": ["█ █", "█ █", "█████", " █", " █"],
47
+ "5": ["█████", "█ ", "████ ", " █", "████ "],
48
+ "6": [" ███ ", "█ ", "████ ", "█ █", " ███ "],
49
+ "7": ["█████", " █", " █ ", " █ ", " █ "],
50
+ "8": [" ███ ", "█ █", " ███ ", "█ █", " ███ "],
51
+ "9": [" ███ ", "█ █", " ████", " █", " ███ "],
52
+ };
53
+ /**
54
+ * Generate ASCII art banner from text
55
+ */
56
+ const generateAsciiBanner = (text) => {
57
+ const upperText = text.toUpperCase();
58
+ const lines = ["", "", "", "", ""];
59
+ for (const char of upperText) {
60
+ const letterArt = ASCII_LETTERS[char] || ASCII_LETTERS[" "];
61
+ for (let i = 0; i < 5; i++) {
62
+ lines[i] += letterArt[i] + " ";
63
+ }
64
+ }
65
+ return lines.join("\n");
66
+ };
9
67
  // Syntax highlighting color schemes for different languages
10
68
  const syntaxColors = {
11
69
  keyword: chalk_1.default.magenta,
@@ -21,33 +79,147 @@ const syntaxColors = {
21
79
  // Common keywords for different languages
22
80
  const keywords = new Set([
23
81
  // JavaScript/TypeScript
24
- 'const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while', 'do',
25
- 'switch', 'case', 'break', 'continue', 'try', 'catch', 'finally', 'throw',
26
- 'class', 'extends', 'new', 'this', 'super', 'import', 'export', 'from', 'as',
27
- 'default', 'async', 'await', 'yield', 'typeof', 'instanceof', 'in', 'of',
28
- 'true', 'false', 'null', 'undefined', 'void', 'delete', 'static', 'get', 'set',
29
- 'interface', 'type', 'enum', 'implements', 'private', 'public', 'protected',
82
+ "const",
83
+ "let",
84
+ "var",
85
+ "function",
86
+ "return",
87
+ "if",
88
+ "else",
89
+ "for",
90
+ "while",
91
+ "do",
92
+ "switch",
93
+ "case",
94
+ "break",
95
+ "continue",
96
+ "try",
97
+ "catch",
98
+ "finally",
99
+ "throw",
100
+ "class",
101
+ "extends",
102
+ "new",
103
+ "this",
104
+ "super",
105
+ "import",
106
+ "export",
107
+ "from",
108
+ "as",
109
+ "default",
110
+ "async",
111
+ "await",
112
+ "yield",
113
+ "typeof",
114
+ "instanceof",
115
+ "in",
116
+ "of",
117
+ "true",
118
+ "false",
119
+ "null",
120
+ "undefined",
121
+ "void",
122
+ "delete",
123
+ "static",
124
+ "get",
125
+ "set",
126
+ "interface",
127
+ "type",
128
+ "enum",
129
+ "implements",
130
+ "private",
131
+ "public",
132
+ "protected",
30
133
  // Python
31
- 'def', 'class', 'import', 'from', 'as', 'if', 'elif', 'else', 'for', 'while',
32
- 'try', 'except', 'finally', 'raise', 'with', 'lambda', 'return', 'yield',
33
- 'True', 'False', 'None', 'and', 'or', 'not', 'is', 'in', 'pass', 'global',
34
- 'nonlocal', 'assert', 'break', 'continue', 'self', 'async', 'await',
134
+ "def",
135
+ "class",
136
+ "import",
137
+ "from",
138
+ "as",
139
+ "if",
140
+ "elif",
141
+ "else",
142
+ "for",
143
+ "while",
144
+ "try",
145
+ "except",
146
+ "finally",
147
+ "raise",
148
+ "with",
149
+ "lambda",
150
+ "return",
151
+ "yield",
152
+ "True",
153
+ "False",
154
+ "None",
155
+ "and",
156
+ "or",
157
+ "not",
158
+ "is",
159
+ "in",
160
+ "pass",
161
+ "global",
162
+ "nonlocal",
163
+ "assert",
164
+ "break",
165
+ "continue",
166
+ "self",
167
+ "async",
168
+ "await",
35
169
  // Go
36
- 'func', 'package', 'import', 'type', 'struct', 'interface', 'map', 'chan',
37
- 'go', 'defer', 'select', 'range', 'make', 'append', 'len', 'cap', 'nil',
170
+ "func",
171
+ "package",
172
+ "import",
173
+ "type",
174
+ "struct",
175
+ "interface",
176
+ "map",
177
+ "chan",
178
+ "go",
179
+ "defer",
180
+ "select",
181
+ "range",
182
+ "make",
183
+ "append",
184
+ "len",
185
+ "cap",
186
+ "nil",
38
187
  // Rust
39
- 'fn', 'let', 'mut', 'pub', 'mod', 'use', 'struct', 'enum', 'impl', 'trait',
40
- 'match', 'loop', 'move', 'ref', 'self', 'Self', 'where', 'unsafe', 'async',
188
+ "fn",
189
+ "let",
190
+ "mut",
191
+ "pub",
192
+ "mod",
193
+ "use",
194
+ "struct",
195
+ "enum",
196
+ "impl",
197
+ "trait",
198
+ "match",
199
+ "loop",
200
+ "move",
201
+ "ref",
202
+ "self",
203
+ "Self",
204
+ "where",
205
+ "unsafe",
206
+ "async",
41
207
  // Common
42
- 'print', 'println', 'printf', 'console', 'log', 'error', 'warn',
208
+ "print",
209
+ "println",
210
+ "printf",
211
+ "console",
212
+ "log",
213
+ "error",
214
+ "warn",
43
215
  ]);
44
216
  /**
45
217
  * Truncate output for brief display
46
218
  */
47
219
  const truncateOutput = (text, maxLen) => {
48
- const firstLine = text.split('\n')[0];
220
+ const firstLine = text.split("\n")[0];
49
221
  if (firstLine.length > maxLen) {
50
- return firstLine.substring(0, maxLen) + '...';
222
+ return firstLine.substring(0, maxLen) + "...";
51
223
  }
52
224
  return firstLine;
53
225
  };
@@ -55,97 +227,102 @@ const truncateOutput = (text, maxLen) => {
55
227
  * Format diff output with colors
56
228
  */
57
229
  const formatDiffOutput = (output) => {
58
- const lines = output.split('\n');
59
- return lines.map(line => {
230
+ const lines = output.split("\n");
231
+ return lines
232
+ .map((line) => {
60
233
  // File headers
61
- if (line.startsWith('diff --git')) {
234
+ if (line.startsWith("diff --git")) {
62
235
  return chalk_1.default.bold.white(line);
63
236
  }
64
- if (line.startsWith('index ')) {
237
+ if (line.startsWith("index ")) {
65
238
  return chalk_1.default.gray(line);
66
239
  }
67
- if (line.startsWith('---')) {
240
+ if (line.startsWith("---")) {
68
241
  return chalk_1.default.red.bold(line);
69
242
  }
70
- if (line.startsWith('+++')) {
243
+ if (line.startsWith("+++")) {
71
244
  return chalk_1.default.green.bold(line);
72
245
  }
73
246
  // Hunk headers
74
- if (line.startsWith('@@')) {
247
+ if (line.startsWith("@@")) {
75
248
  return chalk_1.default.cyan(line);
76
249
  }
77
250
  // Added lines
78
- if (line.startsWith('+')) {
251
+ if (line.startsWith("+")) {
79
252
  return chalk_1.default.green(line);
80
253
  }
81
254
  // Removed lines
82
- if (line.startsWith('-')) {
255
+ if (line.startsWith("-")) {
83
256
  return chalk_1.default.red(line);
84
257
  }
85
258
  // Context lines
86
259
  return chalk_1.default.gray(line);
87
- }).join('\n');
260
+ })
261
+ .join("\n");
88
262
  };
89
263
  /**
90
264
  * Format git log output with colors
91
265
  */
92
266
  const formatGitLogOutput = (output) => {
93
- const lines = output.split('\n');
94
- return lines.map(line => {
267
+ const lines = output.split("\n");
268
+ return lines
269
+ .map((line) => {
95
270
  // Commit hash
96
271
  if (line.match(/^[a-f0-9]{7,40}\s/)) {
97
- const parts = line.split(' ');
272
+ const parts = line.split(" ");
98
273
  const hash = parts[0];
99
- const rest = parts.slice(1).join(' ');
100
- return chalk_1.default.yellow(hash) + ' ' + rest;
274
+ const rest = parts.slice(1).join(" ");
275
+ return chalk_1.default.yellow(hash) + " " + rest;
101
276
  }
102
277
  // Date lines
103
278
  if (line.match(/^\d{4}-\d{2}-\d{2}/)) {
104
279
  return chalk_1.default.blue(line);
105
280
  }
106
281
  // Author
107
- if (line.toLowerCase().includes('author:')) {
282
+ if (line.toLowerCase().includes("author:")) {
108
283
  return chalk_1.default.cyan(line);
109
284
  }
110
285
  // Commit message (indented)
111
- if (line.startsWith(' ')) {
286
+ if (line.startsWith(" ")) {
112
287
  return chalk_1.default.white(line);
113
288
  }
114
289
  return line;
115
- }).join('\n');
290
+ })
291
+ .join("\n");
116
292
  };
117
293
  /**
118
294
  * Format git status output with colors
119
295
  */
120
296
  const formatGitStatusOutput = (output) => {
121
- const lines = output.split('\n');
122
- return lines.map(line => {
297
+ const lines = output.split("\n");
298
+ return lines
299
+ .map((line) => {
123
300
  // Branch info
124
- if (line.startsWith('On branch') || line.startsWith('HEAD detached')) {
301
+ if (line.startsWith("On branch") || line.startsWith("HEAD detached")) {
125
302
  return chalk_1.default.cyan.bold(line);
126
303
  }
127
304
  // Modified files
128
- if (line.includes('modified:')) {
305
+ if (line.includes("modified:")) {
129
306
  return chalk_1.default.yellow(line);
130
307
  }
131
308
  // New files
132
- if (line.includes('new file:')) {
309
+ if (line.includes("new file:")) {
133
310
  return chalk_1.default.green(line);
134
311
  }
135
312
  // Deleted files
136
- if (line.includes('deleted:')) {
313
+ if (line.includes("deleted:")) {
137
314
  return chalk_1.default.red(line);
138
315
  }
139
316
  // Untracked files header
140
- if (line.includes('Untracked files:')) {
317
+ if (line.includes("Untracked files:")) {
141
318
  return chalk_1.default.magenta.bold(line);
142
319
  }
143
320
  // Staged changes header
144
- if (line.includes('Changes to be committed:')) {
321
+ if (line.includes("Changes to be committed:")) {
145
322
  return chalk_1.default.green.bold(line);
146
323
  }
147
324
  // Unstaged changes header
148
- if (line.includes('Changes not staged')) {
325
+ if (line.includes("Changes not staged")) {
149
326
  return chalk_1.default.yellow.bold(line);
150
327
  }
151
328
  // File status indicators (M, A, D, ??)
@@ -155,19 +332,20 @@ const formatGitStatusOutput = (output) => {
155
332
  const indicator = status[1];
156
333
  const filename = status[2];
157
334
  let color = chalk_1.default.white;
158
- if (indicator.includes('M'))
335
+ if (indicator.includes("M"))
159
336
  color = chalk_1.default.yellow;
160
- if (indicator.includes('A'))
337
+ if (indicator.includes("A"))
161
338
  color = chalk_1.default.green;
162
- if (indicator.includes('D'))
339
+ if (indicator.includes("D"))
163
340
  color = chalk_1.default.red;
164
- if (indicator.includes('?'))
341
+ if (indicator.includes("?"))
165
342
  color = chalk_1.default.gray;
166
343
  return color(` ${indicator} ${filename}`);
167
344
  }
168
345
  }
169
346
  return chalk_1.default.gray(line);
170
- }).join('\n');
347
+ })
348
+ .join("\n");
171
349
  };
172
350
  /**
173
351
  * Apply syntax highlighting to a line of code
@@ -200,21 +378,24 @@ const highlightCodeLine = (line) => {
200
378
  /**
201
379
  * Format file content with line numbers and syntax highlighting
202
380
  */
203
- const formatFileContent = (content, filename) => {
204
- const lines = content.split('\n');
381
+ const formatFileContent = (content, _filename) => {
382
+ const lines = content.split("\n");
205
383
  const lineNumWidth = String(lines.length).length;
206
- return lines.map((line, idx) => {
207
- const lineNum = String(idx + 1).padStart(lineNumWidth, ' ');
384
+ return lines
385
+ .map((line, idx) => {
386
+ const lineNum = String(idx + 1).padStart(lineNumWidth, " ");
208
387
  const highlighted = highlightCodeLine(line);
209
388
  return chalk_1.default.gray(`${lineNum} │ `) + highlighted;
210
- }).join('\n');
389
+ })
390
+ .join("\n");
211
391
  };
212
392
  /**
213
393
  * Format bash command output
214
394
  */
215
395
  const formatBashOutput = (output) => {
216
396
  // Check if it looks like a diff
217
- if (output.includes('diff --git') || output.includes('@@') && (output.includes('+') || output.includes('-'))) {
397
+ if (output.includes("diff --git") ||
398
+ (output.includes("@@") && (output.includes("+") || output.includes("-")))) {
218
399
  return formatDiffOutput(output);
219
400
  }
220
401
  // Check if it looks like git log
@@ -222,18 +403,21 @@ const formatBashOutput = (output) => {
222
403
  return formatGitLogOutput(output);
223
404
  }
224
405
  // Generic output with some highlighting
225
- const lines = output.split('\n');
226
- return lines.map(line => {
406
+ const lines = output.split("\n");
407
+ return lines
408
+ .map((line) => {
227
409
  // Error messages
228
- if (line.toLowerCase().includes('error') || line.toLowerCase().includes('failed')) {
410
+ if (line.toLowerCase().includes("error") || line.toLowerCase().includes("failed")) {
229
411
  return chalk_1.default.red(line);
230
412
  }
231
413
  // Warning messages
232
- if (line.toLowerCase().includes('warning') || line.toLowerCase().includes('warn')) {
414
+ if (line.toLowerCase().includes("warning") || line.toLowerCase().includes("warn")) {
233
415
  return chalk_1.default.yellow(line);
234
416
  }
235
417
  // Success messages
236
- if (line.toLowerCase().includes('success') || line.toLowerCase().includes('done') || line.toLowerCase().includes('passed')) {
418
+ if (line.toLowerCase().includes("success") ||
419
+ line.toLowerCase().includes("done") ||
420
+ line.toLowerCase().includes("passed")) {
237
421
  return chalk_1.default.green(line);
238
422
  }
239
423
  // Paths
@@ -241,53 +425,56 @@ const formatBashOutput = (output) => {
241
425
  return chalk_1.default.cyan(line);
242
426
  }
243
427
  return line;
244
- }).join('\n');
428
+ })
429
+ .join("\n");
245
430
  };
246
431
  /**
247
432
  * Format tool output based on tool type
248
433
  */
249
434
  const formatToolOutput = (toolName, output) => {
250
- if (!output || output.trim() === '') {
251
- return chalk_1.default.gray(' (no output)');
435
+ if (!output || output.trim() === "") {
436
+ return chalk_1.default.gray(" (no output)");
252
437
  }
253
- const separator = chalk_1.default.gray('─'.repeat(60));
254
438
  let formatted;
255
439
  switch (toolName.toLowerCase()) {
256
- case 'git_diff':
257
- case 'gitdiff':
440
+ case "git_diff":
441
+ case "gitdiff":
258
442
  formatted = formatDiffOutput(output);
259
443
  break;
260
- case 'git_log':
261
- case 'gitlog':
444
+ case "git_log":
445
+ case "gitlog":
262
446
  formatted = formatGitLogOutput(output);
263
447
  break;
264
- case 'git_status':
265
- case 'gitstatus':
448
+ case "git_status":
449
+ case "gitstatus":
266
450
  formatted = formatGitStatusOutput(output);
267
451
  break;
268
- case 'read_file':
269
- case 'readfile':
452
+ case "read_file":
453
+ case "readfile":
270
454
  formatted = formatFileContent(output);
271
455
  break;
272
- case 'bash':
273
- case 'shell':
456
+ case "bash":
457
+ case "shell":
274
458
  formatted = formatBashOutput(output);
275
459
  break;
276
- case 'glob':
277
- case 'grep':
460
+ case "glob":
461
+ case "grep":
278
462
  // File lists - highlight paths
279
- formatted = output.split('\n').map(line => {
280
- if (line.includes(':')) {
281
- const [path, ...rest] = line.split(':');
282
- return chalk_1.default.cyan(path) + ':' + chalk_1.default.white(rest.join(':'));
463
+ formatted = output
464
+ .split("\n")
465
+ .map((line) => {
466
+ if (line.includes(":")) {
467
+ const [path, ...rest] = line.split(":");
468
+ return chalk_1.default.cyan(path) + ":" + chalk_1.default.white(rest.join(":"));
283
469
  }
284
470
  return chalk_1.default.cyan(line);
285
- }).join('\n');
471
+ })
472
+ .join("\n");
286
473
  break;
287
474
  default:
288
475
  formatted = output;
289
476
  }
290
- return `\n${chalk_1.default.gray('Output:')}\n${formatted}`;
477
+ return `\n${chalk_1.default.gray("Output:")}\n${formatted}`;
291
478
  };
292
479
  exports.log = {
293
480
  info: (msg) => console.log(chalk_1.default.blue("ℹ"), msg),
@@ -313,14 +500,18 @@ exports.log = {
313
500
  console.log(formatted);
314
501
  },
315
502
  };
316
- const banner = (modelName, toolCount) => {
317
- console.log(chalk_1.default.bold.cyan(`
318
- ____ __ ________ ____
319
- / __ \\_________ _/ /_ / ____/ / / _/
320
- / /_/ / ___/ __ \`/ __ \\ / / / / / /
321
- / ____/ / / /_/ / /_/ / / /___/ /____/ /
322
- /_/ /_/ \\__,_/_.___/ \\____/_____/___/
323
- `));
503
+ const banner = (modelName, toolCount, customization) => {
504
+ const cliName = customization?.cliName || "Prab CLI";
505
+ const userName = customization?.userName;
506
+ const theme = customization?.theme || "default";
507
+ // Choose color based on theme
508
+ const titleColor = theme === "colorful" ? chalk_1.default.bold.magenta : theme === "minimal" ? chalk_1.default.white : chalk_1.default.bold.cyan;
509
+ // Generate ASCII art for the CLI name
510
+ const asciiBanner = generateAsciiBanner(cliName);
511
+ console.log(titleColor("\n" + asciiBanner));
512
+ if (userName) {
513
+ console.log(chalk_1.default.gray(` Welcome, ${chalk_1.default.cyan(userName)}!`));
514
+ }
324
515
  if (modelName) {
325
516
  console.log(chalk_1.default.gray(` Active Model: ${chalk_1.default.cyan(modelName)}`));
326
517
  }
@@ -339,11 +530,7 @@ const showDiff = (before, after, filename) => {
339
530
  }
340
531
  const diff = (0, diff_1.diffLines)(before, after);
341
532
  diff.forEach((part) => {
342
- const color = part.added
343
- ? chalk_1.default.green
344
- : part.removed
345
- ? chalk_1.default.red
346
- : chalk_1.default.gray;
533
+ const color = part.added ? chalk_1.default.green : part.removed ? chalk_1.default.red : chalk_1.default.gray;
347
534
  const prefix = part.added ? "+ " : part.removed ? "- " : " ";
348
535
  const lines = part.value.split("\n");
349
536
  lines.forEach((line) => {
@@ -364,7 +551,7 @@ const showTodoList = (todos) => {
364
551
  return;
365
552
  }
366
553
  console.log(chalk_1.default.bold("\n📋 Todo List:"));
367
- todos.forEach((todo, index) => {
554
+ todos.forEach((todo, _index) => {
368
555
  const status = todo.status === "completed"
369
556
  ? chalk_1.default.green("✓")
370
557
  : todo.status === "in_progress"
@@ -386,11 +573,7 @@ exports.showTodoList = showTodoList;
386
573
  */
387
574
  const showToolProgress = (toolName, status) => {
388
575
  const icon = status === "started" ? "⏳" : status === "completed" ? "✓" : "✗";
389
- const color = status === "started"
390
- ? chalk_1.default.yellow
391
- : status === "completed"
392
- ? chalk_1.default.green
393
- : chalk_1.default.red;
576
+ const color = status === "started" ? chalk_1.default.yellow : status === "completed" ? chalk_1.default.green : chalk_1.default.red;
394
577
  console.log(color(`${icon} ${toolName} ${status}`));
395
578
  };
396
579
  exports.showToolProgress = showToolProgress;
@@ -402,19 +585,16 @@ const formatCodeBlock = (code, language) => {
402
585
  const maxLineLen = Math.max(...lines.map((l) => l.length), 40);
403
586
  const boxWidth = Math.min(maxLineLen + 4, 80);
404
587
  const langLabel = language ? chalk_1.default.cyan.bold(` ${language} `) : "";
405
- const topBorder = chalk_1.default.gray("╭") + langLabel + chalk_1.default.gray("─".repeat(Math.max(0, boxWidth - language.length - 3))) + chalk_1.default.gray("╮");
588
+ const topBorder = chalk_1.default.gray("╭") +
589
+ langLabel +
590
+ chalk_1.default.gray("─".repeat(Math.max(0, boxWidth - language.length - 3))) +
591
+ chalk_1.default.gray("╮");
406
592
  const bottomBorder = chalk_1.default.gray("╰" + "─".repeat(boxWidth - 1) + "╯");
407
593
  const formattedLines = lines.map((line) => {
408
594
  const highlighted = highlightCodeLine(line);
409
595
  return chalk_1.default.gray("│ ") + highlighted;
410
596
  });
411
- return [
412
- "",
413
- topBorder,
414
- ...formattedLines,
415
- bottomBorder,
416
- "",
417
- ].join("\n");
597
+ return ["", topBorder, ...formattedLines, bottomBorder, ""].join("\n");
418
598
  };
419
599
  /**
420
600
  * Format markdown text with colors for terminal display
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prab-cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
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
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -15,8 +15,21 @@
15
15
  "log": "ts-node src/log-viewer.ts",
16
16
  "log:list": "ts-node src/log-viewer.ts list",
17
17
  "log:help": "ts-node src/log-viewer.ts help",
18
- "prepublishOnly": "npm run build",
19
- "test": "echo \"Error: no test specified\" && exit 1"
18
+ "lint": "eslint src/**/*.ts",
19
+ "lint:fix": "eslint src/**/*.ts --fix",
20
+ "format": "prettier --write src/**/*.ts",
21
+ "format:check": "prettier --check src/**/*.ts",
22
+ "typecheck": "tsc --noEmit",
23
+ "validate": "npm run lint && npm run typecheck && npm run build",
24
+ "prepublishOnly": "npm run validate",
25
+ "test": "npm run validate",
26
+ "prepare": "husky"
27
+ },
28
+ "lint-staged": {
29
+ "src/**/*.ts": [
30
+ "eslint --fix",
31
+ "prettier --write"
32
+ ]
20
33
  },
21
34
  "keywords": [
22
35
  "cli",
@@ -66,11 +79,20 @@
66
79
  "zod": "^4.3.5"
67
80
  },
68
81
  "devDependencies": {
82
+ "@eslint/js": "^9.39.2",
69
83
  "@types/diff": "^7.0.2",
70
84
  "@types/glob": "^8.1.0",
71
85
  "@types/inquirer": "^9.0.9",
72
86
  "@types/node": "^25.0.3",
87
+ "@typescript-eslint/eslint-plugin": "^8.53.1",
88
+ "@typescript-eslint/parser": "^8.53.1",
89
+ "eslint": "^9.39.2",
90
+ "eslint-config-prettier": "^10.1.8",
91
+ "eslint-plugin-prettier": "^5.5.5",
92
+ "husky": "^9.1.7",
93
+ "lint-staged": "^16.2.7",
73
94
  "nodemon": "^3.1.11",
95
+ "prettier": "^3.8.0",
74
96
  "ts-node": "^10.9.2",
75
97
  "typescript": "^5.9.3"
76
98
  }