@rely-ai/caliber 1.25.1 → 1.26.0-dev.1773939160
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 +631 -354
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -230,7 +230,7 @@ __export(resolve_caliber_exports, {
|
|
|
230
230
|
isCaliberCommand: () => isCaliberCommand,
|
|
231
231
|
resolveCaliber: () => resolveCaliber
|
|
232
232
|
});
|
|
233
|
-
import
|
|
233
|
+
import fs19 from "fs";
|
|
234
234
|
import { execSync as execSync6 } from "child_process";
|
|
235
235
|
function resolveCaliber() {
|
|
236
236
|
if (_resolved) return _resolved;
|
|
@@ -252,7 +252,7 @@ function resolveCaliber() {
|
|
|
252
252
|
} catch {
|
|
253
253
|
}
|
|
254
254
|
const binPath = process.argv[1];
|
|
255
|
-
if (binPath &&
|
|
255
|
+
if (binPath && fs19.existsSync(binPath)) {
|
|
256
256
|
_resolved = binPath;
|
|
257
257
|
return _resolved;
|
|
258
258
|
}
|
|
@@ -276,13 +276,13 @@ var init_resolve_caliber = __esm({
|
|
|
276
276
|
|
|
277
277
|
// src/utils/editor.ts
|
|
278
278
|
import { execSync as execSync12, spawn as spawn3 } from "child_process";
|
|
279
|
-
import
|
|
280
|
-
import
|
|
279
|
+
import fs26 from "fs";
|
|
280
|
+
import path22 from "path";
|
|
281
281
|
import os5 from "os";
|
|
282
282
|
function getEmptyFilePath(proposedPath) {
|
|
283
|
-
|
|
284
|
-
const tempPath =
|
|
285
|
-
|
|
283
|
+
fs26.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
|
|
284
|
+
const tempPath = path22.join(DIFF_TEMP_DIR, path22.basename(proposedPath));
|
|
285
|
+
fs26.writeFileSync(tempPath, "");
|
|
286
286
|
return tempPath;
|
|
287
287
|
}
|
|
288
288
|
function commandExists(cmd) {
|
|
@@ -322,7 +322,7 @@ var init_editor = __esm({
|
|
|
322
322
|
"src/utils/editor.ts"() {
|
|
323
323
|
"use strict";
|
|
324
324
|
IS_WINDOWS3 = process.platform === "win32";
|
|
325
|
-
DIFF_TEMP_DIR =
|
|
325
|
+
DIFF_TEMP_DIR = path22.join(os5.tmpdir(), "caliber-diff");
|
|
326
326
|
}
|
|
327
327
|
});
|
|
328
328
|
|
|
@@ -334,7 +334,7 @@ __export(review_exports, {
|
|
|
334
334
|
promptWantsReview: () => promptWantsReview
|
|
335
335
|
});
|
|
336
336
|
import chalk10 from "chalk";
|
|
337
|
-
import
|
|
337
|
+
import fs27 from "fs";
|
|
338
338
|
import select4 from "@inquirer/select";
|
|
339
339
|
import { createTwoFilesPatch } from "diff";
|
|
340
340
|
async function promptWantsReview() {
|
|
@@ -371,8 +371,8 @@ async function openReview(method, stagedFiles) {
|
|
|
371
371
|
return;
|
|
372
372
|
}
|
|
373
373
|
const fileInfos = stagedFiles.map((file) => {
|
|
374
|
-
const proposed =
|
|
375
|
-
const current = file.currentPath ?
|
|
374
|
+
const proposed = fs27.readFileSync(file.proposedPath, "utf-8");
|
|
375
|
+
const current = file.currentPath ? fs27.readFileSync(file.currentPath, "utf-8") : "";
|
|
376
376
|
const patch = createTwoFilesPatch(
|
|
377
377
|
file.isNew ? "/dev/null" : file.relativePath,
|
|
378
378
|
file.relativePath,
|
|
@@ -547,13 +547,13 @@ __export(lock_exports, {
|
|
|
547
547
|
isCaliberRunning: () => isCaliberRunning,
|
|
548
548
|
releaseLock: () => releaseLock
|
|
549
549
|
});
|
|
550
|
-
import
|
|
551
|
-
import
|
|
550
|
+
import fs36 from "fs";
|
|
551
|
+
import path28 from "path";
|
|
552
552
|
import os7 from "os";
|
|
553
553
|
function isCaliberRunning() {
|
|
554
554
|
try {
|
|
555
|
-
if (!
|
|
556
|
-
const raw =
|
|
555
|
+
if (!fs36.existsSync(LOCK_FILE)) return false;
|
|
556
|
+
const raw = fs36.readFileSync(LOCK_FILE, "utf-8").trim();
|
|
557
557
|
const { pid, ts } = JSON.parse(raw);
|
|
558
558
|
if (Date.now() - ts > STALE_MS) return false;
|
|
559
559
|
try {
|
|
@@ -568,13 +568,13 @@ function isCaliberRunning() {
|
|
|
568
568
|
}
|
|
569
569
|
function acquireLock() {
|
|
570
570
|
try {
|
|
571
|
-
|
|
571
|
+
fs36.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
|
|
572
572
|
} catch {
|
|
573
573
|
}
|
|
574
574
|
}
|
|
575
575
|
function releaseLock() {
|
|
576
576
|
try {
|
|
577
|
-
if (
|
|
577
|
+
if (fs36.existsSync(LOCK_FILE)) fs36.unlinkSync(LOCK_FILE);
|
|
578
578
|
} catch {
|
|
579
579
|
}
|
|
580
580
|
}
|
|
@@ -582,21 +582,21 @@ var LOCK_FILE, STALE_MS;
|
|
|
582
582
|
var init_lock = __esm({
|
|
583
583
|
"src/lib/lock.ts"() {
|
|
584
584
|
"use strict";
|
|
585
|
-
LOCK_FILE =
|
|
585
|
+
LOCK_FILE = path28.join(os7.tmpdir(), ".caliber.lock");
|
|
586
586
|
STALE_MS = 10 * 60 * 1e3;
|
|
587
587
|
}
|
|
588
588
|
});
|
|
589
589
|
|
|
590
590
|
// src/cli.ts
|
|
591
591
|
import { Command } from "commander";
|
|
592
|
-
import
|
|
593
|
-
import
|
|
592
|
+
import fs46 from "fs";
|
|
593
|
+
import path37 from "path";
|
|
594
594
|
import { fileURLToPath } from "url";
|
|
595
595
|
|
|
596
596
|
// src/commands/init.ts
|
|
597
|
-
import
|
|
597
|
+
import path24 from "path";
|
|
598
598
|
import chalk14 from "chalk";
|
|
599
|
-
import
|
|
599
|
+
import fs31 from "fs";
|
|
600
600
|
|
|
601
601
|
// src/fingerprint/index.ts
|
|
602
602
|
import fs7 from "fs";
|
|
@@ -3424,15 +3424,15 @@ init_config();
|
|
|
3424
3424
|
// src/utils/dependencies.ts
|
|
3425
3425
|
import { readFileSync as readFileSync2 } from "fs";
|
|
3426
3426
|
import { join as join2 } from "path";
|
|
3427
|
-
function readFileOrNull2(
|
|
3427
|
+
function readFileOrNull2(path39) {
|
|
3428
3428
|
try {
|
|
3429
|
-
return readFileSync2(
|
|
3429
|
+
return readFileSync2(path39, "utf-8");
|
|
3430
3430
|
} catch {
|
|
3431
3431
|
return null;
|
|
3432
3432
|
}
|
|
3433
3433
|
}
|
|
3434
|
-
function readJsonOrNull(
|
|
3435
|
-
const content = readFileOrNull2(
|
|
3434
|
+
function readJsonOrNull(path39) {
|
|
3435
|
+
const content = readFileOrNull2(path39);
|
|
3436
3436
|
if (!content) return null;
|
|
3437
3437
|
try {
|
|
3438
3438
|
return JSON.parse(content);
|
|
@@ -4019,7 +4019,7 @@ ${f.content}
|
|
|
4019
4019
|
}
|
|
4020
4020
|
|
|
4021
4021
|
// src/writers/index.ts
|
|
4022
|
-
import
|
|
4022
|
+
import fs16 from "fs";
|
|
4023
4023
|
|
|
4024
4024
|
// src/writers/claude/index.ts
|
|
4025
4025
|
import fs9 from "fs";
|
|
@@ -4253,35 +4253,182 @@ function restoreBackup(backupDir, file) {
|
|
|
4253
4253
|
return true;
|
|
4254
4254
|
}
|
|
4255
4255
|
|
|
4256
|
+
// src/lib/builtin-skills.ts
|
|
4257
|
+
import fs14 from "fs";
|
|
4258
|
+
import path14 from "path";
|
|
4259
|
+
function buildSkillContent(skill) {
|
|
4260
|
+
const frontmatter = `---
|
|
4261
|
+
name: ${skill.name}
|
|
4262
|
+
description: ${skill.description}
|
|
4263
|
+
---
|
|
4264
|
+
|
|
4265
|
+
`;
|
|
4266
|
+
return frontmatter + skill.content;
|
|
4267
|
+
}
|
|
4268
|
+
var FIND_SKILLS_SKILL = {
|
|
4269
|
+
name: "find-skills",
|
|
4270
|
+
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.",
|
|
4271
|
+
content: `# Find Skills
|
|
4272
|
+
|
|
4273
|
+
Search the public skill registry for community-contributed skills
|
|
4274
|
+
relevant to the user's current task and install them into this project.
|
|
4275
|
+
|
|
4276
|
+
## Instructions
|
|
4277
|
+
|
|
4278
|
+
1. Identify the key technologies, frameworks, or task types from the
|
|
4279
|
+
user's request that might have community skills available
|
|
4280
|
+
2. Ask the user: "Would you like me to search for community skills
|
|
4281
|
+
for [identified technologies]?"
|
|
4282
|
+
3. If the user agrees, run:
|
|
4283
|
+
\`\`\`bash
|
|
4284
|
+
caliber skills --query "<relevant terms>"
|
|
4285
|
+
\`\`\`
|
|
4286
|
+
This outputs the top 5 matching skills with scores and descriptions.
|
|
4287
|
+
4. Present the results to the user and ask which ones to install
|
|
4288
|
+
5. Install the selected skills:
|
|
4289
|
+
\`\`\`bash
|
|
4290
|
+
caliber skills --install <slug1>,<slug2>
|
|
4291
|
+
\`\`\`
|
|
4292
|
+
6. Read the installed SKILL.md files to load them into your current
|
|
4293
|
+
context so you can use them immediately in this session
|
|
4294
|
+
7. Summarize what was installed and continue with the user's task
|
|
4295
|
+
|
|
4296
|
+
## Examples
|
|
4297
|
+
|
|
4298
|
+
User: "let's build a web app using React"
|
|
4299
|
+
-> "I notice you want to work with React. Would you like me to search
|
|
4300
|
+
for community skills that could help with React development?"
|
|
4301
|
+
-> If yes: run \`caliber skills --query "react frontend"\`
|
|
4302
|
+
-> Show the user the results, ask which to install
|
|
4303
|
+
-> Run \`caliber skills --install <selected-slugs>\`
|
|
4304
|
+
-> Read the installed files and continue
|
|
4305
|
+
|
|
4306
|
+
User: "help me set up Docker for this project"
|
|
4307
|
+
-> "Would you like me to search for Docker-related skills?"
|
|
4308
|
+
-> If yes: run \`caliber skills --query "docker deployment"\`
|
|
4309
|
+
|
|
4310
|
+
User: "I need to write tests for this Python ML pipeline"
|
|
4311
|
+
-> "Would you like me to find skills for Python ML testing?"
|
|
4312
|
+
-> If yes: run \`caliber skills --query "python machine-learning testing"\`
|
|
4313
|
+
|
|
4314
|
+
## When NOT to trigger
|
|
4315
|
+
|
|
4316
|
+
- The user is working within an already well-configured area
|
|
4317
|
+
- You already suggested skills for this technology in this session
|
|
4318
|
+
- The user is in the middle of urgent debugging or time-sensitive work
|
|
4319
|
+
- The technology is too generic (e.g. just "code" or "programming")
|
|
4320
|
+
`
|
|
4321
|
+
};
|
|
4322
|
+
var SAVE_LEARNING_SKILL = {
|
|
4323
|
+
name: "save-learning",
|
|
4324
|
+
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.",
|
|
4325
|
+
content: `# Save Learning
|
|
4326
|
+
|
|
4327
|
+
Save a user's instruction or preference as a persistent learning that
|
|
4328
|
+
will be applied in all future sessions on this project.
|
|
4329
|
+
|
|
4330
|
+
## Instructions
|
|
4331
|
+
|
|
4332
|
+
1. Detect when the user gives an instruction to remember, such as:
|
|
4333
|
+
- "remember this", "save this", "always do X", "never do Y"
|
|
4334
|
+
- "from now on", "going forward", "in this project we..."
|
|
4335
|
+
- Any stated convention, preference, or rule
|
|
4336
|
+
2. Refine the instruction into a clean, actionable learning bullet with
|
|
4337
|
+
an appropriate type prefix:
|
|
4338
|
+
- \`**[convention]**\` \u2014 coding style, workflow, git conventions
|
|
4339
|
+
- \`**[pattern]**\` \u2014 reusable code patterns
|
|
4340
|
+
- \`**[anti-pattern]**\` \u2014 things to avoid
|
|
4341
|
+
- \`**[preference]**\` \u2014 personal/team preferences
|
|
4342
|
+
- \`**[context]**\` \u2014 project-specific context
|
|
4343
|
+
3. Show the refined learning to the user and ask for confirmation
|
|
4344
|
+
4. If confirmed, run:
|
|
4345
|
+
\`\`\`bash
|
|
4346
|
+
caliber learn add "<refined learning>"
|
|
4347
|
+
\`\`\`
|
|
4348
|
+
For personal preferences (not project-level), add \`--personal\`:
|
|
4349
|
+
\`\`\`bash
|
|
4350
|
+
caliber learn add --personal "<refined learning>"
|
|
4351
|
+
\`\`\`
|
|
4352
|
+
5. Stage the learnings file for the next commit:
|
|
4353
|
+
\`\`\`bash
|
|
4354
|
+
git add CALIBER_LEARNINGS.md
|
|
4355
|
+
\`\`\`
|
|
4356
|
+
|
|
4357
|
+
## Examples
|
|
4358
|
+
|
|
4359
|
+
User: "when developing features, push to next branch not master, remember it"
|
|
4360
|
+
-> Refine: \`**[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`\`
|
|
4361
|
+
-> "I'll save this as a project learning:
|
|
4362
|
+
**[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`
|
|
4363
|
+
Save for future sessions?"
|
|
4364
|
+
-> If yes: run \`caliber learn add "**[convention]** Push feature commits to the next branch, not master"\`
|
|
4365
|
+
-> Run \`git add CALIBER_LEARNINGS.md\`
|
|
4366
|
+
|
|
4367
|
+
User: "always use bun instead of npm"
|
|
4368
|
+
-> Refine: \`**[preference]** Use \\\`bun\\\` instead of \\\`npm\\\` for package management\`
|
|
4369
|
+
-> Confirm and save
|
|
4370
|
+
|
|
4371
|
+
User: "never use any in TypeScript, use unknown instead"
|
|
4372
|
+
-> Refine: \`**[convention]** Use \\\`unknown\\\` instead of \\\`any\\\` in TypeScript\`
|
|
4373
|
+
-> Confirm and save
|
|
4374
|
+
|
|
4375
|
+
## When NOT to trigger
|
|
4376
|
+
|
|
4377
|
+
- The user is giving a one-time instruction for the current task only
|
|
4378
|
+
- The instruction is too vague to be actionable
|
|
4379
|
+
- The user explicitly says "just for now" or "only this time"
|
|
4380
|
+
`
|
|
4381
|
+
};
|
|
4382
|
+
var BUILTIN_SKILLS = [FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL];
|
|
4383
|
+
var PLATFORM_CONFIGS = [
|
|
4384
|
+
{ platformDir: ".claude", skillsDir: path14.join(".claude", "skills") },
|
|
4385
|
+
{ platformDir: ".cursor", skillsDir: path14.join(".cursor", "skills") },
|
|
4386
|
+
{ platformDir: ".agents", skillsDir: path14.join(".agents", "skills") }
|
|
4387
|
+
];
|
|
4388
|
+
function ensureBuiltinSkills() {
|
|
4389
|
+
const written = [];
|
|
4390
|
+
for (const { platformDir, skillsDir } of PLATFORM_CONFIGS) {
|
|
4391
|
+
if (!fs14.existsSync(platformDir)) continue;
|
|
4392
|
+
for (const skill of BUILTIN_SKILLS) {
|
|
4393
|
+
const skillPath = path14.join(skillsDir, skill.name, "SKILL.md");
|
|
4394
|
+
if (fs14.existsSync(skillPath)) continue;
|
|
4395
|
+
fs14.mkdirSync(path14.dirname(skillPath), { recursive: true });
|
|
4396
|
+
fs14.writeFileSync(skillPath, buildSkillContent(skill));
|
|
4397
|
+
written.push(skillPath);
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
return written;
|
|
4401
|
+
}
|
|
4402
|
+
|
|
4256
4403
|
// src/writers/manifest.ts
|
|
4257
4404
|
init_constants();
|
|
4258
|
-
import
|
|
4405
|
+
import fs15 from "fs";
|
|
4259
4406
|
import crypto2 from "crypto";
|
|
4260
4407
|
function readManifest() {
|
|
4261
4408
|
try {
|
|
4262
|
-
if (!
|
|
4263
|
-
return JSON.parse(
|
|
4409
|
+
if (!fs15.existsSync(MANIFEST_FILE)) return null;
|
|
4410
|
+
return JSON.parse(fs15.readFileSync(MANIFEST_FILE, "utf-8"));
|
|
4264
4411
|
} catch {
|
|
4265
4412
|
return null;
|
|
4266
4413
|
}
|
|
4267
4414
|
}
|
|
4268
4415
|
function writeManifest(manifest) {
|
|
4269
|
-
if (!
|
|
4270
|
-
|
|
4416
|
+
if (!fs15.existsSync(CALIBER_DIR)) {
|
|
4417
|
+
fs15.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
4271
4418
|
}
|
|
4272
|
-
|
|
4419
|
+
fs15.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
|
|
4273
4420
|
}
|
|
4274
4421
|
function fileChecksum(filePath) {
|
|
4275
|
-
const content =
|
|
4422
|
+
const content = fs15.readFileSync(filePath);
|
|
4276
4423
|
return crypto2.createHash("sha256").update(content).digest("hex");
|
|
4277
4424
|
}
|
|
4278
4425
|
|
|
4279
4426
|
// src/writers/index.ts
|
|
4280
4427
|
function writeSetup(setup) {
|
|
4281
4428
|
const filesToWrite = getFilesToWrite(setup);
|
|
4282
|
-
const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) =>
|
|
4429
|
+
const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs16.existsSync(f));
|
|
4283
4430
|
const existingFiles = [
|
|
4284
|
-
...filesToWrite.filter((f) =>
|
|
4431
|
+
...filesToWrite.filter((f) => fs16.existsSync(f)),
|
|
4285
4432
|
...filesToDelete
|
|
4286
4433
|
];
|
|
4287
4434
|
const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
|
|
@@ -4300,9 +4447,10 @@ function writeSetup(setup) {
|
|
|
4300
4447
|
}
|
|
4301
4448
|
const deleted = [];
|
|
4302
4449
|
for (const filePath of filesToDelete) {
|
|
4303
|
-
|
|
4450
|
+
fs16.unlinkSync(filePath);
|
|
4304
4451
|
deleted.push(filePath);
|
|
4305
4452
|
}
|
|
4453
|
+
written.push(...ensureBuiltinSkills());
|
|
4306
4454
|
ensureGitignore();
|
|
4307
4455
|
const entries = [
|
|
4308
4456
|
...written.map((file) => ({
|
|
@@ -4330,8 +4478,8 @@ function undoSetup() {
|
|
|
4330
4478
|
const removed = [];
|
|
4331
4479
|
for (const entry of manifest.entries) {
|
|
4332
4480
|
if (entry.action === "created") {
|
|
4333
|
-
if (
|
|
4334
|
-
|
|
4481
|
+
if (fs16.existsSync(entry.path)) {
|
|
4482
|
+
fs16.unlinkSync(entry.path);
|
|
4335
4483
|
removed.push(entry.path);
|
|
4336
4484
|
}
|
|
4337
4485
|
} else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
|
|
@@ -4341,8 +4489,8 @@ function undoSetup() {
|
|
|
4341
4489
|
}
|
|
4342
4490
|
}
|
|
4343
4491
|
const { MANIFEST_FILE: MANIFEST_FILE2 } = (init_constants(), __toCommonJS(constants_exports));
|
|
4344
|
-
if (
|
|
4345
|
-
|
|
4492
|
+
if (fs16.existsSync(MANIFEST_FILE2)) {
|
|
4493
|
+
fs16.unlinkSync(MANIFEST_FILE2);
|
|
4346
4494
|
}
|
|
4347
4495
|
return { restored, removed };
|
|
4348
4496
|
}
|
|
@@ -4383,23 +4531,23 @@ function getFilesToWrite(setup) {
|
|
|
4383
4531
|
}
|
|
4384
4532
|
function ensureGitignore() {
|
|
4385
4533
|
const gitignorePath = ".gitignore";
|
|
4386
|
-
if (
|
|
4387
|
-
const content =
|
|
4534
|
+
if (fs16.existsSync(gitignorePath)) {
|
|
4535
|
+
const content = fs16.readFileSync(gitignorePath, "utf-8");
|
|
4388
4536
|
if (!content.includes(".caliber/")) {
|
|
4389
|
-
|
|
4537
|
+
fs16.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
|
|
4390
4538
|
}
|
|
4391
4539
|
} else {
|
|
4392
|
-
|
|
4540
|
+
fs16.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
|
|
4393
4541
|
}
|
|
4394
4542
|
}
|
|
4395
4543
|
|
|
4396
4544
|
// src/writers/staging.ts
|
|
4397
4545
|
init_constants();
|
|
4398
|
-
import
|
|
4399
|
-
import
|
|
4400
|
-
var STAGED_DIR =
|
|
4401
|
-
var PROPOSED_DIR =
|
|
4402
|
-
var CURRENT_DIR =
|
|
4546
|
+
import fs17 from "fs";
|
|
4547
|
+
import path15 from "path";
|
|
4548
|
+
var STAGED_DIR = path15.join(CALIBER_DIR, "staged");
|
|
4549
|
+
var PROPOSED_DIR = path15.join(STAGED_DIR, "proposed");
|
|
4550
|
+
var CURRENT_DIR = path15.join(STAGED_DIR, "current");
|
|
4403
4551
|
function normalizeContent(content) {
|
|
4404
4552
|
return content.split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
4405
4553
|
}
|
|
@@ -4409,20 +4557,20 @@ function stageFiles(files, projectDir) {
|
|
|
4409
4557
|
let modifiedFiles = 0;
|
|
4410
4558
|
const stagedFiles = [];
|
|
4411
4559
|
for (const file of files) {
|
|
4412
|
-
const originalPath =
|
|
4413
|
-
if (
|
|
4414
|
-
const existing =
|
|
4560
|
+
const originalPath = path15.join(projectDir, file.path);
|
|
4561
|
+
if (fs17.existsSync(originalPath)) {
|
|
4562
|
+
const existing = fs17.readFileSync(originalPath, "utf-8");
|
|
4415
4563
|
if (normalizeContent(existing) === normalizeContent(file.content)) {
|
|
4416
4564
|
continue;
|
|
4417
4565
|
}
|
|
4418
4566
|
}
|
|
4419
|
-
const proposedPath =
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
if (
|
|
4423
|
-
const currentPath =
|
|
4424
|
-
|
|
4425
|
-
|
|
4567
|
+
const proposedPath = path15.join(PROPOSED_DIR, file.path);
|
|
4568
|
+
fs17.mkdirSync(path15.dirname(proposedPath), { recursive: true });
|
|
4569
|
+
fs17.writeFileSync(proposedPath, file.content);
|
|
4570
|
+
if (fs17.existsSync(originalPath)) {
|
|
4571
|
+
const currentPath = path15.join(CURRENT_DIR, file.path);
|
|
4572
|
+
fs17.mkdirSync(path15.dirname(currentPath), { recursive: true });
|
|
4573
|
+
fs17.copyFileSync(originalPath, currentPath);
|
|
4426
4574
|
modifiedFiles++;
|
|
4427
4575
|
stagedFiles.push({ relativePath: file.path, proposedPath, currentPath, originalPath, isNew: false });
|
|
4428
4576
|
} else {
|
|
@@ -4433,22 +4581,13 @@ function stageFiles(files, projectDir) {
|
|
|
4433
4581
|
return { newFiles, modifiedFiles, stagedFiles };
|
|
4434
4582
|
}
|
|
4435
4583
|
function cleanupStaging() {
|
|
4436
|
-
if (
|
|
4437
|
-
|
|
4584
|
+
if (fs17.existsSync(STAGED_DIR)) {
|
|
4585
|
+
fs17.rmSync(STAGED_DIR, { recursive: true, force: true });
|
|
4438
4586
|
}
|
|
4439
4587
|
}
|
|
4440
4588
|
|
|
4441
4589
|
// src/commands/setup-files.ts
|
|
4442
|
-
import
|
|
4443
|
-
function buildSkillContent(skill) {
|
|
4444
|
-
const frontmatter = `---
|
|
4445
|
-
name: ${skill.name}
|
|
4446
|
-
description: ${skill.description}
|
|
4447
|
-
---
|
|
4448
|
-
|
|
4449
|
-
`;
|
|
4450
|
-
return frontmatter + skill.content;
|
|
4451
|
-
}
|
|
4590
|
+
import fs18 from "fs";
|
|
4452
4591
|
function collectSetupFiles(setup, targetAgent) {
|
|
4453
4592
|
const files = [];
|
|
4454
4593
|
const claude = setup.claude;
|
|
@@ -4462,6 +4601,9 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
4462
4601
|
files.push({ path: `.claude/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
4463
4602
|
}
|
|
4464
4603
|
}
|
|
4604
|
+
for (const builtin of BUILTIN_SKILLS) {
|
|
4605
|
+
files.push({ path: `.claude/skills/${builtin.name}/SKILL.md`, content: buildSkillContent(builtin) });
|
|
4606
|
+
}
|
|
4465
4607
|
}
|
|
4466
4608
|
if (codex) {
|
|
4467
4609
|
if (codex.agentsMd) files.push({ path: "AGENTS.md", content: codex.agentsMd });
|
|
@@ -4471,6 +4613,9 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
4471
4613
|
files.push({ path: `.agents/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
4472
4614
|
}
|
|
4473
4615
|
}
|
|
4616
|
+
for (const builtin of BUILTIN_SKILLS) {
|
|
4617
|
+
files.push({ path: `.agents/skills/${builtin.name}/SKILL.md`, content: buildSkillContent(builtin) });
|
|
4618
|
+
}
|
|
4474
4619
|
}
|
|
4475
4620
|
if (cursor) {
|
|
4476
4621
|
if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
|
|
@@ -4480,6 +4625,9 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
4480
4625
|
files.push({ path: `.cursor/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
|
|
4481
4626
|
}
|
|
4482
4627
|
}
|
|
4628
|
+
for (const builtin of BUILTIN_SKILLS) {
|
|
4629
|
+
files.push({ path: `.cursor/skills/${builtin.name}/SKILL.md`, content: buildSkillContent(builtin) });
|
|
4630
|
+
}
|
|
4483
4631
|
const rules = cursor.rules;
|
|
4484
4632
|
if (Array.isArray(rules)) {
|
|
4485
4633
|
for (const rule of rules) {
|
|
@@ -4498,7 +4646,7 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
4498
4646
|
}
|
|
4499
4647
|
}
|
|
4500
4648
|
const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
|
|
4501
|
-
if (codexTargeted && !
|
|
4649
|
+
if (codexTargeted && !fs18.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
|
|
4502
4650
|
const agentRefs = [];
|
|
4503
4651
|
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
4504
4652
|
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
@@ -4516,9 +4664,9 @@ ${agentRefs.join(" ")}
|
|
|
4516
4664
|
|
|
4517
4665
|
// src/lib/learning-hooks.ts
|
|
4518
4666
|
init_resolve_caliber();
|
|
4519
|
-
import
|
|
4520
|
-
import
|
|
4521
|
-
var SETTINGS_PATH =
|
|
4667
|
+
import fs20 from "fs";
|
|
4668
|
+
import path16 from "path";
|
|
4669
|
+
var SETTINGS_PATH = path16.join(".claude", "settings.json");
|
|
4522
4670
|
var HOOK_TAILS = [
|
|
4523
4671
|
{ event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
|
|
4524
4672
|
{ event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
|
|
@@ -4535,17 +4683,17 @@ function getHookConfigs() {
|
|
|
4535
4683
|
}));
|
|
4536
4684
|
}
|
|
4537
4685
|
function readSettings() {
|
|
4538
|
-
if (!
|
|
4686
|
+
if (!fs20.existsSync(SETTINGS_PATH)) return {};
|
|
4539
4687
|
try {
|
|
4540
|
-
return JSON.parse(
|
|
4688
|
+
return JSON.parse(fs20.readFileSync(SETTINGS_PATH, "utf-8"));
|
|
4541
4689
|
} catch {
|
|
4542
4690
|
return {};
|
|
4543
4691
|
}
|
|
4544
4692
|
}
|
|
4545
4693
|
function writeSettings(settings) {
|
|
4546
|
-
const dir =
|
|
4547
|
-
if (!
|
|
4548
|
-
|
|
4694
|
+
const dir = path16.dirname(SETTINGS_PATH);
|
|
4695
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
4696
|
+
fs20.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
4549
4697
|
}
|
|
4550
4698
|
function hasLearningHook(matchers, tail) {
|
|
4551
4699
|
return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
|
|
@@ -4579,7 +4727,7 @@ function installLearningHooks() {
|
|
|
4579
4727
|
writeSettings(settings);
|
|
4580
4728
|
return { installed: true, alreadyInstalled: false };
|
|
4581
4729
|
}
|
|
4582
|
-
var CURSOR_HOOKS_PATH =
|
|
4730
|
+
var CURSOR_HOOKS_PATH = path16.join(".cursor", "hooks.json");
|
|
4583
4731
|
var CURSOR_HOOK_EVENTS = [
|
|
4584
4732
|
{ event: "postToolUse", tail: "learn observe" },
|
|
4585
4733
|
{ event: "postToolUseFailure", tail: "learn observe --failure" },
|
|
@@ -4587,17 +4735,17 @@ var CURSOR_HOOK_EVENTS = [
|
|
|
4587
4735
|
{ event: "sessionEnd", tail: "learn finalize --auto" }
|
|
4588
4736
|
];
|
|
4589
4737
|
function readCursorHooks() {
|
|
4590
|
-
if (!
|
|
4738
|
+
if (!fs20.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
|
|
4591
4739
|
try {
|
|
4592
|
-
return JSON.parse(
|
|
4740
|
+
return JSON.parse(fs20.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
|
|
4593
4741
|
} catch {
|
|
4594
4742
|
return { version: 1, hooks: {} };
|
|
4595
4743
|
}
|
|
4596
4744
|
}
|
|
4597
4745
|
function writeCursorHooks(config) {
|
|
4598
|
-
const dir =
|
|
4599
|
-
if (!
|
|
4600
|
-
|
|
4746
|
+
const dir = path16.dirname(CURSOR_HOOKS_PATH);
|
|
4747
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
4748
|
+
fs20.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
|
|
4601
4749
|
}
|
|
4602
4750
|
function hasCursorHook(entries, tail) {
|
|
4603
4751
|
return entries.some((e) => isCaliberCommand(e.command, tail));
|
|
@@ -4667,10 +4815,10 @@ function removeLearningHooks() {
|
|
|
4667
4815
|
|
|
4668
4816
|
// src/lib/state.ts
|
|
4669
4817
|
init_constants();
|
|
4670
|
-
import
|
|
4671
|
-
import
|
|
4818
|
+
import fs21 from "fs";
|
|
4819
|
+
import path17 from "path";
|
|
4672
4820
|
import { execSync as execSync7 } from "child_process";
|
|
4673
|
-
var STATE_FILE =
|
|
4821
|
+
var STATE_FILE = path17.join(CALIBER_DIR, ".caliber-state.json");
|
|
4674
4822
|
function normalizeTargetAgent(value) {
|
|
4675
4823
|
if (Array.isArray(value)) return value;
|
|
4676
4824
|
if (typeof value === "string") {
|
|
@@ -4681,8 +4829,8 @@ function normalizeTargetAgent(value) {
|
|
|
4681
4829
|
}
|
|
4682
4830
|
function readState() {
|
|
4683
4831
|
try {
|
|
4684
|
-
if (!
|
|
4685
|
-
const raw = JSON.parse(
|
|
4832
|
+
if (!fs21.existsSync(STATE_FILE)) return null;
|
|
4833
|
+
const raw = JSON.parse(fs21.readFileSync(STATE_FILE, "utf-8"));
|
|
4686
4834
|
if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
|
|
4687
4835
|
return raw;
|
|
4688
4836
|
} catch {
|
|
@@ -4690,10 +4838,10 @@ function readState() {
|
|
|
4690
4838
|
}
|
|
4691
4839
|
}
|
|
4692
4840
|
function writeState(state) {
|
|
4693
|
-
if (!
|
|
4694
|
-
|
|
4841
|
+
if (!fs21.existsSync(CALIBER_DIR)) {
|
|
4842
|
+
fs21.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
4695
4843
|
}
|
|
4696
|
-
|
|
4844
|
+
fs21.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
4697
4845
|
}
|
|
4698
4846
|
function getCurrentHeadSha() {
|
|
4699
4847
|
try {
|
|
@@ -5752,22 +5900,22 @@ function checkSources(dir) {
|
|
|
5752
5900
|
|
|
5753
5901
|
// src/scoring/dismissed.ts
|
|
5754
5902
|
init_constants();
|
|
5755
|
-
import
|
|
5756
|
-
import
|
|
5757
|
-
var DISMISSED_FILE =
|
|
5903
|
+
import fs22 from "fs";
|
|
5904
|
+
import path18 from "path";
|
|
5905
|
+
var DISMISSED_FILE = path18.join(CALIBER_DIR, "dismissed-checks.json");
|
|
5758
5906
|
function readDismissedChecks() {
|
|
5759
5907
|
try {
|
|
5760
|
-
if (!
|
|
5761
|
-
return JSON.parse(
|
|
5908
|
+
if (!fs22.existsSync(DISMISSED_FILE)) return [];
|
|
5909
|
+
return JSON.parse(fs22.readFileSync(DISMISSED_FILE, "utf-8"));
|
|
5762
5910
|
} catch {
|
|
5763
5911
|
return [];
|
|
5764
5912
|
}
|
|
5765
5913
|
}
|
|
5766
5914
|
function writeDismissedChecks(checks) {
|
|
5767
|
-
if (!
|
|
5768
|
-
|
|
5915
|
+
if (!fs22.existsSync(CALIBER_DIR)) {
|
|
5916
|
+
fs22.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
5769
5917
|
}
|
|
5770
|
-
|
|
5918
|
+
fs22.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
|
|
5771
5919
|
}
|
|
5772
5920
|
function getDismissedIds() {
|
|
5773
5921
|
return new Set(readDismissedChecks().map((c) => c.id));
|
|
@@ -6015,13 +6163,13 @@ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4,
|
|
|
6015
6163
|
import { join as join10, dirname as dirname2 } from "path";
|
|
6016
6164
|
|
|
6017
6165
|
// src/scanner/index.ts
|
|
6018
|
-
import
|
|
6019
|
-
import
|
|
6166
|
+
import fs23 from "fs";
|
|
6167
|
+
import path19 from "path";
|
|
6020
6168
|
import crypto3 from "crypto";
|
|
6021
6169
|
function scanLocalState(dir) {
|
|
6022
6170
|
const items = [];
|
|
6023
|
-
const claudeMdPath =
|
|
6024
|
-
if (
|
|
6171
|
+
const claudeMdPath = path19.join(dir, "CLAUDE.md");
|
|
6172
|
+
if (fs23.existsSync(claudeMdPath)) {
|
|
6025
6173
|
items.push({
|
|
6026
6174
|
type: "rule",
|
|
6027
6175
|
platform: "claude",
|
|
@@ -6030,10 +6178,10 @@ function scanLocalState(dir) {
|
|
|
6030
6178
|
path: claudeMdPath
|
|
6031
6179
|
});
|
|
6032
6180
|
}
|
|
6033
|
-
const skillsDir =
|
|
6034
|
-
if (
|
|
6035
|
-
for (const file of
|
|
6036
|
-
const filePath =
|
|
6181
|
+
const skillsDir = path19.join(dir, ".claude", "skills");
|
|
6182
|
+
if (fs23.existsSync(skillsDir)) {
|
|
6183
|
+
for (const file of fs23.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
|
|
6184
|
+
const filePath = path19.join(skillsDir, file);
|
|
6037
6185
|
items.push({
|
|
6038
6186
|
type: "skill",
|
|
6039
6187
|
platform: "claude",
|
|
@@ -6043,10 +6191,10 @@ function scanLocalState(dir) {
|
|
|
6043
6191
|
});
|
|
6044
6192
|
}
|
|
6045
6193
|
}
|
|
6046
|
-
const mcpJsonPath =
|
|
6047
|
-
if (
|
|
6194
|
+
const mcpJsonPath = path19.join(dir, ".mcp.json");
|
|
6195
|
+
if (fs23.existsSync(mcpJsonPath)) {
|
|
6048
6196
|
try {
|
|
6049
|
-
const mcpJson = JSON.parse(
|
|
6197
|
+
const mcpJson = JSON.parse(fs23.readFileSync(mcpJsonPath, "utf-8"));
|
|
6050
6198
|
if (mcpJson.mcpServers) {
|
|
6051
6199
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
6052
6200
|
items.push({
|
|
@@ -6061,8 +6209,8 @@ function scanLocalState(dir) {
|
|
|
6061
6209
|
} catch {
|
|
6062
6210
|
}
|
|
6063
6211
|
}
|
|
6064
|
-
const agentsMdPath =
|
|
6065
|
-
if (
|
|
6212
|
+
const agentsMdPath = path19.join(dir, "AGENTS.md");
|
|
6213
|
+
if (fs23.existsSync(agentsMdPath)) {
|
|
6066
6214
|
items.push({
|
|
6067
6215
|
type: "rule",
|
|
6068
6216
|
platform: "codex",
|
|
@@ -6071,12 +6219,12 @@ function scanLocalState(dir) {
|
|
|
6071
6219
|
path: agentsMdPath
|
|
6072
6220
|
});
|
|
6073
6221
|
}
|
|
6074
|
-
const codexSkillsDir =
|
|
6075
|
-
if (
|
|
6222
|
+
const codexSkillsDir = path19.join(dir, ".agents", "skills");
|
|
6223
|
+
if (fs23.existsSync(codexSkillsDir)) {
|
|
6076
6224
|
try {
|
|
6077
|
-
for (const name of
|
|
6078
|
-
const skillFile =
|
|
6079
|
-
if (
|
|
6225
|
+
for (const name of fs23.readdirSync(codexSkillsDir)) {
|
|
6226
|
+
const skillFile = path19.join(codexSkillsDir, name, "SKILL.md");
|
|
6227
|
+
if (fs23.existsSync(skillFile)) {
|
|
6080
6228
|
items.push({
|
|
6081
6229
|
type: "skill",
|
|
6082
6230
|
platform: "codex",
|
|
@@ -6089,8 +6237,8 @@ function scanLocalState(dir) {
|
|
|
6089
6237
|
} catch {
|
|
6090
6238
|
}
|
|
6091
6239
|
}
|
|
6092
|
-
const cursorrulesPath =
|
|
6093
|
-
if (
|
|
6240
|
+
const cursorrulesPath = path19.join(dir, ".cursorrules");
|
|
6241
|
+
if (fs23.existsSync(cursorrulesPath)) {
|
|
6094
6242
|
items.push({
|
|
6095
6243
|
type: "rule",
|
|
6096
6244
|
platform: "cursor",
|
|
@@ -6099,10 +6247,10 @@ function scanLocalState(dir) {
|
|
|
6099
6247
|
path: cursorrulesPath
|
|
6100
6248
|
});
|
|
6101
6249
|
}
|
|
6102
|
-
const cursorRulesDir =
|
|
6103
|
-
if (
|
|
6104
|
-
for (const file of
|
|
6105
|
-
const filePath =
|
|
6250
|
+
const cursorRulesDir = path19.join(dir, ".cursor", "rules");
|
|
6251
|
+
if (fs23.existsSync(cursorRulesDir)) {
|
|
6252
|
+
for (const file of fs23.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
|
|
6253
|
+
const filePath = path19.join(cursorRulesDir, file);
|
|
6106
6254
|
items.push({
|
|
6107
6255
|
type: "rule",
|
|
6108
6256
|
platform: "cursor",
|
|
@@ -6112,12 +6260,12 @@ function scanLocalState(dir) {
|
|
|
6112
6260
|
});
|
|
6113
6261
|
}
|
|
6114
6262
|
}
|
|
6115
|
-
const cursorSkillsDir =
|
|
6116
|
-
if (
|
|
6263
|
+
const cursorSkillsDir = path19.join(dir, ".cursor", "skills");
|
|
6264
|
+
if (fs23.existsSync(cursorSkillsDir)) {
|
|
6117
6265
|
try {
|
|
6118
|
-
for (const name of
|
|
6119
|
-
const skillFile =
|
|
6120
|
-
if (
|
|
6266
|
+
for (const name of fs23.readdirSync(cursorSkillsDir)) {
|
|
6267
|
+
const skillFile = path19.join(cursorSkillsDir, name, "SKILL.md");
|
|
6268
|
+
if (fs23.existsSync(skillFile)) {
|
|
6121
6269
|
items.push({
|
|
6122
6270
|
type: "skill",
|
|
6123
6271
|
platform: "cursor",
|
|
@@ -6130,10 +6278,10 @@ function scanLocalState(dir) {
|
|
|
6130
6278
|
} catch {
|
|
6131
6279
|
}
|
|
6132
6280
|
}
|
|
6133
|
-
const cursorMcpPath =
|
|
6134
|
-
if (
|
|
6281
|
+
const cursorMcpPath = path19.join(dir, ".cursor", "mcp.json");
|
|
6282
|
+
if (fs23.existsSync(cursorMcpPath)) {
|
|
6135
6283
|
try {
|
|
6136
|
-
const mcpJson = JSON.parse(
|
|
6284
|
+
const mcpJson = JSON.parse(fs23.readFileSync(cursorMcpPath, "utf-8"));
|
|
6137
6285
|
if (mcpJson.mcpServers) {
|
|
6138
6286
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
6139
6287
|
items.push({
|
|
@@ -6151,7 +6299,7 @@ function scanLocalState(dir) {
|
|
|
6151
6299
|
return items;
|
|
6152
6300
|
}
|
|
6153
6301
|
function hashFile(filePath) {
|
|
6154
|
-
const text =
|
|
6302
|
+
const text = fs23.readFileSync(filePath, "utf-8");
|
|
6155
6303
|
return crypto3.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
|
|
6156
6304
|
}
|
|
6157
6305
|
function hashJson(obj) {
|
|
@@ -6166,27 +6314,27 @@ import { PostHog } from "posthog-node";
|
|
|
6166
6314
|
import chalk5 from "chalk";
|
|
6167
6315
|
|
|
6168
6316
|
// src/telemetry/config.ts
|
|
6169
|
-
import
|
|
6170
|
-
import
|
|
6317
|
+
import fs24 from "fs";
|
|
6318
|
+
import path20 from "path";
|
|
6171
6319
|
import os4 from "os";
|
|
6172
6320
|
import crypto4 from "crypto";
|
|
6173
6321
|
import { execSync as execSync11 } from "child_process";
|
|
6174
|
-
var CONFIG_DIR2 =
|
|
6175
|
-
var CONFIG_FILE2 =
|
|
6322
|
+
var CONFIG_DIR2 = path20.join(os4.homedir(), ".caliber");
|
|
6323
|
+
var CONFIG_FILE2 = path20.join(CONFIG_DIR2, "config.json");
|
|
6176
6324
|
var runtimeDisabled = false;
|
|
6177
6325
|
function readConfig() {
|
|
6178
6326
|
try {
|
|
6179
|
-
if (!
|
|
6180
|
-
return JSON.parse(
|
|
6327
|
+
if (!fs24.existsSync(CONFIG_FILE2)) return {};
|
|
6328
|
+
return JSON.parse(fs24.readFileSync(CONFIG_FILE2, "utf-8"));
|
|
6181
6329
|
} catch {
|
|
6182
6330
|
return {};
|
|
6183
6331
|
}
|
|
6184
6332
|
}
|
|
6185
6333
|
function writeConfig(config) {
|
|
6186
|
-
if (!
|
|
6187
|
-
|
|
6334
|
+
if (!fs24.existsSync(CONFIG_DIR2)) {
|
|
6335
|
+
fs24.mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
6188
6336
|
}
|
|
6189
|
-
|
|
6337
|
+
fs24.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
6190
6338
|
}
|
|
6191
6339
|
function getMachineId() {
|
|
6192
6340
|
const config = readConfig();
|
|
@@ -6671,7 +6819,109 @@ async function searchSkills(fingerprint, targetPlatforms, onStatus) {
|
|
|
6671
6819
|
const available = results.filter((r) => contentMap.has(r.slug));
|
|
6672
6820
|
return { results: available, contentMap };
|
|
6673
6821
|
}
|
|
6674
|
-
async function
|
|
6822
|
+
async function querySkills(query) {
|
|
6823
|
+
const terms = query.split(/[\s,]+/).filter(Boolean);
|
|
6824
|
+
if (terms.length === 0) {
|
|
6825
|
+
console.log(chalk6.yellow("Please provide search terms."));
|
|
6826
|
+
throw new Error("__exit__");
|
|
6827
|
+
}
|
|
6828
|
+
const platforms = detectLocalPlatforms();
|
|
6829
|
+
const installedSkills = getInstalledSkills(platforms);
|
|
6830
|
+
const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
|
|
6831
|
+
const searchSpinner = ora("Searching skill registries...").start();
|
|
6832
|
+
const allCandidates = await searchAllProviders(terms, primaryPlatform);
|
|
6833
|
+
if (!allCandidates.length) {
|
|
6834
|
+
searchSpinner.succeed("No skills found matching your query.");
|
|
6835
|
+
return;
|
|
6836
|
+
}
|
|
6837
|
+
const newCandidates = allCandidates.filter((c) => !installedSkills.has(c.slug.toLowerCase()));
|
|
6838
|
+
if (!newCandidates.length) {
|
|
6839
|
+
searchSpinner.succeed("All matching skills are already installed.");
|
|
6840
|
+
return;
|
|
6841
|
+
}
|
|
6842
|
+
searchSpinner.succeed(`Found ${newCandidates.length} candidates`);
|
|
6843
|
+
let results;
|
|
6844
|
+
const config = loadConfig();
|
|
6845
|
+
if (config) {
|
|
6846
|
+
const scoreSpinner = ora("Scoring relevance...").start();
|
|
6847
|
+
try {
|
|
6848
|
+
const queryContext = `User is looking for skills related to: ${query}`;
|
|
6849
|
+
results = await scoreWithLLM(newCandidates, queryContext, terms);
|
|
6850
|
+
if (results.length === 0) {
|
|
6851
|
+
scoreSpinner.succeed("No highly relevant skills found.");
|
|
6852
|
+
return;
|
|
6853
|
+
}
|
|
6854
|
+
scoreSpinner.succeed(`${results.length} relevant`);
|
|
6855
|
+
} catch {
|
|
6856
|
+
results = newCandidates.slice(0, 5);
|
|
6857
|
+
}
|
|
6858
|
+
} else {
|
|
6859
|
+
results = newCandidates.slice(0, 5);
|
|
6860
|
+
}
|
|
6861
|
+
const top = results.slice(0, 5);
|
|
6862
|
+
const fetchSpinner = ora("Verifying availability...").start();
|
|
6863
|
+
const contentMap = /* @__PURE__ */ new Map();
|
|
6864
|
+
await Promise.all(top.map(async (rec) => {
|
|
6865
|
+
const content = await fetchSkillContent(rec);
|
|
6866
|
+
if (content) contentMap.set(rec.slug, content);
|
|
6867
|
+
}));
|
|
6868
|
+
const available = top.filter((r) => contentMap.has(r.slug));
|
|
6869
|
+
fetchSpinner.succeed(`${available.length} available`);
|
|
6870
|
+
if (!available.length) {
|
|
6871
|
+
console.log(chalk6.dim(" No installable skills found.\n"));
|
|
6872
|
+
return;
|
|
6873
|
+
}
|
|
6874
|
+
console.log("");
|
|
6875
|
+
for (let i = 0; i < available.length; i++) {
|
|
6876
|
+
const r = available[i];
|
|
6877
|
+
const scoreStr = r.score > 0 ? ` (score: ${r.score})` : "";
|
|
6878
|
+
console.log(` ${i + 1}. ${r.slug}${scoreStr}`);
|
|
6879
|
+
console.log(` ${r.reason || r.name}`);
|
|
6880
|
+
}
|
|
6881
|
+
console.log("");
|
|
6882
|
+
console.log(chalk6.dim(` Install with: caliber skills --install ${available.map((r) => r.slug).join(",")}`));
|
|
6883
|
+
console.log("");
|
|
6884
|
+
}
|
|
6885
|
+
async function installBySlug(slugStr) {
|
|
6886
|
+
const slugs = slugStr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
6887
|
+
if (slugs.length === 0) {
|
|
6888
|
+
console.log(chalk6.yellow("Please provide skill slugs to install."));
|
|
6889
|
+
throw new Error("__exit__");
|
|
6890
|
+
}
|
|
6891
|
+
const platforms = detectLocalPlatforms();
|
|
6892
|
+
const spinner = ora(`Fetching ${slugs.length} skill${slugs.length > 1 ? "s" : ""}...`).start();
|
|
6893
|
+
const allResults = await searchAllProviders(slugs);
|
|
6894
|
+
const matched = [];
|
|
6895
|
+
for (const slug of slugs) {
|
|
6896
|
+
const match = allResults.find((r) => r.slug.toLowerCase() === slug.toLowerCase());
|
|
6897
|
+
if (match) matched.push(match);
|
|
6898
|
+
}
|
|
6899
|
+
if (!matched.length) {
|
|
6900
|
+
spinner.fail("No matching skills found in the registry.");
|
|
6901
|
+
return;
|
|
6902
|
+
}
|
|
6903
|
+
const contentMap = /* @__PURE__ */ new Map();
|
|
6904
|
+
await Promise.all(matched.map(async (rec) => {
|
|
6905
|
+
const content = await fetchSkillContent(rec);
|
|
6906
|
+
if (content) contentMap.set(rec.slug, content);
|
|
6907
|
+
}));
|
|
6908
|
+
const installable = matched.filter((r) => contentMap.has(r.slug));
|
|
6909
|
+
if (!installable.length) {
|
|
6910
|
+
spinner.fail("Could not fetch skill content.");
|
|
6911
|
+
return;
|
|
6912
|
+
}
|
|
6913
|
+
spinner.succeed(`Fetched ${installable.length} skill${installable.length > 1 ? "s" : ""}`);
|
|
6914
|
+
await installSkills(installable, platforms, contentMap);
|
|
6915
|
+
}
|
|
6916
|
+
async function recommendCommand(options) {
|
|
6917
|
+
if (options.install) {
|
|
6918
|
+
await installBySlug(options.install);
|
|
6919
|
+
return;
|
|
6920
|
+
}
|
|
6921
|
+
if (options.query) {
|
|
6922
|
+
await querySkills(options.query);
|
|
6923
|
+
return;
|
|
6924
|
+
}
|
|
6675
6925
|
const proceed = await select3({
|
|
6676
6926
|
message: "Search public repos for relevant skills to add to this project?",
|
|
6677
6927
|
choices: [
|
|
@@ -7145,11 +7395,11 @@ function countIssuePoints(issues) {
|
|
|
7145
7395
|
}
|
|
7146
7396
|
async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
|
|
7147
7397
|
const existsCache = /* @__PURE__ */ new Map();
|
|
7148
|
-
const cachedExists = (
|
|
7149
|
-
const cached = existsCache.get(
|
|
7398
|
+
const cachedExists = (path39) => {
|
|
7399
|
+
const cached = existsCache.get(path39);
|
|
7150
7400
|
if (cached !== void 0) return cached;
|
|
7151
|
-
const result = existsSync9(
|
|
7152
|
-
existsCache.set(
|
|
7401
|
+
const result = existsSync9(path39);
|
|
7402
|
+
existsCache.set(path39, result);
|
|
7153
7403
|
return result;
|
|
7154
7404
|
};
|
|
7155
7405
|
const projectStructure = collectProjectStructure(dir);
|
|
@@ -7288,8 +7538,8 @@ async function runScoreRefineWithSpinner(setup, dir, sessionHistory) {
|
|
|
7288
7538
|
}
|
|
7289
7539
|
|
|
7290
7540
|
// src/lib/debug-report.ts
|
|
7291
|
-
import
|
|
7292
|
-
import
|
|
7541
|
+
import fs25 from "fs";
|
|
7542
|
+
import path21 from "path";
|
|
7293
7543
|
var DebugReport = class {
|
|
7294
7544
|
sections = [];
|
|
7295
7545
|
startTime;
|
|
@@ -7358,11 +7608,11 @@ var DebugReport = class {
|
|
|
7358
7608
|
lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
|
|
7359
7609
|
lines.push("");
|
|
7360
7610
|
}
|
|
7361
|
-
const dir =
|
|
7362
|
-
if (!
|
|
7363
|
-
|
|
7611
|
+
const dir = path21.dirname(outputPath);
|
|
7612
|
+
if (!fs25.existsSync(dir)) {
|
|
7613
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
7364
7614
|
}
|
|
7365
|
-
|
|
7615
|
+
fs25.writeFileSync(outputPath, lines.join("\n"));
|
|
7366
7616
|
}
|
|
7367
7617
|
};
|
|
7368
7618
|
function formatMs(ms) {
|
|
@@ -7763,7 +8013,7 @@ import chalk11 from "chalk";
|
|
|
7763
8013
|
import ora3 from "ora";
|
|
7764
8014
|
import select5 from "@inquirer/select";
|
|
7765
8015
|
import checkbox from "@inquirer/checkbox";
|
|
7766
|
-
import
|
|
8016
|
+
import fs28 from "fs";
|
|
7767
8017
|
|
|
7768
8018
|
// src/ai/refine.ts
|
|
7769
8019
|
async function refineSetup(currentSetup, message, conversationHistory, callbacks) {
|
|
@@ -7904,10 +8154,10 @@ init_config();
|
|
|
7904
8154
|
init_review();
|
|
7905
8155
|
function detectAgents(dir) {
|
|
7906
8156
|
const agents = [];
|
|
7907
|
-
if (
|
|
7908
|
-
if (
|
|
7909
|
-
if (
|
|
7910
|
-
if (
|
|
8157
|
+
if (fs28.existsSync(`${dir}/.claude`)) agents.push("claude");
|
|
8158
|
+
if (fs28.existsSync(`${dir}/.cursor`)) agents.push("cursor");
|
|
8159
|
+
if (fs28.existsSync(`${dir}/.agents`) || fs28.existsSync(`${dir}/AGENTS.md`)) agents.push("codex");
|
|
8160
|
+
if (fs28.existsSync(`${dir}/.github/copilot-instructions.md`)) agents.push("github-copilot");
|
|
7911
8161
|
return agents;
|
|
7912
8162
|
}
|
|
7913
8163
|
async function promptAgent(detected) {
|
|
@@ -8029,18 +8279,18 @@ async function refineLoop(currentSetup, sessionHistory, summarizeSetup2, printSu
|
|
|
8029
8279
|
|
|
8030
8280
|
// src/commands/init-display.ts
|
|
8031
8281
|
import chalk12 from "chalk";
|
|
8032
|
-
import
|
|
8282
|
+
import fs29 from "fs";
|
|
8033
8283
|
function formatWhatChanged(setup) {
|
|
8034
8284
|
const lines = [];
|
|
8035
8285
|
const claude = setup.claude;
|
|
8036
8286
|
const codex = setup.codex;
|
|
8037
8287
|
const cursor = setup.cursor;
|
|
8038
8288
|
if (claude?.claudeMd) {
|
|
8039
|
-
const action =
|
|
8289
|
+
const action = fs29.existsSync("CLAUDE.md") ? "Updated" : "Created";
|
|
8040
8290
|
lines.push(`${action} CLAUDE.md`);
|
|
8041
8291
|
}
|
|
8042
8292
|
if (codex?.agentsMd) {
|
|
8043
|
-
const action =
|
|
8293
|
+
const action = fs29.existsSync("AGENTS.md") ? "Updated" : "Created";
|
|
8044
8294
|
lines.push(`${action} AGENTS.md`);
|
|
8045
8295
|
}
|
|
8046
8296
|
const allSkills = [];
|
|
@@ -8077,7 +8327,7 @@ function printSetupSummary(setup) {
|
|
|
8077
8327
|
};
|
|
8078
8328
|
if (claude) {
|
|
8079
8329
|
if (claude.claudeMd) {
|
|
8080
|
-
const icon =
|
|
8330
|
+
const icon = fs29.existsSync("CLAUDE.md") ? chalk12.yellow("~") : chalk12.green("+");
|
|
8081
8331
|
const desc = getDescription("CLAUDE.md");
|
|
8082
8332
|
console.log(` ${icon} ${chalk12.bold("CLAUDE.md")}`);
|
|
8083
8333
|
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
@@ -8087,7 +8337,7 @@ function printSetupSummary(setup) {
|
|
|
8087
8337
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
8088
8338
|
for (const skill of skills) {
|
|
8089
8339
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
8090
|
-
const icon =
|
|
8340
|
+
const icon = fs29.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
8091
8341
|
const desc = getDescription(skillPath);
|
|
8092
8342
|
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
8093
8343
|
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -8098,7 +8348,7 @@ function printSetupSummary(setup) {
|
|
|
8098
8348
|
const codex = setup.codex;
|
|
8099
8349
|
if (codex) {
|
|
8100
8350
|
if (codex.agentsMd) {
|
|
8101
|
-
const icon =
|
|
8351
|
+
const icon = fs29.existsSync("AGENTS.md") ? chalk12.yellow("~") : chalk12.green("+");
|
|
8102
8352
|
const desc = getDescription("AGENTS.md");
|
|
8103
8353
|
console.log(` ${icon} ${chalk12.bold("AGENTS.md")}`);
|
|
8104
8354
|
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
@@ -8108,7 +8358,7 @@ function printSetupSummary(setup) {
|
|
|
8108
8358
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
8109
8359
|
for (const skill of codexSkills) {
|
|
8110
8360
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
8111
|
-
const icon =
|
|
8361
|
+
const icon = fs29.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
8112
8362
|
const desc = getDescription(skillPath);
|
|
8113
8363
|
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
8114
8364
|
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -8118,7 +8368,7 @@ function printSetupSummary(setup) {
|
|
|
8118
8368
|
}
|
|
8119
8369
|
if (cursor) {
|
|
8120
8370
|
if (cursor.cursorrules) {
|
|
8121
|
-
const icon =
|
|
8371
|
+
const icon = fs29.existsSync(".cursorrules") ? chalk12.yellow("~") : chalk12.green("+");
|
|
8122
8372
|
const desc = getDescription(".cursorrules");
|
|
8123
8373
|
console.log(` ${icon} ${chalk12.bold(".cursorrules")}`);
|
|
8124
8374
|
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
@@ -8128,7 +8378,7 @@ function printSetupSummary(setup) {
|
|
|
8128
8378
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
8129
8379
|
for (const skill of cursorSkills) {
|
|
8130
8380
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
8131
|
-
const icon =
|
|
8381
|
+
const icon = fs29.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
8132
8382
|
const desc = getDescription(skillPath);
|
|
8133
8383
|
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
8134
8384
|
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -8139,7 +8389,7 @@ function printSetupSummary(setup) {
|
|
|
8139
8389
|
if (Array.isArray(rulesArr) && rulesArr.length > 0) {
|
|
8140
8390
|
for (const rule of rulesArr) {
|
|
8141
8391
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
8142
|
-
const icon =
|
|
8392
|
+
const icon = fs29.existsSync(rulePath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
8143
8393
|
const desc = getDescription(rulePath);
|
|
8144
8394
|
console.log(` ${icon} ${chalk12.bold(rulePath)}`);
|
|
8145
8395
|
if (desc) {
|
|
@@ -8186,12 +8436,12 @@ function displayTokenUsage() {
|
|
|
8186
8436
|
// src/commands/init-helpers.ts
|
|
8187
8437
|
init_config();
|
|
8188
8438
|
import chalk13 from "chalk";
|
|
8189
|
-
import
|
|
8190
|
-
import
|
|
8439
|
+
import fs30 from "fs";
|
|
8440
|
+
import path23 from "path";
|
|
8191
8441
|
function isFirstRun(dir) {
|
|
8192
|
-
const caliberDir =
|
|
8442
|
+
const caliberDir = path23.join(dir, ".caliber");
|
|
8193
8443
|
try {
|
|
8194
|
-
const stat =
|
|
8444
|
+
const stat = fs30.statSync(caliberDir);
|
|
8195
8445
|
return !stat.isDirectory();
|
|
8196
8446
|
} catch {
|
|
8197
8447
|
return true;
|
|
@@ -8244,8 +8494,8 @@ function ensurePermissions(fingerprint) {
|
|
|
8244
8494
|
const settingsPath = ".claude/settings.json";
|
|
8245
8495
|
let settings = {};
|
|
8246
8496
|
try {
|
|
8247
|
-
if (
|
|
8248
|
-
settings = JSON.parse(
|
|
8497
|
+
if (fs30.existsSync(settingsPath)) {
|
|
8498
|
+
settings = JSON.parse(fs30.readFileSync(settingsPath, "utf-8"));
|
|
8249
8499
|
}
|
|
8250
8500
|
} catch {
|
|
8251
8501
|
}
|
|
@@ -8254,12 +8504,12 @@ function ensurePermissions(fingerprint) {
|
|
|
8254
8504
|
if (Array.isArray(allow) && allow.length > 0) return;
|
|
8255
8505
|
permissions.allow = derivePermissions(fingerprint);
|
|
8256
8506
|
settings.permissions = permissions;
|
|
8257
|
-
if (!
|
|
8258
|
-
|
|
8507
|
+
if (!fs30.existsSync(".claude")) fs30.mkdirSync(".claude", { recursive: true });
|
|
8508
|
+
fs30.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
8259
8509
|
}
|
|
8260
8510
|
function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
8261
8511
|
try {
|
|
8262
|
-
const logPath =
|
|
8512
|
+
const logPath = path23.join(process.cwd(), ".caliber", "error-log.md");
|
|
8263
8513
|
const lines = [
|
|
8264
8514
|
`# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
8265
8515
|
"",
|
|
@@ -8272,8 +8522,8 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
|
8272
8522
|
lines.push("## Error", "```", error, "```", "");
|
|
8273
8523
|
}
|
|
8274
8524
|
lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
|
|
8275
|
-
|
|
8276
|
-
|
|
8525
|
+
fs30.mkdirSync(path23.join(process.cwd(), ".caliber"), { recursive: true });
|
|
8526
|
+
fs30.writeFileSync(logPath, lines.join("\n"));
|
|
8277
8527
|
console.log(chalk13.dim(`
|
|
8278
8528
|
Error log written to .caliber/error-log.md`));
|
|
8279
8529
|
} catch {
|
|
@@ -8711,7 +8961,7 @@ async function initCommand(options) {
|
|
|
8711
8961
|
const { default: ora9 } = await import("ora");
|
|
8712
8962
|
const writeSpinner = ora9("Writing config files...").start();
|
|
8713
8963
|
try {
|
|
8714
|
-
if (targetAgent.includes("codex") && !
|
|
8964
|
+
if (targetAgent.includes("codex") && !fs31.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
8715
8965
|
const claude = generatedSetup.claude;
|
|
8716
8966
|
const cursor = generatedSetup.cursor;
|
|
8717
8967
|
const agentRefs = [];
|
|
@@ -8860,9 +9110,9 @@ ${agentRefs.join(" ")}
|
|
|
8860
9110
|
}
|
|
8861
9111
|
if (report) {
|
|
8862
9112
|
report.markStep("Finished");
|
|
8863
|
-
const reportPath =
|
|
9113
|
+
const reportPath = path24.join(process.cwd(), ".caliber", "debug-report.md");
|
|
8864
9114
|
report.write(reportPath);
|
|
8865
|
-
console.log(chalk14.dim(` Debug report written to ${
|
|
9115
|
+
console.log(chalk14.dim(` Debug report written to ${path24.relative(process.cwd(), reportPath)}
|
|
8866
9116
|
`));
|
|
8867
9117
|
}
|
|
8868
9118
|
}
|
|
@@ -8901,7 +9151,7 @@ function undoCommand() {
|
|
|
8901
9151
|
|
|
8902
9152
|
// src/commands/status.ts
|
|
8903
9153
|
import chalk16 from "chalk";
|
|
8904
|
-
import
|
|
9154
|
+
import fs32 from "fs";
|
|
8905
9155
|
init_config();
|
|
8906
9156
|
async function statusCommand(options) {
|
|
8907
9157
|
const config = loadConfig();
|
|
@@ -8928,7 +9178,7 @@ async function statusCommand(options) {
|
|
|
8928
9178
|
}
|
|
8929
9179
|
console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
|
|
8930
9180
|
for (const entry of manifest.entries) {
|
|
8931
|
-
const exists =
|
|
9181
|
+
const exists = fs32.existsSync(entry.path);
|
|
8932
9182
|
const icon = exists ? chalk16.green("\u2713") : chalk16.red("\u2717");
|
|
8933
9183
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
8934
9184
|
}
|
|
@@ -9083,21 +9333,21 @@ async function regenerateCommand(options) {
|
|
|
9083
9333
|
}
|
|
9084
9334
|
|
|
9085
9335
|
// src/commands/score.ts
|
|
9086
|
-
import
|
|
9336
|
+
import fs33 from "fs";
|
|
9087
9337
|
import os6 from "os";
|
|
9088
|
-
import
|
|
9338
|
+
import path25 from "path";
|
|
9089
9339
|
import { execFileSync } from "child_process";
|
|
9090
9340
|
import chalk18 from "chalk";
|
|
9091
9341
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".cursorrules", "CALIBER_LEARNINGS.md"];
|
|
9092
9342
|
var CONFIG_DIRS = [".claude", ".cursor"];
|
|
9093
9343
|
function scoreBaseRef(ref, target) {
|
|
9094
9344
|
if (!/^[\w.\-\/~^@{}]+$/.test(ref)) return null;
|
|
9095
|
-
const tmpDir =
|
|
9345
|
+
const tmpDir = fs33.mkdtempSync(path25.join(os6.tmpdir(), "caliber-compare-"));
|
|
9096
9346
|
try {
|
|
9097
9347
|
for (const file of CONFIG_FILES) {
|
|
9098
9348
|
try {
|
|
9099
9349
|
const content = execFileSync("git", ["show", `${ref}:${file}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
9100
|
-
|
|
9350
|
+
fs33.writeFileSync(path25.join(tmpDir, file), content);
|
|
9101
9351
|
} catch {
|
|
9102
9352
|
}
|
|
9103
9353
|
}
|
|
@@ -9105,10 +9355,10 @@ function scoreBaseRef(ref, target) {
|
|
|
9105
9355
|
try {
|
|
9106
9356
|
const files = execFileSync("git", ["ls-tree", "-r", "--name-only", ref, `${dir}/`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n").filter(Boolean);
|
|
9107
9357
|
for (const file of files) {
|
|
9108
|
-
const filePath =
|
|
9109
|
-
|
|
9358
|
+
const filePath = path25.join(tmpDir, file);
|
|
9359
|
+
fs33.mkdirSync(path25.dirname(filePath), { recursive: true });
|
|
9110
9360
|
const content = execFileSync("git", ["show", `${ref}:${file}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
9111
|
-
|
|
9361
|
+
fs33.writeFileSync(filePath, content);
|
|
9112
9362
|
}
|
|
9113
9363
|
} catch {
|
|
9114
9364
|
}
|
|
@@ -9118,7 +9368,7 @@ function scoreBaseRef(ref, target) {
|
|
|
9118
9368
|
} catch {
|
|
9119
9369
|
return null;
|
|
9120
9370
|
} finally {
|
|
9121
|
-
|
|
9371
|
+
fs33.rmSync(tmpDir, { recursive: true, force: true });
|
|
9122
9372
|
}
|
|
9123
9373
|
}
|
|
9124
9374
|
async function scoreCommand(options) {
|
|
@@ -9178,8 +9428,8 @@ async function scoreCommand(options) {
|
|
|
9178
9428
|
}
|
|
9179
9429
|
|
|
9180
9430
|
// src/commands/refresh.ts
|
|
9181
|
-
import
|
|
9182
|
-
import
|
|
9431
|
+
import fs37 from "fs";
|
|
9432
|
+
import path29 from "path";
|
|
9183
9433
|
import chalk19 from "chalk";
|
|
9184
9434
|
import ora6 from "ora";
|
|
9185
9435
|
|
|
@@ -9257,48 +9507,48 @@ function collectDiff(lastSha) {
|
|
|
9257
9507
|
}
|
|
9258
9508
|
|
|
9259
9509
|
// src/writers/refresh.ts
|
|
9260
|
-
import
|
|
9261
|
-
import
|
|
9510
|
+
import fs34 from "fs";
|
|
9511
|
+
import path26 from "path";
|
|
9262
9512
|
function writeRefreshDocs(docs) {
|
|
9263
9513
|
const written = [];
|
|
9264
9514
|
if (docs.claudeMd) {
|
|
9265
|
-
|
|
9515
|
+
fs34.writeFileSync("CLAUDE.md", appendLearningsBlock(appendPreCommitBlock(docs.claudeMd)));
|
|
9266
9516
|
written.push("CLAUDE.md");
|
|
9267
9517
|
}
|
|
9268
9518
|
if (docs.readmeMd) {
|
|
9269
|
-
|
|
9519
|
+
fs34.writeFileSync("README.md", docs.readmeMd);
|
|
9270
9520
|
written.push("README.md");
|
|
9271
9521
|
}
|
|
9272
9522
|
if (docs.cursorrules) {
|
|
9273
|
-
|
|
9523
|
+
fs34.writeFileSync(".cursorrules", docs.cursorrules);
|
|
9274
9524
|
written.push(".cursorrules");
|
|
9275
9525
|
}
|
|
9276
9526
|
if (docs.cursorRules) {
|
|
9277
|
-
const rulesDir =
|
|
9278
|
-
if (!
|
|
9527
|
+
const rulesDir = path26.join(".cursor", "rules");
|
|
9528
|
+
if (!fs34.existsSync(rulesDir)) fs34.mkdirSync(rulesDir, { recursive: true });
|
|
9279
9529
|
for (const rule of docs.cursorRules) {
|
|
9280
|
-
|
|
9530
|
+
fs34.writeFileSync(path26.join(rulesDir, rule.filename), rule.content);
|
|
9281
9531
|
written.push(`.cursor/rules/${rule.filename}`);
|
|
9282
9532
|
}
|
|
9283
9533
|
}
|
|
9284
9534
|
if (docs.claudeSkills) {
|
|
9285
|
-
const skillsDir =
|
|
9286
|
-
if (!
|
|
9535
|
+
const skillsDir = path26.join(".claude", "skills");
|
|
9536
|
+
if (!fs34.existsSync(skillsDir)) fs34.mkdirSync(skillsDir, { recursive: true });
|
|
9287
9537
|
for (const skill of docs.claudeSkills) {
|
|
9288
|
-
|
|
9538
|
+
fs34.writeFileSync(path26.join(skillsDir, skill.filename), skill.content);
|
|
9289
9539
|
written.push(`.claude/skills/${skill.filename}`);
|
|
9290
9540
|
}
|
|
9291
9541
|
}
|
|
9292
9542
|
if (docs.copilotInstructions) {
|
|
9293
|
-
|
|
9294
|
-
|
|
9543
|
+
fs34.mkdirSync(".github", { recursive: true });
|
|
9544
|
+
fs34.writeFileSync(path26.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(docs.copilotInstructions)));
|
|
9295
9545
|
written.push(".github/copilot-instructions.md");
|
|
9296
9546
|
}
|
|
9297
9547
|
if (docs.copilotInstructionFiles) {
|
|
9298
|
-
const instructionsDir =
|
|
9299
|
-
|
|
9548
|
+
const instructionsDir = path26.join(".github", "instructions");
|
|
9549
|
+
fs34.mkdirSync(instructionsDir, { recursive: true });
|
|
9300
9550
|
for (const file of docs.copilotInstructionFiles) {
|
|
9301
|
-
|
|
9551
|
+
fs34.writeFileSync(path26.join(instructionsDir, file.filename), file.content);
|
|
9302
9552
|
written.push(`.github/instructions/${file.filename}`);
|
|
9303
9553
|
}
|
|
9304
9554
|
}
|
|
@@ -9378,8 +9628,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
9378
9628
|
}
|
|
9379
9629
|
|
|
9380
9630
|
// src/learner/writer.ts
|
|
9381
|
-
import
|
|
9382
|
-
import
|
|
9631
|
+
import fs35 from "fs";
|
|
9632
|
+
import path27 from "path";
|
|
9383
9633
|
|
|
9384
9634
|
// src/learner/utils.ts
|
|
9385
9635
|
var TYPE_PREFIX_RE = /^\*\*\[[^\]]+\]\*\*\s*/;
|
|
@@ -9497,20 +9747,20 @@ function deduplicateLearnedItems(existing, incoming) {
|
|
|
9497
9747
|
}
|
|
9498
9748
|
function writeLearnedSectionTo(filePath, header, existing, incoming, mode) {
|
|
9499
9749
|
const { merged, newCount, newItems } = deduplicateLearnedItems(existing, incoming);
|
|
9500
|
-
|
|
9501
|
-
if (mode)
|
|
9750
|
+
fs35.writeFileSync(filePath, header + merged + "\n");
|
|
9751
|
+
if (mode) fs35.chmodSync(filePath, mode);
|
|
9502
9752
|
return { newCount, newItems };
|
|
9503
9753
|
}
|
|
9504
9754
|
function writeLearnedSection(content) {
|
|
9505
9755
|
return writeLearnedSectionTo(LEARNINGS_FILE, LEARNINGS_HEADER, readLearnedSection(), content);
|
|
9506
9756
|
}
|
|
9507
9757
|
function writeLearnedSkill(skill) {
|
|
9508
|
-
const skillDir =
|
|
9509
|
-
if (!
|
|
9510
|
-
const skillPath =
|
|
9511
|
-
if (!skill.isNew &&
|
|
9512
|
-
const existing =
|
|
9513
|
-
|
|
9758
|
+
const skillDir = path27.join(".claude", "skills", skill.name);
|
|
9759
|
+
if (!fs35.existsSync(skillDir)) fs35.mkdirSync(skillDir, { recursive: true });
|
|
9760
|
+
const skillPath = path27.join(skillDir, "SKILL.md");
|
|
9761
|
+
if (!skill.isNew && fs35.existsSync(skillPath)) {
|
|
9762
|
+
const existing = fs35.readFileSync(skillPath, "utf-8");
|
|
9763
|
+
fs35.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
9514
9764
|
} else {
|
|
9515
9765
|
const frontmatter = [
|
|
9516
9766
|
"---",
|
|
@@ -9519,47 +9769,56 @@ function writeLearnedSkill(skill) {
|
|
|
9519
9769
|
"---",
|
|
9520
9770
|
""
|
|
9521
9771
|
].join("\n");
|
|
9522
|
-
|
|
9772
|
+
fs35.writeFileSync(skillPath, frontmatter + skill.content);
|
|
9523
9773
|
}
|
|
9524
9774
|
return skillPath;
|
|
9525
9775
|
}
|
|
9526
9776
|
function writePersonalLearnedSection(content) {
|
|
9527
|
-
if (!
|
|
9777
|
+
if (!fs35.existsSync(AUTH_DIR)) fs35.mkdirSync(AUTH_DIR, { recursive: true });
|
|
9528
9778
|
return writeLearnedSectionTo(PERSONAL_LEARNINGS_FILE, PERSONAL_LEARNINGS_HEADER, readPersonalLearnings(), content, 384);
|
|
9529
9779
|
}
|
|
9780
|
+
function addLearning(bullet, scope = "project") {
|
|
9781
|
+
const formatted = bullet.startsWith("- ") ? bullet : `- ${bullet}`;
|
|
9782
|
+
if (scope === "personal") {
|
|
9783
|
+
const result2 = writePersonalLearnedSection(formatted);
|
|
9784
|
+
return { file: PERSONAL_LEARNINGS_FILE, added: result2.newCount > 0 };
|
|
9785
|
+
}
|
|
9786
|
+
const result = writeLearnedSection(formatted);
|
|
9787
|
+
return { file: LEARNINGS_FILE, added: result.newCount > 0 };
|
|
9788
|
+
}
|
|
9530
9789
|
function readPersonalLearnings() {
|
|
9531
|
-
if (!
|
|
9532
|
-
const content =
|
|
9790
|
+
if (!fs35.existsSync(PERSONAL_LEARNINGS_FILE)) return null;
|
|
9791
|
+
const content = fs35.readFileSync(PERSONAL_LEARNINGS_FILE, "utf-8");
|
|
9533
9792
|
const bullets = content.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
9534
9793
|
return bullets || null;
|
|
9535
9794
|
}
|
|
9536
9795
|
function readLearnedSection() {
|
|
9537
|
-
if (
|
|
9538
|
-
const content2 =
|
|
9796
|
+
if (fs35.existsSync(LEARNINGS_FILE)) {
|
|
9797
|
+
const content2 = fs35.readFileSync(LEARNINGS_FILE, "utf-8");
|
|
9539
9798
|
const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
9540
9799
|
return bullets || null;
|
|
9541
9800
|
}
|
|
9542
9801
|
const claudeMdPath = "CLAUDE.md";
|
|
9543
|
-
if (!
|
|
9544
|
-
const content =
|
|
9802
|
+
if (!fs35.existsSync(claudeMdPath)) return null;
|
|
9803
|
+
const content = fs35.readFileSync(claudeMdPath, "utf-8");
|
|
9545
9804
|
const startIdx = content.indexOf(LEARNED_START);
|
|
9546
9805
|
const endIdx = content.indexOf(LEARNED_END);
|
|
9547
9806
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
9548
9807
|
return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
|
|
9549
9808
|
}
|
|
9550
9809
|
function migrateInlineLearnings() {
|
|
9551
|
-
if (
|
|
9810
|
+
if (fs35.existsSync(LEARNINGS_FILE)) return false;
|
|
9552
9811
|
const claudeMdPath = "CLAUDE.md";
|
|
9553
|
-
if (!
|
|
9554
|
-
const content =
|
|
9812
|
+
if (!fs35.existsSync(claudeMdPath)) return false;
|
|
9813
|
+
const content = fs35.readFileSync(claudeMdPath, "utf-8");
|
|
9555
9814
|
const startIdx = content.indexOf(LEARNED_START);
|
|
9556
9815
|
const endIdx = content.indexOf(LEARNED_END);
|
|
9557
9816
|
if (startIdx === -1 || endIdx === -1) return false;
|
|
9558
9817
|
const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
|
|
9559
9818
|
if (!section) return false;
|
|
9560
|
-
|
|
9819
|
+
fs35.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
|
|
9561
9820
|
const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
|
|
9562
|
-
|
|
9821
|
+
fs35.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
|
|
9563
9822
|
return true;
|
|
9564
9823
|
}
|
|
9565
9824
|
|
|
@@ -9571,11 +9830,11 @@ function log2(quiet, ...args) {
|
|
|
9571
9830
|
function discoverGitRepos(parentDir) {
|
|
9572
9831
|
const repos = [];
|
|
9573
9832
|
try {
|
|
9574
|
-
const entries =
|
|
9833
|
+
const entries = fs37.readdirSync(parentDir, { withFileTypes: true });
|
|
9575
9834
|
for (const entry of entries) {
|
|
9576
9835
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
9577
|
-
const childPath =
|
|
9578
|
-
if (
|
|
9836
|
+
const childPath = path29.join(parentDir, entry.name);
|
|
9837
|
+
if (fs37.existsSync(path29.join(childPath, ".git"))) {
|
|
9579
9838
|
repos.push(childPath);
|
|
9580
9839
|
}
|
|
9581
9840
|
}
|
|
@@ -9649,6 +9908,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
9649
9908
|
log2(quiet, chalk19.dim(`
|
|
9650
9909
|
${response.changesSummary}`));
|
|
9651
9910
|
}
|
|
9911
|
+
const builtinWritten = ensureBuiltinSkills();
|
|
9912
|
+
for (const file of builtinWritten) {
|
|
9913
|
+
log2(quiet, ` ${chalk19.green("\u2713")} ${file} ${chalk19.dim("(built-in)")}`);
|
|
9914
|
+
}
|
|
9652
9915
|
if (currentSha) {
|
|
9653
9916
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
9654
9917
|
}
|
|
@@ -9681,7 +9944,7 @@ async function refreshCommand(options) {
|
|
|
9681
9944
|
`));
|
|
9682
9945
|
const originalDir = process.cwd();
|
|
9683
9946
|
for (const repo of repos) {
|
|
9684
|
-
const repoName =
|
|
9947
|
+
const repoName = path29.basename(repo);
|
|
9685
9948
|
try {
|
|
9686
9949
|
process.chdir(repo);
|
|
9687
9950
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
@@ -9702,31 +9965,31 @@ async function refreshCommand(options) {
|
|
|
9702
9965
|
|
|
9703
9966
|
// src/commands/hooks.ts
|
|
9704
9967
|
import chalk20 from "chalk";
|
|
9705
|
-
import
|
|
9968
|
+
import fs39 from "fs";
|
|
9706
9969
|
|
|
9707
9970
|
// src/lib/hooks.ts
|
|
9708
9971
|
init_resolve_caliber();
|
|
9709
|
-
import
|
|
9710
|
-
import
|
|
9972
|
+
import fs38 from "fs";
|
|
9973
|
+
import path30 from "path";
|
|
9711
9974
|
import { execSync as execSync14 } from "child_process";
|
|
9712
|
-
var SETTINGS_PATH2 =
|
|
9975
|
+
var SETTINGS_PATH2 = path30.join(".claude", "settings.json");
|
|
9713
9976
|
var REFRESH_TAIL = "refresh --quiet";
|
|
9714
9977
|
var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
|
|
9715
9978
|
function getHookCommand() {
|
|
9716
9979
|
return `${resolveCaliber()} ${REFRESH_TAIL}`;
|
|
9717
9980
|
}
|
|
9718
9981
|
function readSettings2() {
|
|
9719
|
-
if (!
|
|
9982
|
+
if (!fs38.existsSync(SETTINGS_PATH2)) return {};
|
|
9720
9983
|
try {
|
|
9721
|
-
return JSON.parse(
|
|
9984
|
+
return JSON.parse(fs38.readFileSync(SETTINGS_PATH2, "utf-8"));
|
|
9722
9985
|
} catch {
|
|
9723
9986
|
return {};
|
|
9724
9987
|
}
|
|
9725
9988
|
}
|
|
9726
9989
|
function writeSettings2(settings) {
|
|
9727
|
-
const dir =
|
|
9728
|
-
if (!
|
|
9729
|
-
|
|
9990
|
+
const dir = path30.dirname(SETTINGS_PATH2);
|
|
9991
|
+
if (!fs38.existsSync(dir)) fs38.mkdirSync(dir, { recursive: true });
|
|
9992
|
+
fs38.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
|
|
9730
9993
|
}
|
|
9731
9994
|
function findHookIndex(sessionEnd) {
|
|
9732
9995
|
return sessionEnd.findIndex(
|
|
@@ -9789,19 +10052,19 @@ ${PRECOMMIT_END}`;
|
|
|
9789
10052
|
function getGitHooksDir() {
|
|
9790
10053
|
try {
|
|
9791
10054
|
const gitDir = execSync14("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
9792
|
-
return
|
|
10055
|
+
return path30.join(gitDir, "hooks");
|
|
9793
10056
|
} catch {
|
|
9794
10057
|
return null;
|
|
9795
10058
|
}
|
|
9796
10059
|
}
|
|
9797
10060
|
function getPreCommitPath() {
|
|
9798
10061
|
const hooksDir = getGitHooksDir();
|
|
9799
|
-
return hooksDir ?
|
|
10062
|
+
return hooksDir ? path30.join(hooksDir, "pre-commit") : null;
|
|
9800
10063
|
}
|
|
9801
10064
|
function isPreCommitHookInstalled() {
|
|
9802
10065
|
const hookPath = getPreCommitPath();
|
|
9803
|
-
if (!hookPath || !
|
|
9804
|
-
const content =
|
|
10066
|
+
if (!hookPath || !fs38.existsSync(hookPath)) return false;
|
|
10067
|
+
const content = fs38.readFileSync(hookPath, "utf-8");
|
|
9805
10068
|
return content.includes(PRECOMMIT_START);
|
|
9806
10069
|
}
|
|
9807
10070
|
function installPreCommitHook() {
|
|
@@ -9810,35 +10073,35 @@ function installPreCommitHook() {
|
|
|
9810
10073
|
}
|
|
9811
10074
|
const hookPath = getPreCommitPath();
|
|
9812
10075
|
if (!hookPath) return { installed: false, alreadyInstalled: false };
|
|
9813
|
-
const hooksDir =
|
|
9814
|
-
if (!
|
|
10076
|
+
const hooksDir = path30.dirname(hookPath);
|
|
10077
|
+
if (!fs38.existsSync(hooksDir)) fs38.mkdirSync(hooksDir, { recursive: true });
|
|
9815
10078
|
let content = "";
|
|
9816
|
-
if (
|
|
9817
|
-
content =
|
|
10079
|
+
if (fs38.existsSync(hookPath)) {
|
|
10080
|
+
content = fs38.readFileSync(hookPath, "utf-8");
|
|
9818
10081
|
if (!content.endsWith("\n")) content += "\n";
|
|
9819
10082
|
content += "\n" + getPrecommitBlock() + "\n";
|
|
9820
10083
|
} else {
|
|
9821
10084
|
content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
|
|
9822
10085
|
}
|
|
9823
|
-
|
|
9824
|
-
|
|
10086
|
+
fs38.writeFileSync(hookPath, content);
|
|
10087
|
+
fs38.chmodSync(hookPath, 493);
|
|
9825
10088
|
return { installed: true, alreadyInstalled: false };
|
|
9826
10089
|
}
|
|
9827
10090
|
function removePreCommitHook() {
|
|
9828
10091
|
const hookPath = getPreCommitPath();
|
|
9829
|
-
if (!hookPath || !
|
|
10092
|
+
if (!hookPath || !fs38.existsSync(hookPath)) {
|
|
9830
10093
|
return { removed: false, notFound: true };
|
|
9831
10094
|
}
|
|
9832
|
-
let content =
|
|
10095
|
+
let content = fs38.readFileSync(hookPath, "utf-8");
|
|
9833
10096
|
if (!content.includes(PRECOMMIT_START)) {
|
|
9834
10097
|
return { removed: false, notFound: true };
|
|
9835
10098
|
}
|
|
9836
10099
|
const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
|
|
9837
10100
|
content = content.replace(regex, "\n");
|
|
9838
10101
|
if (content.trim() === "#!/bin/sh" || content.trim() === "") {
|
|
9839
|
-
|
|
10102
|
+
fs38.unlinkSync(hookPath);
|
|
9840
10103
|
} else {
|
|
9841
|
-
|
|
10104
|
+
fs38.writeFileSync(hookPath, content);
|
|
9842
10105
|
}
|
|
9843
10106
|
return { removed: true, notFound: false };
|
|
9844
10107
|
}
|
|
@@ -9887,11 +10150,11 @@ async function hooksCommand(options) {
|
|
|
9887
10150
|
console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
|
|
9888
10151
|
}
|
|
9889
10152
|
}
|
|
9890
|
-
if (
|
|
10153
|
+
if (fs39.existsSync(".claude")) {
|
|
9891
10154
|
const r = installLearningHooks();
|
|
9892
10155
|
if (r.installed) console.log(chalk20.green(" \u2713") + " Claude Code learning hooks enabled");
|
|
9893
10156
|
}
|
|
9894
|
-
if (
|
|
10157
|
+
if (fs39.existsSync(".cursor")) {
|
|
9895
10158
|
const r = installCursorLearningHooks();
|
|
9896
10159
|
if (r.installed) console.log(chalk20.green(" \u2713") + " Cursor learning hooks enabled");
|
|
9897
10160
|
}
|
|
@@ -10059,8 +10322,8 @@ async function configCommand() {
|
|
|
10059
10322
|
}
|
|
10060
10323
|
|
|
10061
10324
|
// src/commands/learn.ts
|
|
10062
|
-
import
|
|
10063
|
-
import
|
|
10325
|
+
import fs43 from "fs";
|
|
10326
|
+
import path34 from "path";
|
|
10064
10327
|
import chalk23 from "chalk";
|
|
10065
10328
|
|
|
10066
10329
|
// src/learner/stdin.ts
|
|
@@ -10092,8 +10355,8 @@ function readStdin() {
|
|
|
10092
10355
|
|
|
10093
10356
|
// src/learner/storage.ts
|
|
10094
10357
|
init_constants();
|
|
10095
|
-
import
|
|
10096
|
-
import
|
|
10358
|
+
import fs40 from "fs";
|
|
10359
|
+
import path31 from "path";
|
|
10097
10360
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
10098
10361
|
var DEFAULT_STATE = {
|
|
10099
10362
|
sessionId: null,
|
|
@@ -10102,15 +10365,15 @@ var DEFAULT_STATE = {
|
|
|
10102
10365
|
lastAnalysisEventCount: 0
|
|
10103
10366
|
};
|
|
10104
10367
|
function ensureLearningDir() {
|
|
10105
|
-
if (!
|
|
10106
|
-
|
|
10368
|
+
if (!fs40.existsSync(LEARNING_DIR)) {
|
|
10369
|
+
fs40.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
10107
10370
|
}
|
|
10108
10371
|
}
|
|
10109
10372
|
function sessionFilePath() {
|
|
10110
|
-
return
|
|
10373
|
+
return path31.join(LEARNING_DIR, LEARNING_SESSION_FILE);
|
|
10111
10374
|
}
|
|
10112
10375
|
function stateFilePath() {
|
|
10113
|
-
return
|
|
10376
|
+
return path31.join(LEARNING_DIR, LEARNING_STATE_FILE);
|
|
10114
10377
|
}
|
|
10115
10378
|
function truncateResponse(response) {
|
|
10116
10379
|
const str = JSON.stringify(response);
|
|
@@ -10120,10 +10383,10 @@ function truncateResponse(response) {
|
|
|
10120
10383
|
function trimSessionFileIfNeeded(filePath) {
|
|
10121
10384
|
const state = readState2();
|
|
10122
10385
|
if (state.eventCount + 1 > LEARNING_MAX_EVENTS) {
|
|
10123
|
-
const lines =
|
|
10386
|
+
const lines = fs40.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
10124
10387
|
if (lines.length > LEARNING_MAX_EVENTS) {
|
|
10125
10388
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
10126
|
-
|
|
10389
|
+
fs40.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
10127
10390
|
}
|
|
10128
10391
|
}
|
|
10129
10392
|
}
|
|
@@ -10131,19 +10394,19 @@ function appendEvent(event) {
|
|
|
10131
10394
|
ensureLearningDir();
|
|
10132
10395
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
10133
10396
|
const filePath = sessionFilePath();
|
|
10134
|
-
|
|
10397
|
+
fs40.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
10135
10398
|
trimSessionFileIfNeeded(filePath);
|
|
10136
10399
|
}
|
|
10137
10400
|
function appendPromptEvent(event) {
|
|
10138
10401
|
ensureLearningDir();
|
|
10139
10402
|
const filePath = sessionFilePath();
|
|
10140
|
-
|
|
10403
|
+
fs40.appendFileSync(filePath, JSON.stringify(event) + "\n");
|
|
10141
10404
|
trimSessionFileIfNeeded(filePath);
|
|
10142
10405
|
}
|
|
10143
10406
|
function readAllEvents() {
|
|
10144
10407
|
const filePath = sessionFilePath();
|
|
10145
|
-
if (!
|
|
10146
|
-
const lines =
|
|
10408
|
+
if (!fs40.existsSync(filePath)) return [];
|
|
10409
|
+
const lines = fs40.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
10147
10410
|
const events = [];
|
|
10148
10411
|
for (const line of lines) {
|
|
10149
10412
|
try {
|
|
@@ -10155,26 +10418,26 @@ function readAllEvents() {
|
|
|
10155
10418
|
}
|
|
10156
10419
|
function getEventCount() {
|
|
10157
10420
|
const filePath = sessionFilePath();
|
|
10158
|
-
if (!
|
|
10159
|
-
const content =
|
|
10421
|
+
if (!fs40.existsSync(filePath)) return 0;
|
|
10422
|
+
const content = fs40.readFileSync(filePath, "utf-8");
|
|
10160
10423
|
return content.split("\n").filter(Boolean).length;
|
|
10161
10424
|
}
|
|
10162
10425
|
function clearSession() {
|
|
10163
10426
|
const filePath = sessionFilePath();
|
|
10164
|
-
if (
|
|
10427
|
+
if (fs40.existsSync(filePath)) fs40.unlinkSync(filePath);
|
|
10165
10428
|
}
|
|
10166
10429
|
function readState2() {
|
|
10167
10430
|
const filePath = stateFilePath();
|
|
10168
|
-
if (!
|
|
10431
|
+
if (!fs40.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
10169
10432
|
try {
|
|
10170
|
-
return JSON.parse(
|
|
10433
|
+
return JSON.parse(fs40.readFileSync(filePath, "utf-8"));
|
|
10171
10434
|
} catch {
|
|
10172
10435
|
return { ...DEFAULT_STATE };
|
|
10173
10436
|
}
|
|
10174
10437
|
}
|
|
10175
10438
|
function writeState2(state) {
|
|
10176
10439
|
ensureLearningDir();
|
|
10177
|
-
|
|
10440
|
+
fs40.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
10178
10441
|
}
|
|
10179
10442
|
function resetState() {
|
|
10180
10443
|
writeState2({ ...DEFAULT_STATE });
|
|
@@ -10182,16 +10445,16 @@ function resetState() {
|
|
|
10182
10445
|
var LOCK_FILE2 = "finalize.lock";
|
|
10183
10446
|
var LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
10184
10447
|
function lockFilePath() {
|
|
10185
|
-
return
|
|
10448
|
+
return path31.join(LEARNING_DIR, LOCK_FILE2);
|
|
10186
10449
|
}
|
|
10187
10450
|
function acquireFinalizeLock() {
|
|
10188
10451
|
ensureLearningDir();
|
|
10189
10452
|
const lockPath = lockFilePath();
|
|
10190
|
-
if (
|
|
10453
|
+
if (fs40.existsSync(lockPath)) {
|
|
10191
10454
|
try {
|
|
10192
|
-
const stat =
|
|
10455
|
+
const stat = fs40.statSync(lockPath);
|
|
10193
10456
|
if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
|
|
10194
|
-
const pid = parseInt(
|
|
10457
|
+
const pid = parseInt(fs40.readFileSync(lockPath, "utf-8").trim(), 10);
|
|
10195
10458
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
10196
10459
|
return false;
|
|
10197
10460
|
}
|
|
@@ -10199,12 +10462,12 @@ function acquireFinalizeLock() {
|
|
|
10199
10462
|
} catch {
|
|
10200
10463
|
}
|
|
10201
10464
|
try {
|
|
10202
|
-
|
|
10465
|
+
fs40.unlinkSync(lockPath);
|
|
10203
10466
|
} catch {
|
|
10204
10467
|
}
|
|
10205
10468
|
}
|
|
10206
10469
|
try {
|
|
10207
|
-
|
|
10470
|
+
fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
10208
10471
|
return true;
|
|
10209
10472
|
} catch {
|
|
10210
10473
|
return false;
|
|
@@ -10221,7 +10484,7 @@ function isProcessAlive(pid) {
|
|
|
10221
10484
|
function releaseFinalizeLock() {
|
|
10222
10485
|
const lockPath = lockFilePath();
|
|
10223
10486
|
try {
|
|
10224
|
-
if (
|
|
10487
|
+
if (fs40.existsSync(lockPath)) fs40.unlinkSync(lockPath);
|
|
10225
10488
|
} catch {
|
|
10226
10489
|
}
|
|
10227
10490
|
}
|
|
@@ -10267,22 +10530,22 @@ function sanitizeSecrets(text) {
|
|
|
10267
10530
|
|
|
10268
10531
|
// src/lib/notifications.ts
|
|
10269
10532
|
init_constants();
|
|
10270
|
-
import
|
|
10271
|
-
import
|
|
10533
|
+
import fs41 from "fs";
|
|
10534
|
+
import path32 from "path";
|
|
10272
10535
|
import chalk22 from "chalk";
|
|
10273
|
-
var NOTIFICATION_FILE =
|
|
10536
|
+
var NOTIFICATION_FILE = path32.join(LEARNING_DIR, "last-finalize-summary.json");
|
|
10274
10537
|
function writeFinalizeSummary(summary) {
|
|
10275
10538
|
try {
|
|
10276
10539
|
ensureLearningDir();
|
|
10277
|
-
|
|
10540
|
+
fs41.writeFileSync(NOTIFICATION_FILE, JSON.stringify(summary, null, 2));
|
|
10278
10541
|
} catch {
|
|
10279
10542
|
}
|
|
10280
10543
|
}
|
|
10281
10544
|
function checkPendingNotifications() {
|
|
10282
10545
|
try {
|
|
10283
|
-
if (!
|
|
10284
|
-
const raw =
|
|
10285
|
-
|
|
10546
|
+
if (!fs41.existsSync(NOTIFICATION_FILE)) return;
|
|
10547
|
+
const raw = fs41.readFileSync(NOTIFICATION_FILE, "utf-8");
|
|
10548
|
+
fs41.unlinkSync(NOTIFICATION_FILE);
|
|
10286
10549
|
const summary = JSON.parse(raw);
|
|
10287
10550
|
if (!summary.newItemCount || summary.newItemCount === 0) return;
|
|
10288
10551
|
const wasteLabel = summary.wasteTokens > 0 ? ` (~${summary.wasteTokens.toLocaleString()} wasted tokens captured)` : "";
|
|
@@ -10298,7 +10561,7 @@ function checkPendingNotifications() {
|
|
|
10298
10561
|
console.log("");
|
|
10299
10562
|
} catch {
|
|
10300
10563
|
try {
|
|
10301
|
-
|
|
10564
|
+
fs41.unlinkSync(NOTIFICATION_FILE);
|
|
10302
10565
|
} catch {
|
|
10303
10566
|
}
|
|
10304
10567
|
}
|
|
@@ -10436,8 +10699,8 @@ init_config();
|
|
|
10436
10699
|
|
|
10437
10700
|
// src/learner/roi.ts
|
|
10438
10701
|
init_constants();
|
|
10439
|
-
import
|
|
10440
|
-
import
|
|
10702
|
+
import fs42 from "fs";
|
|
10703
|
+
import path33 from "path";
|
|
10441
10704
|
var DEFAULT_TOTALS = {
|
|
10442
10705
|
totalWasteTokens: 0,
|
|
10443
10706
|
totalWasteSeconds: 0,
|
|
@@ -10451,19 +10714,19 @@ var DEFAULT_TOTALS = {
|
|
|
10451
10714
|
lastSessionTimestamp: ""
|
|
10452
10715
|
};
|
|
10453
10716
|
function roiFilePath() {
|
|
10454
|
-
return
|
|
10717
|
+
return path33.join(LEARNING_DIR, LEARNING_ROI_FILE);
|
|
10455
10718
|
}
|
|
10456
10719
|
function readROIStats() {
|
|
10457
10720
|
const filePath = roiFilePath();
|
|
10458
|
-
if (!
|
|
10721
|
+
if (!fs42.existsSync(filePath)) {
|
|
10459
10722
|
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
10460
10723
|
}
|
|
10461
10724
|
try {
|
|
10462
|
-
return JSON.parse(
|
|
10725
|
+
return JSON.parse(fs42.readFileSync(filePath, "utf-8"));
|
|
10463
10726
|
} catch {
|
|
10464
10727
|
try {
|
|
10465
10728
|
const corruptPath = filePath + ".corrupt";
|
|
10466
|
-
|
|
10729
|
+
fs42.renameSync(filePath, corruptPath);
|
|
10467
10730
|
console.error(`caliber: roi-stats.json was corrupt \u2014 renamed to ${corruptPath}`);
|
|
10468
10731
|
} catch {
|
|
10469
10732
|
}
|
|
@@ -10472,7 +10735,7 @@ function readROIStats() {
|
|
|
10472
10735
|
}
|
|
10473
10736
|
function writeROIStats(stats) {
|
|
10474
10737
|
ensureLearningDir();
|
|
10475
|
-
|
|
10738
|
+
fs42.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
|
|
10476
10739
|
}
|
|
10477
10740
|
function recalculateTotals(stats) {
|
|
10478
10741
|
const totals = stats.totals;
|
|
@@ -10679,9 +10942,9 @@ var AUTO_SETTLE_MS = 200;
|
|
|
10679
10942
|
var INCREMENTAL_INTERVAL = 50;
|
|
10680
10943
|
function writeFinalizeError(message) {
|
|
10681
10944
|
try {
|
|
10682
|
-
const errorPath =
|
|
10683
|
-
if (!
|
|
10684
|
-
|
|
10945
|
+
const errorPath = path34.join(LEARNING_DIR, LEARNING_LAST_ERROR_FILE);
|
|
10946
|
+
if (!fs43.existsSync(LEARNING_DIR)) fs43.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
10947
|
+
fs43.writeFileSync(errorPath, JSON.stringify({
|
|
10685
10948
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10686
10949
|
error: message,
|
|
10687
10950
|
pid: process.pid
|
|
@@ -10691,9 +10954,9 @@ function writeFinalizeError(message) {
|
|
|
10691
10954
|
}
|
|
10692
10955
|
function readFinalizeError() {
|
|
10693
10956
|
try {
|
|
10694
|
-
const errorPath =
|
|
10695
|
-
if (!
|
|
10696
|
-
return JSON.parse(
|
|
10957
|
+
const errorPath = path34.join(LEARNING_DIR, LEARNING_LAST_ERROR_FILE);
|
|
10958
|
+
if (!fs43.existsSync(errorPath)) return null;
|
|
10959
|
+
return JSON.parse(fs43.readFileSync(errorPath, "utf-8"));
|
|
10697
10960
|
} catch {
|
|
10698
10961
|
return null;
|
|
10699
10962
|
}
|
|
@@ -10740,14 +11003,14 @@ async function learnObserveCommand(options) {
|
|
|
10740
11003
|
const { resolveCaliber: resolveCaliber2 } = await Promise.resolve().then(() => (init_resolve_caliber(), resolve_caliber_exports));
|
|
10741
11004
|
const bin = resolveCaliber2();
|
|
10742
11005
|
const { spawn: spawn4 } = await import("child_process");
|
|
10743
|
-
const logPath =
|
|
10744
|
-
if (!
|
|
10745
|
-
const logFd =
|
|
11006
|
+
const logPath = path34.join(LEARNING_DIR, LEARNING_FINALIZE_LOG);
|
|
11007
|
+
if (!fs43.existsSync(LEARNING_DIR)) fs43.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
11008
|
+
const logFd = fs43.openSync(logPath, "a");
|
|
10746
11009
|
spawn4(bin, ["learn", "finalize", "--auto", "--incremental"], {
|
|
10747
11010
|
detached: true,
|
|
10748
11011
|
stdio: ["ignore", logFd, logFd]
|
|
10749
11012
|
}).unref();
|
|
10750
|
-
|
|
11013
|
+
fs43.closeSync(logFd);
|
|
10751
11014
|
} catch {
|
|
10752
11015
|
}
|
|
10753
11016
|
}
|
|
@@ -10954,7 +11217,7 @@ async function learnFinalizeCommand(options) {
|
|
|
10954
11217
|
}
|
|
10955
11218
|
async function learnInstallCommand() {
|
|
10956
11219
|
let anyInstalled = false;
|
|
10957
|
-
if (
|
|
11220
|
+
if (fs43.existsSync(".claude")) {
|
|
10958
11221
|
const r = installLearningHooks();
|
|
10959
11222
|
if (r.installed) {
|
|
10960
11223
|
console.log(chalk23.green("\u2713") + " Claude Code learning hooks installed");
|
|
@@ -10963,7 +11226,7 @@ async function learnInstallCommand() {
|
|
|
10963
11226
|
console.log(chalk23.dim(" Claude Code hooks already installed"));
|
|
10964
11227
|
}
|
|
10965
11228
|
}
|
|
10966
|
-
if (
|
|
11229
|
+
if (fs43.existsSync(".cursor")) {
|
|
10967
11230
|
const r = installCursorLearningHooks();
|
|
10968
11231
|
if (r.installed) {
|
|
10969
11232
|
console.log(chalk23.green("\u2713") + " Cursor learning hooks installed");
|
|
@@ -10972,7 +11235,7 @@ async function learnInstallCommand() {
|
|
|
10972
11235
|
console.log(chalk23.dim(" Cursor hooks already installed"));
|
|
10973
11236
|
}
|
|
10974
11237
|
}
|
|
10975
|
-
if (!
|
|
11238
|
+
if (!fs43.existsSync(".claude") && !fs43.existsSync(".cursor")) {
|
|
10976
11239
|
console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
|
|
10977
11240
|
console.log(chalk23.dim(" Run `caliber init` first, or create the directory manually."));
|
|
10978
11241
|
return;
|
|
@@ -11030,8 +11293,8 @@ async function learnStatusCommand() {
|
|
|
11030
11293
|
if (lastError) {
|
|
11031
11294
|
console.log(`Last error: ${chalk23.red(lastError.error)}`);
|
|
11032
11295
|
console.log(chalk23.dim(` at ${lastError.timestamp}`));
|
|
11033
|
-
const logPath =
|
|
11034
|
-
if (
|
|
11296
|
+
const logPath = path34.join(LEARNING_DIR, LEARNING_FINALIZE_LOG);
|
|
11297
|
+
if (fs43.existsSync(logPath)) {
|
|
11035
11298
|
console.log(chalk23.dim(` Full log: ${logPath}`));
|
|
11036
11299
|
}
|
|
11037
11300
|
}
|
|
@@ -11111,11 +11374,11 @@ async function learnDeleteCommand(indexStr) {
|
|
|
11111
11374
|
}
|
|
11112
11375
|
const item = items[targetIdx];
|
|
11113
11376
|
const filePath = item.source === "personal" ? PERSONAL_LEARNINGS_FILE : "CALIBER_LEARNINGS.md";
|
|
11114
|
-
if (!
|
|
11377
|
+
if (!fs43.existsSync(filePath)) {
|
|
11115
11378
|
console.log(chalk23.red("Learnings file not found."));
|
|
11116
11379
|
return;
|
|
11117
11380
|
}
|
|
11118
|
-
const content =
|
|
11381
|
+
const content = fs43.readFileSync(filePath, "utf-8");
|
|
11119
11382
|
const lines = content.split("\n");
|
|
11120
11383
|
const bulletsOfSource = items.filter((i) => i.source === item.source);
|
|
11121
11384
|
const posInFile = bulletsOfSource.indexOf(item);
|
|
@@ -11136,9 +11399,9 @@ async function learnDeleteCommand(indexStr) {
|
|
|
11136
11399
|
}
|
|
11137
11400
|
const bulletToRemove = lines[lineToRemove];
|
|
11138
11401
|
const newLines = lines.filter((_, i) => i !== lineToRemove);
|
|
11139
|
-
|
|
11402
|
+
fs43.writeFileSync(filePath, newLines.join("\n"));
|
|
11140
11403
|
if (item.source === "personal") {
|
|
11141
|
-
|
|
11404
|
+
fs43.chmodSync(filePath, 384);
|
|
11142
11405
|
}
|
|
11143
11406
|
const roiStats = readROIStats();
|
|
11144
11407
|
const cleanText = bulletToRemove.replace(/^- /, "").replace(/^\*\*\[[^\]]+\]\*\*\s*/, "").trim();
|
|
@@ -11149,6 +11412,19 @@ async function learnDeleteCommand(indexStr) {
|
|
|
11149
11412
|
}
|
|
11150
11413
|
console.log(chalk23.green("\u2713") + ` Removed: ${bulletToRemove.replace(/^- /, "").slice(0, 80)}`);
|
|
11151
11414
|
}
|
|
11415
|
+
async function learnAddCommand(content, options) {
|
|
11416
|
+
if (!content.trim()) {
|
|
11417
|
+
console.log(chalk23.yellow("Please provide learning content."));
|
|
11418
|
+
throw new Error("__exit__");
|
|
11419
|
+
}
|
|
11420
|
+
const scope = options.personal ? "personal" : "project";
|
|
11421
|
+
const result = addLearning(content.trim(), scope);
|
|
11422
|
+
if (result.added) {
|
|
11423
|
+
console.log(chalk23.green("\u2713") + ` Learning saved to ${result.file}`);
|
|
11424
|
+
} else {
|
|
11425
|
+
console.log(chalk23.dim(" Similar learning already exists \u2014 skipped."));
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11152
11428
|
|
|
11153
11429
|
// src/commands/insights.ts
|
|
11154
11430
|
import chalk24 from "chalk";
|
|
@@ -11285,8 +11561,8 @@ async function insightsCommand(options) {
|
|
|
11285
11561
|
}
|
|
11286
11562
|
|
|
11287
11563
|
// src/commands/sources.ts
|
|
11288
|
-
import
|
|
11289
|
-
import
|
|
11564
|
+
import fs44 from "fs";
|
|
11565
|
+
import path35 from "path";
|
|
11290
11566
|
import chalk25 from "chalk";
|
|
11291
11567
|
async function sourcesListCommand() {
|
|
11292
11568
|
const dir = process.cwd();
|
|
@@ -11302,9 +11578,9 @@ async function sourcesListCommand() {
|
|
|
11302
11578
|
if (configSources.length > 0) {
|
|
11303
11579
|
for (const source of configSources) {
|
|
11304
11580
|
const sourcePath = source.path || source.url || "";
|
|
11305
|
-
const exists = source.path ?
|
|
11581
|
+
const exists = source.path ? fs44.existsSync(path35.resolve(dir, source.path)) : false;
|
|
11306
11582
|
const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
|
|
11307
|
-
const hasSummary = source.path &&
|
|
11583
|
+
const hasSummary = source.path && fs44.existsSync(path35.join(path35.resolve(dir, source.path), ".caliber", "summary.json"));
|
|
11308
11584
|
console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
|
|
11309
11585
|
console.log(` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`);
|
|
11310
11586
|
if (source.description) console.log(` ${chalk25.dim(source.description)}`);
|
|
@@ -11314,7 +11590,7 @@ async function sourcesListCommand() {
|
|
|
11314
11590
|
if (workspaces.length > 0) {
|
|
11315
11591
|
console.log(chalk25.dim(" Auto-detected workspaces:"));
|
|
11316
11592
|
for (const ws of workspaces) {
|
|
11317
|
-
const exists =
|
|
11593
|
+
const exists = fs44.existsSync(path35.resolve(dir, ws));
|
|
11318
11594
|
console.log(` ${exists ? chalk25.green("\u25CF") : chalk25.red("\u25CF")} ${ws}`);
|
|
11319
11595
|
}
|
|
11320
11596
|
console.log("");
|
|
@@ -11322,8 +11598,8 @@ async function sourcesListCommand() {
|
|
|
11322
11598
|
}
|
|
11323
11599
|
async function sourcesAddCommand(sourcePath) {
|
|
11324
11600
|
const dir = process.cwd();
|
|
11325
|
-
const absPath =
|
|
11326
|
-
if (!
|
|
11601
|
+
const absPath = path35.resolve(dir, sourcePath);
|
|
11602
|
+
if (!fs44.existsSync(absPath)) {
|
|
11327
11603
|
console.log(chalk25.red(`
|
|
11328
11604
|
Path not found: ${sourcePath}
|
|
11329
11605
|
`));
|
|
@@ -11338,7 +11614,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
11338
11614
|
}
|
|
11339
11615
|
const existing = loadSourcesConfig(dir);
|
|
11340
11616
|
const alreadyConfigured = existing.some(
|
|
11341
|
-
(s) => s.path &&
|
|
11617
|
+
(s) => s.path && path35.resolve(dir, s.path) === absPath
|
|
11342
11618
|
);
|
|
11343
11619
|
if (alreadyConfigured) {
|
|
11344
11620
|
console.log(chalk25.yellow(`
|
|
@@ -11386,8 +11662,8 @@ async function sourcesRemoveCommand(name) {
|
|
|
11386
11662
|
}
|
|
11387
11663
|
|
|
11388
11664
|
// src/commands/publish.ts
|
|
11389
|
-
import
|
|
11390
|
-
import
|
|
11665
|
+
import fs45 from "fs";
|
|
11666
|
+
import path36 from "path";
|
|
11391
11667
|
import chalk26 from "chalk";
|
|
11392
11668
|
import ora7 from "ora";
|
|
11393
11669
|
init_config();
|
|
@@ -11401,10 +11677,10 @@ async function publishCommand() {
|
|
|
11401
11677
|
const spinner = ora7("Generating project summary...").start();
|
|
11402
11678
|
try {
|
|
11403
11679
|
const fingerprint = await collectFingerprint(dir);
|
|
11404
|
-
const claudeMd = readFileOrNull(
|
|
11680
|
+
const claudeMd = readFileOrNull(path36.join(dir, "CLAUDE.md"));
|
|
11405
11681
|
const topLevelDirs = fingerprint.fileTree.filter((f) => f.endsWith("/") && !f.includes("/")).map((f) => f.replace(/\/$/, ""));
|
|
11406
11682
|
const summary = {
|
|
11407
|
-
name: fingerprint.packageName ||
|
|
11683
|
+
name: fingerprint.packageName || path36.basename(dir),
|
|
11408
11684
|
version: "1.0.0",
|
|
11409
11685
|
description: fingerprint.description || "",
|
|
11410
11686
|
languages: fingerprint.languages,
|
|
@@ -11416,7 +11692,7 @@ async function publishCommand() {
|
|
|
11416
11692
|
summary.conventions = claudeMd.slice(0, 2e3);
|
|
11417
11693
|
}
|
|
11418
11694
|
try {
|
|
11419
|
-
const pkgContent = readFileOrNull(
|
|
11695
|
+
const pkgContent = readFileOrNull(path36.join(dir, "package.json"));
|
|
11420
11696
|
if (pkgContent) {
|
|
11421
11697
|
const pkg3 = JSON.parse(pkgContent);
|
|
11422
11698
|
if (pkg3.scripts) {
|
|
@@ -11429,14 +11705,14 @@ async function publishCommand() {
|
|
|
11429
11705
|
}
|
|
11430
11706
|
} catch {
|
|
11431
11707
|
}
|
|
11432
|
-
const outputDir =
|
|
11433
|
-
if (!
|
|
11434
|
-
|
|
11708
|
+
const outputDir = path36.join(dir, ".caliber");
|
|
11709
|
+
if (!fs45.existsSync(outputDir)) {
|
|
11710
|
+
fs45.mkdirSync(outputDir, { recursive: true });
|
|
11435
11711
|
}
|
|
11436
|
-
const outputPath =
|
|
11437
|
-
|
|
11712
|
+
const outputPath = path36.join(outputDir, "summary.json");
|
|
11713
|
+
fs45.writeFileSync(outputPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
|
|
11438
11714
|
spinner.succeed("Project summary published");
|
|
11439
|
-
console.log(` ${chalk26.green("\u2713")} ${
|
|
11715
|
+
console.log(` ${chalk26.green("\u2713")} ${path36.relative(dir, outputPath)}`);
|
|
11440
11716
|
console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
|
|
11441
11717
|
console.log(chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n"));
|
|
11442
11718
|
} catch (err) {
|
|
@@ -11448,9 +11724,9 @@ async function publishCommand() {
|
|
|
11448
11724
|
}
|
|
11449
11725
|
|
|
11450
11726
|
// src/cli.ts
|
|
11451
|
-
var __dirname =
|
|
11727
|
+
var __dirname = path37.dirname(fileURLToPath(import.meta.url));
|
|
11452
11728
|
var pkg = JSON.parse(
|
|
11453
|
-
|
|
11729
|
+
fs46.readFileSync(path37.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
11454
11730
|
);
|
|
11455
11731
|
var program = new Command();
|
|
11456
11732
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
@@ -11516,7 +11792,7 @@ program.command("undo").description("Revert all config changes made by Caliber")
|
|
|
11516
11792
|
program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(tracked("status", statusCommand));
|
|
11517
11793
|
program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
|
|
11518
11794
|
program.command("config").description("Configure LLM provider, API key, and model").action(tracked("config", configCommand));
|
|
11519
|
-
program.command("skills").description("Discover and install community skills for your project").action(tracked("skills", recommendCommand));
|
|
11795
|
+
program.command("skills").description("Discover and install community skills for your project").option("--query <terms>", 'Search for skills by topic (e.g. "react frontend")').option("--install <slugs>", "Install specific skills by slug (comma-separated)").action(tracked("skills", recommendCommand));
|
|
11520
11796
|
program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex, github-copilot", parseAgentOption).option("--compare <ref>", "Compare score against a git ref (branch, tag, or SHA)").action(tracked("score", scoreCommand));
|
|
11521
11797
|
program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(tracked("refresh", refreshCommand));
|
|
11522
11798
|
program.command("hooks").description("Manage auto-refresh hooks (toggle interactively)").option("--install", "Enable all hooks non-interactively").option("--remove", "Disable all hooks non-interactively").action(tracked("hooks", hooksCommand));
|
|
@@ -11534,18 +11810,19 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
|
|
|
11534
11810
|
learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
|
|
11535
11811
|
learn.command("list").description("List all learnings with their source and activation data").option("--verbose", "Show explanations and activation counts").action(tracked("learn:list", (opts) => learnListCommand(opts)));
|
|
11536
11812
|
learn.command("delete <index>").description("Delete a learning by its index number (from `caliber learn list`)").action(tracked("learn:delete", (index) => learnDeleteCommand(index)));
|
|
11813
|
+
learn.command("add <content>").description("Add a learning directly (used by agent skills)").option("--personal", "Save as a personal learning instead of project-level").action(tracked("learn:add", learnAddCommand));
|
|
11537
11814
|
|
|
11538
11815
|
// src/utils/version-check.ts
|
|
11539
|
-
import
|
|
11540
|
-
import
|
|
11816
|
+
import fs47 from "fs";
|
|
11817
|
+
import path38 from "path";
|
|
11541
11818
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11542
11819
|
import { execSync as execSync15 } from "child_process";
|
|
11543
11820
|
import chalk27 from "chalk";
|
|
11544
11821
|
import ora8 from "ora";
|
|
11545
11822
|
import confirm2 from "@inquirer/confirm";
|
|
11546
|
-
var __dirname_vc =
|
|
11823
|
+
var __dirname_vc = path38.dirname(fileURLToPath2(import.meta.url));
|
|
11547
11824
|
var pkg2 = JSON.parse(
|
|
11548
|
-
|
|
11825
|
+
fs47.readFileSync(path38.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
11549
11826
|
);
|
|
11550
11827
|
function getChannel(version) {
|
|
11551
11828
|
const match = version.match(/-(dev|next)\./);
|
|
@@ -11570,8 +11847,8 @@ function isNewer(registry, current) {
|
|
|
11570
11847
|
function getInstalledVersion() {
|
|
11571
11848
|
try {
|
|
11572
11849
|
const globalRoot = execSync15("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
11573
|
-
const pkgPath =
|
|
11574
|
-
return JSON.parse(
|
|
11850
|
+
const pkgPath = path38.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
11851
|
+
return JSON.parse(fs47.readFileSync(pkgPath, "utf-8")).version;
|
|
11575
11852
|
} catch {
|
|
11576
11853
|
return null;
|
|
11577
11854
|
}
|