@rely-ai/caliber 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +266 -203
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -51,7 +51,7 @@ var init_constants = __esm({
|
|
|
51
51
|
|
|
52
52
|
// src/cli.ts
|
|
53
53
|
import { Command } from "commander";
|
|
54
|
-
import
|
|
54
|
+
import fs27 from "fs";
|
|
55
55
|
import path22 from "path";
|
|
56
56
|
import { fileURLToPath } from "url";
|
|
57
57
|
|
|
@@ -61,7 +61,7 @@ import ora2 from "ora";
|
|
|
61
61
|
import readline4 from "readline";
|
|
62
62
|
import select2 from "@inquirer/select";
|
|
63
63
|
import checkbox from "@inquirer/checkbox";
|
|
64
|
-
import
|
|
64
|
+
import fs20 from "fs";
|
|
65
65
|
|
|
66
66
|
// src/fingerprint/index.ts
|
|
67
67
|
import fs6 from "fs";
|
|
@@ -2204,25 +2204,92 @@ function openDiffsInEditor(editor, files) {
|
|
|
2204
2204
|
// src/commands/onboard.ts
|
|
2205
2205
|
import { createTwoFilesPatch } from "diff";
|
|
2206
2206
|
|
|
2207
|
-
// src/
|
|
2207
|
+
// src/commands/setup-files.ts
|
|
2208
2208
|
import fs14 from "fs";
|
|
2209
|
+
function buildSkillContent(skill) {
|
|
2210
|
+
const frontmatter = `---
|
|
2211
|
+
name: ${skill.name}
|
|
2212
|
+
description: ${skill.description}
|
|
2213
|
+
---
|
|
2214
|
+
|
|
2215
|
+
`;
|
|
2216
|
+
return frontmatter + skill.content;
|
|
2217
|
+
}
|
|
2218
|
+
function collectSetupFiles(setup) {
|
|
2219
|
+
const files = [];
|
|
2220
|
+
const claude = setup.claude;
|
|
2221
|
+
const cursor = setup.cursor;
|
|
2222
|
+
const codex = setup.codex;
|
|
2223
|
+
if (claude) {
|
|
2224
|
+
if (claude.claudeMd) files.push({ path: "CLAUDE.md", content: claude.claudeMd });
|
|
2225
|
+
const skills = claude.skills;
|
|
2226
|
+
if (Array.isArray(skills)) {
|
|
2227
|
+
for (const skill of skills) {
|
|
2228
|
+
files.push({ path: `.claude/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
if (codex) {
|
|
2233
|
+
if (codex.agentsMd) files.push({ path: "AGENTS.md", content: codex.agentsMd });
|
|
2234
|
+
const codexSkills = codex.skills;
|
|
2235
|
+
if (Array.isArray(codexSkills)) {
|
|
2236
|
+
for (const skill of codexSkills) {
|
|
2237
|
+
files.push({ path: `.agents/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
if (cursor) {
|
|
2242
|
+
if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
|
|
2243
|
+
const cursorSkills = cursor.skills;
|
|
2244
|
+
if (Array.isArray(cursorSkills)) {
|
|
2245
|
+
for (const skill of cursorSkills) {
|
|
2246
|
+
files.push({ path: `.cursor/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
const rules = cursor.rules;
|
|
2250
|
+
if (Array.isArray(rules)) {
|
|
2251
|
+
for (const rule of rules) {
|
|
2252
|
+
files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
if (!fs14.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
|
|
2257
|
+
const agentRefs = [];
|
|
2258
|
+
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
2259
|
+
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
2260
|
+
if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
|
|
2261
|
+
files.push({
|
|
2262
|
+
path: "AGENTS.md",
|
|
2263
|
+
content: `# AGENTS.md
|
|
2264
|
+
|
|
2265
|
+
This project uses AI coding agents configured by [Caliber](https://github.com/rely-ai-org/caliber).
|
|
2266
|
+
|
|
2267
|
+
${agentRefs.join(" ")}
|
|
2268
|
+
`
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
return files;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// src/lib/hooks.ts
|
|
2275
|
+
import fs15 from "fs";
|
|
2209
2276
|
import path12 from "path";
|
|
2210
2277
|
import { execSync as execSync5 } from "child_process";
|
|
2211
2278
|
var SETTINGS_PATH = path12.join(".claude", "settings.json");
|
|
2212
2279
|
var HOOK_COMMAND = "caliber refresh --quiet";
|
|
2213
2280
|
var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
|
|
2214
2281
|
function readSettings() {
|
|
2215
|
-
if (!
|
|
2282
|
+
if (!fs15.existsSync(SETTINGS_PATH)) return {};
|
|
2216
2283
|
try {
|
|
2217
|
-
return JSON.parse(
|
|
2284
|
+
return JSON.parse(fs15.readFileSync(SETTINGS_PATH, "utf-8"));
|
|
2218
2285
|
} catch {
|
|
2219
2286
|
return {};
|
|
2220
2287
|
}
|
|
2221
2288
|
}
|
|
2222
2289
|
function writeSettings(settings) {
|
|
2223
2290
|
const dir = path12.dirname(SETTINGS_PATH);
|
|
2224
|
-
if (!
|
|
2225
|
-
|
|
2291
|
+
if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
|
|
2292
|
+
fs15.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
2226
2293
|
}
|
|
2227
2294
|
function findHookIndex(sessionEnd) {
|
|
2228
2295
|
return sessionEnd.findIndex(
|
|
@@ -2291,8 +2358,8 @@ function getPreCommitPath() {
|
|
|
2291
2358
|
}
|
|
2292
2359
|
function isPreCommitHookInstalled() {
|
|
2293
2360
|
const hookPath = getPreCommitPath();
|
|
2294
|
-
if (!hookPath || !
|
|
2295
|
-
const content =
|
|
2361
|
+
if (!hookPath || !fs15.existsSync(hookPath)) return false;
|
|
2362
|
+
const content = fs15.readFileSync(hookPath, "utf-8");
|
|
2296
2363
|
return content.includes(PRECOMMIT_START);
|
|
2297
2364
|
}
|
|
2298
2365
|
function installPreCommitHook() {
|
|
@@ -2302,40 +2369,40 @@ function installPreCommitHook() {
|
|
|
2302
2369
|
const hookPath = getPreCommitPath();
|
|
2303
2370
|
if (!hookPath) return { installed: false, alreadyInstalled: false };
|
|
2304
2371
|
const hooksDir = path12.dirname(hookPath);
|
|
2305
|
-
if (!
|
|
2372
|
+
if (!fs15.existsSync(hooksDir)) fs15.mkdirSync(hooksDir, { recursive: true });
|
|
2306
2373
|
let content = "";
|
|
2307
|
-
if (
|
|
2308
|
-
content =
|
|
2374
|
+
if (fs15.existsSync(hookPath)) {
|
|
2375
|
+
content = fs15.readFileSync(hookPath, "utf-8");
|
|
2309
2376
|
if (!content.endsWith("\n")) content += "\n";
|
|
2310
2377
|
content += "\n" + PRECOMMIT_BLOCK + "\n";
|
|
2311
2378
|
} else {
|
|
2312
2379
|
content = "#!/bin/sh\n\n" + PRECOMMIT_BLOCK + "\n";
|
|
2313
2380
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2381
|
+
fs15.writeFileSync(hookPath, content);
|
|
2382
|
+
fs15.chmodSync(hookPath, 493);
|
|
2316
2383
|
return { installed: true, alreadyInstalled: false };
|
|
2317
2384
|
}
|
|
2318
2385
|
function removePreCommitHook() {
|
|
2319
2386
|
const hookPath = getPreCommitPath();
|
|
2320
|
-
if (!hookPath || !
|
|
2387
|
+
if (!hookPath || !fs15.existsSync(hookPath)) {
|
|
2321
2388
|
return { removed: false, notFound: true };
|
|
2322
2389
|
}
|
|
2323
|
-
let content =
|
|
2390
|
+
let content = fs15.readFileSync(hookPath, "utf-8");
|
|
2324
2391
|
if (!content.includes(PRECOMMIT_START)) {
|
|
2325
2392
|
return { removed: false, notFound: true };
|
|
2326
2393
|
}
|
|
2327
2394
|
const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
|
|
2328
2395
|
content = content.replace(regex, "\n");
|
|
2329
2396
|
if (content.trim() === "#!/bin/sh" || content.trim() === "") {
|
|
2330
|
-
|
|
2397
|
+
fs15.unlinkSync(hookPath);
|
|
2331
2398
|
} else {
|
|
2332
|
-
|
|
2399
|
+
fs15.writeFileSync(hookPath, content);
|
|
2333
2400
|
}
|
|
2334
2401
|
return { removed: true, notFound: false };
|
|
2335
2402
|
}
|
|
2336
2403
|
|
|
2337
2404
|
// src/lib/learning-hooks.ts
|
|
2338
|
-
import
|
|
2405
|
+
import fs16 from "fs";
|
|
2339
2406
|
import path13 from "path";
|
|
2340
2407
|
var SETTINGS_PATH2 = path13.join(".claude", "settings.json");
|
|
2341
2408
|
var HOOK_CONFIGS = [
|
|
@@ -2356,17 +2423,17 @@ var HOOK_CONFIGS = [
|
|
|
2356
2423
|
}
|
|
2357
2424
|
];
|
|
2358
2425
|
function readSettings2() {
|
|
2359
|
-
if (!
|
|
2426
|
+
if (!fs16.existsSync(SETTINGS_PATH2)) return {};
|
|
2360
2427
|
try {
|
|
2361
|
-
return JSON.parse(
|
|
2428
|
+
return JSON.parse(fs16.readFileSync(SETTINGS_PATH2, "utf-8"));
|
|
2362
2429
|
} catch {
|
|
2363
2430
|
return {};
|
|
2364
2431
|
}
|
|
2365
2432
|
}
|
|
2366
2433
|
function writeSettings2(settings) {
|
|
2367
2434
|
const dir = path13.dirname(SETTINGS_PATH2);
|
|
2368
|
-
if (!
|
|
2369
|
-
|
|
2435
|
+
if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
|
|
2436
|
+
fs16.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
|
|
2370
2437
|
}
|
|
2371
2438
|
function hasLearningHook(matchers, command) {
|
|
2372
2439
|
return matchers.some((entry) => entry.hooks?.some((h) => h.command === command));
|
|
@@ -2423,7 +2490,7 @@ function removeLearningHooks() {
|
|
|
2423
2490
|
|
|
2424
2491
|
// src/lib/state.ts
|
|
2425
2492
|
init_constants();
|
|
2426
|
-
import
|
|
2493
|
+
import fs17 from "fs";
|
|
2427
2494
|
import path14 from "path";
|
|
2428
2495
|
import { execSync as execSync6 } from "child_process";
|
|
2429
2496
|
var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
|
|
@@ -2437,8 +2504,8 @@ function normalizeTargetAgent(value) {
|
|
|
2437
2504
|
}
|
|
2438
2505
|
function readState() {
|
|
2439
2506
|
try {
|
|
2440
|
-
if (!
|
|
2441
|
-
const raw = JSON.parse(
|
|
2507
|
+
if (!fs17.existsSync(STATE_FILE)) return null;
|
|
2508
|
+
const raw = JSON.parse(fs17.readFileSync(STATE_FILE, "utf-8"));
|
|
2442
2509
|
if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
|
|
2443
2510
|
return raw;
|
|
2444
2511
|
} catch {
|
|
@@ -2446,10 +2513,10 @@ function readState() {
|
|
|
2446
2513
|
}
|
|
2447
2514
|
}
|
|
2448
2515
|
function writeState(state) {
|
|
2449
|
-
if (!
|
|
2450
|
-
|
|
2516
|
+
if (!fs17.existsSync(CALIBER_DIR)) {
|
|
2517
|
+
fs17.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
2451
2518
|
}
|
|
2452
|
-
|
|
2519
|
+
fs17.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
2453
2520
|
}
|
|
2454
2521
|
function getCurrentHeadSha() {
|
|
2455
2522
|
try {
|
|
@@ -3670,22 +3737,22 @@ function checkBonus(dir) {
|
|
|
3670
3737
|
|
|
3671
3738
|
// src/scoring/dismissed.ts
|
|
3672
3739
|
init_constants();
|
|
3673
|
-
import
|
|
3740
|
+
import fs18 from "fs";
|
|
3674
3741
|
import path15 from "path";
|
|
3675
3742
|
var DISMISSED_FILE = path15.join(CALIBER_DIR, "dismissed-checks.json");
|
|
3676
3743
|
function readDismissedChecks() {
|
|
3677
3744
|
try {
|
|
3678
|
-
if (!
|
|
3679
|
-
return JSON.parse(
|
|
3745
|
+
if (!fs18.existsSync(DISMISSED_FILE)) return [];
|
|
3746
|
+
return JSON.parse(fs18.readFileSync(DISMISSED_FILE, "utf-8"));
|
|
3680
3747
|
} catch {
|
|
3681
3748
|
return [];
|
|
3682
3749
|
}
|
|
3683
3750
|
}
|
|
3684
3751
|
function writeDismissedChecks(checks) {
|
|
3685
|
-
if (!
|
|
3686
|
-
|
|
3752
|
+
if (!fs18.existsSync(CALIBER_DIR)) {
|
|
3753
|
+
fs18.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
3687
3754
|
}
|
|
3688
|
-
|
|
3755
|
+
fs18.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
|
|
3689
3756
|
}
|
|
3690
3757
|
function getDismissedIds() {
|
|
3691
3758
|
return new Set(readDismissedChecks().map((c) => c.id));
|
|
@@ -3876,7 +3943,7 @@ function displayScoreDelta(before, after) {
|
|
|
3876
3943
|
import chalk4 from "chalk";
|
|
3877
3944
|
import ora from "ora";
|
|
3878
3945
|
import readline3 from "readline";
|
|
3879
|
-
import
|
|
3946
|
+
import fs19 from "fs";
|
|
3880
3947
|
import path16 from "path";
|
|
3881
3948
|
|
|
3882
3949
|
// src/mcp/search.ts
|
|
@@ -4229,7 +4296,7 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
|
|
|
4229
4296
|
}
|
|
4230
4297
|
if (targetAgent.includes("cursor")) {
|
|
4231
4298
|
const cursorDir = path16.join(dir, ".cursor");
|
|
4232
|
-
if (!
|
|
4299
|
+
if (!fs19.existsSync(cursorDir)) fs19.mkdirSync(cursorDir, { recursive: true });
|
|
4233
4300
|
writeMcpJson(path16.join(cursorDir, "mcp.json"), mcpServers);
|
|
4234
4301
|
}
|
|
4235
4302
|
return { installed: installedNames.length, names: installedNames };
|
|
@@ -4237,14 +4304,14 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
|
|
|
4237
4304
|
function writeMcpJson(filePath, mcpServers) {
|
|
4238
4305
|
let existing = {};
|
|
4239
4306
|
try {
|
|
4240
|
-
if (
|
|
4241
|
-
const parsed = JSON.parse(
|
|
4307
|
+
if (fs19.existsSync(filePath)) {
|
|
4308
|
+
const parsed = JSON.parse(fs19.readFileSync(filePath, "utf-8"));
|
|
4242
4309
|
if (parsed.mcpServers) existing = parsed.mcpServers;
|
|
4243
4310
|
}
|
|
4244
4311
|
} catch {
|
|
4245
4312
|
}
|
|
4246
4313
|
const merged = { ...existing, ...mcpServers };
|
|
4247
|
-
|
|
4314
|
+
fs19.writeFileSync(filePath, JSON.stringify({ mcpServers: merged }, null, 2) + "\n");
|
|
4248
4315
|
}
|
|
4249
4316
|
function getExistingMcpNames(fingerprint, targetAgent) {
|
|
4250
4317
|
const names = [];
|
|
@@ -4859,8 +4926,8 @@ async function openReview(method, stagedFiles) {
|
|
|
4859
4926
|
return;
|
|
4860
4927
|
}
|
|
4861
4928
|
const fileInfos = stagedFiles.map((file) => {
|
|
4862
|
-
const proposed =
|
|
4863
|
-
const current = file.currentPath ?
|
|
4929
|
+
const proposed = fs20.readFileSync(file.proposedPath, "utf-8");
|
|
4930
|
+
const current = file.currentPath ? fs20.readFileSync(file.currentPath, "utf-8") : "";
|
|
4864
4931
|
const patch = createTwoFilesPatch(
|
|
4865
4932
|
file.isNew ? "/dev/null" : file.relativePath,
|
|
4866
4933
|
file.relativePath,
|
|
@@ -5043,7 +5110,7 @@ function printSetupSummary(setup) {
|
|
|
5043
5110
|
};
|
|
5044
5111
|
if (claude) {
|
|
5045
5112
|
if (claude.claudeMd) {
|
|
5046
|
-
const icon =
|
|
5113
|
+
const icon = fs20.existsSync("CLAUDE.md") ? chalk5.yellow("~") : chalk5.green("+");
|
|
5047
5114
|
const desc = getDescription("CLAUDE.md");
|
|
5048
5115
|
console.log(` ${icon} ${chalk5.bold("CLAUDE.md")}`);
|
|
5049
5116
|
if (desc) console.log(chalk5.dim(` ${desc}`));
|
|
@@ -5053,7 +5120,7 @@ function printSetupSummary(setup) {
|
|
|
5053
5120
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
5054
5121
|
for (const skill of skills) {
|
|
5055
5122
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
5056
|
-
const icon =
|
|
5123
|
+
const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
|
|
5057
5124
|
const desc = getDescription(skillPath);
|
|
5058
5125
|
console.log(` ${icon} ${chalk5.bold(skillPath)}`);
|
|
5059
5126
|
console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -5064,7 +5131,7 @@ function printSetupSummary(setup) {
|
|
|
5064
5131
|
const codex = setup.codex;
|
|
5065
5132
|
if (codex) {
|
|
5066
5133
|
if (codex.agentsMd) {
|
|
5067
|
-
const icon =
|
|
5134
|
+
const icon = fs20.existsSync("AGENTS.md") ? chalk5.yellow("~") : chalk5.green("+");
|
|
5068
5135
|
const desc = getDescription("AGENTS.md");
|
|
5069
5136
|
console.log(` ${icon} ${chalk5.bold("AGENTS.md")}`);
|
|
5070
5137
|
if (desc) console.log(chalk5.dim(` ${desc}`));
|
|
@@ -5074,7 +5141,7 @@ function printSetupSummary(setup) {
|
|
|
5074
5141
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
5075
5142
|
for (const skill of codexSkills) {
|
|
5076
5143
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
5077
|
-
const icon =
|
|
5144
|
+
const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
|
|
5078
5145
|
const desc = getDescription(skillPath);
|
|
5079
5146
|
console.log(` ${icon} ${chalk5.bold(skillPath)}`);
|
|
5080
5147
|
console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -5084,7 +5151,7 @@ function printSetupSummary(setup) {
|
|
|
5084
5151
|
}
|
|
5085
5152
|
if (cursor) {
|
|
5086
5153
|
if (cursor.cursorrules) {
|
|
5087
|
-
const icon =
|
|
5154
|
+
const icon = fs20.existsSync(".cursorrules") ? chalk5.yellow("~") : chalk5.green("+");
|
|
5088
5155
|
const desc = getDescription(".cursorrules");
|
|
5089
5156
|
console.log(` ${icon} ${chalk5.bold(".cursorrules")}`);
|
|
5090
5157
|
if (desc) console.log(chalk5.dim(` ${desc}`));
|
|
@@ -5094,7 +5161,7 @@ function printSetupSummary(setup) {
|
|
|
5094
5161
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
5095
5162
|
for (const skill of cursorSkills) {
|
|
5096
5163
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
5097
|
-
const icon =
|
|
5164
|
+
const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
|
|
5098
5165
|
const desc = getDescription(skillPath);
|
|
5099
5166
|
console.log(` ${icon} ${chalk5.bold(skillPath)}`);
|
|
5100
5167
|
console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -5105,7 +5172,7 @@ function printSetupSummary(setup) {
|
|
|
5105
5172
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
5106
5173
|
for (const rule of rules) {
|
|
5107
5174
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
5108
|
-
const icon =
|
|
5175
|
+
const icon = fs20.existsSync(rulePath) ? chalk5.yellow("~") : chalk5.green("+");
|
|
5109
5176
|
const desc = getDescription(rulePath);
|
|
5110
5177
|
console.log(` ${icon} ${chalk5.bold(rulePath)}`);
|
|
5111
5178
|
if (desc) {
|
|
@@ -5118,7 +5185,7 @@ function printSetupSummary(setup) {
|
|
|
5118
5185
|
}
|
|
5119
5186
|
}
|
|
5120
5187
|
}
|
|
5121
|
-
if (!codex && !
|
|
5188
|
+
if (!codex && !fs20.existsSync("AGENTS.md")) {
|
|
5122
5189
|
console.log(` ${chalk5.green("+")} ${chalk5.bold("AGENTS.md")}`);
|
|
5123
5190
|
console.log(chalk5.dim(" Cross-agent coordination file"));
|
|
5124
5191
|
console.log("");
|
|
@@ -5133,21 +5200,12 @@ function printSetupSummary(setup) {
|
|
|
5133
5200
|
console.log(` ${chalk5.green("+")} ${chalk5.dim("new")} ${chalk5.yellow("~")} ${chalk5.dim("modified")} ${chalk5.red("-")} ${chalk5.dim("removed")}`);
|
|
5134
5201
|
console.log("");
|
|
5135
5202
|
}
|
|
5136
|
-
function buildSkillContent(skill) {
|
|
5137
|
-
const frontmatter = `---
|
|
5138
|
-
name: ${skill.name}
|
|
5139
|
-
description: ${skill.description}
|
|
5140
|
-
---
|
|
5141
|
-
|
|
5142
|
-
`;
|
|
5143
|
-
return frontmatter + skill.content;
|
|
5144
|
-
}
|
|
5145
5203
|
function ensurePermissions() {
|
|
5146
5204
|
const settingsPath = ".claude/settings.json";
|
|
5147
5205
|
let settings = {};
|
|
5148
5206
|
try {
|
|
5149
|
-
if (
|
|
5150
|
-
settings = JSON.parse(
|
|
5207
|
+
if (fs20.existsSync(settingsPath)) {
|
|
5208
|
+
settings = JSON.parse(fs20.readFileSync(settingsPath, "utf-8"));
|
|
5151
5209
|
}
|
|
5152
5210
|
} catch {
|
|
5153
5211
|
}
|
|
@@ -5161,64 +5219,8 @@ function ensurePermissions() {
|
|
|
5161
5219
|
"Bash(git *)"
|
|
5162
5220
|
];
|
|
5163
5221
|
settings.permissions = permissions;
|
|
5164
|
-
if (!
|
|
5165
|
-
|
|
5166
|
-
}
|
|
5167
|
-
function collectSetupFiles(setup) {
|
|
5168
|
-
const files = [];
|
|
5169
|
-
const claude = setup.claude;
|
|
5170
|
-
const cursor = setup.cursor;
|
|
5171
|
-
const codex = setup.codex;
|
|
5172
|
-
if (claude) {
|
|
5173
|
-
if (claude.claudeMd) files.push({ path: "CLAUDE.md", content: claude.claudeMd });
|
|
5174
|
-
const skills = claude.skills;
|
|
5175
|
-
if (Array.isArray(skills)) {
|
|
5176
|
-
for (const skill of skills) {
|
|
5177
|
-
files.push({ path: `.claude/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
5178
|
-
}
|
|
5179
|
-
}
|
|
5180
|
-
}
|
|
5181
|
-
if (codex) {
|
|
5182
|
-
if (codex.agentsMd) files.push({ path: "AGENTS.md", content: codex.agentsMd });
|
|
5183
|
-
const codexSkills = codex.skills;
|
|
5184
|
-
if (Array.isArray(codexSkills)) {
|
|
5185
|
-
for (const skill of codexSkills) {
|
|
5186
|
-
files.push({ path: `.agents/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
5187
|
-
}
|
|
5188
|
-
}
|
|
5189
|
-
}
|
|
5190
|
-
if (cursor) {
|
|
5191
|
-
if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
|
|
5192
|
-
const cursorSkills = cursor.skills;
|
|
5193
|
-
if (Array.isArray(cursorSkills)) {
|
|
5194
|
-
for (const skill of cursorSkills) {
|
|
5195
|
-
files.push({ path: `.cursor/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
5196
|
-
}
|
|
5197
|
-
}
|
|
5198
|
-
const rules = cursor.rules;
|
|
5199
|
-
if (Array.isArray(rules)) {
|
|
5200
|
-
for (const rule of rules) {
|
|
5201
|
-
files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
|
|
5202
|
-
}
|
|
5203
|
-
}
|
|
5204
|
-
}
|
|
5205
|
-
const hasCodexAgentsMd = codex && codex.agentsMd;
|
|
5206
|
-
if (!fs19.existsSync("AGENTS.md") && !hasCodexAgentsMd) {
|
|
5207
|
-
const agentRefs = [];
|
|
5208
|
-
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
5209
|
-
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
5210
|
-
if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
|
|
5211
|
-
files.push({
|
|
5212
|
-
path: "AGENTS.md",
|
|
5213
|
-
content: `# AGENTS.md
|
|
5214
|
-
|
|
5215
|
-
This project uses AI coding agents configured by [Caliber](https://github.com/rely-ai-org/caliber).
|
|
5216
|
-
|
|
5217
|
-
${agentRefs.join(" ")}
|
|
5218
|
-
`
|
|
5219
|
-
});
|
|
5220
|
-
}
|
|
5221
|
-
return files;
|
|
5222
|
+
if (!fs20.existsSync(".claude")) fs20.mkdirSync(".claude", { recursive: true });
|
|
5223
|
+
fs20.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
5222
5224
|
}
|
|
5223
5225
|
|
|
5224
5226
|
// src/commands/undo.ts
|
|
@@ -5254,7 +5256,7 @@ function undoCommand() {
|
|
|
5254
5256
|
|
|
5255
5257
|
// src/commands/status.ts
|
|
5256
5258
|
import chalk7 from "chalk";
|
|
5257
|
-
import
|
|
5259
|
+
import fs21 from "fs";
|
|
5258
5260
|
async function statusCommand(options) {
|
|
5259
5261
|
const config = loadConfig();
|
|
5260
5262
|
const manifest = readManifest();
|
|
@@ -5280,7 +5282,7 @@ async function statusCommand(options) {
|
|
|
5280
5282
|
}
|
|
5281
5283
|
console.log(` Files managed: ${chalk7.cyan(manifest.entries.length.toString())}`);
|
|
5282
5284
|
for (const entry of manifest.entries) {
|
|
5283
|
-
const exists =
|
|
5285
|
+
const exists = fs21.existsSync(entry.path);
|
|
5284
5286
|
const icon = exists ? chalk7.green("\u2713") : chalk7.red("\u2717");
|
|
5285
5287
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
5286
5288
|
}
|
|
@@ -5290,11 +5292,11 @@ async function statusCommand(options) {
|
|
|
5290
5292
|
// src/commands/regenerate.ts
|
|
5291
5293
|
import chalk8 from "chalk";
|
|
5292
5294
|
import ora4 from "ora";
|
|
5293
|
-
import
|
|
5295
|
+
import select3 from "@inquirer/select";
|
|
5294
5296
|
async function regenerateCommand(options) {
|
|
5295
5297
|
const config = loadConfig();
|
|
5296
5298
|
if (!config) {
|
|
5297
|
-
console.log(chalk8.red("No LLM provider configured. Run ") + chalk8.hex("#83D1EB")("caliber config") + chalk8.red("
|
|
5299
|
+
console.log(chalk8.red("No LLM provider configured. Run ") + chalk8.hex("#83D1EB")("caliber config") + chalk8.red(" first."));
|
|
5298
5300
|
throw new Error("__exit__");
|
|
5299
5301
|
}
|
|
5300
5302
|
const manifest = readManifest();
|
|
@@ -5302,16 +5304,19 @@ async function regenerateCommand(options) {
|
|
|
5302
5304
|
console.log(chalk8.yellow("No existing setup found. Run ") + chalk8.hex("#83D1EB")("caliber onboard") + chalk8.yellow(" first."));
|
|
5303
5305
|
throw new Error("__exit__");
|
|
5304
5306
|
}
|
|
5305
|
-
const
|
|
5307
|
+
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
5308
|
+
const spinner = ora4("Analyzing project...").start();
|
|
5306
5309
|
const fingerprint = collectFingerprint(process.cwd());
|
|
5307
|
-
|
|
5310
|
+
await enrichFingerprintWithLLM(fingerprint, process.cwd());
|
|
5311
|
+
spinner.succeed("Project analyzed");
|
|
5312
|
+
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5313
|
+
displayScoreSummary(baselineScore);
|
|
5308
5314
|
const genSpinner = ora4("Regenerating setup...").start();
|
|
5309
|
-
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES);
|
|
5315
|
+
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
|
|
5310
5316
|
genMessages.start();
|
|
5311
5317
|
let generatedSetup = null;
|
|
5312
5318
|
try {
|
|
5313
|
-
const
|
|
5314
|
-
const result2 = await generateSetup(
|
|
5319
|
+
const result = await generateSetup(
|
|
5315
5320
|
fingerprint,
|
|
5316
5321
|
targetAgent,
|
|
5317
5322
|
void 0,
|
|
@@ -5328,7 +5333,7 @@ async function regenerateCommand(options) {
|
|
|
5328
5333
|
}
|
|
5329
5334
|
}
|
|
5330
5335
|
);
|
|
5331
|
-
if (!generatedSetup) generatedSetup =
|
|
5336
|
+
if (!generatedSetup) generatedSetup = result.setup;
|
|
5332
5337
|
} catch (err) {
|
|
5333
5338
|
genMessages.stop();
|
|
5334
5339
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -5341,23 +5346,81 @@ async function regenerateCommand(options) {
|
|
|
5341
5346
|
throw new Error("__exit__");
|
|
5342
5347
|
}
|
|
5343
5348
|
genSpinner.succeed("Setup regenerated");
|
|
5349
|
+
const setupFiles = collectSetupFiles(generatedSetup);
|
|
5350
|
+
const staged = stageFiles(setupFiles, process.cwd());
|
|
5351
|
+
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
5352
|
+
console.log(chalk8.dim(`
|
|
5353
|
+
${chalk8.green(`${staged.newFiles} new`)} / ${chalk8.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
5354
|
+
`));
|
|
5355
|
+
if (totalChanges === 0) {
|
|
5356
|
+
console.log(chalk8.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
5357
|
+
cleanupStaging();
|
|
5358
|
+
return;
|
|
5359
|
+
}
|
|
5344
5360
|
if (options.dryRun) {
|
|
5345
|
-
console.log(chalk8.yellow("
|
|
5346
|
-
|
|
5361
|
+
console.log(chalk8.yellow("[Dry run] Would write:"));
|
|
5362
|
+
for (const f of staged.stagedFiles) {
|
|
5363
|
+
console.log(` ${f.isNew ? chalk8.green("+") : chalk8.yellow("~")} ${f.relativePath}`);
|
|
5364
|
+
}
|
|
5365
|
+
cleanupStaging();
|
|
5347
5366
|
return;
|
|
5348
5367
|
}
|
|
5349
|
-
const
|
|
5350
|
-
|
|
5351
|
-
|
|
5368
|
+
const action = await select3({
|
|
5369
|
+
message: "Apply regenerated setup?",
|
|
5370
|
+
choices: [
|
|
5371
|
+
{ name: "Accept and apply", value: "accept" },
|
|
5372
|
+
{ name: "Decline", value: "decline" }
|
|
5373
|
+
]
|
|
5374
|
+
});
|
|
5375
|
+
cleanupStaging();
|
|
5376
|
+
if (action === "decline") {
|
|
5377
|
+
console.log(chalk8.dim("Regeneration cancelled. No files were modified."));
|
|
5352
5378
|
return;
|
|
5353
5379
|
}
|
|
5354
|
-
const writeSpinner = ora4("
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5380
|
+
const writeSpinner = ora4("Writing config files...").start();
|
|
5381
|
+
try {
|
|
5382
|
+
const result = writeSetup(generatedSetup);
|
|
5383
|
+
writeSpinner.succeed("Config files written");
|
|
5384
|
+
for (const file of result.written) {
|
|
5385
|
+
console.log(` ${chalk8.green("\u2713")} ${file}`);
|
|
5386
|
+
}
|
|
5387
|
+
if (result.deleted.length > 0) {
|
|
5388
|
+
for (const file of result.deleted) {
|
|
5389
|
+
console.log(` ${chalk8.red("\u2717")} ${file}`);
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
if (result.backupDir) {
|
|
5393
|
+
console.log(chalk8.dim(`
|
|
5394
|
+
Backups saved to ${result.backupDir}`));
|
|
5395
|
+
}
|
|
5396
|
+
} catch (err) {
|
|
5397
|
+
writeSpinner.fail("Failed to write files");
|
|
5398
|
+
console.error(chalk8.red(err instanceof Error ? err.message : "Unknown error"));
|
|
5399
|
+
throw new Error("__exit__");
|
|
5359
5400
|
}
|
|
5360
|
-
|
|
5401
|
+
const sha = getCurrentHeadSha();
|
|
5402
|
+
writeState({
|
|
5403
|
+
lastRefreshSha: sha ?? "",
|
|
5404
|
+
lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5405
|
+
targetAgent
|
|
5406
|
+
});
|
|
5407
|
+
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5408
|
+
if (afterScore.score < baselineScore.score) {
|
|
5409
|
+
console.log("");
|
|
5410
|
+
console.log(chalk8.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
5411
|
+
try {
|
|
5412
|
+
const { restored, removed } = undoSetup();
|
|
5413
|
+
if (restored.length > 0 || removed.length > 0) {
|
|
5414
|
+
console.log(chalk8.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
5415
|
+
}
|
|
5416
|
+
} catch {
|
|
5417
|
+
}
|
|
5418
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
|
|
5419
|
+
return;
|
|
5420
|
+
}
|
|
5421
|
+
displayScoreDelta(baselineScore, afterScore);
|
|
5422
|
+
console.log(chalk8.bold.green(" Regeneration complete!"));
|
|
5423
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber undo") + chalk8.dim(" to revert changes.\n"));
|
|
5361
5424
|
}
|
|
5362
5425
|
|
|
5363
5426
|
// src/commands/recommend.ts
|
|
@@ -5367,13 +5430,13 @@ import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5,
|
|
|
5367
5430
|
import { join as join8, dirname as dirname2 } from "path";
|
|
5368
5431
|
|
|
5369
5432
|
// src/scanner/index.ts
|
|
5370
|
-
import
|
|
5433
|
+
import fs22 from "fs";
|
|
5371
5434
|
import path17 from "path";
|
|
5372
5435
|
import crypto2 from "crypto";
|
|
5373
5436
|
function scanLocalState(dir) {
|
|
5374
5437
|
const items = [];
|
|
5375
5438
|
const claudeMdPath = path17.join(dir, "CLAUDE.md");
|
|
5376
|
-
if (
|
|
5439
|
+
if (fs22.existsSync(claudeMdPath)) {
|
|
5377
5440
|
items.push({
|
|
5378
5441
|
type: "rule",
|
|
5379
5442
|
platform: "claude",
|
|
@@ -5383,8 +5446,8 @@ function scanLocalState(dir) {
|
|
|
5383
5446
|
});
|
|
5384
5447
|
}
|
|
5385
5448
|
const skillsDir = path17.join(dir, ".claude", "skills");
|
|
5386
|
-
if (
|
|
5387
|
-
for (const file of
|
|
5449
|
+
if (fs22.existsSync(skillsDir)) {
|
|
5450
|
+
for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
|
|
5388
5451
|
const filePath = path17.join(skillsDir, file);
|
|
5389
5452
|
items.push({
|
|
5390
5453
|
type: "skill",
|
|
@@ -5396,9 +5459,9 @@ function scanLocalState(dir) {
|
|
|
5396
5459
|
}
|
|
5397
5460
|
}
|
|
5398
5461
|
const mcpJsonPath = path17.join(dir, ".mcp.json");
|
|
5399
|
-
if (
|
|
5462
|
+
if (fs22.existsSync(mcpJsonPath)) {
|
|
5400
5463
|
try {
|
|
5401
|
-
const mcpJson = JSON.parse(
|
|
5464
|
+
const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
|
|
5402
5465
|
if (mcpJson.mcpServers) {
|
|
5403
5466
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
5404
5467
|
items.push({
|
|
@@ -5414,7 +5477,7 @@ function scanLocalState(dir) {
|
|
|
5414
5477
|
}
|
|
5415
5478
|
}
|
|
5416
5479
|
const agentsMdPath = path17.join(dir, "AGENTS.md");
|
|
5417
|
-
if (
|
|
5480
|
+
if (fs22.existsSync(agentsMdPath)) {
|
|
5418
5481
|
items.push({
|
|
5419
5482
|
type: "rule",
|
|
5420
5483
|
platform: "codex",
|
|
@@ -5424,11 +5487,11 @@ function scanLocalState(dir) {
|
|
|
5424
5487
|
});
|
|
5425
5488
|
}
|
|
5426
5489
|
const codexSkillsDir = path17.join(dir, ".agents", "skills");
|
|
5427
|
-
if (
|
|
5490
|
+
if (fs22.existsSync(codexSkillsDir)) {
|
|
5428
5491
|
try {
|
|
5429
|
-
for (const name of
|
|
5492
|
+
for (const name of fs22.readdirSync(codexSkillsDir)) {
|
|
5430
5493
|
const skillFile = path17.join(codexSkillsDir, name, "SKILL.md");
|
|
5431
|
-
if (
|
|
5494
|
+
if (fs22.existsSync(skillFile)) {
|
|
5432
5495
|
items.push({
|
|
5433
5496
|
type: "skill",
|
|
5434
5497
|
platform: "codex",
|
|
@@ -5442,7 +5505,7 @@ function scanLocalState(dir) {
|
|
|
5442
5505
|
}
|
|
5443
5506
|
}
|
|
5444
5507
|
const cursorrulesPath = path17.join(dir, ".cursorrules");
|
|
5445
|
-
if (
|
|
5508
|
+
if (fs22.existsSync(cursorrulesPath)) {
|
|
5446
5509
|
items.push({
|
|
5447
5510
|
type: "rule",
|
|
5448
5511
|
platform: "cursor",
|
|
@@ -5452,8 +5515,8 @@ function scanLocalState(dir) {
|
|
|
5452
5515
|
});
|
|
5453
5516
|
}
|
|
5454
5517
|
const cursorRulesDir = path17.join(dir, ".cursor", "rules");
|
|
5455
|
-
if (
|
|
5456
|
-
for (const file of
|
|
5518
|
+
if (fs22.existsSync(cursorRulesDir)) {
|
|
5519
|
+
for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
|
|
5457
5520
|
const filePath = path17.join(cursorRulesDir, file);
|
|
5458
5521
|
items.push({
|
|
5459
5522
|
type: "rule",
|
|
@@ -5465,11 +5528,11 @@ function scanLocalState(dir) {
|
|
|
5465
5528
|
}
|
|
5466
5529
|
}
|
|
5467
5530
|
const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
|
|
5468
|
-
if (
|
|
5531
|
+
if (fs22.existsSync(cursorSkillsDir)) {
|
|
5469
5532
|
try {
|
|
5470
|
-
for (const name of
|
|
5533
|
+
for (const name of fs22.readdirSync(cursorSkillsDir)) {
|
|
5471
5534
|
const skillFile = path17.join(cursorSkillsDir, name, "SKILL.md");
|
|
5472
|
-
if (
|
|
5535
|
+
if (fs22.existsSync(skillFile)) {
|
|
5473
5536
|
items.push({
|
|
5474
5537
|
type: "skill",
|
|
5475
5538
|
platform: "cursor",
|
|
@@ -5483,9 +5546,9 @@ function scanLocalState(dir) {
|
|
|
5483
5546
|
}
|
|
5484
5547
|
}
|
|
5485
5548
|
const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
|
|
5486
|
-
if (
|
|
5549
|
+
if (fs22.existsSync(cursorMcpPath)) {
|
|
5487
5550
|
try {
|
|
5488
|
-
const mcpJson = JSON.parse(
|
|
5551
|
+
const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
|
|
5489
5552
|
if (mcpJson.mcpServers) {
|
|
5490
5553
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
5491
5554
|
items.push({
|
|
@@ -5503,7 +5566,7 @@ function scanLocalState(dir) {
|
|
|
5503
5566
|
return items;
|
|
5504
5567
|
}
|
|
5505
5568
|
function hashFile(filePath) {
|
|
5506
|
-
const text =
|
|
5569
|
+
const text = fs22.readFileSync(filePath, "utf-8");
|
|
5507
5570
|
return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
|
|
5508
5571
|
}
|
|
5509
5572
|
function hashJson(obj) {
|
|
@@ -6078,13 +6141,13 @@ async function scoreCommand(options) {
|
|
|
6078
6141
|
} else if (result.score < 70) {
|
|
6079
6142
|
console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to improve your setup."));
|
|
6080
6143
|
} else {
|
|
6081
|
-
console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber
|
|
6144
|
+
console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber regenerate") + chalk10.gray(" to rebuild from scratch."));
|
|
6082
6145
|
}
|
|
6083
6146
|
console.log("");
|
|
6084
6147
|
}
|
|
6085
6148
|
|
|
6086
6149
|
// src/commands/refresh.ts
|
|
6087
|
-
import
|
|
6150
|
+
import fs24 from "fs";
|
|
6088
6151
|
import path19 from "path";
|
|
6089
6152
|
import chalk11 from "chalk";
|
|
6090
6153
|
import ora6 from "ora";
|
|
@@ -6162,37 +6225,37 @@ function collectDiff(lastSha) {
|
|
|
6162
6225
|
}
|
|
6163
6226
|
|
|
6164
6227
|
// src/writers/refresh.ts
|
|
6165
|
-
import
|
|
6228
|
+
import fs23 from "fs";
|
|
6166
6229
|
import path18 from "path";
|
|
6167
6230
|
function writeRefreshDocs(docs) {
|
|
6168
6231
|
const written = [];
|
|
6169
6232
|
if (docs.claudeMd) {
|
|
6170
|
-
|
|
6233
|
+
fs23.writeFileSync("CLAUDE.md", docs.claudeMd);
|
|
6171
6234
|
written.push("CLAUDE.md");
|
|
6172
6235
|
}
|
|
6173
6236
|
if (docs.readmeMd) {
|
|
6174
|
-
|
|
6237
|
+
fs23.writeFileSync("README.md", docs.readmeMd);
|
|
6175
6238
|
written.push("README.md");
|
|
6176
6239
|
}
|
|
6177
6240
|
if (docs.cursorrules) {
|
|
6178
|
-
|
|
6241
|
+
fs23.writeFileSync(".cursorrules", docs.cursorrules);
|
|
6179
6242
|
written.push(".cursorrules");
|
|
6180
6243
|
}
|
|
6181
6244
|
if (docs.cursorRules) {
|
|
6182
6245
|
const rulesDir = path18.join(".cursor", "rules");
|
|
6183
|
-
if (!
|
|
6246
|
+
if (!fs23.existsSync(rulesDir)) fs23.mkdirSync(rulesDir, { recursive: true });
|
|
6184
6247
|
for (const rule of docs.cursorRules) {
|
|
6185
6248
|
const filePath = path18.join(rulesDir, rule.filename);
|
|
6186
|
-
|
|
6249
|
+
fs23.writeFileSync(filePath, rule.content);
|
|
6187
6250
|
written.push(filePath);
|
|
6188
6251
|
}
|
|
6189
6252
|
}
|
|
6190
6253
|
if (docs.claudeSkills) {
|
|
6191
6254
|
const skillsDir = path18.join(".claude", "skills");
|
|
6192
|
-
if (!
|
|
6255
|
+
if (!fs23.existsSync(skillsDir)) fs23.mkdirSync(skillsDir, { recursive: true });
|
|
6193
6256
|
for (const skill of docs.claudeSkills) {
|
|
6194
6257
|
const filePath = path18.join(skillsDir, skill.filename);
|
|
6195
|
-
|
|
6258
|
+
fs23.writeFileSync(filePath, skill.content);
|
|
6196
6259
|
written.push(filePath);
|
|
6197
6260
|
}
|
|
6198
6261
|
}
|
|
@@ -6269,11 +6332,11 @@ function log(quiet, ...args) {
|
|
|
6269
6332
|
function discoverGitRepos(parentDir) {
|
|
6270
6333
|
const repos = [];
|
|
6271
6334
|
try {
|
|
6272
|
-
const entries =
|
|
6335
|
+
const entries = fs24.readdirSync(parentDir, { withFileTypes: true });
|
|
6273
6336
|
for (const entry of entries) {
|
|
6274
6337
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
6275
6338
|
const childPath = path19.join(parentDir, entry.name);
|
|
6276
|
-
if (
|
|
6339
|
+
if (fs24.existsSync(path19.join(childPath, ".git"))) {
|
|
6277
6340
|
repos.push(childPath);
|
|
6278
6341
|
}
|
|
6279
6342
|
}
|
|
@@ -6620,7 +6683,7 @@ function readStdin() {
|
|
|
6620
6683
|
|
|
6621
6684
|
// src/learner/storage.ts
|
|
6622
6685
|
init_constants();
|
|
6623
|
-
import
|
|
6686
|
+
import fs25 from "fs";
|
|
6624
6687
|
import path20 from "path";
|
|
6625
6688
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
6626
6689
|
var DEFAULT_STATE = {
|
|
@@ -6629,8 +6692,8 @@ var DEFAULT_STATE = {
|
|
|
6629
6692
|
lastAnalysisTimestamp: null
|
|
6630
6693
|
};
|
|
6631
6694
|
function ensureLearningDir() {
|
|
6632
|
-
if (!
|
|
6633
|
-
|
|
6695
|
+
if (!fs25.existsSync(LEARNING_DIR)) {
|
|
6696
|
+
fs25.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
6634
6697
|
}
|
|
6635
6698
|
}
|
|
6636
6699
|
function sessionFilePath() {
|
|
@@ -6648,49 +6711,49 @@ function appendEvent(event) {
|
|
|
6648
6711
|
ensureLearningDir();
|
|
6649
6712
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
6650
6713
|
const filePath = sessionFilePath();
|
|
6651
|
-
|
|
6714
|
+
fs25.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
6652
6715
|
const count = getEventCount();
|
|
6653
6716
|
if (count > LEARNING_MAX_EVENTS) {
|
|
6654
|
-
const lines =
|
|
6717
|
+
const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
6655
6718
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
6656
|
-
|
|
6719
|
+
fs25.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
6657
6720
|
}
|
|
6658
6721
|
}
|
|
6659
6722
|
function readAllEvents() {
|
|
6660
6723
|
const filePath = sessionFilePath();
|
|
6661
|
-
if (!
|
|
6662
|
-
const lines =
|
|
6724
|
+
if (!fs25.existsSync(filePath)) return [];
|
|
6725
|
+
const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
6663
6726
|
return lines.map((line) => JSON.parse(line));
|
|
6664
6727
|
}
|
|
6665
6728
|
function getEventCount() {
|
|
6666
6729
|
const filePath = sessionFilePath();
|
|
6667
|
-
if (!
|
|
6668
|
-
const content =
|
|
6730
|
+
if (!fs25.existsSync(filePath)) return 0;
|
|
6731
|
+
const content = fs25.readFileSync(filePath, "utf-8");
|
|
6669
6732
|
return content.split("\n").filter(Boolean).length;
|
|
6670
6733
|
}
|
|
6671
6734
|
function clearSession() {
|
|
6672
6735
|
const filePath = sessionFilePath();
|
|
6673
|
-
if (
|
|
6736
|
+
if (fs25.existsSync(filePath)) fs25.unlinkSync(filePath);
|
|
6674
6737
|
}
|
|
6675
6738
|
function readState2() {
|
|
6676
6739
|
const filePath = stateFilePath();
|
|
6677
|
-
if (!
|
|
6740
|
+
if (!fs25.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
6678
6741
|
try {
|
|
6679
|
-
return JSON.parse(
|
|
6742
|
+
return JSON.parse(fs25.readFileSync(filePath, "utf-8"));
|
|
6680
6743
|
} catch {
|
|
6681
6744
|
return { ...DEFAULT_STATE };
|
|
6682
6745
|
}
|
|
6683
6746
|
}
|
|
6684
6747
|
function writeState2(state) {
|
|
6685
6748
|
ensureLearningDir();
|
|
6686
|
-
|
|
6749
|
+
fs25.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
6687
6750
|
}
|
|
6688
6751
|
function resetState() {
|
|
6689
6752
|
writeState2({ ...DEFAULT_STATE });
|
|
6690
6753
|
}
|
|
6691
6754
|
|
|
6692
6755
|
// src/learner/writer.ts
|
|
6693
|
-
import
|
|
6756
|
+
import fs26 from "fs";
|
|
6694
6757
|
import path21 from "path";
|
|
6695
6758
|
var LEARNED_START = "<!-- caliber:learned -->";
|
|
6696
6759
|
var LEARNED_END = "<!-- /caliber:learned -->";
|
|
@@ -6711,8 +6774,8 @@ function writeLearnedContent(update) {
|
|
|
6711
6774
|
function writeLearnedSection(content) {
|
|
6712
6775
|
const claudeMdPath = "CLAUDE.md";
|
|
6713
6776
|
let existing = "";
|
|
6714
|
-
if (
|
|
6715
|
-
existing =
|
|
6777
|
+
if (fs26.existsSync(claudeMdPath)) {
|
|
6778
|
+
existing = fs26.readFileSync(claudeMdPath, "utf-8");
|
|
6716
6779
|
}
|
|
6717
6780
|
const section = `${LEARNED_START}
|
|
6718
6781
|
${content}
|
|
@@ -6726,15 +6789,15 @@ ${LEARNED_END}`;
|
|
|
6726
6789
|
const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
6727
6790
|
updated = existing + separator + "\n" + section + "\n";
|
|
6728
6791
|
}
|
|
6729
|
-
|
|
6792
|
+
fs26.writeFileSync(claudeMdPath, updated);
|
|
6730
6793
|
}
|
|
6731
6794
|
function writeLearnedSkill(skill) {
|
|
6732
6795
|
const skillDir = path21.join(".claude", "skills", skill.name);
|
|
6733
|
-
if (!
|
|
6796
|
+
if (!fs26.existsSync(skillDir)) fs26.mkdirSync(skillDir, { recursive: true });
|
|
6734
6797
|
const skillPath = path21.join(skillDir, "SKILL.md");
|
|
6735
|
-
if (!skill.isNew &&
|
|
6736
|
-
const existing =
|
|
6737
|
-
|
|
6798
|
+
if (!skill.isNew && fs26.existsSync(skillPath)) {
|
|
6799
|
+
const existing = fs26.readFileSync(skillPath, "utf-8");
|
|
6800
|
+
fs26.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
6738
6801
|
} else {
|
|
6739
6802
|
const frontmatter = [
|
|
6740
6803
|
"---",
|
|
@@ -6743,14 +6806,14 @@ function writeLearnedSkill(skill) {
|
|
|
6743
6806
|
"---",
|
|
6744
6807
|
""
|
|
6745
6808
|
].join("\n");
|
|
6746
|
-
|
|
6809
|
+
fs26.writeFileSync(skillPath, frontmatter + skill.content);
|
|
6747
6810
|
}
|
|
6748
6811
|
return skillPath;
|
|
6749
6812
|
}
|
|
6750
6813
|
function readLearnedSection() {
|
|
6751
6814
|
const claudeMdPath = "CLAUDE.md";
|
|
6752
|
-
if (!
|
|
6753
|
-
const content =
|
|
6815
|
+
if (!fs26.existsSync(claudeMdPath)) return null;
|
|
6816
|
+
const content = fs26.readFileSync(claudeMdPath, "utf-8");
|
|
6754
6817
|
const startIdx = content.indexOf(LEARNED_START);
|
|
6755
6818
|
const endIdx = content.indexOf(LEARNED_END);
|
|
6756
6819
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
@@ -6936,7 +6999,7 @@ Learned items in CLAUDE.md: ${chalk14.cyan(String(lineCount))}`);
|
|
|
6936
6999
|
// src/cli.ts
|
|
6937
7000
|
var __dirname = path22.dirname(fileURLToPath(import.meta.url));
|
|
6938
7001
|
var pkg = JSON.parse(
|
|
6939
|
-
|
|
7002
|
+
fs27.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
6940
7003
|
);
|
|
6941
7004
|
var program = new Command();
|
|
6942
7005
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
@@ -6955,7 +7018,7 @@ function parseAgentOption(value) {
|
|
|
6955
7018
|
program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(initCommand);
|
|
6956
7019
|
program.command("undo").description("Revert all config changes made by Caliber").action(undoCommand);
|
|
6957
7020
|
program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(statusCommand);
|
|
6958
|
-
program.command("regenerate").alias("regen").alias("re").
|
|
7021
|
+
program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(regenerateCommand);
|
|
6959
7022
|
program.command("config").description("Configure LLM provider, API key, and model").action(configCommand);
|
|
6960
7023
|
program.command("recommend").description("Discover and install skill recommendations").option("--generate", "Force fresh recommendation search").action(recommendCommand);
|
|
6961
7024
|
program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).action(scoreCommand);
|
|
@@ -6969,22 +7032,22 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
|
|
|
6969
7032
|
learn.command("status").description("Show learning system status").action(learnStatusCommand);
|
|
6970
7033
|
|
|
6971
7034
|
// src/utils/version-check.ts
|
|
6972
|
-
import
|
|
7035
|
+
import fs28 from "fs";
|
|
6973
7036
|
import path23 from "path";
|
|
6974
7037
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6975
7038
|
import { execSync as execSync9 } from "child_process";
|
|
6976
7039
|
import chalk15 from "chalk";
|
|
6977
7040
|
import ora7 from "ora";
|
|
6978
|
-
import
|
|
7041
|
+
import confirm from "@inquirer/confirm";
|
|
6979
7042
|
var __dirname_vc = path23.dirname(fileURLToPath2(import.meta.url));
|
|
6980
7043
|
var pkg2 = JSON.parse(
|
|
6981
|
-
|
|
7044
|
+
fs28.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
6982
7045
|
);
|
|
6983
7046
|
function getInstalledVersion() {
|
|
6984
7047
|
try {
|
|
6985
7048
|
const globalRoot = execSync9("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
6986
7049
|
const pkgPath = path23.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
6987
|
-
return JSON.parse(
|
|
7050
|
+
return JSON.parse(fs28.readFileSync(pkgPath, "utf-8")).version;
|
|
6988
7051
|
} catch {
|
|
6989
7052
|
return null;
|
|
6990
7053
|
}
|
|
@@ -7020,7 +7083,7 @@ Run ${chalk15.bold("npm install -g @rely-ai/caliber")} to upgrade.
|
|
|
7020
7083
|
chalk15.yellow(`
|
|
7021
7084
|
Update available: ${current} -> ${latest}`)
|
|
7022
7085
|
);
|
|
7023
|
-
const shouldUpdate = await
|
|
7086
|
+
const shouldUpdate = await confirm({ message: "Would you like to update now? (Y/n)", default: true });
|
|
7024
7087
|
if (!shouldUpdate) {
|
|
7025
7088
|
console.log();
|
|
7026
7089
|
return;
|
package/package.json
CHANGED