@rely-ai/caliber 1.48.2 → 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 +314 -162
- 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,11 @@ 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;
|
|
4821
4842
|
function tryWindowsDirectNodeInvocation(cmd) {
|
|
4822
4843
|
if (process.platform !== "win32") return null;
|
|
4823
4844
|
if (!/\.cmd$/i.test(cmd)) return null;
|
|
@@ -4875,7 +4896,7 @@ function getPrecommitBlock() {
|
|
|
4875
4896
|
if ${guard}; then
|
|
4876
4897
|
mkdir -p .caliber
|
|
4877
4898
|
echo "\\033[2mcaliber: refreshing docs...\\033[0m"
|
|
4878
|
-
${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
|
|
4879
4900
|
${invoke} learn finalize 2>>.caliber/refresh-hook.log || true
|
|
4880
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
|
|
4881
4902
|
fi
|
|
@@ -4900,19 +4921,29 @@ function isPreCommitHookInstalled() {
|
|
|
4900
4921
|
const hookPath = getPreCommitPath();
|
|
4901
4922
|
if (!hookPath || !fs11.existsSync(hookPath)) return false;
|
|
4902
4923
|
const content = fs11.readFileSync(hookPath, "utf-8");
|
|
4903
|
-
return
|
|
4924
|
+
return PRECOMMIT_ANY_VERSION_START_RE.test(content);
|
|
4904
4925
|
}
|
|
4905
4926
|
function installPreCommitHook() {
|
|
4906
|
-
if (isPreCommitHookInstalled()) {
|
|
4907
|
-
return { installed: false, alreadyInstalled: true };
|
|
4908
|
-
}
|
|
4909
4927
|
const hookPath = getPreCommitPath();
|
|
4910
|
-
if (!hookPath)
|
|
4928
|
+
if (!hookPath) {
|
|
4929
|
+
return { installed: false, alreadyInstalled: false, upgraded: false };
|
|
4930
|
+
}
|
|
4911
4931
|
const hooksDir = path10.dirname(hookPath);
|
|
4912
4932
|
if (!fs11.existsSync(hooksDir)) fs11.mkdirSync(hooksDir, { recursive: true });
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
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) {
|
|
4916
4947
|
if (!content.endsWith("\n")) content += "\n";
|
|
4917
4948
|
content += "\n" + getPrecommitBlock() + "\n";
|
|
4918
4949
|
} else {
|
|
@@ -4920,7 +4951,7 @@ function installPreCommitHook() {
|
|
|
4920
4951
|
}
|
|
4921
4952
|
fs11.writeFileSync(hookPath, content);
|
|
4922
4953
|
fs11.chmodSync(hookPath, 493);
|
|
4923
|
-
return { installed: true, alreadyInstalled: false };
|
|
4954
|
+
return { installed: true, alreadyInstalled: false, upgraded: false };
|
|
4924
4955
|
}
|
|
4925
4956
|
function removePreCommitHook() {
|
|
4926
4957
|
const hookPath = getPreCommitPath();
|
|
@@ -4928,11 +4959,10 @@ function removePreCommitHook() {
|
|
|
4928
4959
|
return { removed: false, notFound: true };
|
|
4929
4960
|
}
|
|
4930
4961
|
let content = fs11.readFileSync(hookPath, "utf-8");
|
|
4931
|
-
if (!
|
|
4962
|
+
if (!PRECOMMIT_ANY_VERSION_START_RE.test(content)) {
|
|
4932
4963
|
return { removed: false, notFound: true };
|
|
4933
4964
|
}
|
|
4934
|
-
|
|
4935
|
-
content = content.replace(regex, "\n");
|
|
4965
|
+
content = content.replace(PRECOMMIT_ANY_VERSION_BLOCK_RE, "\n").replace(/\n{3,}/g, "\n\n");
|
|
4936
4966
|
if (content.trim() === "#!/bin/sh" || content.trim() === "") {
|
|
4937
4967
|
fs11.unlinkSync(hookPath);
|
|
4938
4968
|
} else {
|
|
@@ -7745,10 +7775,11 @@ function detectGitDrift(dir) {
|
|
|
7745
7775
|
}
|
|
7746
7776
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
|
|
7747
7777
|
try {
|
|
7748
|
-
const headTimestamp = execSync12(
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7778
|
+
const headTimestamp = execSync12("git log -1 --format=%ct HEAD", {
|
|
7779
|
+
cwd: dir,
|
|
7780
|
+
encoding: "utf-8",
|
|
7781
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7782
|
+
}).trim();
|
|
7752
7783
|
const headTime = parseInt(headTimestamp, 10) * 1e3;
|
|
7753
7784
|
for (const file of configFiles) {
|
|
7754
7785
|
const filePath = join5(dir, file);
|
|
@@ -7756,7 +7787,11 @@ function detectGitDrift(dir) {
|
|
|
7756
7787
|
try {
|
|
7757
7788
|
const mtime = statSync(filePath).mtime.getTime();
|
|
7758
7789
|
if (mtime > headTime) {
|
|
7759
|
-
return {
|
|
7790
|
+
return {
|
|
7791
|
+
commitsSinceConfigUpdate: 0,
|
|
7792
|
+
lastConfigCommit: "uncommitted (recently modified)",
|
|
7793
|
+
isGitRepo: true
|
|
7794
|
+
};
|
|
7760
7795
|
}
|
|
7761
7796
|
} catch {
|
|
7762
7797
|
}
|
|
@@ -7766,19 +7801,20 @@ function detectGitDrift(dir) {
|
|
|
7766
7801
|
let latestConfigCommitHash = null;
|
|
7767
7802
|
for (const file of configFiles) {
|
|
7768
7803
|
try {
|
|
7769
|
-
const hash = execSync12(
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7804
|
+
const hash = execSync12(`git log -1 --format=%H -- "${file}"`, {
|
|
7805
|
+
cwd: dir,
|
|
7806
|
+
encoding: "utf-8",
|
|
7807
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7808
|
+
}).trim();
|
|
7773
7809
|
if (!hash) continue;
|
|
7774
7810
|
if (!latestConfigCommitHash) {
|
|
7775
7811
|
latestConfigCommitHash = hash;
|
|
7776
7812
|
} else {
|
|
7777
7813
|
try {
|
|
7778
|
-
execSync12(
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
);
|
|
7814
|
+
execSync12(`git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`, {
|
|
7815
|
+
cwd: dir,
|
|
7816
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7817
|
+
});
|
|
7782
7818
|
latestConfigCommitHash = hash;
|
|
7783
7819
|
} catch {
|
|
7784
7820
|
}
|
|
@@ -7790,22 +7826,28 @@ function detectGitDrift(dir) {
|
|
|
7790
7826
|
return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: true };
|
|
7791
7827
|
}
|
|
7792
7828
|
try {
|
|
7793
|
-
const countStr = execSync12(
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7829
|
+
const countStr = execSync12(`git rev-list --count ${latestConfigCommitHash}..HEAD`, {
|
|
7830
|
+
cwd: dir,
|
|
7831
|
+
encoding: "utf-8",
|
|
7832
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7833
|
+
}).trim();
|
|
7797
7834
|
const commitsSince = parseInt(countStr, 10) || 0;
|
|
7798
|
-
const lastDate = execSync12(
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7835
|
+
const lastDate = execSync12(`git log -1 --format=%ci ${latestConfigCommitHash}`, {
|
|
7836
|
+
cwd: dir,
|
|
7837
|
+
encoding: "utf-8",
|
|
7838
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7839
|
+
}).trim();
|
|
7802
7840
|
return {
|
|
7803
7841
|
commitsSinceConfigUpdate: commitsSince,
|
|
7804
7842
|
lastConfigCommit: lastDate,
|
|
7805
7843
|
isGitRepo: true
|
|
7806
7844
|
};
|
|
7807
7845
|
} catch {
|
|
7808
|
-
return {
|
|
7846
|
+
return {
|
|
7847
|
+
commitsSinceConfigUpdate: 0,
|
|
7848
|
+
lastConfigCommit: latestConfigCommitHash,
|
|
7849
|
+
isGitRepo: true
|
|
7850
|
+
};
|
|
7809
7851
|
}
|
|
7810
7852
|
}
|
|
7811
7853
|
function checkAccuracy(dir) {
|
|
@@ -7855,10 +7897,13 @@ function checkAccuracy(dir) {
|
|
|
7855
7897
|
earnedPoints: driftPoints,
|
|
7856
7898
|
passed: drift.commitsSinceConfigUpdate <= 15 || !drift.isGitRepo,
|
|
7857
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`,
|
|
7858
|
-
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,
|
|
7859
7901
|
fix: drift.commitsSinceConfigUpdate > 15 ? {
|
|
7860
7902
|
action: "refresh_config",
|
|
7861
|
-
data: {
|
|
7903
|
+
data: {
|
|
7904
|
+
commitsSince: drift.commitsSinceConfigUpdate,
|
|
7905
|
+
lastConfigCommit: drift.lastConfigCommit
|
|
7906
|
+
},
|
|
7862
7907
|
instruction: `Config is ${drift.commitsSinceConfigUpdate} commits behind. Review recent changes and update config accordingly.`
|
|
7863
7908
|
} : void 0
|
|
7864
7909
|
});
|
|
@@ -7873,10 +7918,11 @@ import { join as join6 } from "path";
|
|
|
7873
7918
|
function getCommitsSinceConfigUpdate(dir) {
|
|
7874
7919
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
|
|
7875
7920
|
try {
|
|
7876
|
-
const headTimestamp = execSync13(
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7921
|
+
const headTimestamp = execSync13("git log -1 --format=%ct HEAD", {
|
|
7922
|
+
cwd: dir,
|
|
7923
|
+
encoding: "utf-8",
|
|
7924
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7925
|
+
}).trim();
|
|
7880
7926
|
const headTime = parseInt(headTimestamp, 10) * 1e3;
|
|
7881
7927
|
for (const file of configFiles) {
|
|
7882
7928
|
const filePath = join6(dir, file);
|
|
@@ -7893,15 +7939,17 @@ function getCommitsSinceConfigUpdate(dir) {
|
|
|
7893
7939
|
}
|
|
7894
7940
|
for (const file of configFiles) {
|
|
7895
7941
|
try {
|
|
7896
|
-
const hash = execSync13(
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7942
|
+
const hash = execSync13(`git log -1 --format=%H -- "${file}"`, {
|
|
7943
|
+
cwd: dir,
|
|
7944
|
+
encoding: "utf-8",
|
|
7945
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7946
|
+
}).trim();
|
|
7900
7947
|
if (hash) {
|
|
7901
|
-
const countStr = execSync13(
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7948
|
+
const countStr = execSync13(`git rev-list --count ${hash}..HEAD`, {
|
|
7949
|
+
cwd: dir,
|
|
7950
|
+
encoding: "utf-8",
|
|
7951
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7952
|
+
}).trim();
|
|
7905
7953
|
return parseInt(countStr, 10) || 0;
|
|
7906
7954
|
}
|
|
7907
7955
|
} catch {
|
|
@@ -7930,7 +7978,7 @@ function checkFreshness(dir) {
|
|
|
7930
7978
|
earnedPoints: freshnessPoints,
|
|
7931
7979
|
passed: freshnessPoints >= 3,
|
|
7932
7980
|
detail: freshnessDetail,
|
|
7933
|
-
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,
|
|
7934
7982
|
fix: commitsSince !== null && freshnessPoints < 3 ? {
|
|
7935
7983
|
action: "refresh_config",
|
|
7936
7984
|
data: { commitsSince },
|
|
@@ -8082,11 +8130,11 @@ function checkBonus(dir) {
|
|
|
8082
8130
|
earnedPoints: hasHooks ? POINTS_HOOKS : 0,
|
|
8083
8131
|
passed: hasHooks,
|
|
8084
8132
|
detail: hasHooks ? hookSources.join(", ") : "No hooks configured",
|
|
8085
|
-
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`,
|
|
8086
8134
|
fix: hasHooks ? void 0 : {
|
|
8087
8135
|
action: "install_hooks",
|
|
8088
8136
|
data: {},
|
|
8089
|
-
instruction: `Run ${
|
|
8137
|
+
instruction: `Run ${displayCaliberName()} init to add pre-commit refresh instructions to config files.`
|
|
8090
8138
|
}
|
|
8091
8139
|
});
|
|
8092
8140
|
const agentsMdExists = existsSync6(join7(dir, "AGENTS.md"));
|
|
@@ -8151,7 +8199,7 @@ function checkBonus(dir) {
|
|
|
8151
8199
|
earnedPoints: hasLearned ? POINTS_LEARNED_CONTENT : 0,
|
|
8152
8200
|
passed: hasLearned,
|
|
8153
8201
|
detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
|
|
8154
|
-
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\``
|
|
8155
8203
|
});
|
|
8156
8204
|
const configContent = (() => {
|
|
8157
8205
|
const parts = [];
|
|
@@ -8198,7 +8246,7 @@ function checkSources(dir) {
|
|
|
8198
8246
|
earnedPoints: hasSources ? POINTS_SOURCES_CONFIGURED : 0,
|
|
8199
8247
|
passed: hasSources,
|
|
8200
8248
|
detail: hasSources ? `${configSources.length} source${configSources.length === 1 ? "" : "s"} configured` : "No external sources configured",
|
|
8201
|
-
suggestion: hasSources ? void 0 : `Run \`${
|
|
8249
|
+
suggestion: hasSources ? void 0 : `Run \`${displayCaliberName()} sources add <path>\` to add related repos or docs`
|
|
8202
8250
|
});
|
|
8203
8251
|
if (hasSources) {
|
|
8204
8252
|
const claudeMd = readFileOrNull(join8(dir, "CLAUDE.md"));
|
|
@@ -8216,7 +8264,7 @@ function checkSources(dir) {
|
|
|
8216
8264
|
earnedPoints: referenced ? POINTS_SOURCES_REFERENCED : 0,
|
|
8217
8265
|
passed: referenced,
|
|
8218
8266
|
detail: referenced ? "At least one source is referenced in CLAUDE.md" : "No configured sources are mentioned in CLAUDE.md",
|
|
8219
|
-
suggestion: referenced ? void 0 : `Regenerate with \`${
|
|
8267
|
+
suggestion: referenced ? void 0 : `Regenerate with \`${displayCaliberName()} init\` to include source context in your config`
|
|
8220
8268
|
});
|
|
8221
8269
|
}
|
|
8222
8270
|
return checks;
|
|
@@ -8327,7 +8375,14 @@ var CATEGORY_LABELS = {
|
|
|
8327
8375
|
freshness: { icon: "\u{1F6E1}\uFE0F", label: "FRESHNESS & SAFETY" },
|
|
8328
8376
|
bonus: { icon: "\u2B50", label: "BONUS" }
|
|
8329
8377
|
};
|
|
8330
|
-
var CATEGORY_ORDER = [
|
|
8378
|
+
var CATEGORY_ORDER = [
|
|
8379
|
+
"existence",
|
|
8380
|
+
"quality",
|
|
8381
|
+
"grounding",
|
|
8382
|
+
"accuracy",
|
|
8383
|
+
"freshness",
|
|
8384
|
+
"bonus"
|
|
8385
|
+
];
|
|
8331
8386
|
function gradeColor(grade) {
|
|
8332
8387
|
switch (grade) {
|
|
8333
8388
|
case "A":
|
|
@@ -8396,7 +8451,9 @@ function displayScore(result) {
|
|
|
8396
8451
|
console.log("");
|
|
8397
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"));
|
|
8398
8453
|
console.log("");
|
|
8399
|
-
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
|
+
);
|
|
8400
8457
|
console.log(` ${progressBar(result.score, result.maxScore)}`);
|
|
8401
8458
|
console.log(chalk3.dim(` Target: ${agentLabel}`));
|
|
8402
8459
|
console.log("");
|
|
@@ -8419,7 +8476,11 @@ function displayScore(result) {
|
|
|
8419
8476
|
formatTopImprovements(result.checks);
|
|
8420
8477
|
}
|
|
8421
8478
|
function formatTopImprovements(checks) {
|
|
8422
|
-
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);
|
|
8423
8484
|
if (improvable.length === 0) return;
|
|
8424
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"));
|
|
8425
8486
|
console.log("");
|
|
@@ -8450,8 +8511,12 @@ function displayScoreSummary(result) {
|
|
|
8450
8511
|
}
|
|
8451
8512
|
const remaining = failing.length - shown.length;
|
|
8452
8513
|
const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
8453
|
-
console.log(
|
|
8454
|
-
|
|
8514
|
+
console.log(
|
|
8515
|
+
chalk3.dim(
|
|
8516
|
+
`
|
|
8517
|
+
Run ${chalk3.hex("#83D1EB")(`${displayCaliberName()} score`)} for details.${moreText}`
|
|
8518
|
+
)
|
|
8519
|
+
);
|
|
8455
8520
|
}
|
|
8456
8521
|
console.log("");
|
|
8457
8522
|
}
|
|
@@ -8467,7 +8532,9 @@ function displayScoreDelta(before, after) {
|
|
|
8467
8532
|
console.log(
|
|
8468
8533
|
` Score: ${beforeGc(`${before.score}`)} ${chalk3.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk3.gray("\u2192")} ${afterGc(after.grade)}`
|
|
8469
8534
|
);
|
|
8470
|
-
console.log(
|
|
8535
|
+
console.log(
|
|
8536
|
+
` ${progressBar(before.score, before.maxScore, 19)} ${chalk3.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`
|
|
8537
|
+
);
|
|
8471
8538
|
console.log("");
|
|
8472
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"));
|
|
8473
8540
|
console.log("");
|
|
@@ -9149,7 +9216,7 @@ async function querySkills(query) {
|
|
|
9149
9216
|
console.log("");
|
|
9150
9217
|
console.log(
|
|
9151
9218
|
chalk5.dim(
|
|
9152
|
-
` Install with: ${
|
|
9219
|
+
` Install with: ${displayCaliberName()} skills --install ${available.map((r) => r.slug).join(",")}`
|
|
9153
9220
|
)
|
|
9154
9221
|
);
|
|
9155
9222
|
console.log("");
|
|
@@ -11137,7 +11204,7 @@ function log(verbose, ...args) {
|
|
|
11137
11204
|
async function initCommand(options) {
|
|
11138
11205
|
const brand = chalk14.hex("#EB9D83");
|
|
11139
11206
|
const title = chalk14.hex("#83D1EB");
|
|
11140
|
-
const bin =
|
|
11207
|
+
const bin = displayCaliberName();
|
|
11141
11208
|
const firstRun = isFirstRun(process.cwd());
|
|
11142
11209
|
if (firstRun) {
|
|
11143
11210
|
console.log(
|
|
@@ -11278,6 +11345,8 @@ async function initCommand(options) {
|
|
|
11278
11345
|
const hookResult = installPreCommitHook();
|
|
11279
11346
|
if (hookResult.installed) {
|
|
11280
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`);
|
|
11281
11350
|
} else if (hookResult.alreadyInstalled) {
|
|
11282
11351
|
console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 active`);
|
|
11283
11352
|
}
|
|
@@ -11977,24 +12046,34 @@ async function statusCommand(options) {
|
|
|
11977
12046
|
const config = loadConfig();
|
|
11978
12047
|
const manifest = readManifest();
|
|
11979
12048
|
if (options.json) {
|
|
11980
|
-
console.log(
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
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
|
+
);
|
|
11986
12061
|
return;
|
|
11987
12062
|
}
|
|
11988
12063
|
console.log(chalk16.bold("\nCaliber Status\n"));
|
|
11989
12064
|
if (config) {
|
|
11990
12065
|
console.log(` LLM: ${chalk16.green(config.provider)} (${config.model})`);
|
|
11991
12066
|
} else {
|
|
11992
|
-
const bin =
|
|
11993
|
-
console.log(
|
|
12067
|
+
const bin = displayCaliberName();
|
|
12068
|
+
console.log(
|
|
12069
|
+
` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")(`${bin} config`)}`
|
|
12070
|
+
);
|
|
11994
12071
|
}
|
|
11995
12072
|
if (!manifest) {
|
|
11996
12073
|
console.log(` Config: ${chalk16.dim("No config applied")}`);
|
|
11997
|
-
console.log(
|
|
12074
|
+
console.log(
|
|
12075
|
+
chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")(`${displayCaliberName()} init`) + chalk16.dim(" to get started.\n")
|
|
12076
|
+
);
|
|
11998
12077
|
return;
|
|
11999
12078
|
}
|
|
12000
12079
|
console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
|
|
@@ -12014,15 +12093,19 @@ init_review();
|
|
|
12014
12093
|
init_config();
|
|
12015
12094
|
init_resolve_caliber();
|
|
12016
12095
|
async function regenerateCommand(options) {
|
|
12017
|
-
const bin =
|
|
12096
|
+
const bin = displayCaliberName();
|
|
12018
12097
|
const config = loadConfig();
|
|
12019
12098
|
if (!config) {
|
|
12020
|
-
console.log(
|
|
12099
|
+
console.log(
|
|
12100
|
+
chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")(`${bin} config`) + chalk17.red(" first.")
|
|
12101
|
+
);
|
|
12021
12102
|
throw new Error("__exit__");
|
|
12022
12103
|
}
|
|
12023
12104
|
const manifest = readManifest();
|
|
12024
12105
|
if (!manifest) {
|
|
12025
|
-
console.log(
|
|
12106
|
+
console.log(
|
|
12107
|
+
chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")(`${bin} init`) + chalk17.yellow(" first.")
|
|
12108
|
+
);
|
|
12026
12109
|
throw new Error("__exit__");
|
|
12027
12110
|
}
|
|
12028
12111
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
@@ -12037,27 +12120,24 @@ async function regenerateCommand(options) {
|
|
|
12037
12120
|
return;
|
|
12038
12121
|
}
|
|
12039
12122
|
const genSpinner = ora5("Regenerating config...").start();
|
|
12040
|
-
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, {
|
|
12123
|
+
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, {
|
|
12124
|
+
showElapsedTime: true
|
|
12125
|
+
});
|
|
12041
12126
|
genMessages.start();
|
|
12042
12127
|
let generatedSetup = null;
|
|
12043
12128
|
try {
|
|
12044
|
-
const result = await generateSetup(
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
{
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
},
|
|
12055
|
-
onError: (error) => {
|
|
12056
|
-
genMessages.stop();
|
|
12057
|
-
genSpinner.fail(`Generation error: ${error}`);
|
|
12058
|
-
}
|
|
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}`);
|
|
12059
12139
|
}
|
|
12060
|
-
);
|
|
12140
|
+
});
|
|
12061
12141
|
if (!generatedSetup) generatedSetup = result.setup;
|
|
12062
12142
|
} catch (err) {
|
|
12063
12143
|
genMessages.stop();
|
|
@@ -12075,9 +12155,13 @@ async function regenerateCommand(options) {
|
|
|
12075
12155
|
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
12076
12156
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
12077
12157
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
12078
|
-
console.log(
|
|
12158
|
+
console.log(
|
|
12159
|
+
chalk17.dim(
|
|
12160
|
+
`
|
|
12079
12161
|
${chalk17.green(`${staged.newFiles} new`)} / ${chalk17.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
12080
|
-
`
|
|
12162
|
+
`
|
|
12163
|
+
)
|
|
12164
|
+
);
|
|
12081
12165
|
if (totalChanges === 0) {
|
|
12082
12166
|
console.log(chalk17.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
12083
12167
|
cleanupStaging();
|
|
@@ -12138,21 +12222,33 @@ async function regenerateCommand(options) {
|
|
|
12138
12222
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
12139
12223
|
if (afterScore.score < baselineScore.score) {
|
|
12140
12224
|
console.log("");
|
|
12141
|
-
console.log(
|
|
12225
|
+
console.log(
|
|
12226
|
+
chalk17.yellow(
|
|
12227
|
+
` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
|
|
12228
|
+
)
|
|
12229
|
+
);
|
|
12142
12230
|
try {
|
|
12143
12231
|
const { restored, removed } = undoSetup();
|
|
12144
12232
|
if (restored.length > 0 || removed.length > 0) {
|
|
12145
|
-
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
|
+
);
|
|
12146
12238
|
}
|
|
12147
12239
|
} catch {
|
|
12148
12240
|
}
|
|
12149
|
-
console.log(
|
|
12241
|
+
console.log(
|
|
12242
|
+
chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} init --force`) + chalk17.dim(" to override.\n")
|
|
12243
|
+
);
|
|
12150
12244
|
return;
|
|
12151
12245
|
}
|
|
12152
12246
|
displayScoreDelta(baselineScore, afterScore);
|
|
12153
12247
|
trackRegenerateCompleted(action, Date.now());
|
|
12154
12248
|
console.log(chalk17.bold.green(" Regeneration complete!"));
|
|
12155
|
-
console.log(
|
|
12249
|
+
console.log(
|
|
12250
|
+
chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} undo`) + chalk17.dim(" to revert changes.\n")
|
|
12251
|
+
);
|
|
12156
12252
|
}
|
|
12157
12253
|
|
|
12158
12254
|
// src/commands/score.ts
|
|
@@ -12267,7 +12363,7 @@ async function scoreCommand(options) {
|
|
|
12267
12363
|
displayScore(result);
|
|
12268
12364
|
const separator = chalk18.gray(" " + "\u2500".repeat(53));
|
|
12269
12365
|
console.log(separator);
|
|
12270
|
-
const bin =
|
|
12366
|
+
const bin = displayCaliberName();
|
|
12271
12367
|
const failing = result.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints));
|
|
12272
12368
|
if (result.score < 70 && failing.length > 0) {
|
|
12273
12369
|
const topFix = failing[0];
|
|
@@ -13228,7 +13324,7 @@ async function refreshCommand(options) {
|
|
|
13228
13324
|
if (!config) {
|
|
13229
13325
|
if (quiet) return;
|
|
13230
13326
|
console.log(
|
|
13231
|
-
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.")
|
|
13232
13328
|
);
|
|
13233
13329
|
throw new Error("__exit__");
|
|
13234
13330
|
}
|
|
@@ -13336,7 +13432,9 @@ async function hooksCommand(options) {
|
|
|
13336
13432
|
if (options.install) {
|
|
13337
13433
|
for (const hook of HOOKS) {
|
|
13338
13434
|
const result = hook.install();
|
|
13339
|
-
if (result.
|
|
13435
|
+
if (result.upgraded) {
|
|
13436
|
+
console.log(chalk20.green(" \u2713") + ` ${hook.label} upgraded to latest version`);
|
|
13437
|
+
} else if (result.alreadyInstalled) {
|
|
13340
13438
|
console.log(chalk20.dim(` ${hook.label} already enabled.`));
|
|
13341
13439
|
} else {
|
|
13342
13440
|
console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
|
|
@@ -14276,7 +14374,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14276
14374
|
if (isAuto) return;
|
|
14277
14375
|
console.log(
|
|
14278
14376
|
chalk23.yellow(
|
|
14279
|
-
`caliber: no LLM provider configured \u2014 run \`${
|
|
14377
|
+
`caliber: no LLM provider configured \u2014 run \`${displayCaliberName()} config\` first`
|
|
14280
14378
|
)
|
|
14281
14379
|
);
|
|
14282
14380
|
clearSession();
|
|
@@ -14442,7 +14540,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14442
14540
|
if (staleLearnings.length > 0 && !isAuto) {
|
|
14443
14541
|
console.log(
|
|
14444
14542
|
chalk23.yellow(
|
|
14445
|
-
`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`
|
|
14446
14544
|
)
|
|
14447
14545
|
);
|
|
14448
14546
|
}
|
|
@@ -14499,7 +14597,7 @@ async function learnInstallCommand() {
|
|
|
14499
14597
|
if (!fs48.existsSync(".claude") && !fs48.existsSync(".cursor")) {
|
|
14500
14598
|
console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
|
|
14501
14599
|
console.log(
|
|
14502
|
-
chalk23.dim(` Run \`${
|
|
14600
|
+
chalk23.dim(` Run \`${displayCaliberName()} init\` first, or create the directory manually.`)
|
|
14503
14601
|
);
|
|
14504
14602
|
return;
|
|
14505
14603
|
}
|
|
@@ -14547,7 +14645,7 @@ async function learnStatusCommand() {
|
|
|
14547
14645
|
}
|
|
14548
14646
|
if (!claudeInstalled && !cursorInstalled) {
|
|
14549
14647
|
console.log(
|
|
14550
|
-
chalk23.dim(` Run \`${
|
|
14648
|
+
chalk23.dim(` Run \`${displayCaliberName()} learn install\` to enable session learning.`)
|
|
14551
14649
|
);
|
|
14552
14650
|
}
|
|
14553
14651
|
console.log();
|
|
@@ -14603,7 +14701,9 @@ function getAllLearnings() {
|
|
|
14603
14701
|
async function learnListCommand(options) {
|
|
14604
14702
|
const items = getAllLearnings();
|
|
14605
14703
|
if (items.length === 0) {
|
|
14606
|
-
console.log(
|
|
14704
|
+
console.log(
|
|
14705
|
+
chalk23.dim(`No learnings yet. Run \`${displayCaliberName()} learn install\` to start.`)
|
|
14706
|
+
);
|
|
14607
14707
|
return;
|
|
14608
14708
|
}
|
|
14609
14709
|
const roiStats = options?.verbose ? readROIStats() : null;
|
|
@@ -14634,7 +14734,7 @@ async function learnDeleteCommand(indexStr) {
|
|
|
14634
14734
|
if (isNaN(index) || index < 1) {
|
|
14635
14735
|
console.log(
|
|
14636
14736
|
chalk23.red(
|
|
14637
|
-
`Invalid index: "${indexStr}". Use a number from \`${
|
|
14737
|
+
`Invalid index: "${indexStr}". Use a number from \`${displayCaliberName()} learn list\`.`
|
|
14638
14738
|
)
|
|
14639
14739
|
);
|
|
14640
14740
|
return;
|
|
@@ -14745,13 +14845,23 @@ function displayColdStart(score) {
|
|
|
14745
14845
|
const hooksInstalled = areLearningHooksInstalled() || areCursorLearningHooksInstalled();
|
|
14746
14846
|
if (!hooksInstalled) {
|
|
14747
14847
|
console.log(chalk24.yellow(" Learning hooks not installed."));
|
|
14748
|
-
console.log(
|
|
14749
|
-
|
|
14750
|
-
|
|
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
|
+
);
|
|
14751
14857
|
} else {
|
|
14752
14858
|
console.log(chalk24.dim(" Learning hooks are active. Use your AI agent and insights"));
|
|
14753
14859
|
console.log(chalk24.dim(" will appear automatically after each session.\n"));
|
|
14754
|
-
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
|
+
);
|
|
14755
14865
|
}
|
|
14756
14866
|
console.log(chalk24.dim(`
|
|
14757
14867
|
Config score: ${score.score}/100 (${score.grade})`));
|
|
@@ -14760,20 +14870,32 @@ function displayColdStart(score) {
|
|
|
14760
14870
|
function displayEarlyData(data, score) {
|
|
14761
14871
|
console.log(chalk24.bold("\n Agent Insights") + chalk24.yellow(" (early data)\n"));
|
|
14762
14872
|
const remaining = MIN_SESSIONS_FULL - data.totalSessions;
|
|
14763
|
-
console.log(
|
|
14764
|
-
|
|
14873
|
+
console.log(
|
|
14874
|
+
chalk24.dim(
|
|
14875
|
+
` ${data.totalSessions}/${MIN_SESSIONS_FULL} sessions tracked \u2014 ${remaining} more for full insights.
|
|
14876
|
+
`
|
|
14877
|
+
)
|
|
14878
|
+
);
|
|
14765
14879
|
console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
|
|
14766
14880
|
console.log(` Learnings accumulated: ${chalk24.cyan(String(data.learningCount))}`);
|
|
14767
14881
|
if (data.totalWasteTokens > 0) {
|
|
14768
|
-
console.log(
|
|
14882
|
+
console.log(
|
|
14883
|
+
` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`
|
|
14884
|
+
);
|
|
14769
14885
|
}
|
|
14770
14886
|
if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
|
|
14771
|
-
console.log(
|
|
14887
|
+
console.log(
|
|
14888
|
+
` Failure rate trend: ${chalk24.green(`${data.failureRateImprovement}% fewer`)} failures with learnings ${chalk24.dim("(early signal)")}`
|
|
14889
|
+
);
|
|
14772
14890
|
} else if (data.totalSessions > 0 && data.failureRateImprovement === null) {
|
|
14773
|
-
console.log(
|
|
14891
|
+
console.log(
|
|
14892
|
+
` Failure rate trend: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`
|
|
14893
|
+
);
|
|
14774
14894
|
}
|
|
14775
14895
|
if (data.taskSuccessRate !== null) {
|
|
14776
|
-
console.log(
|
|
14896
|
+
console.log(
|
|
14897
|
+
` Task success rate: ${chalk24.cyan(`${data.taskSuccessRate}%`)} ${chalk24.dim(`(${data.taskCount} tasks)`)}`
|
|
14898
|
+
);
|
|
14777
14899
|
}
|
|
14778
14900
|
console.log(` Config score: ${chalk24.cyan(`${score.score}/100`)} (${score.grade})`);
|
|
14779
14901
|
console.log("");
|
|
@@ -14783,32 +14905,48 @@ function displayFullInsights(data, score) {
|
|
|
14783
14905
|
console.log(chalk24.bold(" Agent Health"));
|
|
14784
14906
|
if (data.taskSuccessRate !== null) {
|
|
14785
14907
|
const color = data.taskSuccessRate >= 80 ? chalk24.green : data.taskSuccessRate >= 60 ? chalk24.yellow : chalk24.red;
|
|
14786
|
-
console.log(
|
|
14908
|
+
console.log(
|
|
14909
|
+
` Task success rate: ${color(`${data.taskSuccessRate}%`)} across ${data.taskCount} tasks`
|
|
14910
|
+
);
|
|
14787
14911
|
if (data.taskCorrectionCount > 0) {
|
|
14788
|
-
console.log(
|
|
14912
|
+
console.log(
|
|
14913
|
+
` Corrections needed: ${chalk24.yellow(String(data.taskCorrectionCount))} tasks required user correction`
|
|
14914
|
+
);
|
|
14789
14915
|
}
|
|
14790
14916
|
}
|
|
14791
14917
|
console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
|
|
14792
14918
|
console.log(chalk24.bold("\n Learning Impact"));
|
|
14793
14919
|
console.log(` Learnings active: ${chalk24.cyan(String(data.learningCount))}`);
|
|
14794
14920
|
if (data.failureRateWith !== null && data.failureRateWithout !== null) {
|
|
14795
|
-
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
|
+
);
|
|
14796
14924
|
if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
|
|
14797
|
-
console.log(
|
|
14925
|
+
console.log(
|
|
14926
|
+
` Improvement: ${chalk24.green(`${data.failureRateImprovement}%`)} fewer failures`
|
|
14927
|
+
);
|
|
14798
14928
|
} else if (data.failureRateImprovement === null) {
|
|
14799
|
-
console.log(
|
|
14929
|
+
console.log(
|
|
14930
|
+
` Improvement: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`
|
|
14931
|
+
);
|
|
14800
14932
|
}
|
|
14801
14933
|
}
|
|
14802
14934
|
if (data.totalWasteTokens > 0 || data.estimatedSavingsTokens > 0) {
|
|
14803
14935
|
console.log(chalk24.bold("\n Efficiency"));
|
|
14804
14936
|
if (data.totalWasteTokens > 0) {
|
|
14805
|
-
console.log(
|
|
14937
|
+
console.log(
|
|
14938
|
+
` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`
|
|
14939
|
+
);
|
|
14806
14940
|
}
|
|
14807
14941
|
if (data.estimatedSavingsTokens > 0) {
|
|
14808
|
-
console.log(
|
|
14942
|
+
console.log(
|
|
14943
|
+
` Estimated savings: ~${chalk24.green(data.estimatedSavingsTokens.toLocaleString())} tokens`
|
|
14944
|
+
);
|
|
14809
14945
|
}
|
|
14810
14946
|
if (data.estimatedSavingsSeconds > 0) {
|
|
14811
|
-
console.log(
|
|
14947
|
+
console.log(
|
|
14948
|
+
` Time saved: ~${chalk24.green(formatDuration(data.estimatedSavingsSeconds))}`
|
|
14949
|
+
);
|
|
14812
14950
|
}
|
|
14813
14951
|
}
|
|
14814
14952
|
console.log(chalk24.bold("\n Config Quality"));
|
|
@@ -14819,7 +14957,9 @@ function displayFullInsights(data, score) {
|
|
|
14819
14957
|
const trendColor = trend.direction === "up" ? chalk24.green : trend.direction === "down" ? chalk24.red : chalk24.gray;
|
|
14820
14958
|
const arrow = trend.direction === "up" ? "\u2191" : trend.direction === "down" ? "\u2193" : "\u2192";
|
|
14821
14959
|
const sign = trend.delta > 0 ? "+" : "";
|
|
14822
|
-
console.log(
|
|
14960
|
+
console.log(
|
|
14961
|
+
` Trend: ${trendColor(`${arrow} ${sign}${trend.delta} pts`)} ${chalk24.dim(`over ${trend.entries} checks`)}`
|
|
14962
|
+
);
|
|
14823
14963
|
}
|
|
14824
14964
|
console.log("");
|
|
14825
14965
|
}
|
|
@@ -14829,12 +14969,18 @@ async function insightsCommand(options) {
|
|
|
14829
14969
|
const score = computeLocalScore(process.cwd(), readState()?.targetAgent);
|
|
14830
14970
|
trackInsightsViewed(data.totalSessions, data.learningCount);
|
|
14831
14971
|
if (options.json) {
|
|
14832
|
-
console.log(
|
|
14833
|
-
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
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
|
+
);
|
|
14838
14984
|
return;
|
|
14839
14985
|
}
|
|
14840
14986
|
if (data.totalSessions === 0) {
|
|
@@ -14857,7 +15003,9 @@ async function sourcesListCommand() {
|
|
|
14857
15003
|
const workspaces = getDetectedWorkspaces(dir);
|
|
14858
15004
|
if (configSources.length === 0 && workspaces.length === 0) {
|
|
14859
15005
|
console.log(chalk25.dim("\n No sources configured.\n"));
|
|
14860
|
-
console.log(
|
|
15006
|
+
console.log(
|
|
15007
|
+
chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")(`${displayCaliberName()} sources add <path>`)
|
|
15008
|
+
);
|
|
14861
15009
|
console.log(chalk25.dim(" Or add to .caliber/sources.json manually.\n"));
|
|
14862
15010
|
return;
|
|
14863
15011
|
}
|
|
@@ -14869,7 +15017,9 @@ async function sourcesListCommand() {
|
|
|
14869
15017
|
const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
|
|
14870
15018
|
const hasSummary = source.path && fs49.existsSync(path40.join(path40.resolve(dir, source.path), ".caliber", "summary.json"));
|
|
14871
15019
|
console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
|
|
14872
|
-
console.log(
|
|
15020
|
+
console.log(
|
|
15021
|
+
` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`
|
|
15022
|
+
);
|
|
14873
15023
|
if (source.description) console.log(` ${chalk25.dim(source.description)}`);
|
|
14874
15024
|
console.log("");
|
|
14875
15025
|
}
|
|
@@ -14900,9 +15050,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
14900
15050
|
throw new Error("__exit__");
|
|
14901
15051
|
}
|
|
14902
15052
|
const existing = loadSourcesConfig(dir);
|
|
14903
|
-
const alreadyConfigured = existing.some(
|
|
14904
|
-
(s) => s.path && path40.resolve(dir, s.path) === absPath
|
|
14905
|
-
);
|
|
15053
|
+
const alreadyConfigured = existing.some((s) => s.path && path40.resolve(dir, s.path) === absPath);
|
|
14906
15054
|
if (alreadyConfigured) {
|
|
14907
15055
|
console.log(chalk25.yellow(`
|
|
14908
15056
|
Already configured: ${sourcePath}
|
|
@@ -14928,9 +15076,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
14928
15076
|
async function sourcesRemoveCommand(name) {
|
|
14929
15077
|
const dir = process.cwd();
|
|
14930
15078
|
const existing = loadSourcesConfig(dir);
|
|
14931
|
-
const idx = existing.findIndex(
|
|
14932
|
-
(s) => s.path?.includes(name) || s.role === name
|
|
14933
|
-
);
|
|
15079
|
+
const idx = existing.findIndex((s) => s.path?.includes(name) || s.role === name);
|
|
14934
15080
|
if (idx === -1) {
|
|
14935
15081
|
console.log(chalk25.red(`
|
|
14936
15082
|
Source not found: ${name}
|
|
@@ -14943,9 +15089,11 @@ async function sourcesRemoveCommand(name) {
|
|
|
14943
15089
|
}
|
|
14944
15090
|
const removed = existing.splice(idx, 1)[0];
|
|
14945
15091
|
writeSourcesConfig(dir, existing);
|
|
14946
|
-
console.log(
|
|
15092
|
+
console.log(
|
|
15093
|
+
chalk25.green(`
|
|
14947
15094
|
\u2713 Removed ${removed.path || removed.url} (${removed.role || removed.type})
|
|
14948
|
-
`)
|
|
15095
|
+
`)
|
|
15096
|
+
);
|
|
14949
15097
|
}
|
|
14950
15098
|
|
|
14951
15099
|
// src/commands/publish.ts
|
|
@@ -14959,7 +15107,9 @@ async function publishCommand() {
|
|
|
14959
15107
|
const dir = process.cwd();
|
|
14960
15108
|
const config = loadConfig();
|
|
14961
15109
|
if (!config) {
|
|
14962
|
-
console.log(
|
|
15110
|
+
console.log(
|
|
15111
|
+
chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")(`${displayCaliberName()} config`) + chalk26.red(" first.")
|
|
15112
|
+
);
|
|
14963
15113
|
throw new Error("__exit__");
|
|
14964
15114
|
}
|
|
14965
15115
|
const spinner = ora7("Generating project summary...").start();
|
|
@@ -15002,7 +15152,9 @@ async function publishCommand() {
|
|
|
15002
15152
|
spinner.succeed("Project summary published");
|
|
15003
15153
|
console.log(` ${chalk26.green("\u2713")} ${path41.relative(dir, outputPath)}`);
|
|
15004
15154
|
console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
|
|
15005
|
-
console.log(
|
|
15155
|
+
console.log(
|
|
15156
|
+
chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n")
|
|
15157
|
+
);
|
|
15006
15158
|
} catch (err) {
|
|
15007
15159
|
spinner.fail("Failed to generate summary");
|
|
15008
15160
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
package/package.json
CHANGED