@rely-ai/caliber 1.7.8 → 1.8.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.
Files changed (3) hide show
  1. package/README.md +14 -14
  2. package/dist/bin.js +239 -170
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -37,7 +37,7 @@ Caliber **generates, audits, and maintains** your agentic development sessions.
37
37
  ## 🚀 Quick Start
38
38
 
39
39
  ```bash
40
- npx @rely-ai/caliber onboard
40
+ npx @rely-ai/caliber init
41
41
  ```
42
42
 
43
43
  That's it. On first run, Caliber walks you through provider setup interactively.
@@ -46,20 +46,20 @@ Or install globally:
46
46
 
47
47
  ```bash
48
48
  npm install -g @rely-ai/caliber
49
- caliber onboard
49
+ caliber init
50
50
  ```
51
51
 
52
52
  > **Already have an API key?** Skip the interactive setup:
53
53
  >
54
54
  > ```bash
55
55
  > export ANTHROPIC_API_KEY=sk-ant-...
56
- > npx @rely-ai/caliber onboard
56
+ > npx @rely-ai/caliber init
57
57
  > ```
58
58
 
59
59
  ## ⚙️ How It Works
60
60
 
61
61
  ```
62
- caliber onboard
62
+ caliber init
63
63
 
64
64
  ├─ 1. 🔌 Connect Choose your LLM provider — Claude Code seat, Cursor seat,
65
65
  │ or an API key (Anthropic, OpenAI, Vertex AI)
@@ -112,7 +112,7 @@ Every change Caliber makes is reversible:
112
112
 
113
113
  | Command | Description |
114
114
  | -------------------- | ---------------------------------------------------- |
115
- | `caliber onboard` | 🏁 Onboard your project — full 6-step wizard |
115
+ | `caliber init` | 🏁 Initialize your project — full 6-step wizard |
116
116
  | `caliber score` | 📊 Score your config quality (deterministic, no LLM) |
117
117
  | `caliber skills` | 🧩 Discover and install community skills |
118
118
  | `caliber regenerate` | 🔄 Re-analyze and regenerate your setup |
@@ -125,15 +125,15 @@ Every change Caliber makes is reversible:
125
125
  ### Examples
126
126
 
127
127
  ```bash
128
- # Onboarding
129
- caliber onboard # Interactive — picks agent, walks through setup
130
- caliber onboard --agent claude # Target Claude Code only
131
- caliber onboard --agent cursor # Target Cursor only
132
- caliber onboard --agent codex # Target OpenAI Codex only
133
- caliber onboard --agent all # Target all three
134
- caliber onboard --agent claude,cursor # Comma-separated
135
- caliber onboard --dry-run # Preview without writing files
136
- caliber onboard --force # Overwrite existing setup without prompting
128
+ # Initialize
129
+ caliber init # Interactive — picks agent, walks through setup
130
+ caliber init --agent claude # Target Claude Code only
131
+ caliber init --agent cursor # Target Cursor only
132
+ caliber init --agent codex # Target OpenAI Codex only
133
+ caliber init --agent all # Target all three
134
+ caliber init --agent claude,cursor # Comma-separated
135
+ caliber init --dry-run # Preview without writing files
136
+ caliber init --force # Overwrite existing setup without prompting
137
137
 
138
138
  # Scoring
139
139
  caliber score # Full breakdown with grade (A-F)
package/dist/bin.js CHANGED
@@ -169,7 +169,7 @@ import fs30 from "fs";
169
169
  import path24 from "path";
170
170
  import { fileURLToPath } from "url";
171
171
 
172
- // src/commands/onboard.ts
172
+ // src/commands/init.ts
173
173
  import path19 from "path";
174
174
  import chalk8 from "chalk";
175
175
  import ora2 from "ora";
@@ -1476,7 +1476,7 @@ Quality (25 pts):
1476
1476
  - No contradictions (2 pts) \u2014 consistent tool/style recommendations
1477
1477
 
1478
1478
  Coverage (20 pts):
1479
- - Dependency coverage (10 pts) \u2014 CRITICAL: mention the project's actual dependencies by name in CLAUDE.md or skills. Reference the key packages from package.json/requirements.txt/go.mod. The scoring checks whether each non-trivial dependency name appears somewhere in your output. Aim for >80% coverage.
1479
+ - Dependency coverage (10 pts) \u2014 CRITICAL: the exact dependency list is provided in your input under "DEPENDENCY COVERAGE". Mention AT LEAST 85% of them by name in CLAUDE.md or skills. You get full points at 85%+, proportional below that. Weave them naturally into architecture, key deps, and conventions sections.
1480
1480
  - Service/MCP coverage (6 pts) \u2014 reference detected services (DB, cloud, etc.)
1481
1481
  - MCP completeness (4 pts) \u2014 full points if no external services detected
1482
1482
 
@@ -1737,6 +1737,98 @@ async function enrichWithLLM(fingerprint, dir) {
1737
1737
  }
1738
1738
  }
1739
1739
 
1740
+ // src/utils/dependencies.ts
1741
+ import { readFileSync } from "fs";
1742
+ import { join } from "path";
1743
+ function readFileOrNull(path26) {
1744
+ try {
1745
+ return readFileSync(path26, "utf-8");
1746
+ } catch {
1747
+ return null;
1748
+ }
1749
+ }
1750
+ function readJsonOrNull(path26) {
1751
+ const content = readFileOrNull(path26);
1752
+ if (!content) return null;
1753
+ try {
1754
+ return JSON.parse(content);
1755
+ } catch {
1756
+ return null;
1757
+ }
1758
+ }
1759
+ function extractNpmDeps(dir) {
1760
+ const pkg3 = readJsonOrNull(join(dir, "package.json"));
1761
+ if (!pkg3) return [];
1762
+ const deps = {
1763
+ ...pkg3.dependencies,
1764
+ ...pkg3.devDependencies
1765
+ };
1766
+ const trivial = /* @__PURE__ */ new Set([
1767
+ "typescript",
1768
+ "@types/node",
1769
+ "tslib",
1770
+ "ts-node",
1771
+ "tsx",
1772
+ "prettier",
1773
+ "eslint",
1774
+ "@eslint/js",
1775
+ "rimraf",
1776
+ "cross-env",
1777
+ "dotenv",
1778
+ "nodemon",
1779
+ "husky",
1780
+ "lint-staged",
1781
+ "commitlint",
1782
+ "@commitlint/cli",
1783
+ "@commitlint/config-conventional"
1784
+ ]);
1785
+ const trivialPatterns = [
1786
+ /^@rely-ai\//,
1787
+ /^@caliber-ai\//,
1788
+ /^eslint-/,
1789
+ /^@eslint\//,
1790
+ /^prettier-/,
1791
+ /^@typescript-eslint\//
1792
+ ];
1793
+ return Object.keys(deps).filter((d) => !trivial.has(d) && !d.startsWith("@types/") && !trivialPatterns.some((p) => p.test(d))).slice(0, 30);
1794
+ }
1795
+ function extractPythonDeps(dir) {
1796
+ const reqTxt = readFileOrNull(join(dir, "requirements.txt"));
1797
+ if (reqTxt) {
1798
+ return reqTxt.split("\n").map((l) => l.trim().split(/[=<>!~\[]/)[0].trim()).filter((l) => l && !l.startsWith("#")).slice(0, 30);
1799
+ }
1800
+ const pyproject = readFileOrNull(join(dir, "pyproject.toml"));
1801
+ if (pyproject) {
1802
+ const depMatch = pyproject.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
1803
+ if (depMatch) {
1804
+ return depMatch[1].split("\n").map((l) => l.trim().replace(/["',]/g, "").split(/[=<>!~\[]/)[0].trim()).filter((l) => l.length > 0).slice(0, 30);
1805
+ }
1806
+ }
1807
+ return [];
1808
+ }
1809
+ function extractGoDeps(dir) {
1810
+ const goMod = readFileOrNull(join(dir, "go.mod"));
1811
+ if (!goMod) return [];
1812
+ const requireBlock = goMod.match(/require\s*\(([\s\S]*?)\)/);
1813
+ if (!requireBlock) return [];
1814
+ return requireBlock[1].split("\n").map((l) => l.trim().split(/\s/)[0]).filter((l) => l && !l.startsWith("//")).map((l) => l.split("/").pop() || l).slice(0, 30);
1815
+ }
1816
+ function extractRustDeps(dir) {
1817
+ const cargo = readFileOrNull(join(dir, "Cargo.toml"));
1818
+ if (!cargo) return [];
1819
+ const depSection = cargo.match(/\[dependencies\]([\s\S]*?)(?:\[|$)/);
1820
+ if (!depSection) return [];
1821
+ return depSection[1].split("\n").map((l) => l.trim().split(/\s*=/)[0].trim()).filter((l) => l.length > 0 && !l.startsWith("#")).slice(0, 30);
1822
+ }
1823
+ function extractAllDeps(dir) {
1824
+ return [
1825
+ ...extractNpmDeps(dir),
1826
+ ...extractPythonDeps(dir),
1827
+ ...extractGoDeps(dir),
1828
+ ...extractRustDeps(dir)
1829
+ ];
1830
+ }
1831
+
1740
1832
  // src/ai/generate.ts
1741
1833
  var GENERATION_MAX_TOKENS = 64e3;
1742
1834
  var MODEL_MAX_OUTPUT_TOKENS = 128e3;
@@ -1983,6 +2075,12 @@ ${truncate(cfg.content, LIMITS.CONFIG_FILE_CHARS)}`);
1983
2075
  parts.push("\n(Code analysis was truncated due to size limits \u2014 not all files are shown.)");
1984
2076
  }
1985
2077
  }
2078
+ const allDeps = extractAllDeps(process.cwd());
2079
+ if (allDeps.length > 0) {
2080
+ parts.push(`
2081
+ DEPENDENCY COVERAGE \u2014 mention at least 85% of these ${allDeps.length} packages by name in CLAUDE.md or skills for full coverage points:`);
2082
+ parts.push(allDeps.join(", "));
2083
+ }
1986
2084
  if (prompt) parts.push(`
1987
2085
  User instructions: ${prompt}`);
1988
2086
  return parts.join("\n");
@@ -3060,7 +3158,7 @@ var SpinnerMessages = class {
3060
3158
  }
3061
3159
  };
3062
3160
 
3063
- // src/commands/onboard.ts
3161
+ // src/commands/init.ts
3064
3162
  init_config();
3065
3163
 
3066
3164
  // src/commands/interactive-provider-setup.ts
@@ -3140,11 +3238,11 @@ async function runInteractiveProviderSetup(options) {
3140
3238
 
3141
3239
  // src/scoring/index.ts
3142
3240
  import { existsSync as existsSync8 } from "fs";
3143
- import { join as join7 } from "path";
3241
+ import { join as join8 } from "path";
3144
3242
 
3145
3243
  // src/scoring/checks/existence.ts
3146
- import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
3147
- import { join as join2 } from "path";
3244
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
3245
+ import { join as join3 } from "path";
3148
3246
 
3149
3247
  // src/scoring/constants.ts
3150
3248
  var POINTS_CLAUDE_MD_EXISTS = 6;
@@ -3248,100 +3346,27 @@ function computeGrade(score) {
3248
3346
  }
3249
3347
 
3250
3348
  // src/scoring/checks/coverage.ts
3251
- import { readFileSync, readdirSync } from "fs";
3252
- import { join } from "path";
3253
- function readFileOrNull(path26) {
3349
+ import { readFileSync as readFileSync2, readdirSync } from "fs";
3350
+ import { join as join2 } from "path";
3351
+ function readFileOrNull2(path26) {
3254
3352
  try {
3255
- return readFileSync(path26, "utf-8");
3353
+ return readFileSync2(path26, "utf-8");
3256
3354
  } catch {
3257
3355
  return null;
3258
3356
  }
3259
3357
  }
3260
- function readJsonOrNull(path26) {
3261
- const content = readFileOrNull(path26);
3262
- if (!content) return null;
3263
- try {
3264
- return JSON.parse(content);
3265
- } catch {
3266
- return null;
3267
- }
3268
- }
3269
- function extractNpmDeps(dir) {
3270
- const pkg3 = readJsonOrNull(join(dir, "package.json"));
3271
- if (!pkg3) return [];
3272
- const deps = {
3273
- ...pkg3.dependencies,
3274
- ...pkg3.devDependencies
3275
- };
3276
- const trivial = /* @__PURE__ */ new Set([
3277
- "typescript",
3278
- "@types/node",
3279
- "tslib",
3280
- "ts-node",
3281
- "tsx",
3282
- "prettier",
3283
- "eslint",
3284
- "@eslint/js",
3285
- "rimraf",
3286
- "cross-env",
3287
- "dotenv",
3288
- "nodemon",
3289
- "husky",
3290
- "lint-staged",
3291
- "commitlint",
3292
- "@commitlint/cli",
3293
- "@commitlint/config-conventional"
3294
- ]);
3295
- const trivialPatterns = [
3296
- /^@rely-ai\//,
3297
- /^@caliber-ai\//,
3298
- /^eslint-/,
3299
- /^@eslint\//,
3300
- /^prettier-/,
3301
- /^@typescript-eslint\//
3302
- ];
3303
- return Object.keys(deps).filter((d) => !trivial.has(d) && !d.startsWith("@types/") && !trivialPatterns.some((p) => p.test(d))).slice(0, 30);
3304
- }
3305
- function extractPythonDeps(dir) {
3306
- const reqTxt = readFileOrNull(join(dir, "requirements.txt"));
3307
- if (reqTxt) {
3308
- return reqTxt.split("\n").map((l) => l.trim().split(/[=<>!~\[]/)[0].trim()).filter((l) => l && !l.startsWith("#")).slice(0, 30);
3309
- }
3310
- const pyproject = readFileOrNull(join(dir, "pyproject.toml"));
3311
- if (pyproject) {
3312
- const depMatch = pyproject.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
3313
- if (depMatch) {
3314
- return depMatch[1].split("\n").map((l) => l.trim().replace(/["',]/g, "").split(/[=<>!~\[]/)[0].trim()).filter((l) => l.length > 0).slice(0, 30);
3315
- }
3316
- }
3317
- return [];
3318
- }
3319
- function extractGoDeps(dir) {
3320
- const goMod = readFileOrNull(join(dir, "go.mod"));
3321
- if (!goMod) return [];
3322
- const requireBlock = goMod.match(/require\s*\(([\s\S]*?)\)/);
3323
- if (!requireBlock) return [];
3324
- return requireBlock[1].split("\n").map((l) => l.trim().split(/\s/)[0]).filter((l) => l && !l.startsWith("//")).map((l) => l.split("/").pop() || l).slice(0, 30);
3325
- }
3326
- function extractRustDeps(dir) {
3327
- const cargo = readFileOrNull(join(dir, "Cargo.toml"));
3328
- if (!cargo) return [];
3329
- const depSection = cargo.match(/\[dependencies\]([\s\S]*?)(?:\[|$)/);
3330
- if (!depSection) return [];
3331
- return depSection[1].split("\n").map((l) => l.trim().split(/\s*=/)[0].trim()).filter((l) => l.length > 0 && !l.startsWith("#")).slice(0, 30);
3332
- }
3333
3358
  function collectAllConfigContent(dir) {
3334
3359
  const parts = [];
3335
- const claudeMd = readFileOrNull(join(dir, "CLAUDE.md"));
3360
+ const claudeMd = readFileOrNull2(join2(dir, "CLAUDE.md"));
3336
3361
  if (claudeMd) parts.push(claudeMd);
3337
- const cursorrules = readFileOrNull(join(dir, ".cursorrules"));
3362
+ const cursorrules = readFileOrNull2(join2(dir, ".cursorrules"));
3338
3363
  if (cursorrules) parts.push(cursorrules);
3339
- for (const skillsDir of [join(dir, ".claude", "skills"), join(dir, ".cursor", "skills")]) {
3364
+ for (const skillsDir of [join2(dir, ".claude", "skills"), join2(dir, ".cursor", "skills")]) {
3340
3365
  try {
3341
3366
  const entries = readdirSync(skillsDir, { withFileTypes: true });
3342
3367
  for (const entry of entries) {
3343
3368
  if (entry.isDirectory()) {
3344
- const skill = readFileOrNull(join(skillsDir, entry.name, "SKILL.md"));
3369
+ const skill = readFileOrNull2(join2(skillsDir, entry.name, "SKILL.md"));
3345
3370
  if (skill) parts.push(skill);
3346
3371
  }
3347
3372
  }
@@ -3349,10 +3374,10 @@ function collectAllConfigContent(dir) {
3349
3374
  }
3350
3375
  }
3351
3376
  try {
3352
- const rulesDir = join(dir, ".cursor", "rules");
3377
+ const rulesDir = join2(dir, ".cursor", "rules");
3353
3378
  const mdcFiles = readdirSync(rulesDir).filter((f) => f.endsWith(".mdc"));
3354
3379
  for (const f of mdcFiles) {
3355
- const content = readFileOrNull(join(rulesDir, f));
3380
+ const content = readFileOrNull2(join2(rulesDir, f));
3356
3381
  if (content) parts.push(content);
3357
3382
  }
3358
3383
  } catch {
@@ -3400,7 +3425,7 @@ function getConfiguredMcpServers(dir) {
3400
3425
  ];
3401
3426
  for (const rel of mcpFiles) {
3402
3427
  try {
3403
- const content = readFileSync(join(dir, rel), "utf-8");
3428
+ const content = readFileSync2(join2(dir, rel), "utf-8");
3404
3429
  const parsed = JSON.parse(content);
3405
3430
  const mcpServers = parsed.mcpServers;
3406
3431
  if (mcpServers) {
@@ -3516,7 +3541,7 @@ function hasMcpServers(dir) {
3516
3541
  ];
3517
3542
  for (const rel of mcpFiles) {
3518
3543
  try {
3519
- const content = readFileSync2(join2(dir, rel), "utf-8");
3544
+ const content = readFileSync3(join3(dir, rel), "utf-8");
3520
3545
  const parsed = JSON.parse(content);
3521
3546
  const servers = parsed.mcpServers;
3522
3547
  if (servers && Object.keys(servers).length > 0) {
@@ -3530,7 +3555,7 @@ function hasMcpServers(dir) {
3530
3555
  }
3531
3556
  function checkExistence(dir) {
3532
3557
  const checks = [];
3533
- const claudeMdExists = existsSync3(join2(dir, "CLAUDE.md"));
3558
+ const claudeMdExists = existsSync3(join3(dir, "CLAUDE.md"));
3534
3559
  checks.push({
3535
3560
  id: "claude_md_exists",
3536
3561
  name: "CLAUDE.md exists",
@@ -3541,8 +3566,8 @@ function checkExistence(dir) {
3541
3566
  detail: claudeMdExists ? "Found at project root" : "Not found",
3542
3567
  suggestion: claudeMdExists ? void 0 : "Create a CLAUDE.md with project context and commands"
3543
3568
  });
3544
- const hasCursorrules = existsSync3(join2(dir, ".cursorrules"));
3545
- const cursorRulesDir = existsSync3(join2(dir, ".cursor", "rules"));
3569
+ const hasCursorrules = existsSync3(join3(dir, ".cursorrules"));
3570
+ const cursorRulesDir = existsSync3(join3(dir, ".cursor", "rules"));
3546
3571
  const cursorRulesExist = hasCursorrules || cursorRulesDir;
3547
3572
  checks.push({
3548
3573
  id: "cursor_rules_exist",
@@ -3554,7 +3579,7 @@ function checkExistence(dir) {
3554
3579
  detail: hasCursorrules ? ".cursorrules found" : cursorRulesDir ? ".cursor/rules/ found" : "No Cursor rules",
3555
3580
  suggestion: cursorRulesExist ? void 0 : "Add .cursor/rules/ for Cursor users on your team"
3556
3581
  });
3557
- const agentsMdExists = existsSync3(join2(dir, "AGENTS.md"));
3582
+ const agentsMdExists = existsSync3(join3(dir, "AGENTS.md"));
3558
3583
  checks.push({
3559
3584
  id: "codex_agents_md_exists",
3560
3585
  name: "AGENTS.md exists",
@@ -3565,8 +3590,8 @@ function checkExistence(dir) {
3565
3590
  detail: agentsMdExists ? "Found at project root" : "Not found",
3566
3591
  suggestion: agentsMdExists ? void 0 : "Create AGENTS.md with project context for Codex"
3567
3592
  });
3568
- const claudeSkills = countFiles(join2(dir, ".claude", "skills"), /\.(md|SKILL\.md)$/);
3569
- const codexSkills = countFiles(join2(dir, ".agents", "skills"), /SKILL\.md$/);
3593
+ const claudeSkills = countFiles(join3(dir, ".claude", "skills"), /\.(md|SKILL\.md)$/);
3594
+ const codexSkills = countFiles(join3(dir, ".agents", "skills"), /SKILL\.md$/);
3570
3595
  const skillCount = claudeSkills.length + codexSkills.length;
3571
3596
  const skillBase = skillCount >= 1 ? POINTS_SKILLS_EXIST : 0;
3572
3597
  const skillBonus = Math.min((skillCount - 1) * POINTS_SKILLS_BONUS_PER_EXTRA, POINTS_SKILLS_BONUS_CAP);
@@ -3582,7 +3607,7 @@ function checkExistence(dir) {
3582
3607
  detail: skillCount === 0 ? "No skills found" : `${skillCount} skill${skillCount === 1 ? "" : "s"} found`,
3583
3608
  suggestion: skillCount === 0 ? "Add .claude/skills/ with project-specific workflows" : skillCount < 3 ? "Optimal is 2-3 focused skills (SkillsBench research)" : void 0
3584
3609
  });
3585
- const mdcFiles = countFiles(join2(dir, ".cursor", "rules"), /\.mdc$/);
3610
+ const mdcFiles = countFiles(join3(dir, ".cursor", "rules"), /\.mdc$/);
3586
3611
  const mdcCount = mdcFiles.length;
3587
3612
  checks.push({
3588
3613
  id: "cursor_mdc_rules",
@@ -3624,11 +3649,11 @@ function checkExistence(dir) {
3624
3649
  }
3625
3650
 
3626
3651
  // src/scoring/checks/quality.ts
3627
- import { readFileSync as readFileSync3 } from "fs";
3628
- import { join as join3 } from "path";
3629
- function readFileOrNull2(path26) {
3652
+ import { readFileSync as readFileSync4 } from "fs";
3653
+ import { join as join4 } from "path";
3654
+ function readFileOrNull3(path26) {
3630
3655
  try {
3631
- return readFileSync3(path26, "utf-8");
3656
+ return readFileSync4(path26, "utf-8");
3632
3657
  } catch {
3633
3658
  return null;
3634
3659
  }
@@ -3638,9 +3663,9 @@ function countLines(content) {
3638
3663
  }
3639
3664
  function checkQuality(dir) {
3640
3665
  const checks = [];
3641
- const claudeMd = readFileOrNull2(join3(dir, "CLAUDE.md"));
3642
- const cursorrules = readFileOrNull2(join3(dir, ".cursorrules"));
3643
- const agentsMd = readFileOrNull2(join3(dir, "AGENTS.md"));
3666
+ const claudeMd = readFileOrNull3(join4(dir, "CLAUDE.md"));
3667
+ const cursorrules = readFileOrNull3(join4(dir, ".cursorrules"));
3668
+ const agentsMd = readFileOrNull3(join4(dir, "AGENTS.md"));
3644
3669
  const allContent = [claudeMd, cursorrules, agentsMd].filter(Boolean);
3645
3670
  const combinedContent = allContent.join("\n");
3646
3671
  const primaryInstructions = claudeMd ?? agentsMd;
@@ -3779,17 +3804,17 @@ function checkQuality(dir) {
3779
3804
  }
3780
3805
 
3781
3806
  // src/scoring/checks/accuracy.ts
3782
- import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync } from "fs";
3783
- import { join as join4 } from "path";
3784
- function readFileOrNull3(path26) {
3807
+ import { existsSync as existsSync5, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync } from "fs";
3808
+ import { join as join5 } from "path";
3809
+ function readFileOrNull4(path26) {
3785
3810
  try {
3786
- return readFileSync4(path26, "utf-8");
3811
+ return readFileSync5(path26, "utf-8");
3787
3812
  } catch {
3788
3813
  return null;
3789
3814
  }
3790
3815
  }
3791
3816
  function readJsonOrNull2(path26) {
3792
- const content = readFileOrNull3(path26);
3817
+ const content = readFileOrNull4(path26);
3793
3818
  if (!content) return null;
3794
3819
  try {
3795
3820
  return JSON.parse(content);
@@ -3798,12 +3823,12 @@ function readJsonOrNull2(path26) {
3798
3823
  }
3799
3824
  }
3800
3825
  function getPackageScripts(dir) {
3801
- const pkg3 = readJsonOrNull2(join4(dir, "package.json"));
3826
+ const pkg3 = readJsonOrNull2(join5(dir, "package.json"));
3802
3827
  if (!pkg3?.scripts) return /* @__PURE__ */ new Set();
3803
3828
  return new Set(Object.keys(pkg3.scripts));
3804
3829
  }
3805
3830
  function validateDocumentedCommands(dir) {
3806
- const claudeMd = readFileOrNull3(join4(dir, "CLAUDE.md"));
3831
+ const claudeMd = readFileOrNull4(join5(dir, "CLAUDE.md"));
3807
3832
  if (!claudeMd) return { valid: [], invalid: [], total: 0 };
3808
3833
  const scripts = getPackageScripts(dir);
3809
3834
  const valid = [];
@@ -3838,8 +3863,8 @@ function validateDocumentedCommands(dir) {
3838
3863
  valid.push(match[0]);
3839
3864
  }
3840
3865
  const makePattern = /make\s+(\S+)/g;
3841
- if (existsSync5(join4(dir, "Makefile"))) {
3842
- const makefile = readFileOrNull3(join4(dir, "Makefile"));
3866
+ if (existsSync5(join5(dir, "Makefile"))) {
3867
+ const makefile = readFileOrNull4(join5(dir, "Makefile"));
3843
3868
  const makeTargets = /* @__PURE__ */ new Set();
3844
3869
  if (makefile) {
3845
3870
  for (const line of makefile.split("\n")) {
@@ -3861,7 +3886,7 @@ function validateDocumentedCommands(dir) {
3861
3886
  return { valid, invalid, total: valid.length + invalid.length };
3862
3887
  }
3863
3888
  function validateDocumentedPaths(dir) {
3864
- const claudeMd = readFileOrNull3(join4(dir, "CLAUDE.md"));
3889
+ const claudeMd = readFileOrNull4(join5(dir, "CLAUDE.md"));
3865
3890
  if (!claudeMd) return { valid: [], invalid: [], total: 0 };
3866
3891
  const valid = [];
3867
3892
  const invalid = [];
@@ -3872,7 +3897,7 @@ function validateDocumentedPaths(dir) {
3872
3897
  const filePath = match[1];
3873
3898
  if (seen.has(filePath)) continue;
3874
3899
  seen.add(filePath);
3875
- if (existsSync5(join4(dir, filePath))) {
3900
+ if (existsSync5(join5(dir, filePath))) {
3876
3901
  valid.push(filePath);
3877
3902
  } else {
3878
3903
  invalid.push(filePath);
@@ -3884,13 +3909,13 @@ function detectConfigDrift(dir) {
3884
3909
  const srcDirs = ["src", "lib", "app", "cmd", "internal", "pages", "components"];
3885
3910
  let latestSrcMtime = 0;
3886
3911
  for (const srcDir of srcDirs) {
3887
- const fullPath = join4(dir, srcDir);
3912
+ const fullPath = join5(dir, srcDir);
3888
3913
  if (!existsSync5(fullPath)) continue;
3889
3914
  try {
3890
3915
  const files = readdirSync3(fullPath, { recursive: true }).map(String).filter((f) => /\.(ts|js|tsx|jsx|py|go|rs|java|rb)$/.test(f));
3891
3916
  for (const file of files.slice(0, 100)) {
3892
3917
  try {
3893
- const stat = statSync(join4(fullPath, file));
3918
+ const stat = statSync(join5(fullPath, file));
3894
3919
  if (stat.mtime.getTime() > latestSrcMtime) {
3895
3920
  latestSrcMtime = stat.mtime.getTime();
3896
3921
  }
@@ -3904,7 +3929,7 @@ function detectConfigDrift(dir) {
3904
3929
  let latestConfigMtime = 0;
3905
3930
  for (const configFile of configFiles) {
3906
3931
  try {
3907
- const stat = statSync(join4(dir, configFile));
3932
+ const stat = statSync(join5(dir, configFile));
3908
3933
  if (stat.mtime.getTime() > latestConfigMtime) {
3909
3934
  latestConfigMtime = stat.mtime.getTime();
3910
3935
  }
@@ -3970,11 +3995,11 @@ function checkAccuracy(dir) {
3970
3995
  }
3971
3996
 
3972
3997
  // src/scoring/checks/freshness.ts
3973
- import { existsSync as existsSync6, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3974
- import { join as join5 } from "path";
3975
- function readFileOrNull4(path26) {
3998
+ import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
3999
+ import { join as join6 } from "path";
4000
+ function readFileOrNull5(path26) {
3976
4001
  try {
3977
- return readFileSync5(path26, "utf-8");
4002
+ return readFileSync6(path26, "utf-8");
3978
4003
  } catch {
3979
4004
  return null;
3980
4005
  }
@@ -3991,8 +4016,8 @@ function daysSinceModified(filePath) {
3991
4016
  }
3992
4017
  function checkFreshness(dir) {
3993
4018
  const checks = [];
3994
- const claudeMdPath = join5(dir, "CLAUDE.md");
3995
- const agentsMdPath = join5(dir, "AGENTS.md");
4019
+ const claudeMdPath = join6(dir, "CLAUDE.md");
4020
+ const agentsMdPath = join6(dir, "AGENTS.md");
3996
4021
  const primaryPath = existsSync6(claudeMdPath) ? claudeMdPath : agentsMdPath;
3997
4022
  const primaryName = existsSync6(claudeMdPath) ? "CLAUDE.md" : "AGENTS.md";
3998
4023
  const daysOld = daysSinceModified(primaryPath);
@@ -4026,7 +4051,7 @@ function checkFreshness(dir) {
4026
4051
  ];
4027
4052
  const secretFindings = [];
4028
4053
  for (const rel of filesToScan) {
4029
- const content = readFileOrNull4(join5(dir, rel));
4054
+ const content = readFileOrNull5(join6(dir, rel));
4030
4055
  if (!content) continue;
4031
4056
  const lines = content.split("\n");
4032
4057
  for (let i = 0; i < lines.length; i++) {
@@ -4054,10 +4079,10 @@ function checkFreshness(dir) {
4054
4079
  detail: hasSecrets ? `${secretFindings.length} potential secret${secretFindings.length === 1 ? "" : "s"} found in ${secretFindings[0].file}:${secretFindings[0].line}` : "No secrets detected",
4055
4080
  suggestion: hasSecrets ? `Remove secrets from ${secretFindings[0].file}:${secretFindings[0].line} \u2014 use environment variables instead` : void 0
4056
4081
  });
4057
- const settingsPath = join5(dir, ".claude", "settings.json");
4082
+ const settingsPath = join6(dir, ".claude", "settings.json");
4058
4083
  let hasPermissions = false;
4059
4084
  let permissionDetail = "";
4060
- const settingsContent = readFileOrNull4(settingsPath);
4085
+ const settingsContent = readFileOrNull5(settingsPath);
4061
4086
  if (settingsContent) {
4062
4087
  try {
4063
4088
  const settings = JSON.parse(settingsContent);
@@ -4085,12 +4110,12 @@ function checkFreshness(dir) {
4085
4110
  }
4086
4111
 
4087
4112
  // src/scoring/checks/bonus.ts
4088
- import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
4113
+ import { existsSync as existsSync7, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "fs";
4089
4114
  import { execSync as execSync8 } from "child_process";
4090
- import { join as join6 } from "path";
4091
- function readFileOrNull5(path26) {
4115
+ import { join as join7 } from "path";
4116
+ function readFileOrNull6(path26) {
4092
4117
  try {
4093
- return readFileSync6(path26, "utf-8");
4118
+ return readFileSync7(path26, "utf-8");
4094
4119
  } catch {
4095
4120
  return null;
4096
4121
  }
@@ -4098,8 +4123,8 @@ function readFileOrNull5(path26) {
4098
4123
  function hasPreCommitHook(dir) {
4099
4124
  try {
4100
4125
  const gitDir = execSync8("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
4101
- const hookPath = join6(gitDir, "hooks", "pre-commit");
4102
- const content = readFileOrNull5(hookPath);
4126
+ const hookPath = join7(gitDir, "hooks", "pre-commit");
4127
+ const content = readFileOrNull6(hookPath);
4103
4128
  return content ? content.includes("caliber") : false;
4104
4129
  } catch {
4105
4130
  return false;
@@ -4110,7 +4135,7 @@ function checkBonus(dir) {
4110
4135
  let hasClaudeHooks = false;
4111
4136
  let hasPrecommit = false;
4112
4137
  const hookSources = [];
4113
- const settingsContent = readFileOrNull5(join6(dir, ".claude", "settings.json"));
4138
+ const settingsContent = readFileOrNull6(join7(dir, ".claude", "settings.json"));
4114
4139
  if (settingsContent) {
4115
4140
  try {
4116
4141
  const settings = JSON.parse(settingsContent);
@@ -4138,7 +4163,7 @@ function checkBonus(dir) {
4138
4163
  detail: hookDetail,
4139
4164
  suggestion: hasHooks ? void 0 : "Run `caliber hooks --install` for auto-refresh"
4140
4165
  });
4141
- const agentsMdExists = existsSync7(join6(dir, "AGENTS.md"));
4166
+ const agentsMdExists = existsSync7(join7(dir, "AGENTS.md"));
4142
4167
  checks.push({
4143
4168
  id: "agents_md_exists",
4144
4169
  name: "AGENTS.md exists",
@@ -4149,14 +4174,14 @@ function checkBonus(dir) {
4149
4174
  detail: agentsMdExists ? "Found at project root" : "Not found",
4150
4175
  suggestion: agentsMdExists ? void 0 : "Add AGENTS.md \u2014 the emerging cross-agent standard (60k+ repos)"
4151
4176
  });
4152
- const skillsDir = join6(dir, ".claude", "skills");
4177
+ const skillsDir = join7(dir, ".claude", "skills");
4153
4178
  let openSkillsCount = 0;
4154
4179
  let totalSkillFiles = 0;
4155
4180
  try {
4156
4181
  const entries = readdirSync4(skillsDir, { withFileTypes: true });
4157
4182
  for (const entry of entries) {
4158
4183
  if (entry.isDirectory()) {
4159
- const skillMd = readFileOrNull5(join6(skillsDir, entry.name, "SKILL.md"));
4184
+ const skillMd = readFileOrNull6(join7(skillsDir, entry.name, "SKILL.md"));
4160
4185
  if (skillMd) {
4161
4186
  totalSkillFiles++;
4162
4187
  if (skillMd.trimStart().startsWith("---")) {
@@ -4225,9 +4250,9 @@ function filterChecksForTarget(checks, target) {
4225
4250
  }
4226
4251
  function detectTargetAgent(dir) {
4227
4252
  const agents = [];
4228
- if (existsSync8(join7(dir, "CLAUDE.md")) || existsSync8(join7(dir, ".claude", "skills"))) agents.push("claude");
4229
- if (existsSync8(join7(dir, ".cursorrules")) || existsSync8(join7(dir, ".cursor", "rules"))) agents.push("cursor");
4230
- if (existsSync8(join7(dir, ".codex")) || existsSync8(join7(dir, ".agents", "skills"))) agents.push("codex");
4253
+ if (existsSync8(join8(dir, "CLAUDE.md")) || existsSync8(join8(dir, ".claude", "skills"))) agents.push("claude");
4254
+ if (existsSync8(join8(dir, ".cursorrules")) || existsSync8(join8(dir, ".cursor", "rules"))) agents.push("cursor");
4255
+ if (existsSync8(join8(dir, ".codex")) || existsSync8(join8(dir, ".agents", "skills"))) agents.push("codex");
4231
4256
  return agents.length > 0 ? agents : ["claude"];
4232
4257
  }
4233
4258
  function computeLocalScore(dir, targetAgent) {
@@ -4391,8 +4416,8 @@ function displayScoreDelta(before, after) {
4391
4416
  import chalk7 from "chalk";
4392
4417
  import ora from "ora";
4393
4418
  import select4 from "@inquirer/select";
4394
- import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5, existsSync as existsSync9, writeFileSync } from "fs";
4395
- import { join as join8, dirname as dirname2 } from "path";
4419
+ import { mkdirSync, readFileSync as readFileSync8, readdirSync as readdirSync5, existsSync as existsSync9, writeFileSync } from "fs";
4420
+ import { join as join9, dirname as dirname2 } from "path";
4396
4421
 
4397
4422
  // src/scanner/index.ts
4398
4423
  import fs21 from "fs";
@@ -4711,19 +4736,19 @@ function detectLocalPlatforms() {
4711
4736
  }
4712
4737
  function getSkillPath(platform, slug) {
4713
4738
  if (platform === "cursor") {
4714
- return join8(".cursor", "skills", slug, "SKILL.md");
4739
+ return join9(".cursor", "skills", slug, "SKILL.md");
4715
4740
  }
4716
4741
  if (platform === "codex") {
4717
- return join8(".agents", "skills", slug, "SKILL.md");
4742
+ return join9(".agents", "skills", slug, "SKILL.md");
4718
4743
  }
4719
- return join8(".claude", "skills", slug, "SKILL.md");
4744
+ return join9(".claude", "skills", slug, "SKILL.md");
4720
4745
  }
4721
4746
  function getInstalledSkills() {
4722
4747
  const installed = /* @__PURE__ */ new Set();
4723
4748
  const dirs = [
4724
- join8(process.cwd(), ".claude", "skills"),
4725
- join8(process.cwd(), ".cursor", "skills"),
4726
- join8(process.cwd(), ".agents", "skills")
4749
+ join9(process.cwd(), ".claude", "skills"),
4750
+ join9(process.cwd(), ".cursor", "skills"),
4751
+ join9(process.cwd(), ".agents", "skills")
4727
4752
  ];
4728
4753
  for (const dir of dirs) {
4729
4754
  try {
@@ -4924,10 +4949,10 @@ Already installed skills: ${Array.from(installed).join(", ")}`);
4924
4949
  return parts.join("\n");
4925
4950
  }
4926
4951
  function extractTopDeps() {
4927
- const pkgPath = join8(process.cwd(), "package.json");
4952
+ const pkgPath = join9(process.cwd(), "package.json");
4928
4953
  if (!existsSync9(pkgPath)) return [];
4929
4954
  try {
4930
- const pkg3 = JSON.parse(readFileSync7(pkgPath, "utf-8"));
4955
+ const pkg3 = JSON.parse(readFileSync8(pkgPath, "utf-8"));
4931
4956
  const deps = Object.keys(pkg3.dependencies ?? {});
4932
4957
  const trivial = /* @__PURE__ */ new Set([
4933
4958
  "typescript",
@@ -5233,7 +5258,7 @@ async function installSkills(recs, platforms, contentMap) {
5233
5258
  if (!content) continue;
5234
5259
  for (const platform of platforms) {
5235
5260
  const skillPath = getSkillPath(platform, rec.slug);
5236
- const fullPath = join8(process.cwd(), skillPath);
5261
+ const fullPath = join9(process.cwd(), skillPath);
5237
5262
  mkdirSync(dirname2(fullPath), { recursive: true });
5238
5263
  writeFileSync(fullPath, content, "utf-8");
5239
5264
  installed.push(`[${platform}] ${skillPath}`);
@@ -5361,7 +5386,7 @@ function formatMs(ms) {
5361
5386
  return `${secs}s`;
5362
5387
  }
5363
5388
 
5364
- // src/commands/onboard.ts
5389
+ // src/commands/init.ts
5365
5390
  async function initCommand(options) {
5366
5391
  const brand = chalk8.hex("#EB9D83");
5367
5392
  const title = chalk8.hex("#83D1EB");
@@ -5373,12 +5398,12 @@ async function initCommand(options) {
5373
5398
  \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
5374
5399
  \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
5375
5400
  `));
5376
- console.log(chalk8.dim(" Onboard your project for AI-assisted development\n"));
5401
+ console.log(chalk8.dim(" Initialize your project for AI-assisted development\n"));
5377
5402
  console.log(title.bold(" Welcome to Caliber\n"));
5378
5403
  console.log(chalk8.dim(" Caliber analyzes your codebase and creates tailored config files"));
5379
5404
  console.log(chalk8.dim(" so your AI coding agents understand your project from day one.\n"));
5380
5405
  const report = options.debugReport ? new DebugReport() : null;
5381
- console.log(title.bold(" How onboarding works:\n"));
5406
+ console.log(title.bold(" How it works:\n"));
5382
5407
  console.log(chalk8.dim(" 1. Connect Set up your LLM provider"));
5383
5408
  console.log(chalk8.dim(" 2. Discover Analyze your code, dependencies, and structure"));
5384
5409
  console.log(chalk8.dim(" 3. Generate Create config files tailored to your project"));
@@ -5427,7 +5452,7 @@ async function initCommand(options) {
5427
5452
  `));
5428
5453
  if (report) {
5429
5454
  report.markStep("Fingerprint");
5430
- report.addJson("Fingerprint: Git", { remote: fingerprint.remote, packageName: fingerprint.packageName });
5455
+ report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
5431
5456
  report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
5432
5457
  report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
5433
5458
  report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
@@ -5458,15 +5483,22 @@ async function initCommand(options) {
5458
5483
 
5459
5484
  | Check | Passed | Points | Max |
5460
5485
  |-------|--------|--------|-----|
5461
- ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.points} | ${c.maxPoints} |`).join("\n"));
5486
+ ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
5462
5487
  report.addSection("Generation: Target Agents", targetAgent.join(", "));
5463
5488
  }
5464
5489
  const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
5465
- const NON_LLM_CHECKS = /* @__PURE__ */ new Set(["hooks_configured", "agents_md_exists", "permissions_configured", "mcp_servers"]);
5490
+ const NON_LLM_CHECKS = /* @__PURE__ */ new Set([
5491
+ "hooks_configured",
5492
+ "agents_md_exists",
5493
+ "permissions_configured",
5494
+ "mcp_servers",
5495
+ "service_coverage",
5496
+ "mcp_completeness"
5497
+ ]);
5466
5498
  if (hasExistingConfig && baselineScore.score === 100) {
5467
5499
  trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
5468
5500
  console.log(chalk8.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
5469
- console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to regenerate anyway.\n"));
5501
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber init --force") + chalk8.dim(" to regenerate anyway.\n"));
5470
5502
  if (!options.force) return;
5471
5503
  }
5472
5504
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
@@ -5482,7 +5514,7 @@ async function initCommand(options) {
5482
5514
  }
5483
5515
  }
5484
5516
  console.log("");
5485
- console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to regenerate anyway.\n"));
5517
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber init --force") + chalk8.dim(" to regenerate anyway.\n"));
5486
5518
  return;
5487
5519
  }
5488
5520
  const isEmpty = fingerprint.fileTree.length < 3;
@@ -5702,7 +5734,44 @@ async function initCommand(options) {
5702
5734
  if (hookChoice === "skip") {
5703
5735
  console.log(chalk8.dim(" Skipped auto-refresh hooks. Run ") + chalk8.hex("#83D1EB")("caliber hooks --install") + chalk8.dim(" later to enable."));
5704
5736
  }
5705
- const afterScore = computeLocalScore(process.cwd(), targetAgent);
5737
+ let afterScore = computeLocalScore(process.cwd(), targetAgent);
5738
+ if (afterScore.score < 100) {
5739
+ const polishFailingChecks = afterScore.checks.filter((c) => !c.passed && c.maxPoints > 0).filter((c) => !NON_LLM_CHECKS.has(c.id));
5740
+ if (polishFailingChecks.length > 0) {
5741
+ console.log("");
5742
+ console.log(chalk8.dim(` Score: ${afterScore.score}/100 \u2014 polishing ${polishFailingChecks.length} remaining check${polishFailingChecks.length === 1 ? "" : "s"}...`));
5743
+ const polishFailing = polishFailingChecks.map((c) => ({
5744
+ name: c.name,
5745
+ suggestion: c.suggestion
5746
+ }));
5747
+ const polishPassing = afterScore.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
5748
+ try {
5749
+ const polishResult = await generateSetup(
5750
+ fingerprint,
5751
+ targetAgent,
5752
+ void 0,
5753
+ {
5754
+ onStatus: () => {
5755
+ },
5756
+ onComplete: () => {
5757
+ },
5758
+ onError: () => {
5759
+ }
5760
+ },
5761
+ polishFailing,
5762
+ afterScore.score,
5763
+ polishPassing
5764
+ );
5765
+ if (polishResult.setup) {
5766
+ const polishWriteResult = writeSetup(polishResult.setup);
5767
+ if (polishWriteResult.written.length > 0) {
5768
+ afterScore = computeLocalScore(process.cwd(), targetAgent);
5769
+ }
5770
+ }
5771
+ } catch {
5772
+ }
5773
+ }
5774
+ }
5706
5775
  if (afterScore.score < baselineScore.score) {
5707
5776
  trackInitScoreRegression(baselineScore.score, afterScore.score);
5708
5777
  console.log("");
@@ -5714,7 +5783,7 @@ async function initCommand(options) {
5714
5783
  }
5715
5784
  } catch {
5716
5785
  }
5717
- console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
5786
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber init --force") + chalk8.dim(" to override.\n"));
5718
5787
  return;
5719
5788
  }
5720
5789
  if (report) {
@@ -5723,7 +5792,7 @@ async function initCommand(options) {
5723
5792
 
5724
5793
  | Check | Passed | Points | Max |
5725
5794
  |-------|--------|--------|-----|
5726
- ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.points} | ${c.maxPoints} |`).join("\n"));
5795
+ ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
5727
5796
  }
5728
5797
  displayScoreDelta(baselineScore, afterScore);
5729
5798
  console.log(title.bold("\n Step 6/6 \u2014 Community skills\n"));
@@ -5749,7 +5818,7 @@ async function initCommand(options) {
5749
5818
  trackInitSkillsSearch(false, 0);
5750
5819
  console.log(chalk8.dim(" Skipped. Run ") + chalk8.hex("#83D1EB")("caliber skills") + chalk8.dim(" later to browse.\n"));
5751
5820
  }
5752
- console.log(chalk8.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
5821
+ console.log(chalk8.bold.green(" Setup complete! Your project is ready for AI-assisted development."));
5753
5822
  console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber undo") + chalk8.dim(" to revert changes.\n"));
5754
5823
  console.log(chalk8.bold(" Next steps:\n"));
5755
5824
  console.log(` ${title("caliber score")} See your full config breakdown`);
@@ -6089,7 +6158,7 @@ async function statusCommand(options) {
6089
6158
  }
6090
6159
  if (!manifest) {
6091
6160
  console.log(` Setup: ${chalk10.dim("No setup applied")}`);
6092
- console.log(chalk10.dim("\n Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.dim(" to get started.\n"));
6161
+ console.log(chalk10.dim("\n Run ") + chalk10.hex("#83D1EB")("caliber init") + chalk10.dim(" to get started.\n"));
6093
6162
  return;
6094
6163
  }
6095
6164
  console.log(` Files managed: ${chalk10.cyan(manifest.entries.length.toString())}`);
@@ -6114,7 +6183,7 @@ async function regenerateCommand(options) {
6114
6183
  }
6115
6184
  const manifest = readManifest();
6116
6185
  if (!manifest) {
6117
- console.log(chalk11.yellow("No existing setup found. Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.yellow(" first."));
6186
+ console.log(chalk11.yellow("No existing setup found. Run ") + chalk11.hex("#83D1EB")("caliber init") + chalk11.yellow(" first."));
6118
6187
  throw new Error("__exit__");
6119
6188
  }
6120
6189
  const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
@@ -6237,7 +6306,7 @@ async function regenerateCommand(options) {
6237
6306
  }
6238
6307
  } catch {
6239
6308
  }
6240
- console.log(chalk11.dim(" Run ") + chalk11.hex("#83D1EB")("caliber onboard --force") + chalk11.dim(" to override.\n"));
6309
+ console.log(chalk11.dim(" Run ") + chalk11.hex("#83D1EB")("caliber init --force") + chalk11.dim(" to override.\n"));
6241
6310
  return;
6242
6311
  }
6243
6312
  displayScoreDelta(baselineScore, afterScore);
@@ -6265,9 +6334,9 @@ async function scoreCommand(options) {
6265
6334
  const separator = chalk12.gray(" " + "\u2500".repeat(53));
6266
6335
  console.log(separator);
6267
6336
  if (result.score < 40) {
6268
- console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber onboard") + chalk12.gray(" to generate a complete, optimized setup."));
6337
+ console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber init") + chalk12.gray(" to generate a complete, optimized setup."));
6269
6338
  } else if (result.score < 70) {
6270
- console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber onboard") + chalk12.gray(" to improve your setup."));
6339
+ console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber init") + chalk12.gray(" to improve your setup."));
6271
6340
  } else {
6272
6341
  console.log(chalk12.green(" Looking good!") + chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber regenerate") + chalk12.gray(" to rebuild from scratch."));
6273
6342
  }
@@ -7196,7 +7265,7 @@ function parseAgentOption(value) {
7196
7265
  }
7197
7266
  return agents;
7198
7267
  }
7199
- 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").option("--debug-report", void 0, false).action(tracked("onboard", initCommand));
7268
+ program.command("init").description("Initialize 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").option("--debug-report", void 0, false).action(tracked("init", initCommand));
7200
7269
  program.command("undo").description("Revert all config changes made by Caliber").action(tracked("undo", undoCommand));
7201
7270
  program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(tracked("status", statusCommand));
7202
7271
  program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.7.8",
3
+ "version": "1.8.0",
4
4
  "description": "Analyze your codebase and generate optimized AI agent configs (CLAUDE.md, .cursorrules, skills) — no API key needed",
5
5
  "type": "module",
6
6
  "bin": {