@caliber-ai/cli 0.12.0 → 0.14.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 +234 -93
- package/dist/bin.js.map +1 -1
- package/package.json +4 -2
package/dist/bin.js
CHANGED
|
@@ -1709,10 +1709,10 @@ async function initCommand(options) {
|
|
|
1709
1709
|
console.log(chalk3.dim(" your project's stack and conventions.\n"));
|
|
1710
1710
|
console.log(chalk3.dim(" This usually takes 1\u20133 minutes on first run.\n"));
|
|
1711
1711
|
let generatedSetup = null;
|
|
1712
|
-
let setupExplanation;
|
|
1713
1712
|
let rawOutput;
|
|
1714
1713
|
trackEvent("generation_started", { target_agent: targetAgent });
|
|
1715
1714
|
const hasExistingConfig = !!(ec.claudeMd || ec.claudeSettings || ec.claudeSkills?.length || ec.cursorrules || ec.cursorRules?.length || ec.claudeMcpServers || ec.cursorMcpServers);
|
|
1715
|
+
const genStartTime = Date.now();
|
|
1716
1716
|
const genSpinner = ora2("Generating setup...").start();
|
|
1717
1717
|
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
|
|
1718
1718
|
genMessages.start();
|
|
@@ -1729,7 +1729,6 @@ async function initCommand(options) {
|
|
|
1729
1729
|
},
|
|
1730
1730
|
(payload) => {
|
|
1731
1731
|
generatedSetup = payload.setup;
|
|
1732
|
-
setupExplanation = payload.explanation;
|
|
1733
1732
|
rawOutput = payload.raw;
|
|
1734
1733
|
},
|
|
1735
1734
|
(error) => {
|
|
@@ -1757,21 +1756,19 @@ async function initCommand(options) {
|
|
|
1757
1756
|
}
|
|
1758
1757
|
throw new Error("__exit__");
|
|
1759
1758
|
}
|
|
1760
|
-
|
|
1759
|
+
const elapsedMs = Date.now() - genStartTime;
|
|
1760
|
+
const mins = Math.floor(elapsedMs / 6e4);
|
|
1761
|
+
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
1762
|
+
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
1763
|
+
genSpinner.succeed(`Setup generated ${chalk3.dim(`in ${timeStr}`)}`);
|
|
1761
1764
|
printSetupSummary(generatedSetup);
|
|
1762
1765
|
console.log(chalk3.hex("#6366f1").bold(" Step 5/6 \u2014 Review\n"));
|
|
1763
|
-
console.log(chalk3.dim(" Review the proposed files
|
|
1764
|
-
console.log(chalk3.dim(" or
|
|
1765
|
-
let
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
printExplanation(setupExplanation);
|
|
1770
|
-
} else {
|
|
1771
|
-
console.log(chalk3.dim("\nNo explanation available for this setup.\n"));
|
|
1772
|
-
}
|
|
1773
|
-
explained = true;
|
|
1774
|
-
action = await promptAction(explained);
|
|
1766
|
+
console.log(chalk3.dim(" Review the proposed files. You can accept, refine via chat,"));
|
|
1767
|
+
console.log(chalk3.dim(" or preview any file to see exactly what will be written.\n"));
|
|
1768
|
+
let action = await promptAction();
|
|
1769
|
+
while (action === "preview") {
|
|
1770
|
+
await promptFilePreview(generatedSetup);
|
|
1771
|
+
action = await promptAction();
|
|
1775
1772
|
}
|
|
1776
1773
|
if (action === "decline") {
|
|
1777
1774
|
trackEvent("setup_declined");
|
|
@@ -1856,6 +1853,11 @@ async function initCommand(options) {
|
|
|
1856
1853
|
}
|
|
1857
1854
|
console.log(chalk3.bold.green("\nSetup complete! Your coding agent is now configured."));
|
|
1858
1855
|
console.log(chalk3.dim("Run `caliber undo` to revert changes.\n"));
|
|
1856
|
+
console.log(chalk3.bold(" Next steps:\n"));
|
|
1857
|
+
console.log(` ${chalk3.hex("#6366f1")("caliber health")} Check your config quality and fix issues`);
|
|
1858
|
+
console.log(` ${chalk3.hex("#6366f1")("caliber recommend")} Discover additional skills for your stack`);
|
|
1859
|
+
console.log(` ${chalk3.hex("#6366f1")("caliber diff")} See what changed since last setup`);
|
|
1860
|
+
console.log("");
|
|
1859
1861
|
}
|
|
1860
1862
|
async function refineLoop(currentSetup, _targetAgent) {
|
|
1861
1863
|
const history = [];
|
|
@@ -1920,93 +1922,187 @@ async function promptAgent() {
|
|
|
1920
1922
|
]
|
|
1921
1923
|
});
|
|
1922
1924
|
}
|
|
1923
|
-
async function promptAction(
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
const icon = fs16.existsSync(filePath) ? chalk3.yellow("~") : chalk3.green("+");
|
|
1934
|
-
const description = desc ? chalk3.dim(`\u2014 ${desc}`) : "";
|
|
1935
|
-
return ` ${icon} ${filePath} ${description}`;
|
|
1925
|
+
async function promptAction() {
|
|
1926
|
+
return select({
|
|
1927
|
+
message: "What would you like to do?",
|
|
1928
|
+
choices: [
|
|
1929
|
+
{ name: "Accept and apply", value: "accept" },
|
|
1930
|
+
{ name: "Refine via chat", value: "refine" },
|
|
1931
|
+
{ name: "Preview a file", value: "preview" },
|
|
1932
|
+
{ name: "Decline", value: "decline" }
|
|
1933
|
+
]
|
|
1934
|
+
});
|
|
1936
1935
|
}
|
|
1937
1936
|
function printSetupSummary(setup) {
|
|
1938
1937
|
const claude = setup.claude;
|
|
1939
1938
|
const cursor = setup.cursor;
|
|
1940
|
-
const descriptions = setup.fileDescriptions || {};
|
|
1941
1939
|
console.log("");
|
|
1940
|
+
console.log(chalk3.bold(" Files to create:\n"));
|
|
1942
1941
|
if (claude) {
|
|
1943
1942
|
if (claude.claudeMd) {
|
|
1944
|
-
|
|
1943
|
+
const icon = fs16.existsSync("CLAUDE.md") ? chalk3.yellow("~") : chalk3.green("+");
|
|
1944
|
+
const sections = extractClaudeMdSections(claude.claudeMd);
|
|
1945
|
+
console.log(` ${icon} ${chalk3.bold("CLAUDE.md")}`);
|
|
1946
|
+
console.log(chalk3.dim(" Your project's knowledge base for the AI agent \u2014 architecture, build"));
|
|
1947
|
+
console.log(chalk3.dim(" commands, conventions. Claude reads this at the start of every session."));
|
|
1948
|
+
if (sections.length > 0) {
|
|
1949
|
+
console.log(chalk3.dim(` Sections: ${sections.join(", ")}`));
|
|
1950
|
+
}
|
|
1951
|
+
console.log("");
|
|
1945
1952
|
}
|
|
1946
1953
|
if (claude.settings) {
|
|
1947
|
-
|
|
1954
|
+
const icon = fs16.existsSync(".claude/settings.json") ? chalk3.yellow("~") : chalk3.green("+");
|
|
1955
|
+
const settings = claude.settings;
|
|
1956
|
+
const perms = settings.permissions?.allow || [];
|
|
1957
|
+
console.log(` ${icon} ${chalk3.bold(".claude/settings.json")}`);
|
|
1958
|
+
console.log(chalk3.dim(" Pre-approved shell commands so Claude doesn't ask permission each time."));
|
|
1959
|
+
if (perms.length > 0) {
|
|
1960
|
+
console.log(chalk3.dim(` Allows: ${summarizePermissions(perms)}`));
|
|
1961
|
+
}
|
|
1962
|
+
console.log("");
|
|
1948
1963
|
}
|
|
1949
1964
|
if (claude.settingsLocal) {
|
|
1950
|
-
|
|
1965
|
+
const icon = fs16.existsSync(".claude/settings.local.json") ? chalk3.yellow("~") : chalk3.green("+");
|
|
1966
|
+
const settings = claude.settingsLocal;
|
|
1967
|
+
const perms = settings.permissions?.allow || [];
|
|
1968
|
+
console.log(` ${icon} ${chalk3.bold(".claude/settings.local.json")}`);
|
|
1969
|
+
console.log(chalk3.dim(" Your personal permission overrides (not shared with teammates)."));
|
|
1970
|
+
if (perms.length > 0) {
|
|
1971
|
+
console.log(chalk3.dim(` Allows: ${summarizePermissions(perms)}`));
|
|
1972
|
+
}
|
|
1973
|
+
console.log("");
|
|
1951
1974
|
}
|
|
1952
1975
|
const skills = claude.skills;
|
|
1953
1976
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
1954
1977
|
for (const skill of skills) {
|
|
1955
1978
|
const skillPath = `.claude/skills/${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
|
|
1956
|
-
|
|
1979
|
+
const icon = fs16.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
|
|
1980
|
+
console.log(` ${icon} ${chalk3.bold(skillPath)}`);
|
|
1981
|
+
console.log(chalk3.dim(` ${summarizeSkill(skill)}`));
|
|
1982
|
+
console.log("");
|
|
1957
1983
|
}
|
|
1958
1984
|
}
|
|
1959
1985
|
const mcpServers = claude.mcpServers;
|
|
1960
1986
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
1961
|
-
|
|
1987
|
+
const icon = fs16.existsSync(".mcp.json") ? chalk3.yellow("~") : chalk3.green("+");
|
|
1988
|
+
const serverNames = Object.keys(mcpServers);
|
|
1989
|
+
console.log(` ${icon} ${chalk3.bold(".mcp.json")}`);
|
|
1990
|
+
console.log(chalk3.dim(" Connects Claude to external tools it can call directly."));
|
|
1991
|
+
console.log(chalk3.dim(` Servers: ${serverNames.join(", ")}`));
|
|
1992
|
+
console.log("");
|
|
1962
1993
|
}
|
|
1963
1994
|
}
|
|
1964
1995
|
if (cursor) {
|
|
1965
1996
|
if (cursor.cursorrules) {
|
|
1966
|
-
|
|
1997
|
+
const icon = fs16.existsSync(".cursorrules") ? chalk3.yellow("~") : chalk3.green("+");
|
|
1998
|
+
console.log(` ${icon} ${chalk3.bold(".cursorrules")}`);
|
|
1999
|
+
console.log(chalk3.dim(" Project-wide instructions for Cursor \u2014 coding style, architecture,"));
|
|
2000
|
+
console.log(chalk3.dim(" and conventions. Cursor reads this at the start of every session."));
|
|
2001
|
+
console.log("");
|
|
1967
2002
|
}
|
|
1968
2003
|
const rules = cursor.rules;
|
|
1969
2004
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
1970
2005
|
for (const rule of rules) {
|
|
1971
2006
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
1972
|
-
|
|
2007
|
+
const icon = fs16.existsSync(rulePath) ? chalk3.yellow("~") : chalk3.green("+");
|
|
2008
|
+
console.log(` ${icon} ${chalk3.bold(rulePath)}`);
|
|
2009
|
+
const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
|
|
2010
|
+
if (firstLine) console.log(chalk3.dim(` ${firstLine.trim().slice(0, 80)}`));
|
|
2011
|
+
console.log("");
|
|
1973
2012
|
}
|
|
1974
2013
|
}
|
|
1975
2014
|
const mcpServers = cursor.mcpServers;
|
|
1976
2015
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
1977
|
-
|
|
2016
|
+
const icon = fs16.existsSync(".cursor/mcp.json") ? chalk3.yellow("~") : chalk3.green("+");
|
|
2017
|
+
const serverNames = Object.keys(mcpServers);
|
|
2018
|
+
console.log(` ${icon} ${chalk3.bold(".cursor/mcp.json")}`);
|
|
2019
|
+
console.log(chalk3.dim(" Connects Cursor to external tools it can call directly."));
|
|
2020
|
+
console.log(chalk3.dim(` Servers: ${serverNames.join(", ")}`));
|
|
2021
|
+
console.log("");
|
|
1978
2022
|
}
|
|
1979
2023
|
}
|
|
1980
|
-
console.log("");
|
|
1981
2024
|
console.log(` ${chalk3.green("+")} ${chalk3.dim("new")} ${chalk3.yellow("~")} ${chalk3.dim("modified")}`);
|
|
1982
2025
|
console.log("");
|
|
1983
2026
|
}
|
|
1984
|
-
function
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2027
|
+
function extractClaudeMdSections(md) {
|
|
2028
|
+
return md.split("\n").filter((line) => /^##\s+/.test(line)).map((line) => line.replace(/^##\s+/, "").trim());
|
|
2029
|
+
}
|
|
2030
|
+
function summarizePermissions(permissions, maxShow = 3) {
|
|
2031
|
+
if (permissions.length === 0) return "None";
|
|
2032
|
+
const shown = permissions.slice(0, maxShow).join(", ");
|
|
2033
|
+
const remaining = permissions.length - maxShow;
|
|
2034
|
+
return remaining > 0 ? `${shown} (+${remaining} more)` : shown;
|
|
2035
|
+
}
|
|
2036
|
+
function summarizeSkill(skill) {
|
|
2037
|
+
const lines = skill.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"));
|
|
2038
|
+
return lines[0]?.trim().slice(0, 80) || skill.name;
|
|
2039
|
+
}
|
|
2040
|
+
function collectSetupFiles(setup) {
|
|
2041
|
+
const files = [];
|
|
2042
|
+
const claude = setup.claude;
|
|
2043
|
+
const cursor = setup.cursor;
|
|
2044
|
+
if (claude) {
|
|
2045
|
+
if (claude.claudeMd) files.push({ path: "CLAUDE.md", content: claude.claudeMd });
|
|
2046
|
+
if (claude.settings) files.push({ path: ".claude/settings.json", content: JSON.stringify(claude.settings, null, 2) });
|
|
2047
|
+
if (claude.settingsLocal) files.push({ path: ".claude/settings.local.json", content: JSON.stringify(claude.settingsLocal, null, 2) });
|
|
2048
|
+
const skills = claude.skills;
|
|
2049
|
+
if (Array.isArray(skills)) {
|
|
2050
|
+
for (const skill of skills) {
|
|
2051
|
+
const skillPath = `.claude/skills/${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
|
|
2052
|
+
files.push({ path: skillPath, content: skill.content });
|
|
2053
|
+
}
|
|
1994
2054
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
const name = itemMatch[1];
|
|
1998
|
-
const desc = itemMatch[2].replace(/^\s*[-—:]\s*/, "");
|
|
1999
|
-
console.log(` ${chalk3.dim("\u25B8")} ${chalk3.white(name)} ${chalk3.dim(desc)}`);
|
|
2000
|
-
continue;
|
|
2055
|
+
if (claude.mcpServers && Object.keys(claude.mcpServers).length > 0) {
|
|
2056
|
+
files.push({ path: ".mcp.json", content: JSON.stringify({ mcpServers: claude.mcpServers }, null, 2) });
|
|
2001
2057
|
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2058
|
+
}
|
|
2059
|
+
if (cursor) {
|
|
2060
|
+
if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
|
|
2061
|
+
const rules = cursor.rules;
|
|
2062
|
+
if (Array.isArray(rules)) {
|
|
2063
|
+
for (const rule of rules) {
|
|
2064
|
+
files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
if (cursor.mcpServers && Object.keys(cursor.mcpServers).length > 0) {
|
|
2068
|
+
files.push({ path: ".cursor/mcp.json", content: JSON.stringify({ mcpServers: cursor.mcpServers }, null, 2) });
|
|
2006
2069
|
}
|
|
2007
|
-
console.log(` ${chalk3.dim(trimmed)}`);
|
|
2008
2070
|
}
|
|
2071
|
+
return files;
|
|
2072
|
+
}
|
|
2073
|
+
function previewFileContent(filePath, content, maxLines = 25) {
|
|
2074
|
+
const lines = content.split("\n");
|
|
2075
|
+
const displayLines = lines.slice(0, maxLines);
|
|
2076
|
+
const maxWidth = Math.max(60, ...displayLines.map((l) => l.length + 4));
|
|
2077
|
+
const width = Math.min(maxWidth, 80);
|
|
2009
2078
|
console.log("");
|
|
2079
|
+
console.log(` ${chalk3.dim("\u250C\u2500")} ${chalk3.bold(filePath)} ${chalk3.dim("\u2500".repeat(Math.max(0, width - filePath.length - 5)) + "\u2510")}`);
|
|
2080
|
+
console.log(` ${chalk3.dim("\u2502")}${" ".repeat(width - 1)}${chalk3.dim("\u2502")}`);
|
|
2081
|
+
for (const line of displayLines) {
|
|
2082
|
+
const truncated = line.length > width - 5 ? line.slice(0, width - 8) + "..." : line;
|
|
2083
|
+
const padding = " ".repeat(Math.max(0, width - truncated.length - 3));
|
|
2084
|
+
console.log(` ${chalk3.dim("\u2502")} ${truncated}${padding}${chalk3.dim("\u2502")}`);
|
|
2085
|
+
}
|
|
2086
|
+
if (lines.length > maxLines) {
|
|
2087
|
+
console.log(` ${chalk3.dim("\u2502")}${" ".repeat(width - 1)}${chalk3.dim("\u2502")}`);
|
|
2088
|
+
const note = `(showing first ${maxLines} lines, full file is ${lines.length} lines)`;
|
|
2089
|
+
const notePadding = " ".repeat(Math.max(0, width - note.length - 3));
|
|
2090
|
+
console.log(` ${chalk3.dim("\u2502")} ${chalk3.dim(note)}${notePadding}${chalk3.dim("\u2502")}`);
|
|
2091
|
+
}
|
|
2092
|
+
console.log(` ${chalk3.dim("\u2514" + "\u2500".repeat(width - 1) + "\u2518")}`);
|
|
2093
|
+
console.log("");
|
|
2094
|
+
}
|
|
2095
|
+
async function promptFilePreview(setup) {
|
|
2096
|
+
const files = collectSetupFiles(setup);
|
|
2097
|
+
if (files.length === 0) {
|
|
2098
|
+
console.log(chalk3.dim("\n No files to preview.\n"));
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
const choice = await select({
|
|
2102
|
+
message: "Which file to preview?",
|
|
2103
|
+
choices: files.map((f, i) => ({ name: f.path, value: i }))
|
|
2104
|
+
});
|
|
2105
|
+
previewFileContent(files[choice].path, files[choice].content);
|
|
2010
2106
|
}
|
|
2011
2107
|
|
|
2012
2108
|
// src/commands/undo.ts
|
|
@@ -2099,11 +2195,11 @@ async function statusCommand(options) {
|
|
|
2099
2195
|
console.log("");
|
|
2100
2196
|
}
|
|
2101
2197
|
|
|
2102
|
-
// src/commands/
|
|
2198
|
+
// src/commands/regenerate.ts
|
|
2103
2199
|
import chalk6 from "chalk";
|
|
2104
2200
|
import ora4 from "ora";
|
|
2105
2201
|
import confirm from "@inquirer/confirm";
|
|
2106
|
-
async function
|
|
2202
|
+
async function regenerateCommand(options) {
|
|
2107
2203
|
const auth2 = getStoredAuth();
|
|
2108
2204
|
if (!auth2) {
|
|
2109
2205
|
console.log(chalk6.red("Not logged in. Run `caliber login` first."));
|
|
@@ -2147,7 +2243,7 @@ async function updateCommand(options) {
|
|
|
2147
2243
|
},
|
|
2148
2244
|
(error) => {
|
|
2149
2245
|
genMessages.stop();
|
|
2150
|
-
trackEvent("error_occurred", { error_type: "generation_failed", error_message: error, command: "
|
|
2246
|
+
trackEvent("error_occurred", { error_type: "generation_failed", error_message: error, command: "regenerate" });
|
|
2151
2247
|
genSpinner.fail(`Generation error: ${error}`);
|
|
2152
2248
|
},
|
|
2153
2249
|
(status) => {
|
|
@@ -2157,7 +2253,7 @@ async function updateCommand(options) {
|
|
|
2157
2253
|
} catch (err) {
|
|
2158
2254
|
genMessages.stop();
|
|
2159
2255
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
2160
|
-
trackEvent("error_occurred", { error_type: "generation_request_failed", error_message: msg, command: "
|
|
2256
|
+
trackEvent("error_occurred", { error_type: "generation_request_failed", error_message: msg, command: "regenerate" });
|
|
2161
2257
|
genSpinner.fail(`Regeneration failed: ${msg}`);
|
|
2162
2258
|
throw new Error("__exit__");
|
|
2163
2259
|
}
|
|
@@ -2172,16 +2268,16 @@ async function updateCommand(options) {
|
|
|
2172
2268
|
console.log(JSON.stringify(generatedSetup, null, 2));
|
|
2173
2269
|
return;
|
|
2174
2270
|
}
|
|
2175
|
-
const shouldApply = await confirm({ message: "Apply
|
|
2271
|
+
const shouldApply = await confirm({ message: "Apply regenerated setup?", default: true });
|
|
2176
2272
|
if (!shouldApply) {
|
|
2177
|
-
trackEvent("
|
|
2178
|
-
console.log(chalk6.dim("
|
|
2273
|
+
trackEvent("regenerate_declined");
|
|
2274
|
+
console.log(chalk6.dim("Regeneration cancelled."));
|
|
2179
2275
|
return;
|
|
2180
2276
|
}
|
|
2181
2277
|
const writeSpinner = ora4("Updating config files...").start();
|
|
2182
2278
|
const result = writeSetup(generatedSetup);
|
|
2183
2279
|
writeSpinner.succeed("Config files updated");
|
|
2184
|
-
trackEvent("
|
|
2280
|
+
trackEvent("setup_regenerated", { files_written: result.written.length });
|
|
2185
2281
|
for (const file of result.written) {
|
|
2186
2282
|
console.log(` ${chalk6.green("\u2713")} ${file}`);
|
|
2187
2283
|
}
|
|
@@ -2416,6 +2512,7 @@ function printRecommendations(recs) {
|
|
|
2416
2512
|
// src/commands/health.ts
|
|
2417
2513
|
import chalk9 from "chalk";
|
|
2418
2514
|
import ora6 from "ora";
|
|
2515
|
+
import confirm2 from "@inquirer/confirm";
|
|
2419
2516
|
async function healthCommand(options) {
|
|
2420
2517
|
const auth2 = getStoredAuth();
|
|
2421
2518
|
if (!auth2) {
|
|
@@ -2450,30 +2547,44 @@ async function healthCommand(options) {
|
|
|
2450
2547
|
return;
|
|
2451
2548
|
}
|
|
2452
2549
|
printReport(report);
|
|
2453
|
-
|
|
2454
|
-
|
|
2550
|
+
const shouldFix = options.fix || report.recommendations.length > 0 && !options.json && await confirm2({ message: "Would you like to fix these issues?", default: true });
|
|
2551
|
+
if (shouldFix) {
|
|
2552
|
+
const planSpinner = ora6("Generating fix plan...").start();
|
|
2455
2553
|
const plan = await apiRequest(
|
|
2456
2554
|
`/api/context/reports/${report.id}/fix-plan`,
|
|
2457
2555
|
{ method: "POST", body: { projectId } }
|
|
2458
2556
|
);
|
|
2557
|
+
planSpinner.succeed("Fix plan ready");
|
|
2459
2558
|
if (!plan?.actions.length) {
|
|
2460
|
-
console.log(chalk9.dim("No fixes needed."));
|
|
2559
|
+
console.log(chalk9.dim(" No fixes needed."));
|
|
2461
2560
|
return;
|
|
2462
2561
|
}
|
|
2463
|
-
console.log(chalk9.bold("\
|
|
2562
|
+
console.log(chalk9.bold("\n Fix Plan:\n"));
|
|
2464
2563
|
for (const action of plan.actions) {
|
|
2465
|
-
|
|
2466
|
-
|
|
2564
|
+
if (action.type === "remove") {
|
|
2565
|
+
console.log(` ${chalk9.red("\u2717 Remove")} ${action.items.join(", ")}`);
|
|
2566
|
+
if (action.reason) console.log(chalk9.dim(` ${action.reason}`));
|
|
2567
|
+
} else if (action.type === "add") {
|
|
2568
|
+
console.log(` ${chalk9.green("+ Add")} ${action.items.join(", ")}`);
|
|
2569
|
+
if (action.reason) console.log(chalk9.dim(` ${action.reason}`));
|
|
2570
|
+
}
|
|
2571
|
+
console.log("");
|
|
2467
2572
|
}
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2573
|
+
const scoreAfterStr = plan.estimatedScoreAfter != null ? String(plan.estimatedScoreAfter) : `${report.score + plan.estimatedScoreImprovement}`;
|
|
2574
|
+
console.log(` Expected: ${report.score} \u2192 ${chalk9.green(scoreAfterStr)}/100
|
|
2575
|
+
`);
|
|
2576
|
+
const shouldExecute = options.fix || await confirm2({ message: "Apply this fix plan?", default: true });
|
|
2577
|
+
if (!shouldExecute) {
|
|
2578
|
+
console.log(chalk9.dim(" Fix cancelled."));
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
const fixSpinner = ora6("Applying fixes...").start();
|
|
2471
2582
|
try {
|
|
2472
2583
|
const result = await apiRequest(
|
|
2473
2584
|
`/api/context/reports/${report.id}/fix-execute`,
|
|
2474
2585
|
{ method: "POST", body: { projectId } }
|
|
2475
2586
|
);
|
|
2476
|
-
fixSpinner.succeed("
|
|
2587
|
+
fixSpinner.succeed("Fixes applied");
|
|
2477
2588
|
console.log("");
|
|
2478
2589
|
console.log(` Score: ${result.scoreBefore} \u2192 ${chalk9.green(String(result.scoreAfter))} (${chalk9.green(`+${result.improvement}`)})`);
|
|
2479
2590
|
if (result.itemsRemoved) console.log(` Removed: ${result.itemsRemoved} items`);
|
|
@@ -2486,6 +2597,13 @@ Estimated improvement: +${plan.estimatedScoreImprovement} points`));
|
|
|
2486
2597
|
}
|
|
2487
2598
|
}
|
|
2488
2599
|
}
|
|
2600
|
+
var CATEGORY_DESCRIPTIONS = {
|
|
2601
|
+
tooling: "build/test/lint commands (helps agents the most)",
|
|
2602
|
+
essential: "constraints agents can't discover from code",
|
|
2603
|
+
convention: "style/naming rules (linters handle this; low value)",
|
|
2604
|
+
overview: "project summaries (agents discover this by reading code)",
|
|
2605
|
+
workflow: "development workflows and processes"
|
|
2606
|
+
};
|
|
2489
2607
|
function printReport(report) {
|
|
2490
2608
|
const gradeColors = {
|
|
2491
2609
|
A: chalk9.green,
|
|
@@ -2498,24 +2616,43 @@ function printReport(report) {
|
|
|
2498
2616
|
console.log(chalk9.bold("\n Context Health Report\n"));
|
|
2499
2617
|
console.log(` Grade: ${gradeColor(report.grade)} Score: ${gradeColor(String(report.score))}/100
|
|
2500
2618
|
`);
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
const
|
|
2619
|
+
const categories = Object.entries(report.category_breakdown);
|
|
2620
|
+
if (categories.length) {
|
|
2621
|
+
console.log(chalk9.bold(" Category Breakdown:\n"));
|
|
2622
|
+
const itemsByCategory = /* @__PURE__ */ new Map();
|
|
2623
|
+
if (report.item_classifications) {
|
|
2624
|
+
for (const item of report.item_classifications) {
|
|
2625
|
+
const cat = item.category.toLowerCase();
|
|
2626
|
+
if (!itemsByCategory.has(cat)) itemsByCategory.set(cat, []);
|
|
2627
|
+
itemsByCategory.get(cat).push(item);
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2505
2630
|
for (const [name, data] of categories) {
|
|
2506
|
-
const
|
|
2507
|
-
const
|
|
2508
|
-
console.log(` ${
|
|
2631
|
+
const desc = CATEGORY_DESCRIPTIONS[name] || "";
|
|
2632
|
+
const header = desc ? `${chalk9.bold(name)} ${chalk9.dim(`\u2014 ${desc}`)}` : chalk9.bold(name);
|
|
2633
|
+
console.log(` ${header}`);
|
|
2634
|
+
const items = itemsByCategory.get(name);
|
|
2635
|
+
if (items?.length) {
|
|
2636
|
+
for (const item of items) {
|
|
2637
|
+
const icon = item.impactScore >= 0 ? chalk9.green("\u2713") : chalk9.red("\u2717");
|
|
2638
|
+
const snippet = item.recommendation.length > 70 ? item.recommendation.slice(0, 67) + "..." : item.recommendation;
|
|
2639
|
+
console.log(` ${icon} ${item.itemName.padEnd(22)} ${chalk9.dim(`"${snippet}"`)}`);
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
console.log(chalk9.dim(` ${data.count} items \xB7 ${data.tokens} tokens
|
|
2643
|
+
`));
|
|
2509
2644
|
}
|
|
2510
|
-
console.log("");
|
|
2511
2645
|
}
|
|
2512
2646
|
if (report.recommendations.length) {
|
|
2513
|
-
console.log(chalk9.
|
|
2647
|
+
console.log(chalk9.bold(" Recommendations:\n"));
|
|
2514
2648
|
for (const rec of report.recommendations) {
|
|
2515
2649
|
const icon = rec.priority === "high" ? chalk9.red("!") : rec.priority === "medium" ? chalk9.yellow("~") : chalk9.dim("-");
|
|
2516
2650
|
console.log(` ${icon} ${rec.description}`);
|
|
2651
|
+
if (rec.reasoning) {
|
|
2652
|
+
console.log(chalk9.dim(` ${rec.reasoning}`));
|
|
2653
|
+
}
|
|
2654
|
+
console.log("");
|
|
2517
2655
|
}
|
|
2518
|
-
console.log("");
|
|
2519
2656
|
}
|
|
2520
2657
|
}
|
|
2521
2658
|
|
|
@@ -3041,7 +3178,7 @@ import chalk14 from "chalk";
|
|
|
3041
3178
|
import readline2 from "readline";
|
|
3042
3179
|
import ora10 from "ora";
|
|
3043
3180
|
import select2 from "@inquirer/select";
|
|
3044
|
-
import
|
|
3181
|
+
import confirm3 from "@inquirer/confirm";
|
|
3045
3182
|
function prompt(question) {
|
|
3046
3183
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3047
3184
|
return new Promise((resolve2) => {
|
|
@@ -3121,7 +3258,7 @@ async function reviewCommand(message, options) {
|
|
|
3121
3258
|
console.log(` Most useful: ${bestPart || chalk14.dim("(skipped)")}`);
|
|
3122
3259
|
console.log(` Could be better: ${biggestGap || chalk14.dim("(skipped)")}`);
|
|
3123
3260
|
console.log(` Would recommend: ${wouldRecommend}`);
|
|
3124
|
-
const shouldSubmit = await
|
|
3261
|
+
const shouldSubmit = await confirm3({ message: "Submit this review?", default: true });
|
|
3125
3262
|
if (!shouldSubmit) {
|
|
3126
3263
|
console.log(chalk14.dim("\n Review cancelled.\n"));
|
|
3127
3264
|
return;
|
|
@@ -3135,11 +3272,12 @@ var pkg3 = JSON.parse(
|
|
|
3135
3272
|
fs20.readFileSync(path17.resolve(__dirname2, "..", "package.json"), "utf-8")
|
|
3136
3273
|
);
|
|
3137
3274
|
var program = new Command();
|
|
3138
|
-
|
|
3275
|
+
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg3.version}-local` : pkg3.version;
|
|
3276
|
+
program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("Configure your coding agent environment").version(displayVersion);
|
|
3139
3277
|
program.command("init").description("Initialize coding agent setup for this project").option("--agent <type>", "Target agent: claude, cursor, or both").option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(initCommand);
|
|
3140
3278
|
program.command("undo").description("Revert all config changes made by Caliber").action(undoCommand);
|
|
3141
3279
|
program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(statusCommand);
|
|
3142
|
-
program.command("update").description("Re-analyze project and
|
|
3280
|
+
program.command("regenerate").alias("regen").alias("re").alias("update").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(regenerateCommand);
|
|
3143
3281
|
program.command("login").description("Authenticate with Caliber").action(loginCommand);
|
|
3144
3282
|
program.command("logout").description("Clear stored credentials").action(logoutCommand);
|
|
3145
3283
|
program.command("recommend").description("Discover and manage skill recommendations").option("--generate", "Generate new recommendations").option("--status <status>", "Filter by status: pending, accepted, dismissed").action(recommendCommand);
|
|
@@ -3160,13 +3298,13 @@ import { fileURLToPath as fileURLToPath4 } from "url";
|
|
|
3160
3298
|
import { execSync as execSync4 } from "child_process";
|
|
3161
3299
|
import chalk15 from "chalk";
|
|
3162
3300
|
import ora11 from "ora";
|
|
3163
|
-
import
|
|
3301
|
+
import confirm4 from "@inquirer/confirm";
|
|
3164
3302
|
var __dirname_vc = path18.dirname(fileURLToPath4(import.meta.url));
|
|
3165
3303
|
var pkg4 = JSON.parse(
|
|
3166
3304
|
fs21.readFileSync(path18.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
3167
3305
|
);
|
|
3168
3306
|
async function promptYesNo(question) {
|
|
3169
|
-
return
|
|
3307
|
+
return confirm4({ message: question, default: true });
|
|
3170
3308
|
}
|
|
3171
3309
|
async function checkForUpdates() {
|
|
3172
3310
|
if (process.env.CALIBER_SKIP_UPDATE_CHECK) return;
|
|
@@ -3231,6 +3369,9 @@ Restarting: caliber ${args.join(" ")}
|
|
|
3231
3369
|
}
|
|
3232
3370
|
|
|
3233
3371
|
// src/bin.ts
|
|
3372
|
+
if (process.env.CALIBER_LOCAL) {
|
|
3373
|
+
process.env.CALIBER_SKIP_UPDATE_CHECK = "1";
|
|
3374
|
+
}
|
|
3234
3375
|
var firstRun = isFirstRun();
|
|
3235
3376
|
getDeviceId();
|
|
3236
3377
|
if (firstRun) {
|