@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.
- package/dist/bin.js +558 -519
- 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
|
-
|
|
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
|
-
-
|
|
4961
|
-
|
|
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
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
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
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
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
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
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.
|
|
9119
|
-
console.log(chalk14.dim(" 3.
|
|
9120
|
-
console.log(chalk14.dim(" 4. Finalize
|
|
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("
|
|
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
|
|
9201
|
-
|
|
9202
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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": {
|