@caliber-ai/cli 0.16.6 → 0.17.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/dist/bin.js +95 -252
- 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) {
|
|
@@ -3165,7 +3008,8 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
3165
3008
|
}
|
|
3166
3009
|
trackEvent("refresh_completed", {
|
|
3167
3010
|
docs_updated: written.length,
|
|
3168
|
-
changed_files: diff.changedFiles.length
|
|
3011
|
+
changed_files: diff.changedFiles.length,
|
|
3012
|
+
updated_files: written
|
|
3169
3013
|
});
|
|
3170
3014
|
}
|
|
3171
3015
|
async function refreshCommand(options) {
|
|
@@ -3174,7 +3018,7 @@ async function refreshCommand(options) {
|
|
|
3174
3018
|
const auth2 = getStoredAuth();
|
|
3175
3019
|
if (!auth2) {
|
|
3176
3020
|
if (quiet) return;
|
|
3177
|
-
console.log(
|
|
3021
|
+
console.log(chalk11.red("Not authenticated. Run `caliber login` first."));
|
|
3178
3022
|
throw new Error("__exit__");
|
|
3179
3023
|
}
|
|
3180
3024
|
if (isGitRepo()) {
|
|
@@ -3184,10 +3028,10 @@ async function refreshCommand(options) {
|
|
|
3184
3028
|
const repos = discoverGitRepos(process.cwd());
|
|
3185
3029
|
if (repos.length === 0) {
|
|
3186
3030
|
if (quiet) return;
|
|
3187
|
-
console.log(
|
|
3031
|
+
console.log(chalk11.red("Not inside a git repository and no git repos found in child directories."));
|
|
3188
3032
|
throw new Error("__exit__");
|
|
3189
3033
|
}
|
|
3190
|
-
log(quiet,
|
|
3034
|
+
log(quiet, chalk11.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
3191
3035
|
`));
|
|
3192
3036
|
const originalDir = process.cwd();
|
|
3193
3037
|
for (const repo of repos) {
|
|
@@ -3197,7 +3041,7 @@ async function refreshCommand(options) {
|
|
|
3197
3041
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
3198
3042
|
} catch (err) {
|
|
3199
3043
|
if (err instanceof Error && err.message === "__exit__") continue;
|
|
3200
|
-
log(quiet,
|
|
3044
|
+
log(quiet, chalk11.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
|
|
3201
3045
|
}
|
|
3202
3046
|
}
|
|
3203
3047
|
process.chdir(originalDir);
|
|
@@ -3205,46 +3049,46 @@ async function refreshCommand(options) {
|
|
|
3205
3049
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
3206
3050
|
if (quiet) return;
|
|
3207
3051
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3208
|
-
console.log(
|
|
3052
|
+
console.log(chalk11.red(`Refresh failed: ${msg}`));
|
|
3209
3053
|
throw new Error("__exit__");
|
|
3210
3054
|
}
|
|
3211
3055
|
}
|
|
3212
3056
|
|
|
3213
3057
|
// src/commands/hooks.ts
|
|
3214
|
-
import
|
|
3058
|
+
import chalk12 from "chalk";
|
|
3215
3059
|
async function hooksInstallCommand() {
|
|
3216
3060
|
const result = installHook();
|
|
3217
3061
|
if (result.alreadyInstalled) {
|
|
3218
|
-
console.log(
|
|
3062
|
+
console.log(chalk12.dim("Hook already installed."));
|
|
3219
3063
|
return;
|
|
3220
3064
|
}
|
|
3221
|
-
console.log(
|
|
3222
|
-
console.log(
|
|
3065
|
+
console.log(chalk12.green("\u2713") + " SessionEnd hook installed in .claude/settings.json");
|
|
3066
|
+
console.log(chalk12.dim(" Docs will auto-refresh when Claude Code sessions end."));
|
|
3223
3067
|
}
|
|
3224
3068
|
async function hooksRemoveCommand() {
|
|
3225
3069
|
const result = removeHook();
|
|
3226
3070
|
if (result.notFound) {
|
|
3227
|
-
console.log(
|
|
3071
|
+
console.log(chalk12.dim("Hook not found."));
|
|
3228
3072
|
return;
|
|
3229
3073
|
}
|
|
3230
|
-
console.log(
|
|
3074
|
+
console.log(chalk12.green("\u2713") + " SessionEnd hook removed from .claude/settings.json");
|
|
3231
3075
|
}
|
|
3232
3076
|
async function hooksStatusCommand() {
|
|
3233
3077
|
const installed = isHookInstalled();
|
|
3234
3078
|
if (installed) {
|
|
3235
|
-
console.log(
|
|
3079
|
+
console.log(chalk12.green("\u2713") + " Auto-refresh hook is " + chalk12.green("installed"));
|
|
3236
3080
|
} else {
|
|
3237
|
-
console.log(
|
|
3238
|
-
console.log(
|
|
3081
|
+
console.log(chalk12.dim("\u2717") + " Auto-refresh hook is " + chalk12.yellow("not installed"));
|
|
3082
|
+
console.log(chalk12.dim(" Run `caliber hooks install` to enable auto-refresh on session end."));
|
|
3239
3083
|
}
|
|
3240
3084
|
}
|
|
3241
3085
|
|
|
3242
3086
|
// src/commands/review.ts
|
|
3243
|
-
import
|
|
3087
|
+
import chalk13 from "chalk";
|
|
3244
3088
|
import readline2 from "readline";
|
|
3245
|
-
import
|
|
3089
|
+
import ora9 from "ora";
|
|
3246
3090
|
import select2 from "@inquirer/select";
|
|
3247
|
-
import
|
|
3091
|
+
import confirm2 from "@inquirer/confirm";
|
|
3248
3092
|
function prompt(question) {
|
|
3249
3093
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3250
3094
|
return new Promise((resolve2) => {
|
|
@@ -3280,12 +3124,12 @@ function starRating(rating) {
|
|
|
3280
3124
|
return "\u2605".repeat(rating) + "\u2606".repeat(5 - rating);
|
|
3281
3125
|
}
|
|
3282
3126
|
async function submitReview(body) {
|
|
3283
|
-
const spinner =
|
|
3127
|
+
const spinner = ora9("Submitting review...").start();
|
|
3284
3128
|
try {
|
|
3285
3129
|
await apiRequest("/api/reviews", { method: "POST", body });
|
|
3286
3130
|
spinner.succeed("Review submitted");
|
|
3287
3131
|
trackEvent("review_submitted", { rating: body.rating, would_recommend: body.wouldRecommend });
|
|
3288
|
-
console.log(
|
|
3132
|
+
console.log(chalk13.green.bold("\n Thank you for your feedback!\n"));
|
|
3289
3133
|
} catch (err) {
|
|
3290
3134
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3291
3135
|
spinner.fail(`Failed to submit review: ${msg}`);
|
|
@@ -3296,37 +3140,37 @@ async function submitReview(body) {
|
|
|
3296
3140
|
async function reviewCommand(message, options) {
|
|
3297
3141
|
const auth2 = getStoredAuth();
|
|
3298
3142
|
if (!auth2) {
|
|
3299
|
-
console.log(
|
|
3143
|
+
console.log(chalk13.red("\n Not authenticated. Run `caliber login` first.\n"));
|
|
3300
3144
|
throw new Error("__exit__");
|
|
3301
3145
|
}
|
|
3302
3146
|
if (message) {
|
|
3303
3147
|
const rating2 = options.rating ? parseInt(options.rating, 10) : 5;
|
|
3304
3148
|
if (rating2 < 1 || rating2 > 5 || isNaN(rating2)) {
|
|
3305
|
-
console.log(
|
|
3149
|
+
console.log(chalk13.red("Rating must be between 1 and 5."));
|
|
3306
3150
|
throw new Error("__exit__");
|
|
3307
3151
|
}
|
|
3308
|
-
console.log(
|
|
3152
|
+
console.log(chalk13.dim(`
|
|
3309
3153
|
${starRating(rating2)} "${message}"
|
|
3310
3154
|
`));
|
|
3311
3155
|
await submitReview({ rating: rating2, bestPart: message, biggestGap: "", wouldRecommend: "yes" });
|
|
3312
3156
|
return;
|
|
3313
3157
|
}
|
|
3314
|
-
console.log(
|
|
3315
|
-
console.log(
|
|
3316
|
-
console.log(
|
|
3317
|
-
console.log(
|
|
3158
|
+
console.log(chalk13.hex("#6366f1").bold("\n Share your feedback\n"));
|
|
3159
|
+
console.log(chalk13.dim(" We'd love to hear how Caliber is working for you."));
|
|
3160
|
+
console.log(chalk13.dim(" This takes under 2 minutes.\n"));
|
|
3161
|
+
console.log(chalk13.dim(' Tip: use `caliber review "your feedback"` for a quick review.\n'));
|
|
3318
3162
|
const rating = await promptRating();
|
|
3319
|
-
const bestPart = await prompt(
|
|
3320
|
-
const biggestGap = await prompt(
|
|
3163
|
+
const bestPart = await prompt(chalk13.cyan("\n What did you find most useful? "));
|
|
3164
|
+
const biggestGap = await prompt(chalk13.cyan("\n What was missing or could be better? "));
|
|
3321
3165
|
const wouldRecommend = await promptRecommend();
|
|
3322
|
-
console.log(
|
|
3166
|
+
console.log(chalk13.bold("\n Your review:\n"));
|
|
3323
3167
|
console.log(` Rating: ${starRating(rating)} (${rating}/5)`);
|
|
3324
|
-
console.log(` Most useful: ${bestPart ||
|
|
3325
|
-
console.log(` Could be better: ${biggestGap ||
|
|
3168
|
+
console.log(` Most useful: ${bestPart || chalk13.dim("(skipped)")}`);
|
|
3169
|
+
console.log(` Could be better: ${biggestGap || chalk13.dim("(skipped)")}`);
|
|
3326
3170
|
console.log(` Would recommend: ${wouldRecommend}`);
|
|
3327
|
-
const shouldSubmit = await
|
|
3171
|
+
const shouldSubmit = await confirm2({ message: "Submit this review?", default: true });
|
|
3328
3172
|
if (!shouldSubmit) {
|
|
3329
|
-
console.log(
|
|
3173
|
+
console.log(chalk13.dim("\n Review cancelled.\n"));
|
|
3330
3174
|
return;
|
|
3331
3175
|
}
|
|
3332
3176
|
await submitReview({ rating, bestPart, biggestGap, wouldRecommend });
|
|
@@ -3347,7 +3191,6 @@ program.command("regenerate").alias("regen").alias("re").alias("update").descrip
|
|
|
3347
3191
|
program.command("login").description("Authenticate with Caliber").action(loginCommand);
|
|
3348
3192
|
program.command("logout").description("Clear stored credentials").action(logoutCommand);
|
|
3349
3193
|
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
3194
|
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
3195
|
program.command("diff").description("Compare local config with server state").option("--platform <platform>", "Target platform: claude, cursor, or both").action(diffCommand);
|
|
3353
3196
|
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 +3205,9 @@ import fs21 from "fs";
|
|
|
3362
3205
|
import path18 from "path";
|
|
3363
3206
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3364
3207
|
import { execSync as execSync4 } from "child_process";
|
|
3365
|
-
import
|
|
3366
|
-
import
|
|
3367
|
-
import
|
|
3208
|
+
import chalk14 from "chalk";
|
|
3209
|
+
import ora10 from "ora";
|
|
3210
|
+
import confirm3 from "@inquirer/confirm";
|
|
3368
3211
|
var __dirname_vc = path18.dirname(fileURLToPath4(import.meta.url));
|
|
3369
3212
|
var pkg4 = JSON.parse(
|
|
3370
3213
|
fs21.readFileSync(path18.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
@@ -3396,37 +3239,37 @@ async function checkForUpdates() {
|
|
|
3396
3239
|
const isInteractive = process.stdin.isTTY === true;
|
|
3397
3240
|
if (!isInteractive) {
|
|
3398
3241
|
console.log(
|
|
3399
|
-
|
|
3242
|
+
chalk14.yellow(
|
|
3400
3243
|
`
|
|
3401
3244
|
Update available: ${current} -> ${latest}
|
|
3402
|
-
Run ${
|
|
3245
|
+
Run ${chalk14.bold("npm install -g @caliber-ai/cli")} to upgrade.
|
|
3403
3246
|
`
|
|
3404
3247
|
)
|
|
3405
3248
|
);
|
|
3406
3249
|
return;
|
|
3407
3250
|
}
|
|
3408
3251
|
console.log(
|
|
3409
|
-
|
|
3252
|
+
chalk14.yellow(`
|
|
3410
3253
|
Update available: ${current} -> ${latest}`)
|
|
3411
3254
|
);
|
|
3412
|
-
const shouldUpdate = await
|
|
3255
|
+
const shouldUpdate = await confirm3({ message: "Would you like to update now? (Y/n)", default: true });
|
|
3413
3256
|
if (!shouldUpdate) {
|
|
3414
3257
|
console.log();
|
|
3415
3258
|
return;
|
|
3416
3259
|
}
|
|
3417
|
-
const spinner =
|
|
3260
|
+
const spinner = ora10("Updating @caliber-ai/cli...").start();
|
|
3418
3261
|
try {
|
|
3419
3262
|
execSync4(`npm install -g @caliber-ai/cli@${latest} --prefer-online`, { stdio: "pipe", timeout: 6e4 });
|
|
3420
3263
|
const installed = getInstalledVersion();
|
|
3421
3264
|
if (installed !== latest) {
|
|
3422
3265
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
3423
|
-
console.log(
|
|
3266
|
+
console.log(chalk14.yellow(`Run ${chalk14.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually.
|
|
3424
3267
|
`));
|
|
3425
3268
|
return;
|
|
3426
3269
|
}
|
|
3427
|
-
spinner.succeed(
|
|
3270
|
+
spinner.succeed(chalk14.green(`Updated to ${latest}`));
|
|
3428
3271
|
const args = process.argv.slice(2);
|
|
3429
|
-
console.log(
|
|
3272
|
+
console.log(chalk14.dim(`
|
|
3430
3273
|
Restarting: caliber ${args.join(" ")}
|
|
3431
3274
|
`));
|
|
3432
3275
|
execSync4(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
@@ -3437,10 +3280,10 @@ Restarting: caliber ${args.join(" ")}
|
|
|
3437
3280
|
} catch (err) {
|
|
3438
3281
|
spinner.fail("Update failed");
|
|
3439
3282
|
const msg = err instanceof Error ? err.message : "";
|
|
3440
|
-
if (msg && !msg.includes("SIGTERM")) console.log(
|
|
3283
|
+
if (msg && !msg.includes("SIGTERM")) console.log(chalk14.dim(` ${msg.split("\n")[0]}`));
|
|
3441
3284
|
console.log(
|
|
3442
|
-
|
|
3443
|
-
`Run ${
|
|
3285
|
+
chalk14.yellow(
|
|
3286
|
+
`Run ${chalk14.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually to upgrade.
|
|
3444
3287
|
`
|
|
3445
3288
|
)
|
|
3446
3289
|
);
|