@bobsworkshop/cli 0.1.5 → 0.2.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.
- package/README.md +10 -10
- package/dist/{analyse-auto-OBCDWYWX.js → analyse-auto-HYYDD4OQ.js} +1 -1
- package/dist/{bin/analyse-results-5XEQNL5W.js → analyse-results-7TS24WG7.js} +1 -1
- package/dist/bob.js +3612 -941
- package/dist/{bin/chunk-KDCVG7F2.js → chunk-CI36GGK2.js} +124 -88
- package/package.json +3 -1
- package/dist/analyse-results-QSOD3KVC.js +0 -8
- package/dist/bin/analyse-auto-6T42LV3G.js +0 -529
- package/dist/bin/analyse-auto-BHLEMIH5.js +0 -529
- package/dist/bin/analyse-auto-CM7XEPKT.js +0 -529
- package/dist/bin/analyse-auto-KZNPVVCR.js +0 -529
- package/dist/bin/analyse-auto-OBCDWYWX.js +0 -529
- package/dist/bin/analyse-auto-QUGN5LES.js +0 -529
- package/dist/bin/analyse-auto-RDYNFTCD.js +0 -529
- package/dist/bin/analyse-auto-Y5QUQU4G.js +0 -529
- package/dist/bin/analyse-results-F7TH2YMO.js +0 -8
- package/dist/bin/analyse-results-KM5C7XL7.js +0 -8
- package/dist/bin/analyse-results-KU3KEG3E.js +0 -8
- package/dist/bin/analyse-results-OU6F6TRX.js +0 -8
- package/dist/bin/analyse-results-QSOD3KVC.js +0 -8
- package/dist/bin/analyse-results-UHU4DPO3.js +0 -8
- package/dist/bin/analyse-results-ZM5ABNEL.js +0 -8
- package/dist/bin/bob.js +0 -5144
- package/dist/bin/chunk-IYYF7MYV.js +0 -964
- package/dist/bin/chunk-J4RRWEHU.js +0 -939
- package/dist/bin/chunk-KSHHT2WT.js +0 -939
- package/dist/bin/chunk-L554PTBY.js +0 -888
- package/dist/bin/chunk-LHWBSCJ4.js +0 -878
- package/dist/bin/chunk-RSOPJT6F.js +0 -883
- package/dist/bin/chunk-TXCQFX4W.js +0 -946
- package/dist/chunk-LHWBSCJ4.js +0 -878
|
@@ -304,16 +304,26 @@ async function callLocalModel(endpoint, messages) {
|
|
|
304
304
|
}
|
|
305
305
|
);
|
|
306
306
|
if (response.data?.message?.content) {
|
|
307
|
-
return
|
|
307
|
+
return {
|
|
308
|
+
text: response.data.message.content,
|
|
309
|
+
evalCount: response.data.eval_count || void 0,
|
|
310
|
+
promptEvalCount: response.data.prompt_eval_count || void 0,
|
|
311
|
+
evalDurationMs: response.data.eval_duration ? Math.round(response.data.eval_duration / 1e6) : void 0,
|
|
312
|
+
totalDurationMs: response.data.total_duration ? Math.round(response.data.total_duration / 1e6) : void 0
|
|
313
|
+
};
|
|
308
314
|
}
|
|
309
315
|
const choice = response.data?.choices?.[0];
|
|
310
316
|
if (choice?.message?.content) {
|
|
311
|
-
return
|
|
317
|
+
return {
|
|
318
|
+
text: choice.message.content,
|
|
319
|
+
evalCount: response.data.usage?.completion_tokens || void 0,
|
|
320
|
+
promptEvalCount: response.data.usage?.prompt_tokens || void 0
|
|
321
|
+
};
|
|
312
322
|
}
|
|
313
323
|
if (typeof response.data?.response === "string") {
|
|
314
|
-
return response.data.response;
|
|
324
|
+
return { text: response.data.response };
|
|
315
325
|
}
|
|
316
|
-
return "No response received from local model.";
|
|
326
|
+
return { text: "No response received from local model." };
|
|
317
327
|
} catch (error) {
|
|
318
328
|
if (error.code === "ECONNREFUSED") {
|
|
319
329
|
throw new Error("Cannot connect to local model. Is Ollama running? Check your endpoint: " + endpoint);
|
|
@@ -369,6 +379,13 @@ import * as fs2 from "fs";
|
|
|
369
379
|
import * as path2 from "path";
|
|
370
380
|
import * as readline2 from "readline";
|
|
371
381
|
import chalk2 from "chalk";
|
|
382
|
+
var SUCCESS = chalk2.hex("#66BB6A");
|
|
383
|
+
var INFO = chalk2.hex("#26C6DA");
|
|
384
|
+
var WARNING = chalk2.hex("#FFC107");
|
|
385
|
+
var ERROR = chalk2.hex("#EF5350");
|
|
386
|
+
var MUTED = chalk2.hex("#78909C");
|
|
387
|
+
var BRAND_SECONDARY = chalk2.hex("#FFAB00");
|
|
388
|
+
var BORDER = chalk2.hex("#455A64");
|
|
372
389
|
function extractAllProposedFiles(response) {
|
|
373
390
|
const proposals = [];
|
|
374
391
|
const codeBlockRegex = /```[\w]*\n([\s\S]*?)```/g;
|
|
@@ -433,19 +450,19 @@ async function processAllProposedFiles(response, autoApprove = false, existingRl
|
|
|
433
450
|
function displayExternalFile(proposed) {
|
|
434
451
|
const totalLines = proposed.content.split("\n").length;
|
|
435
452
|
console.log("");
|
|
436
|
-
console.log(
|
|
437
|
-
console.log(
|
|
438
|
-
console.log(
|
|
439
|
-
console.log(
|
|
453
|
+
console.log(WARNING(` \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`));
|
|
454
|
+
console.log(WARNING(` \u2551`) + BRAND_SECONDARY(` \u{1F4CB} EXTERNAL: ${proposed.filePath}`));
|
|
455
|
+
console.log(WARNING(` \u2551`) + MUTED(` This file belongs to another project.`));
|
|
456
|
+
console.log(WARNING(` \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`));
|
|
440
457
|
const previewLines = proposed.content.split("\n").slice(0, 6);
|
|
441
458
|
for (const line of previewLines) {
|
|
442
|
-
console.log(
|
|
459
|
+
console.log(WARNING(` \u2551`) + MUTED(` ${line}`));
|
|
443
460
|
}
|
|
444
461
|
if (totalLines > 6) {
|
|
445
|
-
console.log(
|
|
462
|
+
console.log(WARNING(` \u2551`) + MUTED(` ... (${totalLines - 6} more lines)`));
|
|
446
463
|
}
|
|
447
|
-
console.log(
|
|
448
|
-
console.log(
|
|
464
|
+
console.log(WARNING(` \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`));
|
|
465
|
+
console.log(MUTED(` Copy this file manually to your project at: ${proposed.filePath}`));
|
|
449
466
|
console.log("");
|
|
450
467
|
}
|
|
451
468
|
async function proposeAndWriteFile(proposed, autoApprove = false, existingRl) {
|
|
@@ -456,37 +473,43 @@ async function proposeAndWriteFile(proposed, autoApprove = false, existingRl) {
|
|
|
456
473
|
const absolutePath = path2.join(process.cwd(), proposed.filePath);
|
|
457
474
|
const action = proposed.isNew ? "CREATE" : "UPDATE";
|
|
458
475
|
const icon = proposed.isNew ? "\u{1F4C4}" : "\u270F\uFE0F";
|
|
459
|
-
const
|
|
476
|
+
const accentColor = proposed.isNew ? SUCCESS : BRAND_SECONDARY;
|
|
460
477
|
const totalLines = proposed.content.split("\n").length;
|
|
461
478
|
if (!autoApprove) {
|
|
462
479
|
console.log("");
|
|
463
|
-
console.log(
|
|
464
|
-
console.log(
|
|
465
|
-
console.log(
|
|
480
|
+
console.log(BORDER(` \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`));
|
|
481
|
+
console.log(BORDER(` \u2551`) + accentColor(` ${icon} ${action}: `) + chalk2.white(`${proposed.filePath}`) + MUTED(` (${totalLines} lines)`));
|
|
482
|
+
console.log(BORDER(` \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`));
|
|
466
483
|
const previewLines = proposed.content.split("\n").slice(0, 6);
|
|
467
484
|
for (const line of previewLines) {
|
|
468
|
-
console.log(
|
|
485
|
+
console.log(BORDER(` \u2551`) + MUTED(` ${line}`));
|
|
469
486
|
}
|
|
470
487
|
if (totalLines > 6) {
|
|
471
|
-
console.log(
|
|
488
|
+
console.log(BORDER(` \u2551`) + MUTED(` ... (${totalLines - 6} more lines)`));
|
|
472
489
|
}
|
|
473
|
-
console.log(
|
|
490
|
+
console.log(BORDER(` \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`));
|
|
474
491
|
console.log("");
|
|
492
|
+
const promptText = INFO(` \u{1F4BE} ${action === "CREATE" ? "Write this file" : "Apply changes"}? `) + MUTED(`(y/n/path): `);
|
|
475
493
|
let answer;
|
|
476
494
|
if (existingRl) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
495
|
+
existingRl.pause();
|
|
496
|
+
process.stdout.write(promptText);
|
|
497
|
+
const buf = Buffer.alloc(1024);
|
|
498
|
+
const bytesRead = fs2.readSync(0, buf, 0, 1024, null);
|
|
499
|
+
answer = buf.toString("utf-8", 0, bytesRead).replace(/\r?\n/, "").trim();
|
|
500
|
+
existingRl.resume();
|
|
480
501
|
} else {
|
|
481
502
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
482
503
|
answer = await new Promise((resolve3) => {
|
|
483
|
-
rl.question(
|
|
504
|
+
rl.question(promptText, (ans) => {
|
|
505
|
+
rl.close();
|
|
506
|
+
resolve3(ans);
|
|
507
|
+
});
|
|
484
508
|
});
|
|
485
|
-
rl.close();
|
|
486
509
|
}
|
|
487
510
|
const trimmed = answer.trim().toLowerCase();
|
|
488
511
|
if (trimmed === "n" || trimmed === "no") {
|
|
489
|
-
console.log(
|
|
512
|
+
console.log(MUTED(" \u23ED\uFE0F Skipped."));
|
|
490
513
|
return false;
|
|
491
514
|
}
|
|
492
515
|
if (trimmed !== "y" && trimmed !== "yes" && trimmed.length > 0) {
|
|
@@ -509,14 +532,14 @@ function writeFile(targetPath, content, originalFilePath, isNew) {
|
|
|
509
532
|
}
|
|
510
533
|
fs2.writeFileSync(targetPath, content, "utf-8");
|
|
511
534
|
const relativePath = path2.relative(process.cwd(), targetPath);
|
|
512
|
-
console.log(
|
|
535
|
+
console.log(SUCCESS(` \u2705 Written: ${relativePath}`));
|
|
513
536
|
if (!isNew) {
|
|
514
|
-
console.log(
|
|
537
|
+
console.log(MUTED(` \u{1F4E6} Backup saved to .bob-backups/`));
|
|
515
538
|
}
|
|
516
539
|
console.log("");
|
|
517
540
|
return true;
|
|
518
541
|
} catch (error) {
|
|
519
|
-
console.log(
|
|
542
|
+
console.log(ERROR(` \u274C Write failed: ${error.message}`));
|
|
520
543
|
return false;
|
|
521
544
|
}
|
|
522
545
|
}
|
|
@@ -608,13 +631,15 @@ function markSuggestionById(id, category, status, metadata) {
|
|
|
608
631
|
}
|
|
609
632
|
|
|
610
633
|
// src/commands/analyse-results.ts
|
|
611
|
-
var
|
|
612
|
-
var
|
|
613
|
-
var
|
|
614
|
-
var
|
|
615
|
-
var
|
|
616
|
-
var
|
|
617
|
-
var
|
|
634
|
+
var BRAND_PRIMARY = chalk3.hex("#E66F24");
|
|
635
|
+
var BRAND_SECONDARY2 = chalk3.hex("#FFAB00");
|
|
636
|
+
var SUCCESS2 = chalk3.hex("#66BB6A");
|
|
637
|
+
var INFO2 = chalk3.hex("#26C6DA");
|
|
638
|
+
var WARNING2 = chalk3.hex("#FFC107");
|
|
639
|
+
var ERROR2 = chalk3.hex("#EF5350");
|
|
640
|
+
var MUTED2 = chalk3.hex("#78909C");
|
|
641
|
+
var BORDER2 = chalk3.hex("#455A64");
|
|
642
|
+
var MODE_CONSULTANT = chalk3.hex("#AB47BC");
|
|
618
643
|
var PRIORITY_COLORS = {
|
|
619
644
|
"critical": chalk3.bgHex("#B71C1C").white,
|
|
620
645
|
"high": chalk3.hex("#FF6D00"),
|
|
@@ -622,10 +647,16 @@ var PRIORITY_COLORS = {
|
|
|
622
647
|
"low": chalk3.hex("#66BB6A")
|
|
623
648
|
};
|
|
624
649
|
var CATEGORY_COLORS = {
|
|
625
|
-
"bugs":
|
|
626
|
-
"features":
|
|
627
|
-
"improvements":
|
|
628
|
-
"upgrades":
|
|
650
|
+
"bugs": ERROR2,
|
|
651
|
+
"features": MODE_CONSULTANT,
|
|
652
|
+
"improvements": INFO2,
|
|
653
|
+
"upgrades": SUCCESS2
|
|
654
|
+
};
|
|
655
|
+
var CATEGORY_ICONS = {
|
|
656
|
+
"bugs": "\u{1F534}",
|
|
657
|
+
"features": "\u{1F7E3}",
|
|
658
|
+
"improvements": "\u{1F535}",
|
|
659
|
+
"upgrades": "\u{1F7E2}"
|
|
629
660
|
};
|
|
630
661
|
async function showInteractiveResults(config, category, sort, search) {
|
|
631
662
|
let allSuggestions = [];
|
|
@@ -639,7 +670,7 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
639
670
|
});
|
|
640
671
|
allSuggestions = result?.suggestions || [];
|
|
641
672
|
} catch (error) {
|
|
642
|
-
console.log(
|
|
673
|
+
console.log(ERROR2(` \u274C ${error.message}`));
|
|
643
674
|
return;
|
|
644
675
|
}
|
|
645
676
|
} else {
|
|
@@ -654,33 +685,34 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
654
685
|
sortSuggestions(allSuggestions, sort || "priority");
|
|
655
686
|
if (allSuggestions.length === 0) {
|
|
656
687
|
console.log("");
|
|
657
|
-
console.log(
|
|
688
|
+
console.log(SUCCESS2(" \u2705 No items found. Clean!"));
|
|
658
689
|
console.log("");
|
|
659
690
|
return;
|
|
660
691
|
}
|
|
661
|
-
const color = CATEGORY_COLORS[category] ||
|
|
692
|
+
const color = CATEGORY_COLORS[category] || MUTED2;
|
|
693
|
+
const icon = CATEGORY_ICONS[category] || "\u25C6";
|
|
662
694
|
let running = true;
|
|
663
695
|
let displaySuggestions = [...allSuggestions];
|
|
664
696
|
let currentSort = sort || "priority";
|
|
665
697
|
while (running) {
|
|
666
698
|
console.log("");
|
|
667
|
-
console.log(color(`
|
|
668
|
-
console.log(
|
|
699
|
+
console.log(color(` ${icon} ${category.toUpperCase()} (${displaySuggestions.length} items) \u2502 Sort: ${currentSort}`));
|
|
700
|
+
console.log(MUTED2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
669
701
|
console.log("");
|
|
670
702
|
const choices = [];
|
|
671
703
|
choices.push({
|
|
672
|
-
name:
|
|
704
|
+
name: INFO2(" \u{1F500} Toggle sort"),
|
|
673
705
|
value: "__sort__",
|
|
674
706
|
short: "Sort"
|
|
675
707
|
});
|
|
676
|
-
choices.push(new inquirer.Separator(
|
|
708
|
+
choices.push(new inquirer.Separator(MUTED2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")));
|
|
677
709
|
for (let idx = 0; idx < displaySuggestions.length; idx++) {
|
|
678
710
|
const item = displaySuggestions[idx];
|
|
679
|
-
const pColor = PRIORITY_COLORS[item.priority?.toLowerCase()] ||
|
|
680
|
-
const priorityLabel = (item.priority || "MEDIUM").toUpperCase().padEnd(9);
|
|
681
|
-
const
|
|
682
|
-
const
|
|
683
|
-
const displayName =
|
|
711
|
+
const pColor = PRIORITY_COLORS[item.priority?.toLowerCase()] || MUTED2;
|
|
712
|
+
const priorityLabel = pColor((item.priority || "MEDIUM").toUpperCase().padEnd(9));
|
|
713
|
+
const fileName = (item.filePath || "unknown").split("/").pop() || "unknown";
|
|
714
|
+
const title = (item.title || item.description || "No description").slice(0, 40);
|
|
715
|
+
const displayName = ` ${priorityLabel} ${INFO2(fileName.padEnd(20))} ${chalk3.white(title)}`;
|
|
684
716
|
choices.push({
|
|
685
717
|
name: displayName,
|
|
686
718
|
value: idx,
|
|
@@ -688,9 +720,9 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
688
720
|
description: `${item.priority} ${item.filePath} ${item.title} ${item.description}`
|
|
689
721
|
});
|
|
690
722
|
}
|
|
691
|
-
choices.push(new inquirer.Separator(
|
|
723
|
+
choices.push(new inquirer.Separator(MUTED2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")));
|
|
692
724
|
choices.push({
|
|
693
|
-
name:
|
|
725
|
+
name: MUTED2(" \u2190 Quit"),
|
|
694
726
|
value: "__quit__",
|
|
695
727
|
short: "Quit"
|
|
696
728
|
});
|
|
@@ -720,7 +752,7 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
720
752
|
if (selected === "__sort__") {
|
|
721
753
|
currentSort = currentSort === "priority" ? "file" : "priority";
|
|
722
754
|
sortSuggestions(displaySuggestions, currentSort);
|
|
723
|
-
console.log(
|
|
755
|
+
console.log(INFO2(` Sort changed to: ${currentSort}`));
|
|
724
756
|
continue;
|
|
725
757
|
}
|
|
726
758
|
if (typeof selected === "number") {
|
|
@@ -741,48 +773,49 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
741
773
|
displaySuggestions.splice(selected, 1);
|
|
742
774
|
const originalIdx = allSuggestions.findIndex((s) => s.id === item.id);
|
|
743
775
|
if (originalIdx !== -1) allSuggestions.splice(originalIdx, 1);
|
|
744
|
-
console.log(
|
|
776
|
+
console.log(MUTED2(" \u23ED\uFE0F Dismissed and logged."));
|
|
745
777
|
}
|
|
746
778
|
}
|
|
747
779
|
}
|
|
748
780
|
}
|
|
749
781
|
async function showExpandedView(item, category) {
|
|
750
|
-
const color = CATEGORY_COLORS[category] ||
|
|
751
|
-
const pColor = PRIORITY_COLORS[item.priority?.toLowerCase()] ||
|
|
782
|
+
const color = CATEGORY_COLORS[category] || MUTED2;
|
|
783
|
+
const pColor = PRIORITY_COLORS[item.priority?.toLowerCase()] || MUTED2;
|
|
784
|
+
const icon = CATEGORY_ICONS[category] || "\u25C6";
|
|
752
785
|
console.log("");
|
|
753
|
-
console.log(
|
|
754
|
-
console.log(
|
|
755
|
-
console.log(
|
|
756
|
-
console.log(
|
|
757
|
-
console.log(
|
|
758
|
-
console.log(
|
|
759
|
-
console.log(
|
|
760
|
-
console.log(
|
|
761
|
-
console.log(
|
|
762
|
-
console.log(
|
|
786
|
+
console.log(BORDER2(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
787
|
+
console.log(BORDER2(" \u2551") + ` ${icon} ` + pColor(`${(item.priority || "MEDIUM").toUpperCase()} ${category.toUpperCase().slice(0, -1)}`));
|
|
788
|
+
console.log(BORDER2(" \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
|
|
789
|
+
console.log(BORDER2(" \u2551") + MUTED2(" File: ") + INFO2(item.filePath || "unknown"));
|
|
790
|
+
console.log(BORDER2(" \u2551") + MUTED2(" Priority: ") + pColor((item.priority || "medium").toUpperCase()));
|
|
791
|
+
console.log(BORDER2(" \u2551"));
|
|
792
|
+
console.log(BORDER2(" \u2551") + MUTED2(" Title:"));
|
|
793
|
+
console.log(BORDER2(" \u2551") + chalk3.white.bold(` ${item.title || "No title"}`));
|
|
794
|
+
console.log(BORDER2(" \u2551"));
|
|
795
|
+
console.log(BORDER2(" \u2551") + MUTED2(" Description:"));
|
|
763
796
|
const descLines = wrapText(item.description || "No description", 54);
|
|
764
797
|
for (const line of descLines) {
|
|
765
|
-
console.log(
|
|
798
|
+
console.log(BORDER2(" \u2551") + chalk3.white(` ${line}`));
|
|
766
799
|
}
|
|
767
800
|
if (item.implementation) {
|
|
768
|
-
console.log(
|
|
769
|
-
console.log(
|
|
801
|
+
console.log(BORDER2(" \u2551"));
|
|
802
|
+
console.log(BORDER2(" \u2551") + MUTED2(" Implementation:"));
|
|
770
803
|
const implLines = wrapText(item.implementation, 54);
|
|
771
804
|
for (const line of implLines) {
|
|
772
|
-
console.log(
|
|
805
|
+
console.log(BORDER2(" \u2551") + chalk3.white(` ${line}`));
|
|
773
806
|
}
|
|
774
807
|
}
|
|
775
|
-
console.log(
|
|
808
|
+
console.log(BORDER2(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
776
809
|
console.log("");
|
|
777
810
|
const { action } = await inquirer.prompt([
|
|
778
811
|
{
|
|
779
812
|
type: "select",
|
|
780
813
|
name: "action",
|
|
781
|
-
message: "What do you want to do?",
|
|
814
|
+
message: BRAND_SECONDARY2("What do you want to do?"),
|
|
782
815
|
choices: [
|
|
783
|
-
{ name:
|
|
784
|
-
{ name:
|
|
785
|
-
{ name:
|
|
816
|
+
{ name: SUCCESS2(" \u{1F527} Implement this fix"), value: "implement" },
|
|
817
|
+
{ name: ERROR2(" \u{1F5D1}\uFE0F Dismiss"), value: "dismiss" },
|
|
818
|
+
{ name: MUTED2(" \u2190 Back to list"), value: "back" }
|
|
786
819
|
]
|
|
787
820
|
}
|
|
788
821
|
]);
|
|
@@ -790,12 +823,12 @@ async function showExpandedView(item, category) {
|
|
|
790
823
|
}
|
|
791
824
|
async function handleImplement(item, config, category) {
|
|
792
825
|
console.log("");
|
|
793
|
-
console.log(
|
|
826
|
+
console.log(INFO2(" \u{1F527} Implementing fix..."));
|
|
794
827
|
console.log("");
|
|
795
828
|
if (config.provider === "local" && config.localEndpoint) {
|
|
796
829
|
const fileContent = readFileContent(item.filePath);
|
|
797
830
|
if (!fileContent) {
|
|
798
|
-
console.log(
|
|
831
|
+
console.log(ERROR2(` \u274C Could not read file: ${item.filePath}`));
|
|
799
832
|
return;
|
|
800
833
|
}
|
|
801
834
|
const prompt = `You are MiniBob \u2014 a junior engineer making SURGICAL code fixes under strict supervision.
|
|
@@ -827,7 +860,8 @@ Return the complete file content now:`;
|
|
|
827
860
|
{ role: "system", content: "You are MiniBob, a junior engineer making SURGICAL fixes. Return ONLY valid source code. NO markdown. NO code fences. NO explanation. Start with // File: comment. Make the ABSOLUTE MINIMUM change needed. Do NOT restructure, refactor, or touch ANYTHING beyond the specific fix. If unsure, return the file unchanged." },
|
|
828
861
|
{ role: "user", content: prompt }
|
|
829
862
|
];
|
|
830
|
-
const
|
|
863
|
+
const localResult = await callLocalModel(config.localEndpoint, messages);
|
|
864
|
+
const response = typeof localResult === "object" && localResult.text ? localResult.text : localResult;
|
|
831
865
|
const lines = response.split("\n");
|
|
832
866
|
const firstLine = lines[0].trim();
|
|
833
867
|
let newContent;
|
|
@@ -837,25 +871,26 @@ Return the complete file content now:`;
|
|
|
837
871
|
newContent = response.trim();
|
|
838
872
|
}
|
|
839
873
|
if (newContent.includes("```") || newContent.includes("## ") || newContent.startsWith("Here") || newContent.startsWith("I have") || newContent.startsWith("Sure")) {
|
|
840
|
-
console.log(
|
|
874
|
+
console.log(WARNING2(" \u26A0\uFE0F MiniBob returned explanation instead of code. Fix rejected."));
|
|
841
875
|
return;
|
|
842
876
|
}
|
|
843
877
|
if (newContent.length < fileContent.length * 0.5) {
|
|
844
|
-
console.log(
|
|
878
|
+
console.log(WARNING2(` \u26A0\uFE0F MiniBob's output is ${Math.round(newContent.length / fileContent.length * 100)}% of original size. Rejecting.`));
|
|
845
879
|
return;
|
|
846
880
|
}
|
|
847
881
|
const originalExports = fileContent.match(/export\s+(function|class|const|interface|type|async\s+function)\s+\w+/g) || [];
|
|
848
882
|
for (const exp of originalExports) {
|
|
849
883
|
const exportName = exp.split(/\s+/).pop();
|
|
850
884
|
if (!newContent.includes(exportName)) {
|
|
851
|
-
console.log(
|
|
885
|
+
console.log(WARNING2(` \u26A0\uFE0F MiniBob removed export "${exportName}". Rejecting.`));
|
|
852
886
|
return;
|
|
853
887
|
}
|
|
854
888
|
}
|
|
855
889
|
await proposeAndWriteFile({
|
|
856
890
|
filePath: item.filePath,
|
|
857
891
|
content: newContent,
|
|
858
|
-
isNew: false
|
|
892
|
+
isNew: false,
|
|
893
|
+
isLocal: true
|
|
859
894
|
});
|
|
860
895
|
if (item.id) {
|
|
861
896
|
markSuggestionById(item.id, category, "implemented", {
|
|
@@ -864,7 +899,7 @@ Return the complete file content now:`;
|
|
|
864
899
|
});
|
|
865
900
|
}
|
|
866
901
|
} catch (error) {
|
|
867
|
-
console.log(
|
|
902
|
+
console.log(ERROR2(` \u274C Implementation failed: ${error.message}`));
|
|
868
903
|
}
|
|
869
904
|
} else if (config.loggedIn && config.conversationId) {
|
|
870
905
|
try {
|
|
@@ -876,7 +911,7 @@ Return the complete file content now:`;
|
|
|
876
911
|
jobId: `cli_impl_${Date.now()}`
|
|
877
912
|
});
|
|
878
913
|
if (result?.success) {
|
|
879
|
-
console.log(
|
|
914
|
+
console.log(SUCCESS2(` \u2705 ${result.message}`));
|
|
880
915
|
if (item.id) {
|
|
881
916
|
markSuggestionById(item.id, category, "implemented", {
|
|
882
917
|
reason: "Platform implementation",
|
|
@@ -884,13 +919,13 @@ Return the complete file content now:`;
|
|
|
884
919
|
});
|
|
885
920
|
}
|
|
886
921
|
} else {
|
|
887
|
-
console.log(
|
|
922
|
+
console.log(ERROR2(" \u274C Implementation failed on platform."));
|
|
888
923
|
}
|
|
889
924
|
} catch (error) {
|
|
890
|
-
console.log(
|
|
925
|
+
console.log(ERROR2(` \u274C ${error.message}`));
|
|
891
926
|
}
|
|
892
927
|
} else {
|
|
893
|
-
console.log(
|
|
928
|
+
console.log(ERROR2(" \u274C No provider configured for implementation."));
|
|
894
929
|
}
|
|
895
930
|
console.log("");
|
|
896
931
|
}
|
|
@@ -954,6 +989,7 @@ export {
|
|
|
954
989
|
callLocalModel,
|
|
955
990
|
buildLocalContext,
|
|
956
991
|
readFileContent,
|
|
992
|
+
extractAllProposedFiles,
|
|
957
993
|
extractProposedFile,
|
|
958
994
|
stripCodeBlockFromResponse,
|
|
959
995
|
processAllProposedFiles,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobsworkshop/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Bob's CLI — AI coding assistant and Forge orchestrator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"cli-table3": "^0.6.5",
|
|
39
39
|
"commander": "^15.0.0",
|
|
40
40
|
"conf": "^15.1.0",
|
|
41
|
+
"diff": "^9.0.0",
|
|
41
42
|
"inquirer": "^14.0.2",
|
|
42
43
|
"marked": "^18.0.4",
|
|
43
44
|
"marked-terminal": "^7.3.0",
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
"ws": "^8.21.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
51
|
+
"@types/diff": "^8.0.0",
|
|
50
52
|
"@types/node": "^25.9.1",
|
|
51
53
|
"tsup": "^8.5.1",
|
|
52
54
|
"typescript": "^6.0.3",
|