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