@rely-ai/caliber 1.39.0 → 1.40.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/README.md +13 -1
- package/dist/bin.js +35 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ Requires **Node.js >= 20**.
|
|
|
51
51
|
npx @rely-ai/caliber bootstrap
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Then, in your
|
|
54
|
+
Then, in your terminal (not the IDE chat), start a Claude Code or Cursor CLI session and type:
|
|
55
55
|
|
|
56
56
|
> **/setup-caliber**
|
|
57
57
|
|
|
@@ -61,6 +61,18 @@ Your agent detects your stack, generates tailored configs for every platform you
|
|
|
61
61
|
|
|
62
62
|
> **Your code stays on your machine.** Bootstrap is 100% local — no LLM calls, no code sent anywhere. Generation uses your own AI subscription or API key. Caliber never sees your code.
|
|
63
63
|
|
|
64
|
+
<details>
|
|
65
|
+
<summary><strong>Windows Users</strong></summary>
|
|
66
|
+
|
|
67
|
+
Caliber works on Windows with a few notes:
|
|
68
|
+
|
|
69
|
+
- **Run from your terminal** (PowerShell, CMD, or Git Bash) — not from inside an IDE chat window. Open a terminal, `cd` into your project folder, then run `npx @rely-ai/caliber bootstrap`.
|
|
70
|
+
- **Git Bash is recommended.** Caliber's pre-commit hooks and auto-sync scripts use shell syntax. Git for Windows includes Git Bash, which handles this automatically. If you only use PowerShell, hooks may be skipped silently.
|
|
71
|
+
- **Cursor Agent CLI:** If prompted to install it, download from [cursor.com/downloads](https://www.cursor.com/downloads) instead of the `curl | bash` command shown on macOS/Linux. Then run `agent login` in your terminal to authenticate.
|
|
72
|
+
- **One terminal at a time.** Avoid running Caliber from multiple terminals simultaneously — this can cause conflicting state and unexpected provider detection.
|
|
73
|
+
|
|
74
|
+
</details>
|
|
75
|
+
|
|
64
76
|
## Audits first, writes second
|
|
65
77
|
|
|
66
78
|
Caliber never overwrites your existing configs without asking. The workflow mirrors code review:
|
package/dist/bin.js
CHANGED
|
@@ -858,7 +858,7 @@ function openDiffsInEditor(editor, files) {
|
|
|
858
858
|
for (const file of files) {
|
|
859
859
|
try {
|
|
860
860
|
const leftPath = file.originalPath ?? getEmptyFilePath(file.proposedPath);
|
|
861
|
-
if (
|
|
861
|
+
if (IS_WINDOWS4) {
|
|
862
862
|
const quote = (s) => `"${s}"`;
|
|
863
863
|
spawn3([cmd, "--diff", quote(leftPath), quote(file.proposedPath)].join(" "), { shell: true, stdio: "ignore", detached: true }).unref();
|
|
864
864
|
} else {
|
|
@@ -869,11 +869,11 @@ function openDiffsInEditor(editor, files) {
|
|
|
869
869
|
}
|
|
870
870
|
}
|
|
871
871
|
}
|
|
872
|
-
var
|
|
872
|
+
var IS_WINDOWS4, DIFF_TEMP_DIR;
|
|
873
873
|
var init_editor = __esm({
|
|
874
874
|
"src/utils/editor.ts"() {
|
|
875
875
|
"use strict";
|
|
876
|
-
|
|
876
|
+
IS_WINDOWS4 = process.platform === "win32";
|
|
877
877
|
DIFF_TEMP_DIR = path25.join(os6.tmpdir(), "caliber-diff");
|
|
878
878
|
}
|
|
879
879
|
});
|
|
@@ -3078,6 +3078,10 @@ async function llmCall(options) {
|
|
|
3078
3078
|
await new Promise((r) => setTimeout(r, 1e3 * Math.pow(2, attempt - 1)));
|
|
3079
3079
|
continue;
|
|
3080
3080
|
}
|
|
3081
|
+
if (isRateLimitError(error.message) && attempt < MAX_RETRIES) {
|
|
3082
|
+
await new Promise((r) => setTimeout(r, 2e3 * Math.pow(2, attempt - 1)));
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3081
3085
|
if (isTransientError(error) && attempt < MAX_RETRIES) {
|
|
3082
3086
|
await new Promise((r) => setTimeout(r, 1e3 * Math.pow(2, attempt - 1)));
|
|
3083
3087
|
continue;
|
|
@@ -6274,6 +6278,7 @@ init_config();
|
|
|
6274
6278
|
import chalk3 from "chalk";
|
|
6275
6279
|
import select2 from "@inquirer/select";
|
|
6276
6280
|
import confirm from "@inquirer/confirm";
|
|
6281
|
+
var IS_WINDOWS3 = process.platform === "win32";
|
|
6277
6282
|
var PROVIDER_CHOICES = [
|
|
6278
6283
|
{ name: "Claude Code \u2014 use your existing subscription (no API key)", value: "claude-cli" },
|
|
6279
6284
|
{ name: "Cursor \u2014 use your existing subscription (no API key)", value: "cursor" },
|
|
@@ -6305,8 +6310,13 @@ async function runInteractiveProviderSetup(options) {
|
|
|
6305
6310
|
case "cursor": {
|
|
6306
6311
|
if (!isCursorAgentAvailable()) {
|
|
6307
6312
|
console.log(chalk3.yellow("\n Cursor Agent CLI not found."));
|
|
6308
|
-
|
|
6309
|
-
|
|
6313
|
+
if (IS_WINDOWS3) {
|
|
6314
|
+
console.log(chalk3.dim(" Install it from: ") + chalk3.hex("#83D1EB")("https://www.cursor.com/downloads"));
|
|
6315
|
+
console.log(chalk3.dim(" Then run ") + chalk3.hex("#83D1EB")("agent login") + chalk3.dim(" in PowerShell to authenticate.\n"));
|
|
6316
|
+
} else {
|
|
6317
|
+
console.log(chalk3.dim(" Install it: ") + chalk3.hex("#83D1EB")("curl https://cursor.com/install -fsS | bash"));
|
|
6318
|
+
console.log(chalk3.dim(" Then run ") + chalk3.hex("#83D1EB")("agent login") + chalk3.dim(" to authenticate.\n"));
|
|
6319
|
+
}
|
|
6310
6320
|
const proceed = await confirm({ message: "Continue anyway?" });
|
|
6311
6321
|
if (!proceed) throw new Error("__exit__");
|
|
6312
6322
|
} else if (!isCursorLoggedIn()) {
|
|
@@ -6611,7 +6621,7 @@ function checkExistence(dir) {
|
|
|
6611
6621
|
earnedPoints: Math.min(skillPoints, maxSkillPoints),
|
|
6612
6622
|
passed: skillCount >= 1,
|
|
6613
6623
|
detail: skillCount === 0 ? "No skills found" : `${skillCount} skill${skillCount === 1 ? "" : "s"} found`,
|
|
6614
|
-
suggestion: skillCount === 0 ? "
|
|
6624
|
+
suggestion: skillCount === 0 ? "Skills are reusable agent workflows (e.g., deploy, test, review). Add 2-3 for your most common tasks" : skillCount < 3 ? "Optimal is 2-3 focused skills" : void 0,
|
|
6615
6625
|
fix: skillCount === 0 ? {
|
|
6616
6626
|
action: "create_skills",
|
|
6617
6627
|
data: { currentCount: 0 },
|
|
@@ -6628,7 +6638,7 @@ function checkExistence(dir) {
|
|
|
6628
6638
|
earnedPoints: mdcCount >= 1 ? POINTS_CURSOR_MDC_RULES : 0,
|
|
6629
6639
|
passed: mdcCount >= 1,
|
|
6630
6640
|
detail: mdcCount === 0 ? "No .mdc rule files" : `${mdcCount} .mdc rule${mdcCount === 1 ? "" : "s"} found`,
|
|
6631
|
-
suggestion: mdcCount === 0 ? "
|
|
6641
|
+
suggestion: mdcCount === 0 ? "Cursor .mdc rules use frontmatter to scope rules to specific files/paths. Add them for more targeted Cursor behavior" : void 0,
|
|
6632
6642
|
fix: mdcCount === 0 ? {
|
|
6633
6643
|
action: "create_mdc_rules",
|
|
6634
6644
|
data: {},
|
|
@@ -6644,7 +6654,7 @@ function checkExistence(dir) {
|
|
|
6644
6654
|
earnedPoints: mcp.count >= 1 ? POINTS_MCP_SERVERS : 0,
|
|
6645
6655
|
passed: mcp.count >= 1,
|
|
6646
6656
|
detail: mcp.count > 0 ? `${mcp.count} server${mcp.count === 1 ? "" : "s"} in ${mcp.sources.join(", ")}` : "No MCP servers configured",
|
|
6647
|
-
suggestion: mcp.count === 0 ? "
|
|
6657
|
+
suggestion: mcp.count === 0 ? "MCP servers connect your agent to external tools (databases, Slack, Linear, etc). Add if your team uses external services" : void 0,
|
|
6648
6658
|
fix: mcp.count === 0 ? {
|
|
6649
6659
|
action: "configure_mcp",
|
|
6650
6660
|
data: {},
|
|
@@ -6713,7 +6723,7 @@ function checkQuality(dir) {
|
|
|
6713
6723
|
earnedPoints: tokenPoints,
|
|
6714
6724
|
passed: tokenPoints >= 4,
|
|
6715
6725
|
detail: totalContent.length === 0 ? "No config files to measure" : `~${totalTokens} tokens total across all config files`,
|
|
6716
|
-
suggestion: tokenPoints < 4 && totalContent.length > 0 ? `
|
|
6726
|
+
suggestion: tokenPoints < 4 && totalContent.length > 0 ? `Config is ~${totalTokens} tokens. Agents work best under ~5000 tokens (~4 pages of text) \u2014 trim verbose sections` : void 0,
|
|
6717
6727
|
fix: tokenPoints < 4 && totalContent.length > 0 ? {
|
|
6718
6728
|
action: "reduce_size",
|
|
6719
6729
|
data: { currentTokens: totalTokens, targetTokens: 5e3 },
|
|
@@ -7157,7 +7167,7 @@ function checkFreshness(dir) {
|
|
|
7157
7167
|
earnedPoints: hasPermissions ? POINTS_PERMISSIONS : 0,
|
|
7158
7168
|
passed: hasPermissions,
|
|
7159
7169
|
detail: permissionDetail,
|
|
7160
|
-
suggestion: hasPermissions ? void 0 : "
|
|
7170
|
+
suggestion: hasPermissions ? void 0 : "Permissions control which shell commands the agent can run without asking. Adds a safety layer for your team",
|
|
7161
7171
|
fix: hasPermissions ? void 0 : {
|
|
7162
7172
|
action: "add_permissions",
|
|
7163
7173
|
data: {},
|
|
@@ -7222,7 +7232,7 @@ function checkBonus(dir) {
|
|
|
7222
7232
|
earnedPoints: hasHooks ? POINTS_HOOKS : 0,
|
|
7223
7233
|
passed: hasHooks,
|
|
7224
7234
|
detail: hasHooks ? hookSources.join(", ") : "No hooks configured",
|
|
7225
|
-
suggestion: hasHooks ? void 0 : `Run \`${resolveCaliber()} init\` to
|
|
7235
|
+
suggestion: hasHooks ? void 0 : `Hooks auto-sync your agent config on every commit so it stays fresh. Run \`${resolveCaliber()} init\` to set up`,
|
|
7226
7236
|
fix: hasHooks ? void 0 : {
|
|
7227
7237
|
action: "install_hooks",
|
|
7228
7238
|
data: {},
|
|
@@ -7238,7 +7248,7 @@ function checkBonus(dir) {
|
|
|
7238
7248
|
earnedPoints: agentsMdExists ? POINTS_AGENTS_MD : 0,
|
|
7239
7249
|
passed: agentsMdExists,
|
|
7240
7250
|
detail: agentsMdExists ? "Found at project root" : "Not found",
|
|
7241
|
-
suggestion: agentsMdExists ? void 0 : "
|
|
7251
|
+
suggestion: agentsMdExists ? void 0 : "AGENTS.md provides project context to Codex, Copilot, and other agents. Works alongside CLAUDE.md",
|
|
7242
7252
|
fix: agentsMdExists ? void 0 : {
|
|
7243
7253
|
action: "create_file",
|
|
7244
7254
|
data: { file: "AGENTS.md" },
|
|
@@ -7274,7 +7284,7 @@ function checkBonus(dir) {
|
|
|
7274
7284
|
earnedPoints: allOpenSkills ? POINTS_OPEN_SKILLS_FORMAT : 0,
|
|
7275
7285
|
passed: allOpenSkills || totalSkillFiles === 0,
|
|
7276
7286
|
detail: totalSkillFiles === 0 ? "No skills to check" : allOpenSkills ? `All ${totalSkillFiles} skill${totalSkillFiles === 1 ? "" : "s"} use SKILL.md with frontmatter` : `${openSkillsCount}/${totalSkillFiles} use OpenSkills format`,
|
|
7277
|
-
suggestion: totalSkillFiles > 0 && !allOpenSkills ? "
|
|
7287
|
+
suggestion: totalSkillFiles > 0 && !allOpenSkills ? "OpenSkills format (SKILL.md with YAML header) makes skills portable across agents. Migrate for cross-tool compatibility" : void 0,
|
|
7278
7288
|
fix: totalSkillFiles > 0 && !allOpenSkills ? {
|
|
7279
7289
|
action: "migrate_skills",
|
|
7280
7290
|
data: { openSkills: openSkillsCount, total: totalSkillFiles },
|
|
@@ -7291,7 +7301,7 @@ function checkBonus(dir) {
|
|
|
7291
7301
|
earnedPoints: hasLearned ? POINTS_LEARNED_CONTENT : 0,
|
|
7292
7302
|
passed: hasLearned,
|
|
7293
7303
|
detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
|
|
7294
|
-
suggestion: hasLearned ? void 0 : `
|
|
7304
|
+
suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${resolveCaliber()} learn install\``
|
|
7295
7305
|
});
|
|
7296
7306
|
return checks;
|
|
7297
7307
|
}
|
|
@@ -7532,7 +7542,7 @@ function displayScore(result) {
|
|
|
7532
7542
|
formatTopImprovements(result.checks);
|
|
7533
7543
|
}
|
|
7534
7544
|
function formatTopImprovements(checks) {
|
|
7535
|
-
const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({ name: c.name, potential: c.maxPoints - c.earnedPoints })).sort((a, b) => b.potential - a.potential).slice(0, 5);
|
|
7545
|
+
const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({ name: c.name, potential: c.maxPoints - c.earnedPoints, suggestion: c.suggestion })).sort((a, b) => b.potential - a.potential).slice(0, 5);
|
|
7536
7546
|
if (improvable.length === 0) return;
|
|
7537
7547
|
console.log(chalk4.gray(" \u2500 TOP IMPROVEMENTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
7538
7548
|
console.log("");
|
|
@@ -7542,6 +7552,9 @@ function formatTopImprovements(checks) {
|
|
|
7542
7552
|
const label = chalk4.white(item.name.padEnd(42));
|
|
7543
7553
|
const pts = chalk4.yellow(`+${item.potential} pts`);
|
|
7544
7554
|
console.log(` ${num} ${label}${pts}`);
|
|
7555
|
+
if (item.suggestion) {
|
|
7556
|
+
console.log(chalk4.gray(` ${item.suggestion}`));
|
|
7557
|
+
}
|
|
7545
7558
|
}
|
|
7546
7559
|
console.log("");
|
|
7547
7560
|
}
|
|
@@ -10097,6 +10110,7 @@ function getScoreTrend(entries) {
|
|
|
10097
10110
|
}
|
|
10098
10111
|
|
|
10099
10112
|
// src/commands/init.ts
|
|
10113
|
+
var IS_WINDOWS5 = process.platform === "win32";
|
|
10100
10114
|
function log(verbose, ...args) {
|
|
10101
10115
|
if (verbose) console.log(chalk14.dim(` [verbose] ${args.map(String).join(" ")}`));
|
|
10102
10116
|
}
|
|
@@ -10232,6 +10246,10 @@ async function initCommand(options) {
|
|
|
10232
10246
|
console.log(` ${chalk14.green("\u2713")} Onboarding hook \u2014 nudges new team members to set up`);
|
|
10233
10247
|
installSessionStartHook();
|
|
10234
10248
|
console.log(` ${chalk14.green("\u2713")} Freshness hook \u2014 warns when configs are stale`);
|
|
10249
|
+
if (IS_WINDOWS5) {
|
|
10250
|
+
console.log(chalk14.yellow("\n Note: hooks use shell syntax and require Git Bash (included with Git for Windows)."));
|
|
10251
|
+
console.log(chalk14.dim(" If hooks don't run, ensure Git for Windows is installed and git is using its bundled sh."));
|
|
10252
|
+
}
|
|
10235
10253
|
const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
|
|
10236
10254
|
for (const agent of targetAgent) {
|
|
10237
10255
|
if (agent === "claude" && !fs34.existsSync(".claude"))
|
|
@@ -11209,12 +11227,12 @@ async function scoreCommand(options) {
|
|
|
11209
11227
|
chalk18.gray(" Biggest gain: ") + chalk18.yellow(`+${pts} pts`) + chalk18.gray(` from "${topFix.name}"`) + (topFix.suggestion ? chalk18.gray(` \u2014 ${topFix.suggestion}`) : "")
|
|
11210
11228
|
);
|
|
11211
11229
|
console.log(
|
|
11212
|
-
chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to
|
|
11230
|
+
chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate or update your agent config files.")
|
|
11213
11231
|
);
|
|
11214
11232
|
} else if (failing.length > 0) {
|
|
11215
11233
|
console.log(
|
|
11216
11234
|
chalk18.green(" Looking good!") + chalk18.gray(
|
|
11217
|
-
` ${failing.length}
|
|
11235
|
+
` ${failing.length} optional improvement${failing.length === 1 ? "" : "s"} available.`
|
|
11218
11236
|
)
|
|
11219
11237
|
);
|
|
11220
11238
|
console.log(
|
package/package.json
CHANGED