@rely-ai/caliber 0.2.0 → 0.2.2
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 +70 -36
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1002,12 +1002,12 @@ SCORING CRITERIA \u2014 your output is scored deterministically. Optimize for 10
|
|
|
1002
1002
|
|
|
1003
1003
|
Existence (25 pts):
|
|
1004
1004
|
- CLAUDE.md exists (6 pts) \u2014 always generate
|
|
1005
|
-
- Skills configured (8 pts) \u2014
|
|
1005
|
+
- Skills configured (8 pts) \u2014 generate exactly 3 focused skills for full points (6 base + 1 per extra, cap 2). Two skills = 7 pts, three = 8 pts.
|
|
1006
1006
|
- MCP servers mentioned (3 pts) \u2014 reference detected MCP integrations
|
|
1007
1007
|
- For "both" target: .cursorrules/.cursor/rules/ exist (3+3 pts), cross-platform parity (2 pts)
|
|
1008
1008
|
|
|
1009
1009
|
Quality (25 pts):
|
|
1010
|
-
- Build/test/lint commands documented (8 pts) \u2014 include actual
|
|
1010
|
+
- Build/test/lint commands documented (8 pts) \u2014 include actual commands from the project
|
|
1011
1011
|
- Concise context files (6 pts) \u2014 keep CLAUDE.md under 100 lines for full points (200=4pts, 300=3pts, 500+=0pts)
|
|
1012
1012
|
- No vague instructions (4 pts) \u2014 avoid "follow best practices", "write clean code", "ensure quality"
|
|
1013
1013
|
- No directory tree listings (3 pts) \u2014 do NOT include tree-style file listings in code blocks
|
|
@@ -1018,8 +1018,12 @@ Coverage (20 pts):
|
|
|
1018
1018
|
- Service/MCP coverage (6 pts) \u2014 reference detected services (DB, cloud, etc.)
|
|
1019
1019
|
- MCP completeness (4 pts) \u2014 full points if no external services detected
|
|
1020
1020
|
|
|
1021
|
-
Accuracy (15 pts):
|
|
1022
|
-
- Documented commands exist (6 pts) \u2014
|
|
1021
|
+
Accuracy (15 pts) \u2014 THIS IS CRITICAL, READ CAREFULLY:
|
|
1022
|
+
- Documented commands exist (6 pts) \u2014 the scoring system validates EVERY command you write against the project's actual package.json scripts, Makefile targets, or Cargo.toml. If you write "yarn build" but there is no "build" script in package.json, you LOSE points. Rules:
|
|
1023
|
+
* Look at the "scripts" section in the provided package.json. ONLY reference scripts that exist there.
|
|
1024
|
+
* If a project uses Makefiles, only reference targets that exist in the Makefile.
|
|
1025
|
+
* If there are no build/test scripts, do NOT invent them. Document what actually exists.
|
|
1026
|
+
* Use the exact package manager the project uses (npm/yarn/pnpm/bun) \u2014 check the lockfile.
|
|
1023
1027
|
- Documented paths exist (4 pts) \u2014 ONLY reference file paths from the provided file tree. Never guess paths.
|
|
1024
1028
|
- Config freshness (5 pts) \u2014 config must match current code state
|
|
1025
1029
|
|
|
@@ -1032,7 +1036,7 @@ Bonus (5 pts):
|
|
|
1032
1036
|
|
|
1033
1037
|
OUTPUT SIZE CONSTRAINTS \u2014 these are critical:
|
|
1034
1038
|
- CLAUDE.md: MUST be under 100 lines for maximum score. Aim for 70-90 lines. Be extremely concise \u2014 only commands, architecture overview, and key conventions. Use bullet points and tables, not prose.
|
|
1035
|
-
- Skills:
|
|
1039
|
+
- Skills: generate exactly 3 skills per target platform. Only go above 3 for large multi-framework projects.
|
|
1036
1040
|
- Each skill content: max 150 lines. Focus on patterns and examples, not exhaustive docs.
|
|
1037
1041
|
- Cursor rules: max 5 .mdc files.
|
|
1038
1042
|
- If the project is large, prioritize depth on the 3-4 most critical tools over breadth across everything.`;
|
|
@@ -3103,6 +3107,7 @@ function checkFreshness(dir) {
|
|
|
3103
3107
|
|
|
3104
3108
|
// src/scoring/checks/bonus.ts
|
|
3105
3109
|
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
|
|
3110
|
+
import { execSync as execSync5 } from "child_process";
|
|
3106
3111
|
import { join as join6 } from "path";
|
|
3107
3112
|
function readFileOrNull5(path23) {
|
|
3108
3113
|
try {
|
|
@@ -3111,27 +3116,39 @@ function readFileOrNull5(path23) {
|
|
|
3111
3116
|
return null;
|
|
3112
3117
|
}
|
|
3113
3118
|
}
|
|
3119
|
+
function hasPreCommitHook(dir) {
|
|
3120
|
+
try {
|
|
3121
|
+
const gitDir = execSync5("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3122
|
+
const hookPath = join6(gitDir, "hooks", "pre-commit");
|
|
3123
|
+
const content = readFileOrNull5(hookPath);
|
|
3124
|
+
return content ? content.includes("caliber") : false;
|
|
3125
|
+
} catch {
|
|
3126
|
+
return false;
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3114
3129
|
function checkBonus(dir) {
|
|
3115
3130
|
const checks = [];
|
|
3116
|
-
let
|
|
3117
|
-
let
|
|
3131
|
+
let hasClaudeHooks = false;
|
|
3132
|
+
let hasPrecommit = false;
|
|
3133
|
+
const hookSources = [];
|
|
3118
3134
|
const settingsContent = readFileOrNull5(join6(dir, ".claude", "settings.json"));
|
|
3119
3135
|
if (settingsContent) {
|
|
3120
3136
|
try {
|
|
3121
3137
|
const settings = JSON.parse(settingsContent);
|
|
3122
3138
|
const hooks2 = settings.hooks;
|
|
3123
3139
|
if (hooks2 && Object.keys(hooks2).length > 0) {
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
} else {
|
|
3127
|
-
hookDetail = "No hooks in settings.json";
|
|
3140
|
+
hasClaudeHooks = true;
|
|
3141
|
+
hookSources.push(`Claude Code: ${Object.keys(hooks2).join(", ")}`);
|
|
3128
3142
|
}
|
|
3129
3143
|
} catch {
|
|
3130
|
-
hookDetail = "settings.json is not valid JSON";
|
|
3131
3144
|
}
|
|
3132
|
-
} else {
|
|
3133
|
-
hookDetail = "No .claude/settings.json";
|
|
3134
3145
|
}
|
|
3146
|
+
hasPrecommit = hasPreCommitHook(dir);
|
|
3147
|
+
if (hasPrecommit) {
|
|
3148
|
+
hookSources.push("git pre-commit");
|
|
3149
|
+
}
|
|
3150
|
+
const hasHooks = hasClaudeHooks || hasPrecommit;
|
|
3151
|
+
const hookDetail = hasHooks ? hookSources.join(", ") : settingsContent ? "No hooks in settings.json" : "No hooks configured";
|
|
3135
3152
|
checks.push({
|
|
3136
3153
|
id: "hooks_configured",
|
|
3137
3154
|
name: "Hooks configured",
|
|
@@ -3140,7 +3157,7 @@ function checkBonus(dir) {
|
|
|
3140
3157
|
earnedPoints: hasHooks ? POINTS_HOOKS : 0,
|
|
3141
3158
|
passed: hasHooks,
|
|
3142
3159
|
detail: hookDetail,
|
|
3143
|
-
suggestion: hasHooks ? void 0 : "
|
|
3160
|
+
suggestion: hasHooks ? void 0 : "Run `caliber hooks install` or `caliber hooks install-precommit` for auto-refresh"
|
|
3144
3161
|
});
|
|
3145
3162
|
const agentsMdExists = existsSync7(join6(dir, "AGENTS.md"));
|
|
3146
3163
|
checks.push({
|
|
@@ -3374,10 +3391,10 @@ async function initCommand(options) {
|
|
|
3374
3391
|
console.log(chalk3.dim(" against your actual codebase \u2014 keeping what works, fixing"));
|
|
3375
3392
|
console.log(chalk3.dim(" what's stale, and adding what's missing.\n"));
|
|
3376
3393
|
console.log(chalk3.bold(" How it works:\n"));
|
|
3377
|
-
console.log(chalk3.dim(" 1. Scan Analyze your code, dependencies, and
|
|
3378
|
-
console.log(chalk3.dim(" 2. Generate AI creates config files
|
|
3379
|
-
console.log(chalk3.dim(" 3. Review You accept, refine, or decline the
|
|
3380
|
-
console.log(chalk3.dim(" 4. Apply Config files are written
|
|
3394
|
+
console.log(chalk3.dim(" 1. Scan Analyze your code, dependencies, and existing configs"));
|
|
3395
|
+
console.log(chalk3.dim(" 2. Generate AI creates or improves config files for your project"));
|
|
3396
|
+
console.log(chalk3.dim(" 3. Review You accept, refine, or decline the proposed changes"));
|
|
3397
|
+
console.log(chalk3.dim(" 4. Apply Config files are written with backups\n"));
|
|
3381
3398
|
console.log(chalk3.hex("#6366f1").bold(" Step 1/4 \u2014 Check LLM provider\n"));
|
|
3382
3399
|
const config = loadConfig();
|
|
3383
3400
|
if (!config) {
|
|
@@ -3392,7 +3409,7 @@ async function initCommand(options) {
|
|
|
3392
3409
|
console.log(chalk3.dim(` Provider: ${config.provider} | Model: ${config.model}
|
|
3393
3410
|
`));
|
|
3394
3411
|
console.log(chalk3.hex("#6366f1").bold(" Step 2/4 \u2014 Scan project\n"));
|
|
3395
|
-
console.log(chalk3.dim(" Detecting languages,
|
|
3412
|
+
console.log(chalk3.dim(" Detecting languages, dependencies, file structure, and existing configs.\n"));
|
|
3396
3413
|
const spinner = ora("Analyzing project...").start();
|
|
3397
3414
|
const fingerprint = collectFingerprint(process.cwd());
|
|
3398
3415
|
await enrichFingerprintWithLLM(fingerprint, process.cwd());
|
|
@@ -3406,11 +3423,16 @@ async function initCommand(options) {
|
|
|
3406
3423
|
if (isEmpty) {
|
|
3407
3424
|
fingerprint.description = await promptInput("What will you build in this project?");
|
|
3408
3425
|
}
|
|
3409
|
-
console.log(chalk3.hex("#6366f1").bold(" Step 3/4 \u2014 Auditing your configs\n"));
|
|
3410
|
-
console.log(chalk3.dim(" AI is auditing your CLAUDE.md, skills, and rules against your"));
|
|
3411
|
-
console.log(chalk3.dim(" project's actual codebase and conventions.\n"));
|
|
3412
|
-
console.log(chalk3.dim(" This usually takes 1\u20133 minutes on first run.\n"));
|
|
3413
3426
|
const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length);
|
|
3427
|
+
if (hasExistingConfig) {
|
|
3428
|
+
console.log(chalk3.hex("#6366f1").bold(" Step 3/4 \u2014 Auditing your configs\n"));
|
|
3429
|
+
console.log(chalk3.dim(" AI is reviewing your existing configs against your codebase"));
|
|
3430
|
+
console.log(chalk3.dim(" and suggesting improvements.\n"));
|
|
3431
|
+
} else {
|
|
3432
|
+
console.log(chalk3.hex("#6366f1").bold(" Step 3/4 \u2014 Generating configs\n"));
|
|
3433
|
+
console.log(chalk3.dim(" AI is creating agent config files tailored to your project.\n"));
|
|
3434
|
+
}
|
|
3435
|
+
console.log(chalk3.dim(" This usually takes 1\u20133 minutes.\n"));
|
|
3414
3436
|
const genStartTime = Date.now();
|
|
3415
3437
|
const genSpinner = ora("Generating setup...").start();
|
|
3416
3438
|
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
|
|
@@ -3931,9 +3953,10 @@ async function regenerateCommand(options) {
|
|
|
3931
3953
|
genMessages.start();
|
|
3932
3954
|
let generatedSetup = null;
|
|
3933
3955
|
try {
|
|
3956
|
+
const targetAgent = readState()?.targetAgent ?? "both";
|
|
3934
3957
|
const result2 = await generateSetup(
|
|
3935
3958
|
fingerprint,
|
|
3936
|
-
|
|
3959
|
+
targetAgent,
|
|
3937
3960
|
void 0,
|
|
3938
3961
|
{
|
|
3939
3962
|
onStatus: (status) => {
|
|
@@ -3983,7 +4006,7 @@ async function regenerateCommand(options) {
|
|
|
3983
4006
|
// src/commands/recommend.ts
|
|
3984
4007
|
import chalk7 from "chalk";
|
|
3985
4008
|
import ora4 from "ora";
|
|
3986
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
4009
|
+
import { mkdirSync, readFileSync as readFileSync7, existsSync as existsSync9, writeFileSync } from "fs";
|
|
3987
4010
|
import { join as join8, dirname as dirname2 } from "path";
|
|
3988
4011
|
|
|
3989
4012
|
// src/scanner/index.ts
|
|
@@ -4145,15 +4168,26 @@ async function searchSkills(technologies) {
|
|
|
4145
4168
|
}
|
|
4146
4169
|
return results;
|
|
4147
4170
|
}
|
|
4171
|
+
function extractTopDeps() {
|
|
4172
|
+
const pkgPath = join8(process.cwd(), "package.json");
|
|
4173
|
+
if (!existsSync9(pkgPath)) return [];
|
|
4174
|
+
try {
|
|
4175
|
+
const pkg3 = JSON.parse(readFileSync7(pkgPath, "utf-8"));
|
|
4176
|
+
return Object.keys(pkg3.dependencies ?? {});
|
|
4177
|
+
} catch {
|
|
4178
|
+
return [];
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4148
4181
|
async function recommendCommand(options) {
|
|
4149
4182
|
const fingerprint = collectFingerprint(process.cwd());
|
|
4150
4183
|
const platforms = detectLocalPlatforms();
|
|
4151
|
-
const technologies = [
|
|
4184
|
+
const technologies = [...new Set([
|
|
4152
4185
|
...fingerprint.languages,
|
|
4153
|
-
...fingerprint.frameworks
|
|
4154
|
-
|
|
4186
|
+
...fingerprint.frameworks,
|
|
4187
|
+
...extractTopDeps()
|
|
4188
|
+
].filter(Boolean))];
|
|
4155
4189
|
if (technologies.length === 0) {
|
|
4156
|
-
console.log(chalk7.yellow("Could not detect any languages or
|
|
4190
|
+
console.log(chalk7.yellow("Could not detect any languages or dependencies. Try running from a project root."));
|
|
4157
4191
|
throw new Error("__exit__");
|
|
4158
4192
|
}
|
|
4159
4193
|
const spinner = ora4("Searching for skills...").start();
|
|
@@ -4350,7 +4384,7 @@ import chalk9 from "chalk";
|
|
|
4350
4384
|
import ora5 from "ora";
|
|
4351
4385
|
|
|
4352
4386
|
// src/lib/git-diff.ts
|
|
4353
|
-
import { execSync as
|
|
4387
|
+
import { execSync as execSync6 } from "child_process";
|
|
4354
4388
|
var MAX_DIFF_BYTES = 1e5;
|
|
4355
4389
|
var DOC_PATTERNS = [
|
|
4356
4390
|
"CLAUDE.md",
|
|
@@ -4364,7 +4398,7 @@ function excludeArgs() {
|
|
|
4364
4398
|
}
|
|
4365
4399
|
function safeExec(cmd) {
|
|
4366
4400
|
try {
|
|
4367
|
-
return
|
|
4401
|
+
return execSync6(cmd, {
|
|
4368
4402
|
encoding: "utf-8",
|
|
4369
4403
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4370
4404
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -5163,7 +5197,7 @@ learn.command("status").description("Show learning system status").action(learnS
|
|
|
5163
5197
|
import fs25 from "fs";
|
|
5164
5198
|
import path22 from "path";
|
|
5165
5199
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5166
|
-
import { execSync as
|
|
5200
|
+
import { execSync as execSync7 } from "child_process";
|
|
5167
5201
|
import chalk13 from "chalk";
|
|
5168
5202
|
import ora6 from "ora";
|
|
5169
5203
|
import confirm2 from "@inquirer/confirm";
|
|
@@ -5173,7 +5207,7 @@ var pkg2 = JSON.parse(
|
|
|
5173
5207
|
);
|
|
5174
5208
|
function getInstalledVersion() {
|
|
5175
5209
|
try {
|
|
5176
|
-
const globalRoot =
|
|
5210
|
+
const globalRoot = execSync7("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
5177
5211
|
const pkgPath = path22.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
5178
5212
|
return JSON.parse(fs25.readFileSync(pkgPath, "utf-8")).version;
|
|
5179
5213
|
} catch {
|
|
@@ -5218,7 +5252,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
5218
5252
|
}
|
|
5219
5253
|
const spinner = ora6("Updating caliber...").start();
|
|
5220
5254
|
try {
|
|
5221
|
-
|
|
5255
|
+
execSync7(`npm install -g @rely-ai/caliber@${latest} --prefer-online`, { stdio: "pipe", timeout: 6e4 });
|
|
5222
5256
|
const installed = getInstalledVersion();
|
|
5223
5257
|
if (installed !== latest) {
|
|
5224
5258
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
@@ -5231,7 +5265,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
5231
5265
|
console.log(chalk13.dim(`
|
|
5232
5266
|
Restarting: caliber ${args.join(" ")}
|
|
5233
5267
|
`));
|
|
5234
|
-
|
|
5268
|
+
execSync7(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
5235
5269
|
stdio: "inherit",
|
|
5236
5270
|
env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
|
|
5237
5271
|
});
|
package/package.json
CHANGED