@caliber-ai/cli 0.16.5 → 0.16.7
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/bin.js +93 -251
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -937,16 +937,6 @@ function scanLocalState(dir) {
|
|
|
937
937
|
path: claudeMdPath
|
|
938
938
|
});
|
|
939
939
|
}
|
|
940
|
-
const settingsPath = path9.join(dir, ".claude", "settings.json");
|
|
941
|
-
if (fs8.existsSync(settingsPath)) {
|
|
942
|
-
items.push({
|
|
943
|
-
type: "config",
|
|
944
|
-
platform: "claude",
|
|
945
|
-
name: "settings.json",
|
|
946
|
-
contentHash: hashFile(settingsPath),
|
|
947
|
-
path: settingsPath
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
940
|
const skillsDir = path9.join(dir, ".claude", "skills");
|
|
951
941
|
if (fs8.existsSync(skillsDir)) {
|
|
952
942
|
for (const file of fs8.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
|
|
@@ -970,7 +960,7 @@ function scanLocalState(dir) {
|
|
|
970
960
|
type: "mcp",
|
|
971
961
|
platform: "claude",
|
|
972
962
|
name,
|
|
973
|
-
contentHash:
|
|
963
|
+
contentHash: hashJson(mcpJson.mcpServers[name]),
|
|
974
964
|
path: mcpJsonPath
|
|
975
965
|
});
|
|
976
966
|
}
|
|
@@ -1011,7 +1001,7 @@ function scanLocalState(dir) {
|
|
|
1011
1001
|
type: "mcp",
|
|
1012
1002
|
platform: "cursor",
|
|
1013
1003
|
name,
|
|
1014
|
-
contentHash:
|
|
1004
|
+
contentHash: hashJson(mcpJson.mcpServers[name]),
|
|
1015
1005
|
path: cursorMcpPath
|
|
1016
1006
|
});
|
|
1017
1007
|
}
|
|
@@ -1048,11 +1038,11 @@ function compareState(serverItems, localItems) {
|
|
|
1048
1038
|
return { installed, missing, outdated, extra };
|
|
1049
1039
|
}
|
|
1050
1040
|
function hashFile(filePath) {
|
|
1051
|
-
const
|
|
1052
|
-
return crypto3.createHash("sha256").update(
|
|
1041
|
+
const text = fs8.readFileSync(filePath, "utf-8");
|
|
1042
|
+
return crypto3.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
|
|
1053
1043
|
}
|
|
1054
|
-
function
|
|
1055
|
-
return crypto3.createHash("sha256").update(JSON.stringify(
|
|
1044
|
+
function hashJson(obj) {
|
|
1045
|
+
return crypto3.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
|
|
1056
1046
|
}
|
|
1057
1047
|
|
|
1058
1048
|
// src/api/client.ts
|
|
@@ -2575,11 +2565,10 @@ function printRecommendations(recs) {
|
|
|
2575
2565
|
console.log("");
|
|
2576
2566
|
}
|
|
2577
2567
|
|
|
2578
|
-
// src/commands/
|
|
2568
|
+
// src/commands/sync.ts
|
|
2579
2569
|
import chalk9 from "chalk";
|
|
2580
2570
|
import ora6 from "ora";
|
|
2581
|
-
|
|
2582
|
-
async function healthCommand(options) {
|
|
2571
|
+
async function syncCommand(options) {
|
|
2583
2572
|
const auth2 = getStoredAuth();
|
|
2584
2573
|
if (!auth2) {
|
|
2585
2574
|
console.log(chalk9.red("Not authenticated. Run `caliber login` first."));
|
|
@@ -2596,153 +2585,7 @@ async function healthCommand(options) {
|
|
|
2596
2585
|
throw new Error("__exit__");
|
|
2597
2586
|
}
|
|
2598
2587
|
const projectId = match.project.id;
|
|
2599
|
-
const spinner = ora6("
|
|
2600
|
-
let report;
|
|
2601
|
-
try {
|
|
2602
|
-
report = await apiRequest(
|
|
2603
|
-
`/api/context/project/${projectId}/analyze`,
|
|
2604
|
-
{ method: "POST" }
|
|
2605
|
-
);
|
|
2606
|
-
spinner.succeed("Analysis complete");
|
|
2607
|
-
} catch (err) {
|
|
2608
|
-
spinner.fail("Analysis failed");
|
|
2609
|
-
throw err;
|
|
2610
|
-
}
|
|
2611
|
-
if (options.json) {
|
|
2612
|
-
console.log(JSON.stringify(report, null, 2));
|
|
2613
|
-
return;
|
|
2614
|
-
}
|
|
2615
|
-
printReport(report);
|
|
2616
|
-
const shouldFix = options.fix || report.recommendations.length > 0 && !options.json && await confirm2({ message: "Would you like to fix these issues?", default: true });
|
|
2617
|
-
if (shouldFix) {
|
|
2618
|
-
const planSpinner = ora6("Generating fix plan...").start();
|
|
2619
|
-
const plan = await apiRequest(
|
|
2620
|
-
`/api/context/reports/${report.id}/fix-plan`,
|
|
2621
|
-
{ method: "POST", body: { projectId } }
|
|
2622
|
-
);
|
|
2623
|
-
planSpinner.succeed("Fix plan ready");
|
|
2624
|
-
if (!plan?.actions.length) {
|
|
2625
|
-
console.log(chalk9.dim(" No fixes needed."));
|
|
2626
|
-
return;
|
|
2627
|
-
}
|
|
2628
|
-
console.log(chalk9.bold("\n Fix Plan:\n"));
|
|
2629
|
-
for (const action of plan.actions) {
|
|
2630
|
-
if (action.type === "remove") {
|
|
2631
|
-
console.log(` ${chalk9.red("\u2717 Remove")} ${action.items.join(", ")}`);
|
|
2632
|
-
if (action.reason) console.log(chalk9.dim(` ${action.reason}`));
|
|
2633
|
-
} else if (action.type === "add") {
|
|
2634
|
-
console.log(` ${chalk9.green("+ Add")} ${action.items.join(", ")}`);
|
|
2635
|
-
if (action.reason) console.log(chalk9.dim(` ${action.reason}`));
|
|
2636
|
-
}
|
|
2637
|
-
console.log("");
|
|
2638
|
-
}
|
|
2639
|
-
const scoreAfterStr = plan.estimatedScoreAfter != null ? String(plan.estimatedScoreAfter) : `${report.score + plan.estimatedScoreImprovement}`;
|
|
2640
|
-
console.log(` Expected: ${report.score} \u2192 ${chalk9.green(scoreAfterStr)}/100
|
|
2641
|
-
`);
|
|
2642
|
-
const shouldExecute = options.fix || await confirm2({ message: "Apply this fix plan?", default: true });
|
|
2643
|
-
if (!shouldExecute) {
|
|
2644
|
-
console.log(chalk9.dim(" Fix cancelled."));
|
|
2645
|
-
return;
|
|
2646
|
-
}
|
|
2647
|
-
const fixSpinner = ora6("Applying fixes...").start();
|
|
2648
|
-
try {
|
|
2649
|
-
const result = await apiRequest(
|
|
2650
|
-
`/api/context/reports/${report.id}/fix-execute`,
|
|
2651
|
-
{ method: "POST", body: { projectId } }
|
|
2652
|
-
);
|
|
2653
|
-
fixSpinner.succeed("Fixes applied");
|
|
2654
|
-
console.log("");
|
|
2655
|
-
console.log(` Score: ${result.scoreBefore} \u2192 ${chalk9.green(String(result.scoreAfter))} (${chalk9.green(`+${result.improvement}`)})`);
|
|
2656
|
-
if (result.itemsRemoved) console.log(` Removed: ${result.itemsRemoved} items`);
|
|
2657
|
-
if (result.itemsConsolidated) console.log(` Consolidated: ${result.itemsConsolidated} items`);
|
|
2658
|
-
if (result.itemsAdded) console.log(` Added: ${result.itemsAdded} items`);
|
|
2659
|
-
console.log("");
|
|
2660
|
-
} catch (err) {
|
|
2661
|
-
fixSpinner.fail("Fix execution failed");
|
|
2662
|
-
throw err;
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
}
|
|
2666
|
-
var CATEGORY_DESCRIPTIONS = {
|
|
2667
|
-
tooling: "build/test/lint commands (helps agents the most)",
|
|
2668
|
-
essential: "constraints agents can't discover from code",
|
|
2669
|
-
convention: "style/naming rules (linters handle this; low value)",
|
|
2670
|
-
overview: "project summaries (agents discover this by reading code)",
|
|
2671
|
-
workflow: "development workflows and processes"
|
|
2672
|
-
};
|
|
2673
|
-
function printReport(report) {
|
|
2674
|
-
const gradeColors = {
|
|
2675
|
-
A: chalk9.green,
|
|
2676
|
-
B: chalk9.blue,
|
|
2677
|
-
C: chalk9.yellow,
|
|
2678
|
-
D: chalk9.hex("#FFA500"),
|
|
2679
|
-
F: chalk9.red
|
|
2680
|
-
};
|
|
2681
|
-
const gradeColor = gradeColors[report.grade] || chalk9.white;
|
|
2682
|
-
console.log(chalk9.bold("\n Context Health Report\n"));
|
|
2683
|
-
console.log(` Grade: ${gradeColor(report.grade)} Score: ${gradeColor(String(report.score))}/100
|
|
2684
|
-
`);
|
|
2685
|
-
const categories = Object.entries(report.category_breakdown);
|
|
2686
|
-
if (categories.length) {
|
|
2687
|
-
console.log(chalk9.bold(" Category Breakdown:\n"));
|
|
2688
|
-
const itemsByCategory = /* @__PURE__ */ new Map();
|
|
2689
|
-
if (report.item_classifications) {
|
|
2690
|
-
for (const item of report.item_classifications) {
|
|
2691
|
-
const cat = item.category.toLowerCase();
|
|
2692
|
-
if (!itemsByCategory.has(cat)) itemsByCategory.set(cat, []);
|
|
2693
|
-
itemsByCategory.get(cat).push(item);
|
|
2694
|
-
}
|
|
2695
|
-
}
|
|
2696
|
-
for (const [name, data] of categories) {
|
|
2697
|
-
const desc = CATEGORY_DESCRIPTIONS[name] || "";
|
|
2698
|
-
const header = desc ? `${chalk9.bold(name)} ${chalk9.dim(`\u2014 ${desc}`)}` : chalk9.bold(name);
|
|
2699
|
-
console.log(` ${header}`);
|
|
2700
|
-
const items = itemsByCategory.get(name);
|
|
2701
|
-
if (items?.length) {
|
|
2702
|
-
for (const item of items) {
|
|
2703
|
-
const icon = item.impactScore >= 0 ? chalk9.green("\u2713") : chalk9.red("\u2717");
|
|
2704
|
-
const snippet = item.recommendation.length > 70 ? item.recommendation.slice(0, 67) + "..." : item.recommendation;
|
|
2705
|
-
console.log(` ${icon} ${item.itemName.padEnd(22)} ${chalk9.dim(`"${snippet}"`)}`);
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
console.log(chalk9.dim(` ${data.count} items \xB7 ${data.tokens} tokens
|
|
2709
|
-
`));
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
if (report.recommendations.length) {
|
|
2713
|
-
console.log(chalk9.bold(" Recommendations:\n"));
|
|
2714
|
-
for (const rec of report.recommendations) {
|
|
2715
|
-
const icon = rec.priority === "high" ? chalk9.red("!") : rec.priority === "medium" ? chalk9.yellow("~") : chalk9.dim("-");
|
|
2716
|
-
console.log(` ${icon} ${rec.description}`);
|
|
2717
|
-
if (rec.reasoning) {
|
|
2718
|
-
console.log(chalk9.dim(` ${rec.reasoning}`));
|
|
2719
|
-
}
|
|
2720
|
-
console.log("");
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
|
|
2725
|
-
// src/commands/sync.ts
|
|
2726
|
-
import chalk10 from "chalk";
|
|
2727
|
-
import ora7 from "ora";
|
|
2728
|
-
async function syncCommand(options) {
|
|
2729
|
-
const auth2 = getStoredAuth();
|
|
2730
|
-
if (!auth2) {
|
|
2731
|
-
console.log(chalk10.red("Not authenticated. Run `caliber login` first."));
|
|
2732
|
-
throw new Error("__exit__");
|
|
2733
|
-
}
|
|
2734
|
-
const fingerprint = collectFingerprint(process.cwd());
|
|
2735
|
-
const hash = computeFingerprintHash(fingerprint);
|
|
2736
|
-
const match = await apiRequest(
|
|
2737
|
-
"/api/projects/match",
|
|
2738
|
-
{ method: "POST", body: { fingerprintHash: hash } }
|
|
2739
|
-
);
|
|
2740
|
-
if (!match?.project) {
|
|
2741
|
-
console.log(chalk10.yellow("No project found. Run `caliber init` first."));
|
|
2742
|
-
throw new Error("__exit__");
|
|
2743
|
-
}
|
|
2744
|
-
const projectId = match.project.id;
|
|
2745
|
-
const spinner = ora7("Scanning local state...").start();
|
|
2588
|
+
const spinner = ora6("Scanning local state...").start();
|
|
2746
2589
|
const localItems = scanLocalState(process.cwd());
|
|
2747
2590
|
spinner.text = "Fetching server items...";
|
|
2748
2591
|
const serverItems = await apiRequest(
|
|
@@ -2750,7 +2593,7 @@ async function syncCommand(options) {
|
|
|
2750
2593
|
);
|
|
2751
2594
|
spinner.succeed(`Found ${localItems.length} local items, ${serverItems?.length || 0} server items`);
|
|
2752
2595
|
if (!serverItems?.length) {
|
|
2753
|
-
console.log(
|
|
2596
|
+
console.log(chalk9.dim("\nNo items configured on server. Run `caliber init` to set up your project.\n"));
|
|
2754
2597
|
return;
|
|
2755
2598
|
}
|
|
2756
2599
|
const platformFilter = options.platform;
|
|
@@ -2759,15 +2602,15 @@ async function syncCommand(options) {
|
|
|
2759
2602
|
const diff = compareState(filteredServer, filteredLocal);
|
|
2760
2603
|
printDiff(diff);
|
|
2761
2604
|
if (diff.missing.length === 0 && diff.outdated.length === 0) {
|
|
2762
|
-
console.log(
|
|
2605
|
+
console.log(chalk9.green("\nAll items synced.\n"));
|
|
2763
2606
|
await reportToServer(projectId, filteredServer, diff);
|
|
2764
2607
|
return;
|
|
2765
2608
|
}
|
|
2766
2609
|
if (options.dryRun) {
|
|
2767
|
-
console.log(
|
|
2610
|
+
console.log(chalk9.dim("\nDry run \u2014 no changes made.\n"));
|
|
2768
2611
|
return;
|
|
2769
2612
|
}
|
|
2770
|
-
const installSpinner =
|
|
2613
|
+
const installSpinner = ora6("Installing missing and outdated items...").start();
|
|
2771
2614
|
try {
|
|
2772
2615
|
const setup = buildSetupFromItems([...diff.missing, ...diff.outdated.map((o) => o.server)]);
|
|
2773
2616
|
if (setup) {
|
|
@@ -2820,26 +2663,26 @@ async function reportToServer(projectId, serverItems, diff) {
|
|
|
2820
2663
|
}
|
|
2821
2664
|
}
|
|
2822
2665
|
function printDiff(diff) {
|
|
2823
|
-
console.log(
|
|
2666
|
+
console.log(chalk9.bold("\n Sync Status\n"));
|
|
2824
2667
|
if (diff.installed.length) {
|
|
2825
|
-
console.log(` ${
|
|
2668
|
+
console.log(` ${chalk9.green("\u2713")} Installed: ${diff.installed.length}`);
|
|
2826
2669
|
}
|
|
2827
2670
|
if (diff.missing.length) {
|
|
2828
|
-
console.log(` ${
|
|
2671
|
+
console.log(` ${chalk9.red("\u2717")} Missing: ${diff.missing.length}`);
|
|
2829
2672
|
for (const item of diff.missing) {
|
|
2830
|
-
console.log(` ${
|
|
2673
|
+
console.log(` ${chalk9.red("-")} ${item.name} (${item.type}/${item.platform})`);
|
|
2831
2674
|
}
|
|
2832
2675
|
}
|
|
2833
2676
|
if (diff.outdated.length) {
|
|
2834
|
-
console.log(` ${
|
|
2677
|
+
console.log(` ${chalk9.yellow("~")} Outdated: ${diff.outdated.length}`);
|
|
2835
2678
|
for (const item of diff.outdated) {
|
|
2836
|
-
console.log(` ${
|
|
2679
|
+
console.log(` ${chalk9.yellow("~")} ${item.server.name} (${item.server.type}/${item.server.platform})`);
|
|
2837
2680
|
}
|
|
2838
2681
|
}
|
|
2839
2682
|
if (diff.extra.length) {
|
|
2840
|
-
console.log(` ${
|
|
2683
|
+
console.log(` ${chalk9.dim("+")} Extra (local only): ${diff.extra.length}`);
|
|
2841
2684
|
for (const item of diff.extra) {
|
|
2842
|
-
console.log(` ${
|
|
2685
|
+
console.log(` ${chalk9.dim("+")} ${item.name} (${item.type}/${item.platform})`);
|
|
2843
2686
|
}
|
|
2844
2687
|
}
|
|
2845
2688
|
console.log("");
|
|
@@ -2900,12 +2743,12 @@ function buildSetupFromItems(items) {
|
|
|
2900
2743
|
}
|
|
2901
2744
|
|
|
2902
2745
|
// src/commands/diff.ts
|
|
2903
|
-
import
|
|
2904
|
-
import
|
|
2746
|
+
import chalk10 from "chalk";
|
|
2747
|
+
import ora7 from "ora";
|
|
2905
2748
|
async function diffCommand(options) {
|
|
2906
2749
|
const auth2 = getStoredAuth();
|
|
2907
2750
|
if (!auth2) {
|
|
2908
|
-
console.log(
|
|
2751
|
+
console.log(chalk10.red("Not authenticated. Run `caliber login` first."));
|
|
2909
2752
|
throw new Error("__exit__");
|
|
2910
2753
|
}
|
|
2911
2754
|
const fingerprint = collectFingerprint(process.cwd());
|
|
@@ -2915,58 +2758,58 @@ async function diffCommand(options) {
|
|
|
2915
2758
|
{ method: "POST", body: { fingerprintHash: hash } }
|
|
2916
2759
|
);
|
|
2917
2760
|
if (!match?.project) {
|
|
2918
|
-
console.log(
|
|
2761
|
+
console.log(chalk10.yellow("No project found. Run `caliber init` first."));
|
|
2919
2762
|
throw new Error("__exit__");
|
|
2920
2763
|
}
|
|
2921
2764
|
const projectId = match.project.id;
|
|
2922
|
-
const spinner =
|
|
2765
|
+
const spinner = ora7("Comparing local and server state...").start();
|
|
2923
2766
|
const localItems = scanLocalState(process.cwd());
|
|
2924
2767
|
const serverItems = await apiRequest(
|
|
2925
2768
|
`/api/sync/project/${projectId}/items`
|
|
2926
2769
|
);
|
|
2927
2770
|
spinner.stop();
|
|
2928
2771
|
if (!serverItems?.length) {
|
|
2929
|
-
console.log(
|
|
2772
|
+
console.log(chalk10.dim("\nNo items configured on server.\n"));
|
|
2930
2773
|
return;
|
|
2931
2774
|
}
|
|
2932
2775
|
const platformFilter = options.platform;
|
|
2933
2776
|
const filteredServer = platformFilter ? serverItems.filter((i) => i.platform === platformFilter || i.platform === "both") : serverItems;
|
|
2934
2777
|
const filteredLocal = platformFilter ? localItems.filter((i) => i.platform === platformFilter) : localItems;
|
|
2935
2778
|
const diff = compareState(filteredServer, filteredLocal);
|
|
2936
|
-
console.log(
|
|
2779
|
+
console.log(chalk10.bold("\n Config Diff\n"));
|
|
2937
2780
|
if (diff.installed.length) {
|
|
2938
|
-
console.log(` ${
|
|
2781
|
+
console.log(` ${chalk10.green("\u2713")} In sync: ${diff.installed.length}`);
|
|
2939
2782
|
}
|
|
2940
2783
|
if (diff.missing.length) {
|
|
2941
|
-
console.log(` ${
|
|
2784
|
+
console.log(` ${chalk10.red("\u2717")} Missing locally: ${diff.missing.length}`);
|
|
2942
2785
|
for (const item of diff.missing) {
|
|
2943
|
-
console.log(` ${
|
|
2786
|
+
console.log(` ${chalk10.red("-")} ${item.name} (${item.type}/${item.platform})`);
|
|
2944
2787
|
}
|
|
2945
2788
|
}
|
|
2946
2789
|
if (diff.outdated.length) {
|
|
2947
|
-
console.log(` ${
|
|
2790
|
+
console.log(` ${chalk10.yellow("~")} Outdated: ${diff.outdated.length}`);
|
|
2948
2791
|
for (const item of diff.outdated) {
|
|
2949
|
-
console.log(` ${
|
|
2792
|
+
console.log(` ${chalk10.yellow("~")} ${item.server.name} (${item.server.type}/${item.server.platform})`);
|
|
2950
2793
|
}
|
|
2951
2794
|
}
|
|
2952
2795
|
if (diff.extra.length) {
|
|
2953
|
-
console.log(` ${
|
|
2796
|
+
console.log(` ${chalk10.dim("+")} Local only: ${diff.extra.length}`);
|
|
2954
2797
|
for (const item of diff.extra) {
|
|
2955
|
-
console.log(` ${
|
|
2798
|
+
console.log(` ${chalk10.dim("+")} ${item.name} (${item.type}/${item.platform})`);
|
|
2956
2799
|
}
|
|
2957
2800
|
}
|
|
2958
2801
|
if (diff.missing.length === 0 && diff.outdated.length === 0) {
|
|
2959
|
-
console.log(
|
|
2802
|
+
console.log(chalk10.green("\n Everything is in sync.\n"));
|
|
2960
2803
|
} else {
|
|
2961
|
-
console.log(
|
|
2804
|
+
console.log(chalk10.dim("\n Run `caliber sync` to apply changes.\n"));
|
|
2962
2805
|
}
|
|
2963
2806
|
}
|
|
2964
2807
|
|
|
2965
2808
|
// src/commands/refresh.ts
|
|
2966
2809
|
import fs19 from "fs";
|
|
2967
2810
|
import path16 from "path";
|
|
2968
|
-
import
|
|
2969
|
-
import
|
|
2811
|
+
import chalk11 from "chalk";
|
|
2812
|
+
import ora8 from "ora";
|
|
2970
2813
|
|
|
2971
2814
|
// src/lib/git-diff.ts
|
|
2972
2815
|
import { execSync as execSync3 } from "child_process";
|
|
@@ -3099,7 +2942,7 @@ function discoverGitRepos(parentDir) {
|
|
|
3099
2942
|
}
|
|
3100
2943
|
async function refreshSingleRepo(repoDir, options) {
|
|
3101
2944
|
const quiet = !!options.quiet;
|
|
3102
|
-
const prefix = options.label ? `${
|
|
2945
|
+
const prefix = options.label ? `${chalk11.bold(options.label)} ` : "";
|
|
3103
2946
|
const state = readState();
|
|
3104
2947
|
const lastSha = state?.lastRefreshSha ?? null;
|
|
3105
2948
|
const diff = collectDiff(lastSha);
|
|
@@ -3108,10 +2951,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
3108
2951
|
if (currentSha) {
|
|
3109
2952
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
3110
2953
|
}
|
|
3111
|
-
log(quiet,
|
|
2954
|
+
log(quiet, chalk11.dim(`${prefix}No changes since last refresh.`));
|
|
3112
2955
|
return;
|
|
3113
2956
|
}
|
|
3114
|
-
const spinner = quiet ? null :
|
|
2957
|
+
const spinner = quiet ? null : ora8(`${prefix}Analyzing changes...`).start();
|
|
3115
2958
|
const existingDocs = readExistingConfigs(repoDir);
|
|
3116
2959
|
const fingerprint = collectFingerprint(repoDir);
|
|
3117
2960
|
const projectContext = {
|
|
@@ -3143,10 +2986,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
3143
2986
|
if (options.dryRun) {
|
|
3144
2987
|
spinner?.info(`${prefix}Dry run \u2014 would update:`);
|
|
3145
2988
|
for (const doc of response.docsUpdated) {
|
|
3146
|
-
console.log(` ${
|
|
2989
|
+
console.log(` ${chalk11.yellow("~")} ${doc}`);
|
|
3147
2990
|
}
|
|
3148
2991
|
if (response.changesSummary) {
|
|
3149
|
-
console.log(
|
|
2992
|
+
console.log(chalk11.dim(`
|
|
3150
2993
|
${response.changesSummary}`));
|
|
3151
2994
|
}
|
|
3152
2995
|
return;
|
|
@@ -3154,10 +2997,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
3154
2997
|
const written = writeRefreshDocs(response.updatedDocs);
|
|
3155
2998
|
spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
|
|
3156
2999
|
for (const file of written) {
|
|
3157
|
-
log(quiet, ` ${
|
|
3000
|
+
log(quiet, ` ${chalk11.green("\u2713")} ${file}`);
|
|
3158
3001
|
}
|
|
3159
3002
|
if (response.changesSummary) {
|
|
3160
|
-
log(quiet,
|
|
3003
|
+
log(quiet, chalk11.dim(`
|
|
3161
3004
|
${response.changesSummary}`));
|
|
3162
3005
|
}
|
|
3163
3006
|
if (currentSha) {
|
|
@@ -3174,7 +3017,7 @@ async function refreshCommand(options) {
|
|
|
3174
3017
|
const auth2 = getStoredAuth();
|
|
3175
3018
|
if (!auth2) {
|
|
3176
3019
|
if (quiet) return;
|
|
3177
|
-
console.log(
|
|
3020
|
+
console.log(chalk11.red("Not authenticated. Run `caliber login` first."));
|
|
3178
3021
|
throw new Error("__exit__");
|
|
3179
3022
|
}
|
|
3180
3023
|
if (isGitRepo()) {
|
|
@@ -3184,10 +3027,10 @@ async function refreshCommand(options) {
|
|
|
3184
3027
|
const repos = discoverGitRepos(process.cwd());
|
|
3185
3028
|
if (repos.length === 0) {
|
|
3186
3029
|
if (quiet) return;
|
|
3187
|
-
console.log(
|
|
3030
|
+
console.log(chalk11.red("Not inside a git repository and no git repos found in child directories."));
|
|
3188
3031
|
throw new Error("__exit__");
|
|
3189
3032
|
}
|
|
3190
|
-
log(quiet,
|
|
3033
|
+
log(quiet, chalk11.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
3191
3034
|
`));
|
|
3192
3035
|
const originalDir = process.cwd();
|
|
3193
3036
|
for (const repo of repos) {
|
|
@@ -3197,7 +3040,7 @@ async function refreshCommand(options) {
|
|
|
3197
3040
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
3198
3041
|
} catch (err) {
|
|
3199
3042
|
if (err instanceof Error && err.message === "__exit__") continue;
|
|
3200
|
-
log(quiet,
|
|
3043
|
+
log(quiet, chalk11.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
|
|
3201
3044
|
}
|
|
3202
3045
|
}
|
|
3203
3046
|
process.chdir(originalDir);
|
|
@@ -3205,46 +3048,46 @@ async function refreshCommand(options) {
|
|
|
3205
3048
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
3206
3049
|
if (quiet) return;
|
|
3207
3050
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3208
|
-
console.log(
|
|
3051
|
+
console.log(chalk11.red(`Refresh failed: ${msg}`));
|
|
3209
3052
|
throw new Error("__exit__");
|
|
3210
3053
|
}
|
|
3211
3054
|
}
|
|
3212
3055
|
|
|
3213
3056
|
// src/commands/hooks.ts
|
|
3214
|
-
import
|
|
3057
|
+
import chalk12 from "chalk";
|
|
3215
3058
|
async function hooksInstallCommand() {
|
|
3216
3059
|
const result = installHook();
|
|
3217
3060
|
if (result.alreadyInstalled) {
|
|
3218
|
-
console.log(
|
|
3061
|
+
console.log(chalk12.dim("Hook already installed."));
|
|
3219
3062
|
return;
|
|
3220
3063
|
}
|
|
3221
|
-
console.log(
|
|
3222
|
-
console.log(
|
|
3064
|
+
console.log(chalk12.green("\u2713") + " SessionEnd hook installed in .claude/settings.json");
|
|
3065
|
+
console.log(chalk12.dim(" Docs will auto-refresh when Claude Code sessions end."));
|
|
3223
3066
|
}
|
|
3224
3067
|
async function hooksRemoveCommand() {
|
|
3225
3068
|
const result = removeHook();
|
|
3226
3069
|
if (result.notFound) {
|
|
3227
|
-
console.log(
|
|
3070
|
+
console.log(chalk12.dim("Hook not found."));
|
|
3228
3071
|
return;
|
|
3229
3072
|
}
|
|
3230
|
-
console.log(
|
|
3073
|
+
console.log(chalk12.green("\u2713") + " SessionEnd hook removed from .claude/settings.json");
|
|
3231
3074
|
}
|
|
3232
3075
|
async function hooksStatusCommand() {
|
|
3233
3076
|
const installed = isHookInstalled();
|
|
3234
3077
|
if (installed) {
|
|
3235
|
-
console.log(
|
|
3078
|
+
console.log(chalk12.green("\u2713") + " Auto-refresh hook is " + chalk12.green("installed"));
|
|
3236
3079
|
} else {
|
|
3237
|
-
console.log(
|
|
3238
|
-
console.log(
|
|
3080
|
+
console.log(chalk12.dim("\u2717") + " Auto-refresh hook is " + chalk12.yellow("not installed"));
|
|
3081
|
+
console.log(chalk12.dim(" Run `caliber hooks install` to enable auto-refresh on session end."));
|
|
3239
3082
|
}
|
|
3240
3083
|
}
|
|
3241
3084
|
|
|
3242
3085
|
// src/commands/review.ts
|
|
3243
|
-
import
|
|
3086
|
+
import chalk13 from "chalk";
|
|
3244
3087
|
import readline2 from "readline";
|
|
3245
|
-
import
|
|
3088
|
+
import ora9 from "ora";
|
|
3246
3089
|
import select2 from "@inquirer/select";
|
|
3247
|
-
import
|
|
3090
|
+
import confirm2 from "@inquirer/confirm";
|
|
3248
3091
|
function prompt(question) {
|
|
3249
3092
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3250
3093
|
return new Promise((resolve2) => {
|
|
@@ -3280,12 +3123,12 @@ function starRating(rating) {
|
|
|
3280
3123
|
return "\u2605".repeat(rating) + "\u2606".repeat(5 - rating);
|
|
3281
3124
|
}
|
|
3282
3125
|
async function submitReview(body) {
|
|
3283
|
-
const spinner =
|
|
3126
|
+
const spinner = ora9("Submitting review...").start();
|
|
3284
3127
|
try {
|
|
3285
3128
|
await apiRequest("/api/reviews", { method: "POST", body });
|
|
3286
3129
|
spinner.succeed("Review submitted");
|
|
3287
3130
|
trackEvent("review_submitted", { rating: body.rating, would_recommend: body.wouldRecommend });
|
|
3288
|
-
console.log(
|
|
3131
|
+
console.log(chalk13.green.bold("\n Thank you for your feedback!\n"));
|
|
3289
3132
|
} catch (err) {
|
|
3290
3133
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3291
3134
|
spinner.fail(`Failed to submit review: ${msg}`);
|
|
@@ -3296,37 +3139,37 @@ async function submitReview(body) {
|
|
|
3296
3139
|
async function reviewCommand(message, options) {
|
|
3297
3140
|
const auth2 = getStoredAuth();
|
|
3298
3141
|
if (!auth2) {
|
|
3299
|
-
console.log(
|
|
3142
|
+
console.log(chalk13.red("\n Not authenticated. Run `caliber login` first.\n"));
|
|
3300
3143
|
throw new Error("__exit__");
|
|
3301
3144
|
}
|
|
3302
3145
|
if (message) {
|
|
3303
3146
|
const rating2 = options.rating ? parseInt(options.rating, 10) : 5;
|
|
3304
3147
|
if (rating2 < 1 || rating2 > 5 || isNaN(rating2)) {
|
|
3305
|
-
console.log(
|
|
3148
|
+
console.log(chalk13.red("Rating must be between 1 and 5."));
|
|
3306
3149
|
throw new Error("__exit__");
|
|
3307
3150
|
}
|
|
3308
|
-
console.log(
|
|
3151
|
+
console.log(chalk13.dim(`
|
|
3309
3152
|
${starRating(rating2)} "${message}"
|
|
3310
3153
|
`));
|
|
3311
3154
|
await submitReview({ rating: rating2, bestPart: message, biggestGap: "", wouldRecommend: "yes" });
|
|
3312
3155
|
return;
|
|
3313
3156
|
}
|
|
3314
|
-
console.log(
|
|
3315
|
-
console.log(
|
|
3316
|
-
console.log(
|
|
3317
|
-
console.log(
|
|
3157
|
+
console.log(chalk13.hex("#6366f1").bold("\n Share your feedback\n"));
|
|
3158
|
+
console.log(chalk13.dim(" We'd love to hear how Caliber is working for you."));
|
|
3159
|
+
console.log(chalk13.dim(" This takes under 2 minutes.\n"));
|
|
3160
|
+
console.log(chalk13.dim(' Tip: use `caliber review "your feedback"` for a quick review.\n'));
|
|
3318
3161
|
const rating = await promptRating();
|
|
3319
|
-
const bestPart = await prompt(
|
|
3320
|
-
const biggestGap = await prompt(
|
|
3162
|
+
const bestPart = await prompt(chalk13.cyan("\n What did you find most useful? "));
|
|
3163
|
+
const biggestGap = await prompt(chalk13.cyan("\n What was missing or could be better? "));
|
|
3321
3164
|
const wouldRecommend = await promptRecommend();
|
|
3322
|
-
console.log(
|
|
3165
|
+
console.log(chalk13.bold("\n Your review:\n"));
|
|
3323
3166
|
console.log(` Rating: ${starRating(rating)} (${rating}/5)`);
|
|
3324
|
-
console.log(` Most useful: ${bestPart ||
|
|
3325
|
-
console.log(` Could be better: ${biggestGap ||
|
|
3167
|
+
console.log(` Most useful: ${bestPart || chalk13.dim("(skipped)")}`);
|
|
3168
|
+
console.log(` Could be better: ${biggestGap || chalk13.dim("(skipped)")}`);
|
|
3326
3169
|
console.log(` Would recommend: ${wouldRecommend}`);
|
|
3327
|
-
const shouldSubmit = await
|
|
3170
|
+
const shouldSubmit = await confirm2({ message: "Submit this review?", default: true });
|
|
3328
3171
|
if (!shouldSubmit) {
|
|
3329
|
-
console.log(
|
|
3172
|
+
console.log(chalk13.dim("\n Review cancelled.\n"));
|
|
3330
3173
|
return;
|
|
3331
3174
|
}
|
|
3332
3175
|
await submitReview({ rating, bestPart, biggestGap, wouldRecommend });
|
|
@@ -3347,7 +3190,6 @@ program.command("regenerate").alias("regen").alias("re").alias("update").descrip
|
|
|
3347
3190
|
program.command("login").description("Authenticate with Caliber").action(loginCommand);
|
|
3348
3191
|
program.command("logout").description("Clear stored credentials").action(logoutCommand);
|
|
3349
3192
|
program.command("recommend").description("Discover and manage skill recommendations").option("--generate", "Force fresh recommendation generation").option("--status <status>", "View recommendations by status: pending, accepted, dismissed").action(recommendCommand);
|
|
3350
|
-
program.command("health").description("Analyze context health and quality").option("--fix", "Generate and execute a fix plan").option("--json", "Output as JSON").action(healthCommand);
|
|
3351
3193
|
program.command("sync").description("Sync local config with server state").option("--platform <platform>", "Target platform: claude, cursor, or both").option("--dry-run", "Preview changes without writing files").action(syncCommand);
|
|
3352
3194
|
program.command("diff").description("Compare local config with server state").option("--platform <platform>", "Target platform: claude, cursor, or both").action(diffCommand);
|
|
3353
3195
|
program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(refreshCommand);
|
|
@@ -3362,9 +3204,9 @@ import fs21 from "fs";
|
|
|
3362
3204
|
import path18 from "path";
|
|
3363
3205
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3364
3206
|
import { execSync as execSync4 } from "child_process";
|
|
3365
|
-
import
|
|
3366
|
-
import
|
|
3367
|
-
import
|
|
3207
|
+
import chalk14 from "chalk";
|
|
3208
|
+
import ora10 from "ora";
|
|
3209
|
+
import confirm3 from "@inquirer/confirm";
|
|
3368
3210
|
var __dirname_vc = path18.dirname(fileURLToPath4(import.meta.url));
|
|
3369
3211
|
var pkg4 = JSON.parse(
|
|
3370
3212
|
fs21.readFileSync(path18.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
@@ -3396,37 +3238,37 @@ async function checkForUpdates() {
|
|
|
3396
3238
|
const isInteractive = process.stdin.isTTY === true;
|
|
3397
3239
|
if (!isInteractive) {
|
|
3398
3240
|
console.log(
|
|
3399
|
-
|
|
3241
|
+
chalk14.yellow(
|
|
3400
3242
|
`
|
|
3401
3243
|
Update available: ${current} -> ${latest}
|
|
3402
|
-
Run ${
|
|
3244
|
+
Run ${chalk14.bold("npm install -g @caliber-ai/cli")} to upgrade.
|
|
3403
3245
|
`
|
|
3404
3246
|
)
|
|
3405
3247
|
);
|
|
3406
3248
|
return;
|
|
3407
3249
|
}
|
|
3408
3250
|
console.log(
|
|
3409
|
-
|
|
3251
|
+
chalk14.yellow(`
|
|
3410
3252
|
Update available: ${current} -> ${latest}`)
|
|
3411
3253
|
);
|
|
3412
|
-
const shouldUpdate = await
|
|
3254
|
+
const shouldUpdate = await confirm3({ message: "Would you like to update now? (Y/n)", default: true });
|
|
3413
3255
|
if (!shouldUpdate) {
|
|
3414
3256
|
console.log();
|
|
3415
3257
|
return;
|
|
3416
3258
|
}
|
|
3417
|
-
const spinner =
|
|
3259
|
+
const spinner = ora10("Updating @caliber-ai/cli...").start();
|
|
3418
3260
|
try {
|
|
3419
3261
|
execSync4(`npm install -g @caliber-ai/cli@${latest} --prefer-online`, { stdio: "pipe", timeout: 6e4 });
|
|
3420
3262
|
const installed = getInstalledVersion();
|
|
3421
3263
|
if (installed !== latest) {
|
|
3422
3264
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
3423
|
-
console.log(
|
|
3265
|
+
console.log(chalk14.yellow(`Run ${chalk14.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually.
|
|
3424
3266
|
`));
|
|
3425
3267
|
return;
|
|
3426
3268
|
}
|
|
3427
|
-
spinner.succeed(
|
|
3269
|
+
spinner.succeed(chalk14.green(`Updated to ${latest}`));
|
|
3428
3270
|
const args = process.argv.slice(2);
|
|
3429
|
-
console.log(
|
|
3271
|
+
console.log(chalk14.dim(`
|
|
3430
3272
|
Restarting: caliber ${args.join(" ")}
|
|
3431
3273
|
`));
|
|
3432
3274
|
execSync4(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
@@ -3437,10 +3279,10 @@ Restarting: caliber ${args.join(" ")}
|
|
|
3437
3279
|
} catch (err) {
|
|
3438
3280
|
spinner.fail("Update failed");
|
|
3439
3281
|
const msg = err instanceof Error ? err.message : "";
|
|
3440
|
-
if (msg && !msg.includes("SIGTERM")) console.log(
|
|
3282
|
+
if (msg && !msg.includes("SIGTERM")) console.log(chalk14.dim(` ${msg.split("\n")[0]}`));
|
|
3441
3283
|
console.log(
|
|
3442
|
-
|
|
3443
|
-
`Run ${
|
|
3284
|
+
chalk14.yellow(
|
|
3285
|
+
`Run ${chalk14.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually to upgrade.
|
|
3444
3286
|
`
|
|
3445
3287
|
)
|
|
3446
3288
|
);
|