@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.
- package/README.md +82 -56
- package/dist/bin.js +249 -77
- 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
|
|
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
|
-
|
|
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
|
-
|
|
80
|
+
npx @rely-ai/caliber bootstrap ← one-time, 2 seconds
|
|
74
81
|
│
|
|
75
82
|
▼
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
│
|
|
81
|
-
│
|
|
82
|
-
│
|
|
83
|
-
│
|
|
84
|
-
│
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
|
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
|
-

|
|
270
|
-
|
|
271
|
-
Copy this markdown and replace `94` with your actual score:
|
|
272
|
-
|
|
273
|
-
```
|
|
274
|
-

|
|
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
|
+

|
|
373
|
+
|
|
374
|
+
Copy this markdown and replace `94` with your actual score:
|
|
375
|
+
|
|
376
|
+
```
|
|
377
|
+

|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
6120
|
-
{ maxTokens:
|
|
6121
|
-
{ maxTokens:
|
|
6122
|
-
{ maxTokens:
|
|
6123
|
-
{ maxTokens:
|
|
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(
|
|
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
|
|
9765
|
-
console.log(chalk14.dim(" 2.
|
|
9766
|
-
console.log(chalk14.dim(" 3.
|
|
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(
|
|
9773
|
-
|
|
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(
|
|
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/
|
|
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"))
|
|
9867
|
-
|
|
9868
|
-
if (agent === "
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
9907
|
-
|
|
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
|
-
|
|
9910
|
-
|
|
9911
|
-
|
|
9912
|
-
|
|
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 [
|
|
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(
|
|
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", {
|
|
9991
|
-
|
|
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(
|
|
10002
|
-
|
|
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(
|
|
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", {
|
|
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", {
|
|
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)
|
|
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(
|
|
10047
|
-
|
|
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(
|
|
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(
|
|
10173
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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)
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
10340
|
-
|
|
10341
|
-
|
|
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(
|
|
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(
|
|
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
|
|
10350
|
-
console.log(chalk14.dim(" New team members run /setup-caliber to get set up instantly.\n"));
|
|
10351
|
-
console.log(
|
|
10352
|
-
console.log(` ${title(`${bin}
|
|
10353
|
-
console.log(` ${title(`${bin}
|
|
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(
|
|
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
|
-
|
|
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