@rely-ai/caliber 1.36.0 → 1.37.0-dev.1774891449

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 +82 -56
  2. package/dist/bin.js +249 -77
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ # Caliber
2
+
3
+ **Hand-written `CLAUDE.md` files go stale the moment you refactor.** Your AI agent hallucinates paths that no longer exist, misses new dependencies, and gives advice based on yesterday's architecture. Caliber generates and maintains your AI context files (`CLAUDE.md`, `.cursor/rules/`, `AGENTS.md`) so they stay accurate as your code evolves — and keeps every agent on your team in sync, whether they use Claude Code, Cursor, Codex, or OpenCode.
4
+
1
5
  <p align="center">
2
6
  <img src="assets/demo-header.gif" alt="Caliber product demo" width="900">
3
7
  </p>
@@ -10,30 +14,15 @@
10
14
  <img src="https://img.shields.io/badge/Claude_Code-supported-blue" alt="Claude Code">
11
15
  <img src="https://img.shields.io/badge/Cursor-supported-blue" alt="Cursor">
12
16
  <img src="https://img.shields.io/badge/Codex-supported-blue" alt="Codex">
17
+ <img src="https://img.shields.io/badge/OpenCode-supported-blue" alt="OpenCode">
13
18
  </p>
14
19
 
15
- ---
16
-
17
- ### Try it — zero install, zero commitment
18
-
19
- ```bash
20
- npx @rely-ai/caliber score
21
- ```
22
-
23
- Score your AI agent config in 3 seconds. No API key. No changes to your code. Just a score.
24
-
25
- > **Your code stays on your machine.** Scoring is 100% local — no LLM calls, no code sent anywhere. Generation uses your own AI subscription (Claude Code, Cursor) or your own API key (Anthropic, OpenAI, Vertex AI). Caliber never sees your code.
26
-
27
- ---
28
-
29
- Caliber scores, generates, and keeps your AI agent configs in sync with your codebase. It fingerprints your project — languages, frameworks, dependencies, architecture — and produces tailored configs for **Claude Code**, **Cursor**, and **OpenAI Codex**. When your code evolves, Caliber detects the drift and updates your configs to match.
30
-
31
20
  ## Before / After
32
21
 
33
22
  Most repos start with a hand-written `CLAUDE.md` and nothing else. Here's what Caliber finds — and fixes:
34
23
 
35
24
  ```
36
- Before After caliber init
25
+ Before After /setup-caliber
37
26
  ────────────────────────────── ──────────────────────────────
38
27
 
39
28
  Agent Config Score 35 / 100 Agent Config Score 94 / 100
@@ -53,6 +42,24 @@ Scoring is deterministic — no LLM, no API calls. It cross-references your conf
53
42
  caliber score --compare main # See how your branch changed the score
54
43
  ```
55
44
 
45
+ ## Get Started
46
+
47
+ Requires **Node.js >= 20**.
48
+
49
+ ```bash
50
+ npx @rely-ai/caliber bootstrap
51
+ ```
52
+
53
+ Then, in your next Claude Code or Cursor chat session, type:
54
+
55
+ > **/setup-caliber**
56
+
57
+ Your agent detects your stack, generates tailored configs for every platform your team uses, sets up pre-commit hooks, and enables continuous sync — all from inside your normal workflow.
58
+
59
+ **Don't use Claude Code or Cursor?** Run `caliber init` instead — it's the same setup as a CLI wizard. Works with any LLM provider: bring your own Anthropic, OpenAI, or Vertex AI key.
60
+
61
+ > **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.
62
+
56
63
  ## Audits first, writes second
57
64
 
58
65
  Caliber never overwrites your existing configs without asking. The workflow mirrors code review:
@@ -67,26 +74,28 @@ If your existing config scores **95+**, Caliber skips full regeneration and appl
67
74
 
68
75
  ## How It Works
69
76
 
70
- Caliber is not a one-time setup tool. It's a loop:
77
+ Bootstrap gives your agent the `/setup-caliber` skill. Your agent analyzes your project — languages, frameworks, dependencies, architecture — generates configs, and installs hooks. From there, it's a loop:
71
78
 
72
79
  ```
73
- caliber score
80
+ npx @rely-ai/caliber bootstrap ← one-time, 2 seconds
74
81
 
75
82
 
76
- ┌──── caliber init ◄────────────────┐
77
- │ (generate / fix)
78
- │ │ │
79
- │ ▼ │
80
- your code evolves
81
- (new deps, renamed files,
82
- changed architecture)
83
-
84
-
85
- └──► caliber refresh ──────────────►┘
86
- (detect drift, update configs)
83
+ agent runs /setup-caliber agent handles everything
84
+
85
+
86
+ ┌──── configs generated ◄────────────┐
87
+
88
+
89
+ your code evolves
90
+ (new deps, renamed files,
91
+ changed architecture)
92
+ │ │ │
93
+ │ ▼ │
94
+ └──► caliber refresh ──────────────►─┘
95
+ (auto, on every commit)
87
96
  ```
88
97
 
89
- Auto-refresh hooks run this loop automatically on every commit or at the end of each AI coding session.
98
+ Pre-commit hooks run the refresh loop automatically. New team members get nudged to bootstrap on their first session.
90
99
 
91
100
  ### What It Generates
92
101
 
@@ -106,6 +115,10 @@ Auto-refresh hooks run this loop automatically — on every commit or at the end
106
115
  - `AGENTS.md` — Project context for Codex
107
116
  - `.agents/skills/*/SKILL.md` — Skills for Codex
108
117
 
118
+ **OpenCode**
119
+ - `AGENTS.md` — Project context (shared with Codex when both are targeted)
120
+ - `.opencode/skills/*/SKILL.md` — Skills for OpenCode
121
+
109
122
  ## Key Features
110
123
 
111
124
  <details>
@@ -118,12 +131,13 @@ TypeScript, Python, Go, Rust, Java, Ruby, Terraform, and more. Language and fram
118
131
  <details>
119
132
  <summary><strong>Any AI Tool</strong></summary>
120
133
 
121
- Target a single platform or all three at once:
134
+ `caliber bootstrap` auto-detects which agents you have installed. For manual control:
122
135
  ```bash
123
136
  caliber init --agent claude # Claude Code only
124
137
  caliber init --agent cursor # Cursor only
125
138
  caliber init --agent codex # Codex only
126
- caliber init --agent all # All three
139
+ caliber init --agent opencode # OpenCode only
140
+ caliber init --agent all # All platforms
127
141
  caliber init --agent claude,cursor # Comma-separated
128
142
  ```
129
143
 
@@ -197,12 +211,20 @@ The `refresh` command analyzes your git diff (committed, staged, and unstaged ch
197
211
 
198
212
  </details>
199
213
 
214
+ <details>
215
+ <summary><strong>Team Onboarding</strong></summary>
216
+
217
+ When Caliber is set up in a repo, it automatically nudges new team members to configure it on their machine. A lightweight session hook checks whether the pre-commit hook is installed and prompts setup if not — no manual coordination needed.
218
+
219
+ </details>
220
+
200
221
  <details>
201
222
  <summary><strong>Fully Reversible</strong></summary>
202
223
 
203
224
  - **Automatic backups** — originals saved to `.caliber/backups/` before every write
204
225
  - **Score regression guard** — if a regeneration produces a lower score, changes are auto-reverted
205
226
  - **Full undo** — `caliber undo` restores everything to its previous state
227
+ - **Clean uninstall** — `caliber uninstall` removes everything Caliber added (hooks, generated sections, skills, learnings) while preserving your own content
206
228
  - **Dry run** — preview changes with `--dry-run` before applying
207
229
 
208
230
  </details>
@@ -211,9 +233,10 @@ The `refresh` command analyzes your git diff (committed, staged, and unstaged ch
211
233
 
212
234
  | Command | Description |
213
235
  |---|---|
236
+ | `caliber bootstrap` | Install agent skills — the fastest way to get started |
237
+ | `caliber init` | Full setup wizard — analyze, generate, review, install hooks |
214
238
  | `caliber score` | Score config quality (deterministic, no LLM) |
215
239
  | `caliber score --compare <ref>` | Compare current score against a git ref |
216
- | `caliber init` | Full setup wizard — analyze, generate, review, install hooks |
217
240
  | `caliber regenerate` | Re-analyze and regenerate configs (aliases: `regen`, `re`) |
218
241
  | `caliber refresh` | Update docs based on recent code changes |
219
242
  | `caliber skills` | Discover and install community skills |
@@ -221,6 +244,7 @@ The `refresh` command analyzes your git diff (committed, staged, and unstaged ch
221
244
  | `caliber hooks` | Manage auto-refresh hooks |
222
245
  | `caliber config` | Configure LLM provider, API key, and model |
223
246
  | `caliber status` | Show current setup status |
247
+ | `caliber uninstall` | Remove all Caliber resources from a project |
224
248
  | `caliber undo` | Revert all changes made by Caliber |
225
249
 
226
250
  ## FAQ
@@ -235,9 +259,16 @@ No. Caliber shows you a diff of every proposed change. You accept, refine, or de
235
259
  <details>
236
260
  <summary><strong>Does it need an API key?</strong></summary>
237
261
 
238
- **Scoring:** No. `caliber score` runs 100% locally with no LLM.
262
+ **Bootstrap & scoring:** No. Both run 100% locally with no LLM.
263
+
264
+ **Generation** (via `/setup-caliber` or `caliber init`): Uses your existing Claude Code or Cursor subscription (no API key needed), or bring your own key for Anthropic, OpenAI, or Vertex AI.
265
+
266
+ </details>
267
+
268
+ <details>
269
+ <summary><strong>What's the difference between bootstrap and init?</strong></summary>
239
270
 
240
- **Generation:** Uses your existing Claude Code or Cursor subscription (no API key needed), or bring your own key for Anthropic, OpenAI, or Vertex AI.
271
+ `caliber bootstrap` installs agent skills in 2 seconds your agent then runs `/setup-caliber` to handle the rest from inside your session. `caliber init` is the full interactive wizard for users who prefer a CLI-driven setup. Both end up in the same place.
241
272
 
242
273
  </details>
243
274
 
@@ -258,24 +289,10 @@ Yes. Run `caliber init` from any directory. `caliber refresh` can update configs
258
289
  <details>
259
290
  <summary><strong>Does it send my code anywhere?</strong></summary>
260
291
 
261
- Scoring is fully local. Generation sends your project fingerprint (not source code) to whatever LLM provider you configure — the same provider your AI editor already uses. Anonymous usage analytics (no code, no file contents) can be disabled via `caliber config`.
292
+ Scoring is fully local. Generation sends a project summary (languages, structure, dependencies — not source code) to whatever LLM provider you configure — the same provider your AI editor already uses. Anonymous usage analytics (no code, no file contents) can be disabled via `caliber config`.
262
293
 
263
294
  </details>
264
295
 
265
- ## Add a Caliber badge to your repo
266
-
267
- After scoring your project, add a badge to your README:
268
-
269
- ![Caliber Score](https://img.shields.io/badge/caliber-94%2F100-brightgreen)
270
-
271
- Copy this markdown and replace `94` with your actual score:
272
-
273
- ```
274
- ![Caliber Score](https://img.shields.io/badge/caliber-SCORE%2F100-COLOR)
275
- ```
276
-
277
- Color guide: `brightgreen` (90+), `green` (70-89), `yellow` (40-69), `red` (<40).
278
-
279
296
  ## LLM Providers
280
297
 
281
298
  No API key? No problem. Caliber works with your existing AI tool subscription:
@@ -333,11 +350,6 @@ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
333
350
 
334
351
  </details>
335
352
 
336
- ## Requirements
337
-
338
- - **Node.js** >= 20
339
- - **One LLM provider:** your **Claude Code** or **Cursor** subscription (no API key), or an API key for Anthropic / OpenAI / Vertex AI
340
-
341
353
  ## Contributing
342
354
 
343
355
  See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.
@@ -353,6 +365,20 @@ npm run build # Compile
353
365
 
354
366
  Uses [conventional commits](https://www.conventionalcommits.org/) — `feat:` for features, `fix:` for bug fixes.
355
367
 
368
+ ## Add a Caliber badge to your repo
369
+
370
+ After scoring your project, add a badge to your README:
371
+
372
+ ![Caliber Score](https://img.shields.io/badge/caliber-94%2F100-brightgreen)
373
+
374
+ Copy this markdown and replace `94` with your actual score:
375
+
376
+ ```
377
+ ![Caliber Score](https://img.shields.io/badge/caliber-SCORE%2F100-COLOR)
378
+ ```
379
+
380
+ Color guide: `brightgreen` (90+), `green` (70-89), `yellow` (40-69), `red` (<40).
381
+
356
382
  ## License
357
383
 
358
384
  MIT
package/dist/bin.js CHANGED
@@ -3101,6 +3101,7 @@ var SKILL_FORMAT_RULES = `All skills follow the OpenSkills standard (agentskills
3101
3101
 
3102
3102
  Skill field requirements:
3103
3103
  - "name": kebab-case (lowercase letters, numbers, hyphens only). Becomes the directory name.
3104
+ - "name" MUST NOT be any of these reserved names (they are managed by Caliber automatically): "setup-caliber", "find-skills", "save-learning". Do NOT generate skills with these names.
3104
3105
  - "description": MUST include WHAT it does + WHEN to use it with specific trigger phrases. Example: "Manages database migrations. Use when user says 'run migration', 'create migration', 'db schema change', or modifies files in db/migrations/."
3105
3106
  - "content": markdown body only \u2014 do NOT include YAML frontmatter, it is generated from name+description.
3106
3107
 
@@ -3144,7 +3145,7 @@ PRIORITY WHEN CONSTRAINTS CONFLICT: Grounding and reference density matter more
3144
3145
  Note: Permissions, hooks, freshness tracking, and OpenSkills frontmatter are scored automatically by caliber \u2014 do not optimize for them.
3145
3146
  README.md is provided for context only \u2014 do NOT include a readmeMd field in your output.`;
3146
3147
  var OUTPUT_SIZE_CONSTRAINTS = `OUTPUT SIZE CONSTRAINTS \u2014 these are critical:
3147
- - CLAUDE.md / AGENTS.md: MUST be under 150 lines for maximum score. Aim for 100-140 lines. Be concise \u2014 commands, architecture overview, and key conventions. Use bullet points and tables, not prose.
3148
+ - CLAUDE.md / AGENTS.md: MUST be under 400 lines for maximum score. Aim for 200-350 lines. Be thorough \u2014 commands, architecture overview, key conventions, data flow, and important patterns. Use bullet points and tables, not prose.
3148
3149
 
3149
3150
  Pack project references densely in architecture sections \u2014 use inline paths, not prose paragraphs:
3150
3151
  GOOD: **Entry**: \`src/bin.ts\` \u2192 \`src/cli.ts\` \xB7 **LLM** (\`src/llm/\`): \`anthropic.ts\` \xB7 \`vertex.ts\` \xB7 \`openai-compat.ts\`
@@ -3282,7 +3283,7 @@ Structure:
3282
3283
  5. "## Common Issues" (required) \u2014 specific error messages and their fixes. Not "check your config" but "If you see 'Connection refused on port 5432': 1. Verify postgres is running: docker ps | grep postgres 2. Check .env has correct DATABASE_URL"
3283
3284
 
3284
3285
  Rules:
3285
- - Max 150 lines. Focus on actionable instructions, not documentation prose.
3286
+ - Max 400 lines. Focus on actionable instructions, not documentation prose.
3286
3287
  - Study existing code in the project context to extract the real patterns being used. A skill for "create API route" should show the exact file structure, imports, error handling, and naming that existing routes use.
3287
3288
  - Be specific and actionable. GOOD: "Run \`pnpm test -- --filter=api\` to verify". BAD: "Validate the data before proceeding."
3288
3289
  - Never use ambiguous language. Instead of "handle errors properly", write "Wrap the DB call in try/catch. On failure, return { error: string, code: number } matching the ErrorResponse type in \`src/types.ts\`."
@@ -3340,7 +3341,7 @@ Rules:
3340
3341
  - Update the "fileDescriptions" to reflect any changes you make.
3341
3342
 
3342
3343
  Quality constraints \u2014 your changes are scored, so do not break these:
3343
- - CLAUDE.md / AGENTS.md: MUST stay under 150 lines. If adding content, remove less important lines to stay within budget. Do not refuse the user's request \u2014 make the change and trim elsewhere.
3344
+ - CLAUDE.md / AGENTS.md: MUST stay under 400 lines. If adding content, remove less important lines to stay within budget. Do not refuse the user's request \u2014 make the change and trim elsewhere.
3344
3345
  - Avoid vague instructions ("follow best practices", "write clean code", "ensure quality").
3345
3346
  - Do NOT add directory tree listings in code blocks.
3346
3347
  - Do NOT remove existing code blocks \u2014 they contribute to the executable content score.
@@ -3364,7 +3365,7 @@ CONSERVATIVE UPDATE means:
3364
3365
  - NEVER replace specific paths/commands with generic prose
3365
3366
 
3366
3367
  Quality constraints (the output is scored deterministically):
3367
- - CLAUDE.md / AGENTS.md: MUST stay under 150 lines. If the diff adds content, trim the least important lines elsewhere.
3368
+ - CLAUDE.md / AGENTS.md: MUST stay under 400 lines. If the diff adds content, trim the least important lines elsewhere.
3368
3369
  - Keep 3+ code blocks with executable commands \u2014 do not remove code blocks
3369
3370
  - Every file path, command, and identifier must be in backticks
3370
3371
  - ONLY reference file paths that exist in the provided file tree \u2014 do NOT invent paths
@@ -3377,6 +3378,7 @@ Cross-agent sync:
3377
3378
 
3378
3379
  Managed content:
3379
3380
  - Keep managed blocks (<!-- caliber:managed --> ... <!-- /caliber:managed -->) intact
3381
+ - Keep context sync blocks (<!-- caliber:managed:sync --> ... <!-- /caliber:managed:sync -->) intact
3380
3382
  - Do NOT modify CALIBER_LEARNINGS.md \u2014 it is managed separately
3381
3383
  - Preserve any references to CALIBER_LEARNINGS.md in CLAUDE.md
3382
3384
 
@@ -3392,9 +3394,12 @@ Return a JSON object with this exact shape:
3392
3394
  "copilotInstructionFiles": [{"filename": "name.instructions.md", "content": "..."}] or null
3393
3395
  },
3394
3396
  "changesSummary": "<1-2 sentence summary of what was updated and why>",
3397
+ "fileChanges": [{"file": "CLAUDE.md", "description": "added new API routes, updated build commands"}],
3395
3398
  "docsUpdated": ["CLAUDE.md", "README.md"]
3396
3399
  }
3397
3400
 
3401
+ The "fileChanges" array MUST include one entry per file that was updated (non-null in updatedDocs). Each entry describes what specifically changed in that file \u2014 be concrete (e.g. "added auth middleware section" not "updated docs").
3402
+
3398
3403
  Respond with ONLY the JSON object, no markdown fences or extra text.`;
3399
3404
  var LEARN_SYSTEM_PROMPT = `You are an expert developer experience engineer. You analyze raw tool call events from AI coding sessions to extract reusable operational lessons that will help future LLM sessions work more effectively in this project.
3400
3405
 
@@ -5254,7 +5259,7 @@ import fs12 from "fs";
5254
5259
  import path12 from "path";
5255
5260
  function writeClaudeConfig(config) {
5256
5261
  const written = [];
5257
- fs12.writeFileSync("CLAUDE.md", appendLearningsBlock(appendPreCommitBlock(config.claudeMd)));
5262
+ fs12.writeFileSync("CLAUDE.md", appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.claudeMd))));
5258
5263
  written.push("CLAUDE.md");
5259
5264
  if (config.skills?.length) {
5260
5265
  for (const skill of config.skills) {
@@ -5300,7 +5305,8 @@ function writeCursorConfig(config) {
5300
5305
  }
5301
5306
  const preCommitRule = getCursorPreCommitRule();
5302
5307
  const learningsRule = getCursorLearningsRule();
5303
- const allRules = [...config.rules || [], preCommitRule, learningsRule];
5308
+ const syncRule = getCursorSyncRule();
5309
+ const allRules = [...config.rules || [], preCommitRule, learningsRule, syncRule];
5304
5310
  const rulesDir = path13.join(".cursor", "rules");
5305
5311
  if (!fs13.existsSync(rulesDir)) fs13.mkdirSync(rulesDir, { recursive: true });
5306
5312
  for (const rule of allRules) {
@@ -5383,7 +5389,7 @@ function writeGithubCopilotConfig(config) {
5383
5389
  fs15.mkdirSync(".github", { recursive: true });
5384
5390
  fs15.writeFileSync(
5385
5391
  path15.join(".github", "copilot-instructions.md"),
5386
- appendLearningsBlock(appendPreCommitBlock(config.instructions, "copilot"))
5392
+ appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.instructions, "copilot")))
5387
5393
  );
5388
5394
  written.push(".github/copilot-instructions.md");
5389
5395
  }
@@ -6116,11 +6122,11 @@ var POINTS_LEARNED_CONTENT = 2;
6116
6122
  var POINTS_SOURCES_CONFIGURED = 3;
6117
6123
  var POINTS_SOURCES_REFERENCED = 3;
6118
6124
  var TOKEN_BUDGET_THRESHOLDS = [
6119
- { maxTokens: 2e3, points: 6 },
6120
- { maxTokens: 3500, points: 5 },
6121
- { maxTokens: 5e3, points: 4 },
6122
- { maxTokens: 8e3, points: 2 },
6123
- { maxTokens: 12e3, points: 1 }
6125
+ { maxTokens: 5e3, points: 6 },
6126
+ { maxTokens: 8e3, points: 5 },
6127
+ { maxTokens: 12e3, points: 4 },
6128
+ { maxTokens: 16e3, points: 2 },
6129
+ { maxTokens: 24e3, points: 1 }
6124
6130
  ];
6125
6131
  var CODE_BLOCK_THRESHOLDS = [
6126
6132
  { minBlocks: 3, points: 8 },
@@ -9750,27 +9756,36 @@ async function initCommand(options) {
9750
9756
  const bin = resolveCaliber();
9751
9757
  const firstRun = isFirstRun(process.cwd());
9752
9758
  if (firstRun) {
9753
- console.log(brand.bold(`
9759
+ console.log(
9760
+ brand.bold(`
9754
9761
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
9755
9762
  \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
9756
9763
  \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
9757
9764
  \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
9758
9765
  \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
9759
9766
  \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
9760
- `));
9767
+ `)
9768
+ );
9761
9769
  console.log(chalk14.dim(" Keep your AI agent configs in sync \u2014 automatically."));
9762
9770
  console.log(chalk14.dim(" Works across Claude Code, Cursor, Codex, and GitHub Copilot.\n"));
9763
9771
  console.log(title.bold(" How it works:\n"));
9764
- console.log(chalk14.dim(" 1. Connect Auto-detect your LLM provider and agents"));
9765
- console.log(chalk14.dim(" 2. Build Install sync, scan your project, generate configs"));
9766
- console.log(chalk14.dim(" 3. Done Review score and start syncing\n"));
9772
+ console.log(chalk14.dim(" 1. Connect Link your LLM provider and select your agents"));
9773
+ console.log(chalk14.dim(" 2. Setup Detect stack, install sync hooks & skills"));
9774
+ console.log(chalk14.dim(" 3. Generate Audit existing config or generate from scratch"));
9775
+ console.log(chalk14.dim(" 4. Finalize Review changes and score your setup\n"));
9767
9776
  } else {
9768
9777
  console.log(brand.bold("\n CALIBER") + chalk14.dim(" \u2014 setting up continuous sync\n"));
9769
9778
  }
9770
9779
  const platforms = detectPlatforms();
9771
9780
  if (!platforms.claude && !platforms.cursor && !platforms.codex && !platforms.opencode) {
9772
- console.log(chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex, OpenCode)."));
9773
- console.log(chalk14.yellow(" Caliber will still generate config files, but they won't be auto-installed.\n"));
9781
+ console.log(
9782
+ chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex, OpenCode).")
9783
+ );
9784
+ console.log(
9785
+ chalk14.yellow(
9786
+ " Caliber will still generate config files, but they won't be auto-installed.\n"
9787
+ )
9788
+ );
9774
9789
  }
9775
9790
  const report = options.debugReport ? new DebugReport() : null;
9776
9791
  console.log(title.bold(" Step 1/3 \u2014 Connect\n"));
@@ -9825,9 +9840,12 @@ async function initCommand(options) {
9825
9840
  console.log(chalk14.dim(modelLine + "\n"));
9826
9841
  if (report) {
9827
9842
  report.markStep("Provider connection");
9828
- report.addSection("LLM Provider", `- **Provider**: ${config.provider}
9843
+ report.addSection(
9844
+ "LLM Provider",
9845
+ `- **Provider**: ${config.provider}
9829
9846
  - **Model**: ${displayModel}
9830
- - **Fast model**: ${fastModel || "none"}`);
9847
+ - **Fast model**: ${fastModel || "none"}`
9848
+ );
9831
9849
  }
9832
9850
  await validateModel({ fast: true });
9833
9851
  let targetAgent;
@@ -9852,10 +9870,11 @@ async function initCommand(options) {
9852
9870
  console.log(chalk14.dim(` Target: ${targetAgent.join(", ")}
9853
9871
  `));
9854
9872
  trackInitAgentSelected(targetAgent, agentAutoDetected);
9855
- console.log(title.bold(" Step 2/3 \u2014 Build\n"));
9873
+ console.log(title.bold(" Step 2/4 \u2014 Setup\n"));
9874
+ console.log(chalk14.dim(" Installing sync infrastructure...\n"));
9856
9875
  const hookResult = installPreCommitHook();
9857
9876
  if (hookResult.installed) {
9858
- console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed`);
9877
+ console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed \u2014 configs sync on every commit`);
9859
9878
  } else if (hookResult.alreadyInstalled) {
9860
9879
  console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 active`);
9861
9880
  }
@@ -9863,13 +9882,20 @@ async function initCommand(options) {
9863
9882
  console.log(` ${chalk14.green("\u2713")} Onboarding hook \u2014 nudges new team members to set up`);
9864
9883
  const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
9865
9884
  for (const agent of targetAgent) {
9866
- if (agent === "claude" && !fs34.existsSync(".claude")) fs34.mkdirSync(".claude", { recursive: true });
9867
- if (agent === "cursor" && !fs34.existsSync(".cursor")) fs34.mkdirSync(".cursor", { recursive: true });
9868
- if (agent === "codex" && !fs34.existsSync(".agents")) fs34.mkdirSync(".agents", { recursive: true });
9885
+ if (agent === "claude" && !fs34.existsSync(".claude"))
9886
+ fs34.mkdirSync(".claude", { recursive: true });
9887
+ if (agent === "cursor" && !fs34.existsSync(".cursor"))
9888
+ fs34.mkdirSync(".cursor", { recursive: true });
9889
+ if (agent === "codex" && !fs34.existsSync(".agents"))
9890
+ fs34.mkdirSync(".agents", { recursive: true });
9869
9891
  }
9870
9892
  const skillsWritten = ensureBuiltinSkills2();
9871
9893
  if (skillsWritten.length > 0) {
9872
- console.log(` ${chalk14.green("\u2713")} Agent skills installed`);
9894
+ console.log(
9895
+ ` ${chalk14.green("\u2713")} Agent skills installed \u2014 /setup-caliber, /find-skills, /save-learning`
9896
+ );
9897
+ } else {
9898
+ console.log(` ${chalk14.green("\u2713")} Agent skills \u2014 already installed`);
9873
9899
  }
9874
9900
  const hasLearnableAgent = targetAgent.includes("claude") || targetAgent.includes("cursor");
9875
9901
  if (hasLearnableAgent) {
@@ -9879,15 +9905,31 @@ async function initCommand(options) {
9879
9905
  trackInitLearnEnabled(true);
9880
9906
  }
9881
9907
  console.log("");
9908
+ console.log(chalk14.dim(" New team members can run /setup-caliber inside their coding agent"));
9909
+ console.log(chalk14.dim(" (Claude Code or Cursor) to get set up automatically.\n"));
9882
9910
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
9883
- log(options.verbose, `Baseline score: ${baselineScore.score}/100`);
9911
+ console.log(chalk14.dim(" Current config score:"));
9912
+ displayScoreSummary(baselineScore);
9913
+ if (options.verbose) {
9914
+ for (const c of baselineScore.checks) {
9915
+ log(
9916
+ options.verbose,
9917
+ ` ${c.passed ? "\u2713" : "\u2717"} ${c.name}: ${c.earnedPoints}/${c.maxPoints}${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`
9918
+ );
9919
+ }
9920
+ }
9884
9921
  if (report) {
9885
9922
  report.markStep("Baseline scoring");
9886
- report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
9923
+ report.addSection(
9924
+ "Scoring: Baseline",
9925
+ `**Score**: ${baselineScore.score}/100
9887
9926
 
9888
9927
  | Check | Passed | Points | Max |
9889
9928
  |-------|--------|--------|-----|
9890
- ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
9929
+ ` + baselineScore.checks.map(
9930
+ (c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`
9931
+ ).join("\n")
9932
+ );
9891
9933
  report.addSection("Generation: Target Agents", targetAgent.join(", "));
9892
9934
  }
9893
9935
  const hasExistingConfig = !!(baselineScore.checks.some((c) => c.id === "claude_md_exists" && c.passed) || baselineScore.checks.some((c) => c.id === "cursorrules_exists" && c.passed));
@@ -9901,15 +9943,27 @@ async function initCommand(options) {
9901
9943
  ]);
9902
9944
  const passingCount = baselineScore.checks.filter((c) => c.passed).length;
9903
9945
  const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
9904
- trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9905
9946
  let skipGeneration = false;
9906
- if (hasExistingConfig && baselineScore.score === 100 && !options.force) {
9907
- skipGeneration = true;
9947
+ if (hasExistingConfig && baselineScore.score === 100) {
9948
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
9949
+ console.log(chalk14.bold.green("\n Your config is already optimal.\n"));
9950
+ skipGeneration = !options.force;
9908
9951
  } else if (hasExistingConfig && !options.force && !options.autoApprove) {
9909
- console.log(chalk14.dim(` Config score: ${baselineScore.score}/100 \u2014 Caliber can improve this.
9910
- `));
9911
- const improveAnswer = await confirm2({ message: "Improve your existing configs?" });
9912
- skipGeneration = !improveAnswer;
9952
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9953
+ console.log(
9954
+ chalk14.dim("\n Sync infrastructure is ready. Caliber can also audit your existing")
9955
+ );
9956
+ console.log(chalk14.dim(" configs and improve them using AI.\n"));
9957
+ const auditAnswer = await promptInput(" Audit and improve your existing config? (Y/n) ");
9958
+ skipGeneration = auditAnswer.toLowerCase() === "n";
9959
+ } else if (!hasExistingConfig && !options.force && !options.autoApprove) {
9960
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9961
+ console.log(chalk14.dim("\n Sync infrastructure is ready. Caliber can also generate tailored"));
9962
+ console.log(chalk14.dim(" CLAUDE.md, Cursor rules, and Codex configs for your project.\n"));
9963
+ const generateAnswer = await promptInput(" Generate agent configs? (Y/n) ");
9964
+ skipGeneration = generateAnswer.toLowerCase() === "n";
9965
+ } else {
9966
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9913
9967
  }
9914
9968
  if (skipGeneration) {
9915
9969
  const {
@@ -9937,7 +9991,12 @@ async function initCommand(options) {
9937
9991
  if (targetAgent.includes("cursor")) {
9938
9992
  const rulesDir = path28.join(".cursor", "rules");
9939
9993
  if (!fs34.existsSync(rulesDir)) fs34.mkdirSync(rulesDir, { recursive: true });
9940
- for (const rule of [getCursorPreCommitRule2(), getCursorLearningsRule2(), getCursorSyncRule2(), getCursorSetupRule2()]) {
9994
+ for (const rule of [
9995
+ getCursorPreCommitRule2(),
9996
+ getCursorLearningsRule2(),
9997
+ getCursorSyncRule2(),
9998
+ getCursorSetupRule2()
9999
+ ]) {
9941
10000
  fs34.writeFileSync(path28.join(rulesDir, rule.filename), rule.content);
9942
10001
  }
9943
10002
  console.log(` ${chalk14.green("\u2713")} Cursor rules \u2014 added Caliber sync rules`);
@@ -9969,9 +10028,12 @@ async function initCommand(options) {
9969
10028
  trackInitCompleted("sync-only", baselineScore.score);
9970
10029
  console.log(chalk14.bold.green("\n Caliber sync is set up!\n"));
9971
10030
  console.log(chalk14.dim(" Your agent configs will sync automatically on every commit."));
9972
- console.log(chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n"));
10031
+ console.log(
10032
+ chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n")
10033
+ );
9973
10034
  return;
9974
10035
  }
10036
+ console.log(title.bold("\n Step 3/4 \u2014 Generate\n"));
9975
10037
  const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
9976
10038
  console.log(chalk14.dim(genModelInfo + "\n"));
9977
10039
  if (report) report.markStep("Generation");
@@ -9987,8 +10049,14 @@ async function initCommand(options) {
9987
10049
  const TASK_STACK = display.add("Detecting project stack", { pipelineLabel: "Scan" });
9988
10050
  const TASK_CONFIG = display.add("Generating configs", { depth: 1, pipelineLabel: "Generate" });
9989
10051
  const TASK_SKILLS_GEN = display.add("Generating skills", { depth: 2, pipelineLabel: "Skills" });
9990
- const TASK_SKILLS_SEARCH = display.add("Searching community skills", { depth: 1, pipelineLabel: "Search", pipelineRow: 1 });
9991
- const TASK_SCORE_REFINE = display.add("Validating & refining config", { pipelineLabel: "Validate" });
10052
+ const TASK_SKILLS_SEARCH = display.add("Searching community skills", {
10053
+ depth: 1,
10054
+ pipelineLabel: "Search",
10055
+ pipelineRow: 1
10056
+ });
10057
+ const TASK_SCORE_REFINE = display.add("Validating & refining config", {
10058
+ pipelineLabel: "Validate"
10059
+ });
9992
10060
  display.start();
9993
10061
  display.enableWaitingContent();
9994
10062
  try {
@@ -9998,21 +10066,39 @@ async function initCommand(options) {
9998
10066
  const stackSummary = stackParts.join(", ") || "no languages";
9999
10067
  const largeRepoNote = fingerprint.fileTree.length > 5e3 ? ` (${fingerprint.fileTree.length.toLocaleString()} files, smart sampling active)` : "";
10000
10068
  display.update(TASK_STACK, "done", stackSummary + largeRepoNote);
10001
- trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
10002
- log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
10069
+ trackInitProjectDiscovered(
10070
+ fingerprint.languages.length,
10071
+ fingerprint.frameworks.length,
10072
+ fingerprint.fileTree.length
10073
+ );
10074
+ log(
10075
+ options.verbose,
10076
+ `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`
10077
+ );
10003
10078
  const cliSources = options.source || [];
10004
10079
  const workspaces = getDetectedWorkspaces(process.cwd());
10005
10080
  const sources2 = resolveAllSources(process.cwd(), cliSources, workspaces);
10006
10081
  if (sources2.length > 0) {
10007
10082
  fingerprint.sources = sources2;
10008
- log(options.verbose, `Sources: ${sources2.length} resolved (${sources2.map((s) => s.name).join(", ")})`);
10083
+ log(
10084
+ options.verbose,
10085
+ `Sources: ${sources2.length} resolved (${sources2.map((s) => s.name).join(", ")})`
10086
+ );
10009
10087
  }
10010
10088
  if (report) {
10011
- report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
10089
+ report.addJson("Fingerprint: Git", {
10090
+ remote: fingerprint.gitRemoteUrl,
10091
+ packageName: fingerprint.packageName
10092
+ });
10012
10093
  report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
10013
- report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
10094
+ report.addJson("Fingerprint: Detected Stack", {
10095
+ languages: fingerprint.languages,
10096
+ frameworks: fingerprint.frameworks,
10097
+ tools: fingerprint.tools
10098
+ });
10014
10099
  report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
10015
- if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
10100
+ if (fingerprint.codeAnalysis)
10101
+ report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
10016
10102
  }
10017
10103
  const isEmpty = fingerprint.fileTree.length < 3;
10018
10104
  if (isEmpty) {
@@ -10043,13 +10129,26 @@ async function initCommand(options) {
10043
10129
  let passingChecks;
10044
10130
  let currentScore;
10045
10131
  if (hasExistingConfig && localBaseline.score >= 95 && !options.force) {
10046
- const currentLlmFixable = localBaseline.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
10047
- failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
10132
+ const currentLlmFixable = localBaseline.checks.filter(
10133
+ (c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id)
10134
+ );
10135
+ failingChecks = currentLlmFixable.map((c) => ({
10136
+ name: c.name,
10137
+ suggestion: c.suggestion,
10138
+ fix: c.fix
10139
+ }));
10048
10140
  passingChecks = localBaseline.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
10049
10141
  currentScore = localBaseline.score;
10050
10142
  }
10051
10143
  if (report) {
10052
- const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
10144
+ const fullPrompt = buildGeneratePrompt(
10145
+ fingerprint,
10146
+ targetAgent,
10147
+ fingerprint.description,
10148
+ failingChecks,
10149
+ currentScore,
10150
+ passingChecks
10151
+ );
10053
10152
  report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
10054
10153
  }
10055
10154
  const result = await generateSetup(
@@ -10169,8 +10268,11 @@ async function initCommand(options) {
10169
10268
  if (rawOutput) report.addCodeBlock("Generation: Raw LLM Response", rawOutput);
10170
10269
  report.addJson("Generation: Parsed Config", generatedSetup);
10171
10270
  }
10172
- log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
10173
- console.log(title.bold(" Step 3/3 \u2014 Done\n"));
10271
+ log(
10272
+ options.verbose,
10273
+ `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`
10274
+ );
10275
+ console.log(title.bold(" Step 4/4 \u2014 Finalize\n"));
10174
10276
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
10175
10277
  const staged = stageFiles(setupFiles, process.cwd());
10176
10278
  const totalChanges = staged.newFiles + staged.modifiedFiles;
@@ -10181,10 +10283,18 @@ async function initCommand(options) {
10181
10283
  }
10182
10284
  console.log("");
10183
10285
  }
10184
- console.log(chalk14.dim(` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`));
10286
+ console.log(
10287
+ chalk14.dim(
10288
+ ` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`
10289
+ )
10290
+ );
10185
10291
  if (skillSearchResult.results.length > 0) {
10186
- console.log(chalk14.dim(` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
10187
- `));
10292
+ console.log(
10293
+ chalk14.dim(
10294
+ ` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
10295
+ `
10296
+ )
10297
+ );
10188
10298
  } else {
10189
10299
  console.log("");
10190
10300
  }
@@ -10220,8 +10330,12 @@ async function initCommand(options) {
10220
10330
  }
10221
10331
  const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
10222
10332
  const restaged = stageFiles(updatedFiles, process.cwd());
10223
- console.log(chalk14.dim(` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
10224
- `));
10333
+ console.log(
10334
+ chalk14.dim(
10335
+ ` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
10336
+ `
10337
+ )
10338
+ );
10225
10339
  printSetupSummary(generatedSetup);
10226
10340
  const { openReview: openRev } = await Promise.resolve().then(() => (init_review(), review_exports));
10227
10341
  await openRev("terminal", restaged.stagedFiles);
@@ -10247,7 +10361,8 @@ async function initCommand(options) {
10247
10361
  const agentRefs = [];
10248
10362
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
10249
10363
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
10250
- if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
10364
+ if (agentRefs.length === 0)
10365
+ agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
10251
10366
  const stubContent = `# AGENTS.md
10252
10367
 
10253
10368
  This project uses AI coding agents configured by [Caliber](https://github.com/caliber-ai-org/ai-setup).
@@ -10294,24 +10409,39 @@ ${agentRefs.join(" ")}
10294
10409
  if (afterScore.score < baselineScore.score) {
10295
10410
  trackInitScoreRegression(baselineScore.score, afterScore.score);
10296
10411
  console.log("");
10297
- console.log(chalk14.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
10412
+ console.log(
10413
+ chalk14.yellow(
10414
+ ` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
10415
+ )
10416
+ );
10298
10417
  try {
10299
10418
  const { restored, removed } = undoSetup();
10300
10419
  if (restored.length > 0 || removed.length > 0) {
10301
- console.log(chalk14.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
10420
+ console.log(
10421
+ chalk14.dim(
10422
+ ` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`
10423
+ )
10424
+ );
10302
10425
  }
10303
10426
  } catch {
10304
10427
  }
10305
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n"));
10428
+ console.log(
10429
+ chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n")
10430
+ );
10306
10431
  return;
10307
10432
  }
10308
10433
  if (report) {
10309
10434
  report.markStep("Post-write scoring");
10310
- report.addSection("Scoring: Post-Write", `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
10435
+ report.addSection(
10436
+ "Scoring: Post-Write",
10437
+ `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
10311
10438
 
10312
10439
  | Check | Passed | Points | Max |
10313
10440
  |-------|--------|--------|-----|
10314
- ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
10441
+ ` + afterScore.checks.map(
10442
+ (c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`
10443
+ ).join("\n")
10444
+ );
10315
10445
  }
10316
10446
  recordScore(afterScore, "init");
10317
10447
  trackInitCompleted("full-generation", afterScore.score);
@@ -10319,7 +10449,10 @@ ${agentRefs.join(" ")}
10319
10449
  if (options.verbose) {
10320
10450
  log(options.verbose, `Final score: ${afterScore.score}/100`);
10321
10451
  for (const c of afterScore.checks.filter((ch) => !ch.passed)) {
10322
- log(options.verbose, ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
10452
+ log(
10453
+ options.verbose,
10454
+ ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`
10455
+ );
10323
10456
  }
10324
10457
  }
10325
10458
  let communitySkillsInstalled = 0;
@@ -10336,21 +10469,32 @@ ${agentRefs.join(" ")}
10336
10469
  const done = chalk14.green("\u2713");
10337
10470
  console.log(chalk14.bold.green("\n Caliber is set up!\n"));
10338
10471
  console.log(chalk14.bold(" What's configured:\n"));
10339
- console.log(` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`);
10340
- console.log(` ${done} Config generated ${chalk14.dim(`score: ${afterScore.score}/100`)}`);
10341
- console.log(` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`);
10472
+ console.log(
10473
+ ` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`
10474
+ );
10475
+ console.log(
10476
+ ` ${done} Config generated ${title(`${bin} score`)} ${chalk14.dim("for full breakdown")}`
10477
+ );
10478
+ console.log(
10479
+ ` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`
10480
+ );
10342
10481
  if (hasLearnableAgent) {
10343
- console.log(` ${done} Session learning ${chalk14.dim("learns from your corrections")}`);
10482
+ console.log(
10483
+ ` ${done} Session learning ${chalk14.dim("agent learns from your feedback")}`
10484
+ );
10344
10485
  }
10345
10486
  if (communitySkillsInstalled > 0) {
10346
- console.log(` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} installed for your stack`)}`);
10487
+ console.log(
10488
+ ` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} skill${communitySkillsInstalled > 1 ? "s" : ""} installed for your stack`)}`
10489
+ );
10347
10490
  }
10348
10491
  console.log(chalk14.bold("\n What happens next:\n"));
10349
- console.log(chalk14.dim(" Every commit syncs your agent configs automatically."));
10350
- console.log(chalk14.dim(" New team members run /setup-caliber to get set up instantly.\n"));
10351
- console.log(` ${title(`${bin} score`)} Full scoring breakdown`);
10352
- console.log(` ${title(`${bin} skills`)} Find community skills`);
10353
- console.log(` ${title(`${bin} undo`)} Revert changes`);
10492
+ console.log(chalk14.dim(" Every commit will automatically sync your agent configs."));
10493
+ console.log(chalk14.dim(" New team members can run /setup-caliber to get set up instantly.\n"));
10494
+ console.log(chalk14.bold(" Explore:\n"));
10495
+ console.log(` ${title(`${bin} score`)} Full scoring breakdown with improvement tips`);
10496
+ console.log(` ${title(`${bin} skills`)} Find community skills for your stack`);
10497
+ console.log(` ${title(`${bin} undo`)} Revert all changes from this run`);
10354
10498
  console.log(` ${title(`${bin} uninstall`)} Remove Caliber completely`);
10355
10499
  console.log("");
10356
10500
  if (options.showTokens) {
@@ -10360,8 +10504,10 @@ ${agentRefs.join(" ")}
10360
10504
  report.markStep("Finished");
10361
10505
  const reportPath = path28.join(process.cwd(), ".caliber", "debug-report.md");
10362
10506
  report.write(reportPath);
10363
- console.log(chalk14.dim(` Debug report written to ${path28.relative(process.cwd(), reportPath)}
10364
- `));
10507
+ console.log(
10508
+ chalk14.dim(` Debug report written to ${path28.relative(process.cwd(), reportPath)}
10509
+ `)
10510
+ );
10365
10511
  }
10366
10512
  }
10367
10513
 
@@ -10914,6 +11060,13 @@ Changed files: ${diff.changedFiles.join(", ")}`);
10914
11060
  parts.push("\n[.cursorrules]");
10915
11061
  parts.push(existingDocs.cursorrules);
10916
11062
  }
11063
+ if (existingDocs.claudeSkills?.length) {
11064
+ for (const skill of existingDocs.claudeSkills) {
11065
+ parts.push(`
11066
+ [.claude/skills/${skill.filename}]`);
11067
+ parts.push(skill.content);
11068
+ }
11069
+ }
10917
11070
  if (existingDocs.cursorRules?.length) {
10918
11071
  for (const rule of existingDocs.cursorRules) {
10919
11072
  if (rule.filename.startsWith("caliber-")) continue;
@@ -11176,6 +11329,15 @@ function clearRefreshError() {
11176
11329
  } catch {
11177
11330
  }
11178
11331
  }
11332
+ function detectSyncedAgents(writtenFiles) {
11333
+ const agents = [];
11334
+ const joined = writtenFiles.join(" ");
11335
+ if (joined.includes("CLAUDE.md") || joined.includes(".claude/")) agents.push("Claude Code");
11336
+ if (joined.includes(".cursor/") || joined.includes(".cursorrules")) agents.push("Cursor");
11337
+ if (joined.includes("copilot-instructions") || joined.includes(".github/instructions/")) agents.push("Copilot");
11338
+ if (joined.includes("AGENTS.md") || joined.includes(".agents/")) agents.push("Codex");
11339
+ return agents;
11340
+ }
11179
11341
  function log2(quiet, ...args) {
11180
11342
  if (!quiet) console.log(...args);
11181
11343
  }
@@ -11338,8 +11500,18 @@ async function refreshSingleRepo(repoDir, options) {
11338
11500
  }
11339
11501
  recordScore(postScore, "refresh");
11340
11502
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
11503
+ const fileChangesMap = new Map(
11504
+ (response.fileChanges || []).map((fc) => [fc.file, fc.description])
11505
+ );
11341
11506
  for (const file of written) {
11342
- log2(quiet, ` ${chalk19.green("\u2713")} ${file}`);
11507
+ const desc = fileChangesMap.get(file);
11508
+ const suffix = desc ? chalk19.dim(` \u2014 ${desc}`) : "";
11509
+ log2(quiet, ` ${chalk19.green("\u2713")} ${file}${suffix}`);
11510
+ }
11511
+ const agents = detectSyncedAgents(written);
11512
+ if (agents.length > 1) {
11513
+ log2(quiet, chalk19.cyan(`
11514
+ ${agents.length} agent formats in sync (${agents.join(", ")})`));
11343
11515
  }
11344
11516
  if (response.changesSummary) {
11345
11517
  log2(quiet, chalk19.dim(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.36.0",
3
+ "version": "1.37.0-dev.1774891449",
4
4
  "description": "AI context infrastructure for coding agents — keeps CLAUDE.md, Cursor rules, and skills in sync as your codebase evolves",
5
5
  "type": "module",
6
6
  "bin": {