@bobsworkshop/cli 0.1.4 → 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 +160 -0
- package/dist/{analyse-auto-OBCDWYWX.js → analyse-auto-HYYDD4OQ.js} +1 -1
- package/dist/{bin/analyse-results-F7TH2YMO.js → analyse-results-7TS24WG7.js} +1 -1
- package/dist/bob.js +3612 -941
- package/dist/{bin/chunk-J4RRWEHU.js → chunk-CI36GGK2.js} +152 -91
- 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-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-RDYNFTCD.js +0 -529
- package/dist/bin/analyse-auto-Y5QUQU4G.js +0 -529
- 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/bob.js +0 -5136
- 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;
|
|
@@ -400,7 +417,9 @@ function extractProposedFile(response) {
|
|
|
400
417
|
return all.length > 0 ? all[0] : null;
|
|
401
418
|
}
|
|
402
419
|
function stripCodeBlockFromResponse(response) {
|
|
403
|
-
|
|
420
|
+
let stripped = response.replace(/```[\w]*\n\s*(?:\/\/\s*(?:File:)?\s*[\w\-\.\/\\]+\.\w+|#\s*(?:File:)?\s*[\w\-\.\/\\]+\.\w+|\*\s*\[FILE:)[^\n]*\n[\s\S]*?```/g, "").trim();
|
|
421
|
+
stripped = stripped.replace(/```capability_invocation\s*[\s\S]*?```/g, "").trim();
|
|
422
|
+
return stripped;
|
|
404
423
|
}
|
|
405
424
|
function isLocalProjectFile(filePath) {
|
|
406
425
|
const cwd = process.cwd();
|
|
@@ -417,8 +436,10 @@ function isLocalProjectFile(filePath) {
|
|
|
417
436
|
}
|
|
418
437
|
async function processAllProposedFiles(response, autoApprove = false, existingRl) {
|
|
419
438
|
const proposals = extractAllProposedFiles(response);
|
|
420
|
-
|
|
421
|
-
|
|
439
|
+
const idrpProposals = extractIDRPFileProposals(response);
|
|
440
|
+
const allProposals = [...proposals, ...idrpProposals];
|
|
441
|
+
if (allProposals.length === 0) return;
|
|
442
|
+
for (const proposed of allProposals) {
|
|
422
443
|
if (proposed.isLocal) {
|
|
423
444
|
await proposeAndWriteFile(proposed, autoApprove, existingRl);
|
|
424
445
|
} else {
|
|
@@ -429,19 +450,19 @@ async function processAllProposedFiles(response, autoApprove = false, existingRl
|
|
|
429
450
|
function displayExternalFile(proposed) {
|
|
430
451
|
const totalLines = proposed.content.split("\n").length;
|
|
431
452
|
console.log("");
|
|
432
|
-
console.log(
|
|
433
|
-
console.log(
|
|
434
|
-
console.log(
|
|
435
|
-
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`));
|
|
436
457
|
const previewLines = proposed.content.split("\n").slice(0, 6);
|
|
437
458
|
for (const line of previewLines) {
|
|
438
|
-
console.log(
|
|
459
|
+
console.log(WARNING(` \u2551`) + MUTED(` ${line}`));
|
|
439
460
|
}
|
|
440
461
|
if (totalLines > 6) {
|
|
441
|
-
console.log(
|
|
462
|
+
console.log(WARNING(` \u2551`) + MUTED(` ... (${totalLines - 6} more lines)`));
|
|
442
463
|
}
|
|
443
|
-
console.log(
|
|
444
|
-
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}`));
|
|
445
466
|
console.log("");
|
|
446
467
|
}
|
|
447
468
|
async function proposeAndWriteFile(proposed, autoApprove = false, existingRl) {
|
|
@@ -452,37 +473,43 @@ async function proposeAndWriteFile(proposed, autoApprove = false, existingRl) {
|
|
|
452
473
|
const absolutePath = path2.join(process.cwd(), proposed.filePath);
|
|
453
474
|
const action = proposed.isNew ? "CREATE" : "UPDATE";
|
|
454
475
|
const icon = proposed.isNew ? "\u{1F4C4}" : "\u270F\uFE0F";
|
|
455
|
-
const
|
|
476
|
+
const accentColor = proposed.isNew ? SUCCESS : BRAND_SECONDARY;
|
|
456
477
|
const totalLines = proposed.content.split("\n").length;
|
|
457
478
|
if (!autoApprove) {
|
|
458
479
|
console.log("");
|
|
459
|
-
console.log(
|
|
460
|
-
console.log(
|
|
461
|
-
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`));
|
|
462
483
|
const previewLines = proposed.content.split("\n").slice(0, 6);
|
|
463
484
|
for (const line of previewLines) {
|
|
464
|
-
console.log(
|
|
485
|
+
console.log(BORDER(` \u2551`) + MUTED(` ${line}`));
|
|
465
486
|
}
|
|
466
487
|
if (totalLines > 6) {
|
|
467
|
-
console.log(
|
|
488
|
+
console.log(BORDER(` \u2551`) + MUTED(` ... (${totalLines - 6} more lines)`));
|
|
468
489
|
}
|
|
469
|
-
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`));
|
|
470
491
|
console.log("");
|
|
492
|
+
const promptText = INFO(` \u{1F4BE} ${action === "CREATE" ? "Write this file" : "Apply changes"}? `) + MUTED(`(y/n/path): `);
|
|
471
493
|
let answer;
|
|
472
494
|
if (existingRl) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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();
|
|
476
501
|
} else {
|
|
477
502
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
478
503
|
answer = await new Promise((resolve3) => {
|
|
479
|
-
rl.question(
|
|
504
|
+
rl.question(promptText, (ans) => {
|
|
505
|
+
rl.close();
|
|
506
|
+
resolve3(ans);
|
|
507
|
+
});
|
|
480
508
|
});
|
|
481
|
-
rl.close();
|
|
482
509
|
}
|
|
483
510
|
const trimmed = answer.trim().toLowerCase();
|
|
484
511
|
if (trimmed === "n" || trimmed === "no") {
|
|
485
|
-
console.log(
|
|
512
|
+
console.log(MUTED(" \u23ED\uFE0F Skipped."));
|
|
486
513
|
return false;
|
|
487
514
|
}
|
|
488
515
|
if (trimmed !== "y" && trimmed !== "yes" && trimmed.length > 0) {
|
|
@@ -505,17 +532,38 @@ function writeFile(targetPath, content, originalFilePath, isNew) {
|
|
|
505
532
|
}
|
|
506
533
|
fs2.writeFileSync(targetPath, content, "utf-8");
|
|
507
534
|
const relativePath = path2.relative(process.cwd(), targetPath);
|
|
508
|
-
console.log(
|
|
535
|
+
console.log(SUCCESS(` \u2705 Written: ${relativePath}`));
|
|
509
536
|
if (!isNew) {
|
|
510
|
-
console.log(
|
|
537
|
+
console.log(MUTED(` \u{1F4E6} Backup saved to .bob-backups/`));
|
|
511
538
|
}
|
|
512
539
|
console.log("");
|
|
513
540
|
return true;
|
|
514
541
|
} catch (error) {
|
|
515
|
-
console.log(
|
|
542
|
+
console.log(ERROR(` \u274C Write failed: ${error.message}`));
|
|
516
543
|
return false;
|
|
517
544
|
}
|
|
518
545
|
}
|
|
546
|
+
function extractIDRPFileProposals(response) {
|
|
547
|
+
const proposals = [];
|
|
548
|
+
const invocationRegex = /```capability_invocation\s*([\s\S]*?)```/g;
|
|
549
|
+
let match;
|
|
550
|
+
while ((match = invocationRegex.exec(response)) !== null) {
|
|
551
|
+
try {
|
|
552
|
+
const invocation = JSON.parse(match[1].trim());
|
|
553
|
+
if (invocation.action !== "invoke") continue;
|
|
554
|
+
if (!["workspace_create_file", "workspace_update_file"].includes(invocation.capabilityId)) continue;
|
|
555
|
+
const filePath = invocation.params?.filePath;
|
|
556
|
+
const content = invocation.params?.content || invocation.params?.newContent;
|
|
557
|
+
if (!filePath || !content) continue;
|
|
558
|
+
const absolutePath = path2.join(process.cwd(), filePath);
|
|
559
|
+
const isNew = !fs2.existsSync(absolutePath);
|
|
560
|
+
const isLocal = isLocalProjectFile(filePath);
|
|
561
|
+
proposals.push({ filePath, content, isNew, isLocal });
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return proposals;
|
|
566
|
+
}
|
|
519
567
|
|
|
520
568
|
// src/core/analysis-tracker.ts
|
|
521
569
|
import * as fs3 from "fs";
|
|
@@ -583,13 +631,15 @@ function markSuggestionById(id, category, status, metadata) {
|
|
|
583
631
|
}
|
|
584
632
|
|
|
585
633
|
// src/commands/analyse-results.ts
|
|
586
|
-
var
|
|
587
|
-
var
|
|
588
|
-
var
|
|
589
|
-
var
|
|
590
|
-
var
|
|
591
|
-
var
|
|
592
|
-
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");
|
|
593
643
|
var PRIORITY_COLORS = {
|
|
594
644
|
"critical": chalk3.bgHex("#B71C1C").white,
|
|
595
645
|
"high": chalk3.hex("#FF6D00"),
|
|
@@ -597,10 +647,16 @@ var PRIORITY_COLORS = {
|
|
|
597
647
|
"low": chalk3.hex("#66BB6A")
|
|
598
648
|
};
|
|
599
649
|
var CATEGORY_COLORS = {
|
|
600
|
-
"bugs":
|
|
601
|
-
"features":
|
|
602
|
-
"improvements":
|
|
603
|
-
"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}"
|
|
604
660
|
};
|
|
605
661
|
async function showInteractiveResults(config, category, sort, search) {
|
|
606
662
|
let allSuggestions = [];
|
|
@@ -614,7 +670,7 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
614
670
|
});
|
|
615
671
|
allSuggestions = result?.suggestions || [];
|
|
616
672
|
} catch (error) {
|
|
617
|
-
console.log(
|
|
673
|
+
console.log(ERROR2(` \u274C ${error.message}`));
|
|
618
674
|
return;
|
|
619
675
|
}
|
|
620
676
|
} else {
|
|
@@ -629,33 +685,34 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
629
685
|
sortSuggestions(allSuggestions, sort || "priority");
|
|
630
686
|
if (allSuggestions.length === 0) {
|
|
631
687
|
console.log("");
|
|
632
|
-
console.log(
|
|
688
|
+
console.log(SUCCESS2(" \u2705 No items found. Clean!"));
|
|
633
689
|
console.log("");
|
|
634
690
|
return;
|
|
635
691
|
}
|
|
636
|
-
const color = CATEGORY_COLORS[category] ||
|
|
692
|
+
const color = CATEGORY_COLORS[category] || MUTED2;
|
|
693
|
+
const icon = CATEGORY_ICONS[category] || "\u25C6";
|
|
637
694
|
let running = true;
|
|
638
695
|
let displaySuggestions = [...allSuggestions];
|
|
639
696
|
let currentSort = sort || "priority";
|
|
640
697
|
while (running) {
|
|
641
698
|
console.log("");
|
|
642
|
-
console.log(color(`
|
|
643
|
-
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"));
|
|
644
701
|
console.log("");
|
|
645
702
|
const choices = [];
|
|
646
703
|
choices.push({
|
|
647
|
-
name:
|
|
704
|
+
name: INFO2(" \u{1F500} Toggle sort"),
|
|
648
705
|
value: "__sort__",
|
|
649
706
|
short: "Sort"
|
|
650
707
|
});
|
|
651
|
-
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")));
|
|
652
709
|
for (let idx = 0; idx < displaySuggestions.length; idx++) {
|
|
653
710
|
const item = displaySuggestions[idx];
|
|
654
|
-
const pColor = PRIORITY_COLORS[item.priority?.toLowerCase()] ||
|
|
655
|
-
const priorityLabel = (item.priority || "MEDIUM").toUpperCase().padEnd(9);
|
|
656
|
-
const
|
|
657
|
-
const
|
|
658
|
-
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)}`;
|
|
659
716
|
choices.push({
|
|
660
717
|
name: displayName,
|
|
661
718
|
value: idx,
|
|
@@ -663,9 +720,9 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
663
720
|
description: `${item.priority} ${item.filePath} ${item.title} ${item.description}`
|
|
664
721
|
});
|
|
665
722
|
}
|
|
666
|
-
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")));
|
|
667
724
|
choices.push({
|
|
668
|
-
name:
|
|
725
|
+
name: MUTED2(" \u2190 Quit"),
|
|
669
726
|
value: "__quit__",
|
|
670
727
|
short: "Quit"
|
|
671
728
|
});
|
|
@@ -695,7 +752,7 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
695
752
|
if (selected === "__sort__") {
|
|
696
753
|
currentSort = currentSort === "priority" ? "file" : "priority";
|
|
697
754
|
sortSuggestions(displaySuggestions, currentSort);
|
|
698
|
-
console.log(
|
|
755
|
+
console.log(INFO2(` Sort changed to: ${currentSort}`));
|
|
699
756
|
continue;
|
|
700
757
|
}
|
|
701
758
|
if (typeof selected === "number") {
|
|
@@ -716,48 +773,49 @@ async function showInteractiveResults(config, category, sort, search) {
|
|
|
716
773
|
displaySuggestions.splice(selected, 1);
|
|
717
774
|
const originalIdx = allSuggestions.findIndex((s) => s.id === item.id);
|
|
718
775
|
if (originalIdx !== -1) allSuggestions.splice(originalIdx, 1);
|
|
719
|
-
console.log(
|
|
776
|
+
console.log(MUTED2(" \u23ED\uFE0F Dismissed and logged."));
|
|
720
777
|
}
|
|
721
778
|
}
|
|
722
779
|
}
|
|
723
780
|
}
|
|
724
781
|
async function showExpandedView(item, category) {
|
|
725
|
-
const color = CATEGORY_COLORS[category] ||
|
|
726
|
-
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";
|
|
727
785
|
console.log("");
|
|
728
|
-
console.log(
|
|
729
|
-
console.log(
|
|
730
|
-
console.log(
|
|
731
|
-
console.log(
|
|
732
|
-
console.log(
|
|
733
|
-
console.log(
|
|
734
|
-
console.log(
|
|
735
|
-
console.log(
|
|
736
|
-
console.log(
|
|
737
|
-
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:"));
|
|
738
796
|
const descLines = wrapText(item.description || "No description", 54);
|
|
739
797
|
for (const line of descLines) {
|
|
740
|
-
console.log(
|
|
798
|
+
console.log(BORDER2(" \u2551") + chalk3.white(` ${line}`));
|
|
741
799
|
}
|
|
742
800
|
if (item.implementation) {
|
|
743
|
-
console.log(
|
|
744
|
-
console.log(
|
|
801
|
+
console.log(BORDER2(" \u2551"));
|
|
802
|
+
console.log(BORDER2(" \u2551") + MUTED2(" Implementation:"));
|
|
745
803
|
const implLines = wrapText(item.implementation, 54);
|
|
746
804
|
for (const line of implLines) {
|
|
747
|
-
console.log(
|
|
805
|
+
console.log(BORDER2(" \u2551") + chalk3.white(` ${line}`));
|
|
748
806
|
}
|
|
749
807
|
}
|
|
750
|
-
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"));
|
|
751
809
|
console.log("");
|
|
752
810
|
const { action } = await inquirer.prompt([
|
|
753
811
|
{
|
|
754
812
|
type: "select",
|
|
755
813
|
name: "action",
|
|
756
|
-
message: "What do you want to do?",
|
|
814
|
+
message: BRAND_SECONDARY2("What do you want to do?"),
|
|
757
815
|
choices: [
|
|
758
|
-
{ name:
|
|
759
|
-
{ name:
|
|
760
|
-
{ 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" }
|
|
761
819
|
]
|
|
762
820
|
}
|
|
763
821
|
]);
|
|
@@ -765,12 +823,12 @@ async function showExpandedView(item, category) {
|
|
|
765
823
|
}
|
|
766
824
|
async function handleImplement(item, config, category) {
|
|
767
825
|
console.log("");
|
|
768
|
-
console.log(
|
|
826
|
+
console.log(INFO2(" \u{1F527} Implementing fix..."));
|
|
769
827
|
console.log("");
|
|
770
828
|
if (config.provider === "local" && config.localEndpoint) {
|
|
771
829
|
const fileContent = readFileContent(item.filePath);
|
|
772
830
|
if (!fileContent) {
|
|
773
|
-
console.log(
|
|
831
|
+
console.log(ERROR2(` \u274C Could not read file: ${item.filePath}`));
|
|
774
832
|
return;
|
|
775
833
|
}
|
|
776
834
|
const prompt = `You are MiniBob \u2014 a junior engineer making SURGICAL code fixes under strict supervision.
|
|
@@ -802,7 +860,8 @@ Return the complete file content now:`;
|
|
|
802
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." },
|
|
803
861
|
{ role: "user", content: prompt }
|
|
804
862
|
];
|
|
805
|
-
const
|
|
863
|
+
const localResult = await callLocalModel(config.localEndpoint, messages);
|
|
864
|
+
const response = typeof localResult === "object" && localResult.text ? localResult.text : localResult;
|
|
806
865
|
const lines = response.split("\n");
|
|
807
866
|
const firstLine = lines[0].trim();
|
|
808
867
|
let newContent;
|
|
@@ -812,25 +871,26 @@ Return the complete file content now:`;
|
|
|
812
871
|
newContent = response.trim();
|
|
813
872
|
}
|
|
814
873
|
if (newContent.includes("```") || newContent.includes("## ") || newContent.startsWith("Here") || newContent.startsWith("I have") || newContent.startsWith("Sure")) {
|
|
815
|
-
console.log(
|
|
874
|
+
console.log(WARNING2(" \u26A0\uFE0F MiniBob returned explanation instead of code. Fix rejected."));
|
|
816
875
|
return;
|
|
817
876
|
}
|
|
818
877
|
if (newContent.length < fileContent.length * 0.5) {
|
|
819
|
-
console.log(
|
|
878
|
+
console.log(WARNING2(` \u26A0\uFE0F MiniBob's output is ${Math.round(newContent.length / fileContent.length * 100)}% of original size. Rejecting.`));
|
|
820
879
|
return;
|
|
821
880
|
}
|
|
822
881
|
const originalExports = fileContent.match(/export\s+(function|class|const|interface|type|async\s+function)\s+\w+/g) || [];
|
|
823
882
|
for (const exp of originalExports) {
|
|
824
883
|
const exportName = exp.split(/\s+/).pop();
|
|
825
884
|
if (!newContent.includes(exportName)) {
|
|
826
|
-
console.log(
|
|
885
|
+
console.log(WARNING2(` \u26A0\uFE0F MiniBob removed export "${exportName}". Rejecting.`));
|
|
827
886
|
return;
|
|
828
887
|
}
|
|
829
888
|
}
|
|
830
889
|
await proposeAndWriteFile({
|
|
831
890
|
filePath: item.filePath,
|
|
832
891
|
content: newContent,
|
|
833
|
-
isNew: false
|
|
892
|
+
isNew: false,
|
|
893
|
+
isLocal: true
|
|
834
894
|
});
|
|
835
895
|
if (item.id) {
|
|
836
896
|
markSuggestionById(item.id, category, "implemented", {
|
|
@@ -839,7 +899,7 @@ Return the complete file content now:`;
|
|
|
839
899
|
});
|
|
840
900
|
}
|
|
841
901
|
} catch (error) {
|
|
842
|
-
console.log(
|
|
902
|
+
console.log(ERROR2(` \u274C Implementation failed: ${error.message}`));
|
|
843
903
|
}
|
|
844
904
|
} else if (config.loggedIn && config.conversationId) {
|
|
845
905
|
try {
|
|
@@ -851,7 +911,7 @@ Return the complete file content now:`;
|
|
|
851
911
|
jobId: `cli_impl_${Date.now()}`
|
|
852
912
|
});
|
|
853
913
|
if (result?.success) {
|
|
854
|
-
console.log(
|
|
914
|
+
console.log(SUCCESS2(` \u2705 ${result.message}`));
|
|
855
915
|
if (item.id) {
|
|
856
916
|
markSuggestionById(item.id, category, "implemented", {
|
|
857
917
|
reason: "Platform implementation",
|
|
@@ -859,13 +919,13 @@ Return the complete file content now:`;
|
|
|
859
919
|
});
|
|
860
920
|
}
|
|
861
921
|
} else {
|
|
862
|
-
console.log(
|
|
922
|
+
console.log(ERROR2(" \u274C Implementation failed on platform."));
|
|
863
923
|
}
|
|
864
924
|
} catch (error) {
|
|
865
|
-
console.log(
|
|
925
|
+
console.log(ERROR2(` \u274C ${error.message}`));
|
|
866
926
|
}
|
|
867
927
|
} else {
|
|
868
|
-
console.log(
|
|
928
|
+
console.log(ERROR2(" \u274C No provider configured for implementation."));
|
|
869
929
|
}
|
|
870
930
|
console.log("");
|
|
871
931
|
}
|
|
@@ -929,6 +989,7 @@ export {
|
|
|
929
989
|
callLocalModel,
|
|
930
990
|
buildLocalContext,
|
|
931
991
|
readFileContent,
|
|
992
|
+
extractAllProposedFiles,
|
|
932
993
|
extractProposedFile,
|
|
933
994
|
stripCodeBlockFromResponse,
|
|
934
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",
|