@rely-ai/caliber 1.46.2 → 1.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/bin.js +669 -597
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1206,14 +1206,14 @@ __export(lock_exports, {
|
|
|
1206
1206
|
isCaliberRunning: () => isCaliberRunning,
|
|
1207
1207
|
releaseLock: () => releaseLock
|
|
1208
1208
|
});
|
|
1209
|
-
import
|
|
1210
|
-
import
|
|
1209
|
+
import fs42 from "fs";
|
|
1210
|
+
import path34 from "path";
|
|
1211
1211
|
import os8 from "os";
|
|
1212
1212
|
import crypto5 from "crypto";
|
|
1213
1213
|
function buildLockPath() {
|
|
1214
1214
|
const cwd = process.cwd();
|
|
1215
1215
|
const hash = crypto5.createHash("md5").update(cwd).digest("hex").slice(0, 8);
|
|
1216
|
-
return
|
|
1216
|
+
return path34.join(os8.tmpdir(), `.caliber-${hash}.lock`);
|
|
1217
1217
|
}
|
|
1218
1218
|
function getLockFile() {
|
|
1219
1219
|
if (!_lockPath) _lockPath = buildLockPath();
|
|
@@ -1222,8 +1222,8 @@ function getLockFile() {
|
|
|
1222
1222
|
function isCaliberRunning() {
|
|
1223
1223
|
try {
|
|
1224
1224
|
const lockFile = buildLockPath();
|
|
1225
|
-
if (!
|
|
1226
|
-
const raw =
|
|
1225
|
+
if (!fs42.existsSync(lockFile)) return false;
|
|
1226
|
+
const raw = fs42.readFileSync(lockFile, "utf-8").trim();
|
|
1227
1227
|
const { pid, ts } = JSON.parse(raw);
|
|
1228
1228
|
if (pid === process.pid) return false;
|
|
1229
1229
|
if (Date.now() - ts > STALE_MS) return false;
|
|
@@ -1239,14 +1239,14 @@ function isCaliberRunning() {
|
|
|
1239
1239
|
}
|
|
1240
1240
|
function acquireLock() {
|
|
1241
1241
|
try {
|
|
1242
|
-
|
|
1242
|
+
fs42.writeFileSync(getLockFile(), JSON.stringify({ pid: process.pid, ts: Date.now() }));
|
|
1243
1243
|
} catch {
|
|
1244
1244
|
}
|
|
1245
1245
|
}
|
|
1246
1246
|
function releaseLock() {
|
|
1247
1247
|
try {
|
|
1248
1248
|
const lockFile = getLockFile();
|
|
1249
|
-
if (
|
|
1249
|
+
if (fs42.existsSync(lockFile)) fs42.unlinkSync(lockFile);
|
|
1250
1250
|
} catch {
|
|
1251
1251
|
}
|
|
1252
1252
|
}
|
|
@@ -1261,14 +1261,14 @@ var init_lock = __esm({
|
|
|
1261
1261
|
|
|
1262
1262
|
// src/cli.ts
|
|
1263
1263
|
import { Command } from "commander";
|
|
1264
|
-
import
|
|
1265
|
-
import
|
|
1264
|
+
import fs53 from "fs";
|
|
1265
|
+
import path43 from "path";
|
|
1266
1266
|
import { fileURLToPath } from "url";
|
|
1267
1267
|
|
|
1268
1268
|
// src/commands/init.ts
|
|
1269
|
-
import
|
|
1270
|
-
import
|
|
1271
|
-
import
|
|
1269
|
+
import path29 from "path";
|
|
1270
|
+
import chalk14 from "chalk";
|
|
1271
|
+
import fs36 from "fs";
|
|
1272
1272
|
|
|
1273
1273
|
// src/fingerprint/index.ts
|
|
1274
1274
|
import fs9 from "fs";
|
|
@@ -5366,15 +5366,15 @@ init_config();
|
|
|
5366
5366
|
// src/utils/dependencies.ts
|
|
5367
5367
|
import { readFileSync as readFileSync2 } from "fs";
|
|
5368
5368
|
import { join as join2 } from "path";
|
|
5369
|
-
function readFileOrNull2(
|
|
5369
|
+
function readFileOrNull2(path45) {
|
|
5370
5370
|
try {
|
|
5371
|
-
return readFileSync2(
|
|
5371
|
+
return readFileSync2(path45, "utf-8");
|
|
5372
5372
|
} catch {
|
|
5373
5373
|
return null;
|
|
5374
5374
|
}
|
|
5375
5375
|
}
|
|
5376
|
-
function readJsonOrNull(
|
|
5377
|
-
const content = readFileOrNull2(
|
|
5376
|
+
function readJsonOrNull(path45) {
|
|
5377
|
+
const content = readFileOrNull2(path45);
|
|
5378
5378
|
if (!content) return null;
|
|
5379
5379
|
try {
|
|
5380
5380
|
return JSON.parse(content);
|
|
@@ -8586,8 +8586,8 @@ function trackInitSkillsSearch(searched, installedCount) {
|
|
|
8586
8586
|
function trackInitScoreRegression(oldScore, newScore) {
|
|
8587
8587
|
trackEvent("init_score_regression", { old_score: oldScore, new_score: newScore });
|
|
8588
8588
|
}
|
|
8589
|
-
function trackInitCompleted(
|
|
8590
|
-
trackEvent("init_completed", { path:
|
|
8589
|
+
function trackInitCompleted(path45, score) {
|
|
8590
|
+
trackEvent("init_completed", { path: path45, score });
|
|
8591
8591
|
}
|
|
8592
8592
|
function trackRegenerateCompleted(action, durationMs) {
|
|
8593
8593
|
trackEvent("regenerate_completed", { action, duration_ms: durationMs });
|
|
@@ -9604,11 +9604,11 @@ async function scoreAndRefine(setup, dir, sessionHistory, callbacks, options) {
|
|
|
9604
9604
|
const maxIterations = options?.thorough ? 3 : MAX_REFINE_ITERATIONS;
|
|
9605
9605
|
const minPoints = options?.thorough ? 1 : MIN_POINTS_TO_REFINE;
|
|
9606
9606
|
const existsCache = /* @__PURE__ */ new Map();
|
|
9607
|
-
const cachedExists = (
|
|
9608
|
-
const cached = existsCache.get(
|
|
9607
|
+
const cachedExists = (path45) => {
|
|
9608
|
+
const cached = existsCache.get(path45);
|
|
9609
9609
|
if (cached !== void 0) return cached;
|
|
9610
|
-
const result = existsSync9(
|
|
9611
|
-
existsCache.set(
|
|
9610
|
+
const result = existsSync9(path45);
|
|
9611
|
+
existsCache.set(path45, result);
|
|
9612
9612
|
return result;
|
|
9613
9613
|
};
|
|
9614
9614
|
const projectStructure = collectProjectStructure(dir);
|
|
@@ -10953,14 +10953,84 @@ function getScoreTrend(entries) {
|
|
|
10953
10953
|
};
|
|
10954
10954
|
}
|
|
10955
10955
|
|
|
10956
|
+
// src/fingerprint/large-file-scan.ts
|
|
10957
|
+
import fs35 from "fs";
|
|
10958
|
+
import path28 from "path";
|
|
10959
|
+
var DEFAULT_THRESHOLD_BYTES = 1048576;
|
|
10960
|
+
var DEFAULT_IGNORE_DIRS = IGNORE_DIRS;
|
|
10961
|
+
function scanLargeFiles(dir, options = {}) {
|
|
10962
|
+
const {
|
|
10963
|
+
thresholdBytes = DEFAULT_THRESHOLD_BYTES,
|
|
10964
|
+
ignoreDirs = DEFAULT_IGNORE_DIRS,
|
|
10965
|
+
statSync: stat = fs35.statSync,
|
|
10966
|
+
readdirSync: readdir = (p) => fs35.readdirSync(p)
|
|
10967
|
+
} = options;
|
|
10968
|
+
const warnings = [];
|
|
10969
|
+
walkDir2(dir, ignoreDirs, thresholdBytes, stat, readdir, warnings);
|
|
10970
|
+
return warnings;
|
|
10971
|
+
}
|
|
10972
|
+
function walkDir2(current, ignoreDirs, thresholdBytes, stat, readdir, out) {
|
|
10973
|
+
let names;
|
|
10974
|
+
try {
|
|
10975
|
+
names = readdir(current);
|
|
10976
|
+
} catch (err) {
|
|
10977
|
+
const code = err.code;
|
|
10978
|
+
if (code === "EACCES" || code === "ENOENT" || code === "ENOTDIR") return;
|
|
10979
|
+
throw err;
|
|
10980
|
+
}
|
|
10981
|
+
for (const name of names) {
|
|
10982
|
+
if (ignoreDirs.has(name)) continue;
|
|
10983
|
+
const fullPath = path28.join(current, name);
|
|
10984
|
+
let entry;
|
|
10985
|
+
try {
|
|
10986
|
+
entry = stat(fullPath);
|
|
10987
|
+
} catch {
|
|
10988
|
+
continue;
|
|
10989
|
+
}
|
|
10990
|
+
if (entry.isDirectory()) {
|
|
10991
|
+
walkDir2(fullPath, ignoreDirs, thresholdBytes, stat, readdir, out);
|
|
10992
|
+
} else if (entry.isFile() && entry.size > thresholdBytes) {
|
|
10993
|
+
out.push({
|
|
10994
|
+
filePath: fullPath,
|
|
10995
|
+
sizeBytes: entry.size,
|
|
10996
|
+
sizeMB: (entry.size / 1048576).toFixed(2)
|
|
10997
|
+
});
|
|
10998
|
+
}
|
|
10999
|
+
}
|
|
11000
|
+
}
|
|
11001
|
+
|
|
11002
|
+
// src/fingerprint/large-file-warn.ts
|
|
11003
|
+
import chalk13 from "chalk";
|
|
11004
|
+
function printLargeFileWarnings(warnings, options = {}) {
|
|
11005
|
+
if (warnings.length === 0) return;
|
|
11006
|
+
const { spinner } = options;
|
|
11007
|
+
const header = chalk13.yellow.bold(
|
|
11008
|
+
`\u26A0 ${warnings.length} large file${warnings.length === 1 ? "" : "s"} may bloat your AI context window`
|
|
11009
|
+
);
|
|
11010
|
+
const fileLines = warnings.map((w) => chalk13.yellow(` \u2022 ${w.filePath} (${w.sizeMB} MB)`)).join("\n");
|
|
11011
|
+
const hint = chalk13.dim(
|
|
11012
|
+
" Add them to .gitignore or .caliberignore to keep context lean."
|
|
11013
|
+
);
|
|
11014
|
+
const block = `
|
|
11015
|
+
${header}
|
|
11016
|
+
${fileLines}
|
|
11017
|
+
${hint}
|
|
11018
|
+
`;
|
|
11019
|
+
if (spinner) {
|
|
11020
|
+
spinner.warn(block);
|
|
11021
|
+
} else {
|
|
11022
|
+
process.stderr.write(block + "\n");
|
|
11023
|
+
}
|
|
11024
|
+
}
|
|
11025
|
+
|
|
10956
11026
|
// src/commands/init.ts
|
|
10957
11027
|
var IS_WINDOWS6 = process.platform === "win32";
|
|
10958
11028
|
function log(verbose, ...args) {
|
|
10959
|
-
if (verbose) console.log(
|
|
11029
|
+
if (verbose) console.log(chalk14.dim(` [verbose] ${args.map(String).join(" ")}`));
|
|
10960
11030
|
}
|
|
10961
11031
|
async function initCommand(options) {
|
|
10962
|
-
const brand =
|
|
10963
|
-
const title =
|
|
11032
|
+
const brand = chalk14.hex("#EB9D83");
|
|
11033
|
+
const title = chalk14.hex("#83D1EB");
|
|
10964
11034
|
const bin = resolveCaliber();
|
|
10965
11035
|
const firstRun = isFirstRun(process.cwd());
|
|
10966
11036
|
if (firstRun) {
|
|
@@ -10974,23 +11044,23 @@ async function initCommand(options) {
|
|
|
10974
11044
|
\u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
10975
11045
|
`)
|
|
10976
11046
|
);
|
|
10977
|
-
console.log(
|
|
10978
|
-
console.log(
|
|
11047
|
+
console.log(chalk14.dim(" Keep your AI agent configs in sync \u2014 automatically."));
|
|
11048
|
+
console.log(chalk14.dim(" Works across Claude Code, Cursor, Codex, and GitHub Copilot.\n"));
|
|
10979
11049
|
console.log(title.bold(" How it works:\n"));
|
|
10980
|
-
console.log(
|
|
10981
|
-
console.log(
|
|
10982
|
-
console.log(
|
|
10983
|
-
console.log(
|
|
11050
|
+
console.log(chalk14.dim(" 1. Connect Link your LLM provider and select your agents"));
|
|
11051
|
+
console.log(chalk14.dim(" 2. Setup Detect stack, install sync hooks & skills"));
|
|
11052
|
+
console.log(chalk14.dim(" 3. Generate Audit existing config or generate from scratch"));
|
|
11053
|
+
console.log(chalk14.dim(" 4. Finalize Review changes and score your setup\n"));
|
|
10984
11054
|
} else {
|
|
10985
|
-
console.log(brand.bold("\n CALIBER") +
|
|
11055
|
+
console.log(brand.bold("\n CALIBER") + chalk14.dim(" \u2014 setting up continuous sync\n"));
|
|
10986
11056
|
}
|
|
10987
11057
|
const platforms = detectPlatforms();
|
|
10988
11058
|
if (!platforms.claude && !platforms.cursor && !platforms.codex && !platforms.opencode) {
|
|
10989
11059
|
console.log(
|
|
10990
|
-
|
|
11060
|
+
chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex, OpenCode).")
|
|
10991
11061
|
);
|
|
10992
11062
|
console.log(
|
|
10993
|
-
|
|
11063
|
+
chalk14.yellow(
|
|
10994
11064
|
" Caliber will still generate config files, but they won't be auto-installed.\n"
|
|
10995
11065
|
)
|
|
10996
11066
|
);
|
|
@@ -11000,7 +11070,7 @@ async function initCommand(options) {
|
|
|
11000
11070
|
let config = loadConfig();
|
|
11001
11071
|
if (!config && options.agent?.includes("opencode")) {
|
|
11002
11072
|
if (isOpenCodeAvailable()) {
|
|
11003
|
-
console.log(
|
|
11073
|
+
console.log(chalk14.dim(" Detected: OpenCode (uses your existing subscription)\n"));
|
|
11004
11074
|
const autoConfig = { provider: "opencode", model: DEFAULT_MODELS.opencode };
|
|
11005
11075
|
writeConfigFile(autoConfig);
|
|
11006
11076
|
config = autoConfig;
|
|
@@ -11008,7 +11078,7 @@ async function initCommand(options) {
|
|
|
11008
11078
|
}
|
|
11009
11079
|
if (!config && !options.autoApprove) {
|
|
11010
11080
|
if (isClaudeCliAvailable() && isClaudeCliLoggedIn()) {
|
|
11011
|
-
console.log(
|
|
11081
|
+
console.log(chalk14.dim(" Detected: Claude Code CLI (uses your Pro/Max/Team subscription)\n"));
|
|
11012
11082
|
const useIt = await confirm2({ message: "Use Claude Code as your LLM provider?" });
|
|
11013
11083
|
if (useIt) {
|
|
11014
11084
|
const autoConfig = { provider: "claude-cli", model: "default" };
|
|
@@ -11016,7 +11086,7 @@ async function initCommand(options) {
|
|
|
11016
11086
|
config = autoConfig;
|
|
11017
11087
|
}
|
|
11018
11088
|
} else if (isCursorAgentAvailable() && isCursorLoggedIn()) {
|
|
11019
|
-
console.log(
|
|
11089
|
+
console.log(chalk14.dim(" Detected: Cursor (uses your existing subscription)\n"));
|
|
11020
11090
|
const useIt = await confirm2({ message: "Use Cursor as your LLM provider?" });
|
|
11021
11091
|
if (useIt) {
|
|
11022
11092
|
const autoConfig = { provider: "cursor", model: "sonnet-4.6" };
|
|
@@ -11042,13 +11112,13 @@ async function initCommand(options) {
|
|
|
11042
11112
|
}
|
|
11043
11113
|
}
|
|
11044
11114
|
if (!config) {
|
|
11045
|
-
console.log(
|
|
11115
|
+
console.log(chalk14.dim(" No LLM provider detected.\n"));
|
|
11046
11116
|
await runInteractiveProviderSetup({
|
|
11047
11117
|
selectMessage: "How do you want to use Caliber? (choose LLM provider)"
|
|
11048
11118
|
});
|
|
11049
11119
|
config = loadConfig();
|
|
11050
11120
|
if (!config) {
|
|
11051
|
-
console.log(
|
|
11121
|
+
console.log(chalk14.red(" Configuration cancelled or failed.\n"));
|
|
11052
11122
|
throw new Error("__exit__");
|
|
11053
11123
|
}
|
|
11054
11124
|
}
|
|
@@ -11057,7 +11127,7 @@ async function initCommand(options) {
|
|
|
11057
11127
|
const displayModel = getDisplayModel(config);
|
|
11058
11128
|
const fastModel = getFastModel();
|
|
11059
11129
|
const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
|
|
11060
|
-
console.log(
|
|
11130
|
+
console.log(chalk14.dim(modelLine + "\n"));
|
|
11061
11131
|
if (report) {
|
|
11062
11132
|
report.markStep("Provider connection");
|
|
11063
11133
|
report.addSection(
|
|
@@ -11076,10 +11146,10 @@ async function initCommand(options) {
|
|
|
11076
11146
|
const detected = detectAgents(process.cwd());
|
|
11077
11147
|
if (detected.length > 0 && (options.autoApprove || firstRun)) {
|
|
11078
11148
|
targetAgent = detected;
|
|
11079
|
-
console.log(
|
|
11149
|
+
console.log(chalk14.dim(` Coding agents in this repo: ${detected.join(", ")}
|
|
11080
11150
|
`));
|
|
11081
11151
|
} else if (detected.length > 0) {
|
|
11082
|
-
console.log(
|
|
11152
|
+
console.log(chalk14.dim(` Coding agents in this repo: ${detected.join(", ")}
|
|
11083
11153
|
`));
|
|
11084
11154
|
const useDetected = await confirm2({ message: "Generate configs for these agents?" });
|
|
11085
11155
|
targetAgent = useDetected ? detected : await promptAgent();
|
|
@@ -11087,69 +11157,69 @@ async function initCommand(options) {
|
|
|
11087
11157
|
targetAgent = options.autoApprove ? ["claude"] : await promptAgent();
|
|
11088
11158
|
}
|
|
11089
11159
|
}
|
|
11090
|
-
console.log(
|
|
11160
|
+
console.log(chalk14.dim(` Target: ${targetAgent.join(", ")}
|
|
11091
11161
|
`));
|
|
11092
11162
|
trackInitAgentSelected(targetAgent, agentAutoDetected);
|
|
11093
11163
|
if (targetAgent.length === 1 && targetAgent[0] === "github-copilot") {
|
|
11094
11164
|
console.log(
|
|
11095
|
-
|
|
11165
|
+
chalk14.yellow(
|
|
11096
11166
|
" Note: GitHub Copilot is a sync target \u2014 Caliber writes .github/copilot-instructions.md\n but needs an LLM provider (configured above) to power generation.\n For the best experience, also select claude or cursor as a target agent.\n"
|
|
11097
11167
|
)
|
|
11098
11168
|
);
|
|
11099
11169
|
}
|
|
11100
11170
|
console.log(title.bold(" Step 2/4 \u2014 Setup\n"));
|
|
11101
|
-
console.log(
|
|
11171
|
+
console.log(chalk14.dim(" Installing sync infrastructure...\n"));
|
|
11102
11172
|
const hookResult = installPreCommitHook();
|
|
11103
11173
|
if (hookResult.installed) {
|
|
11104
|
-
console.log(` ${
|
|
11174
|
+
console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed \u2014 configs sync on every commit`);
|
|
11105
11175
|
} else if (hookResult.alreadyInstalled) {
|
|
11106
|
-
console.log(` ${
|
|
11176
|
+
console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 active`);
|
|
11107
11177
|
}
|
|
11108
11178
|
installStopHook();
|
|
11109
|
-
console.log(` ${
|
|
11179
|
+
console.log(` ${chalk14.green("\u2713")} Onboarding hook \u2014 nudges new team members to set up`);
|
|
11110
11180
|
installSessionStartHook();
|
|
11111
|
-
console.log(` ${
|
|
11181
|
+
console.log(` ${chalk14.green("\u2713")} Freshness hook \u2014 warns when configs are stale`);
|
|
11112
11182
|
if (IS_WINDOWS6) {
|
|
11113
11183
|
console.log(
|
|
11114
|
-
|
|
11184
|
+
chalk14.yellow(
|
|
11115
11185
|
"\n Note: hooks use shell syntax and require Git Bash (included with Git for Windows)."
|
|
11116
11186
|
)
|
|
11117
11187
|
);
|
|
11118
11188
|
console.log(
|
|
11119
|
-
|
|
11189
|
+
chalk14.dim(
|
|
11120
11190
|
" If hooks don't run, ensure Git for Windows is installed and git is using its bundled sh."
|
|
11121
11191
|
)
|
|
11122
11192
|
);
|
|
11123
11193
|
}
|
|
11124
11194
|
const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
|
|
11125
11195
|
for (const agent of targetAgent) {
|
|
11126
|
-
if (agent === "claude" && !
|
|
11127
|
-
|
|
11128
|
-
if (agent === "cursor" && !
|
|
11129
|
-
|
|
11130
|
-
if (agent === "codex" && !
|
|
11131
|
-
|
|
11196
|
+
if (agent === "claude" && !fs36.existsSync(".claude"))
|
|
11197
|
+
fs36.mkdirSync(".claude", { recursive: true });
|
|
11198
|
+
if (agent === "cursor" && !fs36.existsSync(".cursor"))
|
|
11199
|
+
fs36.mkdirSync(".cursor", { recursive: true });
|
|
11200
|
+
if (agent === "codex" && !fs36.existsSync(".agents"))
|
|
11201
|
+
fs36.mkdirSync(".agents", { recursive: true });
|
|
11132
11202
|
}
|
|
11133
11203
|
const skillsWritten = ensureBuiltinSkills2();
|
|
11134
11204
|
if (skillsWritten.length > 0) {
|
|
11135
11205
|
console.log(
|
|
11136
|
-
` ${
|
|
11206
|
+
` ${chalk14.green("\u2713")} Agent skills installed \u2014 /setup-caliber, /find-skills, /save-learning`
|
|
11137
11207
|
);
|
|
11138
11208
|
} else {
|
|
11139
|
-
console.log(` ${
|
|
11209
|
+
console.log(` ${chalk14.green("\u2713")} Agent skills \u2014 already installed`);
|
|
11140
11210
|
}
|
|
11141
11211
|
const hasLearnableAgent = targetAgent.includes("claude") || targetAgent.includes("cursor");
|
|
11142
11212
|
if (hasLearnableAgent) {
|
|
11143
11213
|
if (targetAgent.includes("claude")) installLearningHooks();
|
|
11144
11214
|
if (targetAgent.includes("cursor")) installCursorLearningHooks();
|
|
11145
|
-
console.log(` ${
|
|
11215
|
+
console.log(` ${chalk14.green("\u2713")} Session learning enabled`);
|
|
11146
11216
|
trackInitLearnEnabled(true);
|
|
11147
11217
|
}
|
|
11148
11218
|
console.log("");
|
|
11149
|
-
console.log(
|
|
11150
|
-
console.log(
|
|
11219
|
+
console.log(chalk14.dim(" New team members can run /setup-caliber inside their coding agent"));
|
|
11220
|
+
console.log(chalk14.dim(" (Claude Code or Cursor) to get set up automatically.\n"));
|
|
11151
11221
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
11152
|
-
console.log(
|
|
11222
|
+
console.log(chalk14.dim(" Current config score:"));
|
|
11153
11223
|
displayScoreSummary(baselineScore);
|
|
11154
11224
|
if (options.verbose) {
|
|
11155
11225
|
for (const c of baselineScore.checks) {
|
|
@@ -11187,20 +11257,20 @@ async function initCommand(options) {
|
|
|
11187
11257
|
let skipGeneration = false;
|
|
11188
11258
|
if (hasExistingConfig && baselineScore.score === 100) {
|
|
11189
11259
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
|
|
11190
|
-
console.log(
|
|
11260
|
+
console.log(chalk14.bold.green("\n Your config is already optimal.\n"));
|
|
11191
11261
|
skipGeneration = !options.force;
|
|
11192
11262
|
} else if (hasExistingConfig && !options.force && !options.autoApprove) {
|
|
11193
11263
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
|
|
11194
11264
|
console.log(
|
|
11195
|
-
|
|
11265
|
+
chalk14.dim("\n Sync infrastructure is ready. Caliber can also audit your existing")
|
|
11196
11266
|
);
|
|
11197
|
-
console.log(
|
|
11267
|
+
console.log(chalk14.dim(" configs and improve them using AI.\n"));
|
|
11198
11268
|
const auditAnswer = await promptInput(" Audit and improve your existing config? (Y/n) ");
|
|
11199
11269
|
skipGeneration = auditAnswer.toLowerCase() === "n";
|
|
11200
11270
|
} else if (!hasExistingConfig && !options.force && !options.autoApprove) {
|
|
11201
11271
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
|
|
11202
|
-
console.log(
|
|
11203
|
-
console.log(
|
|
11272
|
+
console.log(chalk14.dim("\n Sync infrastructure is ready. Caliber can also generate tailored"));
|
|
11273
|
+
console.log(chalk14.dim(" CLAUDE.md, Cursor rules, and Codex configs for your project.\n"));
|
|
11204
11274
|
const generateAnswer = await promptInput(" Generate agent configs? (Y/n) ");
|
|
11205
11275
|
skipGeneration = generateAnswer.toLowerCase() === "n";
|
|
11206
11276
|
} else {
|
|
@@ -11217,47 +11287,47 @@ async function initCommand(options) {
|
|
|
11217
11287
|
const claudeMdPath = "CLAUDE.md";
|
|
11218
11288
|
let claudeContent = "";
|
|
11219
11289
|
try {
|
|
11220
|
-
claudeContent =
|
|
11290
|
+
claudeContent = fs36.readFileSync(claudeMdPath, "utf-8");
|
|
11221
11291
|
} catch {
|
|
11222
11292
|
}
|
|
11223
11293
|
if (!claudeContent) {
|
|
11224
|
-
claudeContent = `# ${
|
|
11294
|
+
claudeContent = `# ${path29.basename(process.cwd())}
|
|
11225
11295
|
`;
|
|
11226
11296
|
}
|
|
11227
11297
|
const updatedClaude = appendManagedBlocks2(claudeContent, "claude");
|
|
11228
|
-
if (updatedClaude !== claudeContent || !
|
|
11229
|
-
|
|
11230
|
-
console.log(` ${
|
|
11298
|
+
if (updatedClaude !== claudeContent || !fs36.existsSync(claudeMdPath)) {
|
|
11299
|
+
fs36.writeFileSync(claudeMdPath, updatedClaude);
|
|
11300
|
+
console.log(` ${chalk14.green("\u2713")} CLAUDE.md \u2014 added Caliber sync instructions`);
|
|
11231
11301
|
}
|
|
11232
11302
|
if (targetAgent.includes("cursor")) {
|
|
11233
|
-
const rulesDir =
|
|
11234
|
-
if (!
|
|
11303
|
+
const rulesDir = path29.join(".cursor", "rules");
|
|
11304
|
+
if (!fs36.existsSync(rulesDir)) fs36.mkdirSync(rulesDir, { recursive: true });
|
|
11235
11305
|
for (const rule of [
|
|
11236
11306
|
getCursorPreCommitRule2(),
|
|
11237
11307
|
getCursorLearningsRule2(),
|
|
11238
11308
|
getCursorSyncRule2(),
|
|
11239
11309
|
getCursorSetupRule2()
|
|
11240
11310
|
]) {
|
|
11241
|
-
|
|
11311
|
+
fs36.writeFileSync(path29.join(rulesDir, rule.filename), rule.content);
|
|
11242
11312
|
}
|
|
11243
|
-
console.log(` ${
|
|
11313
|
+
console.log(` ${chalk14.green("\u2713")} Cursor rules \u2014 added Caliber sync rules`);
|
|
11244
11314
|
}
|
|
11245
11315
|
if (targetAgent.includes("github-copilot")) {
|
|
11246
|
-
const copilotPath =
|
|
11316
|
+
const copilotPath = path29.join(".github", "copilot-instructions.md");
|
|
11247
11317
|
let copilotContent = "";
|
|
11248
11318
|
try {
|
|
11249
|
-
copilotContent =
|
|
11319
|
+
copilotContent = fs36.readFileSync(copilotPath, "utf-8");
|
|
11250
11320
|
} catch {
|
|
11251
11321
|
}
|
|
11252
11322
|
if (!copilotContent) {
|
|
11253
|
-
|
|
11254
|
-
copilotContent = `# ${
|
|
11323
|
+
fs36.mkdirSync(".github", { recursive: true });
|
|
11324
|
+
copilotContent = `# ${path29.basename(process.cwd())}
|
|
11255
11325
|
`;
|
|
11256
11326
|
}
|
|
11257
11327
|
const updatedCopilot = appendManagedBlocks2(copilotContent, "copilot");
|
|
11258
11328
|
if (updatedCopilot !== copilotContent) {
|
|
11259
|
-
|
|
11260
|
-
console.log(` ${
|
|
11329
|
+
fs36.writeFileSync(copilotPath, updatedCopilot);
|
|
11330
|
+
console.log(` ${chalk14.green("\u2713")} Copilot instructions \u2014 added Caliber sync instructions`);
|
|
11261
11331
|
}
|
|
11262
11332
|
}
|
|
11263
11333
|
const sha2 = getCurrentHeadSha();
|
|
@@ -11267,16 +11337,16 @@ async function initCommand(options) {
|
|
|
11267
11337
|
targetAgent
|
|
11268
11338
|
});
|
|
11269
11339
|
trackInitCompleted("sync-only", baselineScore.score);
|
|
11270
|
-
console.log(
|
|
11271
|
-
console.log(
|
|
11340
|
+
console.log(chalk14.bold.green("\n Caliber sync is set up!\n"));
|
|
11341
|
+
console.log(chalk14.dim(" Your agent configs will sync automatically on every commit."));
|
|
11272
11342
|
console.log(
|
|
11273
|
-
|
|
11343
|
+
chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n")
|
|
11274
11344
|
);
|
|
11275
11345
|
return;
|
|
11276
11346
|
}
|
|
11277
11347
|
console.log(title.bold("\n Step 3/4 \u2014 Generate\n"));
|
|
11278
11348
|
const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
|
|
11279
|
-
console.log(
|
|
11349
|
+
console.log(chalk14.dim(genModelInfo + "\n"));
|
|
11280
11350
|
if (report) report.markStep("Generation");
|
|
11281
11351
|
trackInitGenerationStarted(false);
|
|
11282
11352
|
const genStartTime = Date.now();
|
|
@@ -11303,6 +11373,7 @@ async function initCommand(options) {
|
|
|
11303
11373
|
try {
|
|
11304
11374
|
display.update(TASK_STACK, "running");
|
|
11305
11375
|
fingerprint = await collectFingerprint(process.cwd());
|
|
11376
|
+
printLargeFileWarnings(scanLargeFiles(process.cwd()));
|
|
11306
11377
|
const stackParts = [...fingerprint.languages, ...fingerprint.frameworks];
|
|
11307
11378
|
const stackSummary = stackParts.join(", ") || "no languages";
|
|
11308
11379
|
const largeRepoNote = fingerprint.fileTree.length > 5e3 ? ` (${fingerprint.fileTree.length.toLocaleString()} files, smart sampling active)` : "";
|
|
@@ -11405,7 +11476,7 @@ async function initCommand(options) {
|
|
|
11405
11476
|
onContent: (text) => {
|
|
11406
11477
|
const lines = text.split("\n").filter((l) => l.trim()).slice(-8);
|
|
11407
11478
|
if (lines.length > 0) {
|
|
11408
|
-
display.setPreviewContent(lines.map((l) => ` ${
|
|
11479
|
+
display.setPreviewContent(lines.map((l) => ` ${chalk14.dim(l.slice(0, 80))}`));
|
|
11409
11480
|
}
|
|
11410
11481
|
}
|
|
11411
11482
|
},
|
|
@@ -11488,7 +11559,7 @@ async function initCommand(options) {
|
|
|
11488
11559
|
} catch (err) {
|
|
11489
11560
|
display.stop();
|
|
11490
11561
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
11491
|
-
console.log(
|
|
11562
|
+
console.log(chalk14.red(`
|
|
11492
11563
|
Engine failed: ${msg}
|
|
11493
11564
|
`));
|
|
11494
11565
|
writeErrorLog(config, void 0, msg, "exception");
|
|
@@ -11500,15 +11571,15 @@ async function initCommand(options) {
|
|
|
11500
11571
|
const mins = Math.floor(elapsedMs / 6e4);
|
|
11501
11572
|
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
11502
11573
|
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
11503
|
-
console.log(
|
|
11574
|
+
console.log(chalk14.dim(`
|
|
11504
11575
|
Done in ${timeStr}
|
|
11505
11576
|
`));
|
|
11506
11577
|
if (!generatedSetup) {
|
|
11507
|
-
console.log(
|
|
11578
|
+
console.log(chalk14.red(" Failed to generate config."));
|
|
11508
11579
|
writeErrorLog(config, rawOutput, void 0, genStopReason);
|
|
11509
11580
|
if (rawOutput) {
|
|
11510
|
-
console.log(
|
|
11511
|
-
console.log(
|
|
11581
|
+
console.log(chalk14.dim("\nRaw LLM output (JSON parse failed):"));
|
|
11582
|
+
console.log(chalk14.dim(rawOutput.slice(0, 500)));
|
|
11512
11583
|
}
|
|
11513
11584
|
throw new Error("__exit__");
|
|
11514
11585
|
}
|
|
@@ -11527,19 +11598,19 @@ async function initCommand(options) {
|
|
|
11527
11598
|
const changes = formatWhatChanged(generatedSetup);
|
|
11528
11599
|
if (changes.length > 0) {
|
|
11529
11600
|
for (const line of changes) {
|
|
11530
|
-
console.log(` ${
|
|
11601
|
+
console.log(` ${chalk14.dim("\u2022")} ${line}`);
|
|
11531
11602
|
}
|
|
11532
11603
|
console.log("");
|
|
11533
11604
|
}
|
|
11534
11605
|
console.log(
|
|
11535
|
-
|
|
11536
|
-
` ${
|
|
11606
|
+
chalk14.dim(
|
|
11607
|
+
` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`
|
|
11537
11608
|
)
|
|
11538
11609
|
);
|
|
11539
11610
|
if (skillSearchResult.results.length > 0) {
|
|
11540
11611
|
console.log(
|
|
11541
|
-
|
|
11542
|
-
` ${
|
|
11612
|
+
chalk14.dim(
|
|
11613
|
+
` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
|
|
11543
11614
|
`
|
|
11544
11615
|
)
|
|
11545
11616
|
);
|
|
@@ -11549,7 +11620,7 @@ async function initCommand(options) {
|
|
|
11549
11620
|
const hasSkillResults = skillSearchResult.results.length > 0;
|
|
11550
11621
|
let action;
|
|
11551
11622
|
if (totalChanges === 0 && !hasSkillResults) {
|
|
11552
|
-
console.log(
|
|
11623
|
+
console.log(chalk14.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
11553
11624
|
cleanupStaging();
|
|
11554
11625
|
action = "accept";
|
|
11555
11626
|
} else if (options.autoApprove) {
|
|
@@ -11573,14 +11644,14 @@ async function initCommand(options) {
|
|
|
11573
11644
|
trackInitRefinementRound(refinementRound, !!generatedSetup);
|
|
11574
11645
|
if (!generatedSetup) {
|
|
11575
11646
|
cleanupStaging();
|
|
11576
|
-
console.log(
|
|
11647
|
+
console.log(chalk14.dim("Refinement cancelled. No files were modified."));
|
|
11577
11648
|
return;
|
|
11578
11649
|
}
|
|
11579
11650
|
const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
11580
11651
|
const restaged = stageFiles(updatedFiles, process.cwd());
|
|
11581
11652
|
console.log(
|
|
11582
|
-
|
|
11583
|
-
` ${
|
|
11653
|
+
chalk14.dim(
|
|
11654
|
+
` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
|
|
11584
11655
|
`
|
|
11585
11656
|
)
|
|
11586
11657
|
);
|
|
@@ -11592,18 +11663,18 @@ async function initCommand(options) {
|
|
|
11592
11663
|
}
|
|
11593
11664
|
cleanupStaging();
|
|
11594
11665
|
if (action === "decline") {
|
|
11595
|
-
console.log(
|
|
11666
|
+
console.log(chalk14.dim("Declined. No files were modified."));
|
|
11596
11667
|
return;
|
|
11597
11668
|
}
|
|
11598
11669
|
if (options.dryRun) {
|
|
11599
|
-
console.log(
|
|
11670
|
+
console.log(chalk14.yellow("\n[Dry run] Would write the following files:"));
|
|
11600
11671
|
console.log(JSON.stringify(generatedSetup, null, 2));
|
|
11601
11672
|
return;
|
|
11602
11673
|
}
|
|
11603
11674
|
const { default: ora9 } = await import("ora");
|
|
11604
11675
|
const writeSpinner = ora9("Writing config files...").start();
|
|
11605
11676
|
try {
|
|
11606
|
-
if (targetAgent.includes("codex") && !
|
|
11677
|
+
if (targetAgent.includes("codex") && !fs36.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
11607
11678
|
const claude = generatedSetup.claude;
|
|
11608
11679
|
const cursor = generatedSetup.cursor;
|
|
11609
11680
|
const agentRefs = [];
|
|
@@ -11627,23 +11698,23 @@ ${agentRefs.join(" ")}
|
|
|
11627
11698
|
0,
|
|
11628
11699
|
result.deleted.length
|
|
11629
11700
|
);
|
|
11630
|
-
console.log(
|
|
11701
|
+
console.log(chalk14.bold("\nFiles created/updated:"));
|
|
11631
11702
|
for (const file of result.written) {
|
|
11632
|
-
console.log(` ${
|
|
11703
|
+
console.log(` ${chalk14.green("\u2713")} ${file}`);
|
|
11633
11704
|
}
|
|
11634
11705
|
if (result.deleted.length > 0) {
|
|
11635
|
-
console.log(
|
|
11706
|
+
console.log(chalk14.bold("\nFiles removed:"));
|
|
11636
11707
|
for (const file of result.deleted) {
|
|
11637
|
-
console.log(` ${
|
|
11708
|
+
console.log(` ${chalk14.red("\u2717")} ${file}`);
|
|
11638
11709
|
}
|
|
11639
11710
|
}
|
|
11640
11711
|
if (result.backupDir) {
|
|
11641
|
-
console.log(
|
|
11712
|
+
console.log(chalk14.dim(`
|
|
11642
11713
|
Backups saved to ${result.backupDir}`));
|
|
11643
11714
|
}
|
|
11644
11715
|
} catch (err) {
|
|
11645
11716
|
writeSpinner.fail("Failed to write files");
|
|
11646
|
-
console.error(
|
|
11717
|
+
console.error(chalk14.red(err instanceof Error ? err.message : "Unknown error"));
|
|
11647
11718
|
throw new Error("__exit__");
|
|
11648
11719
|
}
|
|
11649
11720
|
if (fingerprint) ensurePermissions(fingerprint);
|
|
@@ -11658,7 +11729,7 @@ ${agentRefs.join(" ")}
|
|
|
11658
11729
|
trackInitScoreRegression(baselineScore.score, afterScore.score);
|
|
11659
11730
|
console.log("");
|
|
11660
11731
|
console.log(
|
|
11661
|
-
|
|
11732
|
+
chalk14.yellow(
|
|
11662
11733
|
` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
|
|
11663
11734
|
)
|
|
11664
11735
|
);
|
|
@@ -11666,7 +11737,7 @@ ${agentRefs.join(" ")}
|
|
|
11666
11737
|
const { restored, removed } = undoSetup();
|
|
11667
11738
|
if (restored.length > 0 || removed.length > 0) {
|
|
11668
11739
|
console.log(
|
|
11669
|
-
|
|
11740
|
+
chalk14.dim(
|
|
11670
11741
|
` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`
|
|
11671
11742
|
)
|
|
11672
11743
|
);
|
|
@@ -11674,7 +11745,7 @@ ${agentRefs.join(" ")}
|
|
|
11674
11745
|
} catch {
|
|
11675
11746
|
}
|
|
11676
11747
|
console.log(
|
|
11677
|
-
|
|
11748
|
+
chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n")
|
|
11678
11749
|
);
|
|
11679
11750
|
return;
|
|
11680
11751
|
}
|
|
@@ -11705,7 +11776,7 @@ ${agentRefs.join(" ")}
|
|
|
11705
11776
|
}
|
|
11706
11777
|
let communitySkillsInstalled = 0;
|
|
11707
11778
|
if (skillSearchResult.results.length > 0 && !options.autoApprove) {
|
|
11708
|
-
console.log(
|
|
11779
|
+
console.log(chalk14.dim(" Community skills matched to your project:\n"));
|
|
11709
11780
|
const selected = await interactiveSelect(skillSearchResult.results);
|
|
11710
11781
|
if (selected?.length) {
|
|
11711
11782
|
await installSkills(selected, targetAgent, skillSearchResult.contentMap);
|
|
@@ -11714,32 +11785,32 @@ ${agentRefs.join(" ")}
|
|
|
11714
11785
|
}
|
|
11715
11786
|
}
|
|
11716
11787
|
trackInitHookSelected("config-instructions");
|
|
11717
|
-
const done =
|
|
11718
|
-
console.log(
|
|
11719
|
-
console.log(
|
|
11788
|
+
const done = chalk14.green("\u2713");
|
|
11789
|
+
console.log(chalk14.bold.green("\n Caliber is set up!\n"));
|
|
11790
|
+
console.log(chalk14.bold(" What's configured:\n"));
|
|
11720
11791
|
console.log(
|
|
11721
|
-
` ${done} Continuous sync ${
|
|
11792
|
+
` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`
|
|
11722
11793
|
);
|
|
11723
11794
|
console.log(
|
|
11724
|
-
` ${done} Config generated ${title(`${bin} score`)} ${
|
|
11795
|
+
` ${done} Config generated ${title(`${bin} score`)} ${chalk14.dim("for full breakdown")}`
|
|
11725
11796
|
);
|
|
11726
11797
|
console.log(
|
|
11727
|
-
` ${done} Agent skills ${
|
|
11798
|
+
` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`
|
|
11728
11799
|
);
|
|
11729
11800
|
if (hasLearnableAgent) {
|
|
11730
11801
|
console.log(
|
|
11731
|
-
` ${done} Session learning ${
|
|
11802
|
+
` ${done} Session learning ${chalk14.dim("agent learns from your feedback")}`
|
|
11732
11803
|
);
|
|
11733
11804
|
}
|
|
11734
11805
|
if (communitySkillsInstalled > 0) {
|
|
11735
11806
|
console.log(
|
|
11736
|
-
` ${done} Community skills ${
|
|
11807
|
+
` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} skill${communitySkillsInstalled > 1 ? "s" : ""} installed for your stack`)}`
|
|
11737
11808
|
);
|
|
11738
11809
|
}
|
|
11739
|
-
console.log(
|
|
11740
|
-
console.log(
|
|
11741
|
-
console.log(
|
|
11742
|
-
console.log(
|
|
11810
|
+
console.log(chalk14.bold("\n What happens next:\n"));
|
|
11811
|
+
console.log(chalk14.dim(" Every commit will automatically sync your agent configs."));
|
|
11812
|
+
console.log(chalk14.dim(" New team members can run /setup-caliber to get set up instantly.\n"));
|
|
11813
|
+
console.log(chalk14.bold(" Explore:\n"));
|
|
11743
11814
|
console.log(` ${title(`${bin} score`)} Full scoring breakdown with improvement tips`);
|
|
11744
11815
|
console.log(` ${title(`${bin} skills`)} Find community skills for your stack`);
|
|
11745
11816
|
console.log(` ${title(`${bin} undo`)} Revert all changes from this run`);
|
|
@@ -11750,17 +11821,17 @@ ${agentRefs.join(" ")}
|
|
|
11750
11821
|
}
|
|
11751
11822
|
if (report) {
|
|
11752
11823
|
report.markStep("Finished");
|
|
11753
|
-
const reportPath =
|
|
11824
|
+
const reportPath = path29.join(process.cwd(), ".caliber", "debug-report.md");
|
|
11754
11825
|
report.write(reportPath);
|
|
11755
11826
|
console.log(
|
|
11756
|
-
|
|
11827
|
+
chalk14.dim(` Debug report written to ${path29.relative(process.cwd(), reportPath)}
|
|
11757
11828
|
`)
|
|
11758
11829
|
);
|
|
11759
11830
|
}
|
|
11760
11831
|
}
|
|
11761
11832
|
|
|
11762
11833
|
// src/commands/undo.ts
|
|
11763
|
-
import
|
|
11834
|
+
import chalk15 from "chalk";
|
|
11764
11835
|
import ora4 from "ora";
|
|
11765
11836
|
function undoCommand() {
|
|
11766
11837
|
const spinner = ora4("Reverting config changes...").start();
|
|
@@ -11773,27 +11844,27 @@ function undoCommand() {
|
|
|
11773
11844
|
trackUndoExecuted();
|
|
11774
11845
|
spinner.succeed("Config reverted successfully.\n");
|
|
11775
11846
|
if (restored.length > 0) {
|
|
11776
|
-
console.log(
|
|
11847
|
+
console.log(chalk15.cyan(" Restored from backup:"));
|
|
11777
11848
|
for (const file of restored) {
|
|
11778
|
-
console.log(` ${
|
|
11849
|
+
console.log(` ${chalk15.green("\u21A9")} ${file}`);
|
|
11779
11850
|
}
|
|
11780
11851
|
}
|
|
11781
11852
|
if (removed.length > 0) {
|
|
11782
|
-
console.log(
|
|
11853
|
+
console.log(chalk15.cyan(" Removed:"));
|
|
11783
11854
|
for (const file of removed) {
|
|
11784
|
-
console.log(` ${
|
|
11855
|
+
console.log(` ${chalk15.red("\u2717")} ${file}`);
|
|
11785
11856
|
}
|
|
11786
11857
|
}
|
|
11787
11858
|
console.log("");
|
|
11788
11859
|
} catch (err) {
|
|
11789
|
-
spinner.fail(
|
|
11860
|
+
spinner.fail(chalk15.red(err instanceof Error ? err.message : "Undo failed"));
|
|
11790
11861
|
throw new Error("__exit__");
|
|
11791
11862
|
}
|
|
11792
11863
|
}
|
|
11793
11864
|
|
|
11794
11865
|
// src/commands/status.ts
|
|
11795
|
-
import
|
|
11796
|
-
import
|
|
11866
|
+
import chalk16 from "chalk";
|
|
11867
|
+
import fs37 from "fs";
|
|
11797
11868
|
init_config();
|
|
11798
11869
|
init_resolve_caliber();
|
|
11799
11870
|
async function statusCommand(options) {
|
|
@@ -11808,29 +11879,29 @@ async function statusCommand(options) {
|
|
|
11808
11879
|
}, null, 2));
|
|
11809
11880
|
return;
|
|
11810
11881
|
}
|
|
11811
|
-
console.log(
|
|
11882
|
+
console.log(chalk16.bold("\nCaliber Status\n"));
|
|
11812
11883
|
if (config) {
|
|
11813
|
-
console.log(` LLM: ${
|
|
11884
|
+
console.log(` LLM: ${chalk16.green(config.provider)} (${config.model})`);
|
|
11814
11885
|
} else {
|
|
11815
11886
|
const bin = resolveCaliber();
|
|
11816
|
-
console.log(` LLM: ${
|
|
11887
|
+
console.log(` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")(`${bin} config`)}`);
|
|
11817
11888
|
}
|
|
11818
11889
|
if (!manifest) {
|
|
11819
|
-
console.log(` Config: ${
|
|
11820
|
-
console.log(
|
|
11890
|
+
console.log(` Config: ${chalk16.dim("No config applied")}`);
|
|
11891
|
+
console.log(chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")(`${resolveCaliber()} init`) + chalk16.dim(" to get started.\n"));
|
|
11821
11892
|
return;
|
|
11822
11893
|
}
|
|
11823
|
-
console.log(` Files managed: ${
|
|
11894
|
+
console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
|
|
11824
11895
|
for (const entry of manifest.entries) {
|
|
11825
|
-
const exists =
|
|
11826
|
-
const icon = exists ?
|
|
11896
|
+
const exists = fs37.existsSync(entry.path);
|
|
11897
|
+
const icon = exists ? chalk16.green("\u2713") : chalk16.red("\u2717");
|
|
11827
11898
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
11828
11899
|
}
|
|
11829
11900
|
console.log("");
|
|
11830
11901
|
}
|
|
11831
11902
|
|
|
11832
11903
|
// src/commands/regenerate.ts
|
|
11833
|
-
import
|
|
11904
|
+
import chalk17 from "chalk";
|
|
11834
11905
|
import ora5 from "ora";
|
|
11835
11906
|
import select6 from "@inquirer/select";
|
|
11836
11907
|
init_review();
|
|
@@ -11840,12 +11911,12 @@ async function regenerateCommand(options) {
|
|
|
11840
11911
|
const bin = resolveCaliber();
|
|
11841
11912
|
const config = loadConfig();
|
|
11842
11913
|
if (!config) {
|
|
11843
|
-
console.log(
|
|
11914
|
+
console.log(chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")(`${bin} config`) + chalk17.red(" first."));
|
|
11844
11915
|
throw new Error("__exit__");
|
|
11845
11916
|
}
|
|
11846
11917
|
const manifest = readManifest();
|
|
11847
11918
|
if (!manifest) {
|
|
11848
|
-
console.log(
|
|
11919
|
+
console.log(chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")(`${bin} init`) + chalk17.yellow(" first."));
|
|
11849
11920
|
throw new Error("__exit__");
|
|
11850
11921
|
}
|
|
11851
11922
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
@@ -11856,7 +11927,7 @@ async function regenerateCommand(options) {
|
|
|
11856
11927
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
11857
11928
|
displayScoreSummary(baselineScore);
|
|
11858
11929
|
if (baselineScore.score === 100) {
|
|
11859
|
-
console.log(
|
|
11930
|
+
console.log(chalk17.green(" Your config is already at 100/100 \u2014 nothing to regenerate.\n"));
|
|
11860
11931
|
return;
|
|
11861
11932
|
}
|
|
11862
11933
|
const genSpinner = ora5("Regenerating config...").start();
|
|
@@ -11898,18 +11969,18 @@ async function regenerateCommand(options) {
|
|
|
11898
11969
|
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
11899
11970
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
11900
11971
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
11901
|
-
console.log(
|
|
11902
|
-
${
|
|
11972
|
+
console.log(chalk17.dim(`
|
|
11973
|
+
${chalk17.green(`${staged.newFiles} new`)} / ${chalk17.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
11903
11974
|
`));
|
|
11904
11975
|
if (totalChanges === 0) {
|
|
11905
|
-
console.log(
|
|
11976
|
+
console.log(chalk17.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
11906
11977
|
cleanupStaging();
|
|
11907
11978
|
return;
|
|
11908
11979
|
}
|
|
11909
11980
|
if (options.dryRun) {
|
|
11910
|
-
console.log(
|
|
11981
|
+
console.log(chalk17.yellow("[Dry run] Would write:"));
|
|
11911
11982
|
for (const f of staged.stagedFiles) {
|
|
11912
|
-
console.log(` ${f.isNew ?
|
|
11983
|
+
console.log(` ${f.isNew ? chalk17.green("+") : chalk17.yellow("~")} ${f.relativePath}`);
|
|
11913
11984
|
}
|
|
11914
11985
|
cleanupStaging();
|
|
11915
11986
|
return;
|
|
@@ -11928,7 +11999,7 @@ async function regenerateCommand(options) {
|
|
|
11928
11999
|
});
|
|
11929
12000
|
cleanupStaging();
|
|
11930
12001
|
if (action === "decline") {
|
|
11931
|
-
console.log(
|
|
12002
|
+
console.log(chalk17.dim("Regeneration cancelled. No files were modified."));
|
|
11932
12003
|
return;
|
|
11933
12004
|
}
|
|
11934
12005
|
const writeSpinner = ora5("Writing config files...").start();
|
|
@@ -11936,20 +12007,20 @@ async function regenerateCommand(options) {
|
|
|
11936
12007
|
const result = writeSetup(generatedSetup);
|
|
11937
12008
|
writeSpinner.succeed("Config files written");
|
|
11938
12009
|
for (const file of result.written) {
|
|
11939
|
-
console.log(` ${
|
|
12010
|
+
console.log(` ${chalk17.green("\u2713")} ${file}`);
|
|
11940
12011
|
}
|
|
11941
12012
|
if (result.deleted.length > 0) {
|
|
11942
12013
|
for (const file of result.deleted) {
|
|
11943
|
-
console.log(` ${
|
|
12014
|
+
console.log(` ${chalk17.red("\u2717")} ${file}`);
|
|
11944
12015
|
}
|
|
11945
12016
|
}
|
|
11946
12017
|
if (result.backupDir) {
|
|
11947
|
-
console.log(
|
|
12018
|
+
console.log(chalk17.dim(`
|
|
11948
12019
|
Backups saved to ${result.backupDir}`));
|
|
11949
12020
|
}
|
|
11950
12021
|
} catch (err) {
|
|
11951
12022
|
writeSpinner.fail("Failed to write files");
|
|
11952
|
-
console.error(
|
|
12023
|
+
console.error(chalk17.red(err instanceof Error ? err.message : "Unknown error"));
|
|
11953
12024
|
throw new Error("__exit__");
|
|
11954
12025
|
}
|
|
11955
12026
|
const sha = getCurrentHeadSha();
|
|
@@ -11961,35 +12032,35 @@ async function regenerateCommand(options) {
|
|
|
11961
12032
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
11962
12033
|
if (afterScore.score < baselineScore.score) {
|
|
11963
12034
|
console.log("");
|
|
11964
|
-
console.log(
|
|
12035
|
+
console.log(chalk17.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
11965
12036
|
try {
|
|
11966
12037
|
const { restored, removed } = undoSetup();
|
|
11967
12038
|
if (restored.length > 0 || removed.length > 0) {
|
|
11968
|
-
console.log(
|
|
12039
|
+
console.log(chalk17.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
11969
12040
|
}
|
|
11970
12041
|
} catch {
|
|
11971
12042
|
}
|
|
11972
|
-
console.log(
|
|
12043
|
+
console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} init --force`) + chalk17.dim(" to override.\n"));
|
|
11973
12044
|
return;
|
|
11974
12045
|
}
|
|
11975
12046
|
displayScoreDelta(baselineScore, afterScore);
|
|
11976
12047
|
trackRegenerateCompleted(action, Date.now());
|
|
11977
|
-
console.log(
|
|
11978
|
-
console.log(
|
|
12048
|
+
console.log(chalk17.bold.green(" Regeneration complete!"));
|
|
12049
|
+
console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} undo`) + chalk17.dim(" to revert changes.\n"));
|
|
11979
12050
|
}
|
|
11980
12051
|
|
|
11981
12052
|
// src/commands/score.ts
|
|
11982
|
-
import
|
|
12053
|
+
import fs38 from "fs";
|
|
11983
12054
|
import os7 from "os";
|
|
11984
|
-
import
|
|
12055
|
+
import path30 from "path";
|
|
11985
12056
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
11986
|
-
import
|
|
12057
|
+
import chalk18 from "chalk";
|
|
11987
12058
|
init_resolve_caliber();
|
|
11988
12059
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".cursorrules", "CALIBER_LEARNINGS.md"];
|
|
11989
12060
|
var CONFIG_DIRS = [".claude", ".cursor"];
|
|
11990
12061
|
function scoreBaseRef(ref, target) {
|
|
11991
12062
|
if (!/^[\w.\-/~^@{}]+$/.test(ref)) return null;
|
|
11992
|
-
const tmpDir =
|
|
12063
|
+
const tmpDir = fs38.mkdtempSync(path30.join(os7.tmpdir(), "caliber-compare-"));
|
|
11993
12064
|
try {
|
|
11994
12065
|
for (const file of CONFIG_FILES) {
|
|
11995
12066
|
try {
|
|
@@ -11997,7 +12068,7 @@ function scoreBaseRef(ref, target) {
|
|
|
11997
12068
|
encoding: "utf-8",
|
|
11998
12069
|
stdio: ["pipe", "pipe", "pipe"]
|
|
11999
12070
|
});
|
|
12000
|
-
|
|
12071
|
+
fs38.writeFileSync(path30.join(tmpDir, file), content);
|
|
12001
12072
|
} catch {
|
|
12002
12073
|
}
|
|
12003
12074
|
}
|
|
@@ -12008,13 +12079,13 @@ function scoreBaseRef(ref, target) {
|
|
|
12008
12079
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12009
12080
|
}).trim().split("\n").filter(Boolean);
|
|
12010
12081
|
for (const file of files) {
|
|
12011
|
-
const filePath =
|
|
12012
|
-
|
|
12082
|
+
const filePath = path30.join(tmpDir, file);
|
|
12083
|
+
fs38.mkdirSync(path30.dirname(filePath), { recursive: true });
|
|
12013
12084
|
const content = execFileSync4("git", ["show", `${ref}:${file}`], {
|
|
12014
12085
|
encoding: "utf-8",
|
|
12015
12086
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12016
12087
|
});
|
|
12017
|
-
|
|
12088
|
+
fs38.writeFileSync(filePath, content);
|
|
12018
12089
|
}
|
|
12019
12090
|
} catch {
|
|
12020
12091
|
}
|
|
@@ -12024,7 +12095,7 @@ function scoreBaseRef(ref, target) {
|
|
|
12024
12095
|
} catch {
|
|
12025
12096
|
return null;
|
|
12026
12097
|
} finally {
|
|
12027
|
-
|
|
12098
|
+
fs38.rmSync(tmpDir, { recursive: true, force: true });
|
|
12028
12099
|
}
|
|
12029
12100
|
}
|
|
12030
12101
|
async function scoreCommand(options) {
|
|
@@ -12037,7 +12108,7 @@ async function scoreCommand(options) {
|
|
|
12037
12108
|
const baseResult = scoreBaseRef(options.compare, target);
|
|
12038
12109
|
if (!baseResult) {
|
|
12039
12110
|
console.error(
|
|
12040
|
-
|
|
12111
|
+
chalk18.red(`Could not score ref "${options.compare}" \u2014 branch or ref not found.`)
|
|
12041
12112
|
);
|
|
12042
12113
|
process.exitCode = 1;
|
|
12043
12114
|
return;
|
|
@@ -12063,18 +12134,18 @@ async function scoreCommand(options) {
|
|
|
12063
12134
|
return;
|
|
12064
12135
|
}
|
|
12065
12136
|
displayScore(result);
|
|
12066
|
-
const separator2 =
|
|
12137
|
+
const separator2 = chalk18.gray(" " + "\u2500".repeat(53));
|
|
12067
12138
|
console.log(separator2);
|
|
12068
12139
|
if (delta > 0) {
|
|
12069
12140
|
console.log(
|
|
12070
|
-
|
|
12141
|
+
chalk18.green(` +${delta}`) + chalk18.gray(` from ${options.compare} (${baseResult.score}/100)`)
|
|
12071
12142
|
);
|
|
12072
12143
|
} else if (delta < 0) {
|
|
12073
12144
|
console.log(
|
|
12074
|
-
|
|
12145
|
+
chalk18.red(` ${delta}`) + chalk18.gray(` from ${options.compare} (${baseResult.score}/100)`)
|
|
12075
12146
|
);
|
|
12076
12147
|
} else {
|
|
12077
|
-
console.log(
|
|
12148
|
+
console.log(chalk18.gray(` No change from ${options.compare} (${baseResult.score}/100)`));
|
|
12078
12149
|
}
|
|
12079
12150
|
console.log("");
|
|
12080
12151
|
return;
|
|
@@ -12088,7 +12159,7 @@ async function scoreCommand(options) {
|
|
|
12088
12159
|
return;
|
|
12089
12160
|
}
|
|
12090
12161
|
displayScore(result);
|
|
12091
|
-
const separator =
|
|
12162
|
+
const separator = chalk18.gray(" " + "\u2500".repeat(53));
|
|
12092
12163
|
console.log(separator);
|
|
12093
12164
|
const bin = resolveCaliber();
|
|
12094
12165
|
const failing = result.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints));
|
|
@@ -12096,30 +12167,30 @@ async function scoreCommand(options) {
|
|
|
12096
12167
|
const topFix = failing[0];
|
|
12097
12168
|
const pts = topFix.maxPoints - topFix.earnedPoints;
|
|
12098
12169
|
console.log(
|
|
12099
|
-
|
|
12170
|
+
chalk18.gray(" Biggest gain: ") + chalk18.yellow(`+${pts} pts`) + chalk18.gray(` from "${topFix.name}"`) + (topFix.suggestion ? chalk18.gray(` \u2014 ${topFix.suggestion}`) : "")
|
|
12100
12171
|
);
|
|
12101
12172
|
console.log(
|
|
12102
|
-
|
|
12173
|
+
chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate or update your agent config files.")
|
|
12103
12174
|
);
|
|
12104
12175
|
} else if (failing.length > 0) {
|
|
12105
12176
|
console.log(
|
|
12106
|
-
|
|
12177
|
+
chalk18.green(" Looking good!") + chalk18.gray(
|
|
12107
12178
|
` ${failing.length} optional improvement${failing.length === 1 ? "" : "s"} available.`
|
|
12108
12179
|
)
|
|
12109
12180
|
);
|
|
12110
12181
|
console.log(
|
|
12111
|
-
|
|
12182
|
+
chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve, or ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch.")
|
|
12112
12183
|
);
|
|
12113
12184
|
} else {
|
|
12114
|
-
console.log(
|
|
12185
|
+
console.log(chalk18.green(" Perfect score! Your agent configs are fully optimized."));
|
|
12115
12186
|
}
|
|
12116
12187
|
console.log("");
|
|
12117
12188
|
}
|
|
12118
12189
|
|
|
12119
12190
|
// src/commands/refresh.ts
|
|
12120
|
-
import
|
|
12121
|
-
import
|
|
12122
|
-
import
|
|
12191
|
+
import fs43 from "fs";
|
|
12192
|
+
import path35 from "path";
|
|
12193
|
+
import chalk19 from "chalk";
|
|
12123
12194
|
import ora6 from "ora";
|
|
12124
12195
|
import pLimit from "p-limit";
|
|
12125
12196
|
|
|
@@ -12233,62 +12304,62 @@ function scopeDiffToDir(diff, dir, allConfigDirs) {
|
|
|
12233
12304
|
|
|
12234
12305
|
// src/writers/refresh.ts
|
|
12235
12306
|
init_pre_commit_block();
|
|
12236
|
-
import
|
|
12237
|
-
import
|
|
12307
|
+
import fs39 from "fs";
|
|
12308
|
+
import path31 from "path";
|
|
12238
12309
|
function writeFileGroup(groupDir, files) {
|
|
12239
|
-
|
|
12310
|
+
fs39.mkdirSync(groupDir, { recursive: true });
|
|
12240
12311
|
return files.map((file) => {
|
|
12241
|
-
const filePath =
|
|
12242
|
-
|
|
12312
|
+
const filePath = path31.join(groupDir, file.filename);
|
|
12313
|
+
fs39.writeFileSync(filePath, file.content);
|
|
12243
12314
|
return filePath.replace(/\\/g, "/");
|
|
12244
12315
|
});
|
|
12245
12316
|
}
|
|
12246
12317
|
function writeRefreshDocs(docs, dir = ".") {
|
|
12247
12318
|
const written = [];
|
|
12248
|
-
const p = (relPath) => (dir === "." ? relPath :
|
|
12319
|
+
const p = (relPath) => (dir === "." ? relPath : path31.join(dir, relPath)).replace(/\\/g, "/");
|
|
12249
12320
|
const ensureParent = (filePath) => {
|
|
12250
|
-
const parent =
|
|
12251
|
-
if (parent !== "." && !
|
|
12321
|
+
const parent = path31.dirname(filePath);
|
|
12322
|
+
if (parent !== "." && !fs39.existsSync(parent)) fs39.mkdirSync(parent, { recursive: true });
|
|
12252
12323
|
};
|
|
12253
12324
|
if (docs.agentsMd) {
|
|
12254
12325
|
const filePath = p("AGENTS.md");
|
|
12255
12326
|
ensureParent(filePath);
|
|
12256
|
-
|
|
12327
|
+
fs39.writeFileSync(filePath, appendManagedBlocks(docs.agentsMd, "codex"));
|
|
12257
12328
|
written.push(filePath);
|
|
12258
12329
|
}
|
|
12259
12330
|
if (docs.claudeMd) {
|
|
12260
12331
|
const filePath = p("CLAUDE.md");
|
|
12261
12332
|
ensureParent(filePath);
|
|
12262
|
-
|
|
12333
|
+
fs39.writeFileSync(filePath, appendManagedBlocks(docs.claudeMd));
|
|
12263
12334
|
written.push(filePath);
|
|
12264
12335
|
}
|
|
12265
12336
|
if (docs.claudeRules) {
|
|
12266
|
-
written.push(...writeFileGroup(p(
|
|
12337
|
+
written.push(...writeFileGroup(p(path31.join(".claude", "rules")), docs.claudeRules));
|
|
12267
12338
|
}
|
|
12268
12339
|
if (docs.readmeMd) {
|
|
12269
12340
|
const filePath = p("README.md");
|
|
12270
12341
|
ensureParent(filePath);
|
|
12271
|
-
|
|
12342
|
+
fs39.writeFileSync(filePath, docs.readmeMd);
|
|
12272
12343
|
written.push(filePath);
|
|
12273
12344
|
}
|
|
12274
12345
|
if (docs.cursorrules) {
|
|
12275
12346
|
const filePath = p(".cursorrules");
|
|
12276
12347
|
ensureParent(filePath);
|
|
12277
|
-
|
|
12348
|
+
fs39.writeFileSync(filePath, docs.cursorrules);
|
|
12278
12349
|
written.push(filePath);
|
|
12279
12350
|
}
|
|
12280
12351
|
if (docs.cursorRules) {
|
|
12281
|
-
written.push(...writeFileGroup(p(
|
|
12352
|
+
written.push(...writeFileGroup(p(path31.join(".cursor", "rules")), docs.cursorRules));
|
|
12282
12353
|
}
|
|
12283
12354
|
if (docs.copilotInstructions) {
|
|
12284
|
-
const filePath = p(
|
|
12355
|
+
const filePath = p(path31.join(".github", "copilot-instructions.md"));
|
|
12285
12356
|
ensureParent(filePath);
|
|
12286
|
-
|
|
12357
|
+
fs39.writeFileSync(filePath, appendManagedBlocks(docs.copilotInstructions, "copilot"));
|
|
12287
12358
|
written.push(filePath);
|
|
12288
12359
|
}
|
|
12289
12360
|
if (docs.copilotInstructionFiles) {
|
|
12290
12361
|
written.push(
|
|
12291
|
-
...writeFileGroup(p(
|
|
12362
|
+
...writeFileGroup(p(path31.join(".github", "instructions")), docs.copilotInstructionFiles)
|
|
12292
12363
|
);
|
|
12293
12364
|
}
|
|
12294
12365
|
return written;
|
|
@@ -12442,8 +12513,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
12442
12513
|
}
|
|
12443
12514
|
|
|
12444
12515
|
// src/learner/writer.ts
|
|
12445
|
-
import
|
|
12446
|
-
import
|
|
12516
|
+
import fs40 from "fs";
|
|
12517
|
+
import path32 from "path";
|
|
12447
12518
|
|
|
12448
12519
|
// src/learner/utils.ts
|
|
12449
12520
|
var TYPE_PREFIX_RE = /^\*\*\[[^\]]+\]\*\*\s*/;
|
|
@@ -12560,20 +12631,20 @@ function deduplicateLearnedItems(existing, incoming) {
|
|
|
12560
12631
|
}
|
|
12561
12632
|
function writeLearnedSectionTo(filePath, header, existing, incoming, mode) {
|
|
12562
12633
|
const { merged, newCount, newItems } = deduplicateLearnedItems(existing, incoming);
|
|
12563
|
-
|
|
12564
|
-
if (mode)
|
|
12634
|
+
fs40.writeFileSync(filePath, header + merged + "\n");
|
|
12635
|
+
if (mode) fs40.chmodSync(filePath, mode);
|
|
12565
12636
|
return { newCount, newItems };
|
|
12566
12637
|
}
|
|
12567
12638
|
function writeLearnedSection(content) {
|
|
12568
12639
|
return writeLearnedSectionTo(LEARNINGS_FILE, LEARNINGS_HEADER, readLearnedSection(), content);
|
|
12569
12640
|
}
|
|
12570
12641
|
function writeLearnedSkill(skill) {
|
|
12571
|
-
const skillDir =
|
|
12572
|
-
if (!
|
|
12573
|
-
const skillPath =
|
|
12574
|
-
if (!skill.isNew &&
|
|
12575
|
-
const existing =
|
|
12576
|
-
|
|
12642
|
+
const skillDir = path32.join(".claude", "skills", skill.name);
|
|
12643
|
+
if (!fs40.existsSync(skillDir)) fs40.mkdirSync(skillDir, { recursive: true });
|
|
12644
|
+
const skillPath = path32.join(skillDir, "SKILL.md");
|
|
12645
|
+
if (!skill.isNew && fs40.existsSync(skillPath)) {
|
|
12646
|
+
const existing = fs40.readFileSync(skillPath, "utf-8");
|
|
12647
|
+
fs40.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
12577
12648
|
} else {
|
|
12578
12649
|
const frontmatter = [
|
|
12579
12650
|
"---",
|
|
@@ -12582,12 +12653,12 @@ function writeLearnedSkill(skill) {
|
|
|
12582
12653
|
"---",
|
|
12583
12654
|
""
|
|
12584
12655
|
].join("\n");
|
|
12585
|
-
|
|
12656
|
+
fs40.writeFileSync(skillPath, frontmatter + skill.content);
|
|
12586
12657
|
}
|
|
12587
12658
|
return skillPath;
|
|
12588
12659
|
}
|
|
12589
12660
|
function writePersonalLearnedSection(content) {
|
|
12590
|
-
if (!
|
|
12661
|
+
if (!fs40.existsSync(AUTH_DIR)) fs40.mkdirSync(AUTH_DIR, { recursive: true });
|
|
12591
12662
|
return writeLearnedSectionTo(PERSONAL_LEARNINGS_FILE, PERSONAL_LEARNINGS_HEADER, readPersonalLearnings(), content, 384);
|
|
12592
12663
|
}
|
|
12593
12664
|
function addLearning(bullet, scope = "project") {
|
|
@@ -12600,38 +12671,38 @@ function addLearning(bullet, scope = "project") {
|
|
|
12600
12671
|
return { file: LEARNINGS_FILE, added: result.newCount > 0 };
|
|
12601
12672
|
}
|
|
12602
12673
|
function readPersonalLearnings() {
|
|
12603
|
-
if (!
|
|
12604
|
-
const content =
|
|
12674
|
+
if (!fs40.existsSync(PERSONAL_LEARNINGS_FILE)) return null;
|
|
12675
|
+
const content = fs40.readFileSync(PERSONAL_LEARNINGS_FILE, "utf-8");
|
|
12605
12676
|
const bullets = content.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
12606
12677
|
return bullets || null;
|
|
12607
12678
|
}
|
|
12608
12679
|
function readLearnedSection() {
|
|
12609
|
-
if (
|
|
12610
|
-
const content2 =
|
|
12680
|
+
if (fs40.existsSync(LEARNINGS_FILE)) {
|
|
12681
|
+
const content2 = fs40.readFileSync(LEARNINGS_FILE, "utf-8");
|
|
12611
12682
|
const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
12612
12683
|
return bullets || null;
|
|
12613
12684
|
}
|
|
12614
12685
|
const claudeMdPath = "CLAUDE.md";
|
|
12615
|
-
if (!
|
|
12616
|
-
const content =
|
|
12686
|
+
if (!fs40.existsSync(claudeMdPath)) return null;
|
|
12687
|
+
const content = fs40.readFileSync(claudeMdPath, "utf-8");
|
|
12617
12688
|
const startIdx = content.indexOf(LEARNED_START);
|
|
12618
12689
|
const endIdx = content.indexOf(LEARNED_END);
|
|
12619
12690
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
12620
12691
|
return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
|
|
12621
12692
|
}
|
|
12622
12693
|
function migrateInlineLearnings() {
|
|
12623
|
-
if (
|
|
12694
|
+
if (fs40.existsSync(LEARNINGS_FILE)) return false;
|
|
12624
12695
|
const claudeMdPath = "CLAUDE.md";
|
|
12625
|
-
if (!
|
|
12626
|
-
const content =
|
|
12696
|
+
if (!fs40.existsSync(claudeMdPath)) return false;
|
|
12697
|
+
const content = fs40.readFileSync(claudeMdPath, "utf-8");
|
|
12627
12698
|
const startIdx = content.indexOf(LEARNED_START);
|
|
12628
12699
|
const endIdx = content.indexOf(LEARNED_END);
|
|
12629
12700
|
if (startIdx === -1 || endIdx === -1) return false;
|
|
12630
12701
|
const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
|
|
12631
12702
|
if (!section) return false;
|
|
12632
|
-
|
|
12703
|
+
fs40.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
|
|
12633
12704
|
const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
|
|
12634
|
-
|
|
12705
|
+
fs40.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
|
|
12635
12706
|
return true;
|
|
12636
12707
|
}
|
|
12637
12708
|
|
|
@@ -12641,8 +12712,8 @@ init_resolve_caliber();
|
|
|
12641
12712
|
init_builtin_skills();
|
|
12642
12713
|
|
|
12643
12714
|
// src/lib/config-discovery.ts
|
|
12644
|
-
import
|
|
12645
|
-
import
|
|
12715
|
+
import fs41 from "fs";
|
|
12716
|
+
import path33 from "path";
|
|
12646
12717
|
var CONFIG_FILE_MARKERS = [
|
|
12647
12718
|
"CLAUDE.md",
|
|
12648
12719
|
"AGENTS.md",
|
|
@@ -12668,11 +12739,11 @@ var IGNORE_DIRS3 = /* @__PURE__ */ new Set([
|
|
|
12668
12739
|
var MAX_DEPTH = 4;
|
|
12669
12740
|
function hasConfigFiles(dir) {
|
|
12670
12741
|
for (const marker of CONFIG_FILE_MARKERS) {
|
|
12671
|
-
if (
|
|
12742
|
+
if (fs41.existsSync(path33.join(dir, marker))) return true;
|
|
12672
12743
|
}
|
|
12673
12744
|
for (const marker of CONFIG_DIR_MARKERS) {
|
|
12674
|
-
const markerPath =
|
|
12675
|
-
if (
|
|
12745
|
+
const markerPath = path33.join(dir, marker);
|
|
12746
|
+
if (fs41.existsSync(markerPath) && fs41.statSync(markerPath).isDirectory()) return true;
|
|
12676
12747
|
}
|
|
12677
12748
|
return false;
|
|
12678
12749
|
}
|
|
@@ -12689,15 +12760,15 @@ function walkForConfigs(baseDir, currentDir, depth, result) {
|
|
|
12689
12760
|
if (depth >= MAX_DEPTH) return;
|
|
12690
12761
|
let entries;
|
|
12691
12762
|
try {
|
|
12692
|
-
entries =
|
|
12763
|
+
entries = fs41.readdirSync(currentDir, { withFileTypes: true });
|
|
12693
12764
|
} catch {
|
|
12694
12765
|
return;
|
|
12695
12766
|
}
|
|
12696
12767
|
for (const entry of entries) {
|
|
12697
12768
|
if (!entry.isDirectory()) continue;
|
|
12698
12769
|
if (entry.name.startsWith(".") || IGNORE_DIRS3.has(entry.name)) continue;
|
|
12699
|
-
const fullPath =
|
|
12700
|
-
const relPath =
|
|
12770
|
+
const fullPath = path33.join(currentDir, entry.name);
|
|
12771
|
+
const relPath = path33.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
12701
12772
|
if (hasConfigFiles(fullPath)) {
|
|
12702
12773
|
result.push(relPath);
|
|
12703
12774
|
}
|
|
@@ -12708,8 +12779,8 @@ function walkForConfigs(baseDir, currentDir, depth, result) {
|
|
|
12708
12779
|
// src/commands/refresh.ts
|
|
12709
12780
|
function writeRefreshError(error) {
|
|
12710
12781
|
try {
|
|
12711
|
-
if (!
|
|
12712
|
-
|
|
12782
|
+
if (!fs43.existsSync(CALIBER_DIR)) fs43.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
12783
|
+
fs43.writeFileSync(
|
|
12713
12784
|
REFRESH_LAST_ERROR_FILE,
|
|
12714
12785
|
JSON.stringify(
|
|
12715
12786
|
{
|
|
@@ -12728,15 +12799,15 @@ function writeRefreshError(error) {
|
|
|
12728
12799
|
}
|
|
12729
12800
|
function readRefreshError() {
|
|
12730
12801
|
try {
|
|
12731
|
-
if (!
|
|
12732
|
-
return JSON.parse(
|
|
12802
|
+
if (!fs43.existsSync(REFRESH_LAST_ERROR_FILE)) return null;
|
|
12803
|
+
return JSON.parse(fs43.readFileSync(REFRESH_LAST_ERROR_FILE, "utf-8"));
|
|
12733
12804
|
} catch {
|
|
12734
12805
|
return null;
|
|
12735
12806
|
}
|
|
12736
12807
|
}
|
|
12737
12808
|
function clearRefreshError() {
|
|
12738
12809
|
try {
|
|
12739
|
-
if (
|
|
12810
|
+
if (fs43.existsSync(REFRESH_LAST_ERROR_FILE)) fs43.unlinkSync(REFRESH_LAST_ERROR_FILE);
|
|
12740
12811
|
} catch {
|
|
12741
12812
|
}
|
|
12742
12813
|
}
|
|
@@ -12756,11 +12827,11 @@ function log2(quiet, ...args) {
|
|
|
12756
12827
|
function discoverGitRepos(parentDir) {
|
|
12757
12828
|
const repos = [];
|
|
12758
12829
|
try {
|
|
12759
|
-
const entries =
|
|
12830
|
+
const entries = fs43.readdirSync(parentDir, { withFileTypes: true });
|
|
12760
12831
|
for (const entry of entries) {
|
|
12761
12832
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
12762
|
-
const childPath =
|
|
12763
|
-
if (
|
|
12833
|
+
const childPath = path35.join(parentDir, entry.name);
|
|
12834
|
+
if (fs43.existsSync(path35.join(childPath, ".git"))) {
|
|
12764
12835
|
repos.push(childPath);
|
|
12765
12836
|
}
|
|
12766
12837
|
}
|
|
@@ -12770,7 +12841,7 @@ function discoverGitRepos(parentDir) {
|
|
|
12770
12841
|
}
|
|
12771
12842
|
function collectFilesToWrite(updatedDocs, dir = ".") {
|
|
12772
12843
|
const files = [];
|
|
12773
|
-
const p = (relPath) => (dir === "." ? relPath :
|
|
12844
|
+
const p = (relPath) => (dir === "." ? relPath : path35.join(dir, relPath)).replace(/\\/g, "/");
|
|
12774
12845
|
if (updatedDocs.agentsMd) files.push(p("AGENTS.md"));
|
|
12775
12846
|
if (updatedDocs.claudeMd) files.push(p("CLAUDE.md"));
|
|
12776
12847
|
if (Array.isArray(updatedDocs.claudeRules)) {
|
|
@@ -12796,12 +12867,13 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12796
12867
|
const quiet = !!options.quiet;
|
|
12797
12868
|
const suppress = !!options.suppressSpinner;
|
|
12798
12869
|
const effectiveQuiet = quiet || suppress;
|
|
12799
|
-
const prefix = options.label ? `${
|
|
12800
|
-
const absDir = dir === "." ? repoDir :
|
|
12870
|
+
const prefix = options.label ? `${chalk19.bold(options.label)} ` : "";
|
|
12871
|
+
const absDir = dir === "." ? repoDir : path35.resolve(repoDir, dir);
|
|
12801
12872
|
const scope = dir === "." ? void 0 : dir;
|
|
12802
12873
|
const spinner = effectiveQuiet ? null : ora6(`${prefix}Analyzing changes...`).start();
|
|
12803
12874
|
const learnedSection = readLearnedSection();
|
|
12804
12875
|
const fingerprint = await collectFingerprint(absDir);
|
|
12876
|
+
printLargeFileWarnings(scanLargeFiles(absDir), { spinner: spinner ?? void 0 });
|
|
12805
12877
|
const existingDocs = fingerprint.existingConfigs;
|
|
12806
12878
|
const projectContext = {
|
|
12807
12879
|
languages: fingerprint.languages,
|
|
@@ -12853,10 +12925,10 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12853
12925
|
if (options.dryRun) {
|
|
12854
12926
|
spinner?.info(`${prefix}Dry run \u2014 would update:`);
|
|
12855
12927
|
for (const doc of response.docsUpdated) {
|
|
12856
|
-
console.log(` ${
|
|
12928
|
+
console.log(` ${chalk19.yellow("~")} ${doc}`);
|
|
12857
12929
|
}
|
|
12858
12930
|
if (response.changesSummary) {
|
|
12859
|
-
console.log(
|
|
12931
|
+
console.log(chalk19.dim(`
|
|
12860
12932
|
${response.changesSummary}`));
|
|
12861
12933
|
}
|
|
12862
12934
|
return { written: [], fileChanges: [], syncedAgents: [], changesSummary: null };
|
|
@@ -12864,9 +12936,9 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12864
12936
|
const allFilesToWrite = collectFilesToWrite(response.updatedDocs, dir);
|
|
12865
12937
|
const preRefreshContents = /* @__PURE__ */ new Map();
|
|
12866
12938
|
for (const filePath of allFilesToWrite) {
|
|
12867
|
-
const fullPath =
|
|
12939
|
+
const fullPath = path35.resolve(repoDir, filePath);
|
|
12868
12940
|
try {
|
|
12869
|
-
preRefreshContents.set(filePath,
|
|
12941
|
+
preRefreshContents.set(filePath, fs43.readFileSync(fullPath, "utf-8"));
|
|
12870
12942
|
} catch {
|
|
12871
12943
|
preRefreshContents.set(filePath, null);
|
|
12872
12944
|
}
|
|
@@ -12882,14 +12954,14 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12882
12954
|
const postScore = computeLocalScore(absDir, targetAgent);
|
|
12883
12955
|
if (postScore.score < preScore.score) {
|
|
12884
12956
|
for (const [filePath, content] of preRefreshContents) {
|
|
12885
|
-
const fullPath =
|
|
12957
|
+
const fullPath = path35.resolve(repoDir, filePath);
|
|
12886
12958
|
if (content === null) {
|
|
12887
12959
|
try {
|
|
12888
|
-
|
|
12960
|
+
fs43.unlinkSync(fullPath);
|
|
12889
12961
|
} catch {
|
|
12890
12962
|
}
|
|
12891
12963
|
} else {
|
|
12892
|
-
|
|
12964
|
+
fs43.writeFileSync(fullPath, content);
|
|
12893
12965
|
}
|
|
12894
12966
|
}
|
|
12895
12967
|
spinner?.warn(
|
|
@@ -12897,7 +12969,7 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12897
12969
|
);
|
|
12898
12970
|
log2(
|
|
12899
12971
|
effectiveQuiet,
|
|
12900
|
-
|
|
12972
|
+
chalk19.dim(` Config quality gate prevented a regression. No files were changed.`)
|
|
12901
12973
|
);
|
|
12902
12974
|
return { written: [], fileChanges: [], syncedAgents: [], changesSummary: null };
|
|
12903
12975
|
}
|
|
@@ -12910,18 +12982,18 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12910
12982
|
if (!suppress) {
|
|
12911
12983
|
for (const file of written) {
|
|
12912
12984
|
const desc = fileChangesMap.get(file);
|
|
12913
|
-
const suffix = desc ?
|
|
12914
|
-
log2(effectiveQuiet, ` ${
|
|
12985
|
+
const suffix = desc ? chalk19.dim(` \u2014 ${desc}`) : "";
|
|
12986
|
+
log2(effectiveQuiet, ` ${chalk19.green("\u2713")} ${file}${suffix}`);
|
|
12915
12987
|
}
|
|
12916
12988
|
if (syncedAgents.length > 1) {
|
|
12917
12989
|
log2(
|
|
12918
12990
|
effectiveQuiet,
|
|
12919
|
-
|
|
12991
|
+
chalk19.cyan(`
|
|
12920
12992
|
${syncedAgents.length} agent formats in sync (${syncedAgents.join(", ")})`)
|
|
12921
12993
|
);
|
|
12922
12994
|
}
|
|
12923
12995
|
if (response.changesSummary) {
|
|
12924
|
-
log2(effectiveQuiet,
|
|
12996
|
+
log2(effectiveQuiet, chalk19.dim(`
|
|
12925
12997
|
${response.changesSummary}`));
|
|
12926
12998
|
}
|
|
12927
12999
|
}
|
|
@@ -12929,7 +13001,7 @@ async function refreshDir(repoDir, dir, diff, options) {
|
|
|
12929
13001
|
}
|
|
12930
13002
|
async function refreshSingleRepo(repoDir, options) {
|
|
12931
13003
|
const quiet = !!options.quiet;
|
|
12932
|
-
const prefix = options.label ? `${
|
|
13004
|
+
const prefix = options.label ? `${chalk19.bold(options.label)} ` : "";
|
|
12933
13005
|
const state = readState();
|
|
12934
13006
|
const lastSha = state?.lastRefreshSha ?? null;
|
|
12935
13007
|
const currentSha = getCurrentHeadSha();
|
|
@@ -12938,7 +13010,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
12938
13010
|
if (elapsed < REFRESH_COOLDOWN_MS && elapsed > 0) {
|
|
12939
13011
|
log2(
|
|
12940
13012
|
quiet,
|
|
12941
|
-
|
|
13013
|
+
chalk19.dim(`${prefix}Skipped \u2014 last refresh was ${Math.round(elapsed / 1e3)}s ago.`)
|
|
12942
13014
|
);
|
|
12943
13015
|
return;
|
|
12944
13016
|
}
|
|
@@ -12948,14 +13020,14 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
12948
13020
|
if (currentSha) {
|
|
12949
13021
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
12950
13022
|
}
|
|
12951
|
-
log2(quiet,
|
|
13023
|
+
log2(quiet, chalk19.dim(`${prefix}No changes since last refresh.`));
|
|
12952
13024
|
return;
|
|
12953
13025
|
}
|
|
12954
13026
|
const configDirs = discoverConfigDirs(repoDir);
|
|
12955
13027
|
if (configDirs.length <= 1) {
|
|
12956
13028
|
await refreshDir(repoDir, ".", diff, options);
|
|
12957
13029
|
} else {
|
|
12958
|
-
log2(quiet,
|
|
13030
|
+
log2(quiet, chalk19.dim(`${prefix}Found configs in ${configDirs.length} directories
|
|
12959
13031
|
`));
|
|
12960
13032
|
const dirsWithChanges = configDirs.map((dir) => ({ dir, scopedDiff: scopeDiffToDir(diff, dir, configDirs) })).filter(({ scopedDiff }) => scopedDiff.hasChanges);
|
|
12961
13033
|
const parallelSpinner = quiet ? null : ora6(
|
|
@@ -12983,7 +13055,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
12983
13055
|
hadFailure = true;
|
|
12984
13056
|
log2(
|
|
12985
13057
|
quiet,
|
|
12986
|
-
|
|
13058
|
+
chalk19.yellow(
|
|
12987
13059
|
` ${dirLabel}: refresh failed \u2014 ${result.reason instanceof Error ? result.reason.message : "unknown error"}`
|
|
12988
13060
|
)
|
|
12989
13061
|
);
|
|
@@ -12992,20 +13064,20 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
12992
13064
|
const fileChangesMap = new Map(fileChanges.map((fc) => [fc.file, fc.description]));
|
|
12993
13065
|
for (const file of written) {
|
|
12994
13066
|
const desc = fileChangesMap.get(file);
|
|
12995
|
-
const suffix = desc ?
|
|
12996
|
-
log2(quiet, ` ${
|
|
13067
|
+
const suffix = desc ? chalk19.dim(` \u2014 ${desc}`) : "";
|
|
13068
|
+
log2(quiet, ` ${chalk19.green("\u2713")} ${dirLabel}/${file}${suffix}`);
|
|
12997
13069
|
}
|
|
12998
13070
|
if (syncedAgents.length > 1) {
|
|
12999
13071
|
log2(
|
|
13000
13072
|
quiet,
|
|
13001
|
-
|
|
13073
|
+
chalk19.cyan(
|
|
13002
13074
|
`
|
|
13003
13075
|
${syncedAgents.length} agent formats in sync (${syncedAgents.join(", ")})`
|
|
13004
13076
|
)
|
|
13005
13077
|
);
|
|
13006
13078
|
}
|
|
13007
13079
|
if (changesSummary) {
|
|
13008
|
-
log2(quiet,
|
|
13080
|
+
log2(quiet, chalk19.dim(`
|
|
13009
13081
|
${changesSummary}`));
|
|
13010
13082
|
}
|
|
13011
13083
|
}
|
|
@@ -13016,7 +13088,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
13016
13088
|
}
|
|
13017
13089
|
const builtinWritten = ensureBuiltinSkills();
|
|
13018
13090
|
for (const file of builtinWritten) {
|
|
13019
|
-
log2(quiet, ` ${
|
|
13091
|
+
log2(quiet, ` ${chalk19.green("\u2713")} ${file} ${chalk19.dim("(built-in)")}`);
|
|
13020
13092
|
}
|
|
13021
13093
|
clearRefreshError();
|
|
13022
13094
|
if (currentSha) {
|
|
@@ -13033,11 +13105,11 @@ async function refreshCommand(options) {
|
|
|
13033
13105
|
if (!quiet) {
|
|
13034
13106
|
const lastError = readRefreshError();
|
|
13035
13107
|
if (lastError) {
|
|
13036
|
-
console.log(
|
|
13108
|
+
console.log(chalk19.yellow(`
|
|
13037
13109
|
\u26A0 Last refresh failed (${lastError.timestamp}):`));
|
|
13038
|
-
console.log(
|
|
13110
|
+
console.log(chalk19.dim(` ${lastError.error}`));
|
|
13039
13111
|
console.log(
|
|
13040
|
-
|
|
13112
|
+
chalk19.dim(
|
|
13041
13113
|
` Run with --debug for full details, or report at https://github.com/caliber-ai-org/ai-setup/issues
|
|
13042
13114
|
`
|
|
13043
13115
|
)
|
|
@@ -13050,7 +13122,7 @@ async function refreshCommand(options) {
|
|
|
13050
13122
|
if (!config) {
|
|
13051
13123
|
if (quiet) return;
|
|
13052
13124
|
console.log(
|
|
13053
|
-
|
|
13125
|
+
chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")(`${resolveCaliber()} config`) + chalk19.red(" (e.g. choose Cursor) or set an API key.")
|
|
13054
13126
|
);
|
|
13055
13127
|
throw new Error("__exit__");
|
|
13056
13128
|
}
|
|
@@ -13063,15 +13135,15 @@ async function refreshCommand(options) {
|
|
|
13063
13135
|
if (repos.length === 0) {
|
|
13064
13136
|
if (quiet) return;
|
|
13065
13137
|
console.log(
|
|
13066
|
-
|
|
13138
|
+
chalk19.red("Not inside a git repository and no git repos found in child directories.")
|
|
13067
13139
|
);
|
|
13068
13140
|
throw new Error("__exit__");
|
|
13069
13141
|
}
|
|
13070
|
-
log2(quiet,
|
|
13142
|
+
log2(quiet, chalk19.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
13071
13143
|
`));
|
|
13072
13144
|
const originalDir = process.cwd();
|
|
13073
13145
|
for (const repo of repos) {
|
|
13074
|
-
const repoName =
|
|
13146
|
+
const repoName = path35.basename(repo);
|
|
13075
13147
|
try {
|
|
13076
13148
|
process.chdir(repo);
|
|
13077
13149
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
@@ -13080,7 +13152,7 @@ async function refreshCommand(options) {
|
|
|
13080
13152
|
writeRefreshError(err);
|
|
13081
13153
|
log2(
|
|
13082
13154
|
quiet,
|
|
13083
|
-
|
|
13155
|
+
chalk19.yellow(
|
|
13084
13156
|
`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`
|
|
13085
13157
|
)
|
|
13086
13158
|
);
|
|
@@ -13093,14 +13165,14 @@ async function refreshCommand(options) {
|
|
|
13093
13165
|
writeRefreshError(err);
|
|
13094
13166
|
if (quiet) return;
|
|
13095
13167
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
13096
|
-
console.log(
|
|
13168
|
+
console.log(chalk19.red(`Refresh failed: ${msg}`));
|
|
13097
13169
|
throw new Error("__exit__");
|
|
13098
13170
|
}
|
|
13099
13171
|
}
|
|
13100
13172
|
|
|
13101
13173
|
// src/commands/hooks.ts
|
|
13102
|
-
import
|
|
13103
|
-
import
|
|
13174
|
+
import chalk20 from "chalk";
|
|
13175
|
+
import fs44 from "fs";
|
|
13104
13176
|
var HOOKS = [
|
|
13105
13177
|
{
|
|
13106
13178
|
id: "session-end",
|
|
@@ -13136,41 +13208,41 @@ var HOOKS = [
|
|
|
13136
13208
|
}
|
|
13137
13209
|
];
|
|
13138
13210
|
function printStatus() {
|
|
13139
|
-
console.log(
|
|
13211
|
+
console.log(chalk20.bold("\n Hooks\n"));
|
|
13140
13212
|
for (const hook of HOOKS) {
|
|
13141
13213
|
const installed = hook.isInstalled();
|
|
13142
|
-
const icon = installed ?
|
|
13143
|
-
const state = installed ?
|
|
13214
|
+
const icon = installed ? chalk20.green("\u2713") : chalk20.dim("\u2717");
|
|
13215
|
+
const state = installed ? chalk20.green("enabled") : chalk20.dim("disabled");
|
|
13144
13216
|
console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
|
|
13145
|
-
console.log(
|
|
13217
|
+
console.log(chalk20.dim(` ${hook.description}`));
|
|
13146
13218
|
}
|
|
13147
13219
|
console.log("");
|
|
13148
13220
|
}
|
|
13149
13221
|
async function hooksCommand(options) {
|
|
13150
13222
|
if (!options.install && !options.remove) {
|
|
13151
13223
|
console.log(
|
|
13152
|
-
|
|
13224
|
+
chalk20.dim("\n Note: caliber now adds refresh instructions directly to config files.")
|
|
13153
13225
|
);
|
|
13154
13226
|
console.log(
|
|
13155
|
-
|
|
13227
|
+
chalk20.dim(" These hooks are available for non-agent workflows (manual commits).\n")
|
|
13156
13228
|
);
|
|
13157
13229
|
}
|
|
13158
13230
|
if (options.install) {
|
|
13159
13231
|
for (const hook of HOOKS) {
|
|
13160
13232
|
const result = hook.install();
|
|
13161
13233
|
if (result.alreadyInstalled) {
|
|
13162
|
-
console.log(
|
|
13234
|
+
console.log(chalk20.dim(` ${hook.label} already enabled.`));
|
|
13163
13235
|
} else {
|
|
13164
|
-
console.log(
|
|
13236
|
+
console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
|
|
13165
13237
|
}
|
|
13166
13238
|
}
|
|
13167
|
-
if (
|
|
13239
|
+
if (fs44.existsSync(".claude")) {
|
|
13168
13240
|
const r = installLearningHooks();
|
|
13169
|
-
if (r.installed) console.log(
|
|
13241
|
+
if (r.installed) console.log(chalk20.green(" \u2713") + " Claude Code learning hooks enabled");
|
|
13170
13242
|
}
|
|
13171
|
-
if (
|
|
13243
|
+
if (fs44.existsSync(".cursor")) {
|
|
13172
13244
|
const r = installCursorLearningHooks();
|
|
13173
|
-
if (r.installed) console.log(
|
|
13245
|
+
if (r.installed) console.log(chalk20.green(" \u2713") + " Cursor learning hooks enabled");
|
|
13174
13246
|
}
|
|
13175
13247
|
return;
|
|
13176
13248
|
}
|
|
@@ -13178,9 +13250,9 @@ async function hooksCommand(options) {
|
|
|
13178
13250
|
for (const hook of HOOKS) {
|
|
13179
13251
|
const result = hook.remove();
|
|
13180
13252
|
if (result.notFound) {
|
|
13181
|
-
console.log(
|
|
13253
|
+
console.log(chalk20.dim(` ${hook.label} already disabled.`));
|
|
13182
13254
|
} else {
|
|
13183
|
-
console.log(
|
|
13255
|
+
console.log(chalk20.green(" \u2713") + ` ${hook.label} removed`);
|
|
13184
13256
|
}
|
|
13185
13257
|
}
|
|
13186
13258
|
return;
|
|
@@ -13195,18 +13267,18 @@ async function hooksCommand(options) {
|
|
|
13195
13267
|
const states = HOOKS.map((h) => h.isInstalled());
|
|
13196
13268
|
function render() {
|
|
13197
13269
|
const lines = [];
|
|
13198
|
-
lines.push(
|
|
13270
|
+
lines.push(chalk20.bold(" Hooks"));
|
|
13199
13271
|
lines.push("");
|
|
13200
13272
|
for (let i = 0; i < HOOKS.length; i++) {
|
|
13201
13273
|
const hook = HOOKS[i];
|
|
13202
13274
|
const enabled = states[i];
|
|
13203
|
-
const toggle = enabled ?
|
|
13204
|
-
const ptr = i === cursor ?
|
|
13275
|
+
const toggle = enabled ? chalk20.green("[on] ") : chalk20.dim("[off]");
|
|
13276
|
+
const ptr = i === cursor ? chalk20.cyan(">") : " ";
|
|
13205
13277
|
lines.push(` ${ptr} ${toggle} ${hook.label}`);
|
|
13206
|
-
lines.push(
|
|
13278
|
+
lines.push(chalk20.dim(` ${hook.description}`));
|
|
13207
13279
|
}
|
|
13208
13280
|
lines.push("");
|
|
13209
|
-
lines.push(
|
|
13281
|
+
lines.push(chalk20.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
|
|
13210
13282
|
return lines.join("\n");
|
|
13211
13283
|
}
|
|
13212
13284
|
function draw(initial) {
|
|
@@ -13237,16 +13309,16 @@ async function hooksCommand(options) {
|
|
|
13237
13309
|
const wantEnabled = states[i];
|
|
13238
13310
|
if (wantEnabled && !wasInstalled) {
|
|
13239
13311
|
hook.install();
|
|
13240
|
-
console.log(
|
|
13312
|
+
console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
|
|
13241
13313
|
changed++;
|
|
13242
13314
|
} else if (!wantEnabled && wasInstalled) {
|
|
13243
13315
|
hook.remove();
|
|
13244
|
-
console.log(
|
|
13316
|
+
console.log(chalk20.green(" \u2713") + ` ${hook.label} disabled`);
|
|
13245
13317
|
changed++;
|
|
13246
13318
|
}
|
|
13247
13319
|
}
|
|
13248
13320
|
if (changed === 0) {
|
|
13249
|
-
console.log(
|
|
13321
|
+
console.log(chalk20.dim(" No changes."));
|
|
13250
13322
|
}
|
|
13251
13323
|
console.log("");
|
|
13252
13324
|
}
|
|
@@ -13282,7 +13354,7 @@ async function hooksCommand(options) {
|
|
|
13282
13354
|
case "\x1B":
|
|
13283
13355
|
case "":
|
|
13284
13356
|
cleanup();
|
|
13285
|
-
console.log(
|
|
13357
|
+
console.log(chalk20.dim("\n Cancelled.\n"));
|
|
13286
13358
|
resolve3();
|
|
13287
13359
|
break;
|
|
13288
13360
|
}
|
|
@@ -13293,52 +13365,52 @@ async function hooksCommand(options) {
|
|
|
13293
13365
|
|
|
13294
13366
|
// src/commands/config.ts
|
|
13295
13367
|
init_config();
|
|
13296
|
-
import
|
|
13368
|
+
import chalk21 from "chalk";
|
|
13297
13369
|
async function configCommand() {
|
|
13298
13370
|
const existing = loadConfig();
|
|
13299
13371
|
if (existing) {
|
|
13300
13372
|
const displayModel = getDisplayModel(existing);
|
|
13301
13373
|
const fastModel = getFastModel();
|
|
13302
|
-
console.log(
|
|
13303
|
-
console.log(` Provider: ${
|
|
13304
|
-
console.log(` Model: ${
|
|
13374
|
+
console.log(chalk21.bold("\nCurrent Configuration\n"));
|
|
13375
|
+
console.log(` Provider: ${chalk21.cyan(existing.provider)}`);
|
|
13376
|
+
console.log(` Model: ${chalk21.cyan(displayModel)}`);
|
|
13305
13377
|
if (fastModel) {
|
|
13306
|
-
console.log(` Scan: ${
|
|
13378
|
+
console.log(` Scan: ${chalk21.cyan(fastModel)}`);
|
|
13307
13379
|
}
|
|
13308
13380
|
if (existing.apiKey) {
|
|
13309
13381
|
const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
|
|
13310
|
-
console.log(` API Key: ${
|
|
13382
|
+
console.log(` API Key: ${chalk21.dim(masked)}`);
|
|
13311
13383
|
}
|
|
13312
13384
|
if (existing.provider === "cursor") {
|
|
13313
|
-
console.log(` Seat: ${
|
|
13385
|
+
console.log(` Seat: ${chalk21.dim("Cursor (agent acp)")}`);
|
|
13314
13386
|
}
|
|
13315
13387
|
if (existing.provider === "claude-cli") {
|
|
13316
|
-
console.log(` Seat: ${
|
|
13388
|
+
console.log(` Seat: ${chalk21.dim("Claude Code (claude -p)")}`);
|
|
13317
13389
|
}
|
|
13318
13390
|
if (existing.baseUrl) {
|
|
13319
|
-
console.log(` Base URL: ${
|
|
13391
|
+
console.log(` Base URL: ${chalk21.dim(existing.baseUrl)}`);
|
|
13320
13392
|
}
|
|
13321
13393
|
if (existing.vertexProjectId) {
|
|
13322
|
-
console.log(` Vertex Project: ${
|
|
13323
|
-
console.log(` Vertex Region: ${
|
|
13394
|
+
console.log(` Vertex Project: ${chalk21.dim(existing.vertexProjectId)}`);
|
|
13395
|
+
console.log(` Vertex Region: ${chalk21.dim(existing.vertexRegion || "us-east5")}`);
|
|
13324
13396
|
}
|
|
13325
|
-
console.log(` Source: ${
|
|
13397
|
+
console.log(` Source: ${chalk21.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
|
|
13326
13398
|
console.log("");
|
|
13327
13399
|
}
|
|
13328
13400
|
await runInteractiveProviderSetup();
|
|
13329
13401
|
const updated = loadConfig();
|
|
13330
13402
|
if (updated) trackConfigProviderSet(updated.provider);
|
|
13331
|
-
console.log(
|
|
13332
|
-
console.log(
|
|
13403
|
+
console.log(chalk21.green("\n\u2713 Configuration saved"));
|
|
13404
|
+
console.log(chalk21.dim(` ${getConfigFilePath()}
|
|
13333
13405
|
`));
|
|
13334
|
-
console.log(
|
|
13335
|
-
console.log(
|
|
13406
|
+
console.log(chalk21.dim(" You can also set environment variables instead:"));
|
|
13407
|
+
console.log(chalk21.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
|
|
13336
13408
|
}
|
|
13337
13409
|
|
|
13338
13410
|
// src/commands/learn.ts
|
|
13339
|
-
import
|
|
13340
|
-
import
|
|
13341
|
-
import
|
|
13411
|
+
import fs48 from "fs";
|
|
13412
|
+
import path39 from "path";
|
|
13413
|
+
import chalk23 from "chalk";
|
|
13342
13414
|
|
|
13343
13415
|
// src/learner/stdin.ts
|
|
13344
13416
|
var STDIN_TIMEOUT_MS = 5e3;
|
|
@@ -13368,8 +13440,8 @@ function readStdin() {
|
|
|
13368
13440
|
}
|
|
13369
13441
|
|
|
13370
13442
|
// src/learner/storage.ts
|
|
13371
|
-
import
|
|
13372
|
-
import
|
|
13443
|
+
import fs45 from "fs";
|
|
13444
|
+
import path36 from "path";
|
|
13373
13445
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
13374
13446
|
var MAX_PROMPT_LENGTH = 2e3;
|
|
13375
13447
|
var MAX_SESSION_FILE_BYTES = 10 * 1024 * 1024;
|
|
@@ -13380,15 +13452,15 @@ var DEFAULT_STATE = {
|
|
|
13380
13452
|
lastAnalysisEventCount: 0
|
|
13381
13453
|
};
|
|
13382
13454
|
function ensureLearningDir() {
|
|
13383
|
-
if (!
|
|
13384
|
-
|
|
13455
|
+
if (!fs45.existsSync(getLearningDir())) {
|
|
13456
|
+
fs45.mkdirSync(getLearningDir(), { recursive: true });
|
|
13385
13457
|
}
|
|
13386
13458
|
}
|
|
13387
13459
|
function sessionFilePath() {
|
|
13388
|
-
return
|
|
13460
|
+
return path36.join(getLearningDir(), LEARNING_SESSION_FILE);
|
|
13389
13461
|
}
|
|
13390
13462
|
function stateFilePath() {
|
|
13391
|
-
return
|
|
13463
|
+
return path36.join(getLearningDir(), LEARNING_STATE_FILE);
|
|
13392
13464
|
}
|
|
13393
13465
|
function truncateResponse(response) {
|
|
13394
13466
|
const str = JSON.stringify(response);
|
|
@@ -13397,9 +13469,9 @@ function truncateResponse(response) {
|
|
|
13397
13469
|
}
|
|
13398
13470
|
function trimSessionFileIfNeeded(filePath) {
|
|
13399
13471
|
try {
|
|
13400
|
-
const stat =
|
|
13472
|
+
const stat = fs45.statSync(filePath);
|
|
13401
13473
|
if (stat.size > MAX_SESSION_FILE_BYTES) {
|
|
13402
|
-
|
|
13474
|
+
fs45.writeFileSync(filePath, "");
|
|
13403
13475
|
resetState();
|
|
13404
13476
|
return;
|
|
13405
13477
|
}
|
|
@@ -13408,10 +13480,10 @@ function trimSessionFileIfNeeded(filePath) {
|
|
|
13408
13480
|
}
|
|
13409
13481
|
const state = readState2();
|
|
13410
13482
|
if (state.eventCount + 1 > LEARNING_MAX_EVENTS) {
|
|
13411
|
-
const lines =
|
|
13483
|
+
const lines = fs45.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
13412
13484
|
if (lines.length > LEARNING_MAX_EVENTS) {
|
|
13413
13485
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
13414
|
-
|
|
13486
|
+
fs45.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
13415
13487
|
}
|
|
13416
13488
|
}
|
|
13417
13489
|
}
|
|
@@ -13419,7 +13491,7 @@ function appendEvent(event) {
|
|
|
13419
13491
|
ensureLearningDir();
|
|
13420
13492
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
13421
13493
|
const filePath = sessionFilePath();
|
|
13422
|
-
|
|
13494
|
+
fs45.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
13423
13495
|
trimSessionFileIfNeeded(filePath);
|
|
13424
13496
|
}
|
|
13425
13497
|
function appendPromptEvent(event) {
|
|
@@ -13429,22 +13501,22 @@ function appendPromptEvent(event) {
|
|
|
13429
13501
|
prompt_content: event.prompt_content.length > MAX_PROMPT_LENGTH ? event.prompt_content.slice(0, MAX_PROMPT_LENGTH) : event.prompt_content
|
|
13430
13502
|
};
|
|
13431
13503
|
const filePath = sessionFilePath();
|
|
13432
|
-
|
|
13504
|
+
fs45.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
13433
13505
|
trimSessionFileIfNeeded(filePath);
|
|
13434
13506
|
}
|
|
13435
13507
|
function readAllEvents() {
|
|
13436
13508
|
const filePath = sessionFilePath();
|
|
13437
13509
|
try {
|
|
13438
|
-
const stat =
|
|
13510
|
+
const stat = fs45.statSync(filePath);
|
|
13439
13511
|
if (stat.size > MAX_SESSION_FILE_BYTES) {
|
|
13440
|
-
|
|
13512
|
+
fs45.writeFileSync(filePath, "");
|
|
13441
13513
|
resetState();
|
|
13442
13514
|
return [];
|
|
13443
13515
|
}
|
|
13444
13516
|
} catch {
|
|
13445
13517
|
return [];
|
|
13446
13518
|
}
|
|
13447
|
-
const lines =
|
|
13519
|
+
const lines = fs45.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
13448
13520
|
const events = [];
|
|
13449
13521
|
for (const line of lines) {
|
|
13450
13522
|
try {
|
|
@@ -13457,33 +13529,33 @@ function readAllEvents() {
|
|
|
13457
13529
|
function getEventCount() {
|
|
13458
13530
|
const filePath = sessionFilePath();
|
|
13459
13531
|
try {
|
|
13460
|
-
const stat =
|
|
13532
|
+
const stat = fs45.statSync(filePath);
|
|
13461
13533
|
if (stat.size > MAX_SESSION_FILE_BYTES) return 0;
|
|
13462
13534
|
} catch {
|
|
13463
13535
|
return 0;
|
|
13464
13536
|
}
|
|
13465
|
-
const content =
|
|
13537
|
+
const content = fs45.readFileSync(filePath, "utf-8");
|
|
13466
13538
|
return content.split("\n").filter(Boolean).length;
|
|
13467
13539
|
}
|
|
13468
13540
|
function clearSession() {
|
|
13469
13541
|
const filePath = sessionFilePath();
|
|
13470
13542
|
try {
|
|
13471
|
-
|
|
13543
|
+
fs45.writeFileSync(filePath, "");
|
|
13472
13544
|
} catch {
|
|
13473
13545
|
}
|
|
13474
13546
|
}
|
|
13475
13547
|
function readState2() {
|
|
13476
13548
|
const filePath = stateFilePath();
|
|
13477
|
-
if (!
|
|
13549
|
+
if (!fs45.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
13478
13550
|
try {
|
|
13479
|
-
return JSON.parse(
|
|
13551
|
+
return JSON.parse(fs45.readFileSync(filePath, "utf-8"));
|
|
13480
13552
|
} catch {
|
|
13481
13553
|
return { ...DEFAULT_STATE };
|
|
13482
13554
|
}
|
|
13483
13555
|
}
|
|
13484
13556
|
function writeState2(state) {
|
|
13485
13557
|
ensureLearningDir();
|
|
13486
|
-
|
|
13558
|
+
fs45.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
13487
13559
|
}
|
|
13488
13560
|
function resetState() {
|
|
13489
13561
|
writeState2({ ...DEFAULT_STATE });
|
|
@@ -13491,16 +13563,16 @@ function resetState() {
|
|
|
13491
13563
|
var LOCK_FILE = "finalize.lock";
|
|
13492
13564
|
var LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
13493
13565
|
function lockFilePath() {
|
|
13494
|
-
return
|
|
13566
|
+
return path36.join(getLearningDir(), LOCK_FILE);
|
|
13495
13567
|
}
|
|
13496
13568
|
function acquireFinalizeLock() {
|
|
13497
13569
|
ensureLearningDir();
|
|
13498
13570
|
const lockPath = lockFilePath();
|
|
13499
|
-
if (
|
|
13571
|
+
if (fs45.existsSync(lockPath)) {
|
|
13500
13572
|
try {
|
|
13501
|
-
const stat =
|
|
13573
|
+
const stat = fs45.statSync(lockPath);
|
|
13502
13574
|
if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
|
|
13503
|
-
const pid = parseInt(
|
|
13575
|
+
const pid = parseInt(fs45.readFileSync(lockPath, "utf-8").trim(), 10);
|
|
13504
13576
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
13505
13577
|
return false;
|
|
13506
13578
|
}
|
|
@@ -13508,12 +13580,12 @@ function acquireFinalizeLock() {
|
|
|
13508
13580
|
} catch {
|
|
13509
13581
|
}
|
|
13510
13582
|
try {
|
|
13511
|
-
|
|
13583
|
+
fs45.unlinkSync(lockPath);
|
|
13512
13584
|
} catch {
|
|
13513
13585
|
}
|
|
13514
13586
|
}
|
|
13515
13587
|
try {
|
|
13516
|
-
|
|
13588
|
+
fs45.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
13517
13589
|
return true;
|
|
13518
13590
|
} catch {
|
|
13519
13591
|
return false;
|
|
@@ -13530,46 +13602,46 @@ function isProcessAlive(pid) {
|
|
|
13530
13602
|
function releaseFinalizeLock() {
|
|
13531
13603
|
const lockPath = lockFilePath();
|
|
13532
13604
|
try {
|
|
13533
|
-
if (
|
|
13605
|
+
if (fs45.existsSync(lockPath)) fs45.unlinkSync(lockPath);
|
|
13534
13606
|
} catch {
|
|
13535
13607
|
}
|
|
13536
13608
|
}
|
|
13537
13609
|
|
|
13538
13610
|
// src/lib/notifications.ts
|
|
13539
|
-
import
|
|
13540
|
-
import
|
|
13541
|
-
import
|
|
13611
|
+
import fs46 from "fs";
|
|
13612
|
+
import path37 from "path";
|
|
13613
|
+
import chalk22 from "chalk";
|
|
13542
13614
|
function notificationFilePath() {
|
|
13543
|
-
return
|
|
13615
|
+
return path37.join(getLearningDir(), "last-finalize-summary.json");
|
|
13544
13616
|
}
|
|
13545
13617
|
function writeFinalizeSummary(summary) {
|
|
13546
13618
|
try {
|
|
13547
13619
|
ensureLearningDir();
|
|
13548
|
-
|
|
13620
|
+
fs46.writeFileSync(notificationFilePath(), JSON.stringify(summary, null, 2));
|
|
13549
13621
|
} catch {
|
|
13550
13622
|
}
|
|
13551
13623
|
}
|
|
13552
13624
|
function checkPendingNotifications() {
|
|
13553
13625
|
try {
|
|
13554
|
-
if (!
|
|
13555
|
-
const raw =
|
|
13556
|
-
|
|
13626
|
+
if (!fs46.existsSync(notificationFilePath())) return;
|
|
13627
|
+
const raw = fs46.readFileSync(notificationFilePath(), "utf-8");
|
|
13628
|
+
fs46.unlinkSync(notificationFilePath());
|
|
13557
13629
|
const summary = JSON.parse(raw);
|
|
13558
13630
|
if (!summary.newItemCount || summary.newItemCount === 0) return;
|
|
13559
13631
|
const wasteLabel = summary.wasteTokens > 0 ? ` (~${summary.wasteTokens.toLocaleString()} wasted tokens captured)` : "";
|
|
13560
13632
|
console.log(
|
|
13561
|
-
|
|
13633
|
+
chalk22.dim(`caliber: learned ${summary.newItemCount} new pattern${summary.newItemCount === 1 ? "" : "s"} from your last session${wasteLabel}`)
|
|
13562
13634
|
);
|
|
13563
13635
|
for (const item of summary.newItems.slice(0, 3)) {
|
|
13564
|
-
console.log(
|
|
13636
|
+
console.log(chalk22.dim(` + ${item.replace(/^- /, "").slice(0, 80)}`));
|
|
13565
13637
|
}
|
|
13566
13638
|
if (summary.newItems.length > 3) {
|
|
13567
|
-
console.log(
|
|
13639
|
+
console.log(chalk22.dim(` ... and ${summary.newItems.length - 3} more`));
|
|
13568
13640
|
}
|
|
13569
13641
|
console.log("");
|
|
13570
13642
|
} catch {
|
|
13571
13643
|
try {
|
|
13572
|
-
|
|
13644
|
+
fs46.unlinkSync(notificationFilePath());
|
|
13573
13645
|
} catch {
|
|
13574
13646
|
}
|
|
13575
13647
|
}
|
|
@@ -13721,8 +13793,8 @@ function calculateSessionWaste(events) {
|
|
|
13721
13793
|
init_config();
|
|
13722
13794
|
|
|
13723
13795
|
// src/learner/roi.ts
|
|
13724
|
-
import
|
|
13725
|
-
import
|
|
13796
|
+
import fs47 from "fs";
|
|
13797
|
+
import path38 from "path";
|
|
13726
13798
|
var DEFAULT_TOTALS = {
|
|
13727
13799
|
totalWasteTokens: 0,
|
|
13728
13800
|
totalWasteSeconds: 0,
|
|
@@ -13736,19 +13808,19 @@ var DEFAULT_TOTALS = {
|
|
|
13736
13808
|
lastSessionTimestamp: ""
|
|
13737
13809
|
};
|
|
13738
13810
|
function roiFilePath() {
|
|
13739
|
-
return
|
|
13811
|
+
return path38.join(getLearningDir(), LEARNING_ROI_FILE);
|
|
13740
13812
|
}
|
|
13741
13813
|
function readROIStats() {
|
|
13742
13814
|
const filePath = roiFilePath();
|
|
13743
|
-
if (!
|
|
13815
|
+
if (!fs47.existsSync(filePath)) {
|
|
13744
13816
|
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
13745
13817
|
}
|
|
13746
13818
|
try {
|
|
13747
|
-
return JSON.parse(
|
|
13819
|
+
return JSON.parse(fs47.readFileSync(filePath, "utf-8"));
|
|
13748
13820
|
} catch {
|
|
13749
13821
|
try {
|
|
13750
13822
|
const corruptPath = filePath + ".corrupt";
|
|
13751
|
-
|
|
13823
|
+
fs47.renameSync(filePath, corruptPath);
|
|
13752
13824
|
console.error(`caliber: roi-stats.json was corrupt \u2014 renamed to ${corruptPath}`);
|
|
13753
13825
|
} catch {
|
|
13754
13826
|
}
|
|
@@ -13757,7 +13829,7 @@ function readROIStats() {
|
|
|
13757
13829
|
}
|
|
13758
13830
|
function writeROIStats(stats) {
|
|
13759
13831
|
ensureLearningDir();
|
|
13760
|
-
|
|
13832
|
+
fs47.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
|
|
13761
13833
|
}
|
|
13762
13834
|
function recalculateTotals(stats) {
|
|
13763
13835
|
const totals = stats.totals;
|
|
@@ -13966,9 +14038,9 @@ var AUTO_SETTLE_MS = 200;
|
|
|
13966
14038
|
var INCREMENTAL_INTERVAL = 50;
|
|
13967
14039
|
function writeFinalizeError(message) {
|
|
13968
14040
|
try {
|
|
13969
|
-
const errorPath =
|
|
13970
|
-
if (!
|
|
13971
|
-
|
|
14041
|
+
const errorPath = path39.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
|
|
14042
|
+
if (!fs48.existsSync(getLearningDir())) fs48.mkdirSync(getLearningDir(), { recursive: true });
|
|
14043
|
+
fs48.writeFileSync(
|
|
13972
14044
|
errorPath,
|
|
13973
14045
|
JSON.stringify(
|
|
13974
14046
|
{
|
|
@@ -13985,9 +14057,9 @@ function writeFinalizeError(message) {
|
|
|
13985
14057
|
}
|
|
13986
14058
|
function readFinalizeError() {
|
|
13987
14059
|
try {
|
|
13988
|
-
const errorPath =
|
|
13989
|
-
if (!
|
|
13990
|
-
return JSON.parse(
|
|
14060
|
+
const errorPath = path39.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
|
|
14061
|
+
if (!fs48.existsSync(errorPath)) return null;
|
|
14062
|
+
return JSON.parse(fs48.readFileSync(errorPath, "utf-8"));
|
|
13991
14063
|
} catch {
|
|
13992
14064
|
return null;
|
|
13993
14065
|
}
|
|
@@ -14039,9 +14111,9 @@ async function learnObserveCommand(options) {
|
|
|
14039
14111
|
const { resolveCaliber: resolveCaliber2, isNpxResolution: isNpxResolution2 } = await Promise.resolve().then(() => (init_resolve_caliber(), resolve_caliber_exports));
|
|
14040
14112
|
const bin = resolveCaliber2();
|
|
14041
14113
|
const { spawn: spawn5 } = await import("child_process");
|
|
14042
|
-
const logPath =
|
|
14043
|
-
if (!
|
|
14044
|
-
const logFd =
|
|
14114
|
+
const logPath = path39.join(getLearningDir(), LEARNING_FINALIZE_LOG);
|
|
14115
|
+
if (!fs48.existsSync(getLearningDir())) fs48.mkdirSync(getLearningDir(), { recursive: true });
|
|
14116
|
+
const logFd = fs48.openSync(logPath, "a");
|
|
14045
14117
|
const NPX_SUFFIX = " --yes @rely-ai/caliber";
|
|
14046
14118
|
const [exe, binArgs] = isNpxResolution2() ? [bin.slice(0, -NPX_SUFFIX.length) || "npx", ["--yes", "@rely-ai/caliber"]] : [bin, []];
|
|
14047
14119
|
const isWin = process.platform === "win32";
|
|
@@ -14064,7 +14136,7 @@ async function learnObserveCommand(options) {
|
|
|
14064
14136
|
}
|
|
14065
14137
|
});
|
|
14066
14138
|
child.unref();
|
|
14067
|
-
|
|
14139
|
+
fs48.closeSync(logFd);
|
|
14068
14140
|
} catch {
|
|
14069
14141
|
}
|
|
14070
14142
|
}
|
|
@@ -14079,7 +14151,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14079
14151
|
const { isCaliberRunning: isCaliberRunning2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
|
|
14080
14152
|
if (isCaliberRunning2()) {
|
|
14081
14153
|
if (!isAuto)
|
|
14082
|
-
console.log(
|
|
14154
|
+
console.log(chalk23.dim("caliber: skipping finalize \u2014 another caliber process is running"));
|
|
14083
14155
|
return;
|
|
14084
14156
|
}
|
|
14085
14157
|
}
|
|
@@ -14088,7 +14160,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14088
14160
|
}
|
|
14089
14161
|
if (!acquireFinalizeLock()) {
|
|
14090
14162
|
if (!isAuto)
|
|
14091
|
-
console.log(
|
|
14163
|
+
console.log(chalk23.dim("caliber: skipping finalize \u2014 another finalize is in progress"));
|
|
14092
14164
|
return;
|
|
14093
14165
|
}
|
|
14094
14166
|
let analyzed = false;
|
|
@@ -14097,7 +14169,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14097
14169
|
if (!config) {
|
|
14098
14170
|
if (isAuto) return;
|
|
14099
14171
|
console.log(
|
|
14100
|
-
|
|
14172
|
+
chalk23.yellow(
|
|
14101
14173
|
`caliber: no LLM provider configured \u2014 run \`${resolveCaliber()} config\` first`
|
|
14102
14174
|
)
|
|
14103
14175
|
);
|
|
@@ -14110,7 +14182,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14110
14182
|
if (allEvents.length < threshold) {
|
|
14111
14183
|
if (!isAuto)
|
|
14112
14184
|
console.log(
|
|
14113
|
-
|
|
14185
|
+
chalk23.dim(
|
|
14114
14186
|
`caliber: ${allEvents.length}/${threshold} events recorded \u2014 need more before analysis`
|
|
14115
14187
|
)
|
|
14116
14188
|
);
|
|
@@ -14124,7 +14196,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14124
14196
|
if (events.length < threshold) {
|
|
14125
14197
|
if (!isAuto)
|
|
14126
14198
|
console.log(
|
|
14127
|
-
|
|
14199
|
+
chalk23.dim(
|
|
14128
14200
|
`caliber: ${events.length}/${threshold} new events since last analysis \u2014 need more`
|
|
14129
14201
|
)
|
|
14130
14202
|
);
|
|
@@ -14164,12 +14236,12 @@ async function learnFinalizeCommand(options) {
|
|
|
14164
14236
|
} else {
|
|
14165
14237
|
const wasteLabel = waste.totalWasteTokens > 0 ? ` (~${waste.totalWasteTokens.toLocaleString()} wasted tokens captured)` : "";
|
|
14166
14238
|
console.log(
|
|
14167
|
-
|
|
14239
|
+
chalk23.dim(
|
|
14168
14240
|
`caliber: learned ${result.newItemCount} new pattern${result.newItemCount === 1 ? "" : "s"}${wasteLabel}`
|
|
14169
14241
|
)
|
|
14170
14242
|
);
|
|
14171
14243
|
for (const item of result.newItems) {
|
|
14172
|
-
console.log(
|
|
14244
|
+
console.log(chalk23.dim(` + ${item.replace(/^- /, "").slice(0, 80)}`));
|
|
14173
14245
|
}
|
|
14174
14246
|
}
|
|
14175
14247
|
const wastePerLearning = Math.round(waste.totalWasteTokens / result.newItemCount);
|
|
@@ -14263,7 +14335,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14263
14335
|
const staleLearnings = findStaleLearnings(roiStats);
|
|
14264
14336
|
if (staleLearnings.length > 0 && !isAuto) {
|
|
14265
14337
|
console.log(
|
|
14266
|
-
|
|
14338
|
+
chalk23.yellow(
|
|
14267
14339
|
`caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`${resolveCaliber()} learn list --verbose\` to review`
|
|
14268
14340
|
)
|
|
14269
14341
|
);
|
|
@@ -14272,7 +14344,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14272
14344
|
if (!isAuto && t.estimatedSavingsTokens > 0) {
|
|
14273
14345
|
const totalLearnings = existingLearnedItems + newLearningsProduced;
|
|
14274
14346
|
console.log(
|
|
14275
|
-
|
|
14347
|
+
chalk23.dim(
|
|
14276
14348
|
`caliber: ${totalLearnings} learnings active \u2014 est. ~${t.estimatedSavingsTokens.toLocaleString()} tokens saved across ${t.totalSessionsWithLearnings} sessions`
|
|
14277
14349
|
)
|
|
14278
14350
|
);
|
|
@@ -14280,7 +14352,7 @@ async function learnFinalizeCommand(options) {
|
|
|
14280
14352
|
} catch (err) {
|
|
14281
14353
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
14282
14354
|
if (options?.force && !isAuto) {
|
|
14283
|
-
console.error(
|
|
14355
|
+
console.error(chalk23.red("caliber: finalize failed \u2014"), errorMsg);
|
|
14284
14356
|
}
|
|
14285
14357
|
writeFinalizeError(errorMsg);
|
|
14286
14358
|
} finally {
|
|
@@ -14300,54 +14372,54 @@ async function learnFinalizeCommand(options) {
|
|
|
14300
14372
|
}
|
|
14301
14373
|
async function learnInstallCommand() {
|
|
14302
14374
|
let anyInstalled = false;
|
|
14303
|
-
if (
|
|
14375
|
+
if (fs48.existsSync(".claude")) {
|
|
14304
14376
|
const r = installLearningHooks();
|
|
14305
14377
|
if (r.installed) {
|
|
14306
|
-
console.log(
|
|
14378
|
+
console.log(chalk23.green("\u2713") + " Claude Code learning hooks installed");
|
|
14307
14379
|
anyInstalled = true;
|
|
14308
14380
|
} else if (r.alreadyInstalled) {
|
|
14309
|
-
console.log(
|
|
14381
|
+
console.log(chalk23.dim(" Claude Code hooks already installed"));
|
|
14310
14382
|
}
|
|
14311
14383
|
}
|
|
14312
|
-
if (
|
|
14384
|
+
if (fs48.existsSync(".cursor")) {
|
|
14313
14385
|
const r = installCursorLearningHooks();
|
|
14314
14386
|
if (r.installed) {
|
|
14315
|
-
console.log(
|
|
14387
|
+
console.log(chalk23.green("\u2713") + " Cursor learning hooks installed");
|
|
14316
14388
|
anyInstalled = true;
|
|
14317
14389
|
} else if (r.alreadyInstalled) {
|
|
14318
|
-
console.log(
|
|
14390
|
+
console.log(chalk23.dim(" Cursor hooks already installed"));
|
|
14319
14391
|
}
|
|
14320
14392
|
}
|
|
14321
|
-
if (!
|
|
14322
|
-
console.log(
|
|
14393
|
+
if (!fs48.existsSync(".claude") && !fs48.existsSync(".cursor")) {
|
|
14394
|
+
console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
|
|
14323
14395
|
console.log(
|
|
14324
|
-
|
|
14396
|
+
chalk23.dim(` Run \`${resolveCaliber()} init\` first, or create the directory manually.`)
|
|
14325
14397
|
);
|
|
14326
14398
|
return;
|
|
14327
14399
|
}
|
|
14328
14400
|
if (anyInstalled) {
|
|
14329
14401
|
console.log(
|
|
14330
|
-
|
|
14402
|
+
chalk23.dim(
|
|
14331
14403
|
` Tool usage will be recorded and learnings extracted after \u2265${MIN_EVENTS_FOR_ANALYSIS} events.`
|
|
14332
14404
|
)
|
|
14333
14405
|
);
|
|
14334
|
-
console.log(
|
|
14406
|
+
console.log(chalk23.dim(" Learnings written to CALIBER_LEARNINGS.md."));
|
|
14335
14407
|
}
|
|
14336
14408
|
}
|
|
14337
14409
|
async function learnRemoveCommand() {
|
|
14338
14410
|
let anyRemoved = false;
|
|
14339
14411
|
const r1 = removeLearningHooks();
|
|
14340
14412
|
if (r1.removed) {
|
|
14341
|
-
console.log(
|
|
14413
|
+
console.log(chalk23.green("\u2713") + " Claude Code learning hooks removed");
|
|
14342
14414
|
anyRemoved = true;
|
|
14343
14415
|
}
|
|
14344
14416
|
const r2 = removeCursorLearningHooks();
|
|
14345
14417
|
if (r2.removed) {
|
|
14346
|
-
console.log(
|
|
14418
|
+
console.log(chalk23.green("\u2713") + " Cursor learning hooks removed");
|
|
14347
14419
|
anyRemoved = true;
|
|
14348
14420
|
}
|
|
14349
14421
|
if (!anyRemoved) {
|
|
14350
|
-
console.log(
|
|
14422
|
+
console.log(chalk23.dim("No learning hooks found."));
|
|
14351
14423
|
}
|
|
14352
14424
|
}
|
|
14353
14425
|
async function learnStatusCommand() {
|
|
@@ -14355,51 +14427,51 @@ async function learnStatusCommand() {
|
|
|
14355
14427
|
const cursorInstalled = areCursorLearningHooksInstalled();
|
|
14356
14428
|
const state = readState2();
|
|
14357
14429
|
const eventCount = getEventCount();
|
|
14358
|
-
console.log(
|
|
14430
|
+
console.log(chalk23.bold("Session Learning Status"));
|
|
14359
14431
|
console.log();
|
|
14360
14432
|
if (claudeInstalled) {
|
|
14361
|
-
console.log(
|
|
14433
|
+
console.log(chalk23.green("\u2713") + " Claude Code hooks " + chalk23.green("installed"));
|
|
14362
14434
|
} else {
|
|
14363
|
-
console.log(
|
|
14435
|
+
console.log(chalk23.dim("\u2717") + " Claude Code hooks " + chalk23.dim("not installed"));
|
|
14364
14436
|
}
|
|
14365
14437
|
if (cursorInstalled) {
|
|
14366
|
-
console.log(
|
|
14438
|
+
console.log(chalk23.green("\u2713") + " Cursor hooks " + chalk23.green("installed"));
|
|
14367
14439
|
} else {
|
|
14368
|
-
console.log(
|
|
14440
|
+
console.log(chalk23.dim("\u2717") + " Cursor hooks " + chalk23.dim("not installed"));
|
|
14369
14441
|
}
|
|
14370
14442
|
if (!claudeInstalled && !cursorInstalled) {
|
|
14371
14443
|
console.log(
|
|
14372
|
-
|
|
14444
|
+
chalk23.dim(` Run \`${resolveCaliber()} learn install\` to enable session learning.`)
|
|
14373
14445
|
);
|
|
14374
14446
|
}
|
|
14375
14447
|
console.log();
|
|
14376
|
-
console.log(`Events recorded: ${
|
|
14377
|
-
console.log(`Threshold for analysis: ${
|
|
14448
|
+
console.log(`Events recorded: ${chalk23.cyan(String(eventCount))}`);
|
|
14449
|
+
console.log(`Threshold for analysis: ${chalk23.cyan(String(MIN_EVENTS_FOR_ANALYSIS))}`);
|
|
14378
14450
|
if (state.lastAnalysisTimestamp) {
|
|
14379
|
-
console.log(`Last analysis: ${
|
|
14451
|
+
console.log(`Last analysis: ${chalk23.cyan(state.lastAnalysisTimestamp)}`);
|
|
14380
14452
|
} else {
|
|
14381
|
-
console.log(`Last analysis: ${
|
|
14453
|
+
console.log(`Last analysis: ${chalk23.dim("none")}`);
|
|
14382
14454
|
}
|
|
14383
14455
|
const lastError = readFinalizeError();
|
|
14384
14456
|
if (lastError) {
|
|
14385
|
-
console.log(`Last error: ${
|
|
14386
|
-
console.log(
|
|
14387
|
-
const logPath =
|
|
14388
|
-
if (
|
|
14389
|
-
console.log(
|
|
14457
|
+
console.log(`Last error: ${chalk23.red(lastError.error)}`);
|
|
14458
|
+
console.log(chalk23.dim(` at ${lastError.timestamp}`));
|
|
14459
|
+
const logPath = path39.join(getLearningDir(), LEARNING_FINALIZE_LOG);
|
|
14460
|
+
if (fs48.existsSync(logPath)) {
|
|
14461
|
+
console.log(chalk23.dim(` Full log: ${logPath}`));
|
|
14390
14462
|
}
|
|
14391
14463
|
}
|
|
14392
14464
|
const learnedSection = readLearnedSection();
|
|
14393
14465
|
if (learnedSection) {
|
|
14394
14466
|
const lineCount = learnedSection.split("\n").filter(Boolean).length;
|
|
14395
14467
|
console.log(`
|
|
14396
|
-
Learned items in CALIBER_LEARNINGS.md: ${
|
|
14468
|
+
Learned items in CALIBER_LEARNINGS.md: ${chalk23.cyan(String(lineCount))}`);
|
|
14397
14469
|
}
|
|
14398
14470
|
const roiStats = readROIStats();
|
|
14399
14471
|
const roiSummary = formatROISummary(roiStats);
|
|
14400
14472
|
if (roiSummary) {
|
|
14401
14473
|
console.log();
|
|
14402
|
-
console.log(
|
|
14474
|
+
console.log(chalk23.bold(roiSummary.split("\n")[0]));
|
|
14403
14475
|
for (const line of roiSummary.split("\n").slice(1)) {
|
|
14404
14476
|
console.log(line);
|
|
14405
14477
|
}
|
|
@@ -14425,26 +14497,26 @@ function getAllLearnings() {
|
|
|
14425
14497
|
async function learnListCommand(options) {
|
|
14426
14498
|
const items = getAllLearnings();
|
|
14427
14499
|
if (items.length === 0) {
|
|
14428
|
-
console.log(
|
|
14500
|
+
console.log(chalk23.dim(`No learnings yet. Run \`${resolveCaliber()} learn install\` to start.`));
|
|
14429
14501
|
return;
|
|
14430
14502
|
}
|
|
14431
14503
|
const roiStats = options?.verbose ? readROIStats() : null;
|
|
14432
|
-
console.log(
|
|
14504
|
+
console.log(chalk23.bold(`
|
|
14433
14505
|
Learnings (${items.length})
|
|
14434
14506
|
`));
|
|
14435
14507
|
for (const item of items) {
|
|
14436
|
-
const tag = item.source === "personal" ?
|
|
14508
|
+
const tag = item.source === "personal" ? chalk23.magenta("[personal]") : chalk23.blue("[project]");
|
|
14437
14509
|
const display = item.text.replace(/^- /, "").slice(0, 100);
|
|
14438
|
-
console.log(` ${
|
|
14510
|
+
console.log(` ${chalk23.dim(String(item.index + 1).padStart(2, " "))}. ${tag} ${display}`);
|
|
14439
14511
|
if (options?.verbose && roiStats) {
|
|
14440
14512
|
const match = roiStats.learnings.find((l) => display.includes(l.summary.slice(0, 40)));
|
|
14441
14513
|
if (match) {
|
|
14442
14514
|
const activations = match.activationCount ?? 0;
|
|
14443
14515
|
const stale = activations === 0 && roiStats.sessions.length >= 10;
|
|
14444
|
-
const activationLabel = stale ?
|
|
14516
|
+
const activationLabel = stale ? chalk23.yellow(`${activations} activations [stale]`) : chalk23.dim(`${activations} activation${activations === 1 ? "" : "s"}`);
|
|
14445
14517
|
console.log(` ${activationLabel}`);
|
|
14446
14518
|
if (match.explanation) {
|
|
14447
|
-
console.log(` ${
|
|
14519
|
+
console.log(` ${chalk23.dim("Why: " + match.explanation.slice(0, 80))}`);
|
|
14448
14520
|
}
|
|
14449
14521
|
}
|
|
14450
14522
|
}
|
|
@@ -14455,7 +14527,7 @@ async function learnDeleteCommand(indexStr) {
|
|
|
14455
14527
|
const index = parseInt(indexStr, 10);
|
|
14456
14528
|
if (isNaN(index) || index < 1) {
|
|
14457
14529
|
console.log(
|
|
14458
|
-
|
|
14530
|
+
chalk23.red(
|
|
14459
14531
|
`Invalid index: "${indexStr}". Use a number from \`${resolveCaliber()} learn list\`.`
|
|
14460
14532
|
)
|
|
14461
14533
|
);
|
|
@@ -14464,16 +14536,16 @@ async function learnDeleteCommand(indexStr) {
|
|
|
14464
14536
|
const items = getAllLearnings();
|
|
14465
14537
|
const targetIdx = index - 1;
|
|
14466
14538
|
if (targetIdx >= items.length) {
|
|
14467
|
-
console.log(
|
|
14539
|
+
console.log(chalk23.red(`Index ${index} is out of range. You have ${items.length} learnings.`));
|
|
14468
14540
|
return;
|
|
14469
14541
|
}
|
|
14470
14542
|
const item = items[targetIdx];
|
|
14471
14543
|
const filePath = item.source === "personal" ? PERSONAL_LEARNINGS_FILE : "CALIBER_LEARNINGS.md";
|
|
14472
|
-
if (!
|
|
14473
|
-
console.log(
|
|
14544
|
+
if (!fs48.existsSync(filePath)) {
|
|
14545
|
+
console.log(chalk23.red("Learnings file not found."));
|
|
14474
14546
|
return;
|
|
14475
14547
|
}
|
|
14476
|
-
const content =
|
|
14548
|
+
const content = fs48.readFileSync(filePath, "utf-8");
|
|
14477
14549
|
const lines = content.split("\n");
|
|
14478
14550
|
const bulletsOfSource = items.filter((i) => i.source === item.source);
|
|
14479
14551
|
const posInFile = bulletsOfSource.indexOf(item);
|
|
@@ -14489,14 +14561,14 @@ async function learnDeleteCommand(indexStr) {
|
|
|
14489
14561
|
}
|
|
14490
14562
|
}
|
|
14491
14563
|
if (lineToRemove === -1) {
|
|
14492
|
-
console.log(
|
|
14564
|
+
console.log(chalk23.red("Could not locate learning in file."));
|
|
14493
14565
|
return;
|
|
14494
14566
|
}
|
|
14495
14567
|
const bulletToRemove = lines[lineToRemove];
|
|
14496
14568
|
const newLines = lines.filter((_, i) => i !== lineToRemove);
|
|
14497
|
-
|
|
14569
|
+
fs48.writeFileSync(filePath, newLines.join("\n"));
|
|
14498
14570
|
if (item.source === "personal") {
|
|
14499
|
-
|
|
14571
|
+
fs48.chmodSync(filePath, 384);
|
|
14500
14572
|
}
|
|
14501
14573
|
const roiStats = readROIStats();
|
|
14502
14574
|
const cleanText = bulletToRemove.replace(/^- /, "").replace(/^\*\*\[[^\]]+\]\*\*\s*/, "").trim();
|
|
@@ -14505,24 +14577,24 @@ async function learnDeleteCommand(indexStr) {
|
|
|
14505
14577
|
roiStats.learnings.splice(roiIdx, 1);
|
|
14506
14578
|
writeROIStats(roiStats);
|
|
14507
14579
|
}
|
|
14508
|
-
console.log(
|
|
14580
|
+
console.log(chalk23.green("\u2713") + ` Removed: ${bulletToRemove.replace(/^- /, "").slice(0, 80)}`);
|
|
14509
14581
|
}
|
|
14510
14582
|
async function learnAddCommand(content, options) {
|
|
14511
14583
|
if (!content.trim()) {
|
|
14512
|
-
console.log(
|
|
14584
|
+
console.log(chalk23.yellow("Please provide learning content."));
|
|
14513
14585
|
throw new Error("__exit__");
|
|
14514
14586
|
}
|
|
14515
14587
|
const scope = options.personal ? "personal" : "project";
|
|
14516
14588
|
const result = addLearning(content.trim(), scope);
|
|
14517
14589
|
if (result.added) {
|
|
14518
|
-
console.log(
|
|
14590
|
+
console.log(chalk23.green("\u2713") + ` Learning saved to ${result.file}`);
|
|
14519
14591
|
} else {
|
|
14520
|
-
console.log(
|
|
14592
|
+
console.log(chalk23.dim(" Similar learning already exists \u2014 skipped."));
|
|
14521
14593
|
}
|
|
14522
14594
|
}
|
|
14523
14595
|
|
|
14524
14596
|
// src/commands/insights.ts
|
|
14525
|
-
import
|
|
14597
|
+
import chalk24 from "chalk";
|
|
14526
14598
|
init_resolve_caliber();
|
|
14527
14599
|
var MIN_SESSIONS_FULL = 20;
|
|
14528
14600
|
function buildInsightsData(stats) {
|
|
@@ -14563,85 +14635,85 @@ function buildInsightsData(stats) {
|
|
|
14563
14635
|
};
|
|
14564
14636
|
}
|
|
14565
14637
|
function displayColdStart(score) {
|
|
14566
|
-
console.log(
|
|
14638
|
+
console.log(chalk24.bold("\n Agent Insights\n"));
|
|
14567
14639
|
const hooksInstalled = areLearningHooksInstalled() || areCursorLearningHooksInstalled();
|
|
14568
14640
|
if (!hooksInstalled) {
|
|
14569
|
-
console.log(
|
|
14570
|
-
console.log(
|
|
14571
|
-
console.log(
|
|
14572
|
-
console.log(
|
|
14641
|
+
console.log(chalk24.yellow(" Learning hooks not installed."));
|
|
14642
|
+
console.log(chalk24.dim(" Session learning captures patterns from your AI coding sessions \u2014 what"));
|
|
14643
|
+
console.log(chalk24.dim(" fails, what works, corrections you make \u2014 so your agents improve over time.\n"));
|
|
14644
|
+
console.log(chalk24.dim(" Run ") + chalk24.cyan(`${resolveCaliber()} learn install`) + chalk24.dim(" to enable."));
|
|
14573
14645
|
} else {
|
|
14574
|
-
console.log(
|
|
14575
|
-
console.log(
|
|
14576
|
-
console.log(
|
|
14646
|
+
console.log(chalk24.dim(" Learning hooks are active. Use your AI agent and insights"));
|
|
14647
|
+
console.log(chalk24.dim(" will appear automatically after each session.\n"));
|
|
14648
|
+
console.log(chalk24.dim(` Progress: 0/${MIN_SESSIONS_FULL} sessions \u2014 full insights unlock at ${MIN_SESSIONS_FULL}`));
|
|
14577
14649
|
}
|
|
14578
|
-
console.log(
|
|
14650
|
+
console.log(chalk24.dim(`
|
|
14579
14651
|
Config score: ${score.score}/100 (${score.grade})`));
|
|
14580
14652
|
console.log("");
|
|
14581
14653
|
}
|
|
14582
14654
|
function displayEarlyData(data, score) {
|
|
14583
|
-
console.log(
|
|
14655
|
+
console.log(chalk24.bold("\n Agent Insights") + chalk24.yellow(" (early data)\n"));
|
|
14584
14656
|
const remaining = MIN_SESSIONS_FULL - data.totalSessions;
|
|
14585
|
-
console.log(
|
|
14657
|
+
console.log(chalk24.dim(` ${data.totalSessions}/${MIN_SESSIONS_FULL} sessions tracked \u2014 ${remaining} more for full insights.
|
|
14586
14658
|
`));
|
|
14587
|
-
console.log(` Sessions tracked: ${
|
|
14588
|
-
console.log(` Learnings accumulated: ${
|
|
14659
|
+
console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
|
|
14660
|
+
console.log(` Learnings accumulated: ${chalk24.cyan(String(data.learningCount))}`);
|
|
14589
14661
|
if (data.totalWasteTokens > 0) {
|
|
14590
|
-
console.log(` Waste captured: ${
|
|
14662
|
+
console.log(` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`);
|
|
14591
14663
|
}
|
|
14592
14664
|
if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
|
|
14593
|
-
console.log(` Failure rate trend: ${
|
|
14665
|
+
console.log(` Failure rate trend: ${chalk24.green(`${data.failureRateImprovement}% fewer`)} failures with learnings ${chalk24.dim("(early signal)")}`);
|
|
14594
14666
|
} else if (data.totalSessions > 0 && data.failureRateImprovement === null) {
|
|
14595
|
-
console.log(` Failure rate trend: ${
|
|
14667
|
+
console.log(` Failure rate trend: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`);
|
|
14596
14668
|
}
|
|
14597
14669
|
if (data.taskSuccessRate !== null) {
|
|
14598
|
-
console.log(` Task success rate: ${
|
|
14670
|
+
console.log(` Task success rate: ${chalk24.cyan(`${data.taskSuccessRate}%`)} ${chalk24.dim(`(${data.taskCount} tasks)`)}`);
|
|
14599
14671
|
}
|
|
14600
|
-
console.log(` Config score: ${
|
|
14672
|
+
console.log(` Config score: ${chalk24.cyan(`${score.score}/100`)} (${score.grade})`);
|
|
14601
14673
|
console.log("");
|
|
14602
14674
|
}
|
|
14603
14675
|
function displayFullInsights(data, score) {
|
|
14604
|
-
console.log(
|
|
14605
|
-
console.log(
|
|
14676
|
+
console.log(chalk24.bold("\n Agent Insights\n"));
|
|
14677
|
+
console.log(chalk24.bold(" Agent Health"));
|
|
14606
14678
|
if (data.taskSuccessRate !== null) {
|
|
14607
|
-
const color = data.taskSuccessRate >= 80 ?
|
|
14679
|
+
const color = data.taskSuccessRate >= 80 ? chalk24.green : data.taskSuccessRate >= 60 ? chalk24.yellow : chalk24.red;
|
|
14608
14680
|
console.log(` Task success rate: ${color(`${data.taskSuccessRate}%`)} across ${data.taskCount} tasks`);
|
|
14609
14681
|
if (data.taskCorrectionCount > 0) {
|
|
14610
|
-
console.log(` Corrections needed: ${
|
|
14682
|
+
console.log(` Corrections needed: ${chalk24.yellow(String(data.taskCorrectionCount))} tasks required user correction`);
|
|
14611
14683
|
}
|
|
14612
14684
|
}
|
|
14613
|
-
console.log(` Sessions tracked: ${
|
|
14614
|
-
console.log(
|
|
14615
|
-
console.log(` Learnings active: ${
|
|
14685
|
+
console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
|
|
14686
|
+
console.log(chalk24.bold("\n Learning Impact"));
|
|
14687
|
+
console.log(` Learnings active: ${chalk24.cyan(String(data.learningCount))}`);
|
|
14616
14688
|
if (data.failureRateWith !== null && data.failureRateWithout !== null) {
|
|
14617
|
-
console.log(` Failure rate: ${
|
|
14689
|
+
console.log(` Failure rate: ${chalk24.red(data.failureRateWithout.toFixed(1))}/session ${chalk24.dim("\u2192")} ${chalk24.green(data.failureRateWith.toFixed(1))}/session with learnings`);
|
|
14618
14690
|
if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
|
|
14619
|
-
console.log(` Improvement: ${
|
|
14691
|
+
console.log(` Improvement: ${chalk24.green(`${data.failureRateImprovement}%`)} fewer failures`);
|
|
14620
14692
|
} else if (data.failureRateImprovement === null) {
|
|
14621
|
-
console.log(` Improvement: ${
|
|
14693
|
+
console.log(` Improvement: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`);
|
|
14622
14694
|
}
|
|
14623
14695
|
}
|
|
14624
14696
|
if (data.totalWasteTokens > 0 || data.estimatedSavingsTokens > 0) {
|
|
14625
|
-
console.log(
|
|
14697
|
+
console.log(chalk24.bold("\n Efficiency"));
|
|
14626
14698
|
if (data.totalWasteTokens > 0) {
|
|
14627
|
-
console.log(` Waste captured: ${
|
|
14699
|
+
console.log(` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`);
|
|
14628
14700
|
}
|
|
14629
14701
|
if (data.estimatedSavingsTokens > 0) {
|
|
14630
|
-
console.log(` Estimated savings: ~${
|
|
14702
|
+
console.log(` Estimated savings: ~${chalk24.green(data.estimatedSavingsTokens.toLocaleString())} tokens`);
|
|
14631
14703
|
}
|
|
14632
14704
|
if (data.estimatedSavingsSeconds > 0) {
|
|
14633
|
-
console.log(` Time saved: ~${
|
|
14705
|
+
console.log(` Time saved: ~${chalk24.green(formatDuration(data.estimatedSavingsSeconds))}`);
|
|
14634
14706
|
}
|
|
14635
14707
|
}
|
|
14636
|
-
console.log(
|
|
14637
|
-
console.log(` Score: ${
|
|
14708
|
+
console.log(chalk24.bold("\n Config Quality"));
|
|
14709
|
+
console.log(` Score: ${chalk24.cyan(`${score.score}/100`)} (${score.grade})`);
|
|
14638
14710
|
const history = readScoreHistory();
|
|
14639
14711
|
const trend = getScoreTrend(history);
|
|
14640
14712
|
if (trend) {
|
|
14641
|
-
const trendColor = trend.direction === "up" ?
|
|
14713
|
+
const trendColor = trend.direction === "up" ? chalk24.green : trend.direction === "down" ? chalk24.red : chalk24.gray;
|
|
14642
14714
|
const arrow = trend.direction === "up" ? "\u2191" : trend.direction === "down" ? "\u2193" : "\u2192";
|
|
14643
14715
|
const sign = trend.delta > 0 ? "+" : "";
|
|
14644
|
-
console.log(` Trend: ${trendColor(`${arrow} ${sign}${trend.delta} pts`)} ${
|
|
14716
|
+
console.log(` Trend: ${trendColor(`${arrow} ${sign}${trend.delta} pts`)} ${chalk24.dim(`over ${trend.entries} checks`)}`);
|
|
14645
14717
|
}
|
|
14646
14718
|
console.log("");
|
|
14647
14719
|
}
|
|
@@ -14669,64 +14741,64 @@ async function insightsCommand(options) {
|
|
|
14669
14741
|
}
|
|
14670
14742
|
|
|
14671
14743
|
// src/commands/sources.ts
|
|
14672
|
-
import
|
|
14673
|
-
import
|
|
14674
|
-
import
|
|
14744
|
+
import fs49 from "fs";
|
|
14745
|
+
import path40 from "path";
|
|
14746
|
+
import chalk25 from "chalk";
|
|
14675
14747
|
init_resolve_caliber();
|
|
14676
14748
|
async function sourcesListCommand() {
|
|
14677
14749
|
const dir = process.cwd();
|
|
14678
14750
|
const configSources = loadSourcesConfig(dir);
|
|
14679
14751
|
const workspaces = getDetectedWorkspaces(dir);
|
|
14680
14752
|
if (configSources.length === 0 && workspaces.length === 0) {
|
|
14681
|
-
console.log(
|
|
14682
|
-
console.log(
|
|
14683
|
-
console.log(
|
|
14753
|
+
console.log(chalk25.dim("\n No sources configured.\n"));
|
|
14754
|
+
console.log(chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")(`${resolveCaliber()} sources add <path>`));
|
|
14755
|
+
console.log(chalk25.dim(" Or add to .caliber/sources.json manually.\n"));
|
|
14684
14756
|
return;
|
|
14685
14757
|
}
|
|
14686
|
-
console.log(
|
|
14758
|
+
console.log(chalk25.bold("\n External Sources\n"));
|
|
14687
14759
|
if (configSources.length > 0) {
|
|
14688
14760
|
for (const source of configSources) {
|
|
14689
14761
|
const sourcePath = source.path || source.url || "";
|
|
14690
|
-
const exists = source.path ?
|
|
14691
|
-
const status = exists ?
|
|
14692
|
-
const hasSummary = source.path &&
|
|
14693
|
-
console.log(` ${
|
|
14694
|
-
console.log(` Type: ${source.type} Status: ${status}${hasSummary ? " " +
|
|
14695
|
-
if (source.description) console.log(` ${
|
|
14762
|
+
const exists = source.path ? fs49.existsSync(path40.resolve(dir, source.path)) : false;
|
|
14763
|
+
const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
|
|
14764
|
+
const hasSummary = source.path && fs49.existsSync(path40.join(path40.resolve(dir, source.path), ".caliber", "summary.json"));
|
|
14765
|
+
console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
|
|
14766
|
+
console.log(` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`);
|
|
14767
|
+
if (source.description) console.log(` ${chalk25.dim(source.description)}`);
|
|
14696
14768
|
console.log("");
|
|
14697
14769
|
}
|
|
14698
14770
|
}
|
|
14699
14771
|
if (workspaces.length > 0) {
|
|
14700
|
-
console.log(
|
|
14772
|
+
console.log(chalk25.dim(" Auto-detected workspaces:"));
|
|
14701
14773
|
for (const ws of workspaces) {
|
|
14702
|
-
const exists =
|
|
14703
|
-
console.log(` ${exists ?
|
|
14774
|
+
const exists = fs49.existsSync(path40.resolve(dir, ws));
|
|
14775
|
+
console.log(` ${exists ? chalk25.green("\u25CF") : chalk25.red("\u25CF")} ${ws}`);
|
|
14704
14776
|
}
|
|
14705
14777
|
console.log("");
|
|
14706
14778
|
}
|
|
14707
14779
|
}
|
|
14708
14780
|
async function sourcesAddCommand(sourcePath) {
|
|
14709
14781
|
const dir = process.cwd();
|
|
14710
|
-
const absPath =
|
|
14711
|
-
if (!
|
|
14712
|
-
console.log(
|
|
14782
|
+
const absPath = path40.resolve(dir, sourcePath);
|
|
14783
|
+
if (!fs49.existsSync(absPath)) {
|
|
14784
|
+
console.log(chalk25.red(`
|
|
14713
14785
|
Path not found: ${sourcePath}
|
|
14714
14786
|
`));
|
|
14715
14787
|
throw new Error("__exit__");
|
|
14716
14788
|
}
|
|
14717
14789
|
const type = detectSourceType(absPath);
|
|
14718
14790
|
if (isInsideDir(absPath, dir)) {
|
|
14719
|
-
console.log(
|
|
14791
|
+
console.log(chalk25.red(`
|
|
14720
14792
|
Cannot add a path inside the current project as a source.
|
|
14721
14793
|
`));
|
|
14722
14794
|
throw new Error("__exit__");
|
|
14723
14795
|
}
|
|
14724
14796
|
const existing = loadSourcesConfig(dir);
|
|
14725
14797
|
const alreadyConfigured = existing.some(
|
|
14726
|
-
(s) => s.path &&
|
|
14798
|
+
(s) => s.path && path40.resolve(dir, s.path) === absPath
|
|
14727
14799
|
);
|
|
14728
14800
|
if (alreadyConfigured) {
|
|
14729
|
-
console.log(
|
|
14801
|
+
console.log(chalk25.yellow(`
|
|
14730
14802
|
Already configured: ${sourcePath}
|
|
14731
14803
|
`));
|
|
14732
14804
|
return;
|
|
@@ -14743,7 +14815,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
14743
14815
|
};
|
|
14744
14816
|
existing.push(newSource);
|
|
14745
14817
|
writeSourcesConfig(dir, existing);
|
|
14746
|
-
console.log(
|
|
14818
|
+
console.log(chalk25.green(`
|
|
14747
14819
|
\u2713 Added ${sourcePath} as ${type} source (${role})
|
|
14748
14820
|
`));
|
|
14749
14821
|
}
|
|
@@ -14754,26 +14826,26 @@ async function sourcesRemoveCommand(name) {
|
|
|
14754
14826
|
(s) => s.path?.includes(name) || s.role === name
|
|
14755
14827
|
);
|
|
14756
14828
|
if (idx === -1) {
|
|
14757
|
-
console.log(
|
|
14829
|
+
console.log(chalk25.red(`
|
|
14758
14830
|
Source not found: ${name}
|
|
14759
14831
|
`));
|
|
14760
|
-
console.log(
|
|
14832
|
+
console.log(chalk25.dim(" Available sources:"));
|
|
14761
14833
|
for (const s of existing) {
|
|
14762
|
-
console.log(
|
|
14834
|
+
console.log(chalk25.dim(` ${s.path || s.url} (${s.role || s.type})`));
|
|
14763
14835
|
}
|
|
14764
14836
|
throw new Error("__exit__");
|
|
14765
14837
|
}
|
|
14766
14838
|
const removed = existing.splice(idx, 1)[0];
|
|
14767
14839
|
writeSourcesConfig(dir, existing);
|
|
14768
|
-
console.log(
|
|
14840
|
+
console.log(chalk25.green(`
|
|
14769
14841
|
\u2713 Removed ${removed.path || removed.url} (${removed.role || removed.type})
|
|
14770
14842
|
`));
|
|
14771
14843
|
}
|
|
14772
14844
|
|
|
14773
14845
|
// src/commands/publish.ts
|
|
14774
|
-
import
|
|
14775
|
-
import
|
|
14776
|
-
import
|
|
14846
|
+
import fs50 from "fs";
|
|
14847
|
+
import path41 from "path";
|
|
14848
|
+
import chalk26 from "chalk";
|
|
14777
14849
|
import ora7 from "ora";
|
|
14778
14850
|
init_config();
|
|
14779
14851
|
init_resolve_caliber();
|
|
@@ -14781,16 +14853,16 @@ async function publishCommand() {
|
|
|
14781
14853
|
const dir = process.cwd();
|
|
14782
14854
|
const config = loadConfig();
|
|
14783
14855
|
if (!config) {
|
|
14784
|
-
console.log(
|
|
14856
|
+
console.log(chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")(`${resolveCaliber()} config`) + chalk26.red(" first."));
|
|
14785
14857
|
throw new Error("__exit__");
|
|
14786
14858
|
}
|
|
14787
14859
|
const spinner = ora7("Generating project summary...").start();
|
|
14788
14860
|
try {
|
|
14789
14861
|
const fingerprint = await collectFingerprint(dir);
|
|
14790
|
-
const claudeMd = readFileOrNull(
|
|
14862
|
+
const claudeMd = readFileOrNull(path41.join(dir, "CLAUDE.md"));
|
|
14791
14863
|
const topLevelDirs = fingerprint.fileTree.filter((f) => f.endsWith("/") && !f.includes("/")).map((f) => f.replace(/\/$/, ""));
|
|
14792
14864
|
const summary = {
|
|
14793
|
-
name: fingerprint.packageName ||
|
|
14865
|
+
name: fingerprint.packageName || path41.basename(dir),
|
|
14794
14866
|
version: "1.0.0",
|
|
14795
14867
|
description: fingerprint.description || "",
|
|
14796
14868
|
languages: fingerprint.languages,
|
|
@@ -14802,7 +14874,7 @@ async function publishCommand() {
|
|
|
14802
14874
|
summary.conventions = claudeMd.slice(0, 2e3);
|
|
14803
14875
|
}
|
|
14804
14876
|
try {
|
|
14805
|
-
const pkgContent = readFileOrNull(
|
|
14877
|
+
const pkgContent = readFileOrNull(path41.join(dir, "package.json"));
|
|
14806
14878
|
if (pkgContent) {
|
|
14807
14879
|
const pkg3 = JSON.parse(pkgContent);
|
|
14808
14880
|
if (pkg3.scripts) {
|
|
@@ -14815,28 +14887,28 @@ async function publishCommand() {
|
|
|
14815
14887
|
}
|
|
14816
14888
|
} catch {
|
|
14817
14889
|
}
|
|
14818
|
-
const outputDir =
|
|
14819
|
-
if (!
|
|
14820
|
-
|
|
14890
|
+
const outputDir = path41.join(dir, ".caliber");
|
|
14891
|
+
if (!fs50.existsSync(outputDir)) {
|
|
14892
|
+
fs50.mkdirSync(outputDir, { recursive: true });
|
|
14821
14893
|
}
|
|
14822
|
-
const outputPath =
|
|
14823
|
-
|
|
14894
|
+
const outputPath = path41.join(outputDir, "summary.json");
|
|
14895
|
+
fs50.writeFileSync(outputPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
|
|
14824
14896
|
spinner.succeed("Project summary published");
|
|
14825
|
-
console.log(` ${
|
|
14826
|
-
console.log(
|
|
14827
|
-
console.log(
|
|
14897
|
+
console.log(` ${chalk26.green("\u2713")} ${path41.relative(dir, outputPath)}`);
|
|
14898
|
+
console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
|
|
14899
|
+
console.log(chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n"));
|
|
14828
14900
|
} catch (err) {
|
|
14829
14901
|
spinner.fail("Failed to generate summary");
|
|
14830
14902
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
14831
|
-
console.error(
|
|
14903
|
+
console.error(chalk26.red(err instanceof Error ? err.message : "Unknown error"));
|
|
14832
14904
|
throw new Error("__exit__");
|
|
14833
14905
|
}
|
|
14834
14906
|
}
|
|
14835
14907
|
|
|
14836
14908
|
// src/commands/bootstrap.ts
|
|
14837
14909
|
init_builtin_skills();
|
|
14838
|
-
import
|
|
14839
|
-
import
|
|
14910
|
+
import fs51 from "fs";
|
|
14911
|
+
import chalk27 from "chalk";
|
|
14840
14912
|
var PLATFORM_SKILL_DIRS = {
|
|
14841
14913
|
claude: ".claude/skills",
|
|
14842
14914
|
cursor: ".cursor/skills",
|
|
@@ -14856,46 +14928,46 @@ async function bootstrapCommand() {
|
|
|
14856
14928
|
for (const skill of BUILTIN_SKILLS) {
|
|
14857
14929
|
const skillDir = `${skillsDir}/${skill.name}`;
|
|
14858
14930
|
const skillPath = `${skillDir}/SKILL.md`;
|
|
14859
|
-
|
|
14860
|
-
|
|
14931
|
+
fs51.mkdirSync(skillDir, { recursive: true });
|
|
14932
|
+
fs51.writeFileSync(skillPath, buildSkillContent(skill));
|
|
14861
14933
|
written.push(skillPath);
|
|
14862
14934
|
}
|
|
14863
14935
|
}
|
|
14864
14936
|
if (written.length === 0) {
|
|
14865
|
-
console.log(
|
|
14937
|
+
console.log(chalk27.yellow("No skills were written."));
|
|
14866
14938
|
return;
|
|
14867
14939
|
}
|
|
14868
|
-
console.log(
|
|
14940
|
+
console.log(chalk27.bold.green("\n Caliber skills installed!\n"));
|
|
14869
14941
|
for (const file of written) {
|
|
14870
|
-
console.log(` ${
|
|
14942
|
+
console.log(` ${chalk27.green("\u2713")} ${file}`);
|
|
14871
14943
|
}
|
|
14872
|
-
console.log(
|
|
14873
|
-
console.log(
|
|
14944
|
+
console.log(chalk27.dim("\n Your agent can now run /setup-caliber to complete the setup."));
|
|
14945
|
+
console.log(chalk27.dim(' Just tell your agent: "Run /setup-caliber"\n'));
|
|
14874
14946
|
}
|
|
14875
14947
|
|
|
14876
14948
|
// src/commands/uninstall.ts
|
|
14877
|
-
import
|
|
14878
|
-
import
|
|
14879
|
-
import
|
|
14949
|
+
import fs52 from "fs";
|
|
14950
|
+
import path42 from "path";
|
|
14951
|
+
import chalk28 from "chalk";
|
|
14880
14952
|
import confirm3 from "@inquirer/confirm";
|
|
14881
14953
|
init_pre_commit_block();
|
|
14882
14954
|
init_builtin_skills();
|
|
14883
14955
|
init_config();
|
|
14884
14956
|
var MANAGED_DOC_FILES = [
|
|
14885
14957
|
"CLAUDE.md",
|
|
14886
|
-
|
|
14958
|
+
path42.join(".github", "copilot-instructions.md"),
|
|
14887
14959
|
"AGENTS.md"
|
|
14888
14960
|
];
|
|
14889
14961
|
var SKILL_DIRS = PLATFORM_CONFIGS.map((c) => c.skillsDir);
|
|
14890
|
-
var CURSOR_RULES_DIR =
|
|
14891
|
-
var CLAUDE_RULES_DIR =
|
|
14962
|
+
var CURSOR_RULES_DIR = path42.join(".cursor", "rules");
|
|
14963
|
+
var CLAUDE_RULES_DIR = path42.join(".claude", "rules");
|
|
14892
14964
|
function removeCaliberManagedFiles(dir, extension) {
|
|
14893
14965
|
const removed = [];
|
|
14894
|
-
if (!
|
|
14895
|
-
for (const file of
|
|
14966
|
+
if (!fs52.existsSync(dir)) return removed;
|
|
14967
|
+
for (const file of fs52.readdirSync(dir)) {
|
|
14896
14968
|
if (file.startsWith(CALIBER_MANAGED_PREFIX) && file.endsWith(extension)) {
|
|
14897
|
-
const fullPath =
|
|
14898
|
-
|
|
14969
|
+
const fullPath = path42.join(dir, file);
|
|
14970
|
+
fs52.unlinkSync(fullPath);
|
|
14899
14971
|
removed.push(fullPath);
|
|
14900
14972
|
}
|
|
14901
14973
|
}
|
|
@@ -14904,11 +14976,11 @@ function removeCaliberManagedFiles(dir, extension) {
|
|
|
14904
14976
|
function removeBuiltinSkills() {
|
|
14905
14977
|
const removed = [];
|
|
14906
14978
|
for (const skillsDir of SKILL_DIRS) {
|
|
14907
|
-
if (!
|
|
14979
|
+
if (!fs52.existsSync(skillsDir)) continue;
|
|
14908
14980
|
for (const name of BUILTIN_SKILL_NAMES) {
|
|
14909
|
-
const skillDir =
|
|
14910
|
-
if (
|
|
14911
|
-
|
|
14981
|
+
const skillDir = path42.join(skillsDir, name);
|
|
14982
|
+
if (fs52.existsSync(skillDir)) {
|
|
14983
|
+
fs52.rmSync(skillDir, { recursive: true });
|
|
14912
14984
|
removed.push(skillDir);
|
|
14913
14985
|
}
|
|
14914
14986
|
}
|
|
@@ -14918,15 +14990,15 @@ function removeBuiltinSkills() {
|
|
|
14918
14990
|
function stripManagedBlocksFromFiles() {
|
|
14919
14991
|
const modified = [];
|
|
14920
14992
|
for (const filePath of MANAGED_DOC_FILES) {
|
|
14921
|
-
if (!
|
|
14922
|
-
const original =
|
|
14993
|
+
if (!fs52.existsSync(filePath)) continue;
|
|
14994
|
+
const original = fs52.readFileSync(filePath, "utf-8");
|
|
14923
14995
|
const stripped = stripManagedBlocks(original);
|
|
14924
14996
|
if (stripped !== original) {
|
|
14925
14997
|
const trimmed = stripped.trim();
|
|
14926
14998
|
if (!trimmed || /^#\s*\S*$/.test(trimmed)) {
|
|
14927
|
-
|
|
14999
|
+
fs52.unlinkSync(filePath);
|
|
14928
15000
|
} else {
|
|
14929
|
-
|
|
15001
|
+
fs52.writeFileSync(filePath, stripped);
|
|
14930
15002
|
}
|
|
14931
15003
|
modified.push(filePath);
|
|
14932
15004
|
}
|
|
@@ -14934,24 +15006,24 @@ function stripManagedBlocksFromFiles() {
|
|
|
14934
15006
|
return modified;
|
|
14935
15007
|
}
|
|
14936
15008
|
function removeDirectory(dir) {
|
|
14937
|
-
if (!
|
|
14938
|
-
|
|
15009
|
+
if (!fs52.existsSync(dir)) return false;
|
|
15010
|
+
fs52.rmSync(dir, { recursive: true });
|
|
14939
15011
|
return true;
|
|
14940
15012
|
}
|
|
14941
15013
|
async function uninstallCommand(options) {
|
|
14942
|
-
console.log(
|
|
14943
|
-
console.log(
|
|
14944
|
-
console.log(
|
|
14945
|
-
console.log(
|
|
14946
|
-
console.log(
|
|
14947
|
-
console.log(
|
|
14948
|
-
console.log(
|
|
14949
|
-
console.log(
|
|
14950
|
-
console.log(
|
|
15014
|
+
console.log(chalk28.bold("\n Caliber Uninstall\n"));
|
|
15015
|
+
console.log(chalk28.dim(" This will remove all Caliber resources from this project:\n"));
|
|
15016
|
+
console.log(chalk28.dim(" \u2022 Pre-commit hook"));
|
|
15017
|
+
console.log(chalk28.dim(" \u2022 Session learning hooks"));
|
|
15018
|
+
console.log(chalk28.dim(" \u2022 Managed blocks in CLAUDE.md, AGENTS.md, copilot-instructions.md"));
|
|
15019
|
+
console.log(chalk28.dim(" \u2022 Cursor rules (caliber-*.mdc)"));
|
|
15020
|
+
console.log(chalk28.dim(" \u2022 Built-in skills (setup-caliber, find-skills, save-learning)"));
|
|
15021
|
+
console.log(chalk28.dim(" \u2022 CALIBER_LEARNINGS.md"));
|
|
15022
|
+
console.log(chalk28.dim(" \u2022 .caliber/ directory (backups, cache, state)\n"));
|
|
14951
15023
|
if (!options.force) {
|
|
14952
15024
|
const proceed = await confirm3({ message: "Continue with uninstall?" });
|
|
14953
15025
|
if (!proceed) {
|
|
14954
|
-
console.log(
|
|
15026
|
+
console.log(chalk28.dim("\n Cancelled.\n"));
|
|
14955
15027
|
return;
|
|
14956
15028
|
}
|
|
14957
15029
|
}
|
|
@@ -14959,93 +15031,93 @@ async function uninstallCommand(options) {
|
|
|
14959
15031
|
const actions = [];
|
|
14960
15032
|
const hookResult = removePreCommitHook();
|
|
14961
15033
|
if (hookResult.removed) {
|
|
14962
|
-
console.log(` ${
|
|
15034
|
+
console.log(` ${chalk28.red("\u2717")} Pre-commit hook removed`);
|
|
14963
15035
|
actions.push("pre-commit hook");
|
|
14964
15036
|
}
|
|
14965
15037
|
const stopHookResult = removeStopHook();
|
|
14966
15038
|
if (stopHookResult.removed) {
|
|
14967
|
-
console.log(` ${
|
|
15039
|
+
console.log(` ${chalk28.red("\u2717")} Onboarding hook removed`);
|
|
14968
15040
|
actions.push("onboarding hook");
|
|
14969
15041
|
}
|
|
14970
15042
|
const notificationHookResult = removeNotificationHook();
|
|
14971
15043
|
if (notificationHookResult.removed) {
|
|
14972
|
-
console.log(` ${
|
|
15044
|
+
console.log(` ${chalk28.red("\u2717")} Notification hook removed`);
|
|
14973
15045
|
actions.push("notification hook");
|
|
14974
15046
|
}
|
|
14975
15047
|
const sessionStartResult = removeSessionStartHook();
|
|
14976
15048
|
if (sessionStartResult.removed) {
|
|
14977
|
-
console.log(` ${
|
|
15049
|
+
console.log(` ${chalk28.red("\u2717")} SessionStart hook removed`);
|
|
14978
15050
|
actions.push("session-start hook");
|
|
14979
15051
|
}
|
|
14980
15052
|
const learnResult = removeLearningHooks();
|
|
14981
15053
|
if (learnResult.removed) {
|
|
14982
|
-
console.log(` ${
|
|
15054
|
+
console.log(` ${chalk28.red("\u2717")} Claude Code learning hooks removed`);
|
|
14983
15055
|
actions.push("claude learning hooks");
|
|
14984
15056
|
}
|
|
14985
15057
|
const cursorLearnResult = removeCursorLearningHooks();
|
|
14986
15058
|
if (cursorLearnResult.removed) {
|
|
14987
|
-
console.log(` ${
|
|
15059
|
+
console.log(` ${chalk28.red("\u2717")} Cursor learning hooks removed`);
|
|
14988
15060
|
actions.push("cursor learning hooks");
|
|
14989
15061
|
}
|
|
14990
15062
|
const strippedFiles = stripManagedBlocksFromFiles();
|
|
14991
15063
|
for (const file of strippedFiles) {
|
|
14992
|
-
console.log(` ${
|
|
15064
|
+
console.log(` ${chalk28.yellow("~")} ${file} \u2014 managed blocks removed`);
|
|
14993
15065
|
actions.push(file);
|
|
14994
15066
|
}
|
|
14995
15067
|
const removedCursorRules = removeCaliberManagedFiles(CURSOR_RULES_DIR, ".mdc");
|
|
14996
15068
|
for (const rule of removedCursorRules) {
|
|
14997
|
-
console.log(` ${
|
|
15069
|
+
console.log(` ${chalk28.red("\u2717")} ${rule}`);
|
|
14998
15070
|
}
|
|
14999
15071
|
if (removedCursorRules.length > 0) actions.push("cursor rules");
|
|
15000
15072
|
const removedClaudeRules = removeCaliberManagedFiles(CLAUDE_RULES_DIR, ".md");
|
|
15001
15073
|
for (const rule of removedClaudeRules) {
|
|
15002
|
-
console.log(` ${
|
|
15074
|
+
console.log(` ${chalk28.red("\u2717")} ${rule}`);
|
|
15003
15075
|
}
|
|
15004
15076
|
if (removedClaudeRules.length > 0) actions.push("claude rules");
|
|
15005
15077
|
const removedSkills = removeBuiltinSkills();
|
|
15006
15078
|
for (const skill of removedSkills) {
|
|
15007
|
-
console.log(` ${
|
|
15079
|
+
console.log(` ${chalk28.red("\u2717")} ${skill}/`);
|
|
15008
15080
|
}
|
|
15009
15081
|
if (removedSkills.length > 0) actions.push("builtin skills");
|
|
15010
|
-
if (
|
|
15011
|
-
|
|
15012
|
-
console.log(` ${
|
|
15082
|
+
if (fs52.existsSync("CALIBER_LEARNINGS.md")) {
|
|
15083
|
+
fs52.unlinkSync("CALIBER_LEARNINGS.md");
|
|
15084
|
+
console.log(` ${chalk28.red("\u2717")} CALIBER_LEARNINGS.md`);
|
|
15013
15085
|
actions.push("learnings file");
|
|
15014
15086
|
}
|
|
15015
15087
|
if (removeDirectory(CALIBER_DIR)) {
|
|
15016
|
-
console.log(` ${
|
|
15088
|
+
console.log(` ${chalk28.red("\u2717")} .caliber/ directory`);
|
|
15017
15089
|
actions.push(".caliber directory");
|
|
15018
15090
|
}
|
|
15019
15091
|
if (actions.length === 0) {
|
|
15020
|
-
console.log(
|
|
15092
|
+
console.log(chalk28.dim(" Nothing to remove \u2014 Caliber is not installed in this project.\n"));
|
|
15021
15093
|
return;
|
|
15022
15094
|
}
|
|
15023
15095
|
trackUninstallExecuted();
|
|
15024
15096
|
const configPath = getConfigFilePath();
|
|
15025
|
-
if (
|
|
15097
|
+
if (fs52.existsSync(configPath)) {
|
|
15026
15098
|
console.log("");
|
|
15027
15099
|
const removeConfig = options.force || await confirm3({
|
|
15028
15100
|
message: `Remove global config (~/.caliber/config.json)? This affects all projects.`
|
|
15029
15101
|
});
|
|
15030
15102
|
if (removeConfig) {
|
|
15031
|
-
|
|
15032
|
-
console.log(` ${
|
|
15033
|
-
const configDir =
|
|
15103
|
+
fs52.unlinkSync(configPath);
|
|
15104
|
+
console.log(` ${chalk28.red("\u2717")} ${configPath}`);
|
|
15105
|
+
const configDir = path42.dirname(configPath);
|
|
15034
15106
|
try {
|
|
15035
|
-
const remaining =
|
|
15036
|
-
if (remaining.length === 0)
|
|
15107
|
+
const remaining = fs52.readdirSync(configDir);
|
|
15108
|
+
if (remaining.length === 0) fs52.rmdirSync(configDir);
|
|
15037
15109
|
} catch {
|
|
15038
15110
|
}
|
|
15039
15111
|
}
|
|
15040
15112
|
}
|
|
15041
|
-
console.log(
|
|
15113
|
+
console.log(chalk28.bold.green(`
|
|
15042
15114
|
Caliber has been removed from this project.`));
|
|
15043
|
-
console.log(
|
|
15115
|
+
console.log(chalk28.dim(" Your code is untouched \u2014 only Caliber config files were removed.\n"));
|
|
15044
15116
|
}
|
|
15045
15117
|
|
|
15046
15118
|
// src/cli.ts
|
|
15047
|
-
var __dirname =
|
|
15048
|
-
var pkg = JSON.parse(
|
|
15119
|
+
var __dirname = path43.dirname(fileURLToPath(import.meta.url));
|
|
15120
|
+
var pkg = JSON.parse(fs53.readFileSync(path43.resolve(__dirname, "..", "package.json"), "utf-8"));
|
|
15049
15121
|
var program = new Command();
|
|
15050
15122
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
15051
15123
|
program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("AI context infrastructure for coding agents").version(displayVersion).option("--no-traces", "Disable anonymous telemetry for this run");
|
|
@@ -15156,15 +15228,15 @@ learn.command("delete <index>").description("Delete a learning by its index numb
|
|
|
15156
15228
|
learn.command("add <content>").description("Add a learning directly (used by agent skills)").option("--personal", "Save as a personal learning instead of project-level").action(tracked("learn:add", learnAddCommand));
|
|
15157
15229
|
|
|
15158
15230
|
// src/utils/version-check.ts
|
|
15159
|
-
import
|
|
15160
|
-
import
|
|
15231
|
+
import fs54 from "fs";
|
|
15232
|
+
import path44 from "path";
|
|
15161
15233
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15162
15234
|
import { execSync as execSync18, execFileSync as execFileSync5 } from "child_process";
|
|
15163
|
-
import
|
|
15235
|
+
import chalk29 from "chalk";
|
|
15164
15236
|
import ora8 from "ora";
|
|
15165
15237
|
import confirm4 from "@inquirer/confirm";
|
|
15166
|
-
var __dirname_vc =
|
|
15167
|
-
var pkg2 = JSON.parse(
|
|
15238
|
+
var __dirname_vc = path44.dirname(fileURLToPath2(import.meta.url));
|
|
15239
|
+
var pkg2 = JSON.parse(fs54.readFileSync(path44.resolve(__dirname_vc, "..", "package.json"), "utf-8"));
|
|
15168
15240
|
function getChannel(version) {
|
|
15169
15241
|
const match = version.match(/-(dev|next)\./);
|
|
15170
15242
|
return match ? match[1] : "latest";
|
|
@@ -15191,8 +15263,8 @@ function getInstalledVersion() {
|
|
|
15191
15263
|
encoding: "utf-8",
|
|
15192
15264
|
stdio: ["pipe", "pipe", "pipe"]
|
|
15193
15265
|
}).trim();
|
|
15194
|
-
const pkgPath =
|
|
15195
|
-
return JSON.parse(
|
|
15266
|
+
const pkgPath = path44.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
15267
|
+
return JSON.parse(fs54.readFileSync(pkgPath, "utf-8")).version;
|
|
15196
15268
|
} catch {
|
|
15197
15269
|
return null;
|
|
15198
15270
|
}
|
|
@@ -15217,16 +15289,16 @@ async function checkForUpdates() {
|
|
|
15217
15289
|
if (!isInteractive) {
|
|
15218
15290
|
const installTag = channel === "latest" ? "" : `@${channel}`;
|
|
15219
15291
|
console.log(
|
|
15220
|
-
|
|
15292
|
+
chalk29.yellow(
|
|
15221
15293
|
`
|
|
15222
15294
|
Update available: ${current} -> ${latest}
|
|
15223
|
-
Run ${
|
|
15295
|
+
Run ${chalk29.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
|
|
15224
15296
|
`
|
|
15225
15297
|
)
|
|
15226
15298
|
);
|
|
15227
15299
|
return;
|
|
15228
15300
|
}
|
|
15229
|
-
console.log(
|
|
15301
|
+
console.log(chalk29.yellow(`
|
|
15230
15302
|
Update available: ${current} -> ${latest}`));
|
|
15231
15303
|
const shouldUpdate = await confirm4({
|
|
15232
15304
|
message: "Would you like to update now? (Y/n)",
|
|
@@ -15249,14 +15321,14 @@ Update available: ${current} -> ${latest}`));
|
|
|
15249
15321
|
if (installed !== latest) {
|
|
15250
15322
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
15251
15323
|
console.log(
|
|
15252
|
-
|
|
15324
|
+
chalk29.yellow(`Run ${chalk29.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
|
|
15253
15325
|
`)
|
|
15254
15326
|
);
|
|
15255
15327
|
return;
|
|
15256
15328
|
}
|
|
15257
|
-
spinner.succeed(
|
|
15329
|
+
spinner.succeed(chalk29.green(`Updated to ${latest}`));
|
|
15258
15330
|
const args = process.argv.slice(2);
|
|
15259
|
-
console.log(
|
|
15331
|
+
console.log(chalk29.dim(`
|
|
15260
15332
|
Restarting: caliber ${args.join(" ")}
|
|
15261
15333
|
`));
|
|
15262
15334
|
execFileSync5("caliber", args, {
|
|
@@ -15269,11 +15341,11 @@ Restarting: caliber ${args.join(" ")}
|
|
|
15269
15341
|
if (err instanceof Error) {
|
|
15270
15342
|
const stderr = err.stderr;
|
|
15271
15343
|
const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
|
|
15272
|
-
if (errMsg && !errMsg.includes("SIGTERM")) console.log(
|
|
15344
|
+
if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk29.dim(` ${errMsg}`));
|
|
15273
15345
|
}
|
|
15274
15346
|
console.log(
|
|
15275
|
-
|
|
15276
|
-
`Run ${
|
|
15347
|
+
chalk29.yellow(
|
|
15348
|
+
`Run ${chalk29.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually to upgrade.
|
|
15277
15349
|
`
|
|
15278
15350
|
)
|
|
15279
15351
|
);
|