@rely-ai/caliber 1.31.0-dev.1774710550 → 1.31.0-dev.1774711564

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 (2) hide show
  1. package/dist/bin.js +558 -519
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -230,6 +230,288 @@ var init_types = __esm({
230
230
  }
231
231
  });
232
232
 
233
+ // src/lib/builtin-skills.ts
234
+ var builtin_skills_exports = {};
235
+ __export(builtin_skills_exports, {
236
+ BUILTIN_SKILLS: () => BUILTIN_SKILLS,
237
+ FIND_SKILLS_SKILL: () => FIND_SKILLS_SKILL,
238
+ SAVE_LEARNING_SKILL: () => SAVE_LEARNING_SKILL,
239
+ SETUP_CALIBER_SKILL: () => SETUP_CALIBER_SKILL,
240
+ buildSkillContent: () => buildSkillContent,
241
+ ensureBuiltinSkills: () => ensureBuiltinSkills
242
+ });
243
+ import fs17 from "fs";
244
+ import path16 from "path";
245
+ function buildSkillContent(skill) {
246
+ const frontmatter = `---
247
+ name: ${skill.name}
248
+ description: ${skill.description}
249
+ ---
250
+
251
+ `;
252
+ return frontmatter + skill.content;
253
+ }
254
+ function getFindSkillsContent() {
255
+ const bin = resolveCaliber();
256
+ return `# Find Skills
257
+
258
+ Search the public skill registry for community-contributed skills
259
+ relevant to the user's current task and install them into this project.
260
+
261
+ ## Instructions
262
+
263
+ 1. Identify the key technologies, frameworks, or task types from the
264
+ user's request that might have community skills available
265
+ 2. Ask the user: "Would you like me to search for community skills
266
+ for [identified technologies]?"
267
+ 3. If the user agrees, run:
268
+ \`\`\`bash
269
+ ${bin} skills --query "<relevant terms>"
270
+ \`\`\`
271
+ This outputs the top 5 matching skills with scores and descriptions.
272
+ 4. Present the results to the user and ask which ones to install
273
+ 5. Install the selected skills:
274
+ \`\`\`bash
275
+ ${bin} skills --install <slug1>,<slug2>
276
+ \`\`\`
277
+ 6. Read the installed SKILL.md files to load them into your current
278
+ context so you can use them immediately in this session
279
+ 7. Summarize what was installed and continue with the user's task
280
+
281
+ ## Examples
282
+
283
+ User: "let's build a web app using React"
284
+ -> "I notice you want to work with React. Would you like me to search
285
+ for community skills that could help with React development?"
286
+ -> If yes: run \`${bin} skills --query "react frontend"\`
287
+ -> Show the user the results, ask which to install
288
+ -> Run \`${bin} skills --install <selected-slugs>\`
289
+ -> Read the installed files and continue
290
+
291
+ User: "help me set up Docker for this project"
292
+ -> "Would you like me to search for Docker-related skills?"
293
+ -> If yes: run \`${bin} skills --query "docker deployment"\`
294
+
295
+ User: "I need to write tests for this Python ML pipeline"
296
+ -> "Would you like me to find skills for Python ML testing?"
297
+ -> If yes: run \`${bin} skills --query "python machine-learning testing"\`
298
+
299
+ ## When NOT to trigger
300
+
301
+ - The user is working within an already well-configured area
302
+ - You already suggested skills for this technology in this session
303
+ - The user is in the middle of urgent debugging or time-sensitive work
304
+ - The technology is too generic (e.g. just "code" or "programming")
305
+ `;
306
+ }
307
+ function getSaveLearningContent() {
308
+ const bin = resolveCaliber();
309
+ return `# Save Learning
310
+
311
+ Save a user's instruction or preference as a persistent learning that
312
+ will be applied in all future sessions on this project.
313
+
314
+ ## Instructions
315
+
316
+ 1. Detect when the user gives an instruction to remember, such as:
317
+ - "remember this", "save this", "always do X", "never do Y"
318
+ - "from now on", "going forward", "in this project we..."
319
+ - Any stated convention, preference, or rule
320
+ 2. Refine the instruction into a clean, actionable learning bullet with
321
+ an appropriate type prefix:
322
+ - \`**[convention]**\` \u2014 coding style, workflow, git conventions
323
+ - \`**[pattern]**\` \u2014 reusable code patterns
324
+ - \`**[anti-pattern]**\` \u2014 things to avoid
325
+ - \`**[preference]**\` \u2014 personal/team preferences
326
+ - \`**[context]**\` \u2014 project-specific context
327
+ 3. Show the refined learning to the user and ask for confirmation
328
+ 4. If confirmed, run:
329
+ \`\`\`bash
330
+ ${bin} learn add "<refined learning>"
331
+ \`\`\`
332
+ For personal preferences (not project-level), add \`--personal\`:
333
+ \`\`\`bash
334
+ ${bin} learn add --personal "<refined learning>"
335
+ \`\`\`
336
+ 5. Stage the learnings file for the next commit:
337
+ \`\`\`bash
338
+ git add CALIBER_LEARNINGS.md
339
+ \`\`\`
340
+
341
+ ## Examples
342
+
343
+ User: "when developing features, push to next branch not master, remember it"
344
+ -> Refine: \`**[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`\`
345
+ -> "I'll save this as a project learning:
346
+ **[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`
347
+ Save for future sessions?"
348
+ -> If yes: run \`${bin} learn add "**[convention]** Push feature commits to the next branch, not master"\`
349
+ -> Run \`git add CALIBER_LEARNINGS.md\`
350
+
351
+ User: "always use bun instead of npm"
352
+ -> Refine: \`**[preference]** Use \\\`bun\\\` instead of \\\`npm\\\` for package management\`
353
+ -> Confirm and save
354
+
355
+ User: "never use any in TypeScript, use unknown instead"
356
+ -> Refine: \`**[convention]** Use \\\`unknown\\\` instead of \\\`any\\\` in TypeScript\`
357
+ -> Confirm and save
358
+
359
+ ## When NOT to trigger
360
+
361
+ - The user is giving a one-time instruction for the current task only
362
+ - The instruction is too vague to be actionable
363
+ - The user explicitly says "just for now" or "only this time"
364
+ `;
365
+ }
366
+ function getSetupCaliberContent() {
367
+ const bin = resolveCaliber();
368
+ return `# Setup Caliber
369
+
370
+ Set up Caliber for automatic AI agent context sync on this project.
371
+ Caliber keeps your CLAUDE.md, Cursor rules, Copilot instructions, and Codex configs
372
+ in sync with your codebase \u2014 automatically on every commit.
373
+
374
+ ## Instructions
375
+
376
+ 1. Check if Caliber is already set up locally:
377
+ \`\`\`bash
378
+ grep -q "caliber" .git/hooks/pre-commit 2>/dev/null && echo "hook-active" || echo "no-hook"
379
+ \`\`\`
380
+
381
+ 2. If **hook-active**, tell the user: "Caliber is already set up on this repo.
382
+ Your agent configs update automatically on every commit." Then stop.
383
+
384
+ 3. If **no-hook**, ask the user: "Are you setting up Caliber for yourself (solo)
385
+ or for your team?"
386
+
387
+ ### Solo Setup
388
+
389
+ a. Tell the user: "I'll set up Caliber to sync your agent configs automatically
390
+ on every commit."
391
+ b. Install the pre-commit hook:
392
+ \`\`\`bash
393
+ ${bin} hooks --install
394
+ \`\`\`
395
+ c. Run a refresh to make sure configs are current:
396
+ \`\`\`bash
397
+ ${bin} refresh
398
+ \`\`\`
399
+ d. Tell the user what happened and that configs will auto-sync on every commit.
400
+
401
+ ### Team Setup
402
+
403
+ a. Tell the user: "I'll set up Caliber for your team \u2014 local hooks for you,
404
+ plus a GitHub Action for automatic sync across the team."
405
+ b. Install the local pre-commit hook:
406
+ \`\`\`bash
407
+ ${bin} hooks --install
408
+ \`\`\`
409
+ c. Run a refresh:
410
+ \`\`\`bash
411
+ ${bin} refresh
412
+ \`\`\`
413
+ d. Create the GitHub Action workflow for nightly sync. Write this file to
414
+ \`.github/workflows/caliber-sync.yml\`:
415
+ \`\`\`yaml
416
+ name: Caliber Sync
417
+ on:
418
+ schedule:
419
+ - cron: '0 3 * * 1-5'
420
+ pull_request:
421
+ types: [opened, synchronize]
422
+ workflow_dispatch:
423
+ jobs:
424
+ sync:
425
+ runs-on: ubuntu-latest
426
+ steps:
427
+ - uses: actions/checkout@v4
428
+ - uses: caliber-ai-org/ai-setup@v1
429
+ with:
430
+ mode: sync
431
+ auto-refresh: true
432
+ comment: true
433
+ github-token: \${{ secrets.GITHUB_TOKEN }}
434
+ env:
435
+ ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
436
+ \`\`\`
437
+ e. Tell the user: "Created the GitHub Action workflow. Add your ANTHROPIC_API_KEY
438
+ to your repo secrets (Settings \u2192 Secrets \u2192 Actions), then commit and push this
439
+ workflow file. From now on, every PR gets a Caliber sync check and configs
440
+ refresh nightly."
441
+ f. Offer to commit the workflow file and the updated configs.
442
+
443
+ ### If \`${bin}\` is not found
444
+
445
+ Install it first:
446
+ \`\`\`bash
447
+ npm install -g @rely-ai/caliber
448
+ \`\`\`
449
+ Or use npx (no install needed):
450
+ \`\`\`bash
451
+ npx @rely-ai/caliber hooks --install
452
+ \`\`\`
453
+
454
+ ## When to trigger
455
+
456
+ - When a developer first opens this project and Caliber hooks are not installed
457
+ - When the user asks about keeping agent configs up to date
458
+ - When the user asks "how do I set up Caliber" or "what is Caliber"
459
+
460
+ ## When NOT to trigger
461
+
462
+ - Hooks are already installed and working
463
+ - The user is in the middle of time-sensitive work
464
+ `;
465
+ }
466
+ function ensureBuiltinSkills() {
467
+ const written = [];
468
+ for (const { platformDir, skillsDir } of PLATFORM_CONFIGS) {
469
+ if (!fs17.existsSync(platformDir)) continue;
470
+ for (const skill of BUILTIN_SKILLS) {
471
+ const skillPath = path16.join(skillsDir, skill.name, "SKILL.md");
472
+ if (fs17.existsSync(skillPath)) continue;
473
+ fs17.mkdirSync(path16.dirname(skillPath), { recursive: true });
474
+ fs17.writeFileSync(skillPath, buildSkillContent(skill));
475
+ written.push(skillPath);
476
+ }
477
+ }
478
+ return written;
479
+ }
480
+ var FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL, SETUP_CALIBER_SKILL, BUILTIN_SKILLS, PLATFORM_CONFIGS;
481
+ var init_builtin_skills = __esm({
482
+ "src/lib/builtin-skills.ts"() {
483
+ "use strict";
484
+ init_resolve_caliber();
485
+ FIND_SKILLS_SKILL = {
486
+ name: "find-skills",
487
+ description: "Discovers and installs community skills from the public registry. Use when the user mentions a technology, framework, or task that could benefit from specialized skills not yet installed, asks 'how do I do X', 'find a skill for X', or starts work in a new technology area. Proactively suggest when the user's task involves tools or frameworks without existing skills.",
488
+ get content() {
489
+ return getFindSkillsContent();
490
+ }
491
+ };
492
+ SAVE_LEARNING_SKILL = {
493
+ name: "save-learning",
494
+ description: "Saves user instructions as persistent learnings for future sessions. Use when the user says 'remember this', 'always do X', 'from now on', 'never do Y', or gives any instruction they want persisted across sessions. Proactively suggest when the user states a preference, convention, or rule they clearly want followed in the future.",
495
+ get content() {
496
+ return getSaveLearningContent();
497
+ }
498
+ };
499
+ SETUP_CALIBER_SKILL = {
500
+ name: "setup-caliber",
501
+ description: "Sets up Caliber for automatic AI agent context sync. Installs pre-commit hooks so CLAUDE.md, Cursor rules, and Copilot instructions update automatically on every commit. Use when Caliber hooks are not yet installed or when the user asks about keeping agent configs in sync.",
502
+ get content() {
503
+ return getSetupCaliberContent();
504
+ }
505
+ };
506
+ BUILTIN_SKILLS = [FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL, SETUP_CALIBER_SKILL];
507
+ PLATFORM_CONFIGS = [
508
+ { platformDir: ".claude", skillsDir: path16.join(".claude", "skills") },
509
+ { platformDir: ".cursor", skillsDir: path16.join(".cursor", "skills") },
510
+ { platformDir: ".agents", skillsDir: path16.join(".agents", "skills") }
511
+ ];
512
+ }
513
+ });
514
+
233
515
  // src/utils/editor.ts
234
516
  import { execSync as execSync14, spawn as spawn3 } from "child_process";
235
517
  import fs27 from "fs";
@@ -4488,507 +4770,243 @@ function appendPreCommitBlock(content) {
4488
4770
  if (hasPreCommitBlock(content)) return content;
4489
4771
  const trimmed = content.trimEnd();
4490
4772
  return trimmed + "\n\n" + getPreCommitBlock() + "\n";
4491
- }
4492
- function getCursorPreCommitRule() {
4493
- return { filename: CURSOR_RULE_FILENAME, content: getCursorRuleContent() };
4494
- }
4495
- var LEARNINGS_BLOCK_START = "<!-- caliber:managed:learnings -->";
4496
- var LEARNINGS_BLOCK_END = "<!-- /caliber:managed:learnings -->";
4497
- var LEARNINGS_BLOCK = `${LEARNINGS_BLOCK_START}
4498
- ## Session Learnings
4499
-
4500
- Read \`CALIBER_LEARNINGS.md\` for patterns and anti-patterns learned from previous sessions.
4501
- These are auto-extracted from real tool usage \u2014 treat them as project-specific rules.
4502
- ${LEARNINGS_BLOCK_END}`;
4503
- var CURSOR_LEARNINGS_FILENAME = "caliber-learnings.mdc";
4504
- var CURSOR_LEARNINGS_CONTENT = `---
4505
- description: Reference session-learned patterns from CALIBER_LEARNINGS.md
4506
- alwaysApply: true
4507
- ---
4508
- Read \`CALIBER_LEARNINGS.md\` for patterns and anti-patterns learned from previous sessions.
4509
- These are auto-extracted from real tool usage \u2014 treat them as project-specific rules.
4510
- `;
4511
- function hasLearningsBlock(content) {
4512
- return content.includes(LEARNINGS_BLOCK_START);
4513
- }
4514
- function appendLearningsBlock(content) {
4515
- if (hasLearningsBlock(content)) return content;
4516
- const trimmed = content.trimEnd();
4517
- return trimmed + "\n\n" + LEARNINGS_BLOCK + "\n";
4518
- }
4519
- function getCursorLearningsRule() {
4520
- return { filename: CURSOR_LEARNINGS_FILENAME, content: CURSOR_LEARNINGS_CONTENT };
4521
- }
4522
- var SYNC_BLOCK_START = "<!-- caliber:managed:sync -->";
4523
- var SYNC_BLOCK_END = "<!-- /caliber:managed:sync -->";
4524
- function getSyncBlock() {
4525
- const bin = resolveCaliber();
4526
- return `${SYNC_BLOCK_START}
4527
- ## Context Sync
4528
-
4529
- This project uses [Caliber](https://github.com/rely-ai/caliber) to keep AI agent configs in sync across Claude Code, Cursor, Copilot, and Codex.
4530
- Configs update automatically before each commit via \`${bin} refresh\`.
4531
- If the pre-commit hook is not set up, run \`${bin} hooks --install\` to enable automatic sync.
4532
- ${SYNC_BLOCK_END}`;
4533
- }
4534
- function hasSyncBlock(content) {
4535
- return content.includes(SYNC_BLOCK_START);
4536
- }
4537
- function appendSyncBlock(content) {
4538
- if (hasSyncBlock(content)) return content;
4539
- const trimmed = content.trimEnd();
4540
- return trimmed + "\n\n" + getSyncBlock() + "\n";
4541
- }
4542
- var CURSOR_SYNC_FILENAME = "caliber-sync.mdc";
4543
- function getCursorSyncContent() {
4544
- const bin = resolveCaliber();
4545
- return `---
4546
- description: This project uses Caliber for automatic AI agent context sync
4547
- alwaysApply: true
4548
- ---
4549
- This project uses Caliber to keep AI agent configs (CLAUDE.md, Cursor rules, Copilot instructions)
4550
- in sync with the codebase automatically. Before each commit, run \`${bin} refresh\` to sync configs.
4551
- If \`${bin}\` is not found, tell the user: "This project uses Caliber for agent config sync. Install with: npm install -g @rely-ai/caliber"
4552
- `;
4553
- }
4554
- function getCursorSyncRule() {
4555
- return { filename: CURSOR_SYNC_FILENAME, content: getCursorSyncContent() };
4556
- }
4557
-
4558
- // src/writers/claude/index.ts
4559
- function writeClaudeConfig(config) {
4560
- const written = [];
4561
- fs12.writeFileSync("CLAUDE.md", appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.claudeMd))));
4562
- written.push("CLAUDE.md");
4563
- if (config.skills?.length) {
4564
- for (const skill of config.skills) {
4565
- const skillDir = path11.join(".claude", "skills", skill.name);
4566
- if (!fs12.existsSync(skillDir)) fs12.mkdirSync(skillDir, { recursive: true });
4567
- const skillPath = path11.join(skillDir, "SKILL.md");
4568
- const frontmatter = [
4569
- "---",
4570
- `name: ${skill.name}`,
4571
- `description: ${skill.description}`,
4572
- "---",
4573
- ""
4574
- ].join("\n");
4575
- fs12.writeFileSync(skillPath, frontmatter + skill.content);
4576
- written.push(skillPath);
4577
- }
4578
- }
4579
- if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4580
- let existingServers = {};
4581
- try {
4582
- if (fs12.existsSync(".mcp.json")) {
4583
- const existing = JSON.parse(fs12.readFileSync(".mcp.json", "utf-8"));
4584
- if (existing.mcpServers) existingServers = existing.mcpServers;
4585
- }
4586
- } catch {
4587
- }
4588
- const mergedServers = { ...existingServers, ...config.mcpServers };
4589
- fs12.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
4590
- written.push(".mcp.json");
4591
- }
4592
- return written;
4593
- }
4594
-
4595
- // src/writers/cursor/index.ts
4596
- import fs13 from "fs";
4597
- import path12 from "path";
4598
- function writeCursorConfig(config) {
4599
- const written = [];
4600
- if (config.cursorrules) {
4601
- fs13.writeFileSync(".cursorrules", config.cursorrules);
4602
- written.push(".cursorrules");
4603
- }
4604
- const preCommitRule = getCursorPreCommitRule();
4605
- const learningsRule = getCursorLearningsRule();
4606
- const syncRule = getCursorSyncRule();
4607
- const allRules = [...config.rules || [], preCommitRule, learningsRule, syncRule];
4608
- const rulesDir = path12.join(".cursor", "rules");
4609
- if (!fs13.existsSync(rulesDir)) fs13.mkdirSync(rulesDir, { recursive: true });
4610
- for (const rule of allRules) {
4611
- const rulePath = path12.join(rulesDir, rule.filename);
4612
- fs13.writeFileSync(rulePath, rule.content);
4613
- written.push(rulePath);
4614
- }
4615
- if (config.skills?.length) {
4616
- for (const skill of config.skills) {
4617
- const skillDir = path12.join(".cursor", "skills", skill.name);
4618
- if (!fs13.existsSync(skillDir)) fs13.mkdirSync(skillDir, { recursive: true });
4619
- const skillPath = path12.join(skillDir, "SKILL.md");
4620
- const frontmatter = [
4621
- "---",
4622
- `name: ${skill.name}`,
4623
- `description: ${skill.description}`,
4624
- "---",
4625
- ""
4626
- ].join("\n");
4627
- fs13.writeFileSync(skillPath, frontmatter + skill.content);
4628
- written.push(skillPath);
4629
- }
4630
- }
4631
- if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4632
- const cursorDir = ".cursor";
4633
- if (!fs13.existsSync(cursorDir)) fs13.mkdirSync(cursorDir, { recursive: true });
4634
- const mcpPath = path12.join(cursorDir, "mcp.json");
4635
- let existingServers = {};
4636
- try {
4637
- if (fs13.existsSync(mcpPath)) {
4638
- const existing = JSON.parse(fs13.readFileSync(mcpPath, "utf-8"));
4639
- if (existing.mcpServers) existingServers = existing.mcpServers;
4640
- }
4641
- } catch {
4642
- }
4643
- const mergedServers = { ...existingServers, ...config.mcpServers };
4644
- fs13.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
4645
- written.push(mcpPath);
4646
- }
4647
- return written;
4648
- }
4649
-
4650
- // src/writers/codex/index.ts
4651
- import fs14 from "fs";
4652
- import path13 from "path";
4653
- function writeCodexConfig(config) {
4654
- const written = [];
4655
- fs14.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(config.agentsMd)));
4656
- written.push("AGENTS.md");
4657
- if (config.skills?.length) {
4658
- for (const skill of config.skills) {
4659
- const skillDir = path13.join(".agents", "skills", skill.name);
4660
- if (!fs14.existsSync(skillDir)) fs14.mkdirSync(skillDir, { recursive: true });
4661
- const skillPath = path13.join(skillDir, "SKILL.md");
4662
- const frontmatter = [
4663
- "---",
4664
- `name: ${skill.name}`,
4665
- `description: ${skill.description}`,
4666
- "---",
4667
- ""
4668
- ].join("\n");
4669
- fs14.writeFileSync(skillPath, frontmatter + skill.content);
4670
- written.push(skillPath);
4671
- }
4672
- }
4673
- return written;
4674
- }
4675
-
4676
- // src/writers/github-copilot/index.ts
4677
- import fs15 from "fs";
4678
- import path14 from "path";
4679
- function writeGithubCopilotConfig(config) {
4680
- const written = [];
4681
- if (config.instructions) {
4682
- fs15.mkdirSync(".github", { recursive: true });
4683
- fs15.writeFileSync(path14.join(".github", "copilot-instructions.md"), appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.instructions))));
4684
- written.push(".github/copilot-instructions.md");
4685
- }
4686
- if (config.instructionFiles?.length) {
4687
- const instructionsDir = path14.join(".github", "instructions");
4688
- fs15.mkdirSync(instructionsDir, { recursive: true });
4689
- for (const file of config.instructionFiles) {
4690
- fs15.writeFileSync(path14.join(instructionsDir, file.filename), file.content);
4691
- written.push(`.github/instructions/${file.filename}`);
4692
- }
4693
- }
4694
- return written;
4695
- }
4696
-
4697
- // src/writers/backup.ts
4698
- import fs16 from "fs";
4699
- import path15 from "path";
4700
- function createBackup(files) {
4701
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4702
- const backupDir = path15.join(BACKUPS_DIR, timestamp);
4703
- for (const file of files) {
4704
- if (!fs16.existsSync(file)) continue;
4705
- const dest = path15.join(backupDir, file);
4706
- const destDir = path15.dirname(dest);
4707
- if (!fs16.existsSync(destDir)) {
4708
- fs16.mkdirSync(destDir, { recursive: true });
4709
- }
4710
- fs16.copyFileSync(file, dest);
4711
- }
4712
- return backupDir;
4713
- }
4714
- function restoreBackup(backupDir, file) {
4715
- const backupFile = path15.join(backupDir, file);
4716
- if (!fs16.existsSync(backupFile)) return false;
4717
- const destDir = path15.dirname(file);
4718
- if (!fs16.existsSync(destDir)) {
4719
- fs16.mkdirSync(destDir, { recursive: true });
4720
- }
4721
- fs16.copyFileSync(backupFile, file);
4722
- return true;
4723
- }
4724
-
4725
- // src/lib/builtin-skills.ts
4726
- init_resolve_caliber();
4727
- import fs17 from "fs";
4728
- import path16 from "path";
4729
- function buildSkillContent(skill) {
4730
- const frontmatter = `---
4731
- name: ${skill.name}
4732
- description: ${skill.description}
4733
- ---
4734
-
4735
- `;
4736
- return frontmatter + skill.content;
4737
- }
4738
- function getFindSkillsContent() {
4739
- const bin = resolveCaliber();
4740
- return `# Find Skills
4741
-
4742
- Search the public skill registry for community-contributed skills
4743
- relevant to the user's current task and install them into this project.
4744
-
4745
- ## Instructions
4746
-
4747
- 1. Identify the key technologies, frameworks, or task types from the
4748
- user's request that might have community skills available
4749
- 2. Ask the user: "Would you like me to search for community skills
4750
- for [identified technologies]?"
4751
- 3. If the user agrees, run:
4752
- \`\`\`bash
4753
- ${bin} skills --query "<relevant terms>"
4754
- \`\`\`
4755
- This outputs the top 5 matching skills with scores and descriptions.
4756
- 4. Present the results to the user and ask which ones to install
4757
- 5. Install the selected skills:
4758
- \`\`\`bash
4759
- ${bin} skills --install <slug1>,<slug2>
4760
- \`\`\`
4761
- 6. Read the installed SKILL.md files to load them into your current
4762
- context so you can use them immediately in this session
4763
- 7. Summarize what was installed and continue with the user's task
4764
-
4765
- ## Examples
4766
-
4767
- User: "let's build a web app using React"
4768
- -> "I notice you want to work with React. Would you like me to search
4769
- for community skills that could help with React development?"
4770
- -> If yes: run \`${bin} skills --query "react frontend"\`
4771
- -> Show the user the results, ask which to install
4772
- -> Run \`${bin} skills --install <selected-slugs>\`
4773
- -> Read the installed files and continue
4774
-
4775
- User: "help me set up Docker for this project"
4776
- -> "Would you like me to search for Docker-related skills?"
4777
- -> If yes: run \`${bin} skills --query "docker deployment"\`
4778
-
4779
- User: "I need to write tests for this Python ML pipeline"
4780
- -> "Would you like me to find skills for Python ML testing?"
4781
- -> If yes: run \`${bin} skills --query "python machine-learning testing"\`
4782
-
4783
- ## When NOT to trigger
4784
-
4785
- - The user is working within an already well-configured area
4786
- - You already suggested skills for this technology in this session
4787
- - The user is in the middle of urgent debugging or time-sensitive work
4788
- - The technology is too generic (e.g. just "code" or "programming")
4789
- `;
4790
- }
4791
- function getSaveLearningContent() {
4792
- const bin = resolveCaliber();
4793
- return `# Save Learning
4794
-
4795
- Save a user's instruction or preference as a persistent learning that
4796
- will be applied in all future sessions on this project.
4797
-
4798
- ## Instructions
4799
-
4800
- 1. Detect when the user gives an instruction to remember, such as:
4801
- - "remember this", "save this", "always do X", "never do Y"
4802
- - "from now on", "going forward", "in this project we..."
4803
- - Any stated convention, preference, or rule
4804
- 2. Refine the instruction into a clean, actionable learning bullet with
4805
- an appropriate type prefix:
4806
- - \`**[convention]**\` \u2014 coding style, workflow, git conventions
4807
- - \`**[pattern]**\` \u2014 reusable code patterns
4808
- - \`**[anti-pattern]**\` \u2014 things to avoid
4809
- - \`**[preference]**\` \u2014 personal/team preferences
4810
- - \`**[context]**\` \u2014 project-specific context
4811
- 3. Show the refined learning to the user and ask for confirmation
4812
- 4. If confirmed, run:
4813
- \`\`\`bash
4814
- ${bin} learn add "<refined learning>"
4815
- \`\`\`
4816
- For personal preferences (not project-level), add \`--personal\`:
4817
- \`\`\`bash
4818
- ${bin} learn add --personal "<refined learning>"
4819
- \`\`\`
4820
- 5. Stage the learnings file for the next commit:
4821
- \`\`\`bash
4822
- git add CALIBER_LEARNINGS.md
4823
- \`\`\`
4824
-
4825
- ## Examples
4826
-
4827
- User: "when developing features, push to next branch not master, remember it"
4828
- -> Refine: \`**[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`\`
4829
- -> "I'll save this as a project learning:
4830
- **[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`
4831
- Save for future sessions?"
4832
- -> If yes: run \`${bin} learn add "**[convention]** Push feature commits to the next branch, not master"\`
4833
- -> Run \`git add CALIBER_LEARNINGS.md\`
4834
-
4835
- User: "always use bun instead of npm"
4836
- -> Refine: \`**[preference]** Use \\\`bun\\\` instead of \\\`npm\\\` for package management\`
4837
- -> Confirm and save
4838
-
4839
- User: "never use any in TypeScript, use unknown instead"
4840
- -> Refine: \`**[convention]** Use \\\`unknown\\\` instead of \\\`any\\\` in TypeScript\`
4841
- -> Confirm and save
4842
-
4843
- ## When NOT to trigger
4844
-
4845
- - The user is giving a one-time instruction for the current task only
4846
- - The instruction is too vague to be actionable
4847
- - The user explicitly says "just for now" or "only this time"
4848
- `;
4849
- }
4850
- var FIND_SKILLS_SKILL = {
4851
- name: "find-skills",
4852
- description: "Discovers and installs community skills from the public registry. Use when the user mentions a technology, framework, or task that could benefit from specialized skills not yet installed, asks 'how do I do X', 'find a skill for X', or starts work in a new technology area. Proactively suggest when the user's task involves tools or frameworks without existing skills.",
4853
- get content() {
4854
- return getFindSkillsContent();
4855
- }
4856
- };
4857
- var SAVE_LEARNING_SKILL = {
4858
- name: "save-learning",
4859
- description: "Saves user instructions as persistent learnings for future sessions. Use when the user says 'remember this', 'always do X', 'from now on', 'never do Y', or gives any instruction they want persisted across sessions. Proactively suggest when the user states a preference, convention, or rule they clearly want followed in the future.",
4860
- get content() {
4861
- return getSaveLearningContent();
4862
- }
4863
- };
4864
- function getSetupCaliberContent() {
4865
- const bin = resolveCaliber();
4866
- return `# Setup Caliber
4867
-
4868
- Set up Caliber for automatic AI agent context sync on this project.
4869
- Caliber keeps your CLAUDE.md, Cursor rules, Copilot instructions, and Codex configs
4870
- in sync with your codebase \u2014 automatically on every commit.
4871
-
4872
- ## Instructions
4873
-
4874
- 1. Check if Caliber is already set up locally:
4875
- \`\`\`bash
4876
- grep -q "caliber" .git/hooks/pre-commit 2>/dev/null && echo "hook-active" || echo "no-hook"
4877
- \`\`\`
4878
-
4879
- 2. If **hook-active**, tell the user: "Caliber is already set up on this repo.
4880
- Your agent configs update automatically on every commit." Then stop.
4881
-
4882
- 3. If **no-hook**, ask the user: "Are you setting up Caliber for yourself (solo)
4883
- or for your team?"
4884
-
4885
- ### Solo Setup
4886
-
4887
- a. Tell the user: "I'll set up Caliber to sync your agent configs automatically
4888
- on every commit."
4889
- b. Install the pre-commit hook:
4890
- \`\`\`bash
4891
- ${bin} hooks --install
4892
- \`\`\`
4893
- c. Run a refresh to make sure configs are current:
4894
- \`\`\`bash
4895
- ${bin} refresh
4896
- \`\`\`
4897
- d. Tell the user what happened and that configs will auto-sync on every commit.
4898
-
4899
- ### Team Setup
4900
-
4901
- a. Tell the user: "I'll set up Caliber for your team \u2014 local hooks for you,
4902
- plus a GitHub Action for automatic sync across the team."
4903
- b. Install the local pre-commit hook:
4904
- \`\`\`bash
4905
- ${bin} hooks --install
4906
- \`\`\`
4907
- c. Run a refresh:
4908
- \`\`\`bash
4909
- ${bin} refresh
4910
- \`\`\`
4911
- d. Create the GitHub Action workflow for nightly sync. Write this file to
4912
- \`.github/workflows/caliber-sync.yml\`:
4913
- \`\`\`yaml
4914
- name: Caliber Sync
4915
- on:
4916
- schedule:
4917
- - cron: '0 3 * * 1-5'
4918
- pull_request:
4919
- types: [opened, synchronize]
4920
- workflow_dispatch:
4921
- jobs:
4922
- sync:
4923
- runs-on: ubuntu-latest
4924
- steps:
4925
- - uses: actions/checkout@v4
4926
- - uses: caliber-ai-org/ai-setup@v1
4927
- with:
4928
- mode: sync
4929
- auto-refresh: true
4930
- comment: true
4931
- github-token: \${{ secrets.GITHUB_TOKEN }}
4932
- env:
4933
- ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
4934
- \`\`\`
4935
- e. Tell the user: "Created the GitHub Action workflow. Add your ANTHROPIC_API_KEY
4936
- to your repo secrets (Settings \u2192 Secrets \u2192 Actions), then commit and push this
4937
- workflow file. From now on, every PR gets a Caliber sync check and configs
4938
- refresh nightly."
4939
- f. Offer to commit the workflow file and the updated configs.
4940
-
4941
- ### If \`${bin}\` is not found
4942
-
4943
- Install it first:
4944
- \`\`\`bash
4945
- npm install -g @rely-ai/caliber
4946
- \`\`\`
4947
- Or use npx (no install needed):
4948
- \`\`\`bash
4949
- npx @rely-ai/caliber hooks --install
4950
- \`\`\`
4951
-
4952
- ## When to trigger
4953
-
4954
- - When a developer first opens this project and Caliber hooks are not installed
4955
- - When the user asks about keeping agent configs up to date
4956
- - When the user asks "how do I set up Caliber" or "what is Caliber"
4773
+ }
4774
+ function getCursorPreCommitRule() {
4775
+ return { filename: CURSOR_RULE_FILENAME, content: getCursorRuleContent() };
4776
+ }
4777
+ var LEARNINGS_BLOCK_START = "<!-- caliber:managed:learnings -->";
4778
+ var LEARNINGS_BLOCK_END = "<!-- /caliber:managed:learnings -->";
4779
+ var LEARNINGS_BLOCK = `${LEARNINGS_BLOCK_START}
4780
+ ## Session Learnings
4957
4781
 
4958
- ## When NOT to trigger
4782
+ Read \`CALIBER_LEARNINGS.md\` for patterns and anti-patterns learned from previous sessions.
4783
+ These are auto-extracted from real tool usage \u2014 treat them as project-specific rules.
4784
+ ${LEARNINGS_BLOCK_END}`;
4785
+ var CURSOR_LEARNINGS_FILENAME = "caliber-learnings.mdc";
4786
+ var CURSOR_LEARNINGS_CONTENT = `---
4787
+ description: Reference session-learned patterns from CALIBER_LEARNINGS.md
4788
+ alwaysApply: true
4789
+ ---
4790
+ Read \`CALIBER_LEARNINGS.md\` for patterns and anti-patterns learned from previous sessions.
4791
+ These are auto-extracted from real tool usage \u2014 treat them as project-specific rules.
4792
+ `;
4793
+ function hasLearningsBlock(content) {
4794
+ return content.includes(LEARNINGS_BLOCK_START);
4795
+ }
4796
+ function appendLearningsBlock(content) {
4797
+ if (hasLearningsBlock(content)) return content;
4798
+ const trimmed = content.trimEnd();
4799
+ return trimmed + "\n\n" + LEARNINGS_BLOCK + "\n";
4800
+ }
4801
+ function getCursorLearningsRule() {
4802
+ return { filename: CURSOR_LEARNINGS_FILENAME, content: CURSOR_LEARNINGS_CONTENT };
4803
+ }
4804
+ var SYNC_BLOCK_START = "<!-- caliber:managed:sync -->";
4805
+ var SYNC_BLOCK_END = "<!-- /caliber:managed:sync -->";
4806
+ function getSyncBlock() {
4807
+ const bin = resolveCaliber();
4808
+ return `${SYNC_BLOCK_START}
4809
+ ## Context Sync
4959
4810
 
4960
- - Hooks are already installed and working
4961
- - The user is in the middle of time-sensitive work
4811
+ This project uses [Caliber](https://github.com/rely-ai/caliber) to keep AI agent configs in sync across Claude Code, Cursor, Copilot, and Codex.
4812
+ Configs update automatically before each commit via \`${bin} refresh\`.
4813
+ If the pre-commit hook is not set up, run \`${bin} hooks --install\` to enable automatic sync.
4814
+ ${SYNC_BLOCK_END}`;
4815
+ }
4816
+ function hasSyncBlock(content) {
4817
+ return content.includes(SYNC_BLOCK_START);
4818
+ }
4819
+ function appendSyncBlock(content) {
4820
+ if (hasSyncBlock(content)) return content;
4821
+ const trimmed = content.trimEnd();
4822
+ return trimmed + "\n\n" + getSyncBlock() + "\n";
4823
+ }
4824
+ var CURSOR_SYNC_FILENAME = "caliber-sync.mdc";
4825
+ function getCursorSyncContent() {
4826
+ const bin = resolveCaliber();
4827
+ return `---
4828
+ description: This project uses Caliber for automatic AI agent context sync
4829
+ alwaysApply: true
4830
+ ---
4831
+ This project uses Caliber to keep AI agent configs (CLAUDE.md, Cursor rules, Copilot instructions)
4832
+ in sync with the codebase automatically. Before each commit, run \`${bin} refresh\` to sync configs.
4833
+ If \`${bin}\` is not found, tell the user: "This project uses Caliber for agent config sync. Install with: npm install -g @rely-ai/caliber"
4962
4834
  `;
4963
4835
  }
4964
- var SETUP_CALIBER_SKILL = {
4965
- name: "setup-caliber",
4966
- description: "Sets up Caliber for automatic AI agent context sync. Installs pre-commit hooks so CLAUDE.md, Cursor rules, and Copilot instructions update automatically on every commit. Use when Caliber hooks are not yet installed or when the user asks about keeping agent configs in sync.",
4967
- get content() {
4968
- return getSetupCaliberContent();
4836
+ function getCursorSyncRule() {
4837
+ return { filename: CURSOR_SYNC_FILENAME, content: getCursorSyncContent() };
4838
+ }
4839
+
4840
+ // src/writers/claude/index.ts
4841
+ function writeClaudeConfig(config) {
4842
+ const written = [];
4843
+ fs12.writeFileSync("CLAUDE.md", appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.claudeMd))));
4844
+ written.push("CLAUDE.md");
4845
+ if (config.skills?.length) {
4846
+ for (const skill of config.skills) {
4847
+ const skillDir = path11.join(".claude", "skills", skill.name);
4848
+ if (!fs12.existsSync(skillDir)) fs12.mkdirSync(skillDir, { recursive: true });
4849
+ const skillPath = path11.join(skillDir, "SKILL.md");
4850
+ const frontmatter = [
4851
+ "---",
4852
+ `name: ${skill.name}`,
4853
+ `description: ${skill.description}`,
4854
+ "---",
4855
+ ""
4856
+ ].join("\n");
4857
+ fs12.writeFileSync(skillPath, frontmatter + skill.content);
4858
+ written.push(skillPath);
4859
+ }
4969
4860
  }
4970
- };
4971
- var BUILTIN_SKILLS = [FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL, SETUP_CALIBER_SKILL];
4972
- var PLATFORM_CONFIGS = [
4973
- { platformDir: ".claude", skillsDir: path16.join(".claude", "skills") },
4974
- { platformDir: ".cursor", skillsDir: path16.join(".cursor", "skills") },
4975
- { platformDir: ".agents", skillsDir: path16.join(".agents", "skills") }
4976
- ];
4977
- function ensureBuiltinSkills() {
4861
+ if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4862
+ let existingServers = {};
4863
+ try {
4864
+ if (fs12.existsSync(".mcp.json")) {
4865
+ const existing = JSON.parse(fs12.readFileSync(".mcp.json", "utf-8"));
4866
+ if (existing.mcpServers) existingServers = existing.mcpServers;
4867
+ }
4868
+ } catch {
4869
+ }
4870
+ const mergedServers = { ...existingServers, ...config.mcpServers };
4871
+ fs12.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
4872
+ written.push(".mcp.json");
4873
+ }
4874
+ return written;
4875
+ }
4876
+
4877
+ // src/writers/cursor/index.ts
4878
+ import fs13 from "fs";
4879
+ import path12 from "path";
4880
+ function writeCursorConfig(config) {
4978
4881
  const written = [];
4979
- for (const { platformDir, skillsDir } of PLATFORM_CONFIGS) {
4980
- if (!fs17.existsSync(platformDir)) continue;
4981
- for (const skill of BUILTIN_SKILLS) {
4982
- const skillPath = path16.join(skillsDir, skill.name, "SKILL.md");
4983
- if (fs17.existsSync(skillPath)) continue;
4984
- fs17.mkdirSync(path16.dirname(skillPath), { recursive: true });
4985
- fs17.writeFileSync(skillPath, buildSkillContent(skill));
4882
+ if (config.cursorrules) {
4883
+ fs13.writeFileSync(".cursorrules", config.cursorrules);
4884
+ written.push(".cursorrules");
4885
+ }
4886
+ const preCommitRule = getCursorPreCommitRule();
4887
+ const learningsRule = getCursorLearningsRule();
4888
+ const syncRule = getCursorSyncRule();
4889
+ const allRules = [...config.rules || [], preCommitRule, learningsRule, syncRule];
4890
+ const rulesDir = path12.join(".cursor", "rules");
4891
+ if (!fs13.existsSync(rulesDir)) fs13.mkdirSync(rulesDir, { recursive: true });
4892
+ for (const rule of allRules) {
4893
+ const rulePath = path12.join(rulesDir, rule.filename);
4894
+ fs13.writeFileSync(rulePath, rule.content);
4895
+ written.push(rulePath);
4896
+ }
4897
+ if (config.skills?.length) {
4898
+ for (const skill of config.skills) {
4899
+ const skillDir = path12.join(".cursor", "skills", skill.name);
4900
+ if (!fs13.existsSync(skillDir)) fs13.mkdirSync(skillDir, { recursive: true });
4901
+ const skillPath = path12.join(skillDir, "SKILL.md");
4902
+ const frontmatter = [
4903
+ "---",
4904
+ `name: ${skill.name}`,
4905
+ `description: ${skill.description}`,
4906
+ "---",
4907
+ ""
4908
+ ].join("\n");
4909
+ fs13.writeFileSync(skillPath, frontmatter + skill.content);
4910
+ written.push(skillPath);
4911
+ }
4912
+ }
4913
+ if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4914
+ const cursorDir = ".cursor";
4915
+ if (!fs13.existsSync(cursorDir)) fs13.mkdirSync(cursorDir, { recursive: true });
4916
+ const mcpPath = path12.join(cursorDir, "mcp.json");
4917
+ let existingServers = {};
4918
+ try {
4919
+ if (fs13.existsSync(mcpPath)) {
4920
+ const existing = JSON.parse(fs13.readFileSync(mcpPath, "utf-8"));
4921
+ if (existing.mcpServers) existingServers = existing.mcpServers;
4922
+ }
4923
+ } catch {
4924
+ }
4925
+ const mergedServers = { ...existingServers, ...config.mcpServers };
4926
+ fs13.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
4927
+ written.push(mcpPath);
4928
+ }
4929
+ return written;
4930
+ }
4931
+
4932
+ // src/writers/codex/index.ts
4933
+ import fs14 from "fs";
4934
+ import path13 from "path";
4935
+ function writeCodexConfig(config) {
4936
+ const written = [];
4937
+ fs14.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(config.agentsMd)));
4938
+ written.push("AGENTS.md");
4939
+ if (config.skills?.length) {
4940
+ for (const skill of config.skills) {
4941
+ const skillDir = path13.join(".agents", "skills", skill.name);
4942
+ if (!fs14.existsSync(skillDir)) fs14.mkdirSync(skillDir, { recursive: true });
4943
+ const skillPath = path13.join(skillDir, "SKILL.md");
4944
+ const frontmatter = [
4945
+ "---",
4946
+ `name: ${skill.name}`,
4947
+ `description: ${skill.description}`,
4948
+ "---",
4949
+ ""
4950
+ ].join("\n");
4951
+ fs14.writeFileSync(skillPath, frontmatter + skill.content);
4986
4952
  written.push(skillPath);
4987
4953
  }
4988
4954
  }
4989
4955
  return written;
4990
4956
  }
4991
4957
 
4958
+ // src/writers/github-copilot/index.ts
4959
+ import fs15 from "fs";
4960
+ import path14 from "path";
4961
+ function writeGithubCopilotConfig(config) {
4962
+ const written = [];
4963
+ if (config.instructions) {
4964
+ fs15.mkdirSync(".github", { recursive: true });
4965
+ fs15.writeFileSync(path14.join(".github", "copilot-instructions.md"), appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.instructions))));
4966
+ written.push(".github/copilot-instructions.md");
4967
+ }
4968
+ if (config.instructionFiles?.length) {
4969
+ const instructionsDir = path14.join(".github", "instructions");
4970
+ fs15.mkdirSync(instructionsDir, { recursive: true });
4971
+ for (const file of config.instructionFiles) {
4972
+ fs15.writeFileSync(path14.join(instructionsDir, file.filename), file.content);
4973
+ written.push(`.github/instructions/${file.filename}`);
4974
+ }
4975
+ }
4976
+ return written;
4977
+ }
4978
+
4979
+ // src/writers/backup.ts
4980
+ import fs16 from "fs";
4981
+ import path15 from "path";
4982
+ function createBackup(files) {
4983
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4984
+ const backupDir = path15.join(BACKUPS_DIR, timestamp);
4985
+ for (const file of files) {
4986
+ if (!fs16.existsSync(file)) continue;
4987
+ const dest = path15.join(backupDir, file);
4988
+ const destDir = path15.dirname(dest);
4989
+ if (!fs16.existsSync(destDir)) {
4990
+ fs16.mkdirSync(destDir, { recursive: true });
4991
+ }
4992
+ fs16.copyFileSync(file, dest);
4993
+ }
4994
+ return backupDir;
4995
+ }
4996
+ function restoreBackup(backupDir, file) {
4997
+ const backupFile = path15.join(backupDir, file);
4998
+ if (!fs16.existsSync(backupFile)) return false;
4999
+ const destDir = path15.dirname(file);
5000
+ if (!fs16.existsSync(destDir)) {
5001
+ fs16.mkdirSync(destDir, { recursive: true });
5002
+ }
5003
+ fs16.copyFileSync(backupFile, file);
5004
+ return true;
5005
+ }
5006
+
5007
+ // src/writers/index.ts
5008
+ init_builtin_skills();
5009
+
4992
5010
  // src/writers/manifest.ts
4993
5011
  import fs18 from "fs";
4994
5012
  import crypto3 from "crypto";
@@ -5173,6 +5191,7 @@ function cleanupStaging() {
5173
5191
  }
5174
5192
 
5175
5193
  // src/commands/setup-files.ts
5194
+ init_builtin_skills();
5176
5195
  import fs21 from "fs";
5177
5196
  function collectSetupFiles(setup, targetAgent) {
5178
5197
  const files = [];
@@ -9115,9 +9134,9 @@ async function initCommand(options) {
9115
9134
  console.log(chalk14.dim(" Works across Claude Code, Cursor, Codex, and GitHub Copilot.\n"));
9116
9135
  console.log(title.bold(" How it works:\n"));
9117
9136
  console.log(chalk14.dim(" 1. Connect Link your LLM provider and select your agents"));
9118
- console.log(chalk14.dim(" 2. Engine Detect stack, generate configs & skills in parallel"));
9119
- console.log(chalk14.dim(" 3. Review See all changes \u2014 accept, refine, or decline"));
9120
- console.log(chalk14.dim(" 4. Finalize Install sync hooks and score your setup\n"));
9137
+ console.log(chalk14.dim(" 2. Setup Detect stack, install sync hooks & skills"));
9138
+ console.log(chalk14.dim(" 3. Generate Audit existing config or generate from scratch"));
9139
+ console.log(chalk14.dim(" 4. Finalize Review changes and score your setup\n"));
9121
9140
  } else {
9122
9141
  console.log(brand.bold("\n CALIBER") + chalk14.dim(" \u2014 regenerating config\n"));
9123
9142
  }
@@ -9167,8 +9186,26 @@ async function initCommand(options) {
9167
9186
  console.log(chalk14.dim(` Target: ${targetAgent.join(", ")}
9168
9187
  `));
9169
9188
  trackInitAgentSelected(targetAgent, agentAutoDetected);
9189
+ console.log(title.bold(" Step 2/4 \u2014 Setup\n"));
9190
+ const hookResult = installPreCommitHook();
9191
+ if (hookResult.installed) {
9192
+ console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 configs sync on every commit`);
9193
+ } else if (hookResult.alreadyInstalled) {
9194
+ console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 already installed`);
9195
+ }
9196
+ const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
9197
+ for (const agent of targetAgent) {
9198
+ if (agent === "claude" && !fs33.existsSync(".claude")) fs33.mkdirSync(".claude", { recursive: true });
9199
+ if (agent === "cursor" && !fs33.existsSync(".cursor")) fs33.mkdirSync(".cursor", { recursive: true });
9200
+ if (agent === "codex" && !fs33.existsSync(".agents")) fs33.mkdirSync(".agents", { recursive: true });
9201
+ }
9202
+ const skillsWritten = ensureBuiltinSkills2();
9203
+ if (skillsWritten.length > 0) {
9204
+ console.log(` ${chalk14.green("\u2713")} Agent skills \u2014 ${skillsWritten.length} skills installed (setup-caliber, find-skills, save-learning)`);
9205
+ }
9206
+ console.log("");
9170
9207
  let baselineScore = computeLocalScore(process.cwd(), targetAgent);
9171
- console.log(chalk14.dim("\n Current config score:"));
9208
+ console.log(chalk14.dim(" Current config score:"));
9172
9209
  displayScoreSummary(baselineScore);
9173
9210
  if (options.verbose) {
9174
9211
  for (const c of baselineScore.checks) {
@@ -9195,29 +9232,37 @@ async function initCommand(options) {
9195
9232
  ]);
9196
9233
  const passingCount = baselineScore.checks.filter((c) => c.passed).length;
9197
9234
  const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
9235
+ let skipGeneration = false;
9198
9236
  if (hasExistingConfig && baselineScore.score === 100) {
9199
9237
  trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
9200
- console.log(chalk14.bold.green(" Your config is already optimal \u2014 nothing to change.\n"));
9201
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n"));
9202
- if (!options.force) return;
9238
+ console.log(chalk14.bold.green("\n Your config is already optimal.\n"));
9239
+ skipGeneration = !options.force;
9240
+ } else if (hasExistingConfig && !options.force && !options.autoApprove) {
9241
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9242
+ const auditAnswer = await promptInput(" Want Caliber to audit and improve your existing config? (Y/n) ");
9243
+ skipGeneration = auditAnswer.toLowerCase() === "n";
9244
+ } else if (!hasExistingConfig && !options.force && !options.autoApprove) {
9245
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9246
+ const generateAnswer = await promptInput(" Want Caliber to generate agent configs for your project? (Y/n) ");
9247
+ skipGeneration = generateAnswer.toLowerCase() === "n";
9248
+ } else {
9249
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9250
+ }
9251
+ if (skipGeneration) {
9252
+ const sha2 = getCurrentHeadSha();
9253
+ writeState({
9254
+ lastRefreshSha: sha2 ?? "",
9255
+ lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
9256
+ targetAgent
9257
+ });
9258
+ console.log(chalk14.bold.green("\n Caliber sync is set up!\n"));
9259
+ console.log(chalk14.dim(" Your agent configs will sync automatically on every commit."));
9260
+ console.log(chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n"));
9261
+ return;
9203
9262
  }
9204
9263
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
9205
9264
  const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
9206
- trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9207
- if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
9208
- console.log(chalk14.bold.green("\n Your config is fully optimized for LLM generation.\n"));
9209
- console.log(chalk14.dim(" Remaining items need CLI actions:\n"));
9210
- for (const check of allFailingChecks) {
9211
- console.log(chalk14.dim(` \u2022 ${check.name}`));
9212
- if (check.suggestion) {
9213
- console.log(` ${chalk14.hex("#83D1EB")(check.suggestion)}`);
9214
- }
9215
- }
9216
- console.log("");
9217
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n"));
9218
- return;
9219
- }
9220
- console.log(title.bold(" Step 2/4 \u2014 Engine\n"));
9265
+ console.log(title.bold("\n Step 3/4 \u2014 Generate\n"));
9221
9266
  const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
9222
9267
  console.log(chalk14.dim(genModelInfo + "\n"));
9223
9268
  if (report) report.markStep("Generation");
@@ -9416,7 +9461,7 @@ async function initCommand(options) {
9416
9461
  report.addJson("Generation: Parsed Config", generatedSetup);
9417
9462
  }
9418
9463
  log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
9419
- console.log(title.bold(" Step 3/4 \u2014 Review\n"));
9464
+ console.log(title.bold(" Step 4/4 \u2014 Finalize\n"));
9420
9465
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
9421
9466
  const staged = stageFiles(setupFiles, process.cwd());
9422
9467
  const totalChanges = staged.newFiles + staged.modifiedFiles;
@@ -9479,7 +9524,6 @@ async function initCommand(options) {
9479
9524
  console.log(chalk14.dim("Declined. No files were modified."));
9480
9525
  return;
9481
9526
  }
9482
- console.log(title.bold("\n Step 4/4 \u2014 Finalize\n"));
9483
9527
  if (options.dryRun) {
9484
9528
  console.log(chalk14.yellow("\n[Dry run] Would write the following files:"));
9485
9529
  console.log(JSON.stringify(generatedSetup, null, 2));
@@ -9531,12 +9575,6 @@ ${agentRefs.join(" ")}
9531
9575
  throw new Error("__exit__");
9532
9576
  }
9533
9577
  if (fingerprint) ensurePermissions(fingerprint);
9534
- const hookResult = installPreCommitHook();
9535
- if (hookResult.installed) {
9536
- console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed \u2014 configs sync on every commit`);
9537
- } else if (hookResult.alreadyInstalled) {
9538
- console.log(chalk14.dim(" Pre-commit hook already installed"));
9539
- }
9540
9578
  const sha = getCurrentHeadSha();
9541
9579
  writeState({
9542
9580
  lastRefreshSha: sha ?? "",
@@ -10371,6 +10409,7 @@ function migrateInlineLearnings() {
10371
10409
  // src/commands/refresh.ts
10372
10410
  init_config();
10373
10411
  init_resolve_caliber();
10412
+ init_builtin_skills();
10374
10413
  function detectSyncedAgents(writtenFiles) {
10375
10414
  const agents = [];
10376
10415
  const joined = writtenFiles.join(" ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.31.0-dev.1774710550",
3
+ "version": "1.31.0-dev.1774711564",
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": {