@rely-ai/caliber 1.6.1 → 1.7.0
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 +604 -403
- package/package.json +1 -1
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, {
|
|
@@ -56,10 +170,10 @@ import path21 from "path";
|
|
|
56
170
|
import { fileURLToPath } from "url";
|
|
57
171
|
|
|
58
172
|
// src/commands/onboard.ts
|
|
59
|
-
import
|
|
173
|
+
import chalk7 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
178
|
import fs21 from "fs";
|
|
65
179
|
|
|
@@ -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;
|
|
@@ -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 chalk6 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
|
|
|
@@ -4305,6 +4494,7 @@ function hashJson(obj) {
|
|
|
4305
4494
|
}
|
|
4306
4495
|
|
|
4307
4496
|
// src/commands/recommend.ts
|
|
4497
|
+
init_config();
|
|
4308
4498
|
function detectLocalPlatforms() {
|
|
4309
4499
|
const items = scanLocalState(process.cwd());
|
|
4310
4500
|
const platforms = /* @__PURE__ */ new Set();
|
|
@@ -4604,7 +4794,7 @@ function extractTopDeps() {
|
|
|
4604
4794
|
}
|
|
4605
4795
|
}
|
|
4606
4796
|
async function recommendCommand() {
|
|
4607
|
-
const proceed = await
|
|
4797
|
+
const proceed = await select4({
|
|
4608
4798
|
message: "Search public repos for relevant skills to add to this project?",
|
|
4609
4799
|
choices: [
|
|
4610
4800
|
{ name: "Yes, find skills for my project", value: true },
|
|
@@ -4612,7 +4802,7 @@ async function recommendCommand() {
|
|
|
4612
4802
|
]
|
|
4613
4803
|
});
|
|
4614
4804
|
if (!proceed) {
|
|
4615
|
-
console.log(
|
|
4805
|
+
console.log(chalk6.dim(" Cancelled.\n"));
|
|
4616
4806
|
return;
|
|
4617
4807
|
}
|
|
4618
4808
|
await searchAndInstallSkills();
|
|
@@ -4627,7 +4817,7 @@ async function searchAndInstallSkills() {
|
|
|
4627
4817
|
...extractTopDeps()
|
|
4628
4818
|
].filter(Boolean))];
|
|
4629
4819
|
if (technologies.length === 0) {
|
|
4630
|
-
console.log(
|
|
4820
|
+
console.log(chalk6.yellow("Could not detect any languages or dependencies. Try running from a project root."));
|
|
4631
4821
|
throw new Error("__exit__");
|
|
4632
4822
|
}
|
|
4633
4823
|
const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
|
|
@@ -4644,7 +4834,7 @@ async function searchAndInstallSkills() {
|
|
|
4644
4834
|
return;
|
|
4645
4835
|
}
|
|
4646
4836
|
searchSpinner.succeed(
|
|
4647
|
-
`Found ${allCandidates.length} skills` + (filteredCount > 0 ?
|
|
4837
|
+
`Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk6.dim(` (${filteredCount} already installed)`) : "")
|
|
4648
4838
|
);
|
|
4649
4839
|
let results;
|
|
4650
4840
|
const config = loadConfig();
|
|
@@ -4678,7 +4868,7 @@ async function searchAndInstallSkills() {
|
|
|
4678
4868
|
}
|
|
4679
4869
|
const unavailableCount = results.length - available.length;
|
|
4680
4870
|
fetchSpinner.succeed(
|
|
4681
|
-
`${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ?
|
|
4871
|
+
`${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk6.dim(` (${unavailableCount} unavailable)`) : "")
|
|
4682
4872
|
);
|
|
4683
4873
|
const selected = await interactiveSelect(available);
|
|
4684
4874
|
if (selected?.length) {
|
|
@@ -4701,30 +4891,30 @@ async function interactiveSelect(recs) {
|
|
|
4701
4891
|
const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
|
|
4702
4892
|
const prefixWidth = 8;
|
|
4703
4893
|
const scoreWidth = 6;
|
|
4704
|
-
lines.push(
|
|
4894
|
+
lines.push(chalk6.bold(" Skills"));
|
|
4705
4895
|
lines.push("");
|
|
4706
4896
|
if (hasScores) {
|
|
4707
|
-
const header = " ".repeat(prefixWidth) +
|
|
4897
|
+
const header = " ".repeat(prefixWidth) + chalk6.dim("Score".padEnd(scoreWidth)) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Why");
|
|
4708
4898
|
lines.push(header);
|
|
4709
4899
|
} else {
|
|
4710
|
-
const header = " ".repeat(prefixWidth) +
|
|
4900
|
+
const header = " ".repeat(prefixWidth) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Technology".padEnd(18)) + chalk6.dim("Source");
|
|
4711
4901
|
lines.push(header);
|
|
4712
4902
|
}
|
|
4713
|
-
lines.push(
|
|
4903
|
+
lines.push(chalk6.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
|
|
4714
4904
|
for (let i = 0; i < recs.length; i++) {
|
|
4715
4905
|
const rec = recs[i];
|
|
4716
|
-
const check = selected.has(i) ?
|
|
4717
|
-
const ptr = i === cursor ?
|
|
4906
|
+
const check = selected.has(i) ? chalk6.green("[x]") : "[ ]";
|
|
4907
|
+
const ptr = i === cursor ? chalk6.cyan(">") : " ";
|
|
4718
4908
|
if (hasScores) {
|
|
4719
|
-
const scoreColor = rec.score >= 90 ?
|
|
4909
|
+
const scoreColor = rec.score >= 90 ? chalk6.green : rec.score >= 70 ? chalk6.yellow : chalk6.dim;
|
|
4720
4910
|
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)}${
|
|
4911
|
+
lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk6.dim(rec.reason.slice(0, reasonMax))}`);
|
|
4722
4912
|
} else {
|
|
4723
|
-
lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${
|
|
4913
|
+
lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk6.dim(rec.source_url || "")}`);
|
|
4724
4914
|
}
|
|
4725
4915
|
}
|
|
4726
4916
|
lines.push("");
|
|
4727
|
-
lines.push(
|
|
4917
|
+
lines.push(chalk6.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
|
|
4728
4918
|
return lines.join("\n");
|
|
4729
4919
|
}
|
|
4730
4920
|
function draw(initial) {
|
|
@@ -4773,7 +4963,7 @@ async function interactiveSelect(recs) {
|
|
|
4773
4963
|
case "\n":
|
|
4774
4964
|
cleanup();
|
|
4775
4965
|
if (selected.size === 0) {
|
|
4776
|
-
console.log(
|
|
4966
|
+
console.log(chalk6.dim("\n No skills selected.\n"));
|
|
4777
4967
|
resolve2(null);
|
|
4778
4968
|
} else {
|
|
4779
4969
|
resolve2(Array.from(selected).sort().map((i) => recs[i]));
|
|
@@ -4783,7 +4973,7 @@ async function interactiveSelect(recs) {
|
|
|
4783
4973
|
case "\x1B":
|
|
4784
4974
|
case "":
|
|
4785
4975
|
cleanup();
|
|
4786
|
-
console.log(
|
|
4976
|
+
console.log(chalk6.dim("\n Cancelled.\n"));
|
|
4787
4977
|
resolve2(null);
|
|
4788
4978
|
break;
|
|
4789
4979
|
}
|
|
@@ -4846,7 +5036,7 @@ async function installSkills(recs, platforms, contentMap) {
|
|
|
4846
5036
|
if (installed.length > 0) {
|
|
4847
5037
|
spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
|
|
4848
5038
|
for (const p of installed) {
|
|
4849
|
-
console.log(
|
|
5039
|
+
console.log(chalk6.green(` \u2713 ${p}`));
|
|
4850
5040
|
}
|
|
4851
5041
|
} else {
|
|
4852
5042
|
spinner.fail("No skills were installed");
|
|
@@ -4859,19 +5049,19 @@ function printSkills(recs) {
|
|
|
4859
5049
|
const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
|
|
4860
5050
|
const scoreWidth = 6;
|
|
4861
5051
|
const prefixWidth = 2;
|
|
4862
|
-
console.log(
|
|
5052
|
+
console.log(chalk6.bold("\n Skills\n"));
|
|
4863
5053
|
if (hasScores) {
|
|
4864
|
-
console.log(" ".repeat(prefixWidth) +
|
|
5054
|
+
console.log(" ".repeat(prefixWidth) + chalk6.dim("Score".padEnd(scoreWidth)) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Why"));
|
|
4865
5055
|
} else {
|
|
4866
|
-
console.log(" ".repeat(prefixWidth) +
|
|
5056
|
+
console.log(" ".repeat(prefixWidth) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Technology".padEnd(18)) + chalk6.dim("Source"));
|
|
4867
5057
|
}
|
|
4868
|
-
console.log(
|
|
5058
|
+
console.log(chalk6.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
|
|
4869
5059
|
for (const rec of recs) {
|
|
4870
5060
|
if (hasScores) {
|
|
4871
5061
|
const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
|
|
4872
|
-
console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${
|
|
5062
|
+
console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk6.dim(rec.reason.slice(0, reasonMax))}`);
|
|
4873
5063
|
} else {
|
|
4874
|
-
console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${
|
|
5064
|
+
console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk6.dim(rec.source_url || "")}`);
|
|
4875
5065
|
}
|
|
4876
5066
|
}
|
|
4877
5067
|
console.log("");
|
|
@@ -4879,8 +5069,8 @@ function printSkills(recs) {
|
|
|
4879
5069
|
|
|
4880
5070
|
// src/commands/onboard.ts
|
|
4881
5071
|
async function initCommand(options) {
|
|
4882
|
-
const brand =
|
|
4883
|
-
const title =
|
|
5072
|
+
const brand = chalk7.hex("#EB9D83");
|
|
5073
|
+
const title = chalk7.hex("#83D1EB");
|
|
4884
5074
|
console.log(brand.bold(`
|
|
4885
5075
|
\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
5076
|
\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 +5079,21 @@ async function initCommand(options) {
|
|
|
4889
5079
|
\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
5080
|
\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
5081
|
`));
|
|
4892
|
-
console.log(
|
|
5082
|
+
console.log(chalk7.dim(" Onboard your project for AI-assisted development\n"));
|
|
4893
5083
|
console.log(title.bold(" Welcome to Caliber\n"));
|
|
4894
|
-
console.log(
|
|
4895
|
-
console.log(
|
|
5084
|
+
console.log(chalk7.dim(" Caliber analyzes your codebase and creates tailored config files"));
|
|
5085
|
+
console.log(chalk7.dim(" so your AI coding agents understand your project from day one.\n"));
|
|
4896
5086
|
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(
|
|
5087
|
+
console.log(chalk7.dim(" 1. Connect Set up your LLM provider"));
|
|
5088
|
+
console.log(chalk7.dim(" 2. Discover Analyze your code, dependencies, and structure"));
|
|
5089
|
+
console.log(chalk7.dim(" 3. Generate Create config files tailored to your project"));
|
|
5090
|
+
console.log(chalk7.dim(" 4. Review Preview, refine, and apply the changes"));
|
|
5091
|
+
console.log(chalk7.dim(" 5. Enhance Discover MCP servers for your tools"));
|
|
5092
|
+
console.log(chalk7.dim(" 6. Skills Browse community skills for your stack\n"));
|
|
4903
5093
|
console.log(title.bold(" Step 1/6 \u2014 Connect your LLM\n"));
|
|
4904
5094
|
let config = loadConfig();
|
|
4905
5095
|
if (!config) {
|
|
4906
|
-
console.log(
|
|
5096
|
+
console.log(chalk7.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
|
|
4907
5097
|
try {
|
|
4908
5098
|
await runInteractiveProviderSetup({
|
|
4909
5099
|
selectMessage: "How do you want to use Caliber? (choose LLM provider)"
|
|
@@ -4914,22 +5104,23 @@ async function initCommand(options) {
|
|
|
4914
5104
|
}
|
|
4915
5105
|
config = loadConfig();
|
|
4916
5106
|
if (!config) {
|
|
4917
|
-
console.log(
|
|
5107
|
+
console.log(chalk7.red(" Setup was cancelled or failed.\n"));
|
|
4918
5108
|
throw new Error("__exit__");
|
|
4919
5109
|
}
|
|
4920
|
-
console.log(
|
|
5110
|
+
console.log(chalk7.green(" \u2713 Provider saved. Let's continue.\n"));
|
|
4921
5111
|
}
|
|
4922
5112
|
const displayModel = config.model === "default" && config.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : config.model;
|
|
4923
5113
|
const fastModel = getFastModel();
|
|
4924
5114
|
const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
|
|
4925
|
-
console.log(
|
|
5115
|
+
console.log(chalk7.dim(modelLine + "\n"));
|
|
5116
|
+
await validateModel({ fast: true });
|
|
4926
5117
|
console.log(title.bold(" Step 2/6 \u2014 Discover your project\n"));
|
|
4927
|
-
console.log(
|
|
5118
|
+
console.log(chalk7.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
|
|
4928
5119
|
const spinner = ora2("Analyzing project...").start();
|
|
4929
5120
|
const fingerprint = await collectFingerprint(process.cwd());
|
|
4930
5121
|
spinner.succeed("Project analyzed");
|
|
4931
|
-
console.log(
|
|
4932
|
-
console.log(
|
|
5122
|
+
console.log(chalk7.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
|
|
5123
|
+
console.log(chalk7.dim(` Files: ${fingerprint.fileTree.length} found
|
|
4933
5124
|
`));
|
|
4934
5125
|
const targetAgent = options.agent || await promptAgent();
|
|
4935
5126
|
const preScore = computeLocalScore(process.cwd(), targetAgent);
|
|
@@ -4948,23 +5139,23 @@ async function initCommand(options) {
|
|
|
4948
5139
|
const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
|
|
4949
5140
|
const NON_LLM_CHECKS = /* @__PURE__ */ new Set(["hooks_configured", "agents_md_exists", "permissions_configured", "mcp_servers"]);
|
|
4950
5141
|
if (hasExistingConfig && baselineScore.score === 100) {
|
|
4951
|
-
console.log(
|
|
4952
|
-
console.log(
|
|
5142
|
+
console.log(chalk7.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
|
|
5143
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber onboard --force") + chalk7.dim(" to regenerate anyway.\n"));
|
|
4953
5144
|
if (!options.force) return;
|
|
4954
5145
|
}
|
|
4955
5146
|
const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
4956
5147
|
const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
|
|
4957
5148
|
if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
|
|
4958
|
-
console.log(
|
|
4959
|
-
console.log(
|
|
5149
|
+
console.log(chalk7.bold.green("\n Your config is fully optimized for LLM generation.\n"));
|
|
5150
|
+
console.log(chalk7.dim(" Remaining items need CLI actions:\n"));
|
|
4960
5151
|
for (const check of allFailingChecks) {
|
|
4961
|
-
console.log(
|
|
5152
|
+
console.log(chalk7.dim(` \u2022 ${check.name}`));
|
|
4962
5153
|
if (check.suggestion) {
|
|
4963
|
-
console.log(` ${
|
|
5154
|
+
console.log(` ${chalk7.hex("#83D1EB")(check.suggestion)}`);
|
|
4964
5155
|
}
|
|
4965
5156
|
}
|
|
4966
5157
|
console.log("");
|
|
4967
|
-
console.log(
|
|
5158
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber onboard --force") + chalk7.dim(" to regenerate anyway.\n"));
|
|
4968
5159
|
return;
|
|
4969
5160
|
}
|
|
4970
5161
|
const isEmpty = fingerprint.fileTree.length < 3;
|
|
@@ -4980,22 +5171,22 @@ async function initCommand(options) {
|
|
|
4980
5171
|
currentScore = baselineScore.score;
|
|
4981
5172
|
if (failingChecks.length > 0) {
|
|
4982
5173
|
console.log(title.bold(" Step 3/6 \u2014 Fine-tuning\n"));
|
|
4983
|
-
console.log(
|
|
5174
|
+
console.log(chalk7.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
|
|
4984
5175
|
`));
|
|
4985
5176
|
for (const check of failingChecks) {
|
|
4986
|
-
console.log(
|
|
5177
|
+
console.log(chalk7.dim(` \u2022 ${check.name}`));
|
|
4987
5178
|
}
|
|
4988
5179
|
console.log("");
|
|
4989
5180
|
}
|
|
4990
5181
|
} else if (hasExistingConfig) {
|
|
4991
5182
|
console.log(title.bold(" Step 3/6 \u2014 Improve your setup\n"));
|
|
4992
|
-
console.log(
|
|
4993
|
-
console.log(
|
|
5183
|
+
console.log(chalk7.dim(" Reviewing your existing configs against your codebase"));
|
|
5184
|
+
console.log(chalk7.dim(" and preparing improvements.\n"));
|
|
4994
5185
|
} else {
|
|
4995
5186
|
console.log(title.bold(" Step 3/6 \u2014 Build your agent setup\n"));
|
|
4996
|
-
console.log(
|
|
5187
|
+
console.log(chalk7.dim(" Creating config files tailored to your project.\n"));
|
|
4997
5188
|
}
|
|
4998
|
-
console.log(
|
|
5189
|
+
console.log(chalk7.dim(" This can take a couple of minutes depending on your model and provider.\n"));
|
|
4999
5190
|
const genStartTime = Date.now();
|
|
5000
5191
|
const genSpinner = ora2("Generating setup...").start();
|
|
5001
5192
|
const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
|
|
@@ -5037,8 +5228,8 @@ async function initCommand(options) {
|
|
|
5037
5228
|
if (!generatedSetup) {
|
|
5038
5229
|
genSpinner.fail("Failed to generate setup.");
|
|
5039
5230
|
if (rawOutput) {
|
|
5040
|
-
console.log(
|
|
5041
|
-
console.log(
|
|
5231
|
+
console.log(chalk7.dim("\nRaw LLM output (JSON parse failed):"));
|
|
5232
|
+
console.log(chalk7.dim(rawOutput.slice(0, 500)));
|
|
5042
5233
|
}
|
|
5043
5234
|
throw new Error("__exit__");
|
|
5044
5235
|
}
|
|
@@ -5046,7 +5237,7 @@ async function initCommand(options) {
|
|
|
5046
5237
|
const mins = Math.floor(elapsedMs / 6e4);
|
|
5047
5238
|
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
5048
5239
|
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
5049
|
-
genSpinner.succeed(`Setup generated ${
|
|
5240
|
+
genSpinner.succeed(`Setup generated ${chalk7.dim(`in ${timeStr}`)}`);
|
|
5050
5241
|
printSetupSummary(generatedSetup);
|
|
5051
5242
|
const sessionHistory = [];
|
|
5052
5243
|
sessionHistory.push({
|
|
@@ -5057,11 +5248,11 @@ async function initCommand(options) {
|
|
|
5057
5248
|
const setupFiles = collectSetupFiles(generatedSetup);
|
|
5058
5249
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
5059
5250
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
5060
|
-
console.log(
|
|
5251
|
+
console.log(chalk7.dim(` ${chalk7.green(`${staged.newFiles} new`)} / ${chalk7.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
5061
5252
|
`));
|
|
5062
5253
|
let action;
|
|
5063
5254
|
if (totalChanges === 0) {
|
|
5064
|
-
console.log(
|
|
5255
|
+
console.log(chalk7.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
5065
5256
|
cleanupStaging();
|
|
5066
5257
|
action = "accept";
|
|
5067
5258
|
} else {
|
|
@@ -5076,12 +5267,12 @@ async function initCommand(options) {
|
|
|
5076
5267
|
generatedSetup = await refineLoop(generatedSetup, targetAgent, sessionHistory);
|
|
5077
5268
|
if (!generatedSetup) {
|
|
5078
5269
|
cleanupStaging();
|
|
5079
|
-
console.log(
|
|
5270
|
+
console.log(chalk7.dim("Refinement cancelled. No files were modified."));
|
|
5080
5271
|
return;
|
|
5081
5272
|
}
|
|
5082
5273
|
const updatedFiles = collectSetupFiles(generatedSetup);
|
|
5083
5274
|
const restaged = stageFiles(updatedFiles, process.cwd());
|
|
5084
|
-
console.log(
|
|
5275
|
+
console.log(chalk7.dim(` ${chalk7.green(`${restaged.newFiles} new`)} / ${chalk7.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
|
|
5085
5276
|
`));
|
|
5086
5277
|
printSetupSummary(generatedSetup);
|
|
5087
5278
|
await openReview("terminal", restaged.stagedFiles);
|
|
@@ -5089,11 +5280,11 @@ async function initCommand(options) {
|
|
|
5089
5280
|
}
|
|
5090
5281
|
cleanupStaging();
|
|
5091
5282
|
if (action === "decline") {
|
|
5092
|
-
console.log(
|
|
5283
|
+
console.log(chalk7.dim("Setup declined. No files were modified."));
|
|
5093
5284
|
return;
|
|
5094
5285
|
}
|
|
5095
5286
|
if (options.dryRun) {
|
|
5096
|
-
console.log(
|
|
5287
|
+
console.log(chalk7.yellow("\n[Dry run] Would write the following files:"));
|
|
5097
5288
|
console.log(JSON.stringify(generatedSetup, null, 2));
|
|
5098
5289
|
return;
|
|
5099
5290
|
}
|
|
@@ -5101,23 +5292,23 @@ async function initCommand(options) {
|
|
|
5101
5292
|
try {
|
|
5102
5293
|
const result = writeSetup(generatedSetup);
|
|
5103
5294
|
writeSpinner.succeed("Config files written");
|
|
5104
|
-
console.log(
|
|
5295
|
+
console.log(chalk7.bold("\nFiles created/updated:"));
|
|
5105
5296
|
for (const file of result.written) {
|
|
5106
|
-
console.log(` ${
|
|
5297
|
+
console.log(` ${chalk7.green("\u2713")} ${file}`);
|
|
5107
5298
|
}
|
|
5108
5299
|
if (result.deleted.length > 0) {
|
|
5109
|
-
console.log(
|
|
5300
|
+
console.log(chalk7.bold("\nFiles removed:"));
|
|
5110
5301
|
for (const file of result.deleted) {
|
|
5111
|
-
console.log(` ${
|
|
5302
|
+
console.log(` ${chalk7.red("\u2717")} ${file}`);
|
|
5112
5303
|
}
|
|
5113
5304
|
}
|
|
5114
5305
|
if (result.backupDir) {
|
|
5115
|
-
console.log(
|
|
5306
|
+
console.log(chalk7.dim(`
|
|
5116
5307
|
Backups saved to ${result.backupDir}`));
|
|
5117
5308
|
}
|
|
5118
5309
|
} catch (err) {
|
|
5119
5310
|
writeSpinner.fail("Failed to write files");
|
|
5120
|
-
console.error(
|
|
5311
|
+
console.error(chalk7.red(err instanceof Error ? err.message : "Unknown error"));
|
|
5121
5312
|
throw new Error("__exit__");
|
|
5122
5313
|
}
|
|
5123
5314
|
ensurePermissions();
|
|
@@ -5129,56 +5320,56 @@ async function initCommand(options) {
|
|
|
5129
5320
|
});
|
|
5130
5321
|
console.log("");
|
|
5131
5322
|
console.log(title.bold(" Keep your configs fresh\n"));
|
|
5132
|
-
console.log(
|
|
5323
|
+
console.log(chalk7.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
|
|
5133
5324
|
const hookChoice = await promptHookType(targetAgent);
|
|
5134
5325
|
if (hookChoice === "claude" || hookChoice === "both") {
|
|
5135
5326
|
const hookResult = installHook();
|
|
5136
5327
|
if (hookResult.installed) {
|
|
5137
|
-
console.log(` ${
|
|
5138
|
-
console.log(
|
|
5328
|
+
console.log(` ${chalk7.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
|
|
5329
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber hooks --remove") + chalk7.dim(" to disable"));
|
|
5139
5330
|
} else if (hookResult.alreadyInstalled) {
|
|
5140
|
-
console.log(
|
|
5331
|
+
console.log(chalk7.dim(" Claude Code hook already installed"));
|
|
5141
5332
|
}
|
|
5142
5333
|
const learnResult = installLearningHooks();
|
|
5143
5334
|
if (learnResult.installed) {
|
|
5144
|
-
console.log(` ${
|
|
5145
|
-
console.log(
|
|
5335
|
+
console.log(` ${chalk7.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
|
|
5336
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber learn remove") + chalk7.dim(" to disable"));
|
|
5146
5337
|
} else if (learnResult.alreadyInstalled) {
|
|
5147
|
-
console.log(
|
|
5338
|
+
console.log(chalk7.dim(" Learning hooks already installed"));
|
|
5148
5339
|
}
|
|
5149
5340
|
}
|
|
5150
5341
|
if (hookChoice === "precommit" || hookChoice === "both") {
|
|
5151
5342
|
const precommitResult = installPreCommitHook();
|
|
5152
5343
|
if (precommitResult.installed) {
|
|
5153
|
-
console.log(` ${
|
|
5154
|
-
console.log(
|
|
5344
|
+
console.log(` ${chalk7.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
|
|
5345
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber hooks --remove") + chalk7.dim(" to disable"));
|
|
5155
5346
|
} else if (precommitResult.alreadyInstalled) {
|
|
5156
|
-
console.log(
|
|
5347
|
+
console.log(chalk7.dim(" Pre-commit hook already installed"));
|
|
5157
5348
|
} else {
|
|
5158
|
-
console.log(
|
|
5349
|
+
console.log(chalk7.yellow(" Could not install pre-commit hook (not a git repository?)"));
|
|
5159
5350
|
}
|
|
5160
5351
|
}
|
|
5161
5352
|
if (hookChoice === "skip") {
|
|
5162
|
-
console.log(
|
|
5353
|
+
console.log(chalk7.dim(" Skipped auto-refresh hooks. Run ") + chalk7.hex("#83D1EB")("caliber hooks --install") + chalk7.dim(" later to enable."));
|
|
5163
5354
|
}
|
|
5164
5355
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5165
5356
|
if (afterScore.score < baselineScore.score) {
|
|
5166
5357
|
console.log("");
|
|
5167
|
-
console.log(
|
|
5358
|
+
console.log(chalk7.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
5168
5359
|
try {
|
|
5169
5360
|
const { restored, removed } = undoSetup();
|
|
5170
5361
|
if (restored.length > 0 || removed.length > 0) {
|
|
5171
|
-
console.log(
|
|
5362
|
+
console.log(chalk7.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
5172
5363
|
}
|
|
5173
5364
|
} catch {
|
|
5174
5365
|
}
|
|
5175
|
-
console.log(
|
|
5366
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber onboard --force") + chalk7.dim(" to override.\n"));
|
|
5176
5367
|
return;
|
|
5177
5368
|
}
|
|
5178
5369
|
displayScoreDelta(baselineScore, afterScore);
|
|
5179
5370
|
console.log(title.bold("\n Step 6/6 \u2014 Community skills\n"));
|
|
5180
|
-
console.log(
|
|
5181
|
-
const wantsSkills = await
|
|
5371
|
+
console.log(chalk7.dim(" Search public skill registries for skills that match your tech stack.\n"));
|
|
5372
|
+
const wantsSkills = await select5({
|
|
5182
5373
|
message: "Search public repos for relevant skills to add to this project?",
|
|
5183
5374
|
choices: [
|
|
5184
5375
|
{ name: "Yes, find skills for my project", value: true },
|
|
@@ -5190,16 +5381,16 @@ async function initCommand(options) {
|
|
|
5190
5381
|
await searchAndInstallSkills();
|
|
5191
5382
|
} catch (err) {
|
|
5192
5383
|
if (err.message !== "__exit__") {
|
|
5193
|
-
console.log(
|
|
5384
|
+
console.log(chalk7.dim(" Skills search failed: " + (err.message || "unknown error")));
|
|
5194
5385
|
}
|
|
5195
|
-
console.log(
|
|
5386
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber skills") + chalk7.dim(" later to try again.\n"));
|
|
5196
5387
|
}
|
|
5197
5388
|
} else {
|
|
5198
|
-
console.log(
|
|
5389
|
+
console.log(chalk7.dim(" Skipped. Run ") + chalk7.hex("#83D1EB")("caliber skills") + chalk7.dim(" later to browse.\n"));
|
|
5199
5390
|
}
|
|
5200
|
-
console.log(
|
|
5201
|
-
console.log(
|
|
5202
|
-
console.log(
|
|
5391
|
+
console.log(chalk7.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
|
|
5392
|
+
console.log(chalk7.dim(" Run ") + chalk7.hex("#83D1EB")("caliber undo") + chalk7.dim(" to revert changes.\n"));
|
|
5393
|
+
console.log(chalk7.bold(" Next steps:\n"));
|
|
5203
5394
|
console.log(` ${title("caliber score")} See your full config breakdown`);
|
|
5204
5395
|
console.log(` ${title("caliber skills")} Discover community skills for your stack`);
|
|
5205
5396
|
console.log(` ${title("caliber undo")} Revert all changes from this run`);
|
|
@@ -5216,9 +5407,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
5216
5407
|
}
|
|
5217
5408
|
const isValid = await classifyRefineIntent(message);
|
|
5218
5409
|
if (!isValid) {
|
|
5219
|
-
console.log(
|
|
5220
|
-
console.log(
|
|
5221
|
-
console.log(
|
|
5410
|
+
console.log(chalk7.dim(" This doesn't look like a config change request."));
|
|
5411
|
+
console.log(chalk7.dim(" Describe what to add, remove, or modify in your configs."));
|
|
5412
|
+
console.log(chalk7.dim(' Type "done" to accept the current setup.\n'));
|
|
5222
5413
|
continue;
|
|
5223
5414
|
}
|
|
5224
5415
|
const refineSpinner = ora2("Refining setup...").start();
|
|
@@ -5239,10 +5430,10 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
5239
5430
|
});
|
|
5240
5431
|
refineSpinner.succeed("Setup updated");
|
|
5241
5432
|
printSetupSummary(refined);
|
|
5242
|
-
console.log(
|
|
5433
|
+
console.log(chalk7.dim('Type "done" to accept, or describe more changes.'));
|
|
5243
5434
|
} else {
|
|
5244
5435
|
refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
|
|
5245
|
-
console.log(
|
|
5436
|
+
console.log(chalk7.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
|
|
5246
5437
|
}
|
|
5247
5438
|
}
|
|
5248
5439
|
}
|
|
@@ -5302,7 +5493,7 @@ ${JSON.stringify(checkList, null, 2)}`,
|
|
|
5302
5493
|
function promptInput2(question) {
|
|
5303
5494
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
5304
5495
|
return new Promise((resolve2) => {
|
|
5305
|
-
rl.question(
|
|
5496
|
+
rl.question(chalk7.cyan(`${question} `), (answer) => {
|
|
5306
5497
|
rl.close();
|
|
5307
5498
|
resolve2(answer.trim());
|
|
5308
5499
|
});
|
|
@@ -5334,13 +5525,13 @@ async function promptHookType(targetAgent) {
|
|
|
5334
5525
|
choices.push({ name: "Both (Claude Code + pre-commit)", value: "both" });
|
|
5335
5526
|
}
|
|
5336
5527
|
choices.push({ name: "Skip for now", value: "skip" });
|
|
5337
|
-
return
|
|
5528
|
+
return select5({
|
|
5338
5529
|
message: "How would you like to auto-refresh your docs?",
|
|
5339
5530
|
choices
|
|
5340
5531
|
});
|
|
5341
5532
|
}
|
|
5342
5533
|
async function promptReviewAction() {
|
|
5343
|
-
return
|
|
5534
|
+
return select5({
|
|
5344
5535
|
message: "What would you like to do?",
|
|
5345
5536
|
choices: [
|
|
5346
5537
|
{ name: "Accept and apply", value: "accept" },
|
|
@@ -5355,26 +5546,26 @@ function printSetupSummary(setup) {
|
|
|
5355
5546
|
const fileDescriptions = setup.fileDescriptions;
|
|
5356
5547
|
const deletions = setup.deletions;
|
|
5357
5548
|
console.log("");
|
|
5358
|
-
console.log(
|
|
5549
|
+
console.log(chalk7.bold(" Proposed changes:\n"));
|
|
5359
5550
|
const getDescription = (filePath) => {
|
|
5360
5551
|
return fileDescriptions?.[filePath];
|
|
5361
5552
|
};
|
|
5362
5553
|
if (claude) {
|
|
5363
5554
|
if (claude.claudeMd) {
|
|
5364
|
-
const icon = fs21.existsSync("CLAUDE.md") ?
|
|
5555
|
+
const icon = fs21.existsSync("CLAUDE.md") ? chalk7.yellow("~") : chalk7.green("+");
|
|
5365
5556
|
const desc = getDescription("CLAUDE.md");
|
|
5366
|
-
console.log(` ${icon} ${
|
|
5367
|
-
if (desc) console.log(
|
|
5557
|
+
console.log(` ${icon} ${chalk7.bold("CLAUDE.md")}`);
|
|
5558
|
+
if (desc) console.log(chalk7.dim(` ${desc}`));
|
|
5368
5559
|
console.log("");
|
|
5369
5560
|
}
|
|
5370
5561
|
const skills = claude.skills;
|
|
5371
5562
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
5372
5563
|
for (const skill of skills) {
|
|
5373
5564
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
5374
|
-
const icon = fs21.existsSync(skillPath) ?
|
|
5565
|
+
const icon = fs21.existsSync(skillPath) ? chalk7.yellow("~") : chalk7.green("+");
|
|
5375
5566
|
const desc = getDescription(skillPath);
|
|
5376
|
-
console.log(` ${icon} ${
|
|
5377
|
-
console.log(
|
|
5567
|
+
console.log(` ${icon} ${chalk7.bold(skillPath)}`);
|
|
5568
|
+
console.log(chalk7.dim(` ${desc || skill.description || skill.name}`));
|
|
5378
5569
|
console.log("");
|
|
5379
5570
|
}
|
|
5380
5571
|
}
|
|
@@ -5382,40 +5573,40 @@ function printSetupSummary(setup) {
|
|
|
5382
5573
|
const codex = setup.codex;
|
|
5383
5574
|
if (codex) {
|
|
5384
5575
|
if (codex.agentsMd) {
|
|
5385
|
-
const icon = fs21.existsSync("AGENTS.md") ?
|
|
5576
|
+
const icon = fs21.existsSync("AGENTS.md") ? chalk7.yellow("~") : chalk7.green("+");
|
|
5386
5577
|
const desc = getDescription("AGENTS.md");
|
|
5387
|
-
console.log(` ${icon} ${
|
|
5388
|
-
if (desc) console.log(
|
|
5578
|
+
console.log(` ${icon} ${chalk7.bold("AGENTS.md")}`);
|
|
5579
|
+
if (desc) console.log(chalk7.dim(` ${desc}`));
|
|
5389
5580
|
console.log("");
|
|
5390
5581
|
}
|
|
5391
5582
|
const codexSkills = codex.skills;
|
|
5392
5583
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
5393
5584
|
for (const skill of codexSkills) {
|
|
5394
5585
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
5395
|
-
const icon = fs21.existsSync(skillPath) ?
|
|
5586
|
+
const icon = fs21.existsSync(skillPath) ? chalk7.yellow("~") : chalk7.green("+");
|
|
5396
5587
|
const desc = getDescription(skillPath);
|
|
5397
|
-
console.log(` ${icon} ${
|
|
5398
|
-
console.log(
|
|
5588
|
+
console.log(` ${icon} ${chalk7.bold(skillPath)}`);
|
|
5589
|
+
console.log(chalk7.dim(` ${desc || skill.description || skill.name}`));
|
|
5399
5590
|
console.log("");
|
|
5400
5591
|
}
|
|
5401
5592
|
}
|
|
5402
5593
|
}
|
|
5403
5594
|
if (cursor) {
|
|
5404
5595
|
if (cursor.cursorrules) {
|
|
5405
|
-
const icon = fs21.existsSync(".cursorrules") ?
|
|
5596
|
+
const icon = fs21.existsSync(".cursorrules") ? chalk7.yellow("~") : chalk7.green("+");
|
|
5406
5597
|
const desc = getDescription(".cursorrules");
|
|
5407
|
-
console.log(` ${icon} ${
|
|
5408
|
-
if (desc) console.log(
|
|
5598
|
+
console.log(` ${icon} ${chalk7.bold(".cursorrules")}`);
|
|
5599
|
+
if (desc) console.log(chalk7.dim(` ${desc}`));
|
|
5409
5600
|
console.log("");
|
|
5410
5601
|
}
|
|
5411
5602
|
const cursorSkills = cursor.skills;
|
|
5412
5603
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
5413
5604
|
for (const skill of cursorSkills) {
|
|
5414
5605
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
5415
|
-
const icon = fs21.existsSync(skillPath) ?
|
|
5606
|
+
const icon = fs21.existsSync(skillPath) ? chalk7.yellow("~") : chalk7.green("+");
|
|
5416
5607
|
const desc = getDescription(skillPath);
|
|
5417
|
-
console.log(` ${icon} ${
|
|
5418
|
-
console.log(
|
|
5608
|
+
console.log(` ${icon} ${chalk7.bold(skillPath)}`);
|
|
5609
|
+
console.log(chalk7.dim(` ${desc || skill.description || skill.name}`));
|
|
5419
5610
|
console.log("");
|
|
5420
5611
|
}
|
|
5421
5612
|
}
|
|
@@ -5423,32 +5614,32 @@ function printSetupSummary(setup) {
|
|
|
5423
5614
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
5424
5615
|
for (const rule of rules) {
|
|
5425
5616
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
5426
|
-
const icon = fs21.existsSync(rulePath) ?
|
|
5617
|
+
const icon = fs21.existsSync(rulePath) ? chalk7.yellow("~") : chalk7.green("+");
|
|
5427
5618
|
const desc = getDescription(rulePath);
|
|
5428
|
-
console.log(` ${icon} ${
|
|
5619
|
+
console.log(` ${icon} ${chalk7.bold(rulePath)}`);
|
|
5429
5620
|
if (desc) {
|
|
5430
|
-
console.log(
|
|
5621
|
+
console.log(chalk7.dim(` ${desc}`));
|
|
5431
5622
|
} else {
|
|
5432
5623
|
const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
|
|
5433
|
-
if (firstLine) console.log(
|
|
5624
|
+
if (firstLine) console.log(chalk7.dim(` ${firstLine.trim().slice(0, 80)}`));
|
|
5434
5625
|
}
|
|
5435
5626
|
console.log("");
|
|
5436
5627
|
}
|
|
5437
5628
|
}
|
|
5438
5629
|
}
|
|
5439
5630
|
if (!codex && !fs21.existsSync("AGENTS.md")) {
|
|
5440
|
-
console.log(` ${
|
|
5441
|
-
console.log(
|
|
5631
|
+
console.log(` ${chalk7.green("+")} ${chalk7.bold("AGENTS.md")}`);
|
|
5632
|
+
console.log(chalk7.dim(" Cross-agent coordination file"));
|
|
5442
5633
|
console.log("");
|
|
5443
5634
|
}
|
|
5444
5635
|
if (Array.isArray(deletions) && deletions.length > 0) {
|
|
5445
5636
|
for (const del of deletions) {
|
|
5446
|
-
console.log(` ${
|
|
5447
|
-
console.log(
|
|
5637
|
+
console.log(` ${chalk7.red("-")} ${chalk7.bold(del.filePath)}`);
|
|
5638
|
+
console.log(chalk7.dim(` ${del.reason}`));
|
|
5448
5639
|
console.log("");
|
|
5449
5640
|
}
|
|
5450
5641
|
}
|
|
5451
|
-
console.log(` ${
|
|
5642
|
+
console.log(` ${chalk7.green("+")} ${chalk7.dim("new")} ${chalk7.yellow("~")} ${chalk7.dim("modified")} ${chalk7.red("-")} ${chalk7.dim("removed")}`);
|
|
5452
5643
|
console.log("");
|
|
5453
5644
|
}
|
|
5454
5645
|
function ensurePermissions() {
|
|
@@ -5475,7 +5666,7 @@ function ensurePermissions() {
|
|
|
5475
5666
|
}
|
|
5476
5667
|
|
|
5477
5668
|
// src/commands/undo.ts
|
|
5478
|
-
import
|
|
5669
|
+
import chalk8 from "chalk";
|
|
5479
5670
|
import ora3 from "ora";
|
|
5480
5671
|
function undoCommand() {
|
|
5481
5672
|
const spinner = ora3("Reverting setup...").start();
|
|
@@ -5487,27 +5678,28 @@ function undoCommand() {
|
|
|
5487
5678
|
}
|
|
5488
5679
|
spinner.succeed("Setup reverted successfully.\n");
|
|
5489
5680
|
if (restored.length > 0) {
|
|
5490
|
-
console.log(
|
|
5681
|
+
console.log(chalk8.cyan(" Restored from backup:"));
|
|
5491
5682
|
for (const file of restored) {
|
|
5492
|
-
console.log(` ${
|
|
5683
|
+
console.log(` ${chalk8.green("\u21A9")} ${file}`);
|
|
5493
5684
|
}
|
|
5494
5685
|
}
|
|
5495
5686
|
if (removed.length > 0) {
|
|
5496
|
-
console.log(
|
|
5687
|
+
console.log(chalk8.cyan(" Removed:"));
|
|
5497
5688
|
for (const file of removed) {
|
|
5498
|
-
console.log(` ${
|
|
5689
|
+
console.log(` ${chalk8.red("\u2717")} ${file}`);
|
|
5499
5690
|
}
|
|
5500
5691
|
}
|
|
5501
5692
|
console.log("");
|
|
5502
5693
|
} catch (err) {
|
|
5503
|
-
spinner.fail(
|
|
5694
|
+
spinner.fail(chalk8.red(err instanceof Error ? err.message : "Undo failed"));
|
|
5504
5695
|
throw new Error("__exit__");
|
|
5505
5696
|
}
|
|
5506
5697
|
}
|
|
5507
5698
|
|
|
5508
5699
|
// src/commands/status.ts
|
|
5509
|
-
import
|
|
5700
|
+
import chalk9 from "chalk";
|
|
5510
5701
|
import fs22 from "fs";
|
|
5702
|
+
init_config();
|
|
5511
5703
|
async function statusCommand(options) {
|
|
5512
5704
|
const config = loadConfig();
|
|
5513
5705
|
const manifest = readManifest();
|
|
@@ -5520,49 +5712,51 @@ async function statusCommand(options) {
|
|
|
5520
5712
|
}, null, 2));
|
|
5521
5713
|
return;
|
|
5522
5714
|
}
|
|
5523
|
-
console.log(
|
|
5715
|
+
console.log(chalk9.bold("\nCaliber Status\n"));
|
|
5524
5716
|
if (config) {
|
|
5525
|
-
console.log(` LLM: ${
|
|
5717
|
+
console.log(` LLM: ${chalk9.green(config.provider)} (${config.model})`);
|
|
5526
5718
|
} else {
|
|
5527
|
-
console.log(` LLM: ${
|
|
5719
|
+
console.log(` LLM: ${chalk9.yellow("Not configured")} \u2014 run ${chalk9.hex("#83D1EB")("caliber config")}`);
|
|
5528
5720
|
}
|
|
5529
5721
|
if (!manifest) {
|
|
5530
|
-
console.log(` Setup: ${
|
|
5531
|
-
console.log(
|
|
5722
|
+
console.log(` Setup: ${chalk9.dim("No setup applied")}`);
|
|
5723
|
+
console.log(chalk9.dim("\n Run ") + chalk9.hex("#83D1EB")("caliber onboard") + chalk9.dim(" to get started.\n"));
|
|
5532
5724
|
return;
|
|
5533
5725
|
}
|
|
5534
|
-
console.log(` Files managed: ${
|
|
5726
|
+
console.log(` Files managed: ${chalk9.cyan(manifest.entries.length.toString())}`);
|
|
5535
5727
|
for (const entry of manifest.entries) {
|
|
5536
5728
|
const exists = fs22.existsSync(entry.path);
|
|
5537
|
-
const icon = exists ?
|
|
5729
|
+
const icon = exists ? chalk9.green("\u2713") : chalk9.red("\u2717");
|
|
5538
5730
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
5539
5731
|
}
|
|
5540
5732
|
console.log("");
|
|
5541
5733
|
}
|
|
5542
5734
|
|
|
5543
5735
|
// src/commands/regenerate.ts
|
|
5544
|
-
import
|
|
5736
|
+
import chalk10 from "chalk";
|
|
5545
5737
|
import ora4 from "ora";
|
|
5546
|
-
import
|
|
5738
|
+
import select6 from "@inquirer/select";
|
|
5739
|
+
init_config();
|
|
5547
5740
|
async function regenerateCommand(options) {
|
|
5548
5741
|
const config = loadConfig();
|
|
5549
5742
|
if (!config) {
|
|
5550
|
-
console.log(
|
|
5743
|
+
console.log(chalk10.red("No LLM provider configured. Run ") + chalk10.hex("#83D1EB")("caliber config") + chalk10.red(" first."));
|
|
5551
5744
|
throw new Error("__exit__");
|
|
5552
5745
|
}
|
|
5553
5746
|
const manifest = readManifest();
|
|
5554
5747
|
if (!manifest) {
|
|
5555
|
-
console.log(
|
|
5748
|
+
console.log(chalk10.yellow("No existing setup found. Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.yellow(" first."));
|
|
5556
5749
|
throw new Error("__exit__");
|
|
5557
5750
|
}
|
|
5558
5751
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
5752
|
+
await validateModel({ fast: true });
|
|
5559
5753
|
const spinner = ora4("Analyzing project...").start();
|
|
5560
5754
|
const fingerprint = await collectFingerprint(process.cwd());
|
|
5561
5755
|
spinner.succeed("Project analyzed");
|
|
5562
5756
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5563
5757
|
displayScoreSummary(baselineScore);
|
|
5564
5758
|
if (baselineScore.score === 100) {
|
|
5565
|
-
console.log(
|
|
5759
|
+
console.log(chalk10.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
|
|
5566
5760
|
return;
|
|
5567
5761
|
}
|
|
5568
5762
|
const genSpinner = ora4("Regenerating setup...").start();
|
|
@@ -5603,18 +5797,18 @@ async function regenerateCommand(options) {
|
|
|
5603
5797
|
const setupFiles = collectSetupFiles(generatedSetup);
|
|
5604
5798
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
5605
5799
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
5606
|
-
console.log(
|
|
5607
|
-
${
|
|
5800
|
+
console.log(chalk10.dim(`
|
|
5801
|
+
${chalk10.green(`${staged.newFiles} new`)} / ${chalk10.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
5608
5802
|
`));
|
|
5609
5803
|
if (totalChanges === 0) {
|
|
5610
|
-
console.log(
|
|
5804
|
+
console.log(chalk10.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
5611
5805
|
cleanupStaging();
|
|
5612
5806
|
return;
|
|
5613
5807
|
}
|
|
5614
5808
|
if (options.dryRun) {
|
|
5615
|
-
console.log(
|
|
5809
|
+
console.log(chalk10.yellow("[Dry run] Would write:"));
|
|
5616
5810
|
for (const f of staged.stagedFiles) {
|
|
5617
|
-
console.log(` ${f.isNew ?
|
|
5811
|
+
console.log(` ${f.isNew ? chalk10.green("+") : chalk10.yellow("~")} ${f.relativePath}`);
|
|
5618
5812
|
}
|
|
5619
5813
|
cleanupStaging();
|
|
5620
5814
|
return;
|
|
@@ -5624,7 +5818,7 @@ async function regenerateCommand(options) {
|
|
|
5624
5818
|
const reviewMethod = await promptReviewMethod();
|
|
5625
5819
|
await openReview(reviewMethod, staged.stagedFiles);
|
|
5626
5820
|
}
|
|
5627
|
-
const action = await
|
|
5821
|
+
const action = await select6({
|
|
5628
5822
|
message: "Apply regenerated setup?",
|
|
5629
5823
|
choices: [
|
|
5630
5824
|
{ name: "Accept and apply", value: "accept" },
|
|
@@ -5633,7 +5827,7 @@ async function regenerateCommand(options) {
|
|
|
5633
5827
|
});
|
|
5634
5828
|
cleanupStaging();
|
|
5635
5829
|
if (action === "decline") {
|
|
5636
|
-
console.log(
|
|
5830
|
+
console.log(chalk10.dim("Regeneration cancelled. No files were modified."));
|
|
5637
5831
|
return;
|
|
5638
5832
|
}
|
|
5639
5833
|
const writeSpinner = ora4("Writing config files...").start();
|
|
@@ -5641,20 +5835,20 @@ async function regenerateCommand(options) {
|
|
|
5641
5835
|
const result = writeSetup(generatedSetup);
|
|
5642
5836
|
writeSpinner.succeed("Config files written");
|
|
5643
5837
|
for (const file of result.written) {
|
|
5644
|
-
console.log(` ${
|
|
5838
|
+
console.log(` ${chalk10.green("\u2713")} ${file}`);
|
|
5645
5839
|
}
|
|
5646
5840
|
if (result.deleted.length > 0) {
|
|
5647
5841
|
for (const file of result.deleted) {
|
|
5648
|
-
console.log(` ${
|
|
5842
|
+
console.log(` ${chalk10.red("\u2717")} ${file}`);
|
|
5649
5843
|
}
|
|
5650
5844
|
}
|
|
5651
5845
|
if (result.backupDir) {
|
|
5652
|
-
console.log(
|
|
5846
|
+
console.log(chalk10.dim(`
|
|
5653
5847
|
Backups saved to ${result.backupDir}`));
|
|
5654
5848
|
}
|
|
5655
5849
|
} catch (err) {
|
|
5656
5850
|
writeSpinner.fail("Failed to write files");
|
|
5657
|
-
console.error(
|
|
5851
|
+
console.error(chalk10.red(err instanceof Error ? err.message : "Unknown error"));
|
|
5658
5852
|
throw new Error("__exit__");
|
|
5659
5853
|
}
|
|
5660
5854
|
const sha = getCurrentHeadSha();
|
|
@@ -5666,24 +5860,24 @@ async function regenerateCommand(options) {
|
|
|
5666
5860
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
5667
5861
|
if (afterScore.score < baselineScore.score) {
|
|
5668
5862
|
console.log("");
|
|
5669
|
-
console.log(
|
|
5863
|
+
console.log(chalk10.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
5670
5864
|
try {
|
|
5671
5865
|
const { restored, removed } = undoSetup();
|
|
5672
5866
|
if (restored.length > 0 || removed.length > 0) {
|
|
5673
|
-
console.log(
|
|
5867
|
+
console.log(chalk10.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
5674
5868
|
}
|
|
5675
5869
|
} catch {
|
|
5676
5870
|
}
|
|
5677
|
-
console.log(
|
|
5871
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber onboard --force") + chalk10.dim(" to override.\n"));
|
|
5678
5872
|
return;
|
|
5679
5873
|
}
|
|
5680
5874
|
displayScoreDelta(baselineScore, afterScore);
|
|
5681
|
-
console.log(
|
|
5682
|
-
console.log(
|
|
5875
|
+
console.log(chalk10.bold.green(" Regeneration complete!"));
|
|
5876
|
+
console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber undo") + chalk10.dim(" to revert changes.\n"));
|
|
5683
5877
|
}
|
|
5684
5878
|
|
|
5685
5879
|
// src/commands/score.ts
|
|
5686
|
-
import
|
|
5880
|
+
import chalk11 from "chalk";
|
|
5687
5881
|
async function scoreCommand(options) {
|
|
5688
5882
|
const dir = process.cwd();
|
|
5689
5883
|
const target = options.agent ?? readState()?.targetAgent;
|
|
@@ -5697,14 +5891,14 @@ async function scoreCommand(options) {
|
|
|
5697
5891
|
return;
|
|
5698
5892
|
}
|
|
5699
5893
|
displayScore(result);
|
|
5700
|
-
const separator =
|
|
5894
|
+
const separator = chalk11.gray(" " + "\u2500".repeat(53));
|
|
5701
5895
|
console.log(separator);
|
|
5702
5896
|
if (result.score < 40) {
|
|
5703
|
-
console.log(
|
|
5897
|
+
console.log(chalk11.gray(" Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.gray(" to generate a complete, optimized setup."));
|
|
5704
5898
|
} else if (result.score < 70) {
|
|
5705
|
-
console.log(
|
|
5899
|
+
console.log(chalk11.gray(" Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.gray(" to improve your setup."));
|
|
5706
5900
|
} else {
|
|
5707
|
-
console.log(
|
|
5901
|
+
console.log(chalk11.green(" Looking good!") + chalk11.gray(" Run ") + chalk11.hex("#83D1EB")("caliber regenerate") + chalk11.gray(" to rebuild from scratch."));
|
|
5708
5902
|
}
|
|
5709
5903
|
console.log("");
|
|
5710
5904
|
}
|
|
@@ -5712,7 +5906,7 @@ async function scoreCommand(options) {
|
|
|
5712
5906
|
// src/commands/refresh.ts
|
|
5713
5907
|
import fs24 from "fs";
|
|
5714
5908
|
import path18 from "path";
|
|
5715
|
-
import
|
|
5909
|
+
import chalk12 from "chalk";
|
|
5716
5910
|
import ora5 from "ora";
|
|
5717
5911
|
|
|
5718
5912
|
// src/lib/git-diff.ts
|
|
@@ -5826,6 +6020,7 @@ function writeRefreshDocs(docs) {
|
|
|
5826
6020
|
}
|
|
5827
6021
|
|
|
5828
6022
|
// src/ai/refresh.ts
|
|
6023
|
+
init_config();
|
|
5829
6024
|
async function refreshDocs(diff, existingDocs, projectContext) {
|
|
5830
6025
|
const prompt = buildRefreshPrompt(diff, existingDocs, projectContext);
|
|
5831
6026
|
const fastModel = getFastModel();
|
|
@@ -5889,6 +6084,7 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
5889
6084
|
}
|
|
5890
6085
|
|
|
5891
6086
|
// src/commands/refresh.ts
|
|
6087
|
+
init_config();
|
|
5892
6088
|
function log(quiet, ...args) {
|
|
5893
6089
|
if (!quiet) console.log(...args);
|
|
5894
6090
|
}
|
|
@@ -5909,7 +6105,7 @@ function discoverGitRepos(parentDir) {
|
|
|
5909
6105
|
}
|
|
5910
6106
|
async function refreshSingleRepo(repoDir, options) {
|
|
5911
6107
|
const quiet = !!options.quiet;
|
|
5912
|
-
const prefix = options.label ? `${
|
|
6108
|
+
const prefix = options.label ? `${chalk12.bold(options.label)} ` : "";
|
|
5913
6109
|
const state = readState();
|
|
5914
6110
|
const lastSha = state?.lastRefreshSha ?? null;
|
|
5915
6111
|
const diff = collectDiff(lastSha);
|
|
@@ -5918,7 +6114,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
5918
6114
|
if (currentSha) {
|
|
5919
6115
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
5920
6116
|
}
|
|
5921
|
-
log(quiet,
|
|
6117
|
+
log(quiet, chalk12.dim(`${prefix}No changes since last refresh.`));
|
|
5922
6118
|
return;
|
|
5923
6119
|
}
|
|
5924
6120
|
const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
|
|
@@ -5950,10 +6146,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
5950
6146
|
if (options.dryRun) {
|
|
5951
6147
|
spinner?.info(`${prefix}Dry run \u2014 would update:`);
|
|
5952
6148
|
for (const doc of response.docsUpdated) {
|
|
5953
|
-
console.log(` ${
|
|
6149
|
+
console.log(` ${chalk12.yellow("~")} ${doc}`);
|
|
5954
6150
|
}
|
|
5955
6151
|
if (response.changesSummary) {
|
|
5956
|
-
console.log(
|
|
6152
|
+
console.log(chalk12.dim(`
|
|
5957
6153
|
${response.changesSummary}`));
|
|
5958
6154
|
}
|
|
5959
6155
|
return;
|
|
@@ -5961,10 +6157,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
5961
6157
|
const written = writeRefreshDocs(response.updatedDocs);
|
|
5962
6158
|
spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
|
|
5963
6159
|
for (const file of written) {
|
|
5964
|
-
log(quiet, ` ${
|
|
6160
|
+
log(quiet, ` ${chalk12.green("\u2713")} ${file}`);
|
|
5965
6161
|
}
|
|
5966
6162
|
if (response.changesSummary) {
|
|
5967
|
-
log(quiet,
|
|
6163
|
+
log(quiet, chalk12.dim(`
|
|
5968
6164
|
${response.changesSummary}`));
|
|
5969
6165
|
}
|
|
5970
6166
|
if (currentSha) {
|
|
@@ -5977,9 +6173,10 @@ async function refreshCommand(options) {
|
|
|
5977
6173
|
const config = loadConfig();
|
|
5978
6174
|
if (!config) {
|
|
5979
6175
|
if (quiet) return;
|
|
5980
|
-
console.log(
|
|
6176
|
+
console.log(chalk12.red("No LLM provider configured. Run ") + chalk12.hex("#83D1EB")("caliber config") + chalk12.red(" (e.g. choose Cursor) or set an API key."));
|
|
5981
6177
|
throw new Error("__exit__");
|
|
5982
6178
|
}
|
|
6179
|
+
await validateModel({ fast: true });
|
|
5983
6180
|
if (isGitRepo()) {
|
|
5984
6181
|
await refreshSingleRepo(process.cwd(), options);
|
|
5985
6182
|
return;
|
|
@@ -5987,10 +6184,10 @@ async function refreshCommand(options) {
|
|
|
5987
6184
|
const repos = discoverGitRepos(process.cwd());
|
|
5988
6185
|
if (repos.length === 0) {
|
|
5989
6186
|
if (quiet) return;
|
|
5990
|
-
console.log(
|
|
6187
|
+
console.log(chalk12.red("Not inside a git repository and no git repos found in child directories."));
|
|
5991
6188
|
throw new Error("__exit__");
|
|
5992
6189
|
}
|
|
5993
|
-
log(quiet,
|
|
6190
|
+
log(quiet, chalk12.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
5994
6191
|
`));
|
|
5995
6192
|
const originalDir = process.cwd();
|
|
5996
6193
|
for (const repo of repos) {
|
|
@@ -6000,7 +6197,7 @@ async function refreshCommand(options) {
|
|
|
6000
6197
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
6001
6198
|
} catch (err) {
|
|
6002
6199
|
if (err instanceof Error && err.message === "__exit__") continue;
|
|
6003
|
-
log(quiet,
|
|
6200
|
+
log(quiet, chalk12.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
|
|
6004
6201
|
}
|
|
6005
6202
|
}
|
|
6006
6203
|
process.chdir(originalDir);
|
|
@@ -6008,13 +6205,13 @@ async function refreshCommand(options) {
|
|
|
6008
6205
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
6009
6206
|
if (quiet) return;
|
|
6010
6207
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
6011
|
-
console.log(
|
|
6208
|
+
console.log(chalk12.red(`Refresh failed: ${msg}`));
|
|
6012
6209
|
throw new Error("__exit__");
|
|
6013
6210
|
}
|
|
6014
6211
|
}
|
|
6015
6212
|
|
|
6016
6213
|
// src/commands/hooks.ts
|
|
6017
|
-
import
|
|
6214
|
+
import chalk13 from "chalk";
|
|
6018
6215
|
var HOOKS = [
|
|
6019
6216
|
{
|
|
6020
6217
|
id: "session-end",
|
|
@@ -6034,13 +6231,13 @@ var HOOKS = [
|
|
|
6034
6231
|
}
|
|
6035
6232
|
];
|
|
6036
6233
|
function printStatus() {
|
|
6037
|
-
console.log(
|
|
6234
|
+
console.log(chalk13.bold("\n Hooks\n"));
|
|
6038
6235
|
for (const hook of HOOKS) {
|
|
6039
6236
|
const installed = hook.isInstalled();
|
|
6040
|
-
const icon = installed ?
|
|
6041
|
-
const state = installed ?
|
|
6237
|
+
const icon = installed ? chalk13.green("\u2713") : chalk13.dim("\u2717");
|
|
6238
|
+
const state = installed ? chalk13.green("enabled") : chalk13.dim("disabled");
|
|
6042
6239
|
console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
|
|
6043
|
-
console.log(
|
|
6240
|
+
console.log(chalk13.dim(` ${hook.description}`));
|
|
6044
6241
|
}
|
|
6045
6242
|
console.log("");
|
|
6046
6243
|
}
|
|
@@ -6049,9 +6246,9 @@ async function hooksCommand(options) {
|
|
|
6049
6246
|
for (const hook of HOOKS) {
|
|
6050
6247
|
const result = hook.install();
|
|
6051
6248
|
if (result.alreadyInstalled) {
|
|
6052
|
-
console.log(
|
|
6249
|
+
console.log(chalk13.dim(` ${hook.label} already enabled.`));
|
|
6053
6250
|
} else {
|
|
6054
|
-
console.log(
|
|
6251
|
+
console.log(chalk13.green(" \u2713") + ` ${hook.label} enabled`);
|
|
6055
6252
|
}
|
|
6056
6253
|
}
|
|
6057
6254
|
return;
|
|
@@ -6060,9 +6257,9 @@ async function hooksCommand(options) {
|
|
|
6060
6257
|
for (const hook of HOOKS) {
|
|
6061
6258
|
const result = hook.remove();
|
|
6062
6259
|
if (result.notFound) {
|
|
6063
|
-
console.log(
|
|
6260
|
+
console.log(chalk13.dim(` ${hook.label} already disabled.`));
|
|
6064
6261
|
} else {
|
|
6065
|
-
console.log(
|
|
6262
|
+
console.log(chalk13.green(" \u2713") + ` ${hook.label} removed`);
|
|
6066
6263
|
}
|
|
6067
6264
|
}
|
|
6068
6265
|
return;
|
|
@@ -6077,18 +6274,18 @@ async function hooksCommand(options) {
|
|
|
6077
6274
|
const states = HOOKS.map((h) => h.isInstalled());
|
|
6078
6275
|
function render() {
|
|
6079
6276
|
const lines = [];
|
|
6080
|
-
lines.push(
|
|
6277
|
+
lines.push(chalk13.bold(" Hooks"));
|
|
6081
6278
|
lines.push("");
|
|
6082
6279
|
for (let i = 0; i < HOOKS.length; i++) {
|
|
6083
6280
|
const hook = HOOKS[i];
|
|
6084
6281
|
const enabled = states[i];
|
|
6085
|
-
const toggle = enabled ?
|
|
6086
|
-
const ptr = i === cursor ?
|
|
6282
|
+
const toggle = enabled ? chalk13.green("[on] ") : chalk13.dim("[off]");
|
|
6283
|
+
const ptr = i === cursor ? chalk13.cyan(">") : " ";
|
|
6087
6284
|
lines.push(` ${ptr} ${toggle} ${hook.label}`);
|
|
6088
|
-
lines.push(
|
|
6285
|
+
lines.push(chalk13.dim(` ${hook.description}`));
|
|
6089
6286
|
}
|
|
6090
6287
|
lines.push("");
|
|
6091
|
-
lines.push(
|
|
6288
|
+
lines.push(chalk13.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
|
|
6092
6289
|
return lines.join("\n");
|
|
6093
6290
|
}
|
|
6094
6291
|
function draw(initial) {
|
|
@@ -6119,16 +6316,16 @@ async function hooksCommand(options) {
|
|
|
6119
6316
|
const wantEnabled = states[i];
|
|
6120
6317
|
if (wantEnabled && !wasInstalled) {
|
|
6121
6318
|
hook.install();
|
|
6122
|
-
console.log(
|
|
6319
|
+
console.log(chalk13.green(" \u2713") + ` ${hook.label} enabled`);
|
|
6123
6320
|
changed++;
|
|
6124
6321
|
} else if (!wantEnabled && wasInstalled) {
|
|
6125
6322
|
hook.remove();
|
|
6126
|
-
console.log(
|
|
6323
|
+
console.log(chalk13.green(" \u2713") + ` ${hook.label} disabled`);
|
|
6127
6324
|
changed++;
|
|
6128
6325
|
}
|
|
6129
6326
|
}
|
|
6130
6327
|
if (changed === 0) {
|
|
6131
|
-
console.log(
|
|
6328
|
+
console.log(chalk13.dim(" No changes."));
|
|
6132
6329
|
}
|
|
6133
6330
|
console.log("");
|
|
6134
6331
|
}
|
|
@@ -6164,7 +6361,7 @@ async function hooksCommand(options) {
|
|
|
6164
6361
|
case "\x1B":
|
|
6165
6362
|
case "":
|
|
6166
6363
|
cleanup();
|
|
6167
|
-
console.log(
|
|
6364
|
+
console.log(chalk13.dim("\n Cancelled.\n"));
|
|
6168
6365
|
resolve2();
|
|
6169
6366
|
break;
|
|
6170
6367
|
}
|
|
@@ -6174,48 +6371,49 @@ async function hooksCommand(options) {
|
|
|
6174
6371
|
}
|
|
6175
6372
|
|
|
6176
6373
|
// src/commands/config.ts
|
|
6177
|
-
|
|
6374
|
+
init_config();
|
|
6375
|
+
import chalk14 from "chalk";
|
|
6178
6376
|
async function configCommand() {
|
|
6179
6377
|
const existing = loadConfig();
|
|
6180
6378
|
if (existing) {
|
|
6181
6379
|
const displayModel = existing.model === "default" && existing.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : existing.model;
|
|
6182
6380
|
const fastModel = getFastModel();
|
|
6183
|
-
console.log(
|
|
6184
|
-
console.log(` Provider: ${
|
|
6185
|
-
console.log(` Model: ${
|
|
6381
|
+
console.log(chalk14.bold("\nCurrent Configuration\n"));
|
|
6382
|
+
console.log(` Provider: ${chalk14.cyan(existing.provider)}`);
|
|
6383
|
+
console.log(` Model: ${chalk14.cyan(displayModel)}`);
|
|
6186
6384
|
if (fastModel) {
|
|
6187
|
-
console.log(` Scan: ${
|
|
6385
|
+
console.log(` Scan: ${chalk14.cyan(fastModel)}`);
|
|
6188
6386
|
}
|
|
6189
6387
|
if (existing.apiKey) {
|
|
6190
6388
|
const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
|
|
6191
|
-
console.log(` API Key: ${
|
|
6389
|
+
console.log(` API Key: ${chalk14.dim(masked)}`);
|
|
6192
6390
|
}
|
|
6193
6391
|
if (existing.provider === "cursor") {
|
|
6194
|
-
console.log(` Seat: ${
|
|
6392
|
+
console.log(` Seat: ${chalk14.dim("Cursor (agent acp)")}`);
|
|
6195
6393
|
}
|
|
6196
6394
|
if (existing.provider === "claude-cli") {
|
|
6197
|
-
console.log(` Seat: ${
|
|
6395
|
+
console.log(` Seat: ${chalk14.dim("Claude Code (claude -p)")}`);
|
|
6198
6396
|
}
|
|
6199
6397
|
if (existing.baseUrl) {
|
|
6200
|
-
console.log(` Base URL: ${
|
|
6398
|
+
console.log(` Base URL: ${chalk14.dim(existing.baseUrl)}`);
|
|
6201
6399
|
}
|
|
6202
6400
|
if (existing.vertexProjectId) {
|
|
6203
|
-
console.log(` Vertex Project: ${
|
|
6204
|
-
console.log(` Vertex Region: ${
|
|
6401
|
+
console.log(` Vertex Project: ${chalk14.dim(existing.vertexProjectId)}`);
|
|
6402
|
+
console.log(` Vertex Region: ${chalk14.dim(existing.vertexRegion || "us-east5")}`);
|
|
6205
6403
|
}
|
|
6206
|
-
console.log(` Source: ${
|
|
6404
|
+
console.log(` Source: ${chalk14.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
6405
|
console.log("");
|
|
6208
6406
|
}
|
|
6209
6407
|
await runInteractiveProviderSetup();
|
|
6210
|
-
console.log(
|
|
6211
|
-
console.log(
|
|
6408
|
+
console.log(chalk14.green("\n\u2713 Configuration saved"));
|
|
6409
|
+
console.log(chalk14.dim(` ${getConfigFilePath()}
|
|
6212
6410
|
`));
|
|
6213
|
-
console.log(
|
|
6214
|
-
console.log(
|
|
6411
|
+
console.log(chalk14.dim(" You can also set environment variables instead:"));
|
|
6412
|
+
console.log(chalk14.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
|
|
6215
6413
|
}
|
|
6216
6414
|
|
|
6217
6415
|
// src/commands/learn.ts
|
|
6218
|
-
import
|
|
6416
|
+
import chalk15 from "chalk";
|
|
6219
6417
|
|
|
6220
6418
|
// src/learner/stdin.ts
|
|
6221
6419
|
var STDIN_TIMEOUT_MS = 5e3;
|
|
@@ -6384,6 +6582,7 @@ function readLearnedSection() {
|
|
|
6384
6582
|
}
|
|
6385
6583
|
|
|
6386
6584
|
// src/ai/learn.ts
|
|
6585
|
+
init_config();
|
|
6387
6586
|
var MAX_PROMPT_TOKENS = 1e5;
|
|
6388
6587
|
function formatEventsForPrompt(events) {
|
|
6389
6588
|
return events.map((e, i) => {
|
|
@@ -6457,6 +6656,7 @@ ${eventsText}`;
|
|
|
6457
6656
|
}
|
|
6458
6657
|
|
|
6459
6658
|
// src/commands/learn.ts
|
|
6659
|
+
init_config();
|
|
6460
6660
|
async function learnObserveCommand(options) {
|
|
6461
6661
|
try {
|
|
6462
6662
|
const raw = await readStdin();
|
|
@@ -6494,6 +6694,7 @@ async function learnFinalizeCommand() {
|
|
|
6494
6694
|
resetState();
|
|
6495
6695
|
return;
|
|
6496
6696
|
}
|
|
6697
|
+
await validateModel();
|
|
6497
6698
|
const existingConfigs = readExistingConfigs(process.cwd());
|
|
6498
6699
|
const existingLearnedSection = readLearnedSection();
|
|
6499
6700
|
const existingSkills = existingConfigs.claudeSkills || [];
|
|
@@ -6518,46 +6719,46 @@ async function learnFinalizeCommand() {
|
|
|
6518
6719
|
async function learnInstallCommand() {
|
|
6519
6720
|
const result = installLearningHooks();
|
|
6520
6721
|
if (result.alreadyInstalled) {
|
|
6521
|
-
console.log(
|
|
6722
|
+
console.log(chalk15.dim("Learning hooks already installed."));
|
|
6522
6723
|
return;
|
|
6523
6724
|
}
|
|
6524
|
-
console.log(
|
|
6525
|
-
console.log(
|
|
6526
|
-
console.log(
|
|
6725
|
+
console.log(chalk15.green("\u2713") + " Learning hooks installed in .claude/settings.json");
|
|
6726
|
+
console.log(chalk15.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
|
|
6727
|
+
console.log(chalk15.dim(" Session learnings will be written to CLAUDE.md and skills."));
|
|
6527
6728
|
}
|
|
6528
6729
|
async function learnRemoveCommand() {
|
|
6529
6730
|
const result = removeLearningHooks();
|
|
6530
6731
|
if (result.notFound) {
|
|
6531
|
-
console.log(
|
|
6732
|
+
console.log(chalk15.dim("Learning hooks not found."));
|
|
6532
6733
|
return;
|
|
6533
6734
|
}
|
|
6534
|
-
console.log(
|
|
6735
|
+
console.log(chalk15.green("\u2713") + " Learning hooks removed from .claude/settings.json");
|
|
6535
6736
|
}
|
|
6536
6737
|
async function learnStatusCommand() {
|
|
6537
6738
|
const installed = areLearningHooksInstalled();
|
|
6538
6739
|
const state = readState2();
|
|
6539
6740
|
const eventCount = getEventCount();
|
|
6540
|
-
console.log(
|
|
6741
|
+
console.log(chalk15.bold("Session Learning Status"));
|
|
6541
6742
|
console.log();
|
|
6542
6743
|
if (installed) {
|
|
6543
|
-
console.log(
|
|
6744
|
+
console.log(chalk15.green("\u2713") + " Learning hooks are " + chalk15.green("installed"));
|
|
6544
6745
|
} else {
|
|
6545
|
-
console.log(
|
|
6546
|
-
console.log(
|
|
6746
|
+
console.log(chalk15.dim("\u2717") + " Learning hooks are " + chalk15.yellow("not installed"));
|
|
6747
|
+
console.log(chalk15.dim(" Run `caliber learn install` to enable session learning."));
|
|
6547
6748
|
}
|
|
6548
6749
|
console.log();
|
|
6549
|
-
console.log(`Events recorded: ${
|
|
6550
|
-
console.log(`Total this session: ${
|
|
6750
|
+
console.log(`Events recorded: ${chalk15.cyan(String(eventCount))}`);
|
|
6751
|
+
console.log(`Total this session: ${chalk15.cyan(String(state.eventCount))}`);
|
|
6551
6752
|
if (state.lastAnalysisTimestamp) {
|
|
6552
|
-
console.log(`Last analysis: ${
|
|
6753
|
+
console.log(`Last analysis: ${chalk15.cyan(state.lastAnalysisTimestamp)}`);
|
|
6553
6754
|
} else {
|
|
6554
|
-
console.log(`Last analysis: ${
|
|
6755
|
+
console.log(`Last analysis: ${chalk15.dim("none")}`);
|
|
6555
6756
|
}
|
|
6556
6757
|
const learnedSection = readLearnedSection();
|
|
6557
6758
|
if (learnedSection) {
|
|
6558
6759
|
const lineCount = learnedSection.split("\n").filter(Boolean).length;
|
|
6559
6760
|
console.log(`
|
|
6560
|
-
Learned items in CLAUDE.md: ${
|
|
6761
|
+
Learned items in CLAUDE.md: ${chalk15.cyan(String(lineCount))}`);
|
|
6561
6762
|
}
|
|
6562
6763
|
}
|
|
6563
6764
|
|
|
@@ -6601,7 +6802,7 @@ import fs28 from "fs";
|
|
|
6601
6802
|
import path22 from "path";
|
|
6602
6803
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6603
6804
|
import { execSync as execSync9 } from "child_process";
|
|
6604
|
-
import
|
|
6805
|
+
import chalk16 from "chalk";
|
|
6605
6806
|
import ora6 from "ora";
|
|
6606
6807
|
import confirm from "@inquirer/confirm";
|
|
6607
6808
|
var __dirname_vc = path22.dirname(fileURLToPath2(import.meta.url));
|
|
@@ -6635,17 +6836,17 @@ async function checkForUpdates() {
|
|
|
6635
6836
|
const isInteractive = process.stdin.isTTY === true;
|
|
6636
6837
|
if (!isInteractive) {
|
|
6637
6838
|
console.log(
|
|
6638
|
-
|
|
6839
|
+
chalk16.yellow(
|
|
6639
6840
|
`
|
|
6640
6841
|
Update available: ${current} -> ${latest}
|
|
6641
|
-
Run ${
|
|
6842
|
+
Run ${chalk16.bold("npm install -g @rely-ai/caliber")} to upgrade.
|
|
6642
6843
|
`
|
|
6643
6844
|
)
|
|
6644
6845
|
);
|
|
6645
6846
|
return;
|
|
6646
6847
|
}
|
|
6647
6848
|
console.log(
|
|
6648
|
-
|
|
6849
|
+
chalk16.yellow(`
|
|
6649
6850
|
Update available: ${current} -> ${latest}`)
|
|
6650
6851
|
);
|
|
6651
6852
|
const shouldUpdate = await confirm({ message: "Would you like to update now? (Y/n)", default: true });
|
|
@@ -6663,13 +6864,13 @@ Update available: ${current} -> ${latest}`)
|
|
|
6663
6864
|
const installed = getInstalledVersion();
|
|
6664
6865
|
if (installed !== latest) {
|
|
6665
6866
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
6666
|
-
console.log(
|
|
6867
|
+
console.log(chalk16.yellow(`Run ${chalk16.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
|
|
6667
6868
|
`));
|
|
6668
6869
|
return;
|
|
6669
6870
|
}
|
|
6670
|
-
spinner.succeed(
|
|
6871
|
+
spinner.succeed(chalk16.green(`Updated to ${latest}`));
|
|
6671
6872
|
const args = process.argv.slice(2);
|
|
6672
|
-
console.log(
|
|
6873
|
+
console.log(chalk16.dim(`
|
|
6673
6874
|
Restarting: caliber ${args.join(" ")}
|
|
6674
6875
|
`));
|
|
6675
6876
|
execSync9(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
@@ -6682,11 +6883,11 @@ Restarting: caliber ${args.join(" ")}
|
|
|
6682
6883
|
if (err instanceof Error) {
|
|
6683
6884
|
const stderr = err.stderr;
|
|
6684
6885
|
const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
|
|
6685
|
-
if (errMsg && !errMsg.includes("SIGTERM")) console.log(
|
|
6886
|
+
if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk16.dim(` ${errMsg}`));
|
|
6686
6887
|
}
|
|
6687
6888
|
console.log(
|
|
6688
|
-
|
|
6689
|
-
`Run ${
|
|
6889
|
+
chalk16.yellow(
|
|
6890
|
+
`Run ${chalk16.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
|
|
6690
6891
|
`
|
|
6691
6892
|
)
|
|
6692
6893
|
);
|