@rely-ai/caliber 1.20.0-dev.1773685589 → 1.20.0-dev.1773686430
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 +857 -601
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -177,13 +177,13 @@ __export(lock_exports, {
|
|
|
177
177
|
isCaliberRunning: () => isCaliberRunning,
|
|
178
178
|
releaseLock: () => releaseLock
|
|
179
179
|
});
|
|
180
|
-
import
|
|
181
|
-
import
|
|
182
|
-
import
|
|
180
|
+
import fs29 from "fs";
|
|
181
|
+
import path23 from "path";
|
|
182
|
+
import os5 from "os";
|
|
183
183
|
function isCaliberRunning() {
|
|
184
184
|
try {
|
|
185
|
-
if (!
|
|
186
|
-
const raw =
|
|
185
|
+
if (!fs29.existsSync(LOCK_FILE)) return false;
|
|
186
|
+
const raw = fs29.readFileSync(LOCK_FILE, "utf-8").trim();
|
|
187
187
|
const { pid, ts } = JSON.parse(raw);
|
|
188
188
|
if (Date.now() - ts > STALE_MS) return false;
|
|
189
189
|
try {
|
|
@@ -198,13 +198,13 @@ function isCaliberRunning() {
|
|
|
198
198
|
}
|
|
199
199
|
function acquireLock() {
|
|
200
200
|
try {
|
|
201
|
-
|
|
201
|
+
fs29.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
|
|
202
202
|
} catch {
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
function releaseLock() {
|
|
206
206
|
try {
|
|
207
|
-
if (
|
|
207
|
+
if (fs29.existsSync(LOCK_FILE)) fs29.unlinkSync(LOCK_FILE);
|
|
208
208
|
} catch {
|
|
209
209
|
}
|
|
210
210
|
}
|
|
@@ -212,24 +212,24 @@ var LOCK_FILE, STALE_MS;
|
|
|
212
212
|
var init_lock = __esm({
|
|
213
213
|
"src/lib/lock.ts"() {
|
|
214
214
|
"use strict";
|
|
215
|
-
LOCK_FILE =
|
|
215
|
+
LOCK_FILE = path23.join(os5.tmpdir(), ".caliber.lock");
|
|
216
216
|
STALE_MS = 10 * 60 * 1e3;
|
|
217
217
|
}
|
|
218
218
|
});
|
|
219
219
|
|
|
220
220
|
// src/cli.ts
|
|
221
221
|
import { Command } from "commander";
|
|
222
|
-
import
|
|
223
|
-
import
|
|
222
|
+
import fs33 from "fs";
|
|
223
|
+
import path26 from "path";
|
|
224
224
|
import { fileURLToPath } from "url";
|
|
225
225
|
|
|
226
226
|
// src/commands/init.ts
|
|
227
|
-
import
|
|
228
|
-
import
|
|
227
|
+
import path20 from "path";
|
|
228
|
+
import chalk10 from "chalk";
|
|
229
229
|
import ora2 from "ora";
|
|
230
230
|
import select5 from "@inquirer/select";
|
|
231
231
|
import checkbox from "@inquirer/checkbox";
|
|
232
|
-
import
|
|
232
|
+
import fs25 from "fs";
|
|
233
233
|
|
|
234
234
|
// src/fingerprint/index.ts
|
|
235
235
|
import fs6 from "fs";
|
|
@@ -2262,15 +2262,15 @@ init_config();
|
|
|
2262
2262
|
// src/utils/dependencies.ts
|
|
2263
2263
|
import { readFileSync } from "fs";
|
|
2264
2264
|
import { join } from "path";
|
|
2265
|
-
function readFileOrNull(
|
|
2265
|
+
function readFileOrNull(path28) {
|
|
2266
2266
|
try {
|
|
2267
|
-
return readFileSync(
|
|
2267
|
+
return readFileSync(path28, "utf-8");
|
|
2268
2268
|
} catch {
|
|
2269
2269
|
return null;
|
|
2270
2270
|
}
|
|
2271
2271
|
}
|
|
2272
|
-
function readJsonOrNull(
|
|
2273
|
-
const content = readFileOrNull(
|
|
2272
|
+
function readJsonOrNull(path28) {
|
|
2273
|
+
const content = readFileOrNull(path28);
|
|
2274
2274
|
if (!content) return null;
|
|
2275
2275
|
try {
|
|
2276
2276
|
return JSON.parse(content);
|
|
@@ -2686,6 +2686,37 @@ async function generateMonolithic(fingerprint, targetAgent, prompt, callbacks, f
|
|
|
2686
2686
|
};
|
|
2687
2687
|
return attemptGeneration();
|
|
2688
2688
|
}
|
|
2689
|
+
async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus) {
|
|
2690
|
+
const skillTopics = collectSkillTopics(setup, targetAgent, fingerprint);
|
|
2691
|
+
if (skillTopics.length === 0) return 0;
|
|
2692
|
+
onStatus?.(`Generating ${skillTopics.length} skills...`);
|
|
2693
|
+
const allDeps = extractAllDeps(process.cwd());
|
|
2694
|
+
const skillContext = buildSkillContext(fingerprint, setup, allDeps);
|
|
2695
|
+
const fastModel = getFastModel();
|
|
2696
|
+
const skillResults = await Promise.allSettled(
|
|
2697
|
+
skillTopics.map(
|
|
2698
|
+
({ platform, topic }) => generateSkill(skillContext, topic, fastModel).then((skill) => ({ platform, skill }))
|
|
2699
|
+
)
|
|
2700
|
+
);
|
|
2701
|
+
for (const result of skillResults) {
|
|
2702
|
+
if (result.status === "fulfilled") {
|
|
2703
|
+
const { platform, skill } = result.value;
|
|
2704
|
+
const platformObj = setup[platform] ?? {};
|
|
2705
|
+
const skills = platformObj.skills ?? [];
|
|
2706
|
+
skills.push(skill);
|
|
2707
|
+
platformObj.skills = skills;
|
|
2708
|
+
setup[platform] = platformObj;
|
|
2709
|
+
const skillPath = platform === "codex" ? `.agents/skills/${skill.name}/SKILL.md` : `.${platform}/skills/${skill.name}/SKILL.md`;
|
|
2710
|
+
const descriptions = setup.fileDescriptions ?? {};
|
|
2711
|
+
descriptions[skillPath] = skill.description.slice(0, 80);
|
|
2712
|
+
setup.fileDescriptions = descriptions;
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
const succeeded = skillResults.filter((r) => r.status === "fulfilled").length;
|
|
2716
|
+
const failed = skillResults.filter((r) => r.status === "rejected").length;
|
|
2717
|
+
if (failed > 0) onStatus?.(`${succeeded} generated, ${failed} failed`);
|
|
2718
|
+
return succeeded;
|
|
2719
|
+
}
|
|
2689
2720
|
var LIMITS = {
|
|
2690
2721
|
FILE_TREE_ENTRIES: 500,
|
|
2691
2722
|
EXISTING_CONFIG_CHARS: 8e3,
|
|
@@ -3205,13 +3236,23 @@ function cleanupStaging() {
|
|
|
3205
3236
|
|
|
3206
3237
|
// src/utils/review.ts
|
|
3207
3238
|
import chalk2 from "chalk";
|
|
3208
|
-
import
|
|
3239
|
+
import fs15 from "fs";
|
|
3209
3240
|
import select2 from "@inquirer/select";
|
|
3210
3241
|
import { createTwoFilesPatch } from "diff";
|
|
3211
3242
|
|
|
3212
3243
|
// src/utils/editor.ts
|
|
3213
3244
|
import { execSync as execSync5, spawn as spawn3 } from "child_process";
|
|
3245
|
+
import fs14 from "fs";
|
|
3246
|
+
import path12 from "path";
|
|
3247
|
+
import os3 from "os";
|
|
3214
3248
|
var IS_WINDOWS3 = process.platform === "win32";
|
|
3249
|
+
var DIFF_TEMP_DIR = path12.join(os3.tmpdir(), "caliber-diff");
|
|
3250
|
+
function getEmptyFilePath(proposedPath) {
|
|
3251
|
+
fs14.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
|
|
3252
|
+
const tempPath = path12.join(DIFF_TEMP_DIR, path12.basename(proposedPath));
|
|
3253
|
+
fs14.writeFileSync(tempPath, "");
|
|
3254
|
+
return tempPath;
|
|
3255
|
+
}
|
|
3215
3256
|
function commandExists(cmd) {
|
|
3216
3257
|
try {
|
|
3217
3258
|
const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
@@ -3232,13 +3273,12 @@ function openDiffsInEditor(editor, files) {
|
|
|
3232
3273
|
const cmd = editor === "cursor" ? "cursor" : "code";
|
|
3233
3274
|
for (const file of files) {
|
|
3234
3275
|
try {
|
|
3276
|
+
const leftPath = file.originalPath ?? getEmptyFilePath(file.proposedPath);
|
|
3235
3277
|
if (IS_WINDOWS3) {
|
|
3236
3278
|
const quote = (s) => `"${s}"`;
|
|
3237
|
-
|
|
3238
|
-
spawn3(parts.join(" "), { shell: true, stdio: "ignore", detached: true }).unref();
|
|
3279
|
+
spawn3([cmd, "--diff", quote(leftPath), quote(file.proposedPath)].join(" "), { shell: true, stdio: "ignore", detached: true }).unref();
|
|
3239
3280
|
} else {
|
|
3240
|
-
|
|
3241
|
-
spawn3(cmd, args, { stdio: "ignore", detached: true }).unref();
|
|
3281
|
+
spawn3(cmd, ["--diff", leftPath, file.proposedPath], { stdio: "ignore", detached: true }).unref();
|
|
3242
3282
|
}
|
|
3243
3283
|
} catch {
|
|
3244
3284
|
continue;
|
|
@@ -3281,8 +3321,8 @@ async function openReview(method, stagedFiles) {
|
|
|
3281
3321
|
return;
|
|
3282
3322
|
}
|
|
3283
3323
|
const fileInfos = stagedFiles.map((file) => {
|
|
3284
|
-
const proposed =
|
|
3285
|
-
const current = file.currentPath ?
|
|
3324
|
+
const proposed = fs15.readFileSync(file.proposedPath, "utf-8");
|
|
3325
|
+
const current = file.currentPath ? fs15.readFileSync(file.currentPath, "utf-8") : "";
|
|
3286
3326
|
const patch = createTwoFilesPatch(
|
|
3287
3327
|
file.isNew ? "/dev/null" : file.relativePath,
|
|
3288
3328
|
file.relativePath,
|
|
@@ -3445,7 +3485,7 @@ async function interactiveDiffExplorer(files) {
|
|
|
3445
3485
|
}
|
|
3446
3486
|
|
|
3447
3487
|
// src/commands/setup-files.ts
|
|
3448
|
-
import
|
|
3488
|
+
import fs16 from "fs";
|
|
3449
3489
|
function buildSkillContent(skill) {
|
|
3450
3490
|
const frontmatter = `---
|
|
3451
3491
|
name: ${skill.name}
|
|
@@ -3494,7 +3534,7 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
3494
3534
|
}
|
|
3495
3535
|
}
|
|
3496
3536
|
const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
|
|
3497
|
-
if (codexTargeted && !
|
|
3537
|
+
if (codexTargeted && !fs16.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
|
|
3498
3538
|
const agentRefs = [];
|
|
3499
3539
|
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
3500
3540
|
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
@@ -3511,12 +3551,12 @@ ${agentRefs.join(" ")}
|
|
|
3511
3551
|
}
|
|
3512
3552
|
|
|
3513
3553
|
// src/lib/hooks.ts
|
|
3514
|
-
import
|
|
3515
|
-
import
|
|
3554
|
+
import fs18 from "fs";
|
|
3555
|
+
import path13 from "path";
|
|
3516
3556
|
import { execSync as execSync7 } from "child_process";
|
|
3517
3557
|
|
|
3518
3558
|
// src/lib/resolve-caliber.ts
|
|
3519
|
-
import
|
|
3559
|
+
import fs17 from "fs";
|
|
3520
3560
|
import { execSync as execSync6 } from "child_process";
|
|
3521
3561
|
var _resolved = null;
|
|
3522
3562
|
function resolveCaliber() {
|
|
@@ -3539,7 +3579,7 @@ function resolveCaliber() {
|
|
|
3539
3579
|
} catch {
|
|
3540
3580
|
}
|
|
3541
3581
|
const binPath = process.argv[1];
|
|
3542
|
-
if (binPath &&
|
|
3582
|
+
if (binPath && fs17.existsSync(binPath)) {
|
|
3543
3583
|
_resolved = binPath;
|
|
3544
3584
|
return _resolved;
|
|
3545
3585
|
}
|
|
@@ -3555,24 +3595,24 @@ function isCaliberCommand(command, subcommandTail) {
|
|
|
3555
3595
|
}
|
|
3556
3596
|
|
|
3557
3597
|
// src/lib/hooks.ts
|
|
3558
|
-
var SETTINGS_PATH =
|
|
3598
|
+
var SETTINGS_PATH = path13.join(".claude", "settings.json");
|
|
3559
3599
|
var REFRESH_TAIL = "refresh --quiet";
|
|
3560
3600
|
var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
|
|
3561
3601
|
function getHookCommand() {
|
|
3562
3602
|
return `${resolveCaliber()} ${REFRESH_TAIL}`;
|
|
3563
3603
|
}
|
|
3564
3604
|
function readSettings() {
|
|
3565
|
-
if (!
|
|
3605
|
+
if (!fs18.existsSync(SETTINGS_PATH)) return {};
|
|
3566
3606
|
try {
|
|
3567
|
-
return JSON.parse(
|
|
3607
|
+
return JSON.parse(fs18.readFileSync(SETTINGS_PATH, "utf-8"));
|
|
3568
3608
|
} catch {
|
|
3569
3609
|
return {};
|
|
3570
3610
|
}
|
|
3571
3611
|
}
|
|
3572
3612
|
function writeSettings(settings) {
|
|
3573
|
-
const dir =
|
|
3574
|
-
if (!
|
|
3575
|
-
|
|
3613
|
+
const dir = path13.dirname(SETTINGS_PATH);
|
|
3614
|
+
if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
|
|
3615
|
+
fs18.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
3576
3616
|
}
|
|
3577
3617
|
function findHookIndex(sessionEnd) {
|
|
3578
3618
|
return sessionEnd.findIndex(
|
|
@@ -3635,19 +3675,19 @@ ${PRECOMMIT_END}`;
|
|
|
3635
3675
|
function getGitHooksDir() {
|
|
3636
3676
|
try {
|
|
3637
3677
|
const gitDir = execSync7("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3638
|
-
return
|
|
3678
|
+
return path13.join(gitDir, "hooks");
|
|
3639
3679
|
} catch {
|
|
3640
3680
|
return null;
|
|
3641
3681
|
}
|
|
3642
3682
|
}
|
|
3643
3683
|
function getPreCommitPath() {
|
|
3644
3684
|
const hooksDir = getGitHooksDir();
|
|
3645
|
-
return hooksDir ?
|
|
3685
|
+
return hooksDir ? path13.join(hooksDir, "pre-commit") : null;
|
|
3646
3686
|
}
|
|
3647
3687
|
function isPreCommitHookInstalled() {
|
|
3648
3688
|
const hookPath = getPreCommitPath();
|
|
3649
|
-
if (!hookPath || !
|
|
3650
|
-
const content =
|
|
3689
|
+
if (!hookPath || !fs18.existsSync(hookPath)) return false;
|
|
3690
|
+
const content = fs18.readFileSync(hookPath, "utf-8");
|
|
3651
3691
|
return content.includes(PRECOMMIT_START);
|
|
3652
3692
|
}
|
|
3653
3693
|
function installPreCommitHook() {
|
|
@@ -3656,43 +3696,43 @@ function installPreCommitHook() {
|
|
|
3656
3696
|
}
|
|
3657
3697
|
const hookPath = getPreCommitPath();
|
|
3658
3698
|
if (!hookPath) return { installed: false, alreadyInstalled: false };
|
|
3659
|
-
const hooksDir =
|
|
3660
|
-
if (!
|
|
3699
|
+
const hooksDir = path13.dirname(hookPath);
|
|
3700
|
+
if (!fs18.existsSync(hooksDir)) fs18.mkdirSync(hooksDir, { recursive: true });
|
|
3661
3701
|
let content = "";
|
|
3662
|
-
if (
|
|
3663
|
-
content =
|
|
3702
|
+
if (fs18.existsSync(hookPath)) {
|
|
3703
|
+
content = fs18.readFileSync(hookPath, "utf-8");
|
|
3664
3704
|
if (!content.endsWith("\n")) content += "\n";
|
|
3665
3705
|
content += "\n" + getPrecommitBlock() + "\n";
|
|
3666
3706
|
} else {
|
|
3667
3707
|
content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
|
|
3668
3708
|
}
|
|
3669
|
-
|
|
3670
|
-
|
|
3709
|
+
fs18.writeFileSync(hookPath, content);
|
|
3710
|
+
fs18.chmodSync(hookPath, 493);
|
|
3671
3711
|
return { installed: true, alreadyInstalled: false };
|
|
3672
3712
|
}
|
|
3673
3713
|
function removePreCommitHook() {
|
|
3674
3714
|
const hookPath = getPreCommitPath();
|
|
3675
|
-
if (!hookPath || !
|
|
3715
|
+
if (!hookPath || !fs18.existsSync(hookPath)) {
|
|
3676
3716
|
return { removed: false, notFound: true };
|
|
3677
3717
|
}
|
|
3678
|
-
let content =
|
|
3718
|
+
let content = fs18.readFileSync(hookPath, "utf-8");
|
|
3679
3719
|
if (!content.includes(PRECOMMIT_START)) {
|
|
3680
3720
|
return { removed: false, notFound: true };
|
|
3681
3721
|
}
|
|
3682
|
-
const
|
|
3683
|
-
content = content.replace(
|
|
3722
|
+
const regex2 = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
|
|
3723
|
+
content = content.replace(regex2, "\n");
|
|
3684
3724
|
if (content.trim() === "#!/bin/sh" || content.trim() === "") {
|
|
3685
|
-
|
|
3725
|
+
fs18.unlinkSync(hookPath);
|
|
3686
3726
|
} else {
|
|
3687
|
-
|
|
3727
|
+
fs18.writeFileSync(hookPath, content);
|
|
3688
3728
|
}
|
|
3689
3729
|
return { removed: true, notFound: false };
|
|
3690
3730
|
}
|
|
3691
3731
|
|
|
3692
3732
|
// src/lib/learning-hooks.ts
|
|
3693
|
-
import
|
|
3694
|
-
import
|
|
3695
|
-
var SETTINGS_PATH2 =
|
|
3733
|
+
import fs19 from "fs";
|
|
3734
|
+
import path14 from "path";
|
|
3735
|
+
var SETTINGS_PATH2 = path14.join(".claude", "settings.json");
|
|
3696
3736
|
var HOOK_TAILS = [
|
|
3697
3737
|
{ event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
|
|
3698
3738
|
{ event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
|
|
@@ -3709,17 +3749,17 @@ function getHookConfigs() {
|
|
|
3709
3749
|
}));
|
|
3710
3750
|
}
|
|
3711
3751
|
function readSettings2() {
|
|
3712
|
-
if (!
|
|
3752
|
+
if (!fs19.existsSync(SETTINGS_PATH2)) return {};
|
|
3713
3753
|
try {
|
|
3714
|
-
return JSON.parse(
|
|
3754
|
+
return JSON.parse(fs19.readFileSync(SETTINGS_PATH2, "utf-8"));
|
|
3715
3755
|
} catch {
|
|
3716
3756
|
return {};
|
|
3717
3757
|
}
|
|
3718
3758
|
}
|
|
3719
3759
|
function writeSettings2(settings) {
|
|
3720
|
-
const dir =
|
|
3721
|
-
if (!
|
|
3722
|
-
|
|
3760
|
+
const dir = path14.dirname(SETTINGS_PATH2);
|
|
3761
|
+
if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
|
|
3762
|
+
fs19.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
|
|
3723
3763
|
}
|
|
3724
3764
|
function hasLearningHook(matchers, tail) {
|
|
3725
3765
|
return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
|
|
@@ -3753,7 +3793,7 @@ function installLearningHooks() {
|
|
|
3753
3793
|
writeSettings2(settings);
|
|
3754
3794
|
return { installed: true, alreadyInstalled: false };
|
|
3755
3795
|
}
|
|
3756
|
-
var CURSOR_HOOKS_PATH =
|
|
3796
|
+
var CURSOR_HOOKS_PATH = path14.join(".cursor", "hooks.json");
|
|
3757
3797
|
var CURSOR_HOOK_EVENTS = [
|
|
3758
3798
|
{ event: "postToolUse", tail: "learn observe" },
|
|
3759
3799
|
{ event: "postToolUseFailure", tail: "learn observe --failure" },
|
|
@@ -3761,17 +3801,17 @@ var CURSOR_HOOK_EVENTS = [
|
|
|
3761
3801
|
{ event: "sessionEnd", tail: "learn finalize" }
|
|
3762
3802
|
];
|
|
3763
3803
|
function readCursorHooks() {
|
|
3764
|
-
if (!
|
|
3804
|
+
if (!fs19.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
|
|
3765
3805
|
try {
|
|
3766
|
-
return JSON.parse(
|
|
3806
|
+
return JSON.parse(fs19.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
|
|
3767
3807
|
} catch {
|
|
3768
3808
|
return { version: 1, hooks: {} };
|
|
3769
3809
|
}
|
|
3770
3810
|
}
|
|
3771
3811
|
function writeCursorHooks(config) {
|
|
3772
|
-
const dir =
|
|
3773
|
-
if (!
|
|
3774
|
-
|
|
3812
|
+
const dir = path14.dirname(CURSOR_HOOKS_PATH);
|
|
3813
|
+
if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
|
|
3814
|
+
fs19.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
|
|
3775
3815
|
}
|
|
3776
3816
|
function hasCursorHook(entries, tail) {
|
|
3777
3817
|
return entries.some((e) => isCaliberCommand(e.command, tail));
|
|
@@ -3841,10 +3881,10 @@ function removeLearningHooks() {
|
|
|
3841
3881
|
|
|
3842
3882
|
// src/lib/state.ts
|
|
3843
3883
|
init_constants();
|
|
3844
|
-
import
|
|
3845
|
-
import
|
|
3884
|
+
import fs20 from "fs";
|
|
3885
|
+
import path15 from "path";
|
|
3846
3886
|
import { execSync as execSync8 } from "child_process";
|
|
3847
|
-
var STATE_FILE =
|
|
3887
|
+
var STATE_FILE = path15.join(CALIBER_DIR, ".caliber-state.json");
|
|
3848
3888
|
function normalizeTargetAgent(value) {
|
|
3849
3889
|
if (Array.isArray(value)) return value;
|
|
3850
3890
|
if (typeof value === "string") {
|
|
@@ -3855,8 +3895,8 @@ function normalizeTargetAgent(value) {
|
|
|
3855
3895
|
}
|
|
3856
3896
|
function readState() {
|
|
3857
3897
|
try {
|
|
3858
|
-
if (!
|
|
3859
|
-
const raw = JSON.parse(
|
|
3898
|
+
if (!fs20.existsSync(STATE_FILE)) return null;
|
|
3899
|
+
const raw = JSON.parse(fs20.readFileSync(STATE_FILE, "utf-8"));
|
|
3860
3900
|
if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
|
|
3861
3901
|
return raw;
|
|
3862
3902
|
} catch {
|
|
@@ -3864,10 +3904,10 @@ function readState() {
|
|
|
3864
3904
|
}
|
|
3865
3905
|
}
|
|
3866
3906
|
function writeState(state) {
|
|
3867
|
-
if (!
|
|
3868
|
-
|
|
3907
|
+
if (!fs20.existsSync(CALIBER_DIR)) {
|
|
3908
|
+
fs20.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
3869
3909
|
}
|
|
3870
|
-
|
|
3910
|
+
fs20.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
3871
3911
|
}
|
|
3872
3912
|
function getCurrentHeadSha() {
|
|
3873
3913
|
try {
|
|
@@ -5224,22 +5264,22 @@ function checkBonus(dir) {
|
|
|
5224
5264
|
|
|
5225
5265
|
// src/scoring/dismissed.ts
|
|
5226
5266
|
init_constants();
|
|
5227
|
-
import
|
|
5228
|
-
import
|
|
5229
|
-
var DISMISSED_FILE =
|
|
5267
|
+
import fs21 from "fs";
|
|
5268
|
+
import path16 from "path";
|
|
5269
|
+
var DISMISSED_FILE = path16.join(CALIBER_DIR, "dismissed-checks.json");
|
|
5230
5270
|
function readDismissedChecks() {
|
|
5231
5271
|
try {
|
|
5232
|
-
if (!
|
|
5233
|
-
return JSON.parse(
|
|
5272
|
+
if (!fs21.existsSync(DISMISSED_FILE)) return [];
|
|
5273
|
+
return JSON.parse(fs21.readFileSync(DISMISSED_FILE, "utf-8"));
|
|
5234
5274
|
} catch {
|
|
5235
5275
|
return [];
|
|
5236
5276
|
}
|
|
5237
5277
|
}
|
|
5238
5278
|
function writeDismissedChecks(checks) {
|
|
5239
|
-
if (!
|
|
5240
|
-
|
|
5279
|
+
if (!fs21.existsSync(CALIBER_DIR)) {
|
|
5280
|
+
fs21.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
5241
5281
|
}
|
|
5242
|
-
|
|
5282
|
+
fs21.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
|
|
5243
5283
|
}
|
|
5244
5284
|
function getDismissedIds() {
|
|
5245
5285
|
return new Set(readDismissedChecks().map((c) => c.id));
|
|
@@ -5435,13 +5475,13 @@ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4,
|
|
|
5435
5475
|
import { join as join9, dirname as dirname2 } from "path";
|
|
5436
5476
|
|
|
5437
5477
|
// src/scanner/index.ts
|
|
5438
|
-
import
|
|
5439
|
-
import
|
|
5478
|
+
import fs22 from "fs";
|
|
5479
|
+
import path17 from "path";
|
|
5440
5480
|
import crypto2 from "crypto";
|
|
5441
5481
|
function scanLocalState(dir) {
|
|
5442
5482
|
const items = [];
|
|
5443
|
-
const claudeMdPath =
|
|
5444
|
-
if (
|
|
5483
|
+
const claudeMdPath = path17.join(dir, "CLAUDE.md");
|
|
5484
|
+
if (fs22.existsSync(claudeMdPath)) {
|
|
5445
5485
|
items.push({
|
|
5446
5486
|
type: "rule",
|
|
5447
5487
|
platform: "claude",
|
|
@@ -5450,10 +5490,10 @@ function scanLocalState(dir) {
|
|
|
5450
5490
|
path: claudeMdPath
|
|
5451
5491
|
});
|
|
5452
5492
|
}
|
|
5453
|
-
const skillsDir =
|
|
5454
|
-
if (
|
|
5455
|
-
for (const file of
|
|
5456
|
-
const filePath =
|
|
5493
|
+
const skillsDir = path17.join(dir, ".claude", "skills");
|
|
5494
|
+
if (fs22.existsSync(skillsDir)) {
|
|
5495
|
+
for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
|
|
5496
|
+
const filePath = path17.join(skillsDir, file);
|
|
5457
5497
|
items.push({
|
|
5458
5498
|
type: "skill",
|
|
5459
5499
|
platform: "claude",
|
|
@@ -5463,10 +5503,10 @@ function scanLocalState(dir) {
|
|
|
5463
5503
|
});
|
|
5464
5504
|
}
|
|
5465
5505
|
}
|
|
5466
|
-
const mcpJsonPath =
|
|
5467
|
-
if (
|
|
5506
|
+
const mcpJsonPath = path17.join(dir, ".mcp.json");
|
|
5507
|
+
if (fs22.existsSync(mcpJsonPath)) {
|
|
5468
5508
|
try {
|
|
5469
|
-
const mcpJson = JSON.parse(
|
|
5509
|
+
const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
|
|
5470
5510
|
if (mcpJson.mcpServers) {
|
|
5471
5511
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
5472
5512
|
items.push({
|
|
@@ -5481,8 +5521,8 @@ function scanLocalState(dir) {
|
|
|
5481
5521
|
} catch {
|
|
5482
5522
|
}
|
|
5483
5523
|
}
|
|
5484
|
-
const agentsMdPath =
|
|
5485
|
-
if (
|
|
5524
|
+
const agentsMdPath = path17.join(dir, "AGENTS.md");
|
|
5525
|
+
if (fs22.existsSync(agentsMdPath)) {
|
|
5486
5526
|
items.push({
|
|
5487
5527
|
type: "rule",
|
|
5488
5528
|
platform: "codex",
|
|
@@ -5491,12 +5531,12 @@ function scanLocalState(dir) {
|
|
|
5491
5531
|
path: agentsMdPath
|
|
5492
5532
|
});
|
|
5493
5533
|
}
|
|
5494
|
-
const codexSkillsDir =
|
|
5495
|
-
if (
|
|
5534
|
+
const codexSkillsDir = path17.join(dir, ".agents", "skills");
|
|
5535
|
+
if (fs22.existsSync(codexSkillsDir)) {
|
|
5496
5536
|
try {
|
|
5497
|
-
for (const name of
|
|
5498
|
-
const skillFile =
|
|
5499
|
-
if (
|
|
5537
|
+
for (const name of fs22.readdirSync(codexSkillsDir)) {
|
|
5538
|
+
const skillFile = path17.join(codexSkillsDir, name, "SKILL.md");
|
|
5539
|
+
if (fs22.existsSync(skillFile)) {
|
|
5500
5540
|
items.push({
|
|
5501
5541
|
type: "skill",
|
|
5502
5542
|
platform: "codex",
|
|
@@ -5509,8 +5549,8 @@ function scanLocalState(dir) {
|
|
|
5509
5549
|
} catch {
|
|
5510
5550
|
}
|
|
5511
5551
|
}
|
|
5512
|
-
const cursorrulesPath =
|
|
5513
|
-
if (
|
|
5552
|
+
const cursorrulesPath = path17.join(dir, ".cursorrules");
|
|
5553
|
+
if (fs22.existsSync(cursorrulesPath)) {
|
|
5514
5554
|
items.push({
|
|
5515
5555
|
type: "rule",
|
|
5516
5556
|
platform: "cursor",
|
|
@@ -5519,10 +5559,10 @@ function scanLocalState(dir) {
|
|
|
5519
5559
|
path: cursorrulesPath
|
|
5520
5560
|
});
|
|
5521
5561
|
}
|
|
5522
|
-
const cursorRulesDir =
|
|
5523
|
-
if (
|
|
5524
|
-
for (const file of
|
|
5525
|
-
const filePath =
|
|
5562
|
+
const cursorRulesDir = path17.join(dir, ".cursor", "rules");
|
|
5563
|
+
if (fs22.existsSync(cursorRulesDir)) {
|
|
5564
|
+
for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
|
|
5565
|
+
const filePath = path17.join(cursorRulesDir, file);
|
|
5526
5566
|
items.push({
|
|
5527
5567
|
type: "rule",
|
|
5528
5568
|
platform: "cursor",
|
|
@@ -5532,12 +5572,12 @@ function scanLocalState(dir) {
|
|
|
5532
5572
|
});
|
|
5533
5573
|
}
|
|
5534
5574
|
}
|
|
5535
|
-
const cursorSkillsDir =
|
|
5536
|
-
if (
|
|
5575
|
+
const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
|
|
5576
|
+
if (fs22.existsSync(cursorSkillsDir)) {
|
|
5537
5577
|
try {
|
|
5538
|
-
for (const name of
|
|
5539
|
-
const skillFile =
|
|
5540
|
-
if (
|
|
5578
|
+
for (const name of fs22.readdirSync(cursorSkillsDir)) {
|
|
5579
|
+
const skillFile = path17.join(cursorSkillsDir, name, "SKILL.md");
|
|
5580
|
+
if (fs22.existsSync(skillFile)) {
|
|
5541
5581
|
items.push({
|
|
5542
5582
|
type: "skill",
|
|
5543
5583
|
platform: "cursor",
|
|
@@ -5550,10 +5590,10 @@ function scanLocalState(dir) {
|
|
|
5550
5590
|
} catch {
|
|
5551
5591
|
}
|
|
5552
5592
|
}
|
|
5553
|
-
const cursorMcpPath =
|
|
5554
|
-
if (
|
|
5593
|
+
const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
|
|
5594
|
+
if (fs22.existsSync(cursorMcpPath)) {
|
|
5555
5595
|
try {
|
|
5556
|
-
const mcpJson = JSON.parse(
|
|
5596
|
+
const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
|
|
5557
5597
|
if (mcpJson.mcpServers) {
|
|
5558
5598
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
5559
5599
|
items.push({
|
|
@@ -5571,7 +5611,7 @@ function scanLocalState(dir) {
|
|
|
5571
5611
|
return items;
|
|
5572
5612
|
}
|
|
5573
5613
|
function hashFile(filePath) {
|
|
5574
|
-
const text =
|
|
5614
|
+
const text = fs22.readFileSync(filePath, "utf-8");
|
|
5575
5615
|
return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
|
|
5576
5616
|
}
|
|
5577
5617
|
function hashJson(obj) {
|
|
@@ -5586,27 +5626,27 @@ import { PostHog } from "posthog-node";
|
|
|
5586
5626
|
import chalk7 from "chalk";
|
|
5587
5627
|
|
|
5588
5628
|
// src/telemetry/config.ts
|
|
5589
|
-
import
|
|
5590
|
-
import
|
|
5591
|
-
import
|
|
5629
|
+
import fs23 from "fs";
|
|
5630
|
+
import path18 from "path";
|
|
5631
|
+
import os4 from "os";
|
|
5592
5632
|
import crypto3 from "crypto";
|
|
5593
5633
|
import { execSync as execSync12 } from "child_process";
|
|
5594
|
-
var CONFIG_DIR2 =
|
|
5595
|
-
var CONFIG_FILE2 =
|
|
5634
|
+
var CONFIG_DIR2 = path18.join(os4.homedir(), ".caliber");
|
|
5635
|
+
var CONFIG_FILE2 = path18.join(CONFIG_DIR2, "config.json");
|
|
5596
5636
|
var runtimeDisabled = false;
|
|
5597
5637
|
function readConfig() {
|
|
5598
5638
|
try {
|
|
5599
|
-
if (!
|
|
5600
|
-
return JSON.parse(
|
|
5639
|
+
if (!fs23.existsSync(CONFIG_FILE2)) return {};
|
|
5640
|
+
return JSON.parse(fs23.readFileSync(CONFIG_FILE2, "utf-8"));
|
|
5601
5641
|
} catch {
|
|
5602
5642
|
return {};
|
|
5603
5643
|
}
|
|
5604
5644
|
}
|
|
5605
5645
|
function writeConfig(config) {
|
|
5606
|
-
if (!
|
|
5607
|
-
|
|
5646
|
+
if (!fs23.existsSync(CONFIG_DIR2)) {
|
|
5647
|
+
fs23.mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
5608
5648
|
}
|
|
5609
|
-
|
|
5649
|
+
fs23.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
5610
5650
|
}
|
|
5611
5651
|
function getMachineId() {
|
|
5612
5652
|
const config = readConfig();
|
|
@@ -6007,6 +6047,51 @@ function extractTopDeps() {
|
|
|
6007
6047
|
return [];
|
|
6008
6048
|
}
|
|
6009
6049
|
}
|
|
6050
|
+
async function searchSkills(fingerprint, targetPlatforms, onStatus) {
|
|
6051
|
+
const installedSkills = getInstalledSkills(targetPlatforms);
|
|
6052
|
+
const technologies = [...new Set([
|
|
6053
|
+
...fingerprint.languages,
|
|
6054
|
+
...fingerprint.frameworks,
|
|
6055
|
+
...extractTopDeps()
|
|
6056
|
+
].filter(Boolean))];
|
|
6057
|
+
if (technologies.length === 0) {
|
|
6058
|
+
return { results: [], contentMap: /* @__PURE__ */ new Map() };
|
|
6059
|
+
}
|
|
6060
|
+
const primaryPlatform = targetPlatforms.includes("claude") ? "claude" : targetPlatforms[0];
|
|
6061
|
+
onStatus?.("Searching skill registries...");
|
|
6062
|
+
const allCandidates = await searchAllProviders(technologies, primaryPlatform);
|
|
6063
|
+
if (!allCandidates.length) {
|
|
6064
|
+
return { results: [], contentMap: /* @__PURE__ */ new Map() };
|
|
6065
|
+
}
|
|
6066
|
+
const newCandidates = allCandidates.filter((c) => !installedSkills.has(c.slug.toLowerCase()));
|
|
6067
|
+
if (!newCandidates.length) {
|
|
6068
|
+
return { results: [], contentMap: /* @__PURE__ */ new Map() };
|
|
6069
|
+
}
|
|
6070
|
+
onStatus?.(`Scoring ${newCandidates.length} candidates...`);
|
|
6071
|
+
let results;
|
|
6072
|
+
const config = loadConfig();
|
|
6073
|
+
if (config) {
|
|
6074
|
+
try {
|
|
6075
|
+
const projectContext = buildProjectContext(fingerprint, targetPlatforms);
|
|
6076
|
+
results = await scoreWithLLM(newCandidates, projectContext, technologies);
|
|
6077
|
+
} catch {
|
|
6078
|
+
results = newCandidates.slice(0, 20);
|
|
6079
|
+
}
|
|
6080
|
+
} else {
|
|
6081
|
+
results = newCandidates.slice(0, 20);
|
|
6082
|
+
}
|
|
6083
|
+
if (results.length === 0) {
|
|
6084
|
+
return { results: [], contentMap: /* @__PURE__ */ new Map() };
|
|
6085
|
+
}
|
|
6086
|
+
onStatus?.("Fetching skill content...");
|
|
6087
|
+
const contentMap = /* @__PURE__ */ new Map();
|
|
6088
|
+
await Promise.all(results.map(async (rec) => {
|
|
6089
|
+
const content = await fetchSkillContent(rec);
|
|
6090
|
+
if (content) contentMap.set(rec.slug, content);
|
|
6091
|
+
}));
|
|
6092
|
+
const available = results.filter((r) => contentMap.has(r.slug));
|
|
6093
|
+
return { results: available, contentMap };
|
|
6094
|
+
}
|
|
6010
6095
|
async function recommendCommand() {
|
|
6011
6096
|
const proceed = await select4({
|
|
6012
6097
|
message: "Search public repos for relevant skills to add to this project?",
|
|
@@ -6285,8 +6370,8 @@ function printSkills(recs) {
|
|
|
6285
6370
|
}
|
|
6286
6371
|
|
|
6287
6372
|
// src/lib/debug-report.ts
|
|
6288
|
-
import
|
|
6289
|
-
import
|
|
6373
|
+
import fs24 from "fs";
|
|
6374
|
+
import path19 from "path";
|
|
6290
6375
|
var DebugReport = class {
|
|
6291
6376
|
sections = [];
|
|
6292
6377
|
startTime;
|
|
@@ -6355,11 +6440,11 @@ var DebugReport = class {
|
|
|
6355
6440
|
lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
|
|
6356
6441
|
lines.push("");
|
|
6357
6442
|
}
|
|
6358
|
-
const dir =
|
|
6359
|
-
if (!
|
|
6360
|
-
|
|
6443
|
+
const dir = path19.dirname(outputPath);
|
|
6444
|
+
if (!fs24.existsSync(dir)) {
|
|
6445
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
6361
6446
|
}
|
|
6362
|
-
|
|
6447
|
+
fs24.writeFileSync(outputPath, lines.join("\n"));
|
|
6363
6448
|
}
|
|
6364
6449
|
};
|
|
6365
6450
|
function formatMs(ms) {
|
|
@@ -6371,13 +6456,144 @@ function formatMs(ms) {
|
|
|
6371
6456
|
return `${secs}s`;
|
|
6372
6457
|
}
|
|
6373
6458
|
|
|
6459
|
+
// src/utils/parallel-tasks.ts
|
|
6460
|
+
import chalk9 from "chalk";
|
|
6461
|
+
|
|
6462
|
+
// node_modules/ansi-regex/index.js
|
|
6463
|
+
function ansiRegex({ onlyFirst = false } = {}) {
|
|
6464
|
+
const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
|
|
6465
|
+
const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
|
|
6466
|
+
const csi = "[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";
|
|
6467
|
+
const pattern = `${osc}|${csi}`;
|
|
6468
|
+
return new RegExp(pattern, onlyFirst ? void 0 : "g");
|
|
6469
|
+
}
|
|
6470
|
+
|
|
6471
|
+
// node_modules/strip-ansi/index.js
|
|
6472
|
+
var regex = ansiRegex();
|
|
6473
|
+
function stripAnsi(string) {
|
|
6474
|
+
if (typeof string !== "string") {
|
|
6475
|
+
throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
|
|
6476
|
+
}
|
|
6477
|
+
if (!string.includes("\x1B") && !string.includes("\x9B")) {
|
|
6478
|
+
return string;
|
|
6479
|
+
}
|
|
6480
|
+
return string.replace(regex, "");
|
|
6481
|
+
}
|
|
6482
|
+
|
|
6483
|
+
// src/utils/parallel-tasks.ts
|
|
6484
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
6485
|
+
var SPINNER_INTERVAL_MS = 80;
|
|
6486
|
+
var ParallelTaskDisplay = class {
|
|
6487
|
+
tasks = [];
|
|
6488
|
+
lineCount = 0;
|
|
6489
|
+
spinnerFrame = 0;
|
|
6490
|
+
timer = null;
|
|
6491
|
+
startTime = 0;
|
|
6492
|
+
rendered = false;
|
|
6493
|
+
add(name) {
|
|
6494
|
+
const index = this.tasks.length;
|
|
6495
|
+
this.tasks.push({ name, status: "pending", message: "" });
|
|
6496
|
+
return index;
|
|
6497
|
+
}
|
|
6498
|
+
start() {
|
|
6499
|
+
this.startTime = Date.now();
|
|
6500
|
+
this.draw(true);
|
|
6501
|
+
this.timer = setInterval(() => {
|
|
6502
|
+
this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
6503
|
+
this.draw(false);
|
|
6504
|
+
}, SPINNER_INTERVAL_MS);
|
|
6505
|
+
}
|
|
6506
|
+
update(index, status, message) {
|
|
6507
|
+
const task = this.tasks[index];
|
|
6508
|
+
if (!task) return;
|
|
6509
|
+
if (status === "running" && task.status === "pending") {
|
|
6510
|
+
task.startTime = Date.now();
|
|
6511
|
+
}
|
|
6512
|
+
if ((status === "done" || status === "failed") && !task.endTime) {
|
|
6513
|
+
task.endTime = Date.now();
|
|
6514
|
+
}
|
|
6515
|
+
task.status = status;
|
|
6516
|
+
if (message !== void 0) task.message = message;
|
|
6517
|
+
}
|
|
6518
|
+
stop() {
|
|
6519
|
+
if (this.timer) {
|
|
6520
|
+
clearInterval(this.timer);
|
|
6521
|
+
this.timer = null;
|
|
6522
|
+
}
|
|
6523
|
+
this.draw(false);
|
|
6524
|
+
}
|
|
6525
|
+
formatTime(ms) {
|
|
6526
|
+
const secs = Math.floor(ms / 1e3);
|
|
6527
|
+
if (secs < 60) return `${secs}s`;
|
|
6528
|
+
return `${Math.floor(secs / 60)}m ${secs % 60}s`;
|
|
6529
|
+
}
|
|
6530
|
+
truncate(text, maxVisible) {
|
|
6531
|
+
const plain = stripAnsi(text);
|
|
6532
|
+
if (plain.length <= maxVisible) return text;
|
|
6533
|
+
let visible = 0;
|
|
6534
|
+
let i = 0;
|
|
6535
|
+
while (i < text.length && visible < maxVisible - 3) {
|
|
6536
|
+
if (text[i] === "\x1B") {
|
|
6537
|
+
const end = text.indexOf("m", i);
|
|
6538
|
+
if (end !== -1) {
|
|
6539
|
+
i = end + 1;
|
|
6540
|
+
continue;
|
|
6541
|
+
}
|
|
6542
|
+
}
|
|
6543
|
+
visible++;
|
|
6544
|
+
i++;
|
|
6545
|
+
}
|
|
6546
|
+
return text.slice(0, i) + "...";
|
|
6547
|
+
}
|
|
6548
|
+
renderLine(task) {
|
|
6549
|
+
const maxWidth = process.stdout.columns || 80;
|
|
6550
|
+
const elapsed = task.startTime ? this.formatTime((task.endTime ?? Date.now()) - task.startTime) : "";
|
|
6551
|
+
let line;
|
|
6552
|
+
switch (task.status) {
|
|
6553
|
+
case "pending":
|
|
6554
|
+
line = ` ${chalk9.dim("\u25CB")} ${chalk9.dim(task.name)}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}`;
|
|
6555
|
+
break;
|
|
6556
|
+
case "running": {
|
|
6557
|
+
const spinner = chalk9.cyan(SPINNER_FRAMES[this.spinnerFrame]);
|
|
6558
|
+
const time = elapsed ? chalk9.dim(` (${elapsed})`) : "";
|
|
6559
|
+
line = ` ${spinner} ${task.name}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}${time}`;
|
|
6560
|
+
break;
|
|
6561
|
+
}
|
|
6562
|
+
case "done": {
|
|
6563
|
+
const time = elapsed ? chalk9.dim(` (${elapsed})`) : "";
|
|
6564
|
+
line = ` ${chalk9.green("\u2713")} ${task.name}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}${time}`;
|
|
6565
|
+
break;
|
|
6566
|
+
}
|
|
6567
|
+
case "failed":
|
|
6568
|
+
line = ` ${chalk9.red("\u2717")} ${task.name}${task.message ? chalk9.red(` \u2014 ${task.message}`) : ""}`;
|
|
6569
|
+
break;
|
|
6570
|
+
}
|
|
6571
|
+
return this.truncate(line, maxWidth - 1);
|
|
6572
|
+
}
|
|
6573
|
+
draw(initial) {
|
|
6574
|
+
const { stdout } = process;
|
|
6575
|
+
if (!initial && this.rendered && this.lineCount > 0) {
|
|
6576
|
+
stdout.write(`\x1B[${this.lineCount}A`);
|
|
6577
|
+
}
|
|
6578
|
+
stdout.write("\x1B[0J");
|
|
6579
|
+
const lines = this.tasks.map((t) => this.renderLine(t));
|
|
6580
|
+
const totalElapsed = this.formatTime(Date.now() - this.startTime);
|
|
6581
|
+
lines.push(chalk9.dim(`
|
|
6582
|
+
Total: ${totalElapsed}`));
|
|
6583
|
+
const output = lines.join("\n");
|
|
6584
|
+
stdout.write(output + "\n");
|
|
6585
|
+
this.lineCount = output.split("\n").length;
|
|
6586
|
+
this.rendered = true;
|
|
6587
|
+
}
|
|
6588
|
+
};
|
|
6589
|
+
|
|
6374
6590
|
// src/commands/init.ts
|
|
6375
6591
|
function log(verbose, ...args) {
|
|
6376
|
-
if (verbose) console.log(
|
|
6592
|
+
if (verbose) console.log(chalk10.dim(` [verbose] ${args.map(String).join(" ")}`));
|
|
6377
6593
|
}
|
|
6378
6594
|
async function initCommand(options) {
|
|
6379
|
-
const brand =
|
|
6380
|
-
const title =
|
|
6595
|
+
const brand = chalk10.hex("#EB9D83");
|
|
6596
|
+
const title = chalk10.hex("#83D1EB");
|
|
6381
6597
|
console.log(brand.bold(`
|
|
6382
6598
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
6383
6599
|
\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
@@ -6386,34 +6602,33 @@ async function initCommand(options) {
|
|
|
6386
6602
|
\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
6387
6603
|
\u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
6388
6604
|
`));
|
|
6389
|
-
console.log(
|
|
6390
|
-
console.log(
|
|
6605
|
+
console.log(chalk10.dim(" Scan your project and generate tailored config files for"));
|
|
6606
|
+
console.log(chalk10.dim(" Claude Code, Cursor, and Codex.\n"));
|
|
6391
6607
|
const report = options.debugReport ? new DebugReport() : null;
|
|
6392
6608
|
console.log(title.bold(" How it works:\n"));
|
|
6393
|
-
console.log(
|
|
6394
|
-
console.log(
|
|
6395
|
-
console.log(
|
|
6396
|
-
console.log(
|
|
6397
|
-
console.log(
|
|
6398
|
-
console.log(title.bold(" Step 1/5 \u2014 Connect\n"));
|
|
6609
|
+
console.log(chalk10.dim(" 1. Setup Connect your LLM provider and select your agents"));
|
|
6610
|
+
console.log(chalk10.dim(" 2. Engine Detect stack, generate configs & skills in parallel"));
|
|
6611
|
+
console.log(chalk10.dim(" 3. Review See all changes \u2014 accept, refine, or decline"));
|
|
6612
|
+
console.log(chalk10.dim(" 4. Finalize Score check and auto-sync hooks\n"));
|
|
6613
|
+
console.log(title.bold(" Step 1/4 \u2014 Setup\n"));
|
|
6399
6614
|
let config = loadConfig();
|
|
6400
6615
|
if (!config) {
|
|
6401
|
-
console.log(
|
|
6616
|
+
console.log(chalk10.dim(" No LLM provider configured yet.\n"));
|
|
6402
6617
|
await runInteractiveProviderSetup({
|
|
6403
6618
|
selectMessage: "How do you want to use Caliber? (choose LLM provider)"
|
|
6404
6619
|
});
|
|
6405
6620
|
config = loadConfig();
|
|
6406
6621
|
if (!config) {
|
|
6407
|
-
console.log(
|
|
6622
|
+
console.log(chalk10.red(" Setup was cancelled or failed.\n"));
|
|
6408
6623
|
throw new Error("__exit__");
|
|
6409
6624
|
}
|
|
6410
|
-
console.log(
|
|
6625
|
+
console.log(chalk10.green(" \u2713 Provider saved\n"));
|
|
6411
6626
|
}
|
|
6412
6627
|
trackInitProviderSelected(config.provider, config.model);
|
|
6413
6628
|
const displayModel = getDisplayModel(config);
|
|
6414
6629
|
const fastModel = getFastModel();
|
|
6415
6630
|
const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
|
|
6416
|
-
console.log(
|
|
6631
|
+
console.log(chalk10.dim(modelLine + "\n"));
|
|
6417
6632
|
if (report) {
|
|
6418
6633
|
report.markStep("Provider setup");
|
|
6419
6634
|
report.addSection("LLM Provider", `- **Provider**: ${config.provider}
|
|
@@ -6421,30 +6636,6 @@ async function initCommand(options) {
|
|
|
6421
6636
|
- **Fast model**: ${fastModel || "none"}`);
|
|
6422
6637
|
}
|
|
6423
6638
|
await validateModel({ fast: true });
|
|
6424
|
-
console.log(title.bold(" Step 2/5 \u2014 Discover\n"));
|
|
6425
|
-
const spinner = ora2("Scanning code, dependencies, and existing configs...").start();
|
|
6426
|
-
const fingerprint = await collectFingerprint(process.cwd());
|
|
6427
|
-
spinner.succeed("Project scanned");
|
|
6428
|
-
log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
|
|
6429
|
-
if (options.verbose && fingerprint.codeAnalysis) {
|
|
6430
|
-
log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.filesIncluded}/${fingerprint.codeAnalysis.filesAnalyzed} files, ~${fingerprint.codeAnalysis.includedTokens.toLocaleString()} tokens, ${fingerprint.codeAnalysis.duplicateGroups} dedup groups`);
|
|
6431
|
-
}
|
|
6432
|
-
trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
|
|
6433
|
-
const langDisplay = fingerprint.languages.join(", ") || "none detected";
|
|
6434
|
-
const frameworkDisplay = fingerprint.frameworks.length > 0 ? ` (${fingerprint.frameworks.join(", ")})` : "";
|
|
6435
|
-
console.log(chalk9.dim(` Languages: ${langDisplay}${frameworkDisplay}`));
|
|
6436
|
-
console.log(chalk9.dim(` Files: ${fingerprint.fileTree.length} found
|
|
6437
|
-
`));
|
|
6438
|
-
if (report) {
|
|
6439
|
-
report.markStep("Fingerprint");
|
|
6440
|
-
report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
|
|
6441
|
-
report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
|
|
6442
|
-
report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
|
|
6443
|
-
report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
|
|
6444
|
-
if (fingerprint.codeAnalysis) {
|
|
6445
|
-
report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
|
|
6446
|
-
}
|
|
6447
|
-
}
|
|
6448
6639
|
let targetAgent;
|
|
6449
6640
|
if (options.agent) {
|
|
6450
6641
|
targetAgent = options.agent;
|
|
@@ -6454,30 +6645,27 @@ async function initCommand(options) {
|
|
|
6454
6645
|
} else {
|
|
6455
6646
|
targetAgent = await promptAgent();
|
|
6456
6647
|
}
|
|
6457
|
-
console.log(
|
|
6648
|
+
console.log(chalk10.dim(` Target: ${targetAgent.join(", ")}
|
|
6458
6649
|
`));
|
|
6459
6650
|
trackInitAgentSelected(targetAgent);
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
}
|
|
6651
|
+
let wantsSkills = false;
|
|
6652
|
+
if (!options.autoApprove) {
|
|
6653
|
+
wantsSkills = await select5({
|
|
6654
|
+
message: "Discover community-maintained skills that match your stack?",
|
|
6655
|
+
choices: [
|
|
6656
|
+
{ name: "Yes, find skills for my project", value: true },
|
|
6657
|
+
{ name: "Skip for now", value: false }
|
|
6658
|
+
]
|
|
6659
|
+
});
|
|
6470
6660
|
}
|
|
6471
|
-
|
|
6472
|
-
console.log(
|
|
6661
|
+
let baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
6662
|
+
console.log(chalk10.dim("\n Current setup score:"));
|
|
6473
6663
|
displayScoreSummary(baselineScore);
|
|
6474
6664
|
if (options.verbose) {
|
|
6475
6665
|
for (const c of baselineScore.checks) {
|
|
6476
6666
|
log(options.verbose, ` ${c.passed ? "\u2713" : "\u2717"} ${c.name}: ${c.earnedPoints}/${c.maxPoints}${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
|
|
6477
6667
|
}
|
|
6478
6668
|
}
|
|
6479
|
-
const passingCount = baselineScore.checks.filter((c) => c.passed).length;
|
|
6480
|
-
const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
|
|
6481
6669
|
if (report) {
|
|
6482
6670
|
report.markStep("Baseline scoring");
|
|
6483
6671
|
report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
|
|
@@ -6487,7 +6675,7 @@ async function initCommand(options) {
|
|
|
6487
6675
|
` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
|
|
6488
6676
|
report.addSection("Generation: Target Agents", targetAgent.join(", "));
|
|
6489
6677
|
}
|
|
6490
|
-
const hasExistingConfig = !!(
|
|
6678
|
+
const hasExistingConfig = !!(baselineScore.checks.some((c) => c.id === "claude_md_exists" && c.passed) || baselineScore.checks.some((c) => c.id === "cursorrules_exists" && c.passed));
|
|
6491
6679
|
const NON_LLM_CHECKS = /* @__PURE__ */ new Set([
|
|
6492
6680
|
"hooks_configured",
|
|
6493
6681
|
"agents_md_exists",
|
|
@@ -6496,111 +6684,175 @@ async function initCommand(options) {
|
|
|
6496
6684
|
"service_coverage",
|
|
6497
6685
|
"mcp_completeness"
|
|
6498
6686
|
]);
|
|
6687
|
+
const passingCount = baselineScore.checks.filter((c) => c.passed).length;
|
|
6688
|
+
const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
|
|
6499
6689
|
if (hasExistingConfig && baselineScore.score === 100) {
|
|
6500
6690
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
|
|
6501
|
-
console.log(
|
|
6502
|
-
console.log(
|
|
6691
|
+
console.log(chalk10.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
|
|
6692
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber init --force") + chalk10.dim(" to regenerate anyway.\n"));
|
|
6503
6693
|
if (!options.force) return;
|
|
6504
6694
|
}
|
|
6505
6695
|
const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
6506
6696
|
const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
|
|
6507
6697
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
|
|
6508
6698
|
if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
|
|
6509
|
-
console.log(
|
|
6510
|
-
console.log(
|
|
6699
|
+
console.log(chalk10.bold.green("\n Your config is fully optimized for LLM generation.\n"));
|
|
6700
|
+
console.log(chalk10.dim(" Remaining items need CLI actions:\n"));
|
|
6511
6701
|
for (const check of allFailingChecks) {
|
|
6512
|
-
console.log(
|
|
6702
|
+
console.log(chalk10.dim(` \u2022 ${check.name}`));
|
|
6513
6703
|
if (check.suggestion) {
|
|
6514
|
-
console.log(` ${
|
|
6704
|
+
console.log(` ${chalk10.hex("#83D1EB")(check.suggestion)}`);
|
|
6515
6705
|
}
|
|
6516
6706
|
}
|
|
6517
6707
|
console.log("");
|
|
6518
|
-
console.log(
|
|
6708
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber init --force") + chalk10.dim(" to regenerate anyway.\n"));
|
|
6519
6709
|
return;
|
|
6520
6710
|
}
|
|
6711
|
+
console.log(title.bold(" Step 2/4 \u2014 Engine\n"));
|
|
6712
|
+
const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
|
|
6713
|
+
console.log(chalk10.dim(genModelInfo + "\n"));
|
|
6714
|
+
if (report) report.markStep("Generation");
|
|
6715
|
+
trackInitGenerationStarted(false);
|
|
6716
|
+
const genStartTime = Date.now();
|
|
6717
|
+
let generatedSetup = null;
|
|
6718
|
+
let rawOutput;
|
|
6719
|
+
let genStopReason;
|
|
6720
|
+
let skillSearchResult = { results: [], contentMap: /* @__PURE__ */ new Map() };
|
|
6721
|
+
let fingerprint;
|
|
6722
|
+
const fpSpinner = ora2("Scanning project...").start();
|
|
6723
|
+
try {
|
|
6724
|
+
fingerprint = await collectFingerprint(process.cwd());
|
|
6725
|
+
fpSpinner.succeed(`Stack detected \u2014 ${fingerprint.languages.join(", ") || "no languages"}${fingerprint.frameworks.length > 0 ? `, ${fingerprint.frameworks.join(", ")}` : ""}`);
|
|
6726
|
+
} catch (err) {
|
|
6727
|
+
fpSpinner.fail("Failed to scan project");
|
|
6728
|
+
throw new Error("__exit__");
|
|
6729
|
+
}
|
|
6730
|
+
trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
|
|
6731
|
+
log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
|
|
6732
|
+
if (report) {
|
|
6733
|
+
report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
|
|
6734
|
+
report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
|
|
6735
|
+
report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
|
|
6736
|
+
report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
|
|
6737
|
+
if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
|
|
6738
|
+
}
|
|
6521
6739
|
const isEmpty = fingerprint.fileTree.length < 3;
|
|
6522
6740
|
if (isEmpty) {
|
|
6523
6741
|
fingerprint.description = await promptInput("What will you build in this project?");
|
|
6524
6742
|
}
|
|
6743
|
+
const failingForDismissal = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
6744
|
+
if (failingForDismissal.length > 0) {
|
|
6745
|
+
const newDismissals = await evaluateDismissals(failingForDismissal, fingerprint);
|
|
6746
|
+
if (newDismissals.length > 0) {
|
|
6747
|
+
const existing = readDismissedChecks();
|
|
6748
|
+
const existingIds = new Set(existing.map((d) => d.id));
|
|
6749
|
+
const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
|
|
6750
|
+
writeDismissedChecks(merged);
|
|
6751
|
+
baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
6752
|
+
}
|
|
6753
|
+
}
|
|
6525
6754
|
let failingChecks;
|
|
6526
6755
|
let passingChecks;
|
|
6527
6756
|
let currentScore;
|
|
6528
6757
|
if (hasExistingConfig && baselineScore.score >= 95 && !options.force) {
|
|
6529
|
-
|
|
6758
|
+
const currentLlmFixable = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
|
|
6759
|
+
failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
|
|
6530
6760
|
passingChecks = baselineScore.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
|
|
6531
6761
|
currentScore = baselineScore.score;
|
|
6532
|
-
if (failingChecks.length > 0) {
|
|
6533
|
-
console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
|
|
6534
|
-
console.log(chalk9.dim(` Score is ${baselineScore.score}/100 \u2014 fine-tuning ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
|
|
6535
|
-
`));
|
|
6536
|
-
for (const check of failingChecks) {
|
|
6537
|
-
console.log(chalk9.dim(` \u2022 ${check.name}`));
|
|
6538
|
-
}
|
|
6539
|
-
console.log("");
|
|
6540
|
-
}
|
|
6541
|
-
} else if (hasExistingConfig) {
|
|
6542
|
-
console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
|
|
6543
|
-
console.log(chalk9.dim(" Auditing your existing configs against your codebase and improving them.\n"));
|
|
6544
|
-
} else {
|
|
6545
|
-
console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
|
|
6546
|
-
console.log(chalk9.dim(" Building CLAUDE.md, rules, and skills tailored to your project.\n"));
|
|
6547
6762
|
}
|
|
6548
|
-
const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
|
|
6549
|
-
console.log(chalk9.dim(genModelInfo));
|
|
6550
|
-
console.log(chalk9.dim(" This can take a couple of minutes depending on your model and provider.\n"));
|
|
6551
6763
|
if (report) {
|
|
6552
|
-
report.markStep("Generation");
|
|
6553
6764
|
const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
|
|
6554
6765
|
report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
|
|
6555
6766
|
}
|
|
6556
|
-
|
|
6557
|
-
const
|
|
6558
|
-
const
|
|
6559
|
-
const
|
|
6560
|
-
|
|
6561
|
-
let generatedSetup = null;
|
|
6562
|
-
let rawOutput;
|
|
6563
|
-
let genStopReason;
|
|
6767
|
+
const display = new ParallelTaskDisplay();
|
|
6768
|
+
const TASK_CONFIG = display.add("Generating configs");
|
|
6769
|
+
const TASK_SKILLS_GEN = display.add("Generating skills");
|
|
6770
|
+
const TASK_SKILLS_SEARCH = wantsSkills ? display.add("Searching community skills") : -1;
|
|
6771
|
+
display.start();
|
|
6564
6772
|
try {
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6773
|
+
display.update(TASK_CONFIG, "running");
|
|
6774
|
+
const generatePromise = (async () => {
|
|
6775
|
+
const result = await generateSetup(
|
|
6776
|
+
fingerprint,
|
|
6777
|
+
targetAgent,
|
|
6778
|
+
fingerprint.description,
|
|
6779
|
+
{
|
|
6780
|
+
onStatus: (status) => display.update(TASK_CONFIG, "running", status),
|
|
6781
|
+
onComplete: (setup) => {
|
|
6782
|
+
generatedSetup = setup;
|
|
6783
|
+
},
|
|
6784
|
+
onError: (error) => display.update(TASK_CONFIG, "failed", error)
|
|
6575
6785
|
},
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
}
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
currentScore,
|
|
6583
|
-
passingChecks
|
|
6584
|
-
);
|
|
6585
|
-
if (!generatedSetup) {
|
|
6586
|
-
generatedSetup = result.setup;
|
|
6786
|
+
failingChecks,
|
|
6787
|
+
currentScore,
|
|
6788
|
+
passingChecks,
|
|
6789
|
+
{ skipSkills: true }
|
|
6790
|
+
);
|
|
6791
|
+
if (!generatedSetup) generatedSetup = result.setup;
|
|
6587
6792
|
rawOutput = result.raw;
|
|
6588
|
-
|
|
6589
|
-
|
|
6793
|
+
genStopReason = result.stopReason;
|
|
6794
|
+
if (!generatedSetup) {
|
|
6795
|
+
display.update(TASK_CONFIG, "failed", "Could not parse LLM response");
|
|
6796
|
+
display.update(TASK_SKILLS_GEN, "failed", "Skipped");
|
|
6797
|
+
return;
|
|
6798
|
+
}
|
|
6799
|
+
display.update(TASK_CONFIG, "done");
|
|
6800
|
+
display.update(TASK_SKILLS_GEN, "running");
|
|
6801
|
+
const skillCount = await generateSkillsForSetup(
|
|
6802
|
+
generatedSetup,
|
|
6803
|
+
fingerprint,
|
|
6804
|
+
targetAgent,
|
|
6805
|
+
(status) => display.update(TASK_SKILLS_GEN, "running", status)
|
|
6806
|
+
);
|
|
6807
|
+
display.update(TASK_SKILLS_GEN, "done", `${skillCount} skills`);
|
|
6808
|
+
})();
|
|
6809
|
+
const SEARCH_TIMEOUT_MS = 6e4;
|
|
6810
|
+
const searchPromise = wantsSkills ? (async () => {
|
|
6811
|
+
display.update(TASK_SKILLS_SEARCH, "running");
|
|
6812
|
+
try {
|
|
6813
|
+
const searchWithTimeout = Promise.race([
|
|
6814
|
+
searchSkills(
|
|
6815
|
+
fingerprint,
|
|
6816
|
+
targetAgent,
|
|
6817
|
+
(status) => display.update(TASK_SKILLS_SEARCH, "running", status)
|
|
6818
|
+
),
|
|
6819
|
+
new Promise(
|
|
6820
|
+
(_, reject) => setTimeout(() => reject(new Error("timeout")), SEARCH_TIMEOUT_MS)
|
|
6821
|
+
)
|
|
6822
|
+
]);
|
|
6823
|
+
skillSearchResult = await searchWithTimeout;
|
|
6824
|
+
const count = skillSearchResult.results.length;
|
|
6825
|
+
display.update(TASK_SKILLS_SEARCH, "done", count > 0 ? `${count} skills found` : "No matches");
|
|
6826
|
+
} catch (err) {
|
|
6827
|
+
const reason = err instanceof Error && err.message === "timeout" ? "Timed out" : "Search failed";
|
|
6828
|
+
display.update(TASK_SKILLS_SEARCH, "failed", reason);
|
|
6829
|
+
}
|
|
6830
|
+
})() : Promise.resolve();
|
|
6831
|
+
await Promise.all([generatePromise, searchPromise]);
|
|
6590
6832
|
} catch (err) {
|
|
6591
|
-
|
|
6833
|
+
display.stop();
|
|
6592
6834
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
6593
|
-
|
|
6835
|
+
console.log(chalk10.red(`
|
|
6836
|
+
Engine failed: ${msg}
|
|
6837
|
+
`));
|
|
6594
6838
|
writeErrorLog(config, void 0, msg, "exception");
|
|
6595
6839
|
throw new Error("__exit__");
|
|
6596
6840
|
}
|
|
6597
|
-
|
|
6841
|
+
display.stop();
|
|
6842
|
+
const elapsedMs = Date.now() - genStartTime;
|
|
6843
|
+
trackInitGenerationCompleted(elapsedMs, 0);
|
|
6844
|
+
const mins = Math.floor(elapsedMs / 6e4);
|
|
6845
|
+
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
6846
|
+
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
6847
|
+
console.log(chalk10.dim(`
|
|
6848
|
+
Completed in ${timeStr}
|
|
6849
|
+
`));
|
|
6598
6850
|
if (!generatedSetup) {
|
|
6599
|
-
|
|
6851
|
+
console.log(chalk10.red(" Failed to generate setup."));
|
|
6600
6852
|
writeErrorLog(config, rawOutput, void 0, genStopReason);
|
|
6601
6853
|
if (rawOutput) {
|
|
6602
|
-
console.log(
|
|
6603
|
-
console.log(
|
|
6854
|
+
console.log(chalk10.dim("\nRaw LLM output (JSON parse failed):"));
|
|
6855
|
+
console.log(chalk10.dim(rawOutput.slice(0, 500)));
|
|
6604
6856
|
}
|
|
6605
6857
|
throw new Error("__exit__");
|
|
6606
6858
|
}
|
|
@@ -6608,12 +6860,6 @@ async function initCommand(options) {
|
|
|
6608
6860
|
if (rawOutput) report.addCodeBlock("Generation: Raw LLM Response", rawOutput);
|
|
6609
6861
|
report.addJson("Generation: Parsed Setup", generatedSetup);
|
|
6610
6862
|
}
|
|
6611
|
-
const elapsedMs = Date.now() - genStartTime;
|
|
6612
|
-
trackInitGenerationCompleted(elapsedMs, 0);
|
|
6613
|
-
const mins = Math.floor(elapsedMs / 6e4);
|
|
6614
|
-
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
6615
|
-
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
6616
|
-
genSpinner.succeed(`Setup generated ${chalk9.dim(`in ${timeStr}`)}`);
|
|
6617
6863
|
log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
|
|
6618
6864
|
printSetupSummary(generatedSetup);
|
|
6619
6865
|
const sessionHistory = [];
|
|
@@ -6621,15 +6867,20 @@ async function initCommand(options) {
|
|
|
6621
6867
|
role: "assistant",
|
|
6622
6868
|
content: summarizeSetup("Initial generation", generatedSetup)
|
|
6623
6869
|
});
|
|
6624
|
-
console.log(title.bold(" Step 4
|
|
6870
|
+
console.log(title.bold(" Step 3/4 \u2014 Review\n"));
|
|
6625
6871
|
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
6626
6872
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
6627
6873
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
6628
|
-
console.log(
|
|
6874
|
+
console.log(chalk10.dim(` ${chalk10.green(`${staged.newFiles} new`)} / ${chalk10.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`));
|
|
6875
|
+
if (skillSearchResult.results.length > 0) {
|
|
6876
|
+
console.log(chalk10.dim(` ${chalk10.cyan(`${skillSearchResult.results.length}`)} community skills available to install
|
|
6629
6877
|
`));
|
|
6878
|
+
} else {
|
|
6879
|
+
console.log("");
|
|
6880
|
+
}
|
|
6630
6881
|
let action;
|
|
6631
|
-
if (totalChanges === 0) {
|
|
6632
|
-
console.log(
|
|
6882
|
+
if (totalChanges === 0 && skillSearchResult.results.length === 0) {
|
|
6883
|
+
console.log(chalk10.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
6633
6884
|
cleanupStaging();
|
|
6634
6885
|
action = "accept";
|
|
6635
6886
|
} else if (options.autoApprove) {
|
|
@@ -6637,13 +6888,15 @@ async function initCommand(options) {
|
|
|
6637
6888
|
action = "accept";
|
|
6638
6889
|
trackInitReviewAction(action, "auto-approved");
|
|
6639
6890
|
} else {
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6891
|
+
if (totalChanges > 0) {
|
|
6892
|
+
const wantsReview = await promptWantsReview();
|
|
6893
|
+
if (wantsReview) {
|
|
6894
|
+
const reviewMethod = await promptReviewMethod();
|
|
6895
|
+
await openReview(reviewMethod, staged.stagedFiles);
|
|
6896
|
+
}
|
|
6644
6897
|
}
|
|
6645
6898
|
action = await promptReviewAction();
|
|
6646
|
-
trackInitReviewAction(action,
|
|
6899
|
+
trackInitReviewAction(action, totalChanges > 0 ? "reviewed" : "skipped");
|
|
6647
6900
|
}
|
|
6648
6901
|
let refinementRound = 0;
|
|
6649
6902
|
while (action === "refine") {
|
|
@@ -6652,12 +6905,12 @@ async function initCommand(options) {
|
|
|
6652
6905
|
trackInitRefinementRound(refinementRound, !!generatedSetup);
|
|
6653
6906
|
if (!generatedSetup) {
|
|
6654
6907
|
cleanupStaging();
|
|
6655
|
-
console.log(
|
|
6908
|
+
console.log(chalk10.dim("Refinement cancelled. No files were modified."));
|
|
6656
6909
|
return;
|
|
6657
6910
|
}
|
|
6658
6911
|
const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
6659
6912
|
const restaged = stageFiles(updatedFiles, process.cwd());
|
|
6660
|
-
console.log(
|
|
6913
|
+
console.log(chalk10.dim(` ${chalk10.green(`${restaged.newFiles} new`)} / ${chalk10.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
|
|
6661
6914
|
`));
|
|
6662
6915
|
printSetupSummary(generatedSetup);
|
|
6663
6916
|
await openReview("terminal", restaged.stagedFiles);
|
|
@@ -6666,17 +6919,18 @@ async function initCommand(options) {
|
|
|
6666
6919
|
}
|
|
6667
6920
|
cleanupStaging();
|
|
6668
6921
|
if (action === "decline") {
|
|
6669
|
-
console.log(
|
|
6922
|
+
console.log(chalk10.dim("Setup declined. No files were modified."));
|
|
6670
6923
|
return;
|
|
6671
6924
|
}
|
|
6925
|
+
console.log(title.bold("\n Step 4/4 \u2014 Finalize\n"));
|
|
6672
6926
|
if (options.dryRun) {
|
|
6673
|
-
console.log(
|
|
6927
|
+
console.log(chalk10.yellow("\n[Dry run] Would write the following files:"));
|
|
6674
6928
|
console.log(JSON.stringify(generatedSetup, null, 2));
|
|
6675
6929
|
return;
|
|
6676
6930
|
}
|
|
6677
6931
|
const writeSpinner = ora2("Writing config files...").start();
|
|
6678
6932
|
try {
|
|
6679
|
-
if (targetAgent.includes("codex") && !
|
|
6933
|
+
if (targetAgent.includes("codex") && !fs25.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
6680
6934
|
const claude = generatedSetup.claude;
|
|
6681
6935
|
const cursor = generatedSetup.cursor;
|
|
6682
6936
|
const agentRefs = [];
|
|
@@ -6699,85 +6953,45 @@ ${agentRefs.join(" ")}
|
|
|
6699
6953
|
0,
|
|
6700
6954
|
result.deleted.length
|
|
6701
6955
|
);
|
|
6702
|
-
console.log(
|
|
6956
|
+
console.log(chalk10.bold("\nFiles created/updated:"));
|
|
6703
6957
|
for (const file of result.written) {
|
|
6704
|
-
console.log(` ${
|
|
6958
|
+
console.log(` ${chalk10.green("\u2713")} ${file}`);
|
|
6705
6959
|
}
|
|
6706
6960
|
if (result.deleted.length > 0) {
|
|
6707
|
-
console.log(
|
|
6961
|
+
console.log(chalk10.bold("\nFiles removed:"));
|
|
6708
6962
|
for (const file of result.deleted) {
|
|
6709
|
-
console.log(` ${
|
|
6963
|
+
console.log(` ${chalk10.red("\u2717")} ${file}`);
|
|
6710
6964
|
}
|
|
6711
6965
|
}
|
|
6712
6966
|
if (result.backupDir) {
|
|
6713
|
-
console.log(
|
|
6967
|
+
console.log(chalk10.dim(`
|
|
6714
6968
|
Backups saved to ${result.backupDir}`));
|
|
6715
6969
|
}
|
|
6716
6970
|
} catch (err) {
|
|
6717
6971
|
writeSpinner.fail("Failed to write files");
|
|
6718
|
-
console.error(
|
|
6972
|
+
console.error(chalk10.red(err instanceof Error ? err.message : "Unknown error"));
|
|
6719
6973
|
throw new Error("__exit__");
|
|
6720
6974
|
}
|
|
6721
|
-
ensurePermissions(fingerprint);
|
|
6975
|
+
if (fingerprint) ensurePermissions(fingerprint);
|
|
6722
6976
|
const sha = getCurrentHeadSha();
|
|
6723
6977
|
writeState({
|
|
6724
6978
|
lastRefreshSha: sha ?? "",
|
|
6725
6979
|
lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6726
6980
|
targetAgent
|
|
6727
6981
|
});
|
|
6728
|
-
console.log("");
|
|
6729
|
-
console.log(chalk9.dim(" Auto-refresh: keep your configs in sync as your code changes.\n"));
|
|
6730
|
-
let hookChoice;
|
|
6731
|
-
if (options.autoApprove) {
|
|
6732
|
-
hookChoice = "skip";
|
|
6733
|
-
log(options.verbose, "Auto-approve: skipping hook installation");
|
|
6734
|
-
} else {
|
|
6735
|
-
hookChoice = await promptHookType(targetAgent);
|
|
6736
|
-
}
|
|
6737
|
-
trackInitHookSelected(hookChoice);
|
|
6738
|
-
if (hookChoice === "claude" || hookChoice === "both") {
|
|
6739
|
-
const hookResult = installHook();
|
|
6740
|
-
if (hookResult.installed) {
|
|
6741
|
-
console.log(` ${chalk9.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
|
|
6742
|
-
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber hooks --remove") + chalk9.dim(" to disable"));
|
|
6743
|
-
} else if (hookResult.alreadyInstalled) {
|
|
6744
|
-
console.log(chalk9.dim(" Claude Code hook already installed"));
|
|
6745
|
-
}
|
|
6746
|
-
const learnResult = installLearningHooks();
|
|
6747
|
-
if (learnResult.installed) {
|
|
6748
|
-
console.log(` ${chalk9.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
|
|
6749
|
-
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber learn remove") + chalk9.dim(" to disable"));
|
|
6750
|
-
} else if (learnResult.alreadyInstalled) {
|
|
6751
|
-
console.log(chalk9.dim(" Learning hooks already installed"));
|
|
6752
|
-
}
|
|
6753
|
-
}
|
|
6754
|
-
if (hookChoice === "precommit" || hookChoice === "both") {
|
|
6755
|
-
const precommitResult = installPreCommitHook();
|
|
6756
|
-
if (precommitResult.installed) {
|
|
6757
|
-
console.log(` ${chalk9.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
|
|
6758
|
-
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber hooks --remove") + chalk9.dim(" to disable"));
|
|
6759
|
-
} else if (precommitResult.alreadyInstalled) {
|
|
6760
|
-
console.log(chalk9.dim(" Pre-commit hook already installed"));
|
|
6761
|
-
} else {
|
|
6762
|
-
console.log(chalk9.yellow(" Could not install pre-commit hook (not a git repository?)"));
|
|
6763
|
-
}
|
|
6764
|
-
}
|
|
6765
|
-
if (hookChoice === "skip") {
|
|
6766
|
-
console.log(chalk9.dim(" Skipped auto-refresh hooks. Run ") + chalk9.hex("#83D1EB")("caliber hooks --install") + chalk9.dim(" later to enable."));
|
|
6767
|
-
}
|
|
6768
6982
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
6769
6983
|
if (afterScore.score < baselineScore.score) {
|
|
6770
6984
|
trackInitScoreRegression(baselineScore.score, afterScore.score);
|
|
6771
6985
|
console.log("");
|
|
6772
|
-
console.log(
|
|
6986
|
+
console.log(chalk10.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
6773
6987
|
try {
|
|
6774
6988
|
const { restored, removed } = undoSetup();
|
|
6775
6989
|
if (restored.length > 0 || removed.length > 0) {
|
|
6776
|
-
console.log(
|
|
6990
|
+
console.log(chalk10.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
6777
6991
|
}
|
|
6778
6992
|
} catch {
|
|
6779
6993
|
}
|
|
6780
|
-
console.log(
|
|
6994
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber init --force") + chalk10.dim(" to override.\n"));
|
|
6781
6995
|
return;
|
|
6782
6996
|
}
|
|
6783
6997
|
if (report) {
|
|
@@ -6795,39 +7009,57 @@ ${agentRefs.join(" ")}
|
|
|
6795
7009
|
log(options.verbose, ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
|
|
6796
7010
|
}
|
|
6797
7011
|
}
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
7012
|
+
if (skillSearchResult.results.length > 0 && !options.autoApprove) {
|
|
7013
|
+
console.log(chalk10.dim(" Community skills matched to your project:\n"));
|
|
7014
|
+
const selected = await interactiveSelect(skillSearchResult.results);
|
|
7015
|
+
if (selected?.length) {
|
|
7016
|
+
await installSkills(selected, targetAgent, skillSearchResult.contentMap);
|
|
7017
|
+
trackInitSkillsSearch(true, selected.length);
|
|
7018
|
+
}
|
|
7019
|
+
}
|
|
7020
|
+
console.log("");
|
|
7021
|
+
let hookChoice;
|
|
6801
7022
|
if (options.autoApprove) {
|
|
6802
|
-
|
|
6803
|
-
log(options.verbose, "Auto-approve: skipping
|
|
7023
|
+
hookChoice = "skip";
|
|
7024
|
+
log(options.verbose, "Auto-approve: skipping hook installation");
|
|
6804
7025
|
} else {
|
|
6805
|
-
|
|
6806
|
-
message: "Search public repos for relevant skills to add to this project?",
|
|
6807
|
-
choices: [
|
|
6808
|
-
{ name: "Yes, find skills for my project", value: true },
|
|
6809
|
-
{ name: "Skip for now", value: false }
|
|
6810
|
-
]
|
|
6811
|
-
});
|
|
7026
|
+
hookChoice = await promptHookType(targetAgent);
|
|
6812
7027
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
7028
|
+
trackInitHookSelected(hookChoice);
|
|
7029
|
+
if (hookChoice === "claude" || hookChoice === "both") {
|
|
7030
|
+
const hookResult = installHook();
|
|
7031
|
+
if (hookResult.installed) {
|
|
7032
|
+
console.log(` ${chalk10.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
|
|
7033
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber hooks --remove") + chalk10.dim(" to disable"));
|
|
7034
|
+
} else if (hookResult.alreadyInstalled) {
|
|
7035
|
+
console.log(chalk10.dim(" Claude Code hook already installed"));
|
|
7036
|
+
}
|
|
7037
|
+
const learnResult = installLearningHooks();
|
|
7038
|
+
if (learnResult.installed) {
|
|
7039
|
+
console.log(` ${chalk10.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
|
|
7040
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber learn remove") + chalk10.dim(" to disable"));
|
|
7041
|
+
} else if (learnResult.alreadyInstalled) {
|
|
7042
|
+
console.log(chalk10.dim(" Learning hooks already installed"));
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
7045
|
+
if (hookChoice === "precommit" || hookChoice === "both") {
|
|
7046
|
+
const precommitResult = installPreCommitHook();
|
|
7047
|
+
if (precommitResult.installed) {
|
|
7048
|
+
console.log(` ${chalk10.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
|
|
7049
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber hooks --remove") + chalk10.dim(" to disable"));
|
|
7050
|
+
} else if (precommitResult.alreadyInstalled) {
|
|
7051
|
+
console.log(chalk10.dim(" Pre-commit hook already installed"));
|
|
7052
|
+
} else {
|
|
7053
|
+
console.log(chalk10.yellow(" Could not install pre-commit hook (not a git repository?)"));
|
|
6822
7054
|
}
|
|
6823
|
-
} else {
|
|
6824
|
-
trackInitSkillsSearch(false, 0);
|
|
6825
|
-
console.log(chalk9.dim(" Skipped. Run ") + chalk9.hex("#83D1EB")("caliber skills") + chalk9.dim(" later to browse.\n"));
|
|
6826
7055
|
}
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
console.log(
|
|
7056
|
+
if (hookChoice === "skip") {
|
|
7057
|
+
console.log(chalk10.dim(" Skipped auto-sync hooks. Run ") + chalk10.hex("#83D1EB")("caliber hooks --install") + chalk10.dim(" later to enable."));
|
|
7058
|
+
}
|
|
7059
|
+
console.log(chalk10.bold.green("\n Setup complete!"));
|
|
7060
|
+
console.log(chalk10.dim(" Your AI agents now understand your project's architecture, build commands,"));
|
|
7061
|
+
console.log(chalk10.dim(" testing patterns, and conventions. All changes are backed up automatically.\n"));
|
|
7062
|
+
console.log(chalk10.bold(" Next steps:\n"));
|
|
6831
7063
|
console.log(` ${title("caliber score")} See your full config breakdown`);
|
|
6832
7064
|
console.log(` ${title("caliber refresh")} Update docs after code changes`);
|
|
6833
7065
|
console.log(` ${title("caliber hooks")} Toggle auto-refresh hooks`);
|
|
@@ -6839,9 +7071,9 @@ ${agentRefs.join(" ")}
|
|
|
6839
7071
|
}
|
|
6840
7072
|
if (report) {
|
|
6841
7073
|
report.markStep("Finished");
|
|
6842
|
-
const reportPath =
|
|
7074
|
+
const reportPath = path20.join(process.cwd(), ".caliber", "debug-report.md");
|
|
6843
7075
|
report.write(reportPath);
|
|
6844
|
-
console.log(
|
|
7076
|
+
console.log(chalk10.dim(` Debug report written to ${path20.relative(process.cwd(), reportPath)}
|
|
6845
7077
|
`));
|
|
6846
7078
|
}
|
|
6847
7079
|
}
|
|
@@ -6856,9 +7088,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
6856
7088
|
}
|
|
6857
7089
|
const isValid = await classifyRefineIntent(message);
|
|
6858
7090
|
if (!isValid) {
|
|
6859
|
-
console.log(
|
|
6860
|
-
console.log(
|
|
6861
|
-
console.log(
|
|
7091
|
+
console.log(chalk10.dim(" This doesn't look like a config change request."));
|
|
7092
|
+
console.log(chalk10.dim(" Describe what to add, remove, or modify in your configs."));
|
|
7093
|
+
console.log(chalk10.dim(' Type "done" to accept the current setup.\n'));
|
|
6862
7094
|
continue;
|
|
6863
7095
|
}
|
|
6864
7096
|
const refineSpinner = ora2("Refining setup...").start();
|
|
@@ -6879,16 +7111,16 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
6879
7111
|
});
|
|
6880
7112
|
refineSpinner.succeed("Setup updated");
|
|
6881
7113
|
printSetupSummary(refined);
|
|
6882
|
-
console.log(
|
|
7114
|
+
console.log(chalk10.dim('Type "done" to accept, or describe more changes.'));
|
|
6883
7115
|
} else {
|
|
6884
7116
|
refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
|
|
6885
|
-
console.log(
|
|
7117
|
+
console.log(chalk10.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
|
|
6886
7118
|
}
|
|
6887
7119
|
}
|
|
6888
7120
|
}
|
|
6889
7121
|
function summarizeSetup(action, setup) {
|
|
6890
7122
|
const descriptions = setup.fileDescriptions;
|
|
6891
|
-
const files = descriptions ? Object.entries(descriptions).map(([
|
|
7123
|
+
const files = descriptions ? Object.entries(descriptions).map(([path28, desc]) => ` ${path28}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
|
|
6892
7124
|
return `${action}. Files:
|
|
6893
7125
|
${files}`;
|
|
6894
7126
|
}
|
|
@@ -6910,6 +7142,7 @@ Return {"valid": true} or {"valid": false}. Nothing else.`,
|
|
|
6910
7142
|
}
|
|
6911
7143
|
}
|
|
6912
7144
|
async function evaluateDismissals(failingChecks, fingerprint) {
|
|
7145
|
+
if (failingChecks.length === 0) return [];
|
|
6913
7146
|
const fastModel = getFastModel();
|
|
6914
7147
|
const checkList = failingChecks.map((c) => ({
|
|
6915
7148
|
id: c.id,
|
|
@@ -6977,7 +7210,7 @@ async function promptHookType(targetAgent) {
|
|
|
6977
7210
|
}
|
|
6978
7211
|
choices.push({ name: "Skip for now", value: "skip" });
|
|
6979
7212
|
return select5({
|
|
6980
|
-
message: "
|
|
7213
|
+
message: "Keep your AI docs & skills in sync as your code evolves?",
|
|
6981
7214
|
choices
|
|
6982
7215
|
});
|
|
6983
7216
|
}
|
|
@@ -6997,26 +7230,26 @@ function printSetupSummary(setup) {
|
|
|
6997
7230
|
const fileDescriptions = setup.fileDescriptions;
|
|
6998
7231
|
const deletions = setup.deletions;
|
|
6999
7232
|
console.log("");
|
|
7000
|
-
console.log(
|
|
7233
|
+
console.log(chalk10.bold(" Proposed changes:\n"));
|
|
7001
7234
|
const getDescription = (filePath) => {
|
|
7002
7235
|
return fileDescriptions?.[filePath];
|
|
7003
7236
|
};
|
|
7004
7237
|
if (claude) {
|
|
7005
7238
|
if (claude.claudeMd) {
|
|
7006
|
-
const icon =
|
|
7239
|
+
const icon = fs25.existsSync("CLAUDE.md") ? chalk10.yellow("~") : chalk10.green("+");
|
|
7007
7240
|
const desc = getDescription("CLAUDE.md");
|
|
7008
|
-
console.log(` ${icon} ${
|
|
7009
|
-
if (desc) console.log(
|
|
7241
|
+
console.log(` ${icon} ${chalk10.bold("CLAUDE.md")}`);
|
|
7242
|
+
if (desc) console.log(chalk10.dim(` ${desc}`));
|
|
7010
7243
|
console.log("");
|
|
7011
7244
|
}
|
|
7012
7245
|
const skills = claude.skills;
|
|
7013
7246
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
7014
7247
|
for (const skill of skills) {
|
|
7015
7248
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
7016
|
-
const icon =
|
|
7249
|
+
const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
|
|
7017
7250
|
const desc = getDescription(skillPath);
|
|
7018
|
-
console.log(` ${icon} ${
|
|
7019
|
-
console.log(
|
|
7251
|
+
console.log(` ${icon} ${chalk10.bold(skillPath)}`);
|
|
7252
|
+
console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
|
|
7020
7253
|
console.log("");
|
|
7021
7254
|
}
|
|
7022
7255
|
}
|
|
@@ -7024,40 +7257,40 @@ function printSetupSummary(setup) {
|
|
|
7024
7257
|
const codex = setup.codex;
|
|
7025
7258
|
if (codex) {
|
|
7026
7259
|
if (codex.agentsMd) {
|
|
7027
|
-
const icon =
|
|
7260
|
+
const icon = fs25.existsSync("AGENTS.md") ? chalk10.yellow("~") : chalk10.green("+");
|
|
7028
7261
|
const desc = getDescription("AGENTS.md");
|
|
7029
|
-
console.log(` ${icon} ${
|
|
7030
|
-
if (desc) console.log(
|
|
7262
|
+
console.log(` ${icon} ${chalk10.bold("AGENTS.md")}`);
|
|
7263
|
+
if (desc) console.log(chalk10.dim(` ${desc}`));
|
|
7031
7264
|
console.log("");
|
|
7032
7265
|
}
|
|
7033
7266
|
const codexSkills = codex.skills;
|
|
7034
7267
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
7035
7268
|
for (const skill of codexSkills) {
|
|
7036
7269
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
7037
|
-
const icon =
|
|
7270
|
+
const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
|
|
7038
7271
|
const desc = getDescription(skillPath);
|
|
7039
|
-
console.log(` ${icon} ${
|
|
7040
|
-
console.log(
|
|
7272
|
+
console.log(` ${icon} ${chalk10.bold(skillPath)}`);
|
|
7273
|
+
console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
|
|
7041
7274
|
console.log("");
|
|
7042
7275
|
}
|
|
7043
7276
|
}
|
|
7044
7277
|
}
|
|
7045
7278
|
if (cursor) {
|
|
7046
7279
|
if (cursor.cursorrules) {
|
|
7047
|
-
const icon =
|
|
7280
|
+
const icon = fs25.existsSync(".cursorrules") ? chalk10.yellow("~") : chalk10.green("+");
|
|
7048
7281
|
const desc = getDescription(".cursorrules");
|
|
7049
|
-
console.log(` ${icon} ${
|
|
7050
|
-
if (desc) console.log(
|
|
7282
|
+
console.log(` ${icon} ${chalk10.bold(".cursorrules")}`);
|
|
7283
|
+
if (desc) console.log(chalk10.dim(` ${desc}`));
|
|
7051
7284
|
console.log("");
|
|
7052
7285
|
}
|
|
7053
7286
|
const cursorSkills = cursor.skills;
|
|
7054
7287
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
7055
7288
|
for (const skill of cursorSkills) {
|
|
7056
7289
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
7057
|
-
const icon =
|
|
7290
|
+
const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
|
|
7058
7291
|
const desc = getDescription(skillPath);
|
|
7059
|
-
console.log(` ${icon} ${
|
|
7060
|
-
console.log(
|
|
7292
|
+
console.log(` ${icon} ${chalk10.bold(skillPath)}`);
|
|
7293
|
+
console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
|
|
7061
7294
|
console.log("");
|
|
7062
7295
|
}
|
|
7063
7296
|
}
|
|
@@ -7065,14 +7298,14 @@ function printSetupSummary(setup) {
|
|
|
7065
7298
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
7066
7299
|
for (const rule of rules) {
|
|
7067
7300
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
7068
|
-
const icon =
|
|
7301
|
+
const icon = fs25.existsSync(rulePath) ? chalk10.yellow("~") : chalk10.green("+");
|
|
7069
7302
|
const desc = getDescription(rulePath);
|
|
7070
|
-
console.log(` ${icon} ${
|
|
7303
|
+
console.log(` ${icon} ${chalk10.bold(rulePath)}`);
|
|
7071
7304
|
if (desc) {
|
|
7072
|
-
console.log(
|
|
7305
|
+
console.log(chalk10.dim(` ${desc}`));
|
|
7073
7306
|
} else {
|
|
7074
7307
|
const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
|
|
7075
|
-
if (firstLine) console.log(
|
|
7308
|
+
if (firstLine) console.log(chalk10.dim(` ${firstLine.trim().slice(0, 80)}`));
|
|
7076
7309
|
}
|
|
7077
7310
|
console.log("");
|
|
7078
7311
|
}
|
|
@@ -7080,12 +7313,12 @@ function printSetupSummary(setup) {
|
|
|
7080
7313
|
}
|
|
7081
7314
|
if (Array.isArray(deletions) && deletions.length > 0) {
|
|
7082
7315
|
for (const del of deletions) {
|
|
7083
|
-
console.log(` ${
|
|
7084
|
-
console.log(
|
|
7316
|
+
console.log(` ${chalk10.red("-")} ${chalk10.bold(del.filePath)}`);
|
|
7317
|
+
console.log(chalk10.dim(` ${del.reason}`));
|
|
7085
7318
|
console.log("");
|
|
7086
7319
|
}
|
|
7087
7320
|
}
|
|
7088
|
-
console.log(` ${
|
|
7321
|
+
console.log(` ${chalk10.green("+")} ${chalk10.dim("new")} ${chalk10.yellow("~")} ${chalk10.dim("modified")} ${chalk10.red("-")} ${chalk10.dim("removed")}`);
|
|
7089
7322
|
console.log("");
|
|
7090
7323
|
}
|
|
7091
7324
|
function derivePermissions(fingerprint) {
|
|
@@ -7129,8 +7362,8 @@ function ensurePermissions(fingerprint) {
|
|
|
7129
7362
|
const settingsPath = ".claude/settings.json";
|
|
7130
7363
|
let settings = {};
|
|
7131
7364
|
try {
|
|
7132
|
-
if (
|
|
7133
|
-
settings = JSON.parse(
|
|
7365
|
+
if (fs25.existsSync(settingsPath)) {
|
|
7366
|
+
settings = JSON.parse(fs25.readFileSync(settingsPath, "utf-8"));
|
|
7134
7367
|
}
|
|
7135
7368
|
} catch {
|
|
7136
7369
|
}
|
|
@@ -7139,32 +7372,32 @@ function ensurePermissions(fingerprint) {
|
|
|
7139
7372
|
if (Array.isArray(allow) && allow.length > 0) return;
|
|
7140
7373
|
permissions.allow = derivePermissions(fingerprint);
|
|
7141
7374
|
settings.permissions = permissions;
|
|
7142
|
-
if (!
|
|
7143
|
-
|
|
7375
|
+
if (!fs25.existsSync(".claude")) fs25.mkdirSync(".claude", { recursive: true });
|
|
7376
|
+
fs25.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
7144
7377
|
}
|
|
7145
7378
|
function displayTokenUsage() {
|
|
7146
7379
|
const summary = getUsageSummary();
|
|
7147
7380
|
if (summary.length === 0) {
|
|
7148
|
-
console.log(
|
|
7381
|
+
console.log(chalk10.dim(" Token tracking not available for this provider.\n"));
|
|
7149
7382
|
return;
|
|
7150
7383
|
}
|
|
7151
|
-
console.log(
|
|
7384
|
+
console.log(chalk10.bold(" Token usage:\n"));
|
|
7152
7385
|
let totalIn = 0;
|
|
7153
7386
|
let totalOut = 0;
|
|
7154
7387
|
for (const m of summary) {
|
|
7155
7388
|
totalIn += m.inputTokens;
|
|
7156
7389
|
totalOut += m.outputTokens;
|
|
7157
|
-
const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ?
|
|
7158
|
-
console.log(` ${
|
|
7390
|
+
const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ? chalk10.dim(` (cache: ${m.cacheReadTokens.toLocaleString()} read, ${m.cacheWriteTokens.toLocaleString()} write)`) : "";
|
|
7391
|
+
console.log(` ${chalk10.dim(m.model)}: ${m.inputTokens.toLocaleString()} in / ${m.outputTokens.toLocaleString()} out (${m.calls} call${m.calls === 1 ? "" : "s"})${cacheInfo}`);
|
|
7159
7392
|
}
|
|
7160
7393
|
if (summary.length > 1) {
|
|
7161
|
-
console.log(` ${
|
|
7394
|
+
console.log(` ${chalk10.dim("Total")}: ${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out`);
|
|
7162
7395
|
}
|
|
7163
7396
|
console.log("");
|
|
7164
7397
|
}
|
|
7165
7398
|
function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
7166
7399
|
try {
|
|
7167
|
-
const logPath =
|
|
7400
|
+
const logPath = path20.join(process.cwd(), ".caliber", "error-log.md");
|
|
7168
7401
|
const lines = [
|
|
7169
7402
|
`# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
7170
7403
|
"",
|
|
@@ -7177,16 +7410,16 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
|
7177
7410
|
lines.push("## Error", "```", error, "```", "");
|
|
7178
7411
|
}
|
|
7179
7412
|
lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
console.log(
|
|
7413
|
+
fs25.mkdirSync(path20.join(process.cwd(), ".caliber"), { recursive: true });
|
|
7414
|
+
fs25.writeFileSync(logPath, lines.join("\n"));
|
|
7415
|
+
console.log(chalk10.dim(`
|
|
7183
7416
|
Error log written to .caliber/error-log.md`));
|
|
7184
7417
|
} catch {
|
|
7185
7418
|
}
|
|
7186
7419
|
}
|
|
7187
7420
|
|
|
7188
7421
|
// src/commands/undo.ts
|
|
7189
|
-
import
|
|
7422
|
+
import chalk11 from "chalk";
|
|
7190
7423
|
import ora3 from "ora";
|
|
7191
7424
|
function undoCommand() {
|
|
7192
7425
|
const spinner = ora3("Reverting setup...").start();
|
|
@@ -7199,27 +7432,27 @@ function undoCommand() {
|
|
|
7199
7432
|
trackUndoExecuted();
|
|
7200
7433
|
spinner.succeed("Setup reverted successfully.\n");
|
|
7201
7434
|
if (restored.length > 0) {
|
|
7202
|
-
console.log(
|
|
7435
|
+
console.log(chalk11.cyan(" Restored from backup:"));
|
|
7203
7436
|
for (const file of restored) {
|
|
7204
|
-
console.log(` ${
|
|
7437
|
+
console.log(` ${chalk11.green("\u21A9")} ${file}`);
|
|
7205
7438
|
}
|
|
7206
7439
|
}
|
|
7207
7440
|
if (removed.length > 0) {
|
|
7208
|
-
console.log(
|
|
7441
|
+
console.log(chalk11.cyan(" Removed:"));
|
|
7209
7442
|
for (const file of removed) {
|
|
7210
|
-
console.log(` ${
|
|
7443
|
+
console.log(` ${chalk11.red("\u2717")} ${file}`);
|
|
7211
7444
|
}
|
|
7212
7445
|
}
|
|
7213
7446
|
console.log("");
|
|
7214
7447
|
} catch (err) {
|
|
7215
|
-
spinner.fail(
|
|
7448
|
+
spinner.fail(chalk11.red(err instanceof Error ? err.message : "Undo failed"));
|
|
7216
7449
|
throw new Error("__exit__");
|
|
7217
7450
|
}
|
|
7218
7451
|
}
|
|
7219
7452
|
|
|
7220
7453
|
// src/commands/status.ts
|
|
7221
|
-
import
|
|
7222
|
-
import
|
|
7454
|
+
import chalk12 from "chalk";
|
|
7455
|
+
import fs26 from "fs";
|
|
7223
7456
|
init_config();
|
|
7224
7457
|
async function statusCommand(options) {
|
|
7225
7458
|
const config = loadConfig();
|
|
@@ -7233,40 +7466,40 @@ async function statusCommand(options) {
|
|
|
7233
7466
|
}, null, 2));
|
|
7234
7467
|
return;
|
|
7235
7468
|
}
|
|
7236
|
-
console.log(
|
|
7469
|
+
console.log(chalk12.bold("\nCaliber Status\n"));
|
|
7237
7470
|
if (config) {
|
|
7238
|
-
console.log(` LLM: ${
|
|
7471
|
+
console.log(` LLM: ${chalk12.green(config.provider)} (${config.model})`);
|
|
7239
7472
|
} else {
|
|
7240
|
-
console.log(` LLM: ${
|
|
7473
|
+
console.log(` LLM: ${chalk12.yellow("Not configured")} \u2014 run ${chalk12.hex("#83D1EB")("caliber config")}`);
|
|
7241
7474
|
}
|
|
7242
7475
|
if (!manifest) {
|
|
7243
|
-
console.log(` Setup: ${
|
|
7244
|
-
console.log(
|
|
7476
|
+
console.log(` Setup: ${chalk12.dim("No setup applied")}`);
|
|
7477
|
+
console.log(chalk12.dim("\n Run ") + chalk12.hex("#83D1EB")("caliber init") + chalk12.dim(" to get started.\n"));
|
|
7245
7478
|
return;
|
|
7246
7479
|
}
|
|
7247
|
-
console.log(` Files managed: ${
|
|
7480
|
+
console.log(` Files managed: ${chalk12.cyan(manifest.entries.length.toString())}`);
|
|
7248
7481
|
for (const entry of manifest.entries) {
|
|
7249
|
-
const exists =
|
|
7250
|
-
const icon = exists ?
|
|
7482
|
+
const exists = fs26.existsSync(entry.path);
|
|
7483
|
+
const icon = exists ? chalk12.green("\u2713") : chalk12.red("\u2717");
|
|
7251
7484
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
7252
7485
|
}
|
|
7253
7486
|
console.log("");
|
|
7254
7487
|
}
|
|
7255
7488
|
|
|
7256
7489
|
// src/commands/regenerate.ts
|
|
7257
|
-
import
|
|
7490
|
+
import chalk13 from "chalk";
|
|
7258
7491
|
import ora4 from "ora";
|
|
7259
7492
|
import select6 from "@inquirer/select";
|
|
7260
7493
|
init_config();
|
|
7261
7494
|
async function regenerateCommand(options) {
|
|
7262
7495
|
const config = loadConfig();
|
|
7263
7496
|
if (!config) {
|
|
7264
|
-
console.log(
|
|
7497
|
+
console.log(chalk13.red("No LLM provider configured. Run ") + chalk13.hex("#83D1EB")("caliber config") + chalk13.red(" first."));
|
|
7265
7498
|
throw new Error("__exit__");
|
|
7266
7499
|
}
|
|
7267
7500
|
const manifest = readManifest();
|
|
7268
7501
|
if (!manifest) {
|
|
7269
|
-
console.log(
|
|
7502
|
+
console.log(chalk13.yellow("No existing setup found. Run ") + chalk13.hex("#83D1EB")("caliber init") + chalk13.yellow(" first."));
|
|
7270
7503
|
throw new Error("__exit__");
|
|
7271
7504
|
}
|
|
7272
7505
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
@@ -7277,7 +7510,7 @@ async function regenerateCommand(options) {
|
|
|
7277
7510
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
7278
7511
|
displayScoreSummary(baselineScore);
|
|
7279
7512
|
if (baselineScore.score === 100) {
|
|
7280
|
-
console.log(
|
|
7513
|
+
console.log(chalk13.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
|
|
7281
7514
|
return;
|
|
7282
7515
|
}
|
|
7283
7516
|
const genSpinner = ora4("Regenerating setup...").start();
|
|
@@ -7318,18 +7551,18 @@ async function regenerateCommand(options) {
|
|
|
7318
7551
|
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
7319
7552
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
7320
7553
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
7321
|
-
console.log(
|
|
7322
|
-
${
|
|
7554
|
+
console.log(chalk13.dim(`
|
|
7555
|
+
${chalk13.green(`${staged.newFiles} new`)} / ${chalk13.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
7323
7556
|
`));
|
|
7324
7557
|
if (totalChanges === 0) {
|
|
7325
|
-
console.log(
|
|
7558
|
+
console.log(chalk13.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
7326
7559
|
cleanupStaging();
|
|
7327
7560
|
return;
|
|
7328
7561
|
}
|
|
7329
7562
|
if (options.dryRun) {
|
|
7330
|
-
console.log(
|
|
7563
|
+
console.log(chalk13.yellow("[Dry run] Would write:"));
|
|
7331
7564
|
for (const f of staged.stagedFiles) {
|
|
7332
|
-
console.log(` ${f.isNew ?
|
|
7565
|
+
console.log(` ${f.isNew ? chalk13.green("+") : chalk13.yellow("~")} ${f.relativePath}`);
|
|
7333
7566
|
}
|
|
7334
7567
|
cleanupStaging();
|
|
7335
7568
|
return;
|
|
@@ -7348,7 +7581,7 @@ async function regenerateCommand(options) {
|
|
|
7348
7581
|
});
|
|
7349
7582
|
cleanupStaging();
|
|
7350
7583
|
if (action === "decline") {
|
|
7351
|
-
console.log(
|
|
7584
|
+
console.log(chalk13.dim("Regeneration cancelled. No files were modified."));
|
|
7352
7585
|
return;
|
|
7353
7586
|
}
|
|
7354
7587
|
const writeSpinner = ora4("Writing config files...").start();
|
|
@@ -7356,20 +7589,20 @@ async function regenerateCommand(options) {
|
|
|
7356
7589
|
const result = writeSetup(generatedSetup);
|
|
7357
7590
|
writeSpinner.succeed("Config files written");
|
|
7358
7591
|
for (const file of result.written) {
|
|
7359
|
-
console.log(` ${
|
|
7592
|
+
console.log(` ${chalk13.green("\u2713")} ${file}`);
|
|
7360
7593
|
}
|
|
7361
7594
|
if (result.deleted.length > 0) {
|
|
7362
7595
|
for (const file of result.deleted) {
|
|
7363
|
-
console.log(` ${
|
|
7596
|
+
console.log(` ${chalk13.red("\u2717")} ${file}`);
|
|
7364
7597
|
}
|
|
7365
7598
|
}
|
|
7366
7599
|
if (result.backupDir) {
|
|
7367
|
-
console.log(
|
|
7600
|
+
console.log(chalk13.dim(`
|
|
7368
7601
|
Backups saved to ${result.backupDir}`));
|
|
7369
7602
|
}
|
|
7370
7603
|
} catch (err) {
|
|
7371
7604
|
writeSpinner.fail("Failed to write files");
|
|
7372
|
-
console.error(
|
|
7605
|
+
console.error(chalk13.red(err instanceof Error ? err.message : "Unknown error"));
|
|
7373
7606
|
throw new Error("__exit__");
|
|
7374
7607
|
}
|
|
7375
7608
|
const sha = getCurrentHeadSha();
|
|
@@ -7381,25 +7614,25 @@ async function regenerateCommand(options) {
|
|
|
7381
7614
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
7382
7615
|
if (afterScore.score < baselineScore.score) {
|
|
7383
7616
|
console.log("");
|
|
7384
|
-
console.log(
|
|
7617
|
+
console.log(chalk13.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
7385
7618
|
try {
|
|
7386
7619
|
const { restored, removed } = undoSetup();
|
|
7387
7620
|
if (restored.length > 0 || removed.length > 0) {
|
|
7388
|
-
console.log(
|
|
7621
|
+
console.log(chalk13.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
7389
7622
|
}
|
|
7390
7623
|
} catch {
|
|
7391
7624
|
}
|
|
7392
|
-
console.log(
|
|
7625
|
+
console.log(chalk13.dim(" Run ") + chalk13.hex("#83D1EB")("caliber init --force") + chalk13.dim(" to override.\n"));
|
|
7393
7626
|
return;
|
|
7394
7627
|
}
|
|
7395
7628
|
displayScoreDelta(baselineScore, afterScore);
|
|
7396
7629
|
trackRegenerateCompleted(action, Date.now());
|
|
7397
|
-
console.log(
|
|
7398
|
-
console.log(
|
|
7630
|
+
console.log(chalk13.bold.green(" Regeneration complete!"));
|
|
7631
|
+
console.log(chalk13.dim(" Run ") + chalk13.hex("#83D1EB")("caliber undo") + chalk13.dim(" to revert changes.\n"));
|
|
7399
7632
|
}
|
|
7400
7633
|
|
|
7401
7634
|
// src/commands/score.ts
|
|
7402
|
-
import
|
|
7635
|
+
import chalk14 from "chalk";
|
|
7403
7636
|
async function scoreCommand(options) {
|
|
7404
7637
|
const dir = process.cwd();
|
|
7405
7638
|
const target = options.agent ?? readState()?.targetAgent;
|
|
@@ -7414,22 +7647,22 @@ async function scoreCommand(options) {
|
|
|
7414
7647
|
return;
|
|
7415
7648
|
}
|
|
7416
7649
|
displayScore(result);
|
|
7417
|
-
const separator =
|
|
7650
|
+
const separator = chalk14.gray(" " + "\u2500".repeat(53));
|
|
7418
7651
|
console.log(separator);
|
|
7419
7652
|
if (result.score < 40) {
|
|
7420
|
-
console.log(
|
|
7653
|
+
console.log(chalk14.gray(" Run ") + chalk14.hex("#83D1EB")("caliber init") + chalk14.gray(" to generate a complete, optimized setup."));
|
|
7421
7654
|
} else if (result.score < 70) {
|
|
7422
|
-
console.log(
|
|
7655
|
+
console.log(chalk14.gray(" Run ") + chalk14.hex("#83D1EB")("caliber init") + chalk14.gray(" to improve your setup."));
|
|
7423
7656
|
} else {
|
|
7424
|
-
console.log(
|
|
7657
|
+
console.log(chalk14.green(" Looking good!") + chalk14.gray(" Run ") + chalk14.hex("#83D1EB")("caliber regenerate") + chalk14.gray(" to rebuild from scratch."));
|
|
7425
7658
|
}
|
|
7426
7659
|
console.log("");
|
|
7427
7660
|
}
|
|
7428
7661
|
|
|
7429
7662
|
// src/commands/refresh.ts
|
|
7430
|
-
import
|
|
7431
|
-
import
|
|
7432
|
-
import
|
|
7663
|
+
import fs30 from "fs";
|
|
7664
|
+
import path24 from "path";
|
|
7665
|
+
import chalk15 from "chalk";
|
|
7433
7666
|
import ora5 from "ora";
|
|
7434
7667
|
|
|
7435
7668
|
// src/lib/git-diff.ts
|
|
@@ -7506,37 +7739,37 @@ function collectDiff(lastSha) {
|
|
|
7506
7739
|
}
|
|
7507
7740
|
|
|
7508
7741
|
// src/writers/refresh.ts
|
|
7509
|
-
import
|
|
7510
|
-
import
|
|
7742
|
+
import fs27 from "fs";
|
|
7743
|
+
import path21 from "path";
|
|
7511
7744
|
function writeRefreshDocs(docs) {
|
|
7512
7745
|
const written = [];
|
|
7513
7746
|
if (docs.claudeMd) {
|
|
7514
|
-
|
|
7747
|
+
fs27.writeFileSync("CLAUDE.md", docs.claudeMd);
|
|
7515
7748
|
written.push("CLAUDE.md");
|
|
7516
7749
|
}
|
|
7517
7750
|
if (docs.readmeMd) {
|
|
7518
|
-
|
|
7751
|
+
fs27.writeFileSync("README.md", docs.readmeMd);
|
|
7519
7752
|
written.push("README.md");
|
|
7520
7753
|
}
|
|
7521
7754
|
if (docs.cursorrules) {
|
|
7522
|
-
|
|
7755
|
+
fs27.writeFileSync(".cursorrules", docs.cursorrules);
|
|
7523
7756
|
written.push(".cursorrules");
|
|
7524
7757
|
}
|
|
7525
7758
|
if (docs.cursorRules) {
|
|
7526
|
-
const rulesDir =
|
|
7527
|
-
if (!
|
|
7759
|
+
const rulesDir = path21.join(".cursor", "rules");
|
|
7760
|
+
if (!fs27.existsSync(rulesDir)) fs27.mkdirSync(rulesDir, { recursive: true });
|
|
7528
7761
|
for (const rule of docs.cursorRules) {
|
|
7529
|
-
const filePath =
|
|
7530
|
-
|
|
7762
|
+
const filePath = path21.join(rulesDir, rule.filename);
|
|
7763
|
+
fs27.writeFileSync(filePath, rule.content);
|
|
7531
7764
|
written.push(filePath);
|
|
7532
7765
|
}
|
|
7533
7766
|
}
|
|
7534
7767
|
if (docs.claudeSkills) {
|
|
7535
|
-
const skillsDir =
|
|
7536
|
-
if (!
|
|
7768
|
+
const skillsDir = path21.join(".claude", "skills");
|
|
7769
|
+
if (!fs27.existsSync(skillsDir)) fs27.mkdirSync(skillsDir, { recursive: true });
|
|
7537
7770
|
for (const skill of docs.claudeSkills) {
|
|
7538
|
-
const filePath =
|
|
7539
|
-
|
|
7771
|
+
const filePath = path21.join(skillsDir, skill.filename);
|
|
7772
|
+
fs27.writeFileSync(filePath, skill.content);
|
|
7540
7773
|
written.push(filePath);
|
|
7541
7774
|
}
|
|
7542
7775
|
}
|
|
@@ -7613,8 +7846,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
7613
7846
|
}
|
|
7614
7847
|
|
|
7615
7848
|
// src/learner/writer.ts
|
|
7616
|
-
import
|
|
7617
|
-
import
|
|
7849
|
+
import fs28 from "fs";
|
|
7850
|
+
import path22 from "path";
|
|
7618
7851
|
var LEARNINGS_FILE = "CALIBER_LEARNINGS.md";
|
|
7619
7852
|
var LEARNINGS_HEADER = `# Caliber Learnings
|
|
7620
7853
|
|
|
@@ -7698,16 +7931,16 @@ function deduplicateLearnedItems(existing, incoming) {
|
|
|
7698
7931
|
function writeLearnedSection(content) {
|
|
7699
7932
|
const existingSection = readLearnedSection();
|
|
7700
7933
|
const { merged, newCount, newItems } = deduplicateLearnedItems(existingSection, content);
|
|
7701
|
-
|
|
7934
|
+
fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
|
|
7702
7935
|
return { newCount, newItems };
|
|
7703
7936
|
}
|
|
7704
7937
|
function writeLearnedSkill(skill) {
|
|
7705
|
-
const skillDir =
|
|
7706
|
-
if (!
|
|
7707
|
-
const skillPath =
|
|
7708
|
-
if (!skill.isNew &&
|
|
7709
|
-
const existing =
|
|
7710
|
-
|
|
7938
|
+
const skillDir = path22.join(".claude", "skills", skill.name);
|
|
7939
|
+
if (!fs28.existsSync(skillDir)) fs28.mkdirSync(skillDir, { recursive: true });
|
|
7940
|
+
const skillPath = path22.join(skillDir, "SKILL.md");
|
|
7941
|
+
if (!skill.isNew && fs28.existsSync(skillPath)) {
|
|
7942
|
+
const existing = fs28.readFileSync(skillPath, "utf-8");
|
|
7943
|
+
fs28.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
7711
7944
|
} else {
|
|
7712
7945
|
const frontmatter = [
|
|
7713
7946
|
"---",
|
|
@@ -7716,37 +7949,37 @@ function writeLearnedSkill(skill) {
|
|
|
7716
7949
|
"---",
|
|
7717
7950
|
""
|
|
7718
7951
|
].join("\n");
|
|
7719
|
-
|
|
7952
|
+
fs28.writeFileSync(skillPath, frontmatter + skill.content);
|
|
7720
7953
|
}
|
|
7721
7954
|
return skillPath;
|
|
7722
7955
|
}
|
|
7723
7956
|
function readLearnedSection() {
|
|
7724
|
-
if (
|
|
7725
|
-
const content2 =
|
|
7957
|
+
if (fs28.existsSync(LEARNINGS_FILE)) {
|
|
7958
|
+
const content2 = fs28.readFileSync(LEARNINGS_FILE, "utf-8");
|
|
7726
7959
|
const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
7727
7960
|
return bullets || null;
|
|
7728
7961
|
}
|
|
7729
7962
|
const claudeMdPath = "CLAUDE.md";
|
|
7730
|
-
if (!
|
|
7731
|
-
const content =
|
|
7963
|
+
if (!fs28.existsSync(claudeMdPath)) return null;
|
|
7964
|
+
const content = fs28.readFileSync(claudeMdPath, "utf-8");
|
|
7732
7965
|
const startIdx = content.indexOf(LEARNED_START);
|
|
7733
7966
|
const endIdx = content.indexOf(LEARNED_END);
|
|
7734
7967
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
7735
7968
|
return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
|
|
7736
7969
|
}
|
|
7737
7970
|
function migrateInlineLearnings() {
|
|
7738
|
-
if (
|
|
7971
|
+
if (fs28.existsSync(LEARNINGS_FILE)) return false;
|
|
7739
7972
|
const claudeMdPath = "CLAUDE.md";
|
|
7740
|
-
if (!
|
|
7741
|
-
const content =
|
|
7973
|
+
if (!fs28.existsSync(claudeMdPath)) return false;
|
|
7974
|
+
const content = fs28.readFileSync(claudeMdPath, "utf-8");
|
|
7742
7975
|
const startIdx = content.indexOf(LEARNED_START);
|
|
7743
7976
|
const endIdx = content.indexOf(LEARNED_END);
|
|
7744
7977
|
if (startIdx === -1 || endIdx === -1) return false;
|
|
7745
7978
|
const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
|
|
7746
7979
|
if (!section) return false;
|
|
7747
|
-
|
|
7980
|
+
fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
|
|
7748
7981
|
const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
|
|
7749
|
-
|
|
7982
|
+
fs28.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
|
|
7750
7983
|
return true;
|
|
7751
7984
|
}
|
|
7752
7985
|
|
|
@@ -7758,11 +7991,11 @@ function log2(quiet, ...args) {
|
|
|
7758
7991
|
function discoverGitRepos(parentDir) {
|
|
7759
7992
|
const repos = [];
|
|
7760
7993
|
try {
|
|
7761
|
-
const entries =
|
|
7994
|
+
const entries = fs30.readdirSync(parentDir, { withFileTypes: true });
|
|
7762
7995
|
for (const entry of entries) {
|
|
7763
7996
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
7764
|
-
const childPath =
|
|
7765
|
-
if (
|
|
7997
|
+
const childPath = path24.join(parentDir, entry.name);
|
|
7998
|
+
if (fs30.existsSync(path24.join(childPath, ".git"))) {
|
|
7766
7999
|
repos.push(childPath);
|
|
7767
8000
|
}
|
|
7768
8001
|
}
|
|
@@ -7772,7 +8005,7 @@ function discoverGitRepos(parentDir) {
|
|
|
7772
8005
|
}
|
|
7773
8006
|
async function refreshSingleRepo(repoDir, options) {
|
|
7774
8007
|
const quiet = !!options.quiet;
|
|
7775
|
-
const prefix = options.label ? `${
|
|
8008
|
+
const prefix = options.label ? `${chalk15.bold(options.label)} ` : "";
|
|
7776
8009
|
const state = readState();
|
|
7777
8010
|
const lastSha = state?.lastRefreshSha ?? null;
|
|
7778
8011
|
const diff = collectDiff(lastSha);
|
|
@@ -7781,7 +8014,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
7781
8014
|
if (currentSha) {
|
|
7782
8015
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
7783
8016
|
}
|
|
7784
|
-
log2(quiet,
|
|
8017
|
+
log2(quiet, chalk15.dim(`${prefix}No changes since last refresh.`));
|
|
7785
8018
|
return;
|
|
7786
8019
|
}
|
|
7787
8020
|
const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
|
|
@@ -7815,10 +8048,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
7815
8048
|
if (options.dryRun) {
|
|
7816
8049
|
spinner?.info(`${prefix}Dry run \u2014 would update:`);
|
|
7817
8050
|
for (const doc of response.docsUpdated) {
|
|
7818
|
-
console.log(` ${
|
|
8051
|
+
console.log(` ${chalk15.yellow("~")} ${doc}`);
|
|
7819
8052
|
}
|
|
7820
8053
|
if (response.changesSummary) {
|
|
7821
|
-
console.log(
|
|
8054
|
+
console.log(chalk15.dim(`
|
|
7822
8055
|
${response.changesSummary}`));
|
|
7823
8056
|
}
|
|
7824
8057
|
return;
|
|
@@ -7827,10 +8060,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
7827
8060
|
trackRefreshCompleted(written.length, Date.now());
|
|
7828
8061
|
spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
|
|
7829
8062
|
for (const file of written) {
|
|
7830
|
-
log2(quiet, ` ${
|
|
8063
|
+
log2(quiet, ` ${chalk15.green("\u2713")} ${file}`);
|
|
7831
8064
|
}
|
|
7832
8065
|
if (response.changesSummary) {
|
|
7833
|
-
log2(quiet,
|
|
8066
|
+
log2(quiet, chalk15.dim(`
|
|
7834
8067
|
${response.changesSummary}`));
|
|
7835
8068
|
}
|
|
7836
8069
|
if (currentSha) {
|
|
@@ -7847,7 +8080,7 @@ async function refreshCommand(options) {
|
|
|
7847
8080
|
const config = loadConfig();
|
|
7848
8081
|
if (!config) {
|
|
7849
8082
|
if (quiet) return;
|
|
7850
|
-
console.log(
|
|
8083
|
+
console.log(chalk15.red("No LLM provider configured. Run ") + chalk15.hex("#83D1EB")("caliber config") + chalk15.red(" (e.g. choose Cursor) or set an API key."));
|
|
7851
8084
|
throw new Error("__exit__");
|
|
7852
8085
|
}
|
|
7853
8086
|
await validateModel({ fast: true });
|
|
@@ -7858,20 +8091,20 @@ async function refreshCommand(options) {
|
|
|
7858
8091
|
const repos = discoverGitRepos(process.cwd());
|
|
7859
8092
|
if (repos.length === 0) {
|
|
7860
8093
|
if (quiet) return;
|
|
7861
|
-
console.log(
|
|
8094
|
+
console.log(chalk15.red("Not inside a git repository and no git repos found in child directories."));
|
|
7862
8095
|
throw new Error("__exit__");
|
|
7863
8096
|
}
|
|
7864
|
-
log2(quiet,
|
|
8097
|
+
log2(quiet, chalk15.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
7865
8098
|
`));
|
|
7866
8099
|
const originalDir = process.cwd();
|
|
7867
8100
|
for (const repo of repos) {
|
|
7868
|
-
const repoName =
|
|
8101
|
+
const repoName = path24.basename(repo);
|
|
7869
8102
|
try {
|
|
7870
8103
|
process.chdir(repo);
|
|
7871
8104
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
7872
8105
|
} catch (err) {
|
|
7873
8106
|
if (err instanceof Error && err.message === "__exit__") continue;
|
|
7874
|
-
log2(quiet,
|
|
8107
|
+
log2(quiet, chalk15.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
|
|
7875
8108
|
}
|
|
7876
8109
|
}
|
|
7877
8110
|
process.chdir(originalDir);
|
|
@@ -7879,13 +8112,13 @@ async function refreshCommand(options) {
|
|
|
7879
8112
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
7880
8113
|
if (quiet) return;
|
|
7881
8114
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
7882
|
-
console.log(
|
|
8115
|
+
console.log(chalk15.red(`Refresh failed: ${msg}`));
|
|
7883
8116
|
throw new Error("__exit__");
|
|
7884
8117
|
}
|
|
7885
8118
|
}
|
|
7886
8119
|
|
|
7887
8120
|
// src/commands/hooks.ts
|
|
7888
|
-
import
|
|
8121
|
+
import chalk16 from "chalk";
|
|
7889
8122
|
var HOOKS = [
|
|
7890
8123
|
{
|
|
7891
8124
|
id: "session-end",
|
|
@@ -7905,13 +8138,13 @@ var HOOKS = [
|
|
|
7905
8138
|
}
|
|
7906
8139
|
];
|
|
7907
8140
|
function printStatus() {
|
|
7908
|
-
console.log(
|
|
8141
|
+
console.log(chalk16.bold("\n Hooks\n"));
|
|
7909
8142
|
for (const hook of HOOKS) {
|
|
7910
8143
|
const installed = hook.isInstalled();
|
|
7911
|
-
const icon = installed ?
|
|
7912
|
-
const state = installed ?
|
|
8144
|
+
const icon = installed ? chalk16.green("\u2713") : chalk16.dim("\u2717");
|
|
8145
|
+
const state = installed ? chalk16.green("enabled") : chalk16.dim("disabled");
|
|
7913
8146
|
console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
|
|
7914
|
-
console.log(
|
|
8147
|
+
console.log(chalk16.dim(` ${hook.description}`));
|
|
7915
8148
|
}
|
|
7916
8149
|
console.log("");
|
|
7917
8150
|
}
|
|
@@ -7920,9 +8153,9 @@ async function hooksCommand(options) {
|
|
|
7920
8153
|
for (const hook of HOOKS) {
|
|
7921
8154
|
const result = hook.install();
|
|
7922
8155
|
if (result.alreadyInstalled) {
|
|
7923
|
-
console.log(
|
|
8156
|
+
console.log(chalk16.dim(` ${hook.label} already enabled.`));
|
|
7924
8157
|
} else {
|
|
7925
|
-
console.log(
|
|
8158
|
+
console.log(chalk16.green(" \u2713") + ` ${hook.label} enabled`);
|
|
7926
8159
|
}
|
|
7927
8160
|
}
|
|
7928
8161
|
return;
|
|
@@ -7931,9 +8164,9 @@ async function hooksCommand(options) {
|
|
|
7931
8164
|
for (const hook of HOOKS) {
|
|
7932
8165
|
const result = hook.remove();
|
|
7933
8166
|
if (result.notFound) {
|
|
7934
|
-
console.log(
|
|
8167
|
+
console.log(chalk16.dim(` ${hook.label} already disabled.`));
|
|
7935
8168
|
} else {
|
|
7936
|
-
console.log(
|
|
8169
|
+
console.log(chalk16.green(" \u2713") + ` ${hook.label} removed`);
|
|
7937
8170
|
}
|
|
7938
8171
|
}
|
|
7939
8172
|
return;
|
|
@@ -7948,18 +8181,18 @@ async function hooksCommand(options) {
|
|
|
7948
8181
|
const states = HOOKS.map((h) => h.isInstalled());
|
|
7949
8182
|
function render() {
|
|
7950
8183
|
const lines = [];
|
|
7951
|
-
lines.push(
|
|
8184
|
+
lines.push(chalk16.bold(" Hooks"));
|
|
7952
8185
|
lines.push("");
|
|
7953
8186
|
for (let i = 0; i < HOOKS.length; i++) {
|
|
7954
8187
|
const hook = HOOKS[i];
|
|
7955
8188
|
const enabled = states[i];
|
|
7956
|
-
const toggle = enabled ?
|
|
7957
|
-
const ptr = i === cursor ?
|
|
8189
|
+
const toggle = enabled ? chalk16.green("[on] ") : chalk16.dim("[off]");
|
|
8190
|
+
const ptr = i === cursor ? chalk16.cyan(">") : " ";
|
|
7958
8191
|
lines.push(` ${ptr} ${toggle} ${hook.label}`);
|
|
7959
|
-
lines.push(
|
|
8192
|
+
lines.push(chalk16.dim(` ${hook.description}`));
|
|
7960
8193
|
}
|
|
7961
8194
|
lines.push("");
|
|
7962
|
-
lines.push(
|
|
8195
|
+
lines.push(chalk16.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
|
|
7963
8196
|
return lines.join("\n");
|
|
7964
8197
|
}
|
|
7965
8198
|
function draw(initial) {
|
|
@@ -7990,16 +8223,16 @@ async function hooksCommand(options) {
|
|
|
7990
8223
|
const wantEnabled = states[i];
|
|
7991
8224
|
if (wantEnabled && !wasInstalled) {
|
|
7992
8225
|
hook.install();
|
|
7993
|
-
console.log(
|
|
8226
|
+
console.log(chalk16.green(" \u2713") + ` ${hook.label} enabled`);
|
|
7994
8227
|
changed++;
|
|
7995
8228
|
} else if (!wantEnabled && wasInstalled) {
|
|
7996
8229
|
hook.remove();
|
|
7997
|
-
console.log(
|
|
8230
|
+
console.log(chalk16.green(" \u2713") + ` ${hook.label} disabled`);
|
|
7998
8231
|
changed++;
|
|
7999
8232
|
}
|
|
8000
8233
|
}
|
|
8001
8234
|
if (changed === 0) {
|
|
8002
|
-
console.log(
|
|
8235
|
+
console.log(chalk16.dim(" No changes."));
|
|
8003
8236
|
}
|
|
8004
8237
|
console.log("");
|
|
8005
8238
|
}
|
|
@@ -8035,7 +8268,7 @@ async function hooksCommand(options) {
|
|
|
8035
8268
|
case "\x1B":
|
|
8036
8269
|
case "":
|
|
8037
8270
|
cleanup();
|
|
8038
|
-
console.log(
|
|
8271
|
+
console.log(chalk16.dim("\n Cancelled.\n"));
|
|
8039
8272
|
resolve2();
|
|
8040
8273
|
break;
|
|
8041
8274
|
}
|
|
@@ -8046,51 +8279,51 @@ async function hooksCommand(options) {
|
|
|
8046
8279
|
|
|
8047
8280
|
// src/commands/config.ts
|
|
8048
8281
|
init_config();
|
|
8049
|
-
import
|
|
8282
|
+
import chalk17 from "chalk";
|
|
8050
8283
|
async function configCommand() {
|
|
8051
8284
|
const existing = loadConfig();
|
|
8052
8285
|
if (existing) {
|
|
8053
8286
|
const displayModel = getDisplayModel(existing);
|
|
8054
8287
|
const fastModel = getFastModel();
|
|
8055
|
-
console.log(
|
|
8056
|
-
console.log(` Provider: ${
|
|
8057
|
-
console.log(` Model: ${
|
|
8288
|
+
console.log(chalk17.bold("\nCurrent Configuration\n"));
|
|
8289
|
+
console.log(` Provider: ${chalk17.cyan(existing.provider)}`);
|
|
8290
|
+
console.log(` Model: ${chalk17.cyan(displayModel)}`);
|
|
8058
8291
|
if (fastModel) {
|
|
8059
|
-
console.log(` Scan: ${
|
|
8292
|
+
console.log(` Scan: ${chalk17.cyan(fastModel)}`);
|
|
8060
8293
|
}
|
|
8061
8294
|
if (existing.apiKey) {
|
|
8062
8295
|
const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
|
|
8063
|
-
console.log(` API Key: ${
|
|
8296
|
+
console.log(` API Key: ${chalk17.dim(masked)}`);
|
|
8064
8297
|
}
|
|
8065
8298
|
if (existing.provider === "cursor") {
|
|
8066
|
-
console.log(` Seat: ${
|
|
8299
|
+
console.log(` Seat: ${chalk17.dim("Cursor (agent acp)")}`);
|
|
8067
8300
|
}
|
|
8068
8301
|
if (existing.provider === "claude-cli") {
|
|
8069
|
-
console.log(` Seat: ${
|
|
8302
|
+
console.log(` Seat: ${chalk17.dim("Claude Code (claude -p)")}`);
|
|
8070
8303
|
}
|
|
8071
8304
|
if (existing.baseUrl) {
|
|
8072
|
-
console.log(` Base URL: ${
|
|
8305
|
+
console.log(` Base URL: ${chalk17.dim(existing.baseUrl)}`);
|
|
8073
8306
|
}
|
|
8074
8307
|
if (existing.vertexProjectId) {
|
|
8075
|
-
console.log(` Vertex Project: ${
|
|
8076
|
-
console.log(` Vertex Region: ${
|
|
8308
|
+
console.log(` Vertex Project: ${chalk17.dim(existing.vertexProjectId)}`);
|
|
8309
|
+
console.log(` Vertex Region: ${chalk17.dim(existing.vertexRegion || "us-east5")}`);
|
|
8077
8310
|
}
|
|
8078
|
-
console.log(` Source: ${
|
|
8311
|
+
console.log(` Source: ${chalk17.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
|
|
8079
8312
|
console.log("");
|
|
8080
8313
|
}
|
|
8081
8314
|
await runInteractiveProviderSetup();
|
|
8082
8315
|
const updated = loadConfig();
|
|
8083
8316
|
if (updated) trackConfigProviderSet(updated.provider);
|
|
8084
|
-
console.log(
|
|
8085
|
-
console.log(
|
|
8317
|
+
console.log(chalk17.green("\n\u2713 Configuration saved"));
|
|
8318
|
+
console.log(chalk17.dim(` ${getConfigFilePath()}
|
|
8086
8319
|
`));
|
|
8087
|
-
console.log(
|
|
8088
|
-
console.log(
|
|
8320
|
+
console.log(chalk17.dim(" You can also set environment variables instead:"));
|
|
8321
|
+
console.log(chalk17.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
|
|
8089
8322
|
}
|
|
8090
8323
|
|
|
8091
8324
|
// src/commands/learn.ts
|
|
8092
|
-
import
|
|
8093
|
-
import
|
|
8325
|
+
import fs32 from "fs";
|
|
8326
|
+
import chalk18 from "chalk";
|
|
8094
8327
|
|
|
8095
8328
|
// src/learner/stdin.ts
|
|
8096
8329
|
var STDIN_TIMEOUT_MS = 5e3;
|
|
@@ -8121,8 +8354,8 @@ function readStdin() {
|
|
|
8121
8354
|
|
|
8122
8355
|
// src/learner/storage.ts
|
|
8123
8356
|
init_constants();
|
|
8124
|
-
import
|
|
8125
|
-
import
|
|
8357
|
+
import fs31 from "fs";
|
|
8358
|
+
import path25 from "path";
|
|
8126
8359
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
8127
8360
|
var DEFAULT_STATE = {
|
|
8128
8361
|
sessionId: null,
|
|
@@ -8130,15 +8363,15 @@ var DEFAULT_STATE = {
|
|
|
8130
8363
|
lastAnalysisTimestamp: null
|
|
8131
8364
|
};
|
|
8132
8365
|
function ensureLearningDir() {
|
|
8133
|
-
if (!
|
|
8134
|
-
|
|
8366
|
+
if (!fs31.existsSync(LEARNING_DIR)) {
|
|
8367
|
+
fs31.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
8135
8368
|
}
|
|
8136
8369
|
}
|
|
8137
8370
|
function sessionFilePath() {
|
|
8138
|
-
return
|
|
8371
|
+
return path25.join(LEARNING_DIR, LEARNING_SESSION_FILE);
|
|
8139
8372
|
}
|
|
8140
8373
|
function stateFilePath() {
|
|
8141
|
-
return
|
|
8374
|
+
return path25.join(LEARNING_DIR, LEARNING_STATE_FILE);
|
|
8142
8375
|
}
|
|
8143
8376
|
function truncateResponse(response) {
|
|
8144
8377
|
const str = JSON.stringify(response);
|
|
@@ -8149,29 +8382,29 @@ function appendEvent(event) {
|
|
|
8149
8382
|
ensureLearningDir();
|
|
8150
8383
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
8151
8384
|
const filePath = sessionFilePath();
|
|
8152
|
-
|
|
8385
|
+
fs31.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
8153
8386
|
const count = getEventCount();
|
|
8154
8387
|
if (count > LEARNING_MAX_EVENTS) {
|
|
8155
|
-
const lines =
|
|
8388
|
+
const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8156
8389
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
8157
|
-
|
|
8390
|
+
fs31.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
8158
8391
|
}
|
|
8159
8392
|
}
|
|
8160
8393
|
function appendPromptEvent(event) {
|
|
8161
8394
|
ensureLearningDir();
|
|
8162
8395
|
const filePath = sessionFilePath();
|
|
8163
|
-
|
|
8396
|
+
fs31.appendFileSync(filePath, JSON.stringify(event) + "\n");
|
|
8164
8397
|
const count = getEventCount();
|
|
8165
8398
|
if (count > LEARNING_MAX_EVENTS) {
|
|
8166
|
-
const lines =
|
|
8399
|
+
const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8167
8400
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
8168
|
-
|
|
8401
|
+
fs31.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
8169
8402
|
}
|
|
8170
8403
|
}
|
|
8171
8404
|
function readAllEvents() {
|
|
8172
8405
|
const filePath = sessionFilePath();
|
|
8173
|
-
if (!
|
|
8174
|
-
const lines =
|
|
8406
|
+
if (!fs31.existsSync(filePath)) return [];
|
|
8407
|
+
const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8175
8408
|
const events = [];
|
|
8176
8409
|
for (const line of lines) {
|
|
8177
8410
|
try {
|
|
@@ -8183,26 +8416,26 @@ function readAllEvents() {
|
|
|
8183
8416
|
}
|
|
8184
8417
|
function getEventCount() {
|
|
8185
8418
|
const filePath = sessionFilePath();
|
|
8186
|
-
if (!
|
|
8187
|
-
const content =
|
|
8419
|
+
if (!fs31.existsSync(filePath)) return 0;
|
|
8420
|
+
const content = fs31.readFileSync(filePath, "utf-8");
|
|
8188
8421
|
return content.split("\n").filter(Boolean).length;
|
|
8189
8422
|
}
|
|
8190
8423
|
function clearSession() {
|
|
8191
8424
|
const filePath = sessionFilePath();
|
|
8192
|
-
if (
|
|
8425
|
+
if (fs31.existsSync(filePath)) fs31.unlinkSync(filePath);
|
|
8193
8426
|
}
|
|
8194
8427
|
function readState2() {
|
|
8195
8428
|
const filePath = stateFilePath();
|
|
8196
|
-
if (!
|
|
8429
|
+
if (!fs31.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
8197
8430
|
try {
|
|
8198
|
-
return JSON.parse(
|
|
8431
|
+
return JSON.parse(fs31.readFileSync(filePath, "utf-8"));
|
|
8199
8432
|
} catch {
|
|
8200
8433
|
return { ...DEFAULT_STATE };
|
|
8201
8434
|
}
|
|
8202
8435
|
}
|
|
8203
8436
|
function writeState2(state) {
|
|
8204
8437
|
ensureLearningDir();
|
|
8205
|
-
|
|
8438
|
+
fs31.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
8206
8439
|
}
|
|
8207
8440
|
function resetState() {
|
|
8208
8441
|
writeState2({ ...DEFAULT_STATE });
|
|
@@ -8210,14 +8443,14 @@ function resetState() {
|
|
|
8210
8443
|
var LOCK_FILE2 = "finalize.lock";
|
|
8211
8444
|
var LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
8212
8445
|
function lockFilePath() {
|
|
8213
|
-
return
|
|
8446
|
+
return path25.join(LEARNING_DIR, LOCK_FILE2);
|
|
8214
8447
|
}
|
|
8215
8448
|
function acquireFinalizeLock() {
|
|
8216
8449
|
ensureLearningDir();
|
|
8217
8450
|
const lockPath = lockFilePath();
|
|
8218
|
-
if (
|
|
8451
|
+
if (fs31.existsSync(lockPath)) {
|
|
8219
8452
|
try {
|
|
8220
|
-
const stat =
|
|
8453
|
+
const stat = fs31.statSync(lockPath);
|
|
8221
8454
|
if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
|
|
8222
8455
|
return false;
|
|
8223
8456
|
}
|
|
@@ -8225,7 +8458,7 @@ function acquireFinalizeLock() {
|
|
|
8225
8458
|
}
|
|
8226
8459
|
}
|
|
8227
8460
|
try {
|
|
8228
|
-
|
|
8461
|
+
fs31.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
8229
8462
|
return true;
|
|
8230
8463
|
} catch {
|
|
8231
8464
|
return false;
|
|
@@ -8234,7 +8467,7 @@ function acquireFinalizeLock() {
|
|
|
8234
8467
|
function releaseFinalizeLock() {
|
|
8235
8468
|
const lockPath = lockFilePath();
|
|
8236
8469
|
try {
|
|
8237
|
-
if (
|
|
8470
|
+
if (fs31.existsSync(lockPath)) fs31.unlinkSync(lockPath);
|
|
8238
8471
|
} catch {
|
|
8239
8472
|
}
|
|
8240
8473
|
}
|
|
@@ -8406,26 +8639,26 @@ async function learnFinalizeCommand(options) {
|
|
|
8406
8639
|
if (!options?.force) {
|
|
8407
8640
|
const { isCaliberRunning: isCaliberRunning2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
|
|
8408
8641
|
if (isCaliberRunning2()) {
|
|
8409
|
-
console.log(
|
|
8642
|
+
console.log(chalk18.dim("caliber: skipping finalize \u2014 another caliber process is running"));
|
|
8410
8643
|
return;
|
|
8411
8644
|
}
|
|
8412
8645
|
}
|
|
8413
8646
|
if (!acquireFinalizeLock()) {
|
|
8414
|
-
console.log(
|
|
8647
|
+
console.log(chalk18.dim("caliber: skipping finalize \u2014 another finalize is in progress"));
|
|
8415
8648
|
return;
|
|
8416
8649
|
}
|
|
8417
8650
|
let analyzed = false;
|
|
8418
8651
|
try {
|
|
8419
8652
|
const config = loadConfig();
|
|
8420
8653
|
if (!config) {
|
|
8421
|
-
console.log(
|
|
8654
|
+
console.log(chalk18.yellow("caliber: no LLM provider configured \u2014 run `caliber config` first"));
|
|
8422
8655
|
clearSession();
|
|
8423
8656
|
resetState();
|
|
8424
8657
|
return;
|
|
8425
8658
|
}
|
|
8426
8659
|
const events = readAllEvents();
|
|
8427
8660
|
if (events.length < MIN_EVENTS_FOR_ANALYSIS) {
|
|
8428
|
-
console.log(
|
|
8661
|
+
console.log(chalk18.dim(`caliber: ${events.length}/${MIN_EVENTS_FOR_ANALYSIS} events recorded \u2014 need more before analysis`));
|
|
8429
8662
|
return;
|
|
8430
8663
|
}
|
|
8431
8664
|
await validateModel({ fast: true });
|
|
@@ -8446,15 +8679,15 @@ async function learnFinalizeCommand(options) {
|
|
|
8446
8679
|
skills: response.skills
|
|
8447
8680
|
});
|
|
8448
8681
|
if (result.newItemCount > 0) {
|
|
8449
|
-
console.log(
|
|
8682
|
+
console.log(chalk18.dim(`caliber: learned ${result.newItemCount} new pattern${result.newItemCount === 1 ? "" : "s"}`));
|
|
8450
8683
|
for (const item of result.newItems) {
|
|
8451
|
-
console.log(
|
|
8684
|
+
console.log(chalk18.dim(` + ${item.replace(/^- /, "").slice(0, 80)}`));
|
|
8452
8685
|
}
|
|
8453
8686
|
}
|
|
8454
8687
|
}
|
|
8455
8688
|
} catch (err) {
|
|
8456
8689
|
if (options?.force) {
|
|
8457
|
-
console.error(
|
|
8690
|
+
console.error(chalk18.red("caliber: finalize failed \u2014"), err instanceof Error ? err.message : err);
|
|
8458
8691
|
}
|
|
8459
8692
|
} finally {
|
|
8460
8693
|
if (analyzed) {
|
|
@@ -8466,48 +8699,48 @@ async function learnFinalizeCommand(options) {
|
|
|
8466
8699
|
}
|
|
8467
8700
|
async function learnInstallCommand() {
|
|
8468
8701
|
let anyInstalled = false;
|
|
8469
|
-
if (
|
|
8702
|
+
if (fs32.existsSync(".claude")) {
|
|
8470
8703
|
const r = installLearningHooks();
|
|
8471
8704
|
if (r.installed) {
|
|
8472
|
-
console.log(
|
|
8705
|
+
console.log(chalk18.green("\u2713") + " Claude Code learning hooks installed");
|
|
8473
8706
|
anyInstalled = true;
|
|
8474
8707
|
} else if (r.alreadyInstalled) {
|
|
8475
|
-
console.log(
|
|
8708
|
+
console.log(chalk18.dim(" Claude Code hooks already installed"));
|
|
8476
8709
|
}
|
|
8477
8710
|
}
|
|
8478
|
-
if (
|
|
8711
|
+
if (fs32.existsSync(".cursor")) {
|
|
8479
8712
|
const r = installCursorLearningHooks();
|
|
8480
8713
|
if (r.installed) {
|
|
8481
|
-
console.log(
|
|
8714
|
+
console.log(chalk18.green("\u2713") + " Cursor learning hooks installed");
|
|
8482
8715
|
anyInstalled = true;
|
|
8483
8716
|
} else if (r.alreadyInstalled) {
|
|
8484
|
-
console.log(
|
|
8717
|
+
console.log(chalk18.dim(" Cursor hooks already installed"));
|
|
8485
8718
|
}
|
|
8486
8719
|
}
|
|
8487
|
-
if (!
|
|
8488
|
-
console.log(
|
|
8489
|
-
console.log(
|
|
8720
|
+
if (!fs32.existsSync(".claude") && !fs32.existsSync(".cursor")) {
|
|
8721
|
+
console.log(chalk18.yellow("No .claude/ or .cursor/ directory found."));
|
|
8722
|
+
console.log(chalk18.dim(" Run `caliber init` first, or create the directory manually."));
|
|
8490
8723
|
return;
|
|
8491
8724
|
}
|
|
8492
8725
|
if (anyInstalled) {
|
|
8493
|
-
console.log(
|
|
8494
|
-
console.log(
|
|
8726
|
+
console.log(chalk18.dim(` Tool usage will be recorded and learnings extracted after \u2265${MIN_EVENTS_FOR_ANALYSIS} events.`));
|
|
8727
|
+
console.log(chalk18.dim(" Learnings written to CALIBER_LEARNINGS.md."));
|
|
8495
8728
|
}
|
|
8496
8729
|
}
|
|
8497
8730
|
async function learnRemoveCommand() {
|
|
8498
8731
|
let anyRemoved = false;
|
|
8499
8732
|
const r1 = removeLearningHooks();
|
|
8500
8733
|
if (r1.removed) {
|
|
8501
|
-
console.log(
|
|
8734
|
+
console.log(chalk18.green("\u2713") + " Claude Code learning hooks removed");
|
|
8502
8735
|
anyRemoved = true;
|
|
8503
8736
|
}
|
|
8504
8737
|
const r2 = removeCursorLearningHooks();
|
|
8505
8738
|
if (r2.removed) {
|
|
8506
|
-
console.log(
|
|
8739
|
+
console.log(chalk18.green("\u2713") + " Cursor learning hooks removed");
|
|
8507
8740
|
anyRemoved = true;
|
|
8508
8741
|
}
|
|
8509
8742
|
if (!anyRemoved) {
|
|
8510
|
-
console.log(
|
|
8743
|
+
console.log(chalk18.dim("No learning hooks found."));
|
|
8511
8744
|
}
|
|
8512
8745
|
}
|
|
8513
8746
|
async function learnStatusCommand() {
|
|
@@ -8515,41 +8748,41 @@ async function learnStatusCommand() {
|
|
|
8515
8748
|
const cursorInstalled = areCursorLearningHooksInstalled();
|
|
8516
8749
|
const state = readState2();
|
|
8517
8750
|
const eventCount = getEventCount();
|
|
8518
|
-
console.log(
|
|
8751
|
+
console.log(chalk18.bold("Session Learning Status"));
|
|
8519
8752
|
console.log();
|
|
8520
8753
|
if (claudeInstalled) {
|
|
8521
|
-
console.log(
|
|
8754
|
+
console.log(chalk18.green("\u2713") + " Claude Code hooks " + chalk18.green("installed"));
|
|
8522
8755
|
} else {
|
|
8523
|
-
console.log(
|
|
8756
|
+
console.log(chalk18.dim("\u2717") + " Claude Code hooks " + chalk18.dim("not installed"));
|
|
8524
8757
|
}
|
|
8525
8758
|
if (cursorInstalled) {
|
|
8526
|
-
console.log(
|
|
8759
|
+
console.log(chalk18.green("\u2713") + " Cursor hooks " + chalk18.green("installed"));
|
|
8527
8760
|
} else {
|
|
8528
|
-
console.log(
|
|
8761
|
+
console.log(chalk18.dim("\u2717") + " Cursor hooks " + chalk18.dim("not installed"));
|
|
8529
8762
|
}
|
|
8530
8763
|
if (!claudeInstalled && !cursorInstalled) {
|
|
8531
|
-
console.log(
|
|
8764
|
+
console.log(chalk18.dim(" Run `caliber learn install` to enable session learning."));
|
|
8532
8765
|
}
|
|
8533
8766
|
console.log();
|
|
8534
|
-
console.log(`Events recorded: ${
|
|
8535
|
-
console.log(`Threshold for analysis: ${
|
|
8767
|
+
console.log(`Events recorded: ${chalk18.cyan(String(eventCount))}`);
|
|
8768
|
+
console.log(`Threshold for analysis: ${chalk18.cyan(String(MIN_EVENTS_FOR_ANALYSIS))}`);
|
|
8536
8769
|
if (state.lastAnalysisTimestamp) {
|
|
8537
|
-
console.log(`Last analysis: ${
|
|
8770
|
+
console.log(`Last analysis: ${chalk18.cyan(state.lastAnalysisTimestamp)}`);
|
|
8538
8771
|
} else {
|
|
8539
|
-
console.log(`Last analysis: ${
|
|
8772
|
+
console.log(`Last analysis: ${chalk18.dim("none")}`);
|
|
8540
8773
|
}
|
|
8541
8774
|
const learnedSection = readLearnedSection();
|
|
8542
8775
|
if (learnedSection) {
|
|
8543
8776
|
const lineCount = learnedSection.split("\n").filter(Boolean).length;
|
|
8544
8777
|
console.log(`
|
|
8545
|
-
Learned items in CALIBER_LEARNINGS.md: ${
|
|
8778
|
+
Learned items in CALIBER_LEARNINGS.md: ${chalk18.cyan(String(lineCount))}`);
|
|
8546
8779
|
}
|
|
8547
8780
|
}
|
|
8548
8781
|
|
|
8549
8782
|
// src/cli.ts
|
|
8550
|
-
var __dirname =
|
|
8783
|
+
var __dirname = path26.dirname(fileURLToPath(import.meta.url));
|
|
8551
8784
|
var pkg = JSON.parse(
|
|
8552
|
-
|
|
8785
|
+
fs33.readFileSync(path26.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
8553
8786
|
);
|
|
8554
8787
|
var program = new Command();
|
|
8555
8788
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
@@ -8623,22 +8856,42 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
|
|
|
8623
8856
|
learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
|
|
8624
8857
|
|
|
8625
8858
|
// src/utils/version-check.ts
|
|
8626
|
-
import
|
|
8627
|
-
import
|
|
8859
|
+
import fs34 from "fs";
|
|
8860
|
+
import path27 from "path";
|
|
8628
8861
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8629
8862
|
import { execSync as execSync14 } from "child_process";
|
|
8630
|
-
import
|
|
8863
|
+
import chalk19 from "chalk";
|
|
8631
8864
|
import ora6 from "ora";
|
|
8632
8865
|
import confirm2 from "@inquirer/confirm";
|
|
8633
|
-
var __dirname_vc =
|
|
8866
|
+
var __dirname_vc = path27.dirname(fileURLToPath2(import.meta.url));
|
|
8634
8867
|
var pkg2 = JSON.parse(
|
|
8635
|
-
|
|
8868
|
+
fs34.readFileSync(path27.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
8636
8869
|
);
|
|
8870
|
+
function getChannel(version) {
|
|
8871
|
+
const match = version.match(/-(dev|next)\./);
|
|
8872
|
+
return match ? match[1] : "latest";
|
|
8873
|
+
}
|
|
8874
|
+
function isNewer(registry, current) {
|
|
8875
|
+
const parse = (v) => {
|
|
8876
|
+
const [core, pre] = v.split("-");
|
|
8877
|
+
const parts = core.split(".").map(Number);
|
|
8878
|
+
return { major: parts[0], minor: parts[1], patch: parts[2], pre };
|
|
8879
|
+
};
|
|
8880
|
+
const r = parse(registry);
|
|
8881
|
+
const c = parse(current);
|
|
8882
|
+
if (r.major !== c.major) return r.major > c.major;
|
|
8883
|
+
if (r.minor !== c.minor) return r.minor > c.minor;
|
|
8884
|
+
if (r.patch !== c.patch) return r.patch > c.patch;
|
|
8885
|
+
if (!r.pre && c.pre) return true;
|
|
8886
|
+
if (r.pre && !c.pre) return false;
|
|
8887
|
+
if (r.pre && c.pre) return r.pre > c.pre;
|
|
8888
|
+
return false;
|
|
8889
|
+
}
|
|
8637
8890
|
function getInstalledVersion() {
|
|
8638
8891
|
try {
|
|
8639
8892
|
const globalRoot = execSync14("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
8640
|
-
const pkgPath =
|
|
8641
|
-
return JSON.parse(
|
|
8893
|
+
const pkgPath = path27.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
8894
|
+
return JSON.parse(fs34.readFileSync(pkgPath, "utf-8")).version;
|
|
8642
8895
|
} catch {
|
|
8643
8896
|
return null;
|
|
8644
8897
|
}
|
|
@@ -8646,9 +8899,11 @@ function getInstalledVersion() {
|
|
|
8646
8899
|
async function checkForUpdates() {
|
|
8647
8900
|
if (process.env.CALIBER_SKIP_UPDATE_CHECK) return;
|
|
8648
8901
|
try {
|
|
8902
|
+
const current = pkg2.version;
|
|
8903
|
+
const channel = getChannel(current);
|
|
8649
8904
|
const controller = new AbortController();
|
|
8650
8905
|
const timeout = setTimeout(() => controller.abort(), 2e3);
|
|
8651
|
-
const res = await fetch(
|
|
8906
|
+
const res = await fetch(`https://registry.npmjs.org/@rely-ai/caliber/${channel}`, {
|
|
8652
8907
|
signal: controller.signal
|
|
8653
8908
|
});
|
|
8654
8909
|
clearTimeout(timeout);
|
|
@@ -8656,22 +8911,22 @@ async function checkForUpdates() {
|
|
|
8656
8911
|
const data = await res.json();
|
|
8657
8912
|
const latest = data.version;
|
|
8658
8913
|
if (!latest) return;
|
|
8659
|
-
|
|
8660
|
-
if (current === latest) return;
|
|
8914
|
+
if (!isNewer(latest, current)) return;
|
|
8661
8915
|
const isInteractive = process.stdin.isTTY === true;
|
|
8662
8916
|
if (!isInteractive) {
|
|
8917
|
+
const installTag = channel === "latest" ? "" : `@${channel}`;
|
|
8663
8918
|
console.log(
|
|
8664
|
-
|
|
8919
|
+
chalk19.yellow(
|
|
8665
8920
|
`
|
|
8666
8921
|
Update available: ${current} -> ${latest}
|
|
8667
|
-
Run ${
|
|
8922
|
+
Run ${chalk19.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
|
|
8668
8923
|
`
|
|
8669
8924
|
)
|
|
8670
8925
|
);
|
|
8671
8926
|
return;
|
|
8672
8927
|
}
|
|
8673
8928
|
console.log(
|
|
8674
|
-
|
|
8929
|
+
chalk19.yellow(`
|
|
8675
8930
|
Update available: ${current} -> ${latest}`)
|
|
8676
8931
|
);
|
|
8677
8932
|
const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
|
|
@@ -8679,9 +8934,10 @@ Update available: ${current} -> ${latest}`)
|
|
|
8679
8934
|
console.log();
|
|
8680
8935
|
return;
|
|
8681
8936
|
}
|
|
8937
|
+
const tag = channel === "latest" ? latest : channel;
|
|
8682
8938
|
const spinner = ora6("Updating caliber...").start();
|
|
8683
8939
|
try {
|
|
8684
|
-
execSync14(`npm install -g @rely-ai/caliber@${
|
|
8940
|
+
execSync14(`npm install -g @rely-ai/caliber@${tag}`, {
|
|
8685
8941
|
stdio: "pipe",
|
|
8686
8942
|
timeout: 12e4,
|
|
8687
8943
|
env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
|
|
@@ -8689,13 +8945,13 @@ Update available: ${current} -> ${latest}`)
|
|
|
8689
8945
|
const installed = getInstalledVersion();
|
|
8690
8946
|
if (installed !== latest) {
|
|
8691
8947
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
8692
|
-
console.log(
|
|
8948
|
+
console.log(chalk19.yellow(`Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
|
|
8693
8949
|
`));
|
|
8694
8950
|
return;
|
|
8695
8951
|
}
|
|
8696
|
-
spinner.succeed(
|
|
8952
|
+
spinner.succeed(chalk19.green(`Updated to ${latest}`));
|
|
8697
8953
|
const args = process.argv.slice(2);
|
|
8698
|
-
console.log(
|
|
8954
|
+
console.log(chalk19.dim(`
|
|
8699
8955
|
Restarting: caliber ${args.join(" ")}
|
|
8700
8956
|
`));
|
|
8701
8957
|
execSync14(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
@@ -8708,11 +8964,11 @@ Restarting: caliber ${args.join(" ")}
|
|
|
8708
8964
|
if (err instanceof Error) {
|
|
8709
8965
|
const stderr = err.stderr;
|
|
8710
8966
|
const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
|
|
8711
|
-
if (errMsg && !errMsg.includes("SIGTERM")) console.log(
|
|
8967
|
+
if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk19.dim(` ${errMsg}`));
|
|
8712
8968
|
}
|
|
8713
8969
|
console.log(
|
|
8714
|
-
|
|
8715
|
-
`Run ${
|
|
8970
|
+
chalk19.yellow(
|
|
8971
|
+
`Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually to upgrade.
|
|
8716
8972
|
`
|
|
8717
8973
|
)
|
|
8718
8974
|
);
|