@rely-ai/caliber 1.6.1 → 1.7.1
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 +945 -508
- package/package.json +3 -2
package/dist/bin.js
CHANGED
|
@@ -20,6 +20,120 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
20
20
|
};
|
|
21
21
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
22
|
|
|
23
|
+
// src/llm/config.ts
|
|
24
|
+
var config_exports = {};
|
|
25
|
+
__export(config_exports, {
|
|
26
|
+
DEFAULT_FAST_MODELS: () => DEFAULT_FAST_MODELS,
|
|
27
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
28
|
+
getConfigFilePath: () => getConfigFilePath,
|
|
29
|
+
getFastModel: () => getFastModel,
|
|
30
|
+
loadConfig: () => loadConfig,
|
|
31
|
+
readConfigFile: () => readConfigFile,
|
|
32
|
+
resolveFromEnv: () => resolveFromEnv,
|
|
33
|
+
writeConfigFile: () => writeConfigFile
|
|
34
|
+
});
|
|
35
|
+
import fs4 from "fs";
|
|
36
|
+
import path4 from "path";
|
|
37
|
+
import os from "os";
|
|
38
|
+
function loadConfig() {
|
|
39
|
+
const envConfig = resolveFromEnv();
|
|
40
|
+
if (envConfig) return envConfig;
|
|
41
|
+
return readConfigFile();
|
|
42
|
+
}
|
|
43
|
+
function resolveFromEnv() {
|
|
44
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
45
|
+
return {
|
|
46
|
+
provider: "anthropic",
|
|
47
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
48
|
+
model: process.env.CALIBER_MODEL || DEFAULT_MODELS.anthropic
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID) {
|
|
52
|
+
return {
|
|
53
|
+
provider: "vertex",
|
|
54
|
+
model: process.env.CALIBER_MODEL || DEFAULT_MODELS.vertex,
|
|
55
|
+
vertexProjectId: process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID,
|
|
56
|
+
vertexRegion: process.env.VERTEX_REGION || process.env.GCP_REGION || "us-east5",
|
|
57
|
+
vertexCredentials: process.env.VERTEX_SA_CREDENTIALS || process.env.GOOGLE_APPLICATION_CREDENTIALS
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (process.env.OPENAI_API_KEY) {
|
|
61
|
+
return {
|
|
62
|
+
provider: "openai",
|
|
63
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
64
|
+
model: process.env.CALIBER_MODEL || DEFAULT_MODELS.openai,
|
|
65
|
+
baseUrl: process.env.OPENAI_BASE_URL
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (process.env.CALIBER_USE_CURSOR_SEAT === "1" || process.env.CALIBER_USE_CURSOR_SEAT === "true") {
|
|
69
|
+
return {
|
|
70
|
+
provider: "cursor",
|
|
71
|
+
model: DEFAULT_MODELS.cursor
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (process.env.CALIBER_USE_CLAUDE_CLI === "1" || process.env.CALIBER_USE_CLAUDE_CLI === "true") {
|
|
75
|
+
return {
|
|
76
|
+
provider: "claude-cli",
|
|
77
|
+
model: DEFAULT_MODELS["claude-cli"]
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function readConfigFile() {
|
|
83
|
+
try {
|
|
84
|
+
if (!fs4.existsSync(CONFIG_FILE)) return null;
|
|
85
|
+
const raw = fs4.readFileSync(CONFIG_FILE, "utf-8");
|
|
86
|
+
const parsed = JSON.parse(raw);
|
|
87
|
+
if (!parsed.provider || !["anthropic", "vertex", "openai", "cursor", "claude-cli"].includes(parsed.provider)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return parsed;
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function writeConfigFile(config) {
|
|
96
|
+
if (!fs4.existsSync(CONFIG_DIR)) {
|
|
97
|
+
fs4.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
const sanitized = { ...config };
|
|
100
|
+
if (sanitized.apiKey) {
|
|
101
|
+
sanitized.apiKey = sanitized.apiKey.trim();
|
|
102
|
+
}
|
|
103
|
+
fs4.writeFileSync(CONFIG_FILE, JSON.stringify(sanitized, null, 2) + "\n", { mode: 384 });
|
|
104
|
+
}
|
|
105
|
+
function getConfigFilePath() {
|
|
106
|
+
return CONFIG_FILE;
|
|
107
|
+
}
|
|
108
|
+
function getFastModel() {
|
|
109
|
+
if (process.env.CALIBER_FAST_MODEL) return process.env.CALIBER_FAST_MODEL;
|
|
110
|
+
if (process.env.ANTHROPIC_SMALL_FAST_MODEL) return process.env.ANTHROPIC_SMALL_FAST_MODEL;
|
|
111
|
+
const config = loadConfig();
|
|
112
|
+
if (config?.fastModel) return config.fastModel;
|
|
113
|
+
if (config?.provider) return DEFAULT_FAST_MODELS[config.provider];
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, DEFAULT_FAST_MODELS;
|
|
117
|
+
var init_config = __esm({
|
|
118
|
+
"src/llm/config.ts"() {
|
|
119
|
+
"use strict";
|
|
120
|
+
CONFIG_DIR = path4.join(os.homedir(), ".caliber");
|
|
121
|
+
CONFIG_FILE = path4.join(CONFIG_DIR, "config.json");
|
|
122
|
+
DEFAULT_MODELS = {
|
|
123
|
+
anthropic: "claude-sonnet-4-6",
|
|
124
|
+
vertex: "claude-sonnet-4-6",
|
|
125
|
+
openai: "gpt-4.1",
|
|
126
|
+
cursor: "default",
|
|
127
|
+
"claude-cli": "default"
|
|
128
|
+
};
|
|
129
|
+
DEFAULT_FAST_MODELS = {
|
|
130
|
+
anthropic: "claude-haiku-4-5-20251001",
|
|
131
|
+
vertex: "claude-haiku-4-5-20251001",
|
|
132
|
+
openai: "gpt-4.1-mini"
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
23
137
|
// src/constants.ts
|
|
24
138
|
var constants_exports = {};
|
|
25
139
|
__export(constants_exports, {
|
|
@@ -51,17 +165,17 @@ var init_constants = __esm({
|
|
|
51
165
|
|
|
52
166
|
// src/cli.ts
|
|
53
167
|
import { Command } from "commander";
|
|
54
|
-
import
|
|
55
|
-
import
|
|
168
|
+
import fs28 from "fs";
|
|
169
|
+
import path22 from "path";
|
|
56
170
|
import { fileURLToPath } from "url";
|
|
57
171
|
|
|
58
172
|
// src/commands/onboard.ts
|
|
59
|
-
import
|
|
173
|
+
import chalk8 from "chalk";
|
|
60
174
|
import ora2 from "ora";
|
|
61
175
|
import readline3 from "readline";
|
|
62
|
-
import
|
|
176
|
+
import select5 from "@inquirer/select";
|
|
63
177
|
import checkbox from "@inquirer/checkbox";
|
|
64
|
-
import
|
|
178
|
+
import fs22 from "fs";
|
|
65
179
|
|
|
66
180
|
// src/fingerprint/index.ts
|
|
67
181
|
import fs6 from "fs";
|
|
@@ -507,102 +621,8 @@ function estimateSummarySize(summary) {
|
|
|
507
621
|
return summary.path.length + summary.imports.reduce((s, i) => s + i.length, 0) + summary.exports.reduce((s, e) => s + e.length, 0) + summary.functions.reduce((s, f) => s + f.length, 0) + summary.classes.reduce((s, c) => s + c.length, 0) + summary.types.reduce((s, t) => s + t.length, 0) + summary.routes.reduce((s, r) => s + r.length, 0);
|
|
508
622
|
}
|
|
509
623
|
|
|
510
|
-
// src/llm/
|
|
511
|
-
|
|
512
|
-
import path4 from "path";
|
|
513
|
-
import os from "os";
|
|
514
|
-
var CONFIG_DIR = path4.join(os.homedir(), ".caliber");
|
|
515
|
-
var CONFIG_FILE = path4.join(CONFIG_DIR, "config.json");
|
|
516
|
-
var DEFAULT_MODELS = {
|
|
517
|
-
anthropic: "claude-sonnet-4-6",
|
|
518
|
-
vertex: "claude-sonnet-4-6",
|
|
519
|
-
openai: "gpt-4.1",
|
|
520
|
-
cursor: "default",
|
|
521
|
-
"claude-cli": "default"
|
|
522
|
-
};
|
|
523
|
-
var DEFAULT_FAST_MODELS = {
|
|
524
|
-
anthropic: "claude-haiku-4-5-20251001",
|
|
525
|
-
vertex: "claude-haiku-4-5-20251001",
|
|
526
|
-
openai: "gpt-4.1-mini"
|
|
527
|
-
};
|
|
528
|
-
function loadConfig() {
|
|
529
|
-
const envConfig = resolveFromEnv();
|
|
530
|
-
if (envConfig) return envConfig;
|
|
531
|
-
return readConfigFile();
|
|
532
|
-
}
|
|
533
|
-
function resolveFromEnv() {
|
|
534
|
-
if (process.env.ANTHROPIC_API_KEY) {
|
|
535
|
-
return {
|
|
536
|
-
provider: "anthropic",
|
|
537
|
-
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
538
|
-
model: process.env.CALIBER_MODEL || DEFAULT_MODELS.anthropic
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
if (process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID) {
|
|
542
|
-
return {
|
|
543
|
-
provider: "vertex",
|
|
544
|
-
model: process.env.CALIBER_MODEL || DEFAULT_MODELS.vertex,
|
|
545
|
-
vertexProjectId: process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID,
|
|
546
|
-
vertexRegion: process.env.VERTEX_REGION || process.env.GCP_REGION || "us-east5",
|
|
547
|
-
vertexCredentials: process.env.VERTEX_SA_CREDENTIALS || process.env.GOOGLE_APPLICATION_CREDENTIALS
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
if (process.env.OPENAI_API_KEY) {
|
|
551
|
-
return {
|
|
552
|
-
provider: "openai",
|
|
553
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
554
|
-
model: process.env.CALIBER_MODEL || DEFAULT_MODELS.openai,
|
|
555
|
-
baseUrl: process.env.OPENAI_BASE_URL
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
if (process.env.CALIBER_USE_CURSOR_SEAT === "1" || process.env.CALIBER_USE_CURSOR_SEAT === "true") {
|
|
559
|
-
return {
|
|
560
|
-
provider: "cursor",
|
|
561
|
-
model: DEFAULT_MODELS.cursor
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
if (process.env.CALIBER_USE_CLAUDE_CLI === "1" || process.env.CALIBER_USE_CLAUDE_CLI === "true") {
|
|
565
|
-
return {
|
|
566
|
-
provider: "claude-cli",
|
|
567
|
-
model: DEFAULT_MODELS["claude-cli"]
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
return null;
|
|
571
|
-
}
|
|
572
|
-
function readConfigFile() {
|
|
573
|
-
try {
|
|
574
|
-
if (!fs4.existsSync(CONFIG_FILE)) return null;
|
|
575
|
-
const raw = fs4.readFileSync(CONFIG_FILE, "utf-8");
|
|
576
|
-
const parsed = JSON.parse(raw);
|
|
577
|
-
if (!parsed.provider || !["anthropic", "vertex", "openai", "cursor", "claude-cli"].includes(parsed.provider)) {
|
|
578
|
-
return null;
|
|
579
|
-
}
|
|
580
|
-
return parsed;
|
|
581
|
-
} catch {
|
|
582
|
-
return null;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
function writeConfigFile(config) {
|
|
586
|
-
if (!fs4.existsSync(CONFIG_DIR)) {
|
|
587
|
-
fs4.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
588
|
-
}
|
|
589
|
-
const sanitized = { ...config };
|
|
590
|
-
if (sanitized.apiKey) {
|
|
591
|
-
sanitized.apiKey = sanitized.apiKey.trim();
|
|
592
|
-
}
|
|
593
|
-
fs4.writeFileSync(CONFIG_FILE, JSON.stringify(sanitized, null, 2) + "\n", { mode: 384 });
|
|
594
|
-
}
|
|
595
|
-
function getConfigFilePath() {
|
|
596
|
-
return CONFIG_FILE;
|
|
597
|
-
}
|
|
598
|
-
function getFastModel() {
|
|
599
|
-
if (process.env.CALIBER_FAST_MODEL) return process.env.CALIBER_FAST_MODEL;
|
|
600
|
-
if (process.env.ANTHROPIC_SMALL_FAST_MODEL) return process.env.ANTHROPIC_SMALL_FAST_MODEL;
|
|
601
|
-
const config = loadConfig();
|
|
602
|
-
if (config?.fastModel) return config.fastModel;
|
|
603
|
-
if (config?.provider) return DEFAULT_FAST_MODELS[config.provider];
|
|
604
|
-
return void 0;
|
|
605
|
-
}
|
|
624
|
+
// src/llm/index.ts
|
|
625
|
+
init_config();
|
|
606
626
|
|
|
607
627
|
// src/llm/anthropic.ts
|
|
608
628
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -623,6 +643,14 @@ var AnthropicProvider = class {
|
|
|
623
643
|
const block = response.content[0];
|
|
624
644
|
return block.type === "text" ? block.text : "";
|
|
625
645
|
}
|
|
646
|
+
async listModels() {
|
|
647
|
+
const models = [];
|
|
648
|
+
const page = await this.client.models.list({ limit: 100 });
|
|
649
|
+
for (const model of page.data) {
|
|
650
|
+
models.push(model.id);
|
|
651
|
+
}
|
|
652
|
+
return models;
|
|
653
|
+
}
|
|
626
654
|
async stream(options, callbacks) {
|
|
627
655
|
const messages = options.messages ? [
|
|
628
656
|
...options.messages.map((msg) => ({
|
|
@@ -743,6 +771,13 @@ var OpenAICompatProvider = class {
|
|
|
743
771
|
});
|
|
744
772
|
return response.choices[0]?.message?.content || "";
|
|
745
773
|
}
|
|
774
|
+
async listModels() {
|
|
775
|
+
const models = [];
|
|
776
|
+
for await (const model of this.client.models.list()) {
|
|
777
|
+
models.push(model.id);
|
|
778
|
+
}
|
|
779
|
+
return models;
|
|
780
|
+
}
|
|
746
781
|
async stream(options, callbacks) {
|
|
747
782
|
const messages = [
|
|
748
783
|
{ role: "system", content: options.system }
|
|
@@ -1108,7 +1143,108 @@ function estimateTokens(text) {
|
|
|
1108
1143
|
return Math.ceil(text.length / 4);
|
|
1109
1144
|
}
|
|
1110
1145
|
|
|
1146
|
+
// src/llm/model-recovery.ts
|
|
1147
|
+
init_config();
|
|
1148
|
+
import chalk from "chalk";
|
|
1149
|
+
import select from "@inquirer/select";
|
|
1150
|
+
var KNOWN_MODELS = {
|
|
1151
|
+
anthropic: [
|
|
1152
|
+
"claude-sonnet-4-6",
|
|
1153
|
+
"claude-sonnet-4-5-20250514",
|
|
1154
|
+
"claude-haiku-4-5-20251001",
|
|
1155
|
+
"claude-opus-4-6",
|
|
1156
|
+
"claude-opus-4-1-20250620"
|
|
1157
|
+
],
|
|
1158
|
+
vertex: [
|
|
1159
|
+
"claude-sonnet-4-6@20250514",
|
|
1160
|
+
"claude-sonnet-4-5-20250514",
|
|
1161
|
+
"claude-haiku-4-5-20251001",
|
|
1162
|
+
"claude-opus-4-6@20250605",
|
|
1163
|
+
"claude-opus-4-1-20250620"
|
|
1164
|
+
],
|
|
1165
|
+
openai: [
|
|
1166
|
+
"gpt-4.1",
|
|
1167
|
+
"gpt-4.1-mini",
|
|
1168
|
+
"gpt-4o",
|
|
1169
|
+
"gpt-4o-mini",
|
|
1170
|
+
"o3-mini"
|
|
1171
|
+
],
|
|
1172
|
+
cursor: [],
|
|
1173
|
+
"claude-cli": []
|
|
1174
|
+
};
|
|
1175
|
+
function isModelNotAvailableError(error) {
|
|
1176
|
+
const msg = error.message.toLowerCase();
|
|
1177
|
+
const status = error.status;
|
|
1178
|
+
if (status === 404 && msg.includes("model")) return true;
|
|
1179
|
+
if (msg.includes("model") && (msg.includes("not found") || msg.includes("not_found"))) return true;
|
|
1180
|
+
if (msg.includes("model") && msg.includes("not available")) return true;
|
|
1181
|
+
if (msg.includes("model") && msg.includes("does not exist")) return true;
|
|
1182
|
+
if (msg.includes("publisher model")) return true;
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
function filterRelevantModels(models, provider) {
|
|
1186
|
+
switch (provider) {
|
|
1187
|
+
case "anthropic":
|
|
1188
|
+
case "vertex":
|
|
1189
|
+
return models.filter((m) => m.startsWith("claude-"));
|
|
1190
|
+
case "openai":
|
|
1191
|
+
return models.filter(
|
|
1192
|
+
(m) => m.startsWith("gpt-4") || m.startsWith("gpt-3.5") || m.startsWith("o1") || m.startsWith("o3")
|
|
1193
|
+
);
|
|
1194
|
+
default:
|
|
1195
|
+
return models;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
async function handleModelNotAvailable(failedModel, provider, config) {
|
|
1199
|
+
if (!process.stdin.isTTY) {
|
|
1200
|
+
console.error(
|
|
1201
|
+
chalk.red(`Model "${failedModel}" is not available. Run \`caliber config\` to select a different model.`)
|
|
1202
|
+
);
|
|
1203
|
+
return null;
|
|
1204
|
+
}
|
|
1205
|
+
console.log(chalk.yellow(`
|
|
1206
|
+
\u26A0 Model "${failedModel}" is not available on your ${config.provider} deployment.`));
|
|
1207
|
+
let models = [];
|
|
1208
|
+
if (provider.listModels) {
|
|
1209
|
+
try {
|
|
1210
|
+
const allModels = await provider.listModels();
|
|
1211
|
+
models = filterRelevantModels(allModels, config.provider);
|
|
1212
|
+
} catch {
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
if (models.length === 0) {
|
|
1216
|
+
models = KNOWN_MODELS[config.provider] ?? [];
|
|
1217
|
+
}
|
|
1218
|
+
models = models.filter((m) => m !== failedModel);
|
|
1219
|
+
if (models.length === 0) {
|
|
1220
|
+
console.log(chalk.red(" No alternative models found. Run `caliber config` to configure manually."));
|
|
1221
|
+
return null;
|
|
1222
|
+
}
|
|
1223
|
+
console.log("");
|
|
1224
|
+
let selected;
|
|
1225
|
+
try {
|
|
1226
|
+
selected = await select({
|
|
1227
|
+
message: "Pick an available model",
|
|
1228
|
+
choices: models.map((m) => ({ name: m, value: m }))
|
|
1229
|
+
});
|
|
1230
|
+
} catch {
|
|
1231
|
+
return null;
|
|
1232
|
+
}
|
|
1233
|
+
const isDefaultModel = failedModel === config.model;
|
|
1234
|
+
const updatedConfig = isDefaultModel ? { ...config, model: selected } : { ...config, fastModel: selected };
|
|
1235
|
+
writeConfigFile(updatedConfig);
|
|
1236
|
+
if (isDefaultModel) {
|
|
1237
|
+
process.env.CALIBER_MODEL = selected;
|
|
1238
|
+
} else {
|
|
1239
|
+
process.env.CALIBER_FAST_MODEL = selected;
|
|
1240
|
+
}
|
|
1241
|
+
console.log(chalk.green(`\u2713 Switched to ${selected}
|
|
1242
|
+
`));
|
|
1243
|
+
return selected;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1111
1246
|
// src/llm/index.ts
|
|
1247
|
+
init_config();
|
|
1112
1248
|
var cachedProvider = null;
|
|
1113
1249
|
var cachedConfig = null;
|
|
1114
1250
|
function createProvider(config) {
|
|
@@ -1151,6 +1287,10 @@ function getProvider() {
|
|
|
1151
1287
|
cachedProvider = createProvider(config);
|
|
1152
1288
|
return cachedProvider;
|
|
1153
1289
|
}
|
|
1290
|
+
function resetProvider() {
|
|
1291
|
+
cachedProvider = null;
|
|
1292
|
+
cachedConfig = null;
|
|
1293
|
+
}
|
|
1154
1294
|
var TRANSIENT_ERRORS = ["terminated", "ECONNRESET", "ETIMEDOUT", "socket hang up", "other side closed"];
|
|
1155
1295
|
var MAX_RETRIES = 3;
|
|
1156
1296
|
function isTransientError(error) {
|
|
@@ -1168,6 +1308,16 @@ async function llmCall(options) {
|
|
|
1168
1308
|
return await provider.call(options);
|
|
1169
1309
|
} catch (err) {
|
|
1170
1310
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1311
|
+
if (isModelNotAvailableError(error) && cachedConfig) {
|
|
1312
|
+
const failedModel = options.model || cachedConfig.model;
|
|
1313
|
+
const newModel = await handleModelNotAvailable(failedModel, provider, cachedConfig);
|
|
1314
|
+
if (newModel) {
|
|
1315
|
+
resetProvider();
|
|
1316
|
+
const newProvider = getProvider();
|
|
1317
|
+
return await newProvider.call({ ...options, model: newModel });
|
|
1318
|
+
}
|
|
1319
|
+
throw error;
|
|
1320
|
+
}
|
|
1171
1321
|
if (isOverloaded(error) && attempt < MAX_RETRIES) {
|
|
1172
1322
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
1173
1323
|
continue;
|
|
@@ -1185,6 +1335,40 @@ async function llmJsonCall(options) {
|
|
|
1185
1335
|
const text = await llmCall(options);
|
|
1186
1336
|
return parseJsonResponse(text);
|
|
1187
1337
|
}
|
|
1338
|
+
async function validateModel(options) {
|
|
1339
|
+
const provider = getProvider();
|
|
1340
|
+
const config = cachedConfig;
|
|
1341
|
+
if (!config) return;
|
|
1342
|
+
const modelsToCheck = [config.model];
|
|
1343
|
+
if (options?.fast) {
|
|
1344
|
+
const { getFastModel: getFastModel2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1345
|
+
const fast = getFastModel2();
|
|
1346
|
+
if (fast && fast !== config.model) modelsToCheck.push(fast);
|
|
1347
|
+
}
|
|
1348
|
+
for (const model of modelsToCheck) {
|
|
1349
|
+
try {
|
|
1350
|
+
await provider.call({
|
|
1351
|
+
system: "Respond with OK",
|
|
1352
|
+
prompt: "ping",
|
|
1353
|
+
model,
|
|
1354
|
+
maxTokens: 1
|
|
1355
|
+
});
|
|
1356
|
+
} catch (err) {
|
|
1357
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1358
|
+
if (isModelNotAvailableError(error)) {
|
|
1359
|
+
const newModel = await handleModelNotAvailable(model, provider, config);
|
|
1360
|
+
if (newModel) {
|
|
1361
|
+
resetProvider();
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
throw error;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// src/ai/detect.ts
|
|
1371
|
+
init_config();
|
|
1188
1372
|
|
|
1189
1373
|
// src/ai/prompts.ts
|
|
1190
1374
|
var GENERATION_SYSTEM_PROMPT = `You are an expert auditor for coding agent configurations (Claude Code, Cursor, and Codex).
|
|
@@ -1479,6 +1663,7 @@ async function detectProjectStack(fileTree, fileContents) {
|
|
|
1479
1663
|
}
|
|
1480
1664
|
|
|
1481
1665
|
// src/fingerprint/index.ts
|
|
1666
|
+
init_config();
|
|
1482
1667
|
async function collectFingerprint(dir) {
|
|
1483
1668
|
const gitRemoteUrl = getGitRemoteUrl();
|
|
1484
1669
|
const fileTree = getFileTree(dir);
|
|
@@ -2176,9 +2361,9 @@ function cleanupStaging() {
|
|
|
2176
2361
|
}
|
|
2177
2362
|
|
|
2178
2363
|
// src/utils/review.ts
|
|
2179
|
-
import
|
|
2364
|
+
import chalk2 from "chalk";
|
|
2180
2365
|
import fs14 from "fs";
|
|
2181
|
-
import
|
|
2366
|
+
import select2 from "@inquirer/select";
|
|
2182
2367
|
import { createTwoFilesPatch } from "diff";
|
|
2183
2368
|
|
|
2184
2369
|
// src/utils/editor.ts
|
|
@@ -2221,7 +2406,7 @@ function openDiffsInEditor(editor, files) {
|
|
|
2221
2406
|
|
|
2222
2407
|
// src/utils/review.ts
|
|
2223
2408
|
async function promptWantsReview() {
|
|
2224
|
-
return
|
|
2409
|
+
return select2({
|
|
2225
2410
|
message: "Would you like to review the diffs before deciding?",
|
|
2226
2411
|
choices: [
|
|
2227
2412
|
{ name: "Yes, show me the diffs", value: true },
|
|
@@ -2242,7 +2427,7 @@ async function promptReviewMethod() {
|
|
|
2242
2427
|
return { name: "Terminal", value: "terminal" };
|
|
2243
2428
|
}
|
|
2244
2429
|
});
|
|
2245
|
-
return
|
|
2430
|
+
return select2({ message: "How would you like to review the changes?", choices });
|
|
2246
2431
|
}
|
|
2247
2432
|
async function openReview(method, stagedFiles) {
|
|
2248
2433
|
if (method === "cursor" || method === "vscode") {
|
|
@@ -2250,7 +2435,7 @@ async function openReview(method, stagedFiles) {
|
|
|
2250
2435
|
originalPath: f.originalPath,
|
|
2251
2436
|
proposedPath: f.proposedPath
|
|
2252
2437
|
})));
|
|
2253
|
-
console.log(
|
|
2438
|
+
console.log(chalk2.dim(" Diffs opened in your editor.\n"));
|
|
2254
2439
|
return;
|
|
2255
2440
|
}
|
|
2256
2441
|
const fileInfos = stagedFiles.map((file) => {
|
|
@@ -2281,8 +2466,8 @@ async function openReview(method, stagedFiles) {
|
|
|
2281
2466
|
async function interactiveDiffExplorer(files) {
|
|
2282
2467
|
if (!process.stdin.isTTY) {
|
|
2283
2468
|
for (const f of files) {
|
|
2284
|
-
const icon = f.isNew ?
|
|
2285
|
-
const stats = f.isNew ?
|
|
2469
|
+
const icon = f.isNew ? chalk2.green("+") : chalk2.yellow("~");
|
|
2470
|
+
const stats = f.isNew ? chalk2.dim(`${f.lines} lines`) : `${chalk2.green(`+${f.added}`)} ${chalk2.red(`-${f.removed}`)}`;
|
|
2286
2471
|
console.log(` ${icon} ${f.relativePath} ${stats}`);
|
|
2287
2472
|
}
|
|
2288
2473
|
console.log("");
|
|
@@ -2298,47 +2483,47 @@ async function interactiveDiffExplorer(files) {
|
|
|
2298
2483
|
}
|
|
2299
2484
|
function renderFileList() {
|
|
2300
2485
|
const lines = [];
|
|
2301
|
-
lines.push(
|
|
2486
|
+
lines.push(chalk2.bold(" Review changes"));
|
|
2302
2487
|
lines.push("");
|
|
2303
2488
|
for (let i = 0; i < files.length; i++) {
|
|
2304
2489
|
const f = files[i];
|
|
2305
|
-
const ptr = i === cursor ?
|
|
2306
|
-
const icon = f.isNew ?
|
|
2307
|
-
const stats = f.isNew ?
|
|
2490
|
+
const ptr = i === cursor ? chalk2.cyan(">") : " ";
|
|
2491
|
+
const icon = f.isNew ? chalk2.green("+") : chalk2.yellow("~");
|
|
2492
|
+
const stats = f.isNew ? chalk2.dim(`${f.lines} lines`) : `${chalk2.green(`+${f.added}`)} ${chalk2.red(`-${f.removed}`)}`;
|
|
2308
2493
|
lines.push(` ${ptr} ${icon} ${f.relativePath} ${stats}`);
|
|
2309
2494
|
}
|
|
2310
2495
|
lines.push("");
|
|
2311
|
-
lines.push(
|
|
2496
|
+
lines.push(chalk2.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
|
|
2312
2497
|
return lines.join("\n");
|
|
2313
2498
|
}
|
|
2314
2499
|
function renderDiff(index) {
|
|
2315
2500
|
const f = files[index];
|
|
2316
2501
|
const lines = [];
|
|
2317
|
-
const header = f.isNew ? ` ${
|
|
2502
|
+
const header = f.isNew ? ` ${chalk2.green("+")} ${f.relativePath} ${chalk2.dim("(new file)")}` : ` ${chalk2.yellow("~")} ${f.relativePath} ${chalk2.green(`+${f.added}`)} ${chalk2.red(`-${f.removed}`)}`;
|
|
2318
2503
|
lines.push(header);
|
|
2319
|
-
lines.push(
|
|
2504
|
+
lines.push(chalk2.dim(" " + "\u2500".repeat(60)));
|
|
2320
2505
|
const patchLines = f.patch.split("\n");
|
|
2321
2506
|
const bodyLines = patchLines.slice(4);
|
|
2322
2507
|
const maxVisible = getTermHeight() - 4;
|
|
2323
2508
|
const visibleLines = bodyLines.slice(scrollOffset, scrollOffset + maxVisible);
|
|
2324
2509
|
for (const line of visibleLines) {
|
|
2325
2510
|
if (line.startsWith("+")) {
|
|
2326
|
-
lines.push(
|
|
2511
|
+
lines.push(chalk2.green(" " + line));
|
|
2327
2512
|
} else if (line.startsWith("-")) {
|
|
2328
|
-
lines.push(
|
|
2513
|
+
lines.push(chalk2.red(" " + line));
|
|
2329
2514
|
} else if (line.startsWith("@@")) {
|
|
2330
|
-
lines.push(
|
|
2515
|
+
lines.push(chalk2.cyan(" " + line));
|
|
2331
2516
|
} else {
|
|
2332
|
-
lines.push(
|
|
2517
|
+
lines.push(chalk2.dim(" " + line));
|
|
2333
2518
|
}
|
|
2334
2519
|
}
|
|
2335
2520
|
const totalBody = bodyLines.length;
|
|
2336
2521
|
if (totalBody > maxVisible) {
|
|
2337
2522
|
const pct = Math.round((scrollOffset + maxVisible) / totalBody * 100);
|
|
2338
|
-
lines.push(
|
|
2523
|
+
lines.push(chalk2.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
|
|
2339
2524
|
}
|
|
2340
2525
|
lines.push("");
|
|
2341
|
-
lines.push(
|
|
2526
|
+
lines.push(chalk2.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
|
|
2342
2527
|
return lines.join("\n");
|
|
2343
2528
|
}
|
|
2344
2529
|
function draw(initial) {
|
|
@@ -2744,7 +2929,7 @@ function getCurrentHeadSha() {
|
|
|
2744
2929
|
}
|
|
2745
2930
|
|
|
2746
2931
|
// src/utils/spinner-messages.ts
|
|
2747
|
-
import
|
|
2932
|
+
import chalk3 from "chalk";
|
|
2748
2933
|
var GENERATION_MESSAGES = [
|
|
2749
2934
|
"Analyzing your project structure and dependencies...",
|
|
2750
2935
|
"Mapping out build commands and test workflows...",
|
|
@@ -2794,9 +2979,9 @@ var SpinnerMessages = class {
|
|
|
2794
2979
|
this.currentBaseMessage = this.messages[0];
|
|
2795
2980
|
this.updateSpinnerText();
|
|
2796
2981
|
if (this.showElapsedTime) {
|
|
2797
|
-
this.spinner.suffixText =
|
|
2982
|
+
this.spinner.suffixText = chalk3.dim(`(${this.formatElapsed()})`);
|
|
2798
2983
|
this.elapsedTimer = setInterval(() => {
|
|
2799
|
-
this.spinner.suffixText =
|
|
2984
|
+
this.spinner.suffixText = chalk3.dim(`(${this.formatElapsed()})`);
|
|
2800
2985
|
}, 1e3);
|
|
2801
2986
|
}
|
|
2802
2987
|
this.timer = setInterval(() => {
|
|
@@ -2830,14 +3015,18 @@ var SpinnerMessages = class {
|
|
|
2830
3015
|
}
|
|
2831
3016
|
};
|
|
2832
3017
|
|
|
3018
|
+
// src/commands/onboard.ts
|
|
3019
|
+
init_config();
|
|
3020
|
+
|
|
2833
3021
|
// src/commands/interactive-provider-setup.ts
|
|
2834
|
-
|
|
3022
|
+
init_config();
|
|
3023
|
+
import chalk4 from "chalk";
|
|
2835
3024
|
import readline2 from "readline";
|
|
2836
|
-
import
|
|
3025
|
+
import select3 from "@inquirer/select";
|
|
2837
3026
|
function promptInput(question) {
|
|
2838
3027
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
2839
3028
|
return new Promise((resolve2) => {
|
|
2840
|
-
rl.question(
|
|
3029
|
+
rl.question(chalk4.cyan(`${question} `), (answer) => {
|
|
2841
3030
|
rl.close();
|
|
2842
3031
|
resolve2(answer.trim());
|
|
2843
3032
|
});
|
|
@@ -2852,7 +3041,7 @@ var PROVIDER_CHOICES = [
|
|
|
2852
3041
|
];
|
|
2853
3042
|
async function runInteractiveProviderSetup(options) {
|
|
2854
3043
|
const message = options?.selectMessage ?? "Select LLM provider";
|
|
2855
|
-
const provider = await
|
|
3044
|
+
const provider = await select3({
|
|
2856
3045
|
message,
|
|
2857
3046
|
choices: PROVIDER_CHOICES
|
|
2858
3047
|
});
|
|
@@ -2860,19 +3049,19 @@ async function runInteractiveProviderSetup(options) {
|
|
|
2860
3049
|
switch (provider) {
|
|
2861
3050
|
case "claude-cli": {
|
|
2862
3051
|
config.model = "default";
|
|
2863
|
-
console.log(
|
|
3052
|
+
console.log(chalk4.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
|
|
2864
3053
|
break;
|
|
2865
3054
|
}
|
|
2866
3055
|
case "cursor": {
|
|
2867
3056
|
config.model = "default";
|
|
2868
|
-
console.log(
|
|
3057
|
+
console.log(chalk4.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
|
|
2869
3058
|
break;
|
|
2870
3059
|
}
|
|
2871
3060
|
case "anthropic": {
|
|
2872
|
-
console.log(
|
|
3061
|
+
console.log(chalk4.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
|
|
2873
3062
|
config.apiKey = await promptInput("Anthropic API key:");
|
|
2874
3063
|
if (!config.apiKey) {
|
|
2875
|
-
console.log(
|
|
3064
|
+
console.log(chalk4.red("API key is required."));
|
|
2876
3065
|
throw new Error("__exit__");
|
|
2877
3066
|
}
|
|
2878
3067
|
config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.anthropic}):`) || DEFAULT_MODELS.anthropic;
|
|
@@ -2881,7 +3070,7 @@ async function runInteractiveProviderSetup(options) {
|
|
|
2881
3070
|
case "vertex": {
|
|
2882
3071
|
config.vertexProjectId = await promptInput("GCP Project ID:");
|
|
2883
3072
|
if (!config.vertexProjectId) {
|
|
2884
|
-
console.log(
|
|
3073
|
+
console.log(chalk4.red("Project ID is required."));
|
|
2885
3074
|
throw new Error("__exit__");
|
|
2886
3075
|
}
|
|
2887
3076
|
config.vertexRegion = await promptInput("Region (default: us-east5):") || "us-east5";
|
|
@@ -2892,7 +3081,7 @@ async function runInteractiveProviderSetup(options) {
|
|
|
2892
3081
|
case "openai": {
|
|
2893
3082
|
config.apiKey = await promptInput("API key:");
|
|
2894
3083
|
if (!config.apiKey) {
|
|
2895
|
-
console.log(
|
|
3084
|
+
console.log(chalk4.red("API key is required."));
|
|
2896
3085
|
throw new Error("__exit__");
|
|
2897
3086
|
}
|
|
2898
3087
|
config.baseUrl = await promptInput("Base URL (leave empty for OpenAI, or enter custom endpoint):") || void 0;
|
|
@@ -3016,15 +3205,15 @@ function computeGrade(score) {
|
|
|
3016
3205
|
// src/scoring/checks/coverage.ts
|
|
3017
3206
|
import { readFileSync, readdirSync } from "fs";
|
|
3018
3207
|
import { join } from "path";
|
|
3019
|
-
function readFileOrNull(
|
|
3208
|
+
function readFileOrNull(path24) {
|
|
3020
3209
|
try {
|
|
3021
|
-
return readFileSync(
|
|
3210
|
+
return readFileSync(path24, "utf-8");
|
|
3022
3211
|
} catch {
|
|
3023
3212
|
return null;
|
|
3024
3213
|
}
|
|
3025
3214
|
}
|
|
3026
|
-
function readJsonOrNull(
|
|
3027
|
-
const content = readFileOrNull(
|
|
3215
|
+
function readJsonOrNull(path24) {
|
|
3216
|
+
const content = readFileOrNull(path24);
|
|
3028
3217
|
if (!content) return null;
|
|
3029
3218
|
try {
|
|
3030
3219
|
return JSON.parse(content);
|
|
@@ -3392,9 +3581,9 @@ function checkExistence(dir) {
|
|
|
3392
3581
|
// src/scoring/checks/quality.ts
|
|
3393
3582
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3394
3583
|
import { join as join3 } from "path";
|
|
3395
|
-
function readFileOrNull2(
|
|
3584
|
+
function readFileOrNull2(path24) {
|
|
3396
3585
|
try {
|
|
3397
|
-
return readFileSync3(
|
|
3586
|
+
return readFileSync3(path24, "utf-8");
|
|
3398
3587
|
} catch {
|
|
3399
3588
|
return null;
|
|
3400
3589
|
}
|
|
@@ -3547,15 +3736,15 @@ function checkQuality(dir) {
|
|
|
3547
3736
|
// src/scoring/checks/accuracy.ts
|
|
3548
3737
|
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync } from "fs";
|
|
3549
3738
|
import { join as join4 } from "path";
|
|
3550
|
-
function readFileOrNull3(
|
|
3739
|
+
function readFileOrNull3(path24) {
|
|
3551
3740
|
try {
|
|
3552
|
-
return readFileSync4(
|
|
3741
|
+
return readFileSync4(path24, "utf-8");
|
|
3553
3742
|
} catch {
|
|
3554
3743
|
return null;
|
|
3555
3744
|
}
|
|
3556
3745
|
}
|
|
3557
|
-
function readJsonOrNull2(
|
|
3558
|
-
const content = readFileOrNull3(
|
|
3746
|
+
function readJsonOrNull2(path24) {
|
|
3747
|
+
const content = readFileOrNull3(path24);
|
|
3559
3748
|
if (!content) return null;
|
|
3560
3749
|
try {
|
|
3561
3750
|
return JSON.parse(content);
|
|
@@ -3738,9 +3927,9 @@ function checkAccuracy(dir) {
|
|
|
3738
3927
|
// src/scoring/checks/freshness.ts
|
|
3739
3928
|
import { existsSync as existsSync6, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
3740
3929
|
import { join as join5 } from "path";
|
|
3741
|
-
function readFileOrNull4(
|
|
3930
|
+
function readFileOrNull4(path24) {
|
|
3742
3931
|
try {
|
|
3743
|
-
return readFileSync5(
|
|
3932
|
+
return readFileSync5(path24, "utf-8");
|
|
3744
3933
|
} catch {
|
|
3745
3934
|
return null;
|
|
3746
3935
|
}
|
|
@@ -3854,9 +4043,9 @@ function checkFreshness(dir) {
|
|
|
3854
4043
|
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
|
|
3855
4044
|
import { execSync as execSync7 } from "child_process";
|
|
3856
4045
|
import { join as join6 } from "path";
|
|
3857
|
-
function readFileOrNull5(
|
|
4046
|
+
function readFileOrNull5(path24) {
|
|
3858
4047
|
try {
|
|
3859
|
-
return readFileSync6(
|
|
4048
|
+
return readFileSync6(path24, "utf-8");
|
|
3860
4049
|
} catch {
|
|
3861
4050
|
return null;
|
|
3862
4051
|
}
|
|
@@ -4030,7 +4219,7 @@ function computeLocalScore(dir, targetAgent) {
|
|
|
4030
4219
|
}
|
|
4031
4220
|
|
|
4032
4221
|
// src/scoring/display.ts
|
|
4033
|
-
import
|
|
4222
|
+
import chalk5 from "chalk";
|
|
4034
4223
|
var AGENT_DISPLAY_NAMES = {
|
|
4035
4224
|
claude: "Claude Code",
|
|
4036
4225
|
cursor: "Cursor",
|
|
@@ -4048,31 +4237,31 @@ var CATEGORY_ORDER = ["existence", "quality", "coverage", "accuracy", "freshness
|
|
|
4048
4237
|
function gradeColor(grade) {
|
|
4049
4238
|
switch (grade) {
|
|
4050
4239
|
case "A":
|
|
4051
|
-
return
|
|
4240
|
+
return chalk5.green;
|
|
4052
4241
|
case "B":
|
|
4053
|
-
return
|
|
4242
|
+
return chalk5.greenBright;
|
|
4054
4243
|
case "C":
|
|
4055
|
-
return
|
|
4244
|
+
return chalk5.yellow;
|
|
4056
4245
|
case "D":
|
|
4057
|
-
return
|
|
4246
|
+
return chalk5.hex("#f97316");
|
|
4058
4247
|
case "F":
|
|
4059
|
-
return
|
|
4248
|
+
return chalk5.red;
|
|
4060
4249
|
default:
|
|
4061
|
-
return
|
|
4250
|
+
return chalk5.white;
|
|
4062
4251
|
}
|
|
4063
4252
|
}
|
|
4064
4253
|
function progressBar(score, max, width = 40) {
|
|
4065
4254
|
const filled = Math.round(score / max * width);
|
|
4066
4255
|
const empty = width - filled;
|
|
4067
|
-
const bar =
|
|
4256
|
+
const bar = chalk5.hex("#f97316")("\u2593".repeat(filled)) + chalk5.gray("\u2591".repeat(empty));
|
|
4068
4257
|
return bar;
|
|
4069
4258
|
}
|
|
4070
4259
|
function formatCheck(check) {
|
|
4071
|
-
const icon = check.passed ?
|
|
4072
|
-
const points = check.passed ?
|
|
4073
|
-
const name = check.passed ?
|
|
4074
|
-
const detail = check.detail ?
|
|
4075
|
-
const suggestion = !check.passed && check.suggestion ?
|
|
4260
|
+
const icon = check.passed ? chalk5.green("\u2713") : check.earnedPoints < 0 ? chalk5.red("\u2717") : chalk5.gray("\u2717");
|
|
4261
|
+
const points = check.passed ? chalk5.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk5.red(`${check.earnedPoints}`.padStart(4)) : chalk5.gray(" \u2014");
|
|
4262
|
+
const name = check.passed ? chalk5.white(check.name) : chalk5.gray(check.name);
|
|
4263
|
+
const detail = check.detail ? chalk5.gray(` (${check.detail})`) : "";
|
|
4264
|
+
const suggestion = !check.passed && check.suggestion ? chalk5.gray(`
|
|
4076
4265
|
\u2192 ${check.suggestion}`) : "";
|
|
4077
4266
|
return ` ${icon} ${name.padEnd(38)}${points}${detail}${suggestion}`;
|
|
4078
4267
|
}
|
|
@@ -4080,19 +4269,19 @@ function displayScore(result) {
|
|
|
4080
4269
|
const gc = gradeColor(result.grade);
|
|
4081
4270
|
const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
|
|
4082
4271
|
console.log("");
|
|
4083
|
-
console.log(
|
|
4272
|
+
console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4084
4273
|
console.log("");
|
|
4085
|
-
console.log(` ${
|
|
4274
|
+
console.log(` ${chalk5.bold("Agent Config Score")} ${gc(chalk5.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk5.bold(result.grade))}`);
|
|
4086
4275
|
console.log(` ${progressBar(result.score, result.maxScore)}`);
|
|
4087
|
-
console.log(
|
|
4276
|
+
console.log(chalk5.dim(` Target: ${agentLabel}`));
|
|
4088
4277
|
console.log("");
|
|
4089
|
-
console.log(
|
|
4278
|
+
console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4090
4279
|
console.log("");
|
|
4091
4280
|
for (const category of CATEGORY_ORDER) {
|
|
4092
4281
|
const summary = result.categories[category];
|
|
4093
4282
|
const categoryChecks = result.checks.filter((c) => c.category === category);
|
|
4094
4283
|
console.log(
|
|
4095
|
-
|
|
4284
|
+
chalk5.gray(` ${CATEGORY_LABELS[category]}`) + chalk5.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk5.white(`${summary.earned}`) + chalk5.gray(` / ${summary.max}`)
|
|
4096
4285
|
);
|
|
4097
4286
|
for (const check of categoryChecks) {
|
|
4098
4287
|
console.log(formatCheck(check));
|
|
@@ -4105,48 +4294,48 @@ function displayScoreSummary(result) {
|
|
|
4105
4294
|
const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
|
|
4106
4295
|
console.log("");
|
|
4107
4296
|
console.log(
|
|
4108
|
-
|
|
4297
|
+
chalk5.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk5.gray(` (Grade ${result.grade})`) + chalk5.gray(` \xB7 ${agentLabel}`) + chalk5.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
|
|
4109
4298
|
);
|
|
4110
4299
|
const failing = result.checks.filter((c) => !c.passed);
|
|
4111
4300
|
if (failing.length > 0) {
|
|
4112
4301
|
const shown = failing.slice(0, 5);
|
|
4113
4302
|
for (const check of shown) {
|
|
4114
|
-
console.log(
|
|
4303
|
+
console.log(chalk5.gray(` \u2717 ${check.name}`));
|
|
4115
4304
|
}
|
|
4116
4305
|
const remaining = failing.length - shown.length;
|
|
4117
4306
|
const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
4118
|
-
console.log(
|
|
4119
|
-
Run ${
|
|
4307
|
+
console.log(chalk5.dim(`
|
|
4308
|
+
Run ${chalk5.hex("#83D1EB")("caliber score")} for details.${moreText}`));
|
|
4120
4309
|
}
|
|
4121
4310
|
console.log("");
|
|
4122
4311
|
}
|
|
4123
4312
|
function displayScoreDelta(before, after) {
|
|
4124
4313
|
const delta = after.score - before.score;
|
|
4125
4314
|
const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
|
|
4126
|
-
const deltaColor = delta >= 0 ?
|
|
4315
|
+
const deltaColor = delta >= 0 ? chalk5.green : chalk5.red;
|
|
4127
4316
|
const beforeGc = gradeColor(before.grade);
|
|
4128
4317
|
const afterGc = gradeColor(after.grade);
|
|
4129
4318
|
console.log("");
|
|
4130
|
-
console.log(
|
|
4319
|
+
console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4131
4320
|
console.log("");
|
|
4132
4321
|
console.log(
|
|
4133
|
-
` Score: ${beforeGc(`${before.score}`)} ${
|
|
4322
|
+
` Score: ${beforeGc(`${before.score}`)} ${chalk5.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk5.gray("\u2192")} ${afterGc(after.grade)}`
|
|
4134
4323
|
);
|
|
4135
|
-
console.log(` ${progressBar(before.score, before.maxScore, 19)} ${
|
|
4324
|
+
console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk5.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
|
|
4136
4325
|
console.log("");
|
|
4137
|
-
console.log(
|
|
4326
|
+
console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4138
4327
|
console.log("");
|
|
4139
4328
|
const improved = after.checks.filter((ac) => {
|
|
4140
4329
|
const bc = before.checks.find((b) => b.id === ac.id);
|
|
4141
4330
|
return bc && ac.earnedPoints > bc.earnedPoints;
|
|
4142
4331
|
});
|
|
4143
4332
|
if (improved.length > 0) {
|
|
4144
|
-
console.log(
|
|
4333
|
+
console.log(chalk5.gray(" What improved:"));
|
|
4145
4334
|
for (const check of improved) {
|
|
4146
4335
|
const bc = before.checks.find((b) => b.id === check.id);
|
|
4147
4336
|
const gain = check.earnedPoints - bc.earnedPoints;
|
|
4148
4337
|
console.log(
|
|
4149
|
-
|
|
4338
|
+
chalk5.green(" +") + chalk5.white(` ${check.name.padEnd(50)}`) + chalk5.green(`+${gain}`)
|
|
4150
4339
|
);
|
|
4151
4340
|
}
|
|
4152
4341
|
console.log("");
|
|
@@ -4154,9 +4343,9 @@ function displayScoreDelta(before, after) {
|
|
|
4154
4343
|
}
|
|
4155
4344
|
|
|
4156
4345
|
// src/commands/recommend.ts
|
|
4157
|
-
import
|
|
4346
|
+
import chalk7 from "chalk";
|
|
4158
4347
|
import ora from "ora";
|
|
4159
|
-
import
|
|
4348
|
+
import select4 from "@inquirer/select";
|
|
4160
4349
|
import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5, existsSync as existsSync9, writeFileSync } from "fs";
|
|
4161
4350
|
import { join as join8, dirname as dirname2 } from "path";
|
|
4162
4351
|
|
|
@@ -4304,6 +4493,168 @@ function hashJson(obj) {
|
|
|
4304
4493
|
return crypto2.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
|
|
4305
4494
|
}
|
|
4306
4495
|
|
|
4496
|
+
// src/commands/recommend.ts
|
|
4497
|
+
init_config();
|
|
4498
|
+
|
|
4499
|
+
// src/telemetry/index.ts
|
|
4500
|
+
import { PostHog } from "posthog-node";
|
|
4501
|
+
import chalk6 from "chalk";
|
|
4502
|
+
|
|
4503
|
+
// src/telemetry/config.ts
|
|
4504
|
+
import fs21 from "fs";
|
|
4505
|
+
import path17 from "path";
|
|
4506
|
+
import os3 from "os";
|
|
4507
|
+
import crypto3 from "crypto";
|
|
4508
|
+
import { execSync as execSync8 } from "child_process";
|
|
4509
|
+
var CONFIG_DIR2 = path17.join(os3.homedir(), ".caliber");
|
|
4510
|
+
var CONFIG_FILE2 = path17.join(CONFIG_DIR2, "config.json");
|
|
4511
|
+
var runtimeDisabled = false;
|
|
4512
|
+
function readConfig() {
|
|
4513
|
+
try {
|
|
4514
|
+
if (!fs21.existsSync(CONFIG_FILE2)) return {};
|
|
4515
|
+
return JSON.parse(fs21.readFileSync(CONFIG_FILE2, "utf-8"));
|
|
4516
|
+
} catch {
|
|
4517
|
+
return {};
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
function writeConfig(config) {
|
|
4521
|
+
if (!fs21.existsSync(CONFIG_DIR2)) {
|
|
4522
|
+
fs21.mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
4523
|
+
}
|
|
4524
|
+
fs21.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
4525
|
+
}
|
|
4526
|
+
function getMachineId() {
|
|
4527
|
+
const config = readConfig();
|
|
4528
|
+
if (config.machineId) return config.machineId;
|
|
4529
|
+
const machineId = crypto3.randomUUID();
|
|
4530
|
+
writeConfig({ ...config, machineId });
|
|
4531
|
+
return machineId;
|
|
4532
|
+
}
|
|
4533
|
+
function getGitEmailHash() {
|
|
4534
|
+
try {
|
|
4535
|
+
const email = execSync8("git config user.email", { encoding: "utf-8" }).trim();
|
|
4536
|
+
if (!email) return void 0;
|
|
4537
|
+
return crypto3.createHash("sha256").update(email).digest("hex");
|
|
4538
|
+
} catch {
|
|
4539
|
+
return void 0;
|
|
4540
|
+
}
|
|
4541
|
+
}
|
|
4542
|
+
function isTelemetryDisabled() {
|
|
4543
|
+
if (runtimeDisabled) return true;
|
|
4544
|
+
const envVal = process.env.CALIBER_TELEMETRY_DISABLED;
|
|
4545
|
+
return envVal === "1" || envVal === "true";
|
|
4546
|
+
}
|
|
4547
|
+
function setTelemetryDisabled(disabled) {
|
|
4548
|
+
runtimeDisabled = disabled;
|
|
4549
|
+
}
|
|
4550
|
+
function wasNoticeShown() {
|
|
4551
|
+
return readConfig().telemetryNoticeShown === true;
|
|
4552
|
+
}
|
|
4553
|
+
function markNoticeShown() {
|
|
4554
|
+
const config = readConfig();
|
|
4555
|
+
writeConfig({ ...config, telemetryNoticeShown: true });
|
|
4556
|
+
}
|
|
4557
|
+
|
|
4558
|
+
// src/telemetry/index.ts
|
|
4559
|
+
var POSTHOG_KEY = "phx_o1APdJxfIEvJ2RM0XyUX635wUms4mAWXNjPiIbLjGbU0lIi";
|
|
4560
|
+
var client = null;
|
|
4561
|
+
var distinctId = null;
|
|
4562
|
+
function initTelemetry() {
|
|
4563
|
+
if (isTelemetryDisabled()) return;
|
|
4564
|
+
const machineId = getMachineId();
|
|
4565
|
+
distinctId = machineId;
|
|
4566
|
+
client = new PostHog(POSTHOG_KEY, {
|
|
4567
|
+
host: "https://us.i.posthog.com",
|
|
4568
|
+
flushAt: 20,
|
|
4569
|
+
flushInterval: 0
|
|
4570
|
+
});
|
|
4571
|
+
if (!wasNoticeShown()) {
|
|
4572
|
+
console.log(
|
|
4573
|
+
chalk6.dim(" Caliber collects anonymous usage data to improve the product.") + "\n" + chalk6.dim(" Disable with --no-traces or CALIBER_TELEMETRY_DISABLED=1\n")
|
|
4574
|
+
);
|
|
4575
|
+
markNoticeShown();
|
|
4576
|
+
}
|
|
4577
|
+
const gitEmailHash = getGitEmailHash();
|
|
4578
|
+
client.identify({
|
|
4579
|
+
distinctId: machineId,
|
|
4580
|
+
properties: {
|
|
4581
|
+
...gitEmailHash ? { git_email_hash: gitEmailHash } : {}
|
|
4582
|
+
}
|
|
4583
|
+
});
|
|
4584
|
+
}
|
|
4585
|
+
function trackEvent(name, properties) {
|
|
4586
|
+
if (!client || !distinctId || isTelemetryDisabled()) return;
|
|
4587
|
+
client.capture({
|
|
4588
|
+
distinctId,
|
|
4589
|
+
event: name,
|
|
4590
|
+
properties: properties ?? {}
|
|
4591
|
+
});
|
|
4592
|
+
}
|
|
4593
|
+
async function flushTelemetry() {
|
|
4594
|
+
if (!client) return;
|
|
4595
|
+
try {
|
|
4596
|
+
await client.shutdown();
|
|
4597
|
+
} catch {
|
|
4598
|
+
}
|
|
4599
|
+
client = null;
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4602
|
+
// src/telemetry/events.ts
|
|
4603
|
+
function trackInitProviderSelected(provider, model) {
|
|
4604
|
+
trackEvent("init_provider_selected", { provider, model });
|
|
4605
|
+
}
|
|
4606
|
+
function trackInitProjectDiscovered(languageCount, dependencyCount, fileCount) {
|
|
4607
|
+
trackEvent("init_project_discovered", { language_count: languageCount, dependency_count: dependencyCount, file_count: fileCount });
|
|
4608
|
+
}
|
|
4609
|
+
function trackInitAgentSelected(agents) {
|
|
4610
|
+
trackEvent("init_agent_selected", { agents });
|
|
4611
|
+
}
|
|
4612
|
+
function trackInitScoreComputed(score, passingCount, failingCount, earlyExit) {
|
|
4613
|
+
trackEvent("init_score_computed", { score, passing_count: passingCount, failing_count: failingCount, early_exit: earlyExit });
|
|
4614
|
+
}
|
|
4615
|
+
function trackInitGenerationStarted(isTargetedFix) {
|
|
4616
|
+
trackEvent("init_generation_started", { is_targeted_fix: isTargetedFix });
|
|
4617
|
+
}
|
|
4618
|
+
function trackInitGenerationCompleted(durationMs, retryCount) {
|
|
4619
|
+
trackEvent("init_generation_completed", { duration_ms: durationMs, retry_count: retryCount });
|
|
4620
|
+
}
|
|
4621
|
+
function trackInitReviewAction(action, reviewMethod) {
|
|
4622
|
+
trackEvent("init_review_action", { action, review_method: reviewMethod });
|
|
4623
|
+
}
|
|
4624
|
+
function trackInitRefinementRound(roundNumber, wasValid) {
|
|
4625
|
+
trackEvent("init_refinement_round", { round_number: roundNumber, was_valid: wasValid });
|
|
4626
|
+
}
|
|
4627
|
+
function trackInitFilesWritten(fileCount, createdCount, modifiedCount, deletedCount) {
|
|
4628
|
+
trackEvent("init_files_written", { file_count: fileCount, created_count: createdCount, modified_count: modifiedCount, deleted_count: deletedCount });
|
|
4629
|
+
}
|
|
4630
|
+
function trackInitHookSelected(hookType) {
|
|
4631
|
+
trackEvent("init_hook_selected", { hook_type: hookType });
|
|
4632
|
+
}
|
|
4633
|
+
function trackInitSkillsSearch(searched, installedCount) {
|
|
4634
|
+
trackEvent("init_skills_search", { searched, installed_count: installedCount });
|
|
4635
|
+
}
|
|
4636
|
+
function trackInitScoreRegression(oldScore, newScore) {
|
|
4637
|
+
trackEvent("init_score_regression", { old_score: oldScore, new_score: newScore });
|
|
4638
|
+
}
|
|
4639
|
+
function trackRegenerateCompleted(action, durationMs) {
|
|
4640
|
+
trackEvent("regenerate_completed", { action, duration_ms: durationMs });
|
|
4641
|
+
}
|
|
4642
|
+
function trackRefreshCompleted(changesCount, durationMs) {
|
|
4643
|
+
trackEvent("refresh_completed", { changes_count: changesCount, duration_ms: durationMs });
|
|
4644
|
+
}
|
|
4645
|
+
function trackScoreComputed(score, agent) {
|
|
4646
|
+
trackEvent("score_computed", { score, agent });
|
|
4647
|
+
}
|
|
4648
|
+
function trackConfigProviderSet(provider) {
|
|
4649
|
+
trackEvent("config_provider_set", { provider });
|
|
4650
|
+
}
|
|
4651
|
+
function trackSkillsInstalled(count) {
|
|
4652
|
+
trackEvent("skills_installed", { count });
|
|
4653
|
+
}
|
|
4654
|
+
function trackUndoExecuted() {
|
|
4655
|
+
trackEvent("undo_executed");
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4307
4658
|
// src/commands/recommend.ts
|
|
4308
4659
|
function detectLocalPlatforms() {
|
|
4309
4660
|
const items = scanLocalState(process.cwd());
|
|
@@ -4604,7 +4955,7 @@ function extractTopDeps() {
|
|
|
4604
4955
|
}
|
|
4605
4956
|
}
|
|
4606
4957
|
async function recommendCommand() {
|
|
4607
|
-
const proceed = await
|
|
4958
|
+
const proceed = await select4({
|
|
4608
4959
|
message: "Search public repos for relevant skills to add to this project?",
|
|
4609
4960
|
choices: [
|
|
4610
4961
|
{ name: "Yes, find skills for my project", value: true },
|
|
@@ -4612,7 +4963,7 @@ async function recommendCommand() {
|
|
|
4612
4963
|
]
|
|
4613
4964
|
});
|
|
4614
4965
|
if (!proceed) {
|
|
4615
|
-
console.log(
|
|
4966
|
+
console.log(chalk7.dim(" Cancelled.\n"));
|
|
4616
4967
|
return;
|
|
4617
4968
|
}
|
|
4618
4969
|
await searchAndInstallSkills();
|
|
@@ -4627,7 +4978,7 @@ async function searchAndInstallSkills() {
|
|
|
4627
4978
|
...extractTopDeps()
|
|
4628
4979
|
].filter(Boolean))];
|
|
4629
4980
|
if (technologies.length === 0) {
|
|
4630
|
-
console.log(
|
|
4981
|
+
console.log(chalk7.yellow("Could not detect any languages or dependencies. Try running from a project root."));
|
|
4631
4982
|
throw new Error("__exit__");
|
|
4632
4983
|
}
|
|
4633
4984
|
const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
|
|
@@ -4644,7 +4995,7 @@ async function searchAndInstallSkills() {
|
|
|
4644
4995
|
return;
|
|
4645
4996
|
}
|
|
4646
4997
|
searchSpinner.succeed(
|
|
4647
|
-
`Found ${allCandidates.length} skills` + (filteredCount > 0 ?
|
|
4998
|
+
`Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk7.dim(` (${filteredCount} already installed)`) : "")
|
|
4648
4999
|
);
|
|
4649
5000
|
let results;
|
|
4650
5001
|
const config = loadConfig();
|
|
@@ -4678,7 +5029,7 @@ async function searchAndInstallSkills() {
|
|
|
4678
5029
|
}
|
|
4679
5030
|
const unavailableCount = results.length - available.length;
|
|
4680
5031
|
fetchSpinner.succeed(
|
|
4681
|
-
`${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ?
|
|
5032
|
+
`${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk7.dim(` (${unavailableCount} unavailable)`) : "")
|
|
4682
5033
|
);
|
|
4683
5034
|
const selected = await interactiveSelect(available);
|
|
4684
5035
|
if (selected?.length) {
|
|
@@ -4701,30 +5052,30 @@ async function interactiveSelect(recs) {
|
|
|
4701
5052
|
const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
|
|
4702
5053
|
const prefixWidth = 8;
|
|
4703
5054
|
const scoreWidth = 6;
|
|
4704
|
-
lines.push(
|
|
5055
|
+
lines.push(chalk7.bold(" Skills"));
|
|
4705
5056
|
lines.push("");
|
|
4706
5057
|
if (hasScores) {
|
|
4707
|
-
const header = " ".repeat(prefixWidth) +
|
|
5058
|
+
const header = " ".repeat(prefixWidth) + chalk7.dim("Score".padEnd(scoreWidth)) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Why");
|
|
4708
5059
|
lines.push(header);
|
|
4709
5060
|
} else {
|
|
4710
|
-
const header = " ".repeat(prefixWidth) +
|
|
5061
|
+
const header = " ".repeat(prefixWidth) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Technology".padEnd(18)) + chalk7.dim("Source");
|
|
4711
5062
|
lines.push(header);
|
|
4712
5063
|
}
|
|
4713
|
-
lines.push(
|
|
5064
|
+
lines.push(chalk7.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
|
|
4714
5065
|
for (let i = 0; i < recs.length; i++) {
|
|
4715
5066
|
const rec = recs[i];
|
|
4716
|
-
const check = selected.has(i) ?
|
|
4717
|
-
const ptr = i === cursor ?
|
|
5067
|
+
const check = selected.has(i) ? chalk7.green("[x]") : "[ ]";
|
|
5068
|
+
const ptr = i === cursor ? chalk7.cyan(">") : " ";
|
|
4718
5069
|
if (hasScores) {
|
|
4719
|
-
const scoreColor = rec.score >= 90 ?
|
|
5070
|
+
const scoreColor = rec.score >= 90 ? chalk7.green : rec.score >= 70 ? chalk7.yellow : chalk7.dim;
|
|
4720
5071
|
const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
|
|
4721
|
-
lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${
|
|
5072
|
+
lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk7.dim(rec.reason.slice(0, reasonMax))}`);
|
|
4722
5073
|
} else {
|
|
4723
|
-
lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${
|
|
5074
|
+
lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk7.dim(rec.source_url || "")}`);
|
|
4724
5075
|
}
|
|
4725
5076
|
}
|
|
4726
5077
|
lines.push("");
|
|
4727
|
-
lines.push(
|
|
5078
|
+
lines.push(chalk7.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
|
|
4728
5079
|
return lines.join("\n");
|
|
4729
5080
|
}
|
|
4730
5081
|
function draw(initial) {
|
|
@@ -4773,7 +5124,7 @@ async function interactiveSelect(recs) {
|
|
|
4773
5124
|
case "\n":
|
|
4774
5125
|
cleanup();
|
|
4775
5126
|
if (selected.size === 0) {
|
|
4776
|
-
console.log(
|
|
5127
|
+
console.log(chalk7.dim("\n No skills selected.\n"));
|
|
4777
5128
|
resolve2(null);
|
|
4778
5129
|
} else {
|
|
4779
5130
|
resolve2(Array.from(selected).sort().map((i) => recs[i]));
|
|
@@ -4783,7 +5134,7 @@ async function interactiveSelect(recs) {
|
|
|
4783
5134
|
case "\x1B":
|
|
4784
5135
|
case "":
|
|
4785
5136
|
cleanup();
|
|
4786
|
-
console.log(
|
|
5137
|
+
console.log(chalk7.dim("\n Cancelled.\n"));
|
|
4787
5138
|
resolve2(null);
|
|
4788
5139
|
break;
|
|
4789
5140
|
}
|
|
@@ -4844,9 +5195,10 @@ async function installSkills(recs, platforms, contentMap) {
|
|
|
4844
5195
|
}
|
|
4845
5196
|
}
|
|
4846
5197
|
if (installed.length > 0) {
|
|
5198
|
+
trackSkillsInstalled(installed.length);
|
|
4847
5199
|
spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
|
|
4848
5200
|
for (const p of installed) {
|
|
4849
|
-
console.log(
|
|
5201
|
+
console.log(chalk7.green(` \u2713 ${p}`));
|
|
4850
5202
|
}
|
|
4851
5203
|
} else {
|
|
4852
5204
|
spinner.fail("No skills were installed");
|
|
@@ -4859,19 +5211,19 @@ function printSkills(recs) {
|
|
|
4859
5211
|
const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
|
|
4860
5212
|
const scoreWidth = 6;
|
|
4861
5213
|
const prefixWidth = 2;
|
|
4862
|
-
console.log(
|
|
5214
|
+
console.log(chalk7.bold("\n Skills\n"));
|
|
4863
5215
|
if (hasScores) {
|
|
4864
|
-
console.log(" ".repeat(prefixWidth) +
|
|
5216
|
+
console.log(" ".repeat(prefixWidth) + chalk7.dim("Score".padEnd(scoreWidth)) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Why"));
|
|
4865
5217
|
} else {
|
|
4866
|
-
console.log(" ".repeat(prefixWidth) +
|
|
5218
|
+
console.log(" ".repeat(prefixWidth) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Technology".padEnd(18)) + chalk7.dim("Source"));
|
|
4867
5219
|
}
|
|
4868
|
-
console.log(
|
|
5220
|
+
console.log(chalk7.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
|
|
4869
5221
|
for (const rec of recs) {
|
|
4870
5222
|
if (hasScores) {
|
|
4871
5223
|
const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
|
|
4872
|
-
console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${
|
|
5224
|
+
console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk7.dim(rec.reason.slice(0, reasonMax))}`);
|
|
4873
5225
|
} else {
|
|
4874
|
-
console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${
|
|
5226
|
+
console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk7.dim(rec.source_url || "")}`);
|
|
4875
5227
|
}
|
|
4876
5228
|
}
|
|
4877
5229
|
console.log("");
|
|
@@ -4879,8 +5231,8 @@ function printSkills(recs) {
|
|
|
4879
5231
|
|
|
4880
5232
|
// src/commands/onboard.ts
|
|
4881
5233
|
async function initCommand(options) {
|
|
4882
|
-
const brand =
|
|
4883
|
-
const title =
|
|
5234
|
+
const brand = chalk8.hex("#EB9D83");
|
|
5235
|
+
const title = chalk8.hex("#83D1EB");
|
|
4884
5236
|
console.log(brand.bold(`
|
|
4885
5237
|
\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
|
|
4886
5238
|
\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
|
|
@@ -4889,21 +5241,21 @@ async function initCommand(options) {
|
|
|
4889
5241
|
\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
|
|
4890
5242
|
\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
|
|
4891
5243
|
`));
|
|
4892
|
-
console.log(
|
|
5244
|
+
console.log(chalk8.dim(" Onboard your project for AI-assisted development\n"));
|
|
4893
5245
|
console.log(title.bold(" Welcome to Caliber\n"));
|
|
4894
|
-
console.log(
|
|
4895
|
-
console.log(
|
|
5246
|
+
console.log(chalk8.dim(" Caliber analyzes your codebase and creates tailored config files"));
|
|
5247
|
+
console.log(chalk8.dim(" so your AI coding agents understand your project from day one.\n"));
|
|
4896
5248
|
console.log(title.bold(" How onboarding works:\n"));
|
|
4897
|
-
console.log(
|
|
4898
|
-
console.log(
|
|
4899
|
-
console.log(
|
|
4900
|
-
console.log(
|
|
4901
|
-
console.log(
|
|
4902
|
-
console.log(
|
|
5249
|
+
console.log(chalk8.dim(" 1. Connect Set up your LLM provider"));
|
|
5250
|
+
console.log(chalk8.dim(" 2. Discover Analyze your code, dependencies, and structure"));
|
|
5251
|
+
console.log(chalk8.dim(" 3. Generate Create config files tailored to your project"));
|
|
5252
|
+
console.log(chalk8.dim(" 4. Review Preview, refine, and apply the changes"));
|
|
5253
|
+
console.log(chalk8.dim(" 5. Enhance Discover MCP servers for your tools"));
|
|
5254
|
+
console.log(chalk8.dim(" 6. Skills Browse community skills for your stack\n"));
|
|
4903
5255
|
console.log(title.bold(" Step 1/6 \u2014 Connect your LLM\n"));
|
|
4904
5256
|
let config = loadConfig();
|
|
4905
5257
|
if (!config) {
|
|
4906
|
-
console.log(
|
|
5258
|
+
console.log(chalk8.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
|
|
4907
5259
|
try {
|
|
4908
5260
|
await runInteractiveProviderSetup({
|
|
4909
5261
|
selectMessage: "How do you want to use Caliber? (choose LLM provider)"
|
|
@@ -4914,24 +5266,28 @@ async function initCommand(options) {
|
|
|
4914
5266
|
}
|
|
4915
5267
|
config = loadConfig();
|
|
4916
5268
|
if (!config) {
|
|
4917
|
-
console.log(
|
|
5269
|
+
console.log(chalk8.red(" Setup was cancelled or failed.\n"));
|
|
4918
5270
|
throw new Error("__exit__");
|
|
4919
5271
|
}
|
|
4920
|
-
console.log(
|
|
5272
|
+
console.log(chalk8.green(" \u2713 Provider saved. Let's continue.\n"));
|
|
4921
5273
|
}
|
|
5274
|
+
trackInitProviderSelected(config.provider, config.model);
|
|
4922
5275
|
const displayModel = config.model === "default" && config.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : config.model;
|
|
4923
5276
|
const fastModel = getFastModel();
|
|
4924
5277
|
const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
|
|
4925
|
-
console.log(
|
|
5278
|
+
console.log(chalk8.dim(modelLine + "\n"));
|
|
5279
|
+
await validateModel({ fast: true });
|
|
4926
5280
|
console.log(title.bold(" Step 2/6 \u2014 Discover your project\n"));
|
|
4927
|
-
console.log(
|
|
5281
|
+
console.log(chalk8.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
|
|
4928
5282
|
const spinner = ora2("Analyzing project...").start();
|
|
4929
5283
|
const fingerprint = await collectFingerprint(process.cwd());
|
|
4930
5284
|
spinner.succeed("Project analyzed");
|
|
4931
|
-
|
|
4932
|
-
console.log(
|
|
5285
|
+
trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
|
|
5286
|
+
console.log(chalk8.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
|
|
5287
|
+
console.log(chalk8.dim(` Files: ${fingerprint.fileTree.length} found
|
|
4933
5288
|
`));
|
|
4934
5289
|
const targetAgent = options.agent || await promptAgent();
|
|
5290
|
+
trackInitAgentSelected(targetAgent);
|
|
4935
5291
|
const preScore = computeLocalScore(process.cwd(), targetAgent);
|
|
4936
5292
|
const failingForDismissal = preScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
4937
5293
|
if (failingForDismissal.length > 0) {
|
|
@@ -4945,26 +5301,30 @@ async function initCommand(options) {
|
|
|
4945
5301
|
}
|
|
4946
5302
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
4947
5303
|
displayScoreSummary(baselineScore);
|
|
5304
|
+
const passingCount = baselineScore.checks.filter((c) => c.passed).length;
|
|
5305
|
+
const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
|
|
4948
5306
|
const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
|
|
4949
5307
|
const NON_LLM_CHECKS = /* @__PURE__ */ new Set(["hooks_configured", "agents_md_exists", "permissions_configured", "mcp_servers"]);
|
|
4950
5308
|
if (hasExistingConfig && baselineScore.score === 100) {
|
|
4951
|
-
|
|
4952
|
-
console.log(
|
|
5309
|
+
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
|
|
5310
|
+
console.log(chalk8.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
|
|
5311
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to regenerate anyway.\n"));
|
|
4953
5312
|
if (!options.force) return;
|
|
4954
5313
|
}
|
|
4955
5314
|
const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
4956
5315
|
const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
|
|
5316
|
+
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
|
|
4957
5317
|
if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
|
|
4958
|
-
console.log(
|
|
4959
|
-
console.log(
|
|
5318
|
+
console.log(chalk8.bold.green("\n Your config is fully optimized for LLM generation.\n"));
|
|
5319
|
+
console.log(chalk8.dim(" Remaining items need CLI actions:\n"));
|
|
4960
5320
|
for (const check of allFailingChecks) {
|
|
4961
|
-
console.log(
|
|
5321
|
+
console.log(chalk8.dim(` \u2022 ${check.name}`));
|
|
4962
5322
|
if (check.suggestion) {
|
|
4963
|
-
console.log(` ${
|
|
5323
|
+
console.log(` ${chalk8.hex("#83D1EB")(check.suggestion)}`);
|
|
4964
5324
|
}
|
|
4965
5325
|
}
|
|
4966
5326
|
console.log("");
|
|
4967
|
-
console.log(
|
|
5327
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to regenerate anyway.\n"));
|
|
4968
5328
|
return;
|
|
4969
5329
|
}
|
|
4970
5330
|
const isEmpty = fingerprint.fileTree.length < 3;
|
|
@@ -4980,22 +5340,23 @@ async function initCommand(options) {
|
|
|
4980
5340
|
currentScore = baselineScore.score;
|
|
4981
5341
|
if (failingChecks.length > 0) {
|
|
4982
5342
|
console.log(title.bold(" Step 3/6 \u2014 Fine-tuning\n"));
|
|
4983
|
-
console.log(
|
|
5343
|
+
console.log(chalk8.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
|
|
4984
5344
|
`));
|
|
4985
5345
|
for (const check of failingChecks) {
|
|
4986
|
-
console.log(
|
|
5346
|
+
console.log(chalk8.dim(` \u2022 ${check.name}`));
|
|
4987
5347
|
}
|
|
4988
5348
|
console.log("");
|
|
4989
5349
|
}
|
|
4990
5350
|
} else if (hasExistingConfig) {
|
|
4991
5351
|
console.log(title.bold(" Step 3/6 \u2014 Improve your setup\n"));
|
|
4992
|
-
console.log(
|
|
4993
|
-
console.log(
|
|
5352
|
+
console.log(chalk8.dim(" Reviewing your existing configs against your codebase"));
|
|
5353
|
+
console.log(chalk8.dim(" and preparing improvements.\n"));
|
|
4994
5354
|
} else {
|
|
4995
5355
|
console.log(title.bold(" Step 3/6 \u2014 Build your agent setup\n"));
|
|
4996
|
-
console.log(
|
|
5356
|
+
console.log(chalk8.dim(" Creating config files tailored to your project.\n"));
|
|
4997
5357
|
}
|
|
4998
|
-
console.log(
|
|
5358
|
+
console.log(chalk8.dim(" This can take a couple of minutes depending on your model and provider.\n"));
|
|
5359
|
+
trackInitGenerationStarted(!!failingChecks);
|
|
4999
5360
|
const genStartTime = Date.now();
|
|
5000
5361
|
const genSpinner = ora2("Generating setup...").start();
|
|
5001
5362
|
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
|
|
@@ -5037,16 +5398,17 @@ async function initCommand(options) {
|
|
|
5037
5398
|
if (!generatedSetup) {
|
|
5038
5399
|
genSpinner.fail("Failed to generate setup.");
|
|
5039
5400
|
if (rawOutput) {
|
|
5040
|
-
console.log(
|
|
5041
|
-
console.log(
|
|
5401
|
+
console.log(chalk8.dim("\nRaw LLM output (JSON parse failed):"));
|
|
5402
|
+
console.log(chalk8.dim(rawOutput.slice(0, 500)));
|
|
5042
5403
|
}
|
|
5043
5404
|
throw new Error("__exit__");
|
|
5044
5405
|
}
|
|
5045
5406
|
const elapsedMs = Date.now() - genStartTime;
|
|
5407
|
+
trackInitGenerationCompleted(elapsedMs, 0);
|
|
5046
5408
|
const mins = Math.floor(elapsedMs / 6e4);
|
|
5047
5409
|
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
5048
5410
|
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
5049
|
-
genSpinner.succeed(`Setup generated ${
|
|
5411
|
+
genSpinner.succeed(`Setup generated ${chalk8.dim(`in ${timeStr}`)}`);
|
|
5050
5412
|
printSetupSummary(generatedSetup);
|
|
5051
5413
|
const sessionHistory = [];
|
|
5052
5414
|
sessionHistory.push({
|
|
@@ -5057,11 +5419,11 @@ async function initCommand(options) {
|
|
|
5057
5419
|
const setupFiles = collectSetupFiles(generatedSetup);
|
|
5058
5420
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
5059
5421
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
5060
|
-
console.log(
|
|
5422
|
+
console.log(chalk8.dim(` ${chalk8.green(`${staged.newFiles} new`)} / ${chalk8.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
5061
5423
|
`));
|
|
5062
5424
|
let action;
|
|
5063
5425
|
if (totalChanges === 0) {
|
|
5064
|
-
console.log(
|
|
5426
|
+
console.log(chalk8.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
5065
5427
|
cleanupStaging();
|
|
5066
5428
|
action = "accept";
|
|
5067
5429
|
} else {
|
|
@@ -5071,29 +5433,34 @@ async function initCommand(options) {
|
|
|
5071
5433
|
await openReview(reviewMethod, staged.stagedFiles);
|
|
5072
5434
|
}
|
|
5073
5435
|
action = await promptReviewAction();
|
|
5436
|
+
trackInitReviewAction(action, wantsReview ? "reviewed" : "skipped");
|
|
5074
5437
|
}
|
|
5438
|
+
let refinementRound = 0;
|
|
5075
5439
|
while (action === "refine") {
|
|
5440
|
+
refinementRound++;
|
|
5076
5441
|
generatedSetup = await refineLoop(generatedSetup, targetAgent, sessionHistory);
|
|
5442
|
+
trackInitRefinementRound(refinementRound, !!generatedSetup);
|
|
5077
5443
|
if (!generatedSetup) {
|
|
5078
5444
|
cleanupStaging();
|
|
5079
|
-
console.log(
|
|
5445
|
+
console.log(chalk8.dim("Refinement cancelled. No files were modified."));
|
|
5080
5446
|
return;
|
|
5081
5447
|
}
|
|
5082
5448
|
const updatedFiles = collectSetupFiles(generatedSetup);
|
|
5083
5449
|
const restaged = stageFiles(updatedFiles, process.cwd());
|
|
5084
|
-
console.log(
|
|
5450
|
+
console.log(chalk8.dim(` ${chalk8.green(`${restaged.newFiles} new`)} / ${chalk8.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
|
|
5085
5451
|
`));
|
|
5086
5452
|
printSetupSummary(generatedSetup);
|
|
5087
5453
|
await openReview("terminal", restaged.stagedFiles);
|
|
5088
5454
|
action = await promptReviewAction();
|
|
5455
|
+
trackInitReviewAction(action, "terminal");
|
|
5089
5456
|
}
|
|
5090
5457
|
cleanupStaging();
|
|
5091
5458
|
if (action === "decline") {
|
|
5092
|
-
console.log(
|
|
5459
|
+
console.log(chalk8.dim("Setup declined. No files were modified."));
|
|
5093
5460
|
return;
|
|
5094
5461
|
}
|
|
5095
5462
|
if (options.dryRun) {
|
|
5096
|
-
console.log(
|
|
5463
|
+
console.log(chalk8.yellow("\n[Dry run] Would write the following files:"));
|
|
5097
5464
|
console.log(JSON.stringify(generatedSetup, null, 2));
|
|
5098
5465
|
return;
|
|
5099
5466
|
}
|
|
@@ -5101,23 +5468,29 @@ async function initCommand(options) {
|
|
|
5101
5468
|
try {
|
|
5102
5469
|
const result = writeSetup(generatedSetup);
|
|
5103
5470
|
writeSpinner.succeed("Config files written");
|
|
5104
|
-
|
|
5471
|
+
trackInitFilesWritten(
|
|
5472
|
+
result.written.length + result.deleted.length,
|
|
5473
|
+
result.written.length,
|
|
5474
|
+
0,
|
|
5475
|
+
result.deleted.length
|
|
5476
|
+
);
|
|
5477
|
+
console.log(chalk8.bold("\nFiles created/updated:"));
|
|
5105
5478
|
for (const file of result.written) {
|
|
5106
|
-
console.log(` ${
|
|
5479
|
+
console.log(` ${chalk8.green("\u2713")} ${file}`);
|
|
5107
5480
|
}
|
|
5108
5481
|
if (result.deleted.length > 0) {
|
|
5109
|
-
console.log(
|
|
5482
|
+
console.log(chalk8.bold("\nFiles removed:"));
|
|
5110
5483
|
for (const file of result.deleted) {
|
|
5111
|
-
console.log(` ${
|
|
5484
|
+
console.log(` ${chalk8.red("\u2717")} ${file}`);
|
|
5112
5485
|
}
|
|
5113
5486
|
}
|
|
5114
5487
|
if (result.backupDir) {
|
|
5115
|
-
console.log(
|
|
5488
|
+
console.log(chalk8.dim(`
|
|
5116
5489
|
Backups saved to ${result.backupDir}`));
|
|
5117
5490
|
}
|
|
5118
5491
|
} catch (err) {
|
|
5119
5492
|
writeSpinner.fail("Failed to write files");
|
|
5120
|
-
console.error(
|
|
5493
|
+
console.error(chalk8.red(err instanceof Error ? err.message : "Unknown error"));
|
|
5121
5494
|
throw new Error("__exit__");
|
|
5122
5495
|
}
|
|
5123
5496
|
ensurePermissions();
|
|
@@ -5129,56 +5502,58 @@ async function initCommand(options) {
|
|
|
5129
5502
|
});
|
|
5130
5503
|
console.log("");
|
|
5131
5504
|
console.log(title.bold(" Keep your configs fresh\n"));
|
|
5132
|
-
console.log(
|
|
5505
|
+
console.log(chalk8.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
|
|
5133
5506
|
const hookChoice = await promptHookType(targetAgent);
|
|
5507
|
+
trackInitHookSelected(hookChoice);
|
|
5134
5508
|
if (hookChoice === "claude" || hookChoice === "both") {
|
|
5135
5509
|
const hookResult = installHook();
|
|
5136
5510
|
if (hookResult.installed) {
|
|
5137
|
-
console.log(` ${
|
|
5138
|
-
console.log(
|
|
5511
|
+
console.log(` ${chalk8.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
|
|
5512
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber hooks --remove") + chalk8.dim(" to disable"));
|
|
5139
5513
|
} else if (hookResult.alreadyInstalled) {
|
|
5140
|
-
console.log(
|
|
5514
|
+
console.log(chalk8.dim(" Claude Code hook already installed"));
|
|
5141
5515
|
}
|
|
5142
5516
|
const learnResult = installLearningHooks();
|
|
5143
5517
|
if (learnResult.installed) {
|
|
5144
|
-
console.log(` ${
|
|
5145
|
-
console.log(
|
|
5518
|
+
console.log(` ${chalk8.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
|
|
5519
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber learn remove") + chalk8.dim(" to disable"));
|
|
5146
5520
|
} else if (learnResult.alreadyInstalled) {
|
|
5147
|
-
console.log(
|
|
5521
|
+
console.log(chalk8.dim(" Learning hooks already installed"));
|
|
5148
5522
|
}
|
|
5149
5523
|
}
|
|
5150
5524
|
if (hookChoice === "precommit" || hookChoice === "both") {
|
|
5151
5525
|
const precommitResult = installPreCommitHook();
|
|
5152
5526
|
if (precommitResult.installed) {
|
|
5153
|
-
console.log(` ${
|
|
5154
|
-
console.log(
|
|
5527
|
+
console.log(` ${chalk8.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
|
|
5528
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber hooks --remove") + chalk8.dim(" to disable"));
|
|
5155
5529
|
} else if (precommitResult.alreadyInstalled) {
|
|
5156
|
-
console.log(
|
|
5530
|
+
console.log(chalk8.dim(" Pre-commit hook already installed"));
|
|
5157
5531
|
} else {
|
|
5158
|
-
console.log(
|
|
5532
|
+
console.log(chalk8.yellow(" Could not install pre-commit hook (not a git repository?)"));
|
|
5159
5533
|
}
|
|
5160
5534
|
}
|
|
5161
5535
|
if (hookChoice === "skip") {
|
|
5162
|
-
console.log(
|
|
5536
|
+
console.log(chalk8.dim(" Skipped auto-refresh hooks. Run ") + chalk8.hex("#83D1EB")("caliber hooks --install") + chalk8.dim(" later to enable."));
|
|
5163
5537
|
}
|
|
5164
5538
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5165
5539
|
if (afterScore.score < baselineScore.score) {
|
|
5540
|
+
trackInitScoreRegression(baselineScore.score, afterScore.score);
|
|
5166
5541
|
console.log("");
|
|
5167
|
-
console.log(
|
|
5542
|
+
console.log(chalk8.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
5168
5543
|
try {
|
|
5169
5544
|
const { restored, removed } = undoSetup();
|
|
5170
5545
|
if (restored.length > 0 || removed.length > 0) {
|
|
5171
|
-
console.log(
|
|
5546
|
+
console.log(chalk8.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
5172
5547
|
}
|
|
5173
5548
|
} catch {
|
|
5174
5549
|
}
|
|
5175
|
-
console.log(
|
|
5550
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
|
|
5176
5551
|
return;
|
|
5177
5552
|
}
|
|
5178
5553
|
displayScoreDelta(baselineScore, afterScore);
|
|
5179
5554
|
console.log(title.bold("\n Step 6/6 \u2014 Community skills\n"));
|
|
5180
|
-
console.log(
|
|
5181
|
-
const wantsSkills = await
|
|
5555
|
+
console.log(chalk8.dim(" Search public skill registries for skills that match your tech stack.\n"));
|
|
5556
|
+
const wantsSkills = await select5({
|
|
5182
5557
|
message: "Search public repos for relevant skills to add to this project?",
|
|
5183
5558
|
choices: [
|
|
5184
5559
|
{ name: "Yes, find skills for my project", value: true },
|
|
@@ -5186,20 +5561,22 @@ async function initCommand(options) {
|
|
|
5186
5561
|
]
|
|
5187
5562
|
});
|
|
5188
5563
|
if (wantsSkills) {
|
|
5564
|
+
trackInitSkillsSearch(true, 0);
|
|
5189
5565
|
try {
|
|
5190
5566
|
await searchAndInstallSkills();
|
|
5191
5567
|
} catch (err) {
|
|
5192
5568
|
if (err.message !== "__exit__") {
|
|
5193
|
-
console.log(
|
|
5569
|
+
console.log(chalk8.dim(" Skills search failed: " + (err.message || "unknown error")));
|
|
5194
5570
|
}
|
|
5195
|
-
console.log(
|
|
5571
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber skills") + chalk8.dim(" later to try again.\n"));
|
|
5196
5572
|
}
|
|
5197
5573
|
} else {
|
|
5198
|
-
|
|
5574
|
+
trackInitSkillsSearch(false, 0);
|
|
5575
|
+
console.log(chalk8.dim(" Skipped. Run ") + chalk8.hex("#83D1EB")("caliber skills") + chalk8.dim(" later to browse.\n"));
|
|
5199
5576
|
}
|
|
5200
|
-
console.log(
|
|
5201
|
-
console.log(
|
|
5202
|
-
console.log(
|
|
5577
|
+
console.log(chalk8.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
|
|
5578
|
+
console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber undo") + chalk8.dim(" to revert changes.\n"));
|
|
5579
|
+
console.log(chalk8.bold(" Next steps:\n"));
|
|
5203
5580
|
console.log(` ${title("caliber score")} See your full config breakdown`);
|
|
5204
5581
|
console.log(` ${title("caliber skills")} Discover community skills for your stack`);
|
|
5205
5582
|
console.log(` ${title("caliber undo")} Revert all changes from this run`);
|
|
@@ -5216,9 +5593,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
5216
5593
|
}
|
|
5217
5594
|
const isValid = await classifyRefineIntent(message);
|
|
5218
5595
|
if (!isValid) {
|
|
5219
|
-
console.log(
|
|
5220
|
-
console.log(
|
|
5221
|
-
console.log(
|
|
5596
|
+
console.log(chalk8.dim(" This doesn't look like a config change request."));
|
|
5597
|
+
console.log(chalk8.dim(" Describe what to add, remove, or modify in your configs."));
|
|
5598
|
+
console.log(chalk8.dim(' Type "done" to accept the current setup.\n'));
|
|
5222
5599
|
continue;
|
|
5223
5600
|
}
|
|
5224
5601
|
const refineSpinner = ora2("Refining setup...").start();
|
|
@@ -5239,16 +5616,16 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
5239
5616
|
});
|
|
5240
5617
|
refineSpinner.succeed("Setup updated");
|
|
5241
5618
|
printSetupSummary(refined);
|
|
5242
|
-
console.log(
|
|
5619
|
+
console.log(chalk8.dim('Type "done" to accept, or describe more changes.'));
|
|
5243
5620
|
} else {
|
|
5244
5621
|
refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
|
|
5245
|
-
console.log(
|
|
5622
|
+
console.log(chalk8.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
|
|
5246
5623
|
}
|
|
5247
5624
|
}
|
|
5248
5625
|
}
|
|
5249
5626
|
function summarizeSetup(action, setup) {
|
|
5250
5627
|
const descriptions = setup.fileDescriptions;
|
|
5251
|
-
const files = descriptions ? Object.entries(descriptions).map(([
|
|
5628
|
+
const files = descriptions ? Object.entries(descriptions).map(([path24, desc]) => ` ${path24}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
|
|
5252
5629
|
return `${action}. Files:
|
|
5253
5630
|
${files}`;
|
|
5254
5631
|
}
|
|
@@ -5302,7 +5679,7 @@ ${JSON.stringify(checkList, null, 2)}`,
|
|
|
5302
5679
|
function promptInput2(question) {
|
|
5303
5680
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
5304
5681
|
return new Promise((resolve2) => {
|
|
5305
|
-
rl.question(
|
|
5682
|
+
rl.question(chalk8.cyan(`${question} `), (answer) => {
|
|
5306
5683
|
rl.close();
|
|
5307
5684
|
resolve2(answer.trim());
|
|
5308
5685
|
});
|
|
@@ -5334,13 +5711,13 @@ async function promptHookType(targetAgent) {
|
|
|
5334
5711
|
choices.push({ name: "Both (Claude Code + pre-commit)", value: "both" });
|
|
5335
5712
|
}
|
|
5336
5713
|
choices.push({ name: "Skip for now", value: "skip" });
|
|
5337
|
-
return
|
|
5714
|
+
return select5({
|
|
5338
5715
|
message: "How would you like to auto-refresh your docs?",
|
|
5339
5716
|
choices
|
|
5340
5717
|
});
|
|
5341
5718
|
}
|
|
5342
5719
|
async function promptReviewAction() {
|
|
5343
|
-
return
|
|
5720
|
+
return select5({
|
|
5344
5721
|
message: "What would you like to do?",
|
|
5345
5722
|
choices: [
|
|
5346
5723
|
{ name: "Accept and apply", value: "accept" },
|
|
@@ -5355,26 +5732,26 @@ function printSetupSummary(setup) {
|
|
|
5355
5732
|
const fileDescriptions = setup.fileDescriptions;
|
|
5356
5733
|
const deletions = setup.deletions;
|
|
5357
5734
|
console.log("");
|
|
5358
|
-
console.log(
|
|
5735
|
+
console.log(chalk8.bold(" Proposed changes:\n"));
|
|
5359
5736
|
const getDescription = (filePath) => {
|
|
5360
5737
|
return fileDescriptions?.[filePath];
|
|
5361
5738
|
};
|
|
5362
5739
|
if (claude) {
|
|
5363
5740
|
if (claude.claudeMd) {
|
|
5364
|
-
const icon =
|
|
5741
|
+
const icon = fs22.existsSync("CLAUDE.md") ? chalk8.yellow("~") : chalk8.green("+");
|
|
5365
5742
|
const desc = getDescription("CLAUDE.md");
|
|
5366
|
-
console.log(` ${icon} ${
|
|
5367
|
-
if (desc) console.log(
|
|
5743
|
+
console.log(` ${icon} ${chalk8.bold("CLAUDE.md")}`);
|
|
5744
|
+
if (desc) console.log(chalk8.dim(` ${desc}`));
|
|
5368
5745
|
console.log("");
|
|
5369
5746
|
}
|
|
5370
5747
|
const skills = claude.skills;
|
|
5371
5748
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
5372
5749
|
for (const skill of skills) {
|
|
5373
5750
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
5374
|
-
const icon =
|
|
5751
|
+
const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
|
|
5375
5752
|
const desc = getDescription(skillPath);
|
|
5376
|
-
console.log(` ${icon} ${
|
|
5377
|
-
console.log(
|
|
5753
|
+
console.log(` ${icon} ${chalk8.bold(skillPath)}`);
|
|
5754
|
+
console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
|
|
5378
5755
|
console.log("");
|
|
5379
5756
|
}
|
|
5380
5757
|
}
|
|
@@ -5382,40 +5759,40 @@ function printSetupSummary(setup) {
|
|
|
5382
5759
|
const codex = setup.codex;
|
|
5383
5760
|
if (codex) {
|
|
5384
5761
|
if (codex.agentsMd) {
|
|
5385
|
-
const icon =
|
|
5762
|
+
const icon = fs22.existsSync("AGENTS.md") ? chalk8.yellow("~") : chalk8.green("+");
|
|
5386
5763
|
const desc = getDescription("AGENTS.md");
|
|
5387
|
-
console.log(` ${icon} ${
|
|
5388
|
-
if (desc) console.log(
|
|
5764
|
+
console.log(` ${icon} ${chalk8.bold("AGENTS.md")}`);
|
|
5765
|
+
if (desc) console.log(chalk8.dim(` ${desc}`));
|
|
5389
5766
|
console.log("");
|
|
5390
5767
|
}
|
|
5391
5768
|
const codexSkills = codex.skills;
|
|
5392
5769
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
5393
5770
|
for (const skill of codexSkills) {
|
|
5394
5771
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
5395
|
-
const icon =
|
|
5772
|
+
const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
|
|
5396
5773
|
const desc = getDescription(skillPath);
|
|
5397
|
-
console.log(` ${icon} ${
|
|
5398
|
-
console.log(
|
|
5774
|
+
console.log(` ${icon} ${chalk8.bold(skillPath)}`);
|
|
5775
|
+
console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
|
|
5399
5776
|
console.log("");
|
|
5400
5777
|
}
|
|
5401
5778
|
}
|
|
5402
5779
|
}
|
|
5403
5780
|
if (cursor) {
|
|
5404
5781
|
if (cursor.cursorrules) {
|
|
5405
|
-
const icon =
|
|
5782
|
+
const icon = fs22.existsSync(".cursorrules") ? chalk8.yellow("~") : chalk8.green("+");
|
|
5406
5783
|
const desc = getDescription(".cursorrules");
|
|
5407
|
-
console.log(` ${icon} ${
|
|
5408
|
-
if (desc) console.log(
|
|
5784
|
+
console.log(` ${icon} ${chalk8.bold(".cursorrules")}`);
|
|
5785
|
+
if (desc) console.log(chalk8.dim(` ${desc}`));
|
|
5409
5786
|
console.log("");
|
|
5410
5787
|
}
|
|
5411
5788
|
const cursorSkills = cursor.skills;
|
|
5412
5789
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
5413
5790
|
for (const skill of cursorSkills) {
|
|
5414
5791
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
5415
|
-
const icon =
|
|
5792
|
+
const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
|
|
5416
5793
|
const desc = getDescription(skillPath);
|
|
5417
|
-
console.log(` ${icon} ${
|
|
5418
|
-
console.log(
|
|
5794
|
+
console.log(` ${icon} ${chalk8.bold(skillPath)}`);
|
|
5795
|
+
console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
|
|
5419
5796
|
console.log("");
|
|
5420
5797
|
}
|
|
5421
5798
|
}
|
|
@@ -5423,40 +5800,40 @@ function printSetupSummary(setup) {
|
|
|
5423
5800
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
5424
5801
|
for (const rule of rules) {
|
|
5425
5802
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
5426
|
-
const icon =
|
|
5803
|
+
const icon = fs22.existsSync(rulePath) ? chalk8.yellow("~") : chalk8.green("+");
|
|
5427
5804
|
const desc = getDescription(rulePath);
|
|
5428
|
-
console.log(` ${icon} ${
|
|
5805
|
+
console.log(` ${icon} ${chalk8.bold(rulePath)}`);
|
|
5429
5806
|
if (desc) {
|
|
5430
|
-
console.log(
|
|
5807
|
+
console.log(chalk8.dim(` ${desc}`));
|
|
5431
5808
|
} else {
|
|
5432
5809
|
const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
|
|
5433
|
-
if (firstLine) console.log(
|
|
5810
|
+
if (firstLine) console.log(chalk8.dim(` ${firstLine.trim().slice(0, 80)}`));
|
|
5434
5811
|
}
|
|
5435
5812
|
console.log("");
|
|
5436
5813
|
}
|
|
5437
5814
|
}
|
|
5438
5815
|
}
|
|
5439
|
-
if (!codex && !
|
|
5440
|
-
console.log(` ${
|
|
5441
|
-
console.log(
|
|
5816
|
+
if (!codex && !fs22.existsSync("AGENTS.md")) {
|
|
5817
|
+
console.log(` ${chalk8.green("+")} ${chalk8.bold("AGENTS.md")}`);
|
|
5818
|
+
console.log(chalk8.dim(" Cross-agent coordination file"));
|
|
5442
5819
|
console.log("");
|
|
5443
5820
|
}
|
|
5444
5821
|
if (Array.isArray(deletions) && deletions.length > 0) {
|
|
5445
5822
|
for (const del of deletions) {
|
|
5446
|
-
console.log(` ${
|
|
5447
|
-
console.log(
|
|
5823
|
+
console.log(` ${chalk8.red("-")} ${chalk8.bold(del.filePath)}`);
|
|
5824
|
+
console.log(chalk8.dim(` ${del.reason}`));
|
|
5448
5825
|
console.log("");
|
|
5449
5826
|
}
|
|
5450
5827
|
}
|
|
5451
|
-
console.log(` ${
|
|
5828
|
+
console.log(` ${chalk8.green("+")} ${chalk8.dim("new")} ${chalk8.yellow("~")} ${chalk8.dim("modified")} ${chalk8.red("-")} ${chalk8.dim("removed")}`);
|
|
5452
5829
|
console.log("");
|
|
5453
5830
|
}
|
|
5454
5831
|
function ensurePermissions() {
|
|
5455
5832
|
const settingsPath = ".claude/settings.json";
|
|
5456
5833
|
let settings = {};
|
|
5457
5834
|
try {
|
|
5458
|
-
if (
|
|
5459
|
-
settings = JSON.parse(
|
|
5835
|
+
if (fs22.existsSync(settingsPath)) {
|
|
5836
|
+
settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
|
|
5460
5837
|
}
|
|
5461
5838
|
} catch {
|
|
5462
5839
|
}
|
|
@@ -5470,12 +5847,12 @@ function ensurePermissions() {
|
|
|
5470
5847
|
"Bash(git *)"
|
|
5471
5848
|
];
|
|
5472
5849
|
settings.permissions = permissions;
|
|
5473
|
-
if (!
|
|
5474
|
-
|
|
5850
|
+
if (!fs22.existsSync(".claude")) fs22.mkdirSync(".claude", { recursive: true });
|
|
5851
|
+
fs22.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
5475
5852
|
}
|
|
5476
5853
|
|
|
5477
5854
|
// src/commands/undo.ts
|
|
5478
|
-
import
|
|
5855
|
+
import chalk9 from "chalk";
|
|
5479
5856
|
import ora3 from "ora";
|
|
5480
5857
|
function undoCommand() {
|
|
5481
5858
|
const spinner = ora3("Reverting setup...").start();
|
|
@@ -5485,29 +5862,31 @@ function undoCommand() {
|
|
|
5485
5862
|
spinner.info("Nothing to undo.");
|
|
5486
5863
|
return;
|
|
5487
5864
|
}
|
|
5865
|
+
trackUndoExecuted();
|
|
5488
5866
|
spinner.succeed("Setup reverted successfully.\n");
|
|
5489
5867
|
if (restored.length > 0) {
|
|
5490
|
-
console.log(
|
|
5868
|
+
console.log(chalk9.cyan(" Restored from backup:"));
|
|
5491
5869
|
for (const file of restored) {
|
|
5492
|
-
console.log(` ${
|
|
5870
|
+
console.log(` ${chalk9.green("\u21A9")} ${file}`);
|
|
5493
5871
|
}
|
|
5494
5872
|
}
|
|
5495
5873
|
if (removed.length > 0) {
|
|
5496
|
-
console.log(
|
|
5874
|
+
console.log(chalk9.cyan(" Removed:"));
|
|
5497
5875
|
for (const file of removed) {
|
|
5498
|
-
console.log(` ${
|
|
5876
|
+
console.log(` ${chalk9.red("\u2717")} ${file}`);
|
|
5499
5877
|
}
|
|
5500
5878
|
}
|
|
5501
5879
|
console.log("");
|
|
5502
5880
|
} catch (err) {
|
|
5503
|
-
spinner.fail(
|
|
5881
|
+
spinner.fail(chalk9.red(err instanceof Error ? err.message : "Undo failed"));
|
|
5504
5882
|
throw new Error("__exit__");
|
|
5505
5883
|
}
|
|
5506
5884
|
}
|
|
5507
5885
|
|
|
5508
5886
|
// src/commands/status.ts
|
|
5509
|
-
import
|
|
5510
|
-
import
|
|
5887
|
+
import chalk10 from "chalk";
|
|
5888
|
+
import fs23 from "fs";
|
|
5889
|
+
init_config();
|
|
5511
5890
|
async function statusCommand(options) {
|
|
5512
5891
|
const config = loadConfig();
|
|
5513
5892
|
const manifest = readManifest();
|
|
@@ -5520,49 +5899,51 @@ async function statusCommand(options) {
|
|
|
5520
5899
|
}, null, 2));
|
|
5521
5900
|
return;
|
|
5522
5901
|
}
|
|
5523
|
-
console.log(
|
|
5902
|
+
console.log(chalk10.bold("\nCaliber Status\n"));
|
|
5524
5903
|
if (config) {
|
|
5525
|
-
console.log(` LLM: ${
|
|
5904
|
+
console.log(` LLM: ${chalk10.green(config.provider)} (${config.model})`);
|
|
5526
5905
|
} else {
|
|
5527
|
-
console.log(` LLM: ${
|
|
5906
|
+
console.log(` LLM: ${chalk10.yellow("Not configured")} \u2014 run ${chalk10.hex("#83D1EB")("caliber config")}`);
|
|
5528
5907
|
}
|
|
5529
5908
|
if (!manifest) {
|
|
5530
|
-
console.log(` Setup: ${
|
|
5531
|
-
console.log(
|
|
5909
|
+
console.log(` Setup: ${chalk10.dim("No setup applied")}`);
|
|
5910
|
+
console.log(chalk10.dim("\n Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.dim(" to get started.\n"));
|
|
5532
5911
|
return;
|
|
5533
5912
|
}
|
|
5534
|
-
console.log(` Files managed: ${
|
|
5913
|
+
console.log(` Files managed: ${chalk10.cyan(manifest.entries.length.toString())}`);
|
|
5535
5914
|
for (const entry of manifest.entries) {
|
|
5536
|
-
const exists =
|
|
5537
|
-
const icon = exists ?
|
|
5915
|
+
const exists = fs23.existsSync(entry.path);
|
|
5916
|
+
const icon = exists ? chalk10.green("\u2713") : chalk10.red("\u2717");
|
|
5538
5917
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
5539
5918
|
}
|
|
5540
5919
|
console.log("");
|
|
5541
5920
|
}
|
|
5542
5921
|
|
|
5543
5922
|
// src/commands/regenerate.ts
|
|
5544
|
-
import
|
|
5923
|
+
import chalk11 from "chalk";
|
|
5545
5924
|
import ora4 from "ora";
|
|
5546
|
-
import
|
|
5925
|
+
import select6 from "@inquirer/select";
|
|
5926
|
+
init_config();
|
|
5547
5927
|
async function regenerateCommand(options) {
|
|
5548
5928
|
const config = loadConfig();
|
|
5549
5929
|
if (!config) {
|
|
5550
|
-
console.log(
|
|
5930
|
+
console.log(chalk11.red("No LLM provider configured. Run ") + chalk11.hex("#83D1EB")("caliber config") + chalk11.red(" first."));
|
|
5551
5931
|
throw new Error("__exit__");
|
|
5552
5932
|
}
|
|
5553
5933
|
const manifest = readManifest();
|
|
5554
5934
|
if (!manifest) {
|
|
5555
|
-
console.log(
|
|
5935
|
+
console.log(chalk11.yellow("No existing setup found. Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.yellow(" first."));
|
|
5556
5936
|
throw new Error("__exit__");
|
|
5557
5937
|
}
|
|
5558
5938
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
5939
|
+
await validateModel({ fast: true });
|
|
5559
5940
|
const spinner = ora4("Analyzing project...").start();
|
|
5560
5941
|
const fingerprint = await collectFingerprint(process.cwd());
|
|
5561
5942
|
spinner.succeed("Project analyzed");
|
|
5562
5943
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5563
5944
|
displayScoreSummary(baselineScore);
|
|
5564
5945
|
if (baselineScore.score === 100) {
|
|
5565
|
-
console.log(
|
|
5946
|
+
console.log(chalk11.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
|
|
5566
5947
|
return;
|
|
5567
5948
|
}
|
|
5568
5949
|
const genSpinner = ora4("Regenerating setup...").start();
|
|
@@ -5603,18 +5984,18 @@ async function regenerateCommand(options) {
|
|
|
5603
5984
|
const setupFiles = collectSetupFiles(generatedSetup);
|
|
5604
5985
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
5605
5986
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
5606
|
-
console.log(
|
|
5607
|
-
${
|
|
5987
|
+
console.log(chalk11.dim(`
|
|
5988
|
+
${chalk11.green(`${staged.newFiles} new`)} / ${chalk11.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
5608
5989
|
`));
|
|
5609
5990
|
if (totalChanges === 0) {
|
|
5610
|
-
console.log(
|
|
5991
|
+
console.log(chalk11.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
5611
5992
|
cleanupStaging();
|
|
5612
5993
|
return;
|
|
5613
5994
|
}
|
|
5614
5995
|
if (options.dryRun) {
|
|
5615
|
-
console.log(
|
|
5996
|
+
console.log(chalk11.yellow("[Dry run] Would write:"));
|
|
5616
5997
|
for (const f of staged.stagedFiles) {
|
|
5617
|
-
console.log(` ${f.isNew ?
|
|
5998
|
+
console.log(` ${f.isNew ? chalk11.green("+") : chalk11.yellow("~")} ${f.relativePath}`);
|
|
5618
5999
|
}
|
|
5619
6000
|
cleanupStaging();
|
|
5620
6001
|
return;
|
|
@@ -5624,7 +6005,7 @@ async function regenerateCommand(options) {
|
|
|
5624
6005
|
const reviewMethod = await promptReviewMethod();
|
|
5625
6006
|
await openReview(reviewMethod, staged.stagedFiles);
|
|
5626
6007
|
}
|
|
5627
|
-
const action = await
|
|
6008
|
+
const action = await select6({
|
|
5628
6009
|
message: "Apply regenerated setup?",
|
|
5629
6010
|
choices: [
|
|
5630
6011
|
{ name: "Accept and apply", value: "accept" },
|
|
@@ -5633,7 +6014,7 @@ async function regenerateCommand(options) {
|
|
|
5633
6014
|
});
|
|
5634
6015
|
cleanupStaging();
|
|
5635
6016
|
if (action === "decline") {
|
|
5636
|
-
console.log(
|
|
6017
|
+
console.log(chalk11.dim("Regeneration cancelled. No files were modified."));
|
|
5637
6018
|
return;
|
|
5638
6019
|
}
|
|
5639
6020
|
const writeSpinner = ora4("Writing config files...").start();
|
|
@@ -5641,20 +6022,20 @@ async function regenerateCommand(options) {
|
|
|
5641
6022
|
const result = writeSetup(generatedSetup);
|
|
5642
6023
|
writeSpinner.succeed("Config files written");
|
|
5643
6024
|
for (const file of result.written) {
|
|
5644
|
-
console.log(` ${
|
|
6025
|
+
console.log(` ${chalk11.green("\u2713")} ${file}`);
|
|
5645
6026
|
}
|
|
5646
6027
|
if (result.deleted.length > 0) {
|
|
5647
6028
|
for (const file of result.deleted) {
|
|
5648
|
-
console.log(` ${
|
|
6029
|
+
console.log(` ${chalk11.red("\u2717")} ${file}`);
|
|
5649
6030
|
}
|
|
5650
6031
|
}
|
|
5651
6032
|
if (result.backupDir) {
|
|
5652
|
-
console.log(
|
|
6033
|
+
console.log(chalk11.dim(`
|
|
5653
6034
|
Backups saved to ${result.backupDir}`));
|
|
5654
6035
|
}
|
|
5655
6036
|
} catch (err) {
|
|
5656
6037
|
writeSpinner.fail("Failed to write files");
|
|
5657
|
-
console.error(
|
|
6038
|
+
console.error(chalk11.red(err instanceof Error ? err.message : "Unknown error"));
|
|
5658
6039
|
throw new Error("__exit__");
|
|
5659
6040
|
}
|
|
5660
6041
|
const sha = getCurrentHeadSha();
|
|
@@ -5666,28 +6047,30 @@ async function regenerateCommand(options) {
|
|
|
5666
6047
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5667
6048
|
if (afterScore.score < baselineScore.score) {
|
|
5668
6049
|
console.log("");
|
|
5669
|
-
console.log(
|
|
6050
|
+
console.log(chalk11.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
5670
6051
|
try {
|
|
5671
6052
|
const { restored, removed } = undoSetup();
|
|
5672
6053
|
if (restored.length > 0 || removed.length > 0) {
|
|
5673
|
-
console.log(
|
|
6054
|
+
console.log(chalk11.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
5674
6055
|
}
|
|
5675
6056
|
} catch {
|
|
5676
6057
|
}
|
|
5677
|
-
console.log(
|
|
6058
|
+
console.log(chalk11.dim(" Run ") + chalk11.hex("#83D1EB")("caliber onboard --force") + chalk11.dim(" to override.\n"));
|
|
5678
6059
|
return;
|
|
5679
6060
|
}
|
|
5680
6061
|
displayScoreDelta(baselineScore, afterScore);
|
|
5681
|
-
|
|
5682
|
-
console.log(
|
|
6062
|
+
trackRegenerateCompleted(action, Date.now());
|
|
6063
|
+
console.log(chalk11.bold.green(" Regeneration complete!"));
|
|
6064
|
+
console.log(chalk11.dim(" Run ") + chalk11.hex("#83D1EB")("caliber undo") + chalk11.dim(" to revert changes.\n"));
|
|
5683
6065
|
}
|
|
5684
6066
|
|
|
5685
6067
|
// src/commands/score.ts
|
|
5686
|
-
import
|
|
6068
|
+
import chalk12 from "chalk";
|
|
5687
6069
|
async function scoreCommand(options) {
|
|
5688
6070
|
const dir = process.cwd();
|
|
5689
6071
|
const target = options.agent ?? readState()?.targetAgent;
|
|
5690
6072
|
const result = computeLocalScore(dir, target);
|
|
6073
|
+
trackScoreComputed(result.score, target);
|
|
5691
6074
|
if (options.json) {
|
|
5692
6075
|
console.log(JSON.stringify(result, null, 2));
|
|
5693
6076
|
return;
|
|
@@ -5697,26 +6080,26 @@ async function scoreCommand(options) {
|
|
|
5697
6080
|
return;
|
|
5698
6081
|
}
|
|
5699
6082
|
displayScore(result);
|
|
5700
|
-
const separator =
|
|
6083
|
+
const separator = chalk12.gray(" " + "\u2500".repeat(53));
|
|
5701
6084
|
console.log(separator);
|
|
5702
6085
|
if (result.score < 40) {
|
|
5703
|
-
console.log(
|
|
6086
|
+
console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber onboard") + chalk12.gray(" to generate a complete, optimized setup."));
|
|
5704
6087
|
} else if (result.score < 70) {
|
|
5705
|
-
console.log(
|
|
6088
|
+
console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber onboard") + chalk12.gray(" to improve your setup."));
|
|
5706
6089
|
} else {
|
|
5707
|
-
console.log(
|
|
6090
|
+
console.log(chalk12.green(" Looking good!") + chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber regenerate") + chalk12.gray(" to rebuild from scratch."));
|
|
5708
6091
|
}
|
|
5709
6092
|
console.log("");
|
|
5710
6093
|
}
|
|
5711
6094
|
|
|
5712
6095
|
// src/commands/refresh.ts
|
|
5713
|
-
import
|
|
5714
|
-
import
|
|
5715
|
-
import
|
|
6096
|
+
import fs25 from "fs";
|
|
6097
|
+
import path19 from "path";
|
|
6098
|
+
import chalk13 from "chalk";
|
|
5716
6099
|
import ora5 from "ora";
|
|
5717
6100
|
|
|
5718
6101
|
// src/lib/git-diff.ts
|
|
5719
|
-
import { execSync as
|
|
6102
|
+
import { execSync as execSync9 } from "child_process";
|
|
5720
6103
|
var MAX_DIFF_BYTES = 1e5;
|
|
5721
6104
|
var DOC_PATTERNS = [
|
|
5722
6105
|
"CLAUDE.md",
|
|
@@ -5730,7 +6113,7 @@ function excludeArgs() {
|
|
|
5730
6113
|
}
|
|
5731
6114
|
function safeExec(cmd) {
|
|
5732
6115
|
try {
|
|
5733
|
-
return
|
|
6116
|
+
return execSync9(cmd, {
|
|
5734
6117
|
encoding: "utf-8",
|
|
5735
6118
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5736
6119
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -5788,37 +6171,37 @@ function collectDiff(lastSha) {
|
|
|
5788
6171
|
}
|
|
5789
6172
|
|
|
5790
6173
|
// src/writers/refresh.ts
|
|
5791
|
-
import
|
|
5792
|
-
import
|
|
6174
|
+
import fs24 from "fs";
|
|
6175
|
+
import path18 from "path";
|
|
5793
6176
|
function writeRefreshDocs(docs) {
|
|
5794
6177
|
const written = [];
|
|
5795
6178
|
if (docs.claudeMd) {
|
|
5796
|
-
|
|
6179
|
+
fs24.writeFileSync("CLAUDE.md", docs.claudeMd);
|
|
5797
6180
|
written.push("CLAUDE.md");
|
|
5798
6181
|
}
|
|
5799
6182
|
if (docs.readmeMd) {
|
|
5800
|
-
|
|
6183
|
+
fs24.writeFileSync("README.md", docs.readmeMd);
|
|
5801
6184
|
written.push("README.md");
|
|
5802
6185
|
}
|
|
5803
6186
|
if (docs.cursorrules) {
|
|
5804
|
-
|
|
6187
|
+
fs24.writeFileSync(".cursorrules", docs.cursorrules);
|
|
5805
6188
|
written.push(".cursorrules");
|
|
5806
6189
|
}
|
|
5807
6190
|
if (docs.cursorRules) {
|
|
5808
|
-
const rulesDir =
|
|
5809
|
-
if (!
|
|
6191
|
+
const rulesDir = path18.join(".cursor", "rules");
|
|
6192
|
+
if (!fs24.existsSync(rulesDir)) fs24.mkdirSync(rulesDir, { recursive: true });
|
|
5810
6193
|
for (const rule of docs.cursorRules) {
|
|
5811
|
-
const filePath =
|
|
5812
|
-
|
|
6194
|
+
const filePath = path18.join(rulesDir, rule.filename);
|
|
6195
|
+
fs24.writeFileSync(filePath, rule.content);
|
|
5813
6196
|
written.push(filePath);
|
|
5814
6197
|
}
|
|
5815
6198
|
}
|
|
5816
6199
|
if (docs.claudeSkills) {
|
|
5817
|
-
const skillsDir =
|
|
5818
|
-
if (!
|
|
6200
|
+
const skillsDir = path18.join(".claude", "skills");
|
|
6201
|
+
if (!fs24.existsSync(skillsDir)) fs24.mkdirSync(skillsDir, { recursive: true });
|
|
5819
6202
|
for (const skill of docs.claudeSkills) {
|
|
5820
|
-
const filePath =
|
|
5821
|
-
|
|
6203
|
+
const filePath = path18.join(skillsDir, skill.filename);
|
|
6204
|
+
fs24.writeFileSync(filePath, skill.content);
|
|
5822
6205
|
written.push(filePath);
|
|
5823
6206
|
}
|
|
5824
6207
|
}
|
|
@@ -5826,6 +6209,7 @@ function writeRefreshDocs(docs) {
|
|
|
5826
6209
|
}
|
|
5827
6210
|
|
|
5828
6211
|
// src/ai/refresh.ts
|
|
6212
|
+
init_config();
|
|
5829
6213
|
async function refreshDocs(diff, existingDocs, projectContext) {
|
|
5830
6214
|
const prompt = buildRefreshPrompt(diff, existingDocs, projectContext);
|
|
5831
6215
|
const fastModel = getFastModel();
|
|
@@ -5889,17 +6273,18 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
5889
6273
|
}
|
|
5890
6274
|
|
|
5891
6275
|
// src/commands/refresh.ts
|
|
6276
|
+
init_config();
|
|
5892
6277
|
function log(quiet, ...args) {
|
|
5893
6278
|
if (!quiet) console.log(...args);
|
|
5894
6279
|
}
|
|
5895
6280
|
function discoverGitRepos(parentDir) {
|
|
5896
6281
|
const repos = [];
|
|
5897
6282
|
try {
|
|
5898
|
-
const entries =
|
|
6283
|
+
const entries = fs25.readdirSync(parentDir, { withFileTypes: true });
|
|
5899
6284
|
for (const entry of entries) {
|
|
5900
6285
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
5901
|
-
const childPath =
|
|
5902
|
-
if (
|
|
6286
|
+
const childPath = path19.join(parentDir, entry.name);
|
|
6287
|
+
if (fs25.existsSync(path19.join(childPath, ".git"))) {
|
|
5903
6288
|
repos.push(childPath);
|
|
5904
6289
|
}
|
|
5905
6290
|
}
|
|
@@ -5909,7 +6294,7 @@ function discoverGitRepos(parentDir) {
|
|
|
5909
6294
|
}
|
|
5910
6295
|
async function refreshSingleRepo(repoDir, options) {
|
|
5911
6296
|
const quiet = !!options.quiet;
|
|
5912
|
-
const prefix = options.label ? `${
|
|
6297
|
+
const prefix = options.label ? `${chalk13.bold(options.label)} ` : "";
|
|
5913
6298
|
const state = readState();
|
|
5914
6299
|
const lastSha = state?.lastRefreshSha ?? null;
|
|
5915
6300
|
const diff = collectDiff(lastSha);
|
|
@@ -5918,7 +6303,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
5918
6303
|
if (currentSha) {
|
|
5919
6304
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
5920
6305
|
}
|
|
5921
|
-
log(quiet,
|
|
6306
|
+
log(quiet, chalk13.dim(`${prefix}No changes since last refresh.`));
|
|
5922
6307
|
return;
|
|
5923
6308
|
}
|
|
5924
6309
|
const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
|
|
@@ -5950,21 +6335,22 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
5950
6335
|
if (options.dryRun) {
|
|
5951
6336
|
spinner?.info(`${prefix}Dry run \u2014 would update:`);
|
|
5952
6337
|
for (const doc of response.docsUpdated) {
|
|
5953
|
-
console.log(` ${
|
|
6338
|
+
console.log(` ${chalk13.yellow("~")} ${doc}`);
|
|
5954
6339
|
}
|
|
5955
6340
|
if (response.changesSummary) {
|
|
5956
|
-
console.log(
|
|
6341
|
+
console.log(chalk13.dim(`
|
|
5957
6342
|
${response.changesSummary}`));
|
|
5958
6343
|
}
|
|
5959
6344
|
return;
|
|
5960
6345
|
}
|
|
5961
6346
|
const written = writeRefreshDocs(response.updatedDocs);
|
|
6347
|
+
trackRefreshCompleted(written.length, Date.now());
|
|
5962
6348
|
spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
|
|
5963
6349
|
for (const file of written) {
|
|
5964
|
-
log(quiet, ` ${
|
|
6350
|
+
log(quiet, ` ${chalk13.green("\u2713")} ${file}`);
|
|
5965
6351
|
}
|
|
5966
6352
|
if (response.changesSummary) {
|
|
5967
|
-
log(quiet,
|
|
6353
|
+
log(quiet, chalk13.dim(`
|
|
5968
6354
|
${response.changesSummary}`));
|
|
5969
6355
|
}
|
|
5970
6356
|
if (currentSha) {
|
|
@@ -5977,9 +6363,10 @@ async function refreshCommand(options) {
|
|
|
5977
6363
|
const config = loadConfig();
|
|
5978
6364
|
if (!config) {
|
|
5979
6365
|
if (quiet) return;
|
|
5980
|
-
console.log(
|
|
6366
|
+
console.log(chalk13.red("No LLM provider configured. Run ") + chalk13.hex("#83D1EB")("caliber config") + chalk13.red(" (e.g. choose Cursor) or set an API key."));
|
|
5981
6367
|
throw new Error("__exit__");
|
|
5982
6368
|
}
|
|
6369
|
+
await validateModel({ fast: true });
|
|
5983
6370
|
if (isGitRepo()) {
|
|
5984
6371
|
await refreshSingleRepo(process.cwd(), options);
|
|
5985
6372
|
return;
|
|
@@ -5987,20 +6374,20 @@ async function refreshCommand(options) {
|
|
|
5987
6374
|
const repos = discoverGitRepos(process.cwd());
|
|
5988
6375
|
if (repos.length === 0) {
|
|
5989
6376
|
if (quiet) return;
|
|
5990
|
-
console.log(
|
|
6377
|
+
console.log(chalk13.red("Not inside a git repository and no git repos found in child directories."));
|
|
5991
6378
|
throw new Error("__exit__");
|
|
5992
6379
|
}
|
|
5993
|
-
log(quiet,
|
|
6380
|
+
log(quiet, chalk13.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
5994
6381
|
`));
|
|
5995
6382
|
const originalDir = process.cwd();
|
|
5996
6383
|
for (const repo of repos) {
|
|
5997
|
-
const repoName =
|
|
6384
|
+
const repoName = path19.basename(repo);
|
|
5998
6385
|
try {
|
|
5999
6386
|
process.chdir(repo);
|
|
6000
6387
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
6001
6388
|
} catch (err) {
|
|
6002
6389
|
if (err instanceof Error && err.message === "__exit__") continue;
|
|
6003
|
-
log(quiet,
|
|
6390
|
+
log(quiet, chalk13.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
|
|
6004
6391
|
}
|
|
6005
6392
|
}
|
|
6006
6393
|
process.chdir(originalDir);
|
|
@@ -6008,13 +6395,13 @@ async function refreshCommand(options) {
|
|
|
6008
6395
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
6009
6396
|
if (quiet) return;
|
|
6010
6397
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
6011
|
-
console.log(
|
|
6398
|
+
console.log(chalk13.red(`Refresh failed: ${msg}`));
|
|
6012
6399
|
throw new Error("__exit__");
|
|
6013
6400
|
}
|
|
6014
6401
|
}
|
|
6015
6402
|
|
|
6016
6403
|
// src/commands/hooks.ts
|
|
6017
|
-
import
|
|
6404
|
+
import chalk14 from "chalk";
|
|
6018
6405
|
var HOOKS = [
|
|
6019
6406
|
{
|
|
6020
6407
|
id: "session-end",
|
|
@@ -6034,13 +6421,13 @@ var HOOKS = [
|
|
|
6034
6421
|
}
|
|
6035
6422
|
];
|
|
6036
6423
|
function printStatus() {
|
|
6037
|
-
console.log(
|
|
6424
|
+
console.log(chalk14.bold("\n Hooks\n"));
|
|
6038
6425
|
for (const hook of HOOKS) {
|
|
6039
6426
|
const installed = hook.isInstalled();
|
|
6040
|
-
const icon = installed ?
|
|
6041
|
-
const state = installed ?
|
|
6427
|
+
const icon = installed ? chalk14.green("\u2713") : chalk14.dim("\u2717");
|
|
6428
|
+
const state = installed ? chalk14.green("enabled") : chalk14.dim("disabled");
|
|
6042
6429
|
console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
|
|
6043
|
-
console.log(
|
|
6430
|
+
console.log(chalk14.dim(` ${hook.description}`));
|
|
6044
6431
|
}
|
|
6045
6432
|
console.log("");
|
|
6046
6433
|
}
|
|
@@ -6049,9 +6436,9 @@ async function hooksCommand(options) {
|
|
|
6049
6436
|
for (const hook of HOOKS) {
|
|
6050
6437
|
const result = hook.install();
|
|
6051
6438
|
if (result.alreadyInstalled) {
|
|
6052
|
-
console.log(
|
|
6439
|
+
console.log(chalk14.dim(` ${hook.label} already enabled.`));
|
|
6053
6440
|
} else {
|
|
6054
|
-
console.log(
|
|
6441
|
+
console.log(chalk14.green(" \u2713") + ` ${hook.label} enabled`);
|
|
6055
6442
|
}
|
|
6056
6443
|
}
|
|
6057
6444
|
return;
|
|
@@ -6060,9 +6447,9 @@ async function hooksCommand(options) {
|
|
|
6060
6447
|
for (const hook of HOOKS) {
|
|
6061
6448
|
const result = hook.remove();
|
|
6062
6449
|
if (result.notFound) {
|
|
6063
|
-
console.log(
|
|
6450
|
+
console.log(chalk14.dim(` ${hook.label} already disabled.`));
|
|
6064
6451
|
} else {
|
|
6065
|
-
console.log(
|
|
6452
|
+
console.log(chalk14.green(" \u2713") + ` ${hook.label} removed`);
|
|
6066
6453
|
}
|
|
6067
6454
|
}
|
|
6068
6455
|
return;
|
|
@@ -6077,18 +6464,18 @@ async function hooksCommand(options) {
|
|
|
6077
6464
|
const states = HOOKS.map((h) => h.isInstalled());
|
|
6078
6465
|
function render() {
|
|
6079
6466
|
const lines = [];
|
|
6080
|
-
lines.push(
|
|
6467
|
+
lines.push(chalk14.bold(" Hooks"));
|
|
6081
6468
|
lines.push("");
|
|
6082
6469
|
for (let i = 0; i < HOOKS.length; i++) {
|
|
6083
6470
|
const hook = HOOKS[i];
|
|
6084
6471
|
const enabled = states[i];
|
|
6085
|
-
const toggle = enabled ?
|
|
6086
|
-
const ptr = i === cursor ?
|
|
6472
|
+
const toggle = enabled ? chalk14.green("[on] ") : chalk14.dim("[off]");
|
|
6473
|
+
const ptr = i === cursor ? chalk14.cyan(">") : " ";
|
|
6087
6474
|
lines.push(` ${ptr} ${toggle} ${hook.label}`);
|
|
6088
|
-
lines.push(
|
|
6475
|
+
lines.push(chalk14.dim(` ${hook.description}`));
|
|
6089
6476
|
}
|
|
6090
6477
|
lines.push("");
|
|
6091
|
-
lines.push(
|
|
6478
|
+
lines.push(chalk14.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
|
|
6092
6479
|
return lines.join("\n");
|
|
6093
6480
|
}
|
|
6094
6481
|
function draw(initial) {
|
|
@@ -6119,16 +6506,16 @@ async function hooksCommand(options) {
|
|
|
6119
6506
|
const wantEnabled = states[i];
|
|
6120
6507
|
if (wantEnabled && !wasInstalled) {
|
|
6121
6508
|
hook.install();
|
|
6122
|
-
console.log(
|
|
6509
|
+
console.log(chalk14.green(" \u2713") + ` ${hook.label} enabled`);
|
|
6123
6510
|
changed++;
|
|
6124
6511
|
} else if (!wantEnabled && wasInstalled) {
|
|
6125
6512
|
hook.remove();
|
|
6126
|
-
console.log(
|
|
6513
|
+
console.log(chalk14.green(" \u2713") + ` ${hook.label} disabled`);
|
|
6127
6514
|
changed++;
|
|
6128
6515
|
}
|
|
6129
6516
|
}
|
|
6130
6517
|
if (changed === 0) {
|
|
6131
|
-
console.log(
|
|
6518
|
+
console.log(chalk14.dim(" No changes."));
|
|
6132
6519
|
}
|
|
6133
6520
|
console.log("");
|
|
6134
6521
|
}
|
|
@@ -6164,7 +6551,7 @@ async function hooksCommand(options) {
|
|
|
6164
6551
|
case "\x1B":
|
|
6165
6552
|
case "":
|
|
6166
6553
|
cleanup();
|
|
6167
|
-
console.log(
|
|
6554
|
+
console.log(chalk14.dim("\n Cancelled.\n"));
|
|
6168
6555
|
resolve2();
|
|
6169
6556
|
break;
|
|
6170
6557
|
}
|
|
@@ -6174,48 +6561,51 @@ async function hooksCommand(options) {
|
|
|
6174
6561
|
}
|
|
6175
6562
|
|
|
6176
6563
|
// src/commands/config.ts
|
|
6177
|
-
|
|
6564
|
+
init_config();
|
|
6565
|
+
import chalk15 from "chalk";
|
|
6178
6566
|
async function configCommand() {
|
|
6179
6567
|
const existing = loadConfig();
|
|
6180
6568
|
if (existing) {
|
|
6181
6569
|
const displayModel = existing.model === "default" && existing.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : existing.model;
|
|
6182
6570
|
const fastModel = getFastModel();
|
|
6183
|
-
console.log(
|
|
6184
|
-
console.log(` Provider: ${
|
|
6185
|
-
console.log(` Model: ${
|
|
6571
|
+
console.log(chalk15.bold("\nCurrent Configuration\n"));
|
|
6572
|
+
console.log(` Provider: ${chalk15.cyan(existing.provider)}`);
|
|
6573
|
+
console.log(` Model: ${chalk15.cyan(displayModel)}`);
|
|
6186
6574
|
if (fastModel) {
|
|
6187
|
-
console.log(` Scan: ${
|
|
6575
|
+
console.log(` Scan: ${chalk15.cyan(fastModel)}`);
|
|
6188
6576
|
}
|
|
6189
6577
|
if (existing.apiKey) {
|
|
6190
6578
|
const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
|
|
6191
|
-
console.log(` API Key: ${
|
|
6579
|
+
console.log(` API Key: ${chalk15.dim(masked)}`);
|
|
6192
6580
|
}
|
|
6193
6581
|
if (existing.provider === "cursor") {
|
|
6194
|
-
console.log(` Seat: ${
|
|
6582
|
+
console.log(` Seat: ${chalk15.dim("Cursor (agent acp)")}`);
|
|
6195
6583
|
}
|
|
6196
6584
|
if (existing.provider === "claude-cli") {
|
|
6197
|
-
console.log(` Seat: ${
|
|
6585
|
+
console.log(` Seat: ${chalk15.dim("Claude Code (claude -p)")}`);
|
|
6198
6586
|
}
|
|
6199
6587
|
if (existing.baseUrl) {
|
|
6200
|
-
console.log(` Base URL: ${
|
|
6588
|
+
console.log(` Base URL: ${chalk15.dim(existing.baseUrl)}`);
|
|
6201
6589
|
}
|
|
6202
6590
|
if (existing.vertexProjectId) {
|
|
6203
|
-
console.log(` Vertex Project: ${
|
|
6204
|
-
console.log(` Vertex Region: ${
|
|
6591
|
+
console.log(` Vertex Project: ${chalk15.dim(existing.vertexProjectId)}`);
|
|
6592
|
+
console.log(` Vertex Region: ${chalk15.dim(existing.vertexRegion || "us-east5")}`);
|
|
6205
6593
|
}
|
|
6206
|
-
console.log(` Source: ${
|
|
6594
|
+
console.log(` Source: ${chalk15.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())}`);
|
|
6207
6595
|
console.log("");
|
|
6208
6596
|
}
|
|
6209
6597
|
await runInteractiveProviderSetup();
|
|
6210
|
-
|
|
6211
|
-
|
|
6598
|
+
const updated = loadConfig();
|
|
6599
|
+
if (updated) trackConfigProviderSet(updated.provider);
|
|
6600
|
+
console.log(chalk15.green("\n\u2713 Configuration saved"));
|
|
6601
|
+
console.log(chalk15.dim(` ${getConfigFilePath()}
|
|
6212
6602
|
`));
|
|
6213
|
-
console.log(
|
|
6214
|
-
console.log(
|
|
6603
|
+
console.log(chalk15.dim(" You can also set environment variables instead:"));
|
|
6604
|
+
console.log(chalk15.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
|
|
6215
6605
|
}
|
|
6216
6606
|
|
|
6217
6607
|
// src/commands/learn.ts
|
|
6218
|
-
import
|
|
6608
|
+
import chalk16 from "chalk";
|
|
6219
6609
|
|
|
6220
6610
|
// src/learner/stdin.ts
|
|
6221
6611
|
var STDIN_TIMEOUT_MS = 5e3;
|
|
@@ -6246,8 +6636,8 @@ function readStdin() {
|
|
|
6246
6636
|
|
|
6247
6637
|
// src/learner/storage.ts
|
|
6248
6638
|
init_constants();
|
|
6249
|
-
import
|
|
6250
|
-
import
|
|
6639
|
+
import fs26 from "fs";
|
|
6640
|
+
import path20 from "path";
|
|
6251
6641
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
6252
6642
|
var DEFAULT_STATE = {
|
|
6253
6643
|
sessionId: null,
|
|
@@ -6255,15 +6645,15 @@ var DEFAULT_STATE = {
|
|
|
6255
6645
|
lastAnalysisTimestamp: null
|
|
6256
6646
|
};
|
|
6257
6647
|
function ensureLearningDir() {
|
|
6258
|
-
if (!
|
|
6259
|
-
|
|
6648
|
+
if (!fs26.existsSync(LEARNING_DIR)) {
|
|
6649
|
+
fs26.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
6260
6650
|
}
|
|
6261
6651
|
}
|
|
6262
6652
|
function sessionFilePath() {
|
|
6263
|
-
return
|
|
6653
|
+
return path20.join(LEARNING_DIR, LEARNING_SESSION_FILE);
|
|
6264
6654
|
}
|
|
6265
6655
|
function stateFilePath() {
|
|
6266
|
-
return
|
|
6656
|
+
return path20.join(LEARNING_DIR, LEARNING_STATE_FILE);
|
|
6267
6657
|
}
|
|
6268
6658
|
function truncateResponse(response) {
|
|
6269
6659
|
const str = JSON.stringify(response);
|
|
@@ -6274,50 +6664,50 @@ function appendEvent(event) {
|
|
|
6274
6664
|
ensureLearningDir();
|
|
6275
6665
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
6276
6666
|
const filePath = sessionFilePath();
|
|
6277
|
-
|
|
6667
|
+
fs26.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
6278
6668
|
const count = getEventCount();
|
|
6279
6669
|
if (count > LEARNING_MAX_EVENTS) {
|
|
6280
|
-
const lines =
|
|
6670
|
+
const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
6281
6671
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
6282
|
-
|
|
6672
|
+
fs26.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
6283
6673
|
}
|
|
6284
6674
|
}
|
|
6285
6675
|
function readAllEvents() {
|
|
6286
6676
|
const filePath = sessionFilePath();
|
|
6287
|
-
if (!
|
|
6288
|
-
const lines =
|
|
6677
|
+
if (!fs26.existsSync(filePath)) return [];
|
|
6678
|
+
const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
6289
6679
|
return lines.map((line) => JSON.parse(line));
|
|
6290
6680
|
}
|
|
6291
6681
|
function getEventCount() {
|
|
6292
6682
|
const filePath = sessionFilePath();
|
|
6293
|
-
if (!
|
|
6294
|
-
const content =
|
|
6683
|
+
if (!fs26.existsSync(filePath)) return 0;
|
|
6684
|
+
const content = fs26.readFileSync(filePath, "utf-8");
|
|
6295
6685
|
return content.split("\n").filter(Boolean).length;
|
|
6296
6686
|
}
|
|
6297
6687
|
function clearSession() {
|
|
6298
6688
|
const filePath = sessionFilePath();
|
|
6299
|
-
if (
|
|
6689
|
+
if (fs26.existsSync(filePath)) fs26.unlinkSync(filePath);
|
|
6300
6690
|
}
|
|
6301
6691
|
function readState2() {
|
|
6302
6692
|
const filePath = stateFilePath();
|
|
6303
|
-
if (!
|
|
6693
|
+
if (!fs26.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
6304
6694
|
try {
|
|
6305
|
-
return JSON.parse(
|
|
6695
|
+
return JSON.parse(fs26.readFileSync(filePath, "utf-8"));
|
|
6306
6696
|
} catch {
|
|
6307
6697
|
return { ...DEFAULT_STATE };
|
|
6308
6698
|
}
|
|
6309
6699
|
}
|
|
6310
6700
|
function writeState2(state) {
|
|
6311
6701
|
ensureLearningDir();
|
|
6312
|
-
|
|
6702
|
+
fs26.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
6313
6703
|
}
|
|
6314
6704
|
function resetState() {
|
|
6315
6705
|
writeState2({ ...DEFAULT_STATE });
|
|
6316
6706
|
}
|
|
6317
6707
|
|
|
6318
6708
|
// src/learner/writer.ts
|
|
6319
|
-
import
|
|
6320
|
-
import
|
|
6709
|
+
import fs27 from "fs";
|
|
6710
|
+
import path21 from "path";
|
|
6321
6711
|
var LEARNED_START = "<!-- caliber:learned -->";
|
|
6322
6712
|
var LEARNED_END = "<!-- /caliber:learned -->";
|
|
6323
6713
|
function writeLearnedContent(update) {
|
|
@@ -6337,8 +6727,8 @@ function writeLearnedContent(update) {
|
|
|
6337
6727
|
function writeLearnedSection(content) {
|
|
6338
6728
|
const claudeMdPath = "CLAUDE.md";
|
|
6339
6729
|
let existing = "";
|
|
6340
|
-
if (
|
|
6341
|
-
existing =
|
|
6730
|
+
if (fs27.existsSync(claudeMdPath)) {
|
|
6731
|
+
existing = fs27.readFileSync(claudeMdPath, "utf-8");
|
|
6342
6732
|
}
|
|
6343
6733
|
const section = `${LEARNED_START}
|
|
6344
6734
|
${content}
|
|
@@ -6352,15 +6742,15 @@ ${LEARNED_END}`;
|
|
|
6352
6742
|
const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
6353
6743
|
updated = existing + separator + "\n" + section + "\n";
|
|
6354
6744
|
}
|
|
6355
|
-
|
|
6745
|
+
fs27.writeFileSync(claudeMdPath, updated);
|
|
6356
6746
|
}
|
|
6357
6747
|
function writeLearnedSkill(skill) {
|
|
6358
|
-
const skillDir =
|
|
6359
|
-
if (!
|
|
6360
|
-
const skillPath =
|
|
6361
|
-
if (!skill.isNew &&
|
|
6362
|
-
const existing =
|
|
6363
|
-
|
|
6748
|
+
const skillDir = path21.join(".claude", "skills", skill.name);
|
|
6749
|
+
if (!fs27.existsSync(skillDir)) fs27.mkdirSync(skillDir, { recursive: true });
|
|
6750
|
+
const skillPath = path21.join(skillDir, "SKILL.md");
|
|
6751
|
+
if (!skill.isNew && fs27.existsSync(skillPath)) {
|
|
6752
|
+
const existing = fs27.readFileSync(skillPath, "utf-8");
|
|
6753
|
+
fs27.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
6364
6754
|
} else {
|
|
6365
6755
|
const frontmatter = [
|
|
6366
6756
|
"---",
|
|
@@ -6369,14 +6759,14 @@ function writeLearnedSkill(skill) {
|
|
|
6369
6759
|
"---",
|
|
6370
6760
|
""
|
|
6371
6761
|
].join("\n");
|
|
6372
|
-
|
|
6762
|
+
fs27.writeFileSync(skillPath, frontmatter + skill.content);
|
|
6373
6763
|
}
|
|
6374
6764
|
return skillPath;
|
|
6375
6765
|
}
|
|
6376
6766
|
function readLearnedSection() {
|
|
6377
6767
|
const claudeMdPath = "CLAUDE.md";
|
|
6378
|
-
if (!
|
|
6379
|
-
const content =
|
|
6768
|
+
if (!fs27.existsSync(claudeMdPath)) return null;
|
|
6769
|
+
const content = fs27.readFileSync(claudeMdPath, "utf-8");
|
|
6380
6770
|
const startIdx = content.indexOf(LEARNED_START);
|
|
6381
6771
|
const endIdx = content.indexOf(LEARNED_END);
|
|
6382
6772
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
@@ -6384,6 +6774,7 @@ function readLearnedSection() {
|
|
|
6384
6774
|
}
|
|
6385
6775
|
|
|
6386
6776
|
// src/ai/learn.ts
|
|
6777
|
+
init_config();
|
|
6387
6778
|
var MAX_PROMPT_TOKENS = 1e5;
|
|
6388
6779
|
function formatEventsForPrompt(events) {
|
|
6389
6780
|
return events.map((e, i) => {
|
|
@@ -6457,6 +6848,7 @@ ${eventsText}`;
|
|
|
6457
6848
|
}
|
|
6458
6849
|
|
|
6459
6850
|
// src/commands/learn.ts
|
|
6851
|
+
init_config();
|
|
6460
6852
|
async function learnObserveCommand(options) {
|
|
6461
6853
|
try {
|
|
6462
6854
|
const raw = await readStdin();
|
|
@@ -6494,6 +6886,7 @@ async function learnFinalizeCommand() {
|
|
|
6494
6886
|
resetState();
|
|
6495
6887
|
return;
|
|
6496
6888
|
}
|
|
6889
|
+
await validateModel();
|
|
6497
6890
|
const existingConfigs = readExistingConfigs(process.cwd());
|
|
6498
6891
|
const existingLearnedSection = readLearnedSection();
|
|
6499
6892
|
const existingSkills = existingConfigs.claudeSkills || [];
|
|
@@ -6518,57 +6911,98 @@ async function learnFinalizeCommand() {
|
|
|
6518
6911
|
async function learnInstallCommand() {
|
|
6519
6912
|
const result = installLearningHooks();
|
|
6520
6913
|
if (result.alreadyInstalled) {
|
|
6521
|
-
console.log(
|
|
6914
|
+
console.log(chalk16.dim("Learning hooks already installed."));
|
|
6522
6915
|
return;
|
|
6523
6916
|
}
|
|
6524
|
-
console.log(
|
|
6525
|
-
console.log(
|
|
6526
|
-
console.log(
|
|
6917
|
+
console.log(chalk16.green("\u2713") + " Learning hooks installed in .claude/settings.json");
|
|
6918
|
+
console.log(chalk16.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
|
|
6919
|
+
console.log(chalk16.dim(" Session learnings will be written to CLAUDE.md and skills."));
|
|
6527
6920
|
}
|
|
6528
6921
|
async function learnRemoveCommand() {
|
|
6529
6922
|
const result = removeLearningHooks();
|
|
6530
6923
|
if (result.notFound) {
|
|
6531
|
-
console.log(
|
|
6924
|
+
console.log(chalk16.dim("Learning hooks not found."));
|
|
6532
6925
|
return;
|
|
6533
6926
|
}
|
|
6534
|
-
console.log(
|
|
6927
|
+
console.log(chalk16.green("\u2713") + " Learning hooks removed from .claude/settings.json");
|
|
6535
6928
|
}
|
|
6536
6929
|
async function learnStatusCommand() {
|
|
6537
6930
|
const installed = areLearningHooksInstalled();
|
|
6538
6931
|
const state = readState2();
|
|
6539
6932
|
const eventCount = getEventCount();
|
|
6540
|
-
console.log(
|
|
6933
|
+
console.log(chalk16.bold("Session Learning Status"));
|
|
6541
6934
|
console.log();
|
|
6542
6935
|
if (installed) {
|
|
6543
|
-
console.log(
|
|
6936
|
+
console.log(chalk16.green("\u2713") + " Learning hooks are " + chalk16.green("installed"));
|
|
6544
6937
|
} else {
|
|
6545
|
-
console.log(
|
|
6546
|
-
console.log(
|
|
6938
|
+
console.log(chalk16.dim("\u2717") + " Learning hooks are " + chalk16.yellow("not installed"));
|
|
6939
|
+
console.log(chalk16.dim(" Run `caliber learn install` to enable session learning."));
|
|
6547
6940
|
}
|
|
6548
6941
|
console.log();
|
|
6549
|
-
console.log(`Events recorded: ${
|
|
6550
|
-
console.log(`Total this session: ${
|
|
6942
|
+
console.log(`Events recorded: ${chalk16.cyan(String(eventCount))}`);
|
|
6943
|
+
console.log(`Total this session: ${chalk16.cyan(String(state.eventCount))}`);
|
|
6551
6944
|
if (state.lastAnalysisTimestamp) {
|
|
6552
|
-
console.log(`Last analysis: ${
|
|
6945
|
+
console.log(`Last analysis: ${chalk16.cyan(state.lastAnalysisTimestamp)}`);
|
|
6553
6946
|
} else {
|
|
6554
|
-
console.log(`Last analysis: ${
|
|
6947
|
+
console.log(`Last analysis: ${chalk16.dim("none")}`);
|
|
6555
6948
|
}
|
|
6556
6949
|
const learnedSection = readLearnedSection();
|
|
6557
6950
|
if (learnedSection) {
|
|
6558
6951
|
const lineCount = learnedSection.split("\n").filter(Boolean).length;
|
|
6559
6952
|
console.log(`
|
|
6560
|
-
Learned items in CLAUDE.md: ${
|
|
6953
|
+
Learned items in CLAUDE.md: ${chalk16.cyan(String(lineCount))}`);
|
|
6561
6954
|
}
|
|
6562
6955
|
}
|
|
6563
6956
|
|
|
6564
6957
|
// src/cli.ts
|
|
6565
|
-
var __dirname =
|
|
6958
|
+
var __dirname = path22.dirname(fileURLToPath(import.meta.url));
|
|
6566
6959
|
var pkg = JSON.parse(
|
|
6567
|
-
|
|
6960
|
+
fs28.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
6568
6961
|
);
|
|
6569
6962
|
var program = new Command();
|
|
6570
6963
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
6571
|
-
program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("Configure your coding agent environment").version(displayVersion);
|
|
6964
|
+
program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("Configure your coding agent environment").version(displayVersion).option("--no-traces", "Disable anonymous telemetry for this run");
|
|
6965
|
+
function tracked(commandName, handler) {
|
|
6966
|
+
const wrapper = async (...args) => {
|
|
6967
|
+
const start = Date.now();
|
|
6968
|
+
trackEvent("command_started", {
|
|
6969
|
+
command: commandName,
|
|
6970
|
+
cli_version: pkg.version
|
|
6971
|
+
});
|
|
6972
|
+
try {
|
|
6973
|
+
await handler(...args);
|
|
6974
|
+
trackEvent("command_completed", {
|
|
6975
|
+
command: commandName,
|
|
6976
|
+
duration_ms: Date.now() - start,
|
|
6977
|
+
success: true
|
|
6978
|
+
});
|
|
6979
|
+
} catch (err) {
|
|
6980
|
+
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
|
6981
|
+
const errorType = err instanceof Error ? err.constructor.name : typeof err;
|
|
6982
|
+
if (errorMessage !== "__exit__") {
|
|
6983
|
+
trackEvent("command_error", {
|
|
6984
|
+
command: commandName,
|
|
6985
|
+
error_type: errorType,
|
|
6986
|
+
error_message: errorMessage
|
|
6987
|
+
});
|
|
6988
|
+
}
|
|
6989
|
+
trackEvent("command_completed", {
|
|
6990
|
+
command: commandName,
|
|
6991
|
+
duration_ms: Date.now() - start,
|
|
6992
|
+
success: false
|
|
6993
|
+
});
|
|
6994
|
+
throw err;
|
|
6995
|
+
}
|
|
6996
|
+
};
|
|
6997
|
+
return wrapper;
|
|
6998
|
+
}
|
|
6999
|
+
program.hook("preAction", (thisCommand) => {
|
|
7000
|
+
const opts = thisCommand.optsWithGlobals();
|
|
7001
|
+
if (opts.traces === false) {
|
|
7002
|
+
setTelemetryDisabled(true);
|
|
7003
|
+
}
|
|
7004
|
+
initTelemetry();
|
|
7005
|
+
});
|
|
6572
7006
|
function parseAgentOption(value) {
|
|
6573
7007
|
if (value === "both") return ["claude", "cursor"];
|
|
6574
7008
|
if (value === "all") return ["claude", "cursor", "codex"];
|
|
@@ -6580,39 +7014,39 @@ function parseAgentOption(value) {
|
|
|
6580
7014
|
}
|
|
6581
7015
|
return agents;
|
|
6582
7016
|
}
|
|
6583
|
-
program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(initCommand);
|
|
6584
|
-
program.command("undo").description("Revert all config changes made by Caliber").action(undoCommand);
|
|
6585
|
-
program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(statusCommand);
|
|
6586
|
-
program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(regenerateCommand);
|
|
6587
|
-
program.command("config").description("Configure LLM provider, API key, and model").action(configCommand);
|
|
6588
|
-
program.command("skills").description("Discover and install community skills for your project").action(recommendCommand);
|
|
6589
|
-
program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).action(scoreCommand);
|
|
6590
|
-
program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(refreshCommand);
|
|
6591
|
-
program.command("hooks").description("Manage auto-refresh hooks (toggle interactively)").option("--install", "Enable all hooks non-interactively").option("--remove", "Disable all hooks non-interactively").action(hooksCommand);
|
|
7017
|
+
program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(tracked("onboard", initCommand));
|
|
7018
|
+
program.command("undo").description("Revert all config changes made by Caliber").action(tracked("undo", undoCommand));
|
|
7019
|
+
program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(tracked("status", statusCommand));
|
|
7020
|
+
program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
|
|
7021
|
+
program.command("config").description("Configure LLM provider, API key, and model").action(tracked("config", configCommand));
|
|
7022
|
+
program.command("skills").description("Discover and install community skills for your project").action(tracked("skills", recommendCommand));
|
|
7023
|
+
program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).action(tracked("score", scoreCommand));
|
|
7024
|
+
program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(tracked("refresh", refreshCommand));
|
|
7025
|
+
program.command("hooks").description("Manage auto-refresh hooks (toggle interactively)").option("--install", "Enable all hooks non-interactively").option("--remove", "Disable all hooks non-interactively").action(tracked("hooks", hooksCommand));
|
|
6592
7026
|
var learn = program.command("learn", { hidden: true }).description("[dev] Session learning \u2014 observe tool usage and extract reusable instructions");
|
|
6593
|
-
learn.command("observe").description("Record a tool event from stdin (called by hooks)").option("--failure", "Mark event as a tool failure").action(learnObserveCommand);
|
|
6594
|
-
learn.command("finalize").description("Analyze session events and update CLAUDE.md (called on SessionEnd)").action(learnFinalizeCommand);
|
|
6595
|
-
learn.command("install").description("Install learning hooks into .claude/settings.json").action(learnInstallCommand);
|
|
6596
|
-
learn.command("remove").description("Remove learning hooks from .claude/settings.json").action(learnRemoveCommand);
|
|
6597
|
-
learn.command("status").description("Show learning system status").action(learnStatusCommand);
|
|
7027
|
+
learn.command("observe").description("Record a tool event from stdin (called by hooks)").option("--failure", "Mark event as a tool failure").action(tracked("learn:observe", learnObserveCommand));
|
|
7028
|
+
learn.command("finalize").description("Analyze session events and update CLAUDE.md (called on SessionEnd)").action(tracked("learn:finalize", learnFinalizeCommand));
|
|
7029
|
+
learn.command("install").description("Install learning hooks into .claude/settings.json").action(tracked("learn:install", learnInstallCommand));
|
|
7030
|
+
learn.command("remove").description("Remove learning hooks from .claude/settings.json").action(tracked("learn:remove", learnRemoveCommand));
|
|
7031
|
+
learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
|
|
6598
7032
|
|
|
6599
7033
|
// src/utils/version-check.ts
|
|
6600
|
-
import
|
|
6601
|
-
import
|
|
7034
|
+
import fs29 from "fs";
|
|
7035
|
+
import path23 from "path";
|
|
6602
7036
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6603
|
-
import { execSync as
|
|
6604
|
-
import
|
|
7037
|
+
import { execSync as execSync10 } from "child_process";
|
|
7038
|
+
import chalk17 from "chalk";
|
|
6605
7039
|
import ora6 from "ora";
|
|
6606
7040
|
import confirm from "@inquirer/confirm";
|
|
6607
|
-
var __dirname_vc =
|
|
7041
|
+
var __dirname_vc = path23.dirname(fileURLToPath2(import.meta.url));
|
|
6608
7042
|
var pkg2 = JSON.parse(
|
|
6609
|
-
|
|
7043
|
+
fs29.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
6610
7044
|
);
|
|
6611
7045
|
function getInstalledVersion() {
|
|
6612
7046
|
try {
|
|
6613
|
-
const globalRoot =
|
|
6614
|
-
const pkgPath =
|
|
6615
|
-
return JSON.parse(
|
|
7047
|
+
const globalRoot = execSync10("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7048
|
+
const pkgPath = path23.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
7049
|
+
return JSON.parse(fs29.readFileSync(pkgPath, "utf-8")).version;
|
|
6616
7050
|
} catch {
|
|
6617
7051
|
return null;
|
|
6618
7052
|
}
|
|
@@ -6635,17 +7069,17 @@ async function checkForUpdates() {
|
|
|
6635
7069
|
const isInteractive = process.stdin.isTTY === true;
|
|
6636
7070
|
if (!isInteractive) {
|
|
6637
7071
|
console.log(
|
|
6638
|
-
|
|
7072
|
+
chalk17.yellow(
|
|
6639
7073
|
`
|
|
6640
7074
|
Update available: ${current} -> ${latest}
|
|
6641
|
-
Run ${
|
|
7075
|
+
Run ${chalk17.bold("npm install -g @rely-ai/caliber")} to upgrade.
|
|
6642
7076
|
`
|
|
6643
7077
|
)
|
|
6644
7078
|
);
|
|
6645
7079
|
return;
|
|
6646
7080
|
}
|
|
6647
7081
|
console.log(
|
|
6648
|
-
|
|
7082
|
+
chalk17.yellow(`
|
|
6649
7083
|
Update available: ${current} -> ${latest}`)
|
|
6650
7084
|
);
|
|
6651
7085
|
const shouldUpdate = await confirm({ message: "Would you like to update now? (Y/n)", default: true });
|
|
@@ -6655,7 +7089,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
6655
7089
|
}
|
|
6656
7090
|
const spinner = ora6("Updating caliber...").start();
|
|
6657
7091
|
try {
|
|
6658
|
-
|
|
7092
|
+
execSync10(`npm install -g @rely-ai/caliber@${latest}`, {
|
|
6659
7093
|
stdio: "pipe",
|
|
6660
7094
|
timeout: 12e4,
|
|
6661
7095
|
env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
|
|
@@ -6663,16 +7097,16 @@ Update available: ${current} -> ${latest}`)
|
|
|
6663
7097
|
const installed = getInstalledVersion();
|
|
6664
7098
|
if (installed !== latest) {
|
|
6665
7099
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
6666
|
-
console.log(
|
|
7100
|
+
console.log(chalk17.yellow(`Run ${chalk17.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
|
|
6667
7101
|
`));
|
|
6668
7102
|
return;
|
|
6669
7103
|
}
|
|
6670
|
-
spinner.succeed(
|
|
7104
|
+
spinner.succeed(chalk17.green(`Updated to ${latest}`));
|
|
6671
7105
|
const args = process.argv.slice(2);
|
|
6672
|
-
console.log(
|
|
7106
|
+
console.log(chalk17.dim(`
|
|
6673
7107
|
Restarting: caliber ${args.join(" ")}
|
|
6674
7108
|
`));
|
|
6675
|
-
|
|
7109
|
+
execSync10(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
6676
7110
|
stdio: "inherit",
|
|
6677
7111
|
env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
|
|
6678
7112
|
});
|
|
@@ -6682,11 +7116,11 @@ Restarting: caliber ${args.join(" ")}
|
|
|
6682
7116
|
if (err instanceof Error) {
|
|
6683
7117
|
const stderr = err.stderr;
|
|
6684
7118
|
const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
|
|
6685
|
-
if (errMsg && !errMsg.includes("SIGTERM")) console.log(
|
|
7119
|
+
if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk17.dim(` ${errMsg}`));
|
|
6686
7120
|
}
|
|
6687
7121
|
console.log(
|
|
6688
|
-
|
|
6689
|
-
`Run ${
|
|
7122
|
+
chalk17.yellow(
|
|
7123
|
+
`Run ${chalk17.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
|
|
6690
7124
|
`
|
|
6691
7125
|
)
|
|
6692
7126
|
);
|
|
@@ -6706,5 +7140,8 @@ program.parseAsync().catch((err) => {
|
|
|
6706
7140
|
console.error(msg);
|
|
6707
7141
|
}
|
|
6708
7142
|
process.exitCode = 1;
|
|
6709
|
-
}).finally(() =>
|
|
7143
|
+
}).finally(async () => {
|
|
7144
|
+
await flushTelemetry();
|
|
7145
|
+
process.exit(Number(process.exitCode ?? 0));
|
|
7146
|
+
});
|
|
6710
7147
|
//# sourceMappingURL=bin.js.map
|