@rely-ai/caliber 1.48.1 → 1.49.1
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 +347 -167
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -184,6 +184,7 @@ var init_config = __esm({
|
|
|
184
184
|
// src/lib/resolve-caliber.ts
|
|
185
185
|
var resolve_caliber_exports = {};
|
|
186
186
|
__export(resolve_caliber_exports, {
|
|
187
|
+
displayCaliberName: () => displayCaliberName,
|
|
187
188
|
isCaliberCommand: () => isCaliberCommand,
|
|
188
189
|
isNpxResolution: () => isNpxResolution,
|
|
189
190
|
pickExecutable: () => pickExecutable,
|
|
@@ -254,6 +255,9 @@ function isNpxResolution() {
|
|
|
254
255
|
if (r === "npx --yes @rely-ai/caliber") return true;
|
|
255
256
|
return NPX_RESOLUTION_RE.test(r);
|
|
256
257
|
}
|
|
258
|
+
function displayCaliberName() {
|
|
259
|
+
return isNpxResolution() ? "npx @rely-ai/caliber" : "caliber";
|
|
260
|
+
}
|
|
257
261
|
function resetResolvedCaliber() {
|
|
258
262
|
_resolved = null;
|
|
259
263
|
}
|
|
@@ -344,7 +348,7 @@ npx @rely-ai/caliber refresh
|
|
|
344
348
|
}
|
|
345
349
|
}
|
|
346
350
|
function getPreCommitBlock(platform = "claude") {
|
|
347
|
-
const bin =
|
|
351
|
+
const bin = displayCaliberName();
|
|
348
352
|
return `${BLOCK_START}
|
|
349
353
|
## Before Committing
|
|
350
354
|
|
|
@@ -369,7 +373,7 @@ ${getCaliberNotFoundFallback(platform, bin)}
|
|
|
369
373
|
${BLOCK_END}`;
|
|
370
374
|
}
|
|
371
375
|
function getCursorRuleContent() {
|
|
372
|
-
const bin =
|
|
376
|
+
const bin = displayCaliberName();
|
|
373
377
|
return `---
|
|
374
378
|
description: Run Caliber sync before git commits to keep agent configs up to date
|
|
375
379
|
alwaysApply: true
|
|
@@ -443,7 +447,7 @@ git add ${MANAGED_DOC_PATHS} 2>/dev/null
|
|
|
443
447
|
}
|
|
444
448
|
}
|
|
445
449
|
function getSyncBlock(platform = "claude") {
|
|
446
|
-
const bin =
|
|
450
|
+
const bin = displayCaliberName();
|
|
447
451
|
return `${SYNC_BLOCK_START}
|
|
448
452
|
## Context Sync
|
|
449
453
|
|
|
@@ -467,7 +471,7 @@ function appendManagedBlocks(content, platform = "claude") {
|
|
|
467
471
|
);
|
|
468
472
|
}
|
|
469
473
|
function getCursorSyncContent() {
|
|
470
|
-
const bin =
|
|
474
|
+
const bin = displayCaliberName();
|
|
471
475
|
return `---
|
|
472
476
|
description: This project uses Caliber for automatic AI agent context sync
|
|
473
477
|
alwaysApply: true
|
|
@@ -574,7 +578,7 @@ description: ${skill.description}
|
|
|
574
578
|
return frontmatter + skill.content;
|
|
575
579
|
}
|
|
576
580
|
function getFindSkillsContent() {
|
|
577
|
-
const bin =
|
|
581
|
+
const bin = displayCaliberName();
|
|
578
582
|
return `# Find Skills
|
|
579
583
|
|
|
580
584
|
Search the public skill registry for community-contributed skills
|
|
@@ -627,7 +631,7 @@ User: "I need to write tests for this Python ML pipeline"
|
|
|
627
631
|
`;
|
|
628
632
|
}
|
|
629
633
|
function getSaveLearningContent() {
|
|
630
|
-
const bin =
|
|
634
|
+
const bin = displayCaliberName();
|
|
631
635
|
return `# Save Learning
|
|
632
636
|
|
|
633
637
|
Save a user's instruction or preference as a persistent learning that
|
|
@@ -2583,10 +2587,19 @@ import os3 from "os";
|
|
|
2583
2587
|
// src/llm/seat-based-errors.ts
|
|
2584
2588
|
init_resolve_caliber();
|
|
2585
2589
|
var ERROR_PATTERNS = [
|
|
2586
|
-
{
|
|
2590
|
+
{
|
|
2591
|
+
pattern: /not logged in|not authenticated|login required|unauthorized/i,
|
|
2592
|
+
message: "Not logged in. Run the login command for your provider to re-authenticate."
|
|
2593
|
+
},
|
|
2587
2594
|
{ pattern: /rate limit|too many requests|429/i, message: "Rate limit exceeded. Retrying..." },
|
|
2588
|
-
{
|
|
2589
|
-
|
|
2595
|
+
{
|
|
2596
|
+
pattern: /usage limit|out of usage|budget.*limit|limit.*reached/i,
|
|
2597
|
+
message: () => `Usage limit reached. Run \`${displayCaliberName()} config\` to switch models (e.g. auto or composer-1.5).`
|
|
2598
|
+
},
|
|
2599
|
+
{
|
|
2600
|
+
pattern: /model.*not found|invalid model|model.*unavailable/i,
|
|
2601
|
+
message: () => `The requested model is not available. Run \`${displayCaliberName()} config\` to select a different model.`
|
|
2602
|
+
}
|
|
2590
2603
|
];
|
|
2591
2604
|
function parseSeatBasedError(stderr, exitCode) {
|
|
2592
2605
|
if (!stderr && exitCode === 0) return null;
|
|
@@ -3038,12 +3051,17 @@ function resolveClaudeBin() {
|
|
|
3038
3051
|
_claudeBin = "claude";
|
|
3039
3052
|
return _claudeBin;
|
|
3040
3053
|
}
|
|
3054
|
+
var ANTI_RECURSION_ENV_VARS = /* @__PURE__ */ new Set([
|
|
3055
|
+
"CLAUDECODE",
|
|
3056
|
+
"CLAUDE_CODE_SIMPLE",
|
|
3057
|
+
"CLAUDE_CODE_SESSION_ID",
|
|
3058
|
+
"CLAUDE_CODE_ENTRYPOINT",
|
|
3059
|
+
"CLAUDE_CODE_EXECPATH"
|
|
3060
|
+
]);
|
|
3041
3061
|
function cleanClaudeEnv() {
|
|
3042
3062
|
const env = { ...process.env };
|
|
3043
|
-
for (const key of
|
|
3044
|
-
|
|
3045
|
-
delete env[key];
|
|
3046
|
-
}
|
|
3063
|
+
for (const key of ANTI_RECURSION_ENV_VARS) {
|
|
3064
|
+
delete env[key];
|
|
3047
3065
|
}
|
|
3048
3066
|
return env;
|
|
3049
3067
|
}
|
|
@@ -3505,7 +3523,7 @@ async function handleModelNotAvailable(failedModel, provider, config) {
|
|
|
3505
3523
|
if (!process.stdin.isTTY) {
|
|
3506
3524
|
console.error(
|
|
3507
3525
|
chalk.red(
|
|
3508
|
-
`Model "${failedModel}" is not available. Run \`${
|
|
3526
|
+
`Model "${failedModel}" is not available. Run \`${displayCaliberName()} config\` to select a different model.`
|
|
3509
3527
|
)
|
|
3510
3528
|
);
|
|
3511
3529
|
return null;
|
|
@@ -3531,7 +3549,7 @@ async function handleModelNotAvailable(failedModel, provider, config) {
|
|
|
3531
3549
|
if (models.length === 0) {
|
|
3532
3550
|
console.log(
|
|
3533
3551
|
chalk.red(
|
|
3534
|
-
` No alternative models found. Run \`${
|
|
3552
|
+
` No alternative models found. Run \`${displayCaliberName()} config\` to configure manually.`
|
|
3535
3553
|
)
|
|
3536
3554
|
);
|
|
3537
3555
|
return null;
|
|
@@ -3623,7 +3641,7 @@ function getProvider() {
|
|
|
3623
3641
|
const config = loadConfig();
|
|
3624
3642
|
if (!config) {
|
|
3625
3643
|
throw new Error(
|
|
3626
|
-
`No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, MINIMAX_API_KEY, or VERTEX_PROJECT_ID; or run \`${
|
|
3644
|
+
`No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, MINIMAX_API_KEY, or VERTEX_PROJECT_ID; or run \`${displayCaliberName()} config\` and choose Cursor, Claude Code, or OpenCode; or set CALIBER_USE_CURSOR_SEAT=1 / CALIBER_USE_CLAUDE_CLI=1 / CALIBER_USE_OPENCODE=1.`
|
|
3627
3645
|
);
|
|
3628
3646
|
}
|
|
3629
3647
|
cachedConfig = config;
|
|
@@ -4816,8 +4834,32 @@ var notificationHook = createScriptHook({
|
|
|
4816
4834
|
var isNotificationHookInstalled = notificationHook.isInstalled;
|
|
4817
4835
|
var installNotificationHook = notificationHook.install;
|
|
4818
4836
|
var removeNotificationHook = notificationHook.remove;
|
|
4819
|
-
var
|
|
4820
|
-
var
|
|
4837
|
+
var HOOK_BLOCK_VERSION = "v2";
|
|
4838
|
+
var PRECOMMIT_START = `# caliber:pre-commit:${HOOK_BLOCK_VERSION}:start`;
|
|
4839
|
+
var PRECOMMIT_END = `# caliber:pre-commit:${HOOK_BLOCK_VERSION}:end`;
|
|
4840
|
+
var PRECOMMIT_ANY_VERSION_START_RE = /^#\s*caliber:pre-commit:(?:[a-zA-Z0-9_.-]+:)?start\s*$/m;
|
|
4841
|
+
var PRECOMMIT_ANY_VERSION_BLOCK_RE = /\n?#\s*caliber:pre-commit:(?:[a-zA-Z0-9_.-]+:)?start[\s\S]*?#\s*caliber:pre-commit:(?:[a-zA-Z0-9_.-]+:)?end\n?/g;
|
|
4842
|
+
function tryWindowsDirectNodeInvocation(cmd) {
|
|
4843
|
+
if (process.platform !== "win32") return null;
|
|
4844
|
+
if (!/\.cmd$/i.test(cmd)) return null;
|
|
4845
|
+
const npmDir = path10.dirname(cmd);
|
|
4846
|
+
const binJs = path10.join(npmDir, "node_modules", "@rely-ai", "caliber", "dist", "bin.js");
|
|
4847
|
+
if (!fs11.existsSync(binJs)) return null;
|
|
4848
|
+
let nodePath;
|
|
4849
|
+
try {
|
|
4850
|
+
const out = execSync10("where node", {
|
|
4851
|
+
encoding: "utf-8",
|
|
4852
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
4853
|
+
}).trim();
|
|
4854
|
+
nodePath = pickExecutable(out);
|
|
4855
|
+
if (!nodePath) return null;
|
|
4856
|
+
} catch {
|
|
4857
|
+
return null;
|
|
4858
|
+
}
|
|
4859
|
+
const fwdNode = nodePath.replace(/\\/g, "/");
|
|
4860
|
+
const fwdBin = binJs.replace(/\\/g, "/");
|
|
4861
|
+
return `"${fwdNode}" "${fwdBin}"`;
|
|
4862
|
+
}
|
|
4821
4863
|
function getPrecommitBlock() {
|
|
4822
4864
|
const cmd = resolveCaliber();
|
|
4823
4865
|
const npx = isNpxResolution();
|
|
@@ -4835,19 +4877,26 @@ function getPrecommitBlock() {
|
|
|
4835
4877
|
invoke = cmd;
|
|
4836
4878
|
}
|
|
4837
4879
|
} else {
|
|
4838
|
-
const
|
|
4839
|
-
if (
|
|
4840
|
-
|
|
4880
|
+
const directNode = tryWindowsDirectNodeInvocation(cmd);
|
|
4881
|
+
if (directNode) {
|
|
4882
|
+
const nodeBin = directNode.match(/^"([^"]+)"/)?.[1] ?? "";
|
|
4883
|
+
guard = `[ -x "${nodeBin}" ]`;
|
|
4884
|
+
invoke = directNode;
|
|
4841
4885
|
} else {
|
|
4842
|
-
|
|
4886
|
+
const cmdBash = bashPath(cmd);
|
|
4887
|
+
if (path10.isAbsolute(cmd)) {
|
|
4888
|
+
guard = `[ -x "${cmdBash}" ]`;
|
|
4889
|
+
} else {
|
|
4890
|
+
guard = `[ -x "${cmdBash}" ] || command -v "${cmdBash}" >/dev/null 2>&1`;
|
|
4891
|
+
}
|
|
4892
|
+
invoke = `"${cmdBash}"`;
|
|
4843
4893
|
}
|
|
4844
|
-
invoke = `"${cmdBash}"`;
|
|
4845
4894
|
}
|
|
4846
4895
|
return `${PRECOMMIT_START}
|
|
4847
4896
|
if ${guard}; then
|
|
4848
4897
|
mkdir -p .caliber
|
|
4849
4898
|
echo "\\033[2mcaliber: refreshing docs...\\033[0m"
|
|
4850
|
-
${invoke} refresh --quiet 2>.caliber/refresh-hook.log ||
|
|
4899
|
+
${invoke} refresh --quiet 2>.caliber/refresh-hook.log || echo "\\033[33mcaliber: refresh skipped \u2014 see .caliber/refresh-hook.log\\033[0m" >&2
|
|
4851
4900
|
${invoke} learn finalize 2>>.caliber/refresh-hook.log || true
|
|
4852
4901
|
git diff --name-only -- CLAUDE.md .claude/ .cursor/ AGENTS.md CALIBER_LEARNINGS.md .github/ .agents/ .opencode/ 2>/dev/null | xargs git add 2>/dev/null || true
|
|
4853
4902
|
fi
|
|
@@ -4872,19 +4921,29 @@ function isPreCommitHookInstalled() {
|
|
|
4872
4921
|
const hookPath = getPreCommitPath();
|
|
4873
4922
|
if (!hookPath || !fs11.existsSync(hookPath)) return false;
|
|
4874
4923
|
const content = fs11.readFileSync(hookPath, "utf-8");
|
|
4875
|
-
return
|
|
4924
|
+
return PRECOMMIT_ANY_VERSION_START_RE.test(content);
|
|
4876
4925
|
}
|
|
4877
4926
|
function installPreCommitHook() {
|
|
4878
|
-
if (isPreCommitHookInstalled()) {
|
|
4879
|
-
return { installed: false, alreadyInstalled: true };
|
|
4880
|
-
}
|
|
4881
4927
|
const hookPath = getPreCommitPath();
|
|
4882
|
-
if (!hookPath)
|
|
4928
|
+
if (!hookPath) {
|
|
4929
|
+
return { installed: false, alreadyInstalled: false, upgraded: false };
|
|
4930
|
+
}
|
|
4883
4931
|
const hooksDir = path10.dirname(hookPath);
|
|
4884
4932
|
if (!fs11.existsSync(hooksDir)) fs11.mkdirSync(hooksDir, { recursive: true });
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4933
|
+
const exists = fs11.existsSync(hookPath);
|
|
4934
|
+
let content = exists ? fs11.readFileSync(hookPath, "utf-8") : "";
|
|
4935
|
+
if (PRECOMMIT_ANY_VERSION_START_RE.test(content)) {
|
|
4936
|
+
if (content.includes(PRECOMMIT_START)) {
|
|
4937
|
+
return { installed: false, alreadyInstalled: true, upgraded: false };
|
|
4938
|
+
}
|
|
4939
|
+
content = content.replace(PRECOMMIT_ANY_VERSION_BLOCK_RE, "\n").replace(/\n{3,}/g, "\n\n");
|
|
4940
|
+
if (!content.endsWith("\n")) content += "\n";
|
|
4941
|
+
content += "\n" + getPrecommitBlock() + "\n";
|
|
4942
|
+
fs11.writeFileSync(hookPath, content);
|
|
4943
|
+
fs11.chmodSync(hookPath, 493);
|
|
4944
|
+
return { installed: false, alreadyInstalled: false, upgraded: true };
|
|
4945
|
+
}
|
|
4946
|
+
if (exists) {
|
|
4888
4947
|
if (!content.endsWith("\n")) content += "\n";
|
|
4889
4948
|
content += "\n" + getPrecommitBlock() + "\n";
|
|
4890
4949
|
} else {
|
|
@@ -4892,7 +4951,7 @@ function installPreCommitHook() {
|
|
|
4892
4951
|
}
|
|
4893
4952
|
fs11.writeFileSync(hookPath, content);
|
|
4894
4953
|
fs11.chmodSync(hookPath, 493);
|
|
4895
|
-
return { installed: true, alreadyInstalled: false };
|
|
4954
|
+
return { installed: true, alreadyInstalled: false, upgraded: false };
|
|
4896
4955
|
}
|
|
4897
4956
|
function removePreCommitHook() {
|
|
4898
4957
|
const hookPath = getPreCommitPath();
|
|
@@ -4900,11 +4959,10 @@ function removePreCommitHook() {
|
|
|
4900
4959
|
return { removed: false, notFound: true };
|
|
4901
4960
|
}
|
|
4902
4961
|
let content = fs11.readFileSync(hookPath, "utf-8");
|
|
4903
|
-
if (!
|
|
4962
|
+
if (!PRECOMMIT_ANY_VERSION_START_RE.test(content)) {
|
|
4904
4963
|
return { removed: false, notFound: true };
|
|
4905
4964
|
}
|
|
4906
|
-
|
|
4907
|
-
content = content.replace(regex, "\n");
|
|
4965
|
+
content = content.replace(PRECOMMIT_ANY_VERSION_BLOCK_RE, "\n").replace(/\n{3,}/g, "\n\n");
|
|
4908
4966
|
if (content.trim() === "#!/bin/sh" || content.trim() === "") {
|
|
4909
4967
|
fs11.unlinkSync(hookPath);
|
|
4910
4968
|
} else {
|
|
@@ -7717,10 +7775,11 @@ function detectGitDrift(dir) {
|
|
|
7717
7775
|
}
|
|
7718
7776
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
|
|
7719
7777
|
try {
|
|
7720
|
-
const headTimestamp = execSync12(
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7778
|
+
const headTimestamp = execSync12("git log -1 --format=%ct HEAD", {
|
|
7779
|
+
cwd: dir,
|
|
7780
|
+
encoding: "utf-8",
|
|
7781
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7782
|
+
}).trim();
|
|
7724
7783
|
const headTime = parseInt(headTimestamp, 10) * 1e3;
|
|
7725
7784
|
for (const file of configFiles) {
|
|
7726
7785
|
const filePath = join5(dir, file);
|
|
@@ -7728,7 +7787,11 @@ function detectGitDrift(dir) {
|
|
|
7728
7787
|
try {
|
|
7729
7788
|
const mtime = statSync(filePath).mtime.getTime();
|
|
7730
7789
|
if (mtime > headTime) {
|
|
7731
|
-
return {
|
|
7790
|
+
return {
|
|
7791
|
+
commitsSinceConfigUpdate: 0,
|
|
7792
|
+
lastConfigCommit: "uncommitted (recently modified)",
|
|
7793
|
+
isGitRepo: true
|
|
7794
|
+
};
|
|
7732
7795
|
}
|
|
7733
7796
|
} catch {
|
|
7734
7797
|
}
|
|
@@ -7738,19 +7801,20 @@ function detectGitDrift(dir) {
|
|
|
7738
7801
|
let latestConfigCommitHash = null;
|
|
7739
7802
|
for (const file of configFiles) {
|
|
7740
7803
|
try {
|
|
7741
|
-
const hash = execSync12(
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7804
|
+
const hash = execSync12(`git log -1 --format=%H -- "${file}"`, {
|
|
7805
|
+
cwd: dir,
|
|
7806
|
+
encoding: "utf-8",
|
|
7807
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7808
|
+
}).trim();
|
|
7745
7809
|
if (!hash) continue;
|
|
7746
7810
|
if (!latestConfigCommitHash) {
|
|
7747
7811
|
latestConfigCommitHash = hash;
|
|
7748
7812
|
} else {
|
|
7749
7813
|
try {
|
|
7750
|
-
execSync12(
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
);
|
|
7814
|
+
execSync12(`git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`, {
|
|
7815
|
+
cwd: dir,
|
|
7816
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7817
|
+
});
|
|
7754
7818
|
latestConfigCommitHash = hash;
|
|
7755
7819
|
} catch {
|
|
7756
7820
|
}
|
|
@@ -7762,22 +7826,28 @@ function detectGitDrift(dir) {
|
|
|
7762
7826
|
return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: true };
|
|
7763
7827
|
}
|
|
7764
7828
|
try {
|
|
7765
|
-
const countStr = execSync12(
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7829
|
+
const countStr = execSync12(`git rev-list --count ${latestConfigCommitHash}..HEAD`, {
|
|
7830
|
+
cwd: dir,
|
|
7831
|
+
encoding: "utf-8",
|
|
7832
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7833
|
+
}).trim();
|
|
7769
7834
|
const commitsSince = parseInt(countStr, 10) || 0;
|
|
7770
|
-
const lastDate = execSync12(
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7835
|
+
const lastDate = execSync12(`git log -1 --format=%ci ${latestConfigCommitHash}`, {
|
|
7836
|
+
cwd: dir,
|
|
7837
|
+
encoding: "utf-8",
|
|
7838
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7839
|
+
}).trim();
|
|
7774
7840
|
return {
|
|
7775
7841
|
commitsSinceConfigUpdate: commitsSince,
|
|
7776
7842
|
lastConfigCommit: lastDate,
|
|
7777
7843
|
isGitRepo: true
|
|
7778
7844
|
};
|
|
7779
7845
|
} catch {
|
|
7780
|
-
return {
|
|
7846
|
+
return {
|
|
7847
|
+
commitsSinceConfigUpdate: 0,
|
|
7848
|
+
lastConfigCommit: latestConfigCommitHash,
|
|
7849
|
+
isGitRepo: true
|
|
7850
|
+
};
|
|
7781
7851
|
}
|
|
7782
7852
|
}
|
|
7783
7853
|
function checkAccuracy(dir) {
|
|
@@ -7827,10 +7897,13 @@ function checkAccuracy(dir) {
|
|
|
7827
7897
|
earnedPoints: driftPoints,
|
|
7828
7898
|
passed: drift.commitsSinceConfigUpdate <= 15 || !drift.isGitRepo,
|
|
7829
7899
|
detail: !drift.isGitRepo ? "Not a git repository \u2014 skipping drift check" : !drift.lastConfigCommit ? "Config files not tracked in git" : drift.commitsSinceConfigUpdate === 0 ? "Config is up to date with latest commits" : `${drift.commitsSinceConfigUpdate} commit${drift.commitsSinceConfigUpdate === 1 ? "" : "s"} since last config update`,
|
|
7830
|
-
suggestion: drift.commitsSinceConfigUpdate > 15 ? `Code has had ${drift.commitsSinceConfigUpdate} commits since last config update \u2014 run \`${
|
|
7900
|
+
suggestion: drift.commitsSinceConfigUpdate > 15 ? `Code has had ${drift.commitsSinceConfigUpdate} commits since last config update \u2014 run \`${displayCaliberName()} refresh\` to sync` : void 0,
|
|
7831
7901
|
fix: drift.commitsSinceConfigUpdate > 15 ? {
|
|
7832
7902
|
action: "refresh_config",
|
|
7833
|
-
data: {
|
|
7903
|
+
data: {
|
|
7904
|
+
commitsSince: drift.commitsSinceConfigUpdate,
|
|
7905
|
+
lastConfigCommit: drift.lastConfigCommit
|
|
7906
|
+
},
|
|
7834
7907
|
instruction: `Config is ${drift.commitsSinceConfigUpdate} commits behind. Review recent changes and update config accordingly.`
|
|
7835
7908
|
} : void 0
|
|
7836
7909
|
});
|
|
@@ -7845,10 +7918,11 @@ import { join as join6 } from "path";
|
|
|
7845
7918
|
function getCommitsSinceConfigUpdate(dir) {
|
|
7846
7919
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
|
|
7847
7920
|
try {
|
|
7848
|
-
const headTimestamp = execSync13(
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7921
|
+
const headTimestamp = execSync13("git log -1 --format=%ct HEAD", {
|
|
7922
|
+
cwd: dir,
|
|
7923
|
+
encoding: "utf-8",
|
|
7924
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7925
|
+
}).trim();
|
|
7852
7926
|
const headTime = parseInt(headTimestamp, 10) * 1e3;
|
|
7853
7927
|
for (const file of configFiles) {
|
|
7854
7928
|
const filePath = join6(dir, file);
|
|
@@ -7865,15 +7939,17 @@ function getCommitsSinceConfigUpdate(dir) {
|
|
|
7865
7939
|
}
|
|
7866
7940
|
for (const file of configFiles) {
|
|
7867
7941
|
try {
|
|
7868
|
-
const hash = execSync13(
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7942
|
+
const hash = execSync13(`git log -1 --format=%H -- "${file}"`, {
|
|
7943
|
+
cwd: dir,
|
|
7944
|
+
encoding: "utf-8",
|
|
7945
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7946
|
+
}).trim();
|
|
7872
7947
|
if (hash) {
|
|
7873
|
-
const countStr = execSync13(
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7948
|
+
const countStr = execSync13(`git rev-list --count ${hash}..HEAD`, {
|
|
7949
|
+
cwd: dir,
|
|
7950
|
+
encoding: "utf-8",
|
|
7951
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7952
|
+
}).trim();
|
|
7877
7953
|
return parseInt(countStr, 10) || 0;
|
|
7878
7954
|
}
|
|
7879
7955
|
} catch {
|
|
@@ -7902,7 +7978,7 @@ function checkFreshness(dir) {
|
|
|
7902
7978
|
earnedPoints: freshnessPoints,
|
|
7903
7979
|
passed: freshnessPoints >= 3,
|
|
7904
7980
|
detail: freshnessDetail,
|
|
7905
|
-
suggestion: commitsSince !== null && freshnessPoints < 3 ? `Config is ${commitsSince} commits behind \u2014 run \`${
|
|
7981
|
+
suggestion: commitsSince !== null && freshnessPoints < 3 ? `Config is ${commitsSince} commits behind \u2014 run \`${displayCaliberName()} refresh\` to update it` : void 0,
|
|
7906
7982
|
fix: commitsSince !== null && freshnessPoints < 3 ? {
|
|
7907
7983
|
action: "refresh_config",
|
|
7908
7984
|
data: { commitsSince },
|
|
@@ -8054,11 +8130,11 @@ function checkBonus(dir) {
|
|
|
8054
8130
|
earnedPoints: hasHooks ? POINTS_HOOKS : 0,
|
|
8055
8131
|
passed: hasHooks,
|
|
8056
8132
|
detail: hasHooks ? hookSources.join(", ") : "No hooks configured",
|
|
8057
|
-
suggestion: hasHooks ? void 0 : `Hooks auto-sync your agent config on every commit so it stays fresh. Run \`${
|
|
8133
|
+
suggestion: hasHooks ? void 0 : `Hooks auto-sync your agent config on every commit so it stays fresh. Run \`${displayCaliberName()} init\` to set up`,
|
|
8058
8134
|
fix: hasHooks ? void 0 : {
|
|
8059
8135
|
action: "install_hooks",
|
|
8060
8136
|
data: {},
|
|
8061
|
-
instruction: `Run ${
|
|
8137
|
+
instruction: `Run ${displayCaliberName()} init to add pre-commit refresh instructions to config files.`
|
|
8062
8138
|
}
|
|
8063
8139
|
});
|
|
8064
8140
|
const agentsMdExists = existsSync6(join7(dir, "AGENTS.md"));
|
|
@@ -8123,7 +8199,7 @@ function checkBonus(dir) {
|
|
|
8123
8199
|
earnedPoints: hasLearned ? POINTS_LEARNED_CONTENT : 0,
|
|
8124
8200
|
passed: hasLearned,
|
|
8125
8201
|
detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
|
|
8126
|
-
suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${
|
|
8202
|
+
suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${displayCaliberName()} learn install\``
|
|
8127
8203
|
});
|
|
8128
8204
|
const configContent = (() => {
|
|
8129
8205
|
const parts = [];
|
|
@@ -8170,7 +8246,7 @@ function checkSources(dir) {
|
|
|
8170
8246
|
earnedPoints: hasSources ? POINTS_SOURCES_CONFIGURED : 0,
|
|
8171
8247
|
passed: hasSources,
|
|
8172
8248
|
detail: hasSources ? `${configSources.length} source${configSources.length === 1 ? "" : "s"} configured` : "No external sources configured",
|
|
8173
|
-
suggestion: hasSources ? void 0 : `Run \`${
|
|
8249
|
+
suggestion: hasSources ? void 0 : `Run \`${displayCaliberName()} sources add <path>\` to add related repos or docs`
|
|
8174
8250
|
});
|
|
8175
8251
|
if (hasSources) {
|
|
8176
8252
|
const claudeMd = readFileOrNull(join8(dir, "CLAUDE.md"));
|
|
@@ -8188,7 +8264,7 @@ function checkSources(dir) {
|
|
|
8188
8264
|
earnedPoints: referenced ? POINTS_SOURCES_REFERENCED : 0,
|
|
8189
8265
|
passed: referenced,
|
|
8190
8266
|
detail: referenced ? "At least one source is referenced in CLAUDE.md" : "No configured sources are mentioned in CLAUDE.md",
|
|
8191
|
-
suggestion: referenced ? void 0 : `Regenerate with \`${
|
|
8267
|
+
suggestion: referenced ? void 0 : `Regenerate with \`${displayCaliberName()} init\` to include source context in your config`
|
|
8192
8268
|
});
|
|
8193
8269
|
}
|
|
8194
8270
|
return checks;
|
|
@@ -8299,7 +8375,14 @@ var CATEGORY_LABELS = {
|
|
|
8299
8375
|
freshness: { icon: "\u{1F6E1}\uFE0F", label: "FRESHNESS & SAFETY" },
|
|
8300
8376
|
bonus: { icon: "\u2B50", label: "BONUS" }
|
|
8301
8377
|
};
|
|
8302
|
-
var CATEGORY_ORDER = [
|
|
8378
|
+
var CATEGORY_ORDER = [
|
|
8379
|
+
"existence",
|
|
8380
|
+
"quality",
|
|
8381
|
+
"grounding",
|
|
8382
|
+
"accuracy",
|
|
8383
|
+
"freshness",
|
|
8384
|
+
"bonus"
|
|
8385
|
+
];
|
|
8303
8386
|
function gradeColor(grade) {
|
|
8304
8387
|
switch (grade) {
|
|
8305
8388
|
case "A":
|
|
@@ -8368,7 +8451,9 @@ function displayScore(result) {
|
|
|
8368
8451
|
console.log("");
|
|
8369
8452
|
console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
8370
8453
|
console.log("");
|
|
8371
|
-
console.log(
|
|
8454
|
+
console.log(
|
|
8455
|
+
` ${chalk3.bold("Agent Config Score")} ${gc(chalk3.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk3.bold(result.grade))}`
|
|
8456
|
+
);
|
|
8372
8457
|
console.log(` ${progressBar(result.score, result.maxScore)}`);
|
|
8373
8458
|
console.log(chalk3.dim(` Target: ${agentLabel}`));
|
|
8374
8459
|
console.log("");
|
|
@@ -8391,7 +8476,11 @@ function displayScore(result) {
|
|
|
8391
8476
|
formatTopImprovements(result.checks);
|
|
8392
8477
|
}
|
|
8393
8478
|
function formatTopImprovements(checks) {
|
|
8394
|
-
const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({
|
|
8479
|
+
const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({
|
|
8480
|
+
name: c.name,
|
|
8481
|
+
potential: c.maxPoints - c.earnedPoints,
|
|
8482
|
+
suggestion: c.suggestion
|
|
8483
|
+
})).sort((a, b) => b.potential - a.potential).slice(0, 5);
|
|
8395
8484
|
if (improvable.length === 0) return;
|
|
8396
8485
|
console.log(chalk3.gray(" \u2500 TOP IMPROVEMENTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
8397
8486
|
console.log("");
|
|
@@ -8422,8 +8511,12 @@ function displayScoreSummary(result) {
|
|
|
8422
8511
|
}
|
|
8423
8512
|
const remaining = failing.length - shown.length;
|
|
8424
8513
|
const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
8425
|
-
console.log(
|
|
8426
|
-
|
|
8514
|
+
console.log(
|
|
8515
|
+
chalk3.dim(
|
|
8516
|
+
`
|
|
8517
|
+
Run ${chalk3.hex("#83D1EB")(`${displayCaliberName()} score`)} for details.${moreText}`
|
|
8518
|
+
)
|
|
8519
|
+
);
|
|
8427
8520
|
}
|
|
8428
8521
|
console.log("");
|
|
8429
8522
|
}
|
|
@@ -8439,7 +8532,9 @@ function displayScoreDelta(before, after) {
|
|
|
8439
8532
|
console.log(
|
|
8440
8533
|
` Score: ${beforeGc(`${before.score}`)} ${chalk3.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk3.gray("\u2192")} ${afterGc(after.grade)}`
|
|
8441
8534
|
);
|
|
8442
|
-
console.log(
|
|
8535
|
+
console.log(
|
|
8536
|
+
` ${progressBar(before.score, before.maxScore, 19)} ${chalk3.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`
|
|
8537
|
+
);
|
|
8443
8538
|
console.log("");
|
|
8444
8539
|
console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
8445
8540
|
console.log("");
|
|
@@ -9121,7 +9216,7 @@ async function querySkills(query) {
|
|
|
9121
9216
|
console.log("");
|
|
9122
9217
|
console.log(
|
|
9123
9218
|
chalk5.dim(
|
|
9124
|
-
` Install with: ${
|
|
9219
|
+
` Install with: ${displayCaliberName()} skills --install ${available.map((r) => r.slug).join(",")}`
|
|
9125
9220
|
)
|
|
9126
9221
|
);
|
|
9127
9222
|
console.log("");
|
|
@@ -11109,7 +11204,7 @@ function log(verbose, ...args) {
|
|
|
11109
11204
|
async function initCommand(options) {
|
|
11110
11205
|
const brand = chalk14.hex("#EB9D83");
|
|
11111
11206
|
const title = chalk14.hex("#83D1EB");
|
|
11112
|
-
const bin =
|
|
11207
|
+
const bin = displayCaliberName();
|
|
11113
11208
|
const firstRun = isFirstRun(process.cwd());
|
|
11114
11209
|
if (firstRun) {
|
|
11115
11210
|
console.log(
|
|
@@ -11250,6 +11345,8 @@ async function initCommand(options) {
|
|
|
11250
11345
|
const hookResult = installPreCommitHook();
|
|
11251
11346
|
if (hookResult.installed) {
|
|
11252
11347
|
console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed \u2014 configs sync on every commit`);
|
|
11348
|
+
} else if (hookResult.upgraded) {
|
|
11349
|
+
console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 upgraded to latest version`);
|
|
11253
11350
|
} else if (hookResult.alreadyInstalled) {
|
|
11254
11351
|
console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 active`);
|
|
11255
11352
|
}
|
|
@@ -11949,24 +12046,34 @@ async function statusCommand(options) {
|
|
|
11949
12046
|
const config = loadConfig();
|
|
11950
12047
|
const manifest = readManifest();
|
|
11951
12048
|
if (options.json) {
|
|
11952
|
-
console.log(
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
12049
|
+
console.log(
|
|
12050
|
+
JSON.stringify(
|
|
12051
|
+
{
|
|
12052
|
+
configured: !!config,
|
|
12053
|
+
provider: config?.provider,
|
|
12054
|
+
model: config?.model,
|
|
12055
|
+
manifest
|
|
12056
|
+
},
|
|
12057
|
+
null,
|
|
12058
|
+
2
|
|
12059
|
+
)
|
|
12060
|
+
);
|
|
11958
12061
|
return;
|
|
11959
12062
|
}
|
|
11960
12063
|
console.log(chalk16.bold("\nCaliber Status\n"));
|
|
11961
12064
|
if (config) {
|
|
11962
12065
|
console.log(` LLM: ${chalk16.green(config.provider)} (${config.model})`);
|
|
11963
12066
|
} else {
|
|
11964
|
-
const bin =
|
|
11965
|
-
console.log(
|
|
12067
|
+
const bin = displayCaliberName();
|
|
12068
|
+
console.log(
|
|
12069
|
+
` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")(`${bin} config`)}`
|
|
12070
|
+
);
|
|
11966
12071
|
}
|
|
11967
12072
|
if (!manifest) {
|
|
11968
12073
|
console.log(` Config: ${chalk16.dim("No config applied")}`);
|
|
11969
|
-
console.log(
|
|
12074
|
+
console.log(
|
|
12075
|
+
chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")(`${displayCaliberName()} init`) + chalk16.dim(" to get started.\n")
|
|
12076
|
+
);
|
|
11970
12077
|
return;
|
|
11971
12078
|
}
|
|
11972
12079
|
console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
|
|
@@ -11986,15 +12093,19 @@ init_review();
|
|
|
11986
12093
|
init_config();
|
|
11987
12094
|
init_resolve_caliber();
|
|
11988
12095
|
async function regenerateCommand(options) {
|
|
11989
|
-
const bin =
|
|
12096
|
+
const bin = displayCaliberName();
|
|
11990
12097
|
const config = loadConfig();
|
|
11991
12098
|
if (!config) {
|
|
11992
|
-
console.log(
|
|
12099
|
+
console.log(
|
|
12100
|
+
chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")(`${bin} config`) + chalk17.red(" first.")
|
|
12101
|
+
);
|
|
11993
12102
|
throw new Error("__exit__");
|
|
11994
12103
|
}
|
|
11995
12104
|
const manifest = readManifest();
|
|
11996
12105
|
if (!manifest) {
|
|
11997
|
-
console.log(
|
|
12106
|
+
console.log(
|
|
12107
|
+
chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")(`${bin} init`) + chalk17.yellow(" first.")
|
|
12108
|
+
);
|
|
11998
12109
|
throw new Error("__exit__");
|
|
11999
12110
|
}
|
|
12000
12111
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
@@ -12009,27 +12120,24 @@ async function regenerateCommand(options) {
|
|
|
12009
12120
|
return;
|
|
12010
12121
|
}
|
|
12011
12122
|
const genSpinner = ora5("Regenerating config...").start();
|
|
12012
|
-
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, {
|
|
12123
|
+
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, {
|
|
12124
|
+
showElapsedTime: true
|
|
12125
|
+
});
|
|
12013
12126
|
genMessages.start();
|
|
12014
12127
|
let generatedSetup = null;
|
|
12015
12128
|
try {
|
|
12016
|
-
const result = await generateSetup(
|
|
12017
|
-
|
|
12018
|
-
|
|
12019
|
-
|
|
12020
|
-
{
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
},
|
|
12027
|
-
onError: (error) => {
|
|
12028
|
-
genMessages.stop();
|
|
12029
|
-
genSpinner.fail(`Generation error: ${error}`);
|
|
12030
|
-
}
|
|
12129
|
+
const result = await generateSetup(fingerprint, targetAgent, void 0, {
|
|
12130
|
+
onStatus: (status) => {
|
|
12131
|
+
genMessages.handleServerStatus(status);
|
|
12132
|
+
},
|
|
12133
|
+
onComplete: (setup) => {
|
|
12134
|
+
generatedSetup = setup;
|
|
12135
|
+
},
|
|
12136
|
+
onError: (error) => {
|
|
12137
|
+
genMessages.stop();
|
|
12138
|
+
genSpinner.fail(`Generation error: ${error}`);
|
|
12031
12139
|
}
|
|
12032
|
-
);
|
|
12140
|
+
});
|
|
12033
12141
|
if (!generatedSetup) generatedSetup = result.setup;
|
|
12034
12142
|
} catch (err) {
|
|
12035
12143
|
genMessages.stop();
|
|
@@ -12047,9 +12155,13 @@ async function regenerateCommand(options) {
|
|
|
12047
12155
|
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
12048
12156
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
12049
12157
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
12050
|
-
console.log(
|
|
12158
|
+
console.log(
|
|
12159
|
+
chalk17.dim(
|
|
12160
|
+
`
|
|
12051
12161
|
${chalk17.green(`${staged.newFiles} new`)} / ${chalk17.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
12052
|
-
`
|
|
12162
|
+
`
|
|
12163
|
+
)
|
|
12164
|
+
);
|
|
12053
12165
|
if (totalChanges === 0) {
|
|
12054
12166
|
console.log(chalk17.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
12055
12167
|
cleanupStaging();
|
|
@@ -12110,21 +12222,33 @@ async function regenerateCommand(options) {
|
|
|
12110
12222
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
12111
12223
|
if (afterScore.score < baselineScore.score) {
|
|
12112
12224
|
console.log("");
|
|
12113
|
-
console.log(
|
|
12225
|
+
console.log(
|
|
12226
|
+
chalk17.yellow(
|
|
12227
|
+
` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
|
|
12228
|
+
)
|
|
12229
|
+
);
|
|
12114
12230
|
try {
|
|
12115
12231
|
const { restored, removed } = undoSetup();
|
|
12116
12232
|
if (restored.length > 0 || removed.length > 0) {
|
|
12117
|
-
console.log(
|
|
12233
|
+
console.log(
|
|
12234
|
+
chalk17.dim(
|
|
12235
|
+
` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`
|
|
12236
|
+
)
|
|
12237
|
+
);
|
|
12118
12238
|
}
|
|
12119
12239
|
} catch {
|
|
12120
12240
|
}
|
|
12121
|
-
console.log(
|
|
12241
|
+
console.log(
|
|
12242
|
+
chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} init --force`) + chalk17.dim(" to override.\n")
|
|
12243
|
+
);
|
|
12122
12244
|
return;
|
|
12123
12245
|
}
|
|
12124
12246
|
displayScoreDelta(baselineScore, afterScore);
|
|
12125
12247
|
trackRegenerateCompleted(action, Date.now());
|
|
12126
12248
|
console.log(chalk17.bold.green(" Regeneration complete!"));
|
|
12127
|
-
console.log(
|
|
12249
|
+
console.log(
|
|
12250
|
+
chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} undo`) + chalk17.dim(" to revert changes.\n")
|
|
12251
|
+
);
|
|
12128
12252
|
}
|
|
12129
12253
|
|
|
12130
12254
|
// src/commands/score.ts
|
|
@@ -12239,7 +12363,7 @@ async function scoreCommand(options) {
|
|
|
12239
12363
|
displayScore(result);
|
|
12240
12364
|
const separator = chalk18.gray(" " + "\u2500".repeat(53));
|
|
12241
12365
|
console.log(separator);
|
|
12242
|
-
const bin =
|
|
12366
|
+
const bin = displayCaliberName();
|
|
12243
12367
|
const failing = result.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints));
|
|
12244
12368
|
if (result.score < 70 && failing.length > 0) {
|
|
12245
12369
|
const topFix = failing[0];
|
|
@@ -13200,7 +13324,7 @@ async function refreshCommand(options) {
|
|
|
13200
13324
|
if (!config) {
|
|
13201
13325
|
if (quiet) return;
|
|
13202
13326
|
console.log(
|
|
13203
|
-
chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")(`${
|
|
13327
|
+
chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")(`${displayCaliberName()} config`) + chalk19.red(" (e.g. choose Cursor) or set an API key.")
|
|
13204
13328
|
);
|
|
13205
13329
|
throw new Error("__exit__");
|
|
13206
13330
|
}
|
|
@@ -13308,7 +13432,9 @@ async function hooksCommand(options) {
|
|
|
13308
13432
|
if (options.install) {
|
|
13309
13433
|
for (const hook of HOOKS) {
|
|
13310
13434
|
const result = hook.install();
|
|
13311
|
-
if (result.
|
|
13435
|
+
if (result.upgraded) {
|
|
13436
|
+
console.log(chalk20.green(" \u2713") + ` ${hook.label} upgraded to latest version`);
|
|
13437
|
+
} else if (result.alreadyInstalled) {
|
|
13312
13438
|
console.log(chalk20.dim(` ${hook.label} already enabled.`));
|
|
13313
13439
|
} else {
|
|
13314
13440
|
console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
|
|
@@ -14248,7 +14374,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14248
14374
|
if (isAuto) return;
|
|
14249
14375
|
console.log(
|
|
14250
14376
|
chalk23.yellow(
|
|
14251
|
-
`caliber: no LLM provider configured \u2014 run \`${
|
|
14377
|
+
`caliber: no LLM provider configured \u2014 run \`${displayCaliberName()} config\` first`
|
|
14252
14378
|
)
|
|
14253
14379
|
);
|
|
14254
14380
|
clearSession();
|
|
@@ -14414,7 +14540,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14414
14540
|
if (staleLearnings.length > 0 && !isAuto) {
|
|
14415
14541
|
console.log(
|
|
14416
14542
|
chalk23.yellow(
|
|
14417
|
-
`caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`${
|
|
14543
|
+
`caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`${displayCaliberName()} learn list --verbose\` to review`
|
|
14418
14544
|
)
|
|
14419
14545
|
);
|
|
14420
14546
|
}
|
|
@@ -14471,7 +14597,7 @@ async function learnInstallCommand() {
|
|
|
14471
14597
|
if (!fs48.existsSync(".claude") && !fs48.existsSync(".cursor")) {
|
|
14472
14598
|
console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
|
|
14473
14599
|
console.log(
|
|
14474
|
-
chalk23.dim(` Run \`${
|
|
14600
|
+
chalk23.dim(` Run \`${displayCaliberName()} init\` first, or create the directory manually.`)
|
|
14475
14601
|
);
|
|
14476
14602
|
return;
|
|
14477
14603
|
}
|
|
@@ -14519,7 +14645,7 @@ async function learnStatusCommand() {
|
|
|
14519
14645
|
}
|
|
14520
14646
|
if (!claudeInstalled && !cursorInstalled) {
|
|
14521
14647
|
console.log(
|
|
14522
|
-
chalk23.dim(` Run \`${
|
|
14648
|
+
chalk23.dim(` Run \`${displayCaliberName()} learn install\` to enable session learning.`)
|
|
14523
14649
|
);
|
|
14524
14650
|
}
|
|
14525
14651
|
console.log();
|
|
@@ -14575,7 +14701,9 @@ function getAllLearnings() {
|
|
|
14575
14701
|
async function learnListCommand(options) {
|
|
14576
14702
|
const items = getAllLearnings();
|
|
14577
14703
|
if (items.length === 0) {
|
|
14578
|
-
console.log(
|
|
14704
|
+
console.log(
|
|
14705
|
+
chalk23.dim(`No learnings yet. Run \`${displayCaliberName()} learn install\` to start.`)
|
|
14706
|
+
);
|
|
14579
14707
|
return;
|
|
14580
14708
|
}
|
|
14581
14709
|
const roiStats = options?.verbose ? readROIStats() : null;
|
|
@@ -14606,7 +14734,7 @@ async function learnDeleteCommand(indexStr) {
|
|
|
14606
14734
|
if (isNaN(index) || index < 1) {
|
|
14607
14735
|
console.log(
|
|
14608
14736
|
chalk23.red(
|
|
14609
|
-
`Invalid index: "${indexStr}". Use a number from \`${
|
|
14737
|
+
`Invalid index: "${indexStr}". Use a number from \`${displayCaliberName()} learn list\`.`
|
|
14610
14738
|
)
|
|
14611
14739
|
);
|
|
14612
14740
|
return;
|
|
@@ -14717,13 +14845,23 @@ function displayColdStart(score) {
|
|
|
14717
14845
|
const hooksInstalled = areLearningHooksInstalled() || areCursorLearningHooksInstalled();
|
|
14718
14846
|
if (!hooksInstalled) {
|
|
14719
14847
|
console.log(chalk24.yellow(" Learning hooks not installed."));
|
|
14720
|
-
console.log(
|
|
14721
|
-
|
|
14722
|
-
|
|
14848
|
+
console.log(
|
|
14849
|
+
chalk24.dim(" Session learning captures patterns from your AI coding sessions \u2014 what")
|
|
14850
|
+
);
|
|
14851
|
+
console.log(
|
|
14852
|
+
chalk24.dim(" fails, what works, corrections you make \u2014 so your agents improve over time.\n")
|
|
14853
|
+
);
|
|
14854
|
+
console.log(
|
|
14855
|
+
chalk24.dim(" Run ") + chalk24.cyan(`${displayCaliberName()} learn install`) + chalk24.dim(" to enable.")
|
|
14856
|
+
);
|
|
14723
14857
|
} else {
|
|
14724
14858
|
console.log(chalk24.dim(" Learning hooks are active. Use your AI agent and insights"));
|
|
14725
14859
|
console.log(chalk24.dim(" will appear automatically after each session.\n"));
|
|
14726
|
-
console.log(
|
|
14860
|
+
console.log(
|
|
14861
|
+
chalk24.dim(
|
|
14862
|
+
` Progress: 0/${MIN_SESSIONS_FULL} sessions \u2014 full insights unlock at ${MIN_SESSIONS_FULL}`
|
|
14863
|
+
)
|
|
14864
|
+
);
|
|
14727
14865
|
}
|
|
14728
14866
|
console.log(chalk24.dim(`
|
|
14729
14867
|
Config score: ${score.score}/100 (${score.grade})`));
|
|
@@ -14732,20 +14870,32 @@ function displayColdStart(score) {
|
|
|
14732
14870
|
function displayEarlyData(data, score) {
|
|
14733
14871
|
console.log(chalk24.bold("\n Agent Insights") + chalk24.yellow(" (early data)\n"));
|
|
14734
14872
|
const remaining = MIN_SESSIONS_FULL - data.totalSessions;
|
|
14735
|
-
console.log(
|
|
14736
|
-
|
|
14873
|
+
console.log(
|
|
14874
|
+
chalk24.dim(
|
|
14875
|
+
` ${data.totalSessions}/${MIN_SESSIONS_FULL} sessions tracked \u2014 ${remaining} more for full insights.
|
|
14876
|
+
`
|
|
14877
|
+
)
|
|
14878
|
+
);
|
|
14737
14879
|
console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
|
|
14738
14880
|
console.log(` Learnings accumulated: ${chalk24.cyan(String(data.learningCount))}`);
|
|
14739
14881
|
if (data.totalWasteTokens > 0) {
|
|
14740
|
-
console.log(
|
|
14882
|
+
console.log(
|
|
14883
|
+
` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`
|
|
14884
|
+
);
|
|
14741
14885
|
}
|
|
14742
14886
|
if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
|
|
14743
|
-
console.log(
|
|
14887
|
+
console.log(
|
|
14888
|
+
` Failure rate trend: ${chalk24.green(`${data.failureRateImprovement}% fewer`)} failures with learnings ${chalk24.dim("(early signal)")}`
|
|
14889
|
+
);
|
|
14744
14890
|
} else if (data.totalSessions > 0 && data.failureRateImprovement === null) {
|
|
14745
|
-
console.log(
|
|
14891
|
+
console.log(
|
|
14892
|
+
` Failure rate trend: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`
|
|
14893
|
+
);
|
|
14746
14894
|
}
|
|
14747
14895
|
if (data.taskSuccessRate !== null) {
|
|
14748
|
-
console.log(
|
|
14896
|
+
console.log(
|
|
14897
|
+
` Task success rate: ${chalk24.cyan(`${data.taskSuccessRate}%`)} ${chalk24.dim(`(${data.taskCount} tasks)`)}`
|
|
14898
|
+
);
|
|
14749
14899
|
}
|
|
14750
14900
|
console.log(` Config score: ${chalk24.cyan(`${score.score}/100`)} (${score.grade})`);
|
|
14751
14901
|
console.log("");
|
|
@@ -14755,32 +14905,48 @@ function displayFullInsights(data, score) {
|
|
|
14755
14905
|
console.log(chalk24.bold(" Agent Health"));
|
|
14756
14906
|
if (data.taskSuccessRate !== null) {
|
|
14757
14907
|
const color = data.taskSuccessRate >= 80 ? chalk24.green : data.taskSuccessRate >= 60 ? chalk24.yellow : chalk24.red;
|
|
14758
|
-
console.log(
|
|
14908
|
+
console.log(
|
|
14909
|
+
` Task success rate: ${color(`${data.taskSuccessRate}%`)} across ${data.taskCount} tasks`
|
|
14910
|
+
);
|
|
14759
14911
|
if (data.taskCorrectionCount > 0) {
|
|
14760
|
-
console.log(
|
|
14912
|
+
console.log(
|
|
14913
|
+
` Corrections needed: ${chalk24.yellow(String(data.taskCorrectionCount))} tasks required user correction`
|
|
14914
|
+
);
|
|
14761
14915
|
}
|
|
14762
14916
|
}
|
|
14763
14917
|
console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
|
|
14764
14918
|
console.log(chalk24.bold("\n Learning Impact"));
|
|
14765
14919
|
console.log(` Learnings active: ${chalk24.cyan(String(data.learningCount))}`);
|
|
14766
14920
|
if (data.failureRateWith !== null && data.failureRateWithout !== null) {
|
|
14767
|
-
console.log(
|
|
14921
|
+
console.log(
|
|
14922
|
+
` Failure rate: ${chalk24.red(data.failureRateWithout.toFixed(1))}/session ${chalk24.dim("\u2192")} ${chalk24.green(data.failureRateWith.toFixed(1))}/session with learnings`
|
|
14923
|
+
);
|
|
14768
14924
|
if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
|
|
14769
|
-
console.log(
|
|
14925
|
+
console.log(
|
|
14926
|
+
` Improvement: ${chalk24.green(`${data.failureRateImprovement}%`)} fewer failures`
|
|
14927
|
+
);
|
|
14770
14928
|
} else if (data.failureRateImprovement === null) {
|
|
14771
|
-
console.log(
|
|
14929
|
+
console.log(
|
|
14930
|
+
` Improvement: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`
|
|
14931
|
+
);
|
|
14772
14932
|
}
|
|
14773
14933
|
}
|
|
14774
14934
|
if (data.totalWasteTokens > 0 || data.estimatedSavingsTokens > 0) {
|
|
14775
14935
|
console.log(chalk24.bold("\n Efficiency"));
|
|
14776
14936
|
if (data.totalWasteTokens > 0) {
|
|
14777
|
-
console.log(
|
|
14937
|
+
console.log(
|
|
14938
|
+
` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`
|
|
14939
|
+
);
|
|
14778
14940
|
}
|
|
14779
14941
|
if (data.estimatedSavingsTokens > 0) {
|
|
14780
|
-
console.log(
|
|
14942
|
+
console.log(
|
|
14943
|
+
` Estimated savings: ~${chalk24.green(data.estimatedSavingsTokens.toLocaleString())} tokens`
|
|
14944
|
+
);
|
|
14781
14945
|
}
|
|
14782
14946
|
if (data.estimatedSavingsSeconds > 0) {
|
|
14783
|
-
console.log(
|
|
14947
|
+
console.log(
|
|
14948
|
+
` Time saved: ~${chalk24.green(formatDuration(data.estimatedSavingsSeconds))}`
|
|
14949
|
+
);
|
|
14784
14950
|
}
|
|
14785
14951
|
}
|
|
14786
14952
|
console.log(chalk24.bold("\n Config Quality"));
|
|
@@ -14791,7 +14957,9 @@ function displayFullInsights(data, score) {
|
|
|
14791
14957
|
const trendColor = trend.direction === "up" ? chalk24.green : trend.direction === "down" ? chalk24.red : chalk24.gray;
|
|
14792
14958
|
const arrow = trend.direction === "up" ? "\u2191" : trend.direction === "down" ? "\u2193" : "\u2192";
|
|
14793
14959
|
const sign = trend.delta > 0 ? "+" : "";
|
|
14794
|
-
console.log(
|
|
14960
|
+
console.log(
|
|
14961
|
+
` Trend: ${trendColor(`${arrow} ${sign}${trend.delta} pts`)} ${chalk24.dim(`over ${trend.entries} checks`)}`
|
|
14962
|
+
);
|
|
14795
14963
|
}
|
|
14796
14964
|
console.log("");
|
|
14797
14965
|
}
|
|
@@ -14801,12 +14969,18 @@ async function insightsCommand(options) {
|
|
|
14801
14969
|
const score = computeLocalScore(process.cwd(), readState()?.targetAgent);
|
|
14802
14970
|
trackInsightsViewed(data.totalSessions, data.learningCount);
|
|
14803
14971
|
if (options.json) {
|
|
14804
|
-
console.log(
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
14972
|
+
console.log(
|
|
14973
|
+
JSON.stringify(
|
|
14974
|
+
{
|
|
14975
|
+
...data,
|
|
14976
|
+
tier: data.totalSessions === 0 ? "cold-start" : data.totalSessions < MIN_SESSIONS_FULL ? "early" : "full",
|
|
14977
|
+
configScore: score.score,
|
|
14978
|
+
configGrade: score.grade
|
|
14979
|
+
},
|
|
14980
|
+
null,
|
|
14981
|
+
2
|
|
14982
|
+
)
|
|
14983
|
+
);
|
|
14810
14984
|
return;
|
|
14811
14985
|
}
|
|
14812
14986
|
if (data.totalSessions === 0) {
|
|
@@ -14829,7 +15003,9 @@ async function sourcesListCommand() {
|
|
|
14829
15003
|
const workspaces = getDetectedWorkspaces(dir);
|
|
14830
15004
|
if (configSources.length === 0 && workspaces.length === 0) {
|
|
14831
15005
|
console.log(chalk25.dim("\n No sources configured.\n"));
|
|
14832
|
-
console.log(
|
|
15006
|
+
console.log(
|
|
15007
|
+
chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")(`${displayCaliberName()} sources add <path>`)
|
|
15008
|
+
);
|
|
14833
15009
|
console.log(chalk25.dim(" Or add to .caliber/sources.json manually.\n"));
|
|
14834
15010
|
return;
|
|
14835
15011
|
}
|
|
@@ -14841,7 +15017,9 @@ async function sourcesListCommand() {
|
|
|
14841
15017
|
const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
|
|
14842
15018
|
const hasSummary = source.path && fs49.existsSync(path40.join(path40.resolve(dir, source.path), ".caliber", "summary.json"));
|
|
14843
15019
|
console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
|
|
14844
|
-
console.log(
|
|
15020
|
+
console.log(
|
|
15021
|
+
` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`
|
|
15022
|
+
);
|
|
14845
15023
|
if (source.description) console.log(` ${chalk25.dim(source.description)}`);
|
|
14846
15024
|
console.log("");
|
|
14847
15025
|
}
|
|
@@ -14872,9 +15050,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
14872
15050
|
throw new Error("__exit__");
|
|
14873
15051
|
}
|
|
14874
15052
|
const existing = loadSourcesConfig(dir);
|
|
14875
|
-
const alreadyConfigured = existing.some(
|
|
14876
|
-
(s) => s.path && path40.resolve(dir, s.path) === absPath
|
|
14877
|
-
);
|
|
15053
|
+
const alreadyConfigured = existing.some((s) => s.path && path40.resolve(dir, s.path) === absPath);
|
|
14878
15054
|
if (alreadyConfigured) {
|
|
14879
15055
|
console.log(chalk25.yellow(`
|
|
14880
15056
|
Already configured: ${sourcePath}
|
|
@@ -14900,9 +15076,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
14900
15076
|
async function sourcesRemoveCommand(name) {
|
|
14901
15077
|
const dir = process.cwd();
|
|
14902
15078
|
const existing = loadSourcesConfig(dir);
|
|
14903
|
-
const idx = existing.findIndex(
|
|
14904
|
-
(s) => s.path?.includes(name) || s.role === name
|
|
14905
|
-
);
|
|
15079
|
+
const idx = existing.findIndex((s) => s.path?.includes(name) || s.role === name);
|
|
14906
15080
|
if (idx === -1) {
|
|
14907
15081
|
console.log(chalk25.red(`
|
|
14908
15082
|
Source not found: ${name}
|
|
@@ -14915,9 +15089,11 @@ async function sourcesRemoveCommand(name) {
|
|
|
14915
15089
|
}
|
|
14916
15090
|
const removed = existing.splice(idx, 1)[0];
|
|
14917
15091
|
writeSourcesConfig(dir, existing);
|
|
14918
|
-
console.log(
|
|
15092
|
+
console.log(
|
|
15093
|
+
chalk25.green(`
|
|
14919
15094
|
\u2713 Removed ${removed.path || removed.url} (${removed.role || removed.type})
|
|
14920
|
-
`)
|
|
15095
|
+
`)
|
|
15096
|
+
);
|
|
14921
15097
|
}
|
|
14922
15098
|
|
|
14923
15099
|
// src/commands/publish.ts
|
|
@@ -14931,7 +15107,9 @@ async function publishCommand() {
|
|
|
14931
15107
|
const dir = process.cwd();
|
|
14932
15108
|
const config = loadConfig();
|
|
14933
15109
|
if (!config) {
|
|
14934
|
-
console.log(
|
|
15110
|
+
console.log(
|
|
15111
|
+
chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")(`${displayCaliberName()} config`) + chalk26.red(" first.")
|
|
15112
|
+
);
|
|
14935
15113
|
throw new Error("__exit__");
|
|
14936
15114
|
}
|
|
14937
15115
|
const spinner = ora7("Generating project summary...").start();
|
|
@@ -14974,7 +15152,9 @@ async function publishCommand() {
|
|
|
14974
15152
|
spinner.succeed("Project summary published");
|
|
14975
15153
|
console.log(` ${chalk26.green("\u2713")} ${path41.relative(dir, outputPath)}`);
|
|
14976
15154
|
console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
|
|
14977
|
-
console.log(
|
|
15155
|
+
console.log(
|
|
15156
|
+
chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n")
|
|
15157
|
+
);
|
|
14978
15158
|
} catch (err) {
|
|
14979
15159
|
spinner.fail("Failed to generate summary");
|
|
14980
15160
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
package/package.json
CHANGED