@rely-ai/caliber 1.22.1 → 1.23.0-dev.1773793983
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 +662 -534
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -25,9 +25,11 @@ var config_exports = {};
|
|
|
25
25
|
__export(config_exports, {
|
|
26
26
|
DEFAULT_FAST_MODELS: () => DEFAULT_FAST_MODELS,
|
|
27
27
|
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
28
|
+
MODEL_CONTEXT_WINDOWS: () => MODEL_CONTEXT_WINDOWS,
|
|
28
29
|
getConfigFilePath: () => getConfigFilePath,
|
|
29
30
|
getDisplayModel: () => getDisplayModel,
|
|
30
31
|
getFastModel: () => getFastModel,
|
|
32
|
+
getMaxPromptTokens: () => getMaxPromptTokens,
|
|
31
33
|
loadConfig: () => loadConfig,
|
|
32
34
|
readConfigFile: () => readConfigFile,
|
|
33
35
|
resolveFromEnv: () => resolveFromEnv,
|
|
@@ -36,6 +38,13 @@ __export(config_exports, {
|
|
|
36
38
|
import fs4 from "fs";
|
|
37
39
|
import path4 from "path";
|
|
38
40
|
import os from "os";
|
|
41
|
+
function getMaxPromptTokens() {
|
|
42
|
+
const config = loadConfig();
|
|
43
|
+
const model = process.env.CALIBER_MODEL || config?.model;
|
|
44
|
+
const contextWindow = model ? MODEL_CONTEXT_WINDOWS[model] ?? DEFAULT_CONTEXT_WINDOW : DEFAULT_CONTEXT_WINDOW;
|
|
45
|
+
const budget = Math.floor(contextWindow * INPUT_BUDGET_FRACTION);
|
|
46
|
+
return Math.max(MIN_PROMPT_TOKENS, Math.min(budget, MAX_PROMPT_TOKENS_CAP));
|
|
47
|
+
}
|
|
39
48
|
function loadConfig() {
|
|
40
49
|
const envConfig = resolveFromEnv();
|
|
41
50
|
if (envConfig) return envConfig;
|
|
@@ -123,7 +132,7 @@ function getFastModel() {
|
|
|
123
132
|
if (provider) return DEFAULT_FAST_MODELS[provider];
|
|
124
133
|
return void 0;
|
|
125
134
|
}
|
|
126
|
-
var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, DEFAULT_FAST_MODELS;
|
|
135
|
+
var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, MODEL_CONTEXT_WINDOWS, DEFAULT_CONTEXT_WINDOW, INPUT_BUDGET_FRACTION, MAX_PROMPT_TOKENS_CAP, MIN_PROMPT_TOKENS, DEFAULT_FAST_MODELS;
|
|
127
136
|
var init_config = __esm({
|
|
128
137
|
"src/llm/config.ts"() {
|
|
129
138
|
"use strict";
|
|
@@ -136,6 +145,21 @@ var init_config = __esm({
|
|
|
136
145
|
cursor: "sonnet-4.6",
|
|
137
146
|
"claude-cli": "default"
|
|
138
147
|
};
|
|
148
|
+
MODEL_CONTEXT_WINDOWS = {
|
|
149
|
+
"claude-sonnet-4-6": 2e5,
|
|
150
|
+
"claude-opus-4-6": 2e5,
|
|
151
|
+
"claude-haiku-4-5-20251001": 2e5,
|
|
152
|
+
"claude-sonnet-4-5-20250514": 2e5,
|
|
153
|
+
"gpt-4.1": 1e6,
|
|
154
|
+
"gpt-4.1-mini": 1e6,
|
|
155
|
+
"gpt-4o": 128e3,
|
|
156
|
+
"gpt-4o-mini": 128e3,
|
|
157
|
+
"sonnet-4.6": 2e5
|
|
158
|
+
};
|
|
159
|
+
DEFAULT_CONTEXT_WINDOW = 2e5;
|
|
160
|
+
INPUT_BUDGET_FRACTION = 0.6;
|
|
161
|
+
MAX_PROMPT_TOKENS_CAP = 3e5;
|
|
162
|
+
MIN_PROMPT_TOKENS = 3e4;
|
|
139
163
|
DEFAULT_FAST_MODELS = {
|
|
140
164
|
anthropic: "claude-haiku-4-5-20251001",
|
|
141
165
|
vertex: "claude-haiku-4-5-20251001",
|
|
@@ -158,17 +182,17 @@ __export(constants_exports, {
|
|
|
158
182
|
LEARNING_STATE_FILE: () => LEARNING_STATE_FILE,
|
|
159
183
|
MANIFEST_FILE: () => MANIFEST_FILE
|
|
160
184
|
});
|
|
161
|
-
import
|
|
185
|
+
import path10 from "path";
|
|
162
186
|
import os3 from "os";
|
|
163
187
|
var AUTH_DIR, CALIBER_DIR, MANIFEST_FILE, BACKUPS_DIR, LEARNING_DIR, LEARNING_SESSION_FILE, LEARNING_STATE_FILE, LEARNING_MAX_EVENTS, LEARNING_ROI_FILE;
|
|
164
188
|
var init_constants = __esm({
|
|
165
189
|
"src/constants.ts"() {
|
|
166
190
|
"use strict";
|
|
167
|
-
AUTH_DIR =
|
|
191
|
+
AUTH_DIR = path10.join(os3.homedir(), ".caliber");
|
|
168
192
|
CALIBER_DIR = ".caliber";
|
|
169
|
-
MANIFEST_FILE =
|
|
170
|
-
BACKUPS_DIR =
|
|
171
|
-
LEARNING_DIR =
|
|
193
|
+
MANIFEST_FILE = path10.join(CALIBER_DIR, "manifest.json");
|
|
194
|
+
BACKUPS_DIR = path10.join(CALIBER_DIR, "backups");
|
|
195
|
+
LEARNING_DIR = path10.join(CALIBER_DIR, "learning");
|
|
172
196
|
LEARNING_SESSION_FILE = "current-session.jsonl";
|
|
173
197
|
LEARNING_STATE_FILE = "state.json";
|
|
174
198
|
LEARNING_MAX_EVENTS = 500;
|
|
@@ -183,13 +207,13 @@ __export(lock_exports, {
|
|
|
183
207
|
isCaliberRunning: () => isCaliberRunning,
|
|
184
208
|
releaseLock: () => releaseLock
|
|
185
209
|
});
|
|
186
|
-
import
|
|
187
|
-
import
|
|
210
|
+
import fs30 from "fs";
|
|
211
|
+
import path24 from "path";
|
|
188
212
|
import os6 from "os";
|
|
189
213
|
function isCaliberRunning() {
|
|
190
214
|
try {
|
|
191
|
-
if (!
|
|
192
|
-
const raw =
|
|
215
|
+
if (!fs30.existsSync(LOCK_FILE)) return false;
|
|
216
|
+
const raw = fs30.readFileSync(LOCK_FILE, "utf-8").trim();
|
|
193
217
|
const { pid, ts } = JSON.parse(raw);
|
|
194
218
|
if (Date.now() - ts > STALE_MS) return false;
|
|
195
219
|
try {
|
|
@@ -204,13 +228,13 @@ function isCaliberRunning() {
|
|
|
204
228
|
}
|
|
205
229
|
function acquireLock() {
|
|
206
230
|
try {
|
|
207
|
-
|
|
231
|
+
fs30.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
|
|
208
232
|
} catch {
|
|
209
233
|
}
|
|
210
234
|
}
|
|
211
235
|
function releaseLock() {
|
|
212
236
|
try {
|
|
213
|
-
if (
|
|
237
|
+
if (fs30.existsSync(LOCK_FILE)) fs30.unlinkSync(LOCK_FILE);
|
|
214
238
|
} catch {
|
|
215
239
|
}
|
|
216
240
|
}
|
|
@@ -218,28 +242,28 @@ var LOCK_FILE, STALE_MS;
|
|
|
218
242
|
var init_lock = __esm({
|
|
219
243
|
"src/lib/lock.ts"() {
|
|
220
244
|
"use strict";
|
|
221
|
-
LOCK_FILE =
|
|
245
|
+
LOCK_FILE = path24.join(os6.tmpdir(), ".caliber.lock");
|
|
222
246
|
STALE_MS = 10 * 60 * 1e3;
|
|
223
247
|
}
|
|
224
248
|
});
|
|
225
249
|
|
|
226
250
|
// src/cli.ts
|
|
227
251
|
import { Command } from "commander";
|
|
228
|
-
import
|
|
229
|
-
import
|
|
252
|
+
import fs35 from "fs";
|
|
253
|
+
import path28 from "path";
|
|
230
254
|
import { fileURLToPath } from "url";
|
|
231
255
|
|
|
232
256
|
// src/commands/init.ts
|
|
233
|
-
import
|
|
257
|
+
import path21 from "path";
|
|
234
258
|
import chalk11 from "chalk";
|
|
235
259
|
import ora3 from "ora";
|
|
236
260
|
import select5 from "@inquirer/select";
|
|
237
261
|
import checkbox from "@inquirer/checkbox";
|
|
238
|
-
import
|
|
262
|
+
import fs26 from "fs";
|
|
239
263
|
|
|
240
264
|
// src/fingerprint/index.ts
|
|
241
|
-
import
|
|
242
|
-
import
|
|
265
|
+
import fs7 from "fs";
|
|
266
|
+
import path6 from "path";
|
|
243
267
|
|
|
244
268
|
// src/fingerprint/git.ts
|
|
245
269
|
import { execSync } from "child_process";
|
|
@@ -292,15 +316,23 @@ function getFileTree(dir, maxDepth = 3) {
|
|
|
292
316
|
for (const e of entries) {
|
|
293
317
|
(e.isDir ? dirs : files).push(e);
|
|
294
318
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
319
|
+
const dirMaxMtime = /* @__PURE__ */ new Map();
|
|
320
|
+
for (const d of dirs) dirMaxMtime.set(d.relPath, d.mtime);
|
|
321
|
+
for (const f of files) {
|
|
322
|
+
let remaining = f.relPath;
|
|
323
|
+
while (true) {
|
|
324
|
+
const lastSlash = remaining.lastIndexOf("/");
|
|
325
|
+
if (lastSlash === -1) break;
|
|
326
|
+
const dirPrefix = remaining.slice(0, lastSlash + 1);
|
|
327
|
+
const current = dirMaxMtime.get(dirPrefix);
|
|
328
|
+
if (current !== void 0 && f.mtime > current) {
|
|
329
|
+
dirMaxMtime.set(dirPrefix, f.mtime);
|
|
301
330
|
}
|
|
331
|
+
remaining = remaining.slice(0, lastSlash);
|
|
302
332
|
}
|
|
303
|
-
|
|
333
|
+
}
|
|
334
|
+
for (const d of dirs) {
|
|
335
|
+
d.mtime = dirMaxMtime.get(d.relPath) ?? d.mtime;
|
|
304
336
|
}
|
|
305
337
|
dirs.sort((a, b) => b.mtime - a.mtime);
|
|
306
338
|
files.sort((a, b) => b.mtime - a.mtime);
|
|
@@ -2212,12 +2244,112 @@ async function detectProjectStack(fileTree, suffixCounts) {
|
|
|
2212
2244
|
|
|
2213
2245
|
// src/fingerprint/index.ts
|
|
2214
2246
|
init_config();
|
|
2247
|
+
|
|
2248
|
+
// src/fingerprint/cache.ts
|
|
2249
|
+
import fs6 from "fs";
|
|
2250
|
+
import path5 from "path";
|
|
2251
|
+
import crypto from "crypto";
|
|
2252
|
+
import { execSync as execSync5 } from "child_process";
|
|
2253
|
+
var CACHE_VERSION = 1;
|
|
2254
|
+
var CACHE_DIR = ".caliber/cache";
|
|
2255
|
+
var CACHE_FILE = "fingerprint.json";
|
|
2256
|
+
function getCachePath(dir) {
|
|
2257
|
+
return path5.join(dir, CACHE_DIR, CACHE_FILE);
|
|
2258
|
+
}
|
|
2259
|
+
function getGitHead(dir) {
|
|
2260
|
+
try {
|
|
2261
|
+
return execSync5("git rev-parse HEAD", {
|
|
2262
|
+
cwd: dir,
|
|
2263
|
+
encoding: "utf-8",
|
|
2264
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2265
|
+
timeout: 3e3
|
|
2266
|
+
}).trim();
|
|
2267
|
+
} catch {
|
|
2268
|
+
return "";
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
function getDirtySignature(dir) {
|
|
2272
|
+
try {
|
|
2273
|
+
const output = execSync5("git diff --name-only HEAD", {
|
|
2274
|
+
cwd: dir,
|
|
2275
|
+
encoding: "utf-8",
|
|
2276
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2277
|
+
timeout: 3e3
|
|
2278
|
+
}).trim();
|
|
2279
|
+
return output.split("\n").slice(0, 100).join("\n");
|
|
2280
|
+
} catch {
|
|
2281
|
+
return "";
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
function computeTreeSignature(fileTree, dir) {
|
|
2285
|
+
const hash = crypto.createHash("sha256");
|
|
2286
|
+
hash.update(fileTree.join("\0"));
|
|
2287
|
+
hash.update("\n");
|
|
2288
|
+
hash.update(getDirtySignature(dir));
|
|
2289
|
+
return hash.digest("hex").slice(0, 16);
|
|
2290
|
+
}
|
|
2291
|
+
function loadFingerprintCache(dir, fileTree) {
|
|
2292
|
+
const cachePath = getCachePath(dir);
|
|
2293
|
+
try {
|
|
2294
|
+
if (!fs6.existsSync(cachePath)) return null;
|
|
2295
|
+
const raw = fs6.readFileSync(cachePath, "utf-8");
|
|
2296
|
+
const cache = JSON.parse(raw);
|
|
2297
|
+
if (cache.version !== CACHE_VERSION) return null;
|
|
2298
|
+
const currentHead = getGitHead(dir);
|
|
2299
|
+
if (currentHead && cache.gitHead !== currentHead) return null;
|
|
2300
|
+
const currentSig = computeTreeSignature(fileTree, dir);
|
|
2301
|
+
if (cache.treeSignature !== currentSig) return null;
|
|
2302
|
+
return {
|
|
2303
|
+
codeAnalysis: cache.codeAnalysis,
|
|
2304
|
+
languages: cache.languages,
|
|
2305
|
+
frameworks: cache.frameworks,
|
|
2306
|
+
tools: cache.tools
|
|
2307
|
+
};
|
|
2308
|
+
} catch {
|
|
2309
|
+
return null;
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
function saveFingerprintCache(dir, fileTree, codeAnalysis, languages, frameworks, tools) {
|
|
2313
|
+
const cachePath = getCachePath(dir);
|
|
2314
|
+
try {
|
|
2315
|
+
const cacheDir = path5.dirname(cachePath);
|
|
2316
|
+
if (!fs6.existsSync(cacheDir)) {
|
|
2317
|
+
fs6.mkdirSync(cacheDir, { recursive: true });
|
|
2318
|
+
}
|
|
2319
|
+
const cache = {
|
|
2320
|
+
version: CACHE_VERSION,
|
|
2321
|
+
gitHead: getGitHead(dir),
|
|
2322
|
+
treeSignature: computeTreeSignature(fileTree, dir),
|
|
2323
|
+
codeAnalysis,
|
|
2324
|
+
languages,
|
|
2325
|
+
frameworks,
|
|
2326
|
+
tools
|
|
2327
|
+
};
|
|
2328
|
+
fs6.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
|
|
2329
|
+
} catch {
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
// src/fingerprint/index.ts
|
|
2215
2334
|
async function collectFingerprint(dir) {
|
|
2216
2335
|
const gitRemoteUrl = getGitRemoteUrl();
|
|
2217
2336
|
const fileTree = getFileTree(dir);
|
|
2218
2337
|
const existingConfigs = readExistingConfigs(dir);
|
|
2219
|
-
const codeAnalysis = analyzeCode(dir);
|
|
2220
2338
|
const packageName = readPackageName(dir);
|
|
2339
|
+
const cached = loadFingerprintCache(dir, fileTree);
|
|
2340
|
+
if (cached) {
|
|
2341
|
+
return {
|
|
2342
|
+
gitRemoteUrl,
|
|
2343
|
+
packageName,
|
|
2344
|
+
languages: cached.languages,
|
|
2345
|
+
frameworks: cached.frameworks,
|
|
2346
|
+
tools: cached.tools,
|
|
2347
|
+
fileTree,
|
|
2348
|
+
existingConfigs,
|
|
2349
|
+
codeAnalysis: cached.codeAnalysis
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
const codeAnalysis = analyzeCode(dir);
|
|
2221
2353
|
const fingerprint = {
|
|
2222
2354
|
gitRemoteUrl,
|
|
2223
2355
|
packageName,
|
|
@@ -2229,13 +2361,21 @@ async function collectFingerprint(dir) {
|
|
|
2229
2361
|
codeAnalysis
|
|
2230
2362
|
};
|
|
2231
2363
|
await enrichWithLLM(fingerprint);
|
|
2364
|
+
saveFingerprintCache(
|
|
2365
|
+
dir,
|
|
2366
|
+
fileTree,
|
|
2367
|
+
codeAnalysis,
|
|
2368
|
+
fingerprint.languages,
|
|
2369
|
+
fingerprint.frameworks,
|
|
2370
|
+
fingerprint.tools
|
|
2371
|
+
);
|
|
2232
2372
|
return fingerprint;
|
|
2233
2373
|
}
|
|
2234
2374
|
function readPackageName(dir) {
|
|
2235
2375
|
try {
|
|
2236
|
-
const pkgPath =
|
|
2237
|
-
if (!
|
|
2238
|
-
const pkg3 = JSON.parse(
|
|
2376
|
+
const pkgPath = path6.join(dir, "package.json");
|
|
2377
|
+
if (!fs7.existsSync(pkgPath)) return void 0;
|
|
2378
|
+
const pkg3 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
2239
2379
|
return pkg3.name;
|
|
2240
2380
|
} catch {
|
|
2241
2381
|
return void 0;
|
|
@@ -2249,7 +2389,7 @@ async function enrichWithLLM(fingerprint) {
|
|
|
2249
2389
|
const suffixCounts = {};
|
|
2250
2390
|
for (const entry of fingerprint.fileTree) {
|
|
2251
2391
|
if (entry.endsWith("/")) continue;
|
|
2252
|
-
const ext =
|
|
2392
|
+
const ext = path6.extname(entry).toLowerCase();
|
|
2253
2393
|
if (ext) {
|
|
2254
2394
|
suffixCounts[ext] = (suffixCounts[ext] || 0) + 1;
|
|
2255
2395
|
}
|
|
@@ -2268,15 +2408,15 @@ init_config();
|
|
|
2268
2408
|
// src/utils/dependencies.ts
|
|
2269
2409
|
import { readFileSync } from "fs";
|
|
2270
2410
|
import { join } from "path";
|
|
2271
|
-
function readFileOrNull(
|
|
2411
|
+
function readFileOrNull(path30) {
|
|
2272
2412
|
try {
|
|
2273
|
-
return readFileSync(
|
|
2413
|
+
return readFileSync(path30, "utf-8");
|
|
2274
2414
|
} catch {
|
|
2275
2415
|
return null;
|
|
2276
2416
|
}
|
|
2277
2417
|
}
|
|
2278
|
-
function readJsonOrNull(
|
|
2279
|
-
const content = readFileOrNull(
|
|
2418
|
+
function readJsonOrNull(path30) {
|
|
2419
|
+
const content = readFileOrNull(path30);
|
|
2280
2420
|
if (!content) return null;
|
|
2281
2421
|
try {
|
|
2282
2422
|
return JSON.parse(content);
|
|
@@ -2500,15 +2640,14 @@ Generate the skill content following the instructions in the system prompt.`;
|
|
|
2500
2640
|
content
|
|
2501
2641
|
};
|
|
2502
2642
|
}
|
|
2503
|
-
async function
|
|
2643
|
+
async function streamGeneration(config) {
|
|
2504
2644
|
const provider = getProvider();
|
|
2505
|
-
const userMessage = buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks);
|
|
2506
2645
|
let attempt = 0;
|
|
2507
2646
|
const attemptGeneration = async () => {
|
|
2508
2647
|
attempt++;
|
|
2509
2648
|
const maxTokensForAttempt = Math.min(
|
|
2510
|
-
|
|
2511
|
-
|
|
2649
|
+
config.baseMaxTokens + attempt * config.tokenIncrement,
|
|
2650
|
+
config.maxTokensCap
|
|
2512
2651
|
);
|
|
2513
2652
|
return new Promise((resolve2) => {
|
|
2514
2653
|
let preJsonBuffer = "";
|
|
@@ -2518,8 +2657,8 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
|
|
|
2518
2657
|
let stopReason = null;
|
|
2519
2658
|
provider.stream(
|
|
2520
2659
|
{
|
|
2521
|
-
system:
|
|
2522
|
-
prompt: userMessage,
|
|
2660
|
+
system: config.systemPrompt,
|
|
2661
|
+
prompt: config.userMessage,
|
|
2523
2662
|
maxTokens: maxTokensForAttempt
|
|
2524
2663
|
},
|
|
2525
2664
|
{
|
|
@@ -2532,7 +2671,7 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
|
|
|
2532
2671
|
const trimmed = completedLines[i].trim();
|
|
2533
2672
|
if (trimmed.startsWith("STATUS:")) {
|
|
2534
2673
|
const status = trimmed.slice(7).trim();
|
|
2535
|
-
if (status && callbacks) callbacks.onStatus(status);
|
|
2674
|
+
if (status && config.callbacks) config.callbacks.onStatus(status);
|
|
2536
2675
|
}
|
|
2537
2676
|
}
|
|
2538
2677
|
sentStatuses = completedLines.length;
|
|
@@ -2562,7 +2701,7 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
|
|
|
2562
2701
|
} catch {
|
|
2563
2702
|
}
|
|
2564
2703
|
if (!setup && stopReason === "max_tokens" && attempt < MAX_RETRIES2) {
|
|
2565
|
-
if (callbacks) callbacks.onStatus("Output was truncated, retrying with higher token limit...");
|
|
2704
|
+
if (config.callbacks) config.callbacks.onStatus("Output was truncated, retrying with higher token limit...");
|
|
2566
2705
|
setTimeout(() => attemptGeneration().then(resolve2), 1e3);
|
|
2567
2706
|
return;
|
|
2568
2707
|
}
|
|
@@ -2572,7 +2711,7 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
|
|
|
2572
2711
|
explanation = explainMatch[1].trim();
|
|
2573
2712
|
}
|
|
2574
2713
|
if (setup) {
|
|
2575
|
-
if (callbacks) callbacks.onComplete(setup, explanation);
|
|
2714
|
+
if (config.callbacks) config.callbacks.onComplete(setup, explanation);
|
|
2576
2715
|
resolve2({ setup, explanation, stopReason: stopReason ?? void 0 });
|
|
2577
2716
|
} else {
|
|
2578
2717
|
resolve2({ setup: null, explanation, raw: preJsonBuffer, stopReason: stopReason ?? void 0 });
|
|
@@ -2580,117 +2719,43 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
|
|
|
2580
2719
|
},
|
|
2581
2720
|
onError: (error) => {
|
|
2582
2721
|
if (isTransientError2(error) && attempt < MAX_RETRIES2) {
|
|
2583
|
-
if (callbacks) callbacks.onStatus("Connection interrupted, retrying...");
|
|
2722
|
+
if (config.callbacks) config.callbacks.onStatus("Connection interrupted, retrying...");
|
|
2584
2723
|
setTimeout(() => attemptGeneration().then(resolve2), 2e3);
|
|
2585
2724
|
return;
|
|
2586
2725
|
}
|
|
2587
|
-
if (callbacks) callbacks.onError(error.message);
|
|
2726
|
+
if (config.callbacks) config.callbacks.onError(error.message);
|
|
2588
2727
|
resolve2({ setup: null, raw: error.message, stopReason: "error" });
|
|
2589
2728
|
}
|
|
2590
2729
|
}
|
|
2591
2730
|
).catch((error) => {
|
|
2592
|
-
if (callbacks) callbacks.onError(error.message);
|
|
2731
|
+
if (config.callbacks) config.callbacks.onError(error.message);
|
|
2593
2732
|
resolve2({ setup: null, raw: error.message, stopReason: "error" });
|
|
2594
2733
|
});
|
|
2595
2734
|
});
|
|
2596
2735
|
};
|
|
2597
2736
|
return attemptGeneration();
|
|
2598
2737
|
}
|
|
2738
|
+
async function generateCore(fingerprint, targetAgent, prompt, callbacks, failingChecks, currentScore, passingChecks) {
|
|
2739
|
+
const userMessage = buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks);
|
|
2740
|
+
return streamGeneration({
|
|
2741
|
+
systemPrompt: CORE_GENERATION_PROMPT,
|
|
2742
|
+
userMessage,
|
|
2743
|
+
baseMaxTokens: CORE_MAX_TOKENS,
|
|
2744
|
+
tokenIncrement: 8e3,
|
|
2745
|
+
maxTokensCap: GENERATION_MAX_TOKENS,
|
|
2746
|
+
callbacks
|
|
2747
|
+
});
|
|
2748
|
+
}
|
|
2599
2749
|
async function generateMonolithic(fingerprint, targetAgent, prompt, callbacks, failingChecks, currentScore, passingChecks) {
|
|
2600
|
-
const provider = getProvider();
|
|
2601
2750
|
const userMessage = buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks);
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
let preJsonBuffer = "";
|
|
2611
|
-
let jsonContent = "";
|
|
2612
|
-
let inJson = false;
|
|
2613
|
-
let sentStatuses = 0;
|
|
2614
|
-
let stopReason = null;
|
|
2615
|
-
provider.stream(
|
|
2616
|
-
{
|
|
2617
|
-
system: GENERATION_SYSTEM_PROMPT,
|
|
2618
|
-
prompt: userMessage,
|
|
2619
|
-
maxTokens: maxTokensForAttempt
|
|
2620
|
-
},
|
|
2621
|
-
{
|
|
2622
|
-
onText: (text) => {
|
|
2623
|
-
if (!inJson) {
|
|
2624
|
-
preJsonBuffer += text;
|
|
2625
|
-
const lines = preJsonBuffer.split("\n");
|
|
2626
|
-
const completedLines = lines.slice(0, -1);
|
|
2627
|
-
for (let i = sentStatuses; i < completedLines.length; i++) {
|
|
2628
|
-
const trimmed = completedLines[i].trim();
|
|
2629
|
-
if (trimmed.startsWith("STATUS:")) {
|
|
2630
|
-
const status = trimmed.slice(7).trim();
|
|
2631
|
-
if (status && callbacks) callbacks.onStatus(status);
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
sentStatuses = completedLines.length;
|
|
2635
|
-
const jsonStartMatch = preJsonBuffer.match(/(?:^|\n)\s*(?:```json\s*\n\s*)?\{(?=\s*")/);
|
|
2636
|
-
if (jsonStartMatch) {
|
|
2637
|
-
const matchIndex = preJsonBuffer.indexOf("{", jsonStartMatch.index);
|
|
2638
|
-
inJson = true;
|
|
2639
|
-
jsonContent = preJsonBuffer.slice(matchIndex);
|
|
2640
|
-
}
|
|
2641
|
-
} else {
|
|
2642
|
-
jsonContent += text;
|
|
2643
|
-
}
|
|
2644
|
-
},
|
|
2645
|
-
onEnd: (meta) => {
|
|
2646
|
-
stopReason = meta?.stopReason ?? null;
|
|
2647
|
-
let setup = null;
|
|
2648
|
-
let jsonToParse = (jsonContent || preJsonBuffer).replace(/```\s*$/g, "").trim();
|
|
2649
|
-
if (!jsonContent && preJsonBuffer) {
|
|
2650
|
-
const fallbackMatch = preJsonBuffer.match(/(?:^|\n)\s*(?:```json\s*\n\s*)?\{(?=\s*")/);
|
|
2651
|
-
if (fallbackMatch) {
|
|
2652
|
-
const matchIndex = preJsonBuffer.indexOf("{", fallbackMatch.index);
|
|
2653
|
-
jsonToParse = preJsonBuffer.slice(matchIndex).replace(/```\s*$/g, "").trim();
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
try {
|
|
2657
|
-
setup = JSON.parse(jsonToParse);
|
|
2658
|
-
} catch {
|
|
2659
|
-
}
|
|
2660
|
-
if (!setup && stopReason === "max_tokens" && attempt < MAX_RETRIES2) {
|
|
2661
|
-
if (callbacks) callbacks.onStatus("Output was truncated, retrying with higher token limit...");
|
|
2662
|
-
setTimeout(() => attemptGeneration().then(resolve2), 1e3);
|
|
2663
|
-
return;
|
|
2664
|
-
}
|
|
2665
|
-
let explanation;
|
|
2666
|
-
const explainMatch = preJsonBuffer.match(/EXPLAIN:\s*\n([\s\S]*?)(?=\n\s*(`{3}|\{))/);
|
|
2667
|
-
if (explainMatch) {
|
|
2668
|
-
explanation = explainMatch[1].trim();
|
|
2669
|
-
}
|
|
2670
|
-
if (setup) {
|
|
2671
|
-
if (callbacks) callbacks.onComplete(setup, explanation);
|
|
2672
|
-
resolve2({ setup, explanation, stopReason: stopReason ?? void 0 });
|
|
2673
|
-
} else {
|
|
2674
|
-
resolve2({ setup: null, explanation, raw: preJsonBuffer, stopReason: stopReason ?? void 0 });
|
|
2675
|
-
}
|
|
2676
|
-
},
|
|
2677
|
-
onError: (error) => {
|
|
2678
|
-
if (isTransientError2(error) && attempt < MAX_RETRIES2) {
|
|
2679
|
-
if (callbacks) callbacks.onStatus("Connection interrupted, retrying...");
|
|
2680
|
-
setTimeout(() => attemptGeneration().then(resolve2), 2e3);
|
|
2681
|
-
return;
|
|
2682
|
-
}
|
|
2683
|
-
if (callbacks) callbacks.onError(error.message);
|
|
2684
|
-
resolve2({ setup: null, raw: error.message, stopReason: "error" });
|
|
2685
|
-
}
|
|
2686
|
-
}
|
|
2687
|
-
).catch((error) => {
|
|
2688
|
-
if (callbacks) callbacks.onError(error.message);
|
|
2689
|
-
resolve2({ setup: null, raw: error.message, stopReason: "error" });
|
|
2690
|
-
});
|
|
2691
|
-
});
|
|
2692
|
-
};
|
|
2693
|
-
return attemptGeneration();
|
|
2751
|
+
return streamGeneration({
|
|
2752
|
+
systemPrompt: GENERATION_SYSTEM_PROMPT,
|
|
2753
|
+
userMessage,
|
|
2754
|
+
baseMaxTokens: GENERATION_MAX_TOKENS,
|
|
2755
|
+
tokenIncrement: 16e3,
|
|
2756
|
+
maxTokensCap: MODEL_MAX_OUTPUT_TOKENS,
|
|
2757
|
+
callbacks
|
|
2758
|
+
});
|
|
2694
2759
|
}
|
|
2695
2760
|
async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus) {
|
|
2696
2761
|
const skillTopics = collectSkillTopics(setup, targetAgent, fingerprint);
|
|
@@ -2723,7 +2788,6 @@ async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus)
|
|
|
2723
2788
|
if (failed > 0) onStatus?.(`${succeeded} generated, ${failed} failed`);
|
|
2724
2789
|
return succeeded;
|
|
2725
2790
|
}
|
|
2726
|
-
var MAX_PROMPT_TOKENS = 12e4;
|
|
2727
2791
|
var LIMITS = {
|
|
2728
2792
|
FILE_TREE_ENTRIES: 500,
|
|
2729
2793
|
EXISTING_CONFIG_CHARS: 8e3,
|
|
@@ -2738,6 +2802,7 @@ function truncate(text, maxChars) {
|
|
|
2738
2802
|
}
|
|
2739
2803
|
function sampleFileTree(fileTree, codeAnalysisPaths, limit) {
|
|
2740
2804
|
if (fileTree.length <= limit) return fileTree;
|
|
2805
|
+
const fileTreeSet = new Set(fileTree);
|
|
2741
2806
|
const dirs = [];
|
|
2742
2807
|
const rootFiles = [];
|
|
2743
2808
|
const nestedFiles = [];
|
|
@@ -2763,7 +2828,7 @@ function sampleFileTree(fileTree, codeAnalysisPaths, limit) {
|
|
|
2763
2828
|
for (const f of rootFiles.slice(0, 50)) add(f);
|
|
2764
2829
|
for (const p of codeAnalysisPaths) {
|
|
2765
2830
|
if (result.length >= limit) break;
|
|
2766
|
-
if (
|
|
2831
|
+
if (fileTreeSet.has(p)) add(p);
|
|
2767
2832
|
}
|
|
2768
2833
|
for (const f of nestedFiles) {
|
|
2769
2834
|
if (result.length >= limit) break;
|
|
@@ -2887,20 +2952,25 @@ User instructions: ${prompt}`);
|
|
|
2887
2952
|
if (fingerprint.codeAnalysis) {
|
|
2888
2953
|
const ca = fingerprint.codeAnalysis;
|
|
2889
2954
|
const basePrompt = parts.join("\n");
|
|
2955
|
+
const maxPromptTokens = getMaxPromptTokens();
|
|
2890
2956
|
const baseTokens = estimateTokens(basePrompt);
|
|
2891
|
-
const tokenBudgetForCode = Math.max(0,
|
|
2957
|
+
const tokenBudgetForCode = Math.max(0, maxPromptTokens - baseTokens);
|
|
2892
2958
|
const codeLines = [];
|
|
2893
2959
|
let codeChars = 0;
|
|
2894
|
-
|
|
2960
|
+
const introLine = "Study these files to extract patterns for skills. Use the exact code patterns you see here.\n";
|
|
2961
|
+
codeLines.push(introLine);
|
|
2962
|
+
let runningCodeLen = introLine.length;
|
|
2895
2963
|
const sortedFiles = [...ca.files].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
2896
2964
|
let includedFiles = 0;
|
|
2897
2965
|
for (const f of sortedFiles) {
|
|
2898
2966
|
const entry = `[${f.path}]
|
|
2899
2967
|
${f.content}
|
|
2900
2968
|
`;
|
|
2901
|
-
|
|
2969
|
+
const projectedLen = runningCodeLen + 1 + entry.length;
|
|
2970
|
+
if (Math.ceil(projectedLen / 4) > tokenBudgetForCode && includedFiles > 0) break;
|
|
2902
2971
|
codeLines.push(entry);
|
|
2903
2972
|
codeChars += f.content.length;
|
|
2973
|
+
runningCodeLen = projectedLen;
|
|
2904
2974
|
includedFiles++;
|
|
2905
2975
|
}
|
|
2906
2976
|
const includedTokens = Math.ceil(codeChars / 4);
|
|
@@ -2971,20 +3041,20 @@ Return the complete updated AgentSetup JSON incorporating the user's changes. Re
|
|
|
2971
3041
|
}
|
|
2972
3042
|
|
|
2973
3043
|
// src/writers/index.ts
|
|
2974
|
-
import
|
|
3044
|
+
import fs13 from "fs";
|
|
2975
3045
|
|
|
2976
3046
|
// src/writers/claude/index.ts
|
|
2977
|
-
import
|
|
2978
|
-
import
|
|
3047
|
+
import fs8 from "fs";
|
|
3048
|
+
import path7 from "path";
|
|
2979
3049
|
function writeClaudeConfig(config) {
|
|
2980
3050
|
const written = [];
|
|
2981
|
-
|
|
3051
|
+
fs8.writeFileSync("CLAUDE.md", config.claudeMd);
|
|
2982
3052
|
written.push("CLAUDE.md");
|
|
2983
3053
|
if (config.skills?.length) {
|
|
2984
3054
|
for (const skill of config.skills) {
|
|
2985
|
-
const skillDir =
|
|
2986
|
-
if (!
|
|
2987
|
-
const skillPath =
|
|
3055
|
+
const skillDir = path7.join(".claude", "skills", skill.name);
|
|
3056
|
+
if (!fs8.existsSync(skillDir)) fs8.mkdirSync(skillDir, { recursive: true });
|
|
3057
|
+
const skillPath = path7.join(skillDir, "SKILL.md");
|
|
2988
3058
|
const frontmatter = [
|
|
2989
3059
|
"---",
|
|
2990
3060
|
`name: ${skill.name}`,
|
|
@@ -2992,49 +3062,49 @@ function writeClaudeConfig(config) {
|
|
|
2992
3062
|
"---",
|
|
2993
3063
|
""
|
|
2994
3064
|
].join("\n");
|
|
2995
|
-
|
|
3065
|
+
fs8.writeFileSync(skillPath, frontmatter + skill.content);
|
|
2996
3066
|
written.push(skillPath);
|
|
2997
3067
|
}
|
|
2998
3068
|
}
|
|
2999
3069
|
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
|
3000
3070
|
let existingServers = {};
|
|
3001
3071
|
try {
|
|
3002
|
-
if (
|
|
3003
|
-
const existing = JSON.parse(
|
|
3072
|
+
if (fs8.existsSync(".mcp.json")) {
|
|
3073
|
+
const existing = JSON.parse(fs8.readFileSync(".mcp.json", "utf-8"));
|
|
3004
3074
|
if (existing.mcpServers) existingServers = existing.mcpServers;
|
|
3005
3075
|
}
|
|
3006
3076
|
} catch {
|
|
3007
3077
|
}
|
|
3008
3078
|
const mergedServers = { ...existingServers, ...config.mcpServers };
|
|
3009
|
-
|
|
3079
|
+
fs8.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
|
|
3010
3080
|
written.push(".mcp.json");
|
|
3011
3081
|
}
|
|
3012
3082
|
return written;
|
|
3013
3083
|
}
|
|
3014
3084
|
|
|
3015
3085
|
// src/writers/cursor/index.ts
|
|
3016
|
-
import
|
|
3017
|
-
import
|
|
3086
|
+
import fs9 from "fs";
|
|
3087
|
+
import path8 from "path";
|
|
3018
3088
|
function writeCursorConfig(config) {
|
|
3019
3089
|
const written = [];
|
|
3020
3090
|
if (config.cursorrules) {
|
|
3021
|
-
|
|
3091
|
+
fs9.writeFileSync(".cursorrules", config.cursorrules);
|
|
3022
3092
|
written.push(".cursorrules");
|
|
3023
3093
|
}
|
|
3024
3094
|
if (config.rules?.length) {
|
|
3025
|
-
const rulesDir =
|
|
3026
|
-
if (!
|
|
3095
|
+
const rulesDir = path8.join(".cursor", "rules");
|
|
3096
|
+
if (!fs9.existsSync(rulesDir)) fs9.mkdirSync(rulesDir, { recursive: true });
|
|
3027
3097
|
for (const rule of config.rules) {
|
|
3028
|
-
const rulePath =
|
|
3029
|
-
|
|
3098
|
+
const rulePath = path8.join(rulesDir, rule.filename);
|
|
3099
|
+
fs9.writeFileSync(rulePath, rule.content);
|
|
3030
3100
|
written.push(rulePath);
|
|
3031
3101
|
}
|
|
3032
3102
|
}
|
|
3033
3103
|
if (config.skills?.length) {
|
|
3034
3104
|
for (const skill of config.skills) {
|
|
3035
|
-
const skillDir =
|
|
3036
|
-
if (!
|
|
3037
|
-
const skillPath =
|
|
3105
|
+
const skillDir = path8.join(".cursor", "skills", skill.name);
|
|
3106
|
+
if (!fs9.existsSync(skillDir)) fs9.mkdirSync(skillDir, { recursive: true });
|
|
3107
|
+
const skillPath = path8.join(skillDir, "SKILL.md");
|
|
3038
3108
|
const frontmatter = [
|
|
3039
3109
|
"---",
|
|
3040
3110
|
`name: ${skill.name}`,
|
|
@@ -3042,41 +3112,41 @@ function writeCursorConfig(config) {
|
|
|
3042
3112
|
"---",
|
|
3043
3113
|
""
|
|
3044
3114
|
].join("\n");
|
|
3045
|
-
|
|
3115
|
+
fs9.writeFileSync(skillPath, frontmatter + skill.content);
|
|
3046
3116
|
written.push(skillPath);
|
|
3047
3117
|
}
|
|
3048
3118
|
}
|
|
3049
3119
|
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
|
3050
3120
|
const cursorDir = ".cursor";
|
|
3051
|
-
if (!
|
|
3052
|
-
const mcpPath =
|
|
3121
|
+
if (!fs9.existsSync(cursorDir)) fs9.mkdirSync(cursorDir, { recursive: true });
|
|
3122
|
+
const mcpPath = path8.join(cursorDir, "mcp.json");
|
|
3053
3123
|
let existingServers = {};
|
|
3054
3124
|
try {
|
|
3055
|
-
if (
|
|
3056
|
-
const existing = JSON.parse(
|
|
3125
|
+
if (fs9.existsSync(mcpPath)) {
|
|
3126
|
+
const existing = JSON.parse(fs9.readFileSync(mcpPath, "utf-8"));
|
|
3057
3127
|
if (existing.mcpServers) existingServers = existing.mcpServers;
|
|
3058
3128
|
}
|
|
3059
3129
|
} catch {
|
|
3060
3130
|
}
|
|
3061
3131
|
const mergedServers = { ...existingServers, ...config.mcpServers };
|
|
3062
|
-
|
|
3132
|
+
fs9.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
|
|
3063
3133
|
written.push(mcpPath);
|
|
3064
3134
|
}
|
|
3065
3135
|
return written;
|
|
3066
3136
|
}
|
|
3067
3137
|
|
|
3068
3138
|
// src/writers/codex/index.ts
|
|
3069
|
-
import
|
|
3070
|
-
import
|
|
3139
|
+
import fs10 from "fs";
|
|
3140
|
+
import path9 from "path";
|
|
3071
3141
|
function writeCodexConfig(config) {
|
|
3072
3142
|
const written = [];
|
|
3073
|
-
|
|
3143
|
+
fs10.writeFileSync("AGENTS.md", config.agentsMd);
|
|
3074
3144
|
written.push("AGENTS.md");
|
|
3075
3145
|
if (config.skills?.length) {
|
|
3076
3146
|
for (const skill of config.skills) {
|
|
3077
|
-
const skillDir =
|
|
3078
|
-
if (!
|
|
3079
|
-
const skillPath =
|
|
3147
|
+
const skillDir = path9.join(".agents", "skills", skill.name);
|
|
3148
|
+
if (!fs10.existsSync(skillDir)) fs10.mkdirSync(skillDir, { recursive: true });
|
|
3149
|
+
const skillPath = path9.join(skillDir, "SKILL.md");
|
|
3080
3150
|
const frontmatter = [
|
|
3081
3151
|
"---",
|
|
3082
3152
|
`name: ${skill.name}`,
|
|
@@ -3084,7 +3154,7 @@ function writeCodexConfig(config) {
|
|
|
3084
3154
|
"---",
|
|
3085
3155
|
""
|
|
3086
3156
|
].join("\n");
|
|
3087
|
-
|
|
3157
|
+
fs10.writeFileSync(skillPath, frontmatter + skill.content);
|
|
3088
3158
|
written.push(skillPath);
|
|
3089
3159
|
}
|
|
3090
3160
|
}
|
|
@@ -3093,62 +3163,62 @@ function writeCodexConfig(config) {
|
|
|
3093
3163
|
|
|
3094
3164
|
// src/writers/backup.ts
|
|
3095
3165
|
init_constants();
|
|
3096
|
-
import
|
|
3097
|
-
import
|
|
3166
|
+
import fs11 from "fs";
|
|
3167
|
+
import path11 from "path";
|
|
3098
3168
|
function createBackup(files) {
|
|
3099
3169
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3100
|
-
const backupDir =
|
|
3170
|
+
const backupDir = path11.join(BACKUPS_DIR, timestamp);
|
|
3101
3171
|
for (const file of files) {
|
|
3102
|
-
if (!
|
|
3103
|
-
const dest =
|
|
3104
|
-
const destDir =
|
|
3105
|
-
if (!
|
|
3106
|
-
|
|
3172
|
+
if (!fs11.existsSync(file)) continue;
|
|
3173
|
+
const dest = path11.join(backupDir, file);
|
|
3174
|
+
const destDir = path11.dirname(dest);
|
|
3175
|
+
if (!fs11.existsSync(destDir)) {
|
|
3176
|
+
fs11.mkdirSync(destDir, { recursive: true });
|
|
3107
3177
|
}
|
|
3108
|
-
|
|
3178
|
+
fs11.copyFileSync(file, dest);
|
|
3109
3179
|
}
|
|
3110
3180
|
return backupDir;
|
|
3111
3181
|
}
|
|
3112
3182
|
function restoreBackup(backupDir, file) {
|
|
3113
|
-
const backupFile =
|
|
3114
|
-
if (!
|
|
3115
|
-
const destDir =
|
|
3116
|
-
if (!
|
|
3117
|
-
|
|
3183
|
+
const backupFile = path11.join(backupDir, file);
|
|
3184
|
+
if (!fs11.existsSync(backupFile)) return false;
|
|
3185
|
+
const destDir = path11.dirname(file);
|
|
3186
|
+
if (!fs11.existsSync(destDir)) {
|
|
3187
|
+
fs11.mkdirSync(destDir, { recursive: true });
|
|
3118
3188
|
}
|
|
3119
|
-
|
|
3189
|
+
fs11.copyFileSync(backupFile, file);
|
|
3120
3190
|
return true;
|
|
3121
3191
|
}
|
|
3122
3192
|
|
|
3123
3193
|
// src/writers/manifest.ts
|
|
3124
3194
|
init_constants();
|
|
3125
|
-
import
|
|
3126
|
-
import
|
|
3195
|
+
import fs12 from "fs";
|
|
3196
|
+
import crypto2 from "crypto";
|
|
3127
3197
|
function readManifest() {
|
|
3128
3198
|
try {
|
|
3129
|
-
if (!
|
|
3130
|
-
return JSON.parse(
|
|
3199
|
+
if (!fs12.existsSync(MANIFEST_FILE)) return null;
|
|
3200
|
+
return JSON.parse(fs12.readFileSync(MANIFEST_FILE, "utf-8"));
|
|
3131
3201
|
} catch {
|
|
3132
3202
|
return null;
|
|
3133
3203
|
}
|
|
3134
3204
|
}
|
|
3135
3205
|
function writeManifest(manifest) {
|
|
3136
|
-
if (!
|
|
3137
|
-
|
|
3206
|
+
if (!fs12.existsSync(CALIBER_DIR)) {
|
|
3207
|
+
fs12.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
3138
3208
|
}
|
|
3139
|
-
|
|
3209
|
+
fs12.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
|
|
3140
3210
|
}
|
|
3141
3211
|
function fileChecksum(filePath) {
|
|
3142
|
-
const content =
|
|
3143
|
-
return
|
|
3212
|
+
const content = fs12.readFileSync(filePath);
|
|
3213
|
+
return crypto2.createHash("sha256").update(content).digest("hex");
|
|
3144
3214
|
}
|
|
3145
3215
|
|
|
3146
3216
|
// src/writers/index.ts
|
|
3147
3217
|
function writeSetup(setup) {
|
|
3148
3218
|
const filesToWrite = getFilesToWrite(setup);
|
|
3149
|
-
const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) =>
|
|
3219
|
+
const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs13.existsSync(f));
|
|
3150
3220
|
const existingFiles = [
|
|
3151
|
-
...filesToWrite.filter((f) =>
|
|
3221
|
+
...filesToWrite.filter((f) => fs13.existsSync(f)),
|
|
3152
3222
|
...filesToDelete
|
|
3153
3223
|
];
|
|
3154
3224
|
const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
|
|
@@ -3164,7 +3234,7 @@ function writeSetup(setup) {
|
|
|
3164
3234
|
}
|
|
3165
3235
|
const deleted = [];
|
|
3166
3236
|
for (const filePath of filesToDelete) {
|
|
3167
|
-
|
|
3237
|
+
fs13.unlinkSync(filePath);
|
|
3168
3238
|
deleted.push(filePath);
|
|
3169
3239
|
}
|
|
3170
3240
|
ensureGitignore();
|
|
@@ -3194,8 +3264,8 @@ function undoSetup() {
|
|
|
3194
3264
|
const removed = [];
|
|
3195
3265
|
for (const entry of manifest.entries) {
|
|
3196
3266
|
if (entry.action === "created") {
|
|
3197
|
-
if (
|
|
3198
|
-
|
|
3267
|
+
if (fs13.existsSync(entry.path)) {
|
|
3268
|
+
fs13.unlinkSync(entry.path);
|
|
3199
3269
|
removed.push(entry.path);
|
|
3200
3270
|
}
|
|
3201
3271
|
} else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
|
|
@@ -3205,8 +3275,8 @@ function undoSetup() {
|
|
|
3205
3275
|
}
|
|
3206
3276
|
}
|
|
3207
3277
|
const { MANIFEST_FILE: MANIFEST_FILE2 } = (init_constants(), __toCommonJS(constants_exports));
|
|
3208
|
-
if (
|
|
3209
|
-
|
|
3278
|
+
if (fs13.existsSync(MANIFEST_FILE2)) {
|
|
3279
|
+
fs13.unlinkSync(MANIFEST_FILE2);
|
|
3210
3280
|
}
|
|
3211
3281
|
return { restored, removed };
|
|
3212
3282
|
}
|
|
@@ -3241,23 +3311,23 @@ function getFilesToWrite(setup) {
|
|
|
3241
3311
|
}
|
|
3242
3312
|
function ensureGitignore() {
|
|
3243
3313
|
const gitignorePath = ".gitignore";
|
|
3244
|
-
if (
|
|
3245
|
-
const content =
|
|
3314
|
+
if (fs13.existsSync(gitignorePath)) {
|
|
3315
|
+
const content = fs13.readFileSync(gitignorePath, "utf-8");
|
|
3246
3316
|
if (!content.includes(".caliber/")) {
|
|
3247
|
-
|
|
3317
|
+
fs13.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
|
|
3248
3318
|
}
|
|
3249
3319
|
} else {
|
|
3250
|
-
|
|
3320
|
+
fs13.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
|
|
3251
3321
|
}
|
|
3252
3322
|
}
|
|
3253
3323
|
|
|
3254
3324
|
// src/writers/staging.ts
|
|
3255
3325
|
init_constants();
|
|
3256
|
-
import
|
|
3257
|
-
import
|
|
3258
|
-
var STAGED_DIR =
|
|
3259
|
-
var PROPOSED_DIR =
|
|
3260
|
-
var CURRENT_DIR =
|
|
3326
|
+
import fs14 from "fs";
|
|
3327
|
+
import path12 from "path";
|
|
3328
|
+
var STAGED_DIR = path12.join(CALIBER_DIR, "staged");
|
|
3329
|
+
var PROPOSED_DIR = path12.join(STAGED_DIR, "proposed");
|
|
3330
|
+
var CURRENT_DIR = path12.join(STAGED_DIR, "current");
|
|
3261
3331
|
function normalizeContent(content) {
|
|
3262
3332
|
return content.split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
3263
3333
|
}
|
|
@@ -3267,20 +3337,20 @@ function stageFiles(files, projectDir) {
|
|
|
3267
3337
|
let modifiedFiles = 0;
|
|
3268
3338
|
const stagedFiles = [];
|
|
3269
3339
|
for (const file of files) {
|
|
3270
|
-
const originalPath =
|
|
3271
|
-
if (
|
|
3272
|
-
const existing =
|
|
3340
|
+
const originalPath = path12.join(projectDir, file.path);
|
|
3341
|
+
if (fs14.existsSync(originalPath)) {
|
|
3342
|
+
const existing = fs14.readFileSync(originalPath, "utf-8");
|
|
3273
3343
|
if (normalizeContent(existing) === normalizeContent(file.content)) {
|
|
3274
3344
|
continue;
|
|
3275
3345
|
}
|
|
3276
3346
|
}
|
|
3277
|
-
const proposedPath =
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
if (
|
|
3281
|
-
const currentPath =
|
|
3282
|
-
|
|
3283
|
-
|
|
3347
|
+
const proposedPath = path12.join(PROPOSED_DIR, file.path);
|
|
3348
|
+
fs14.mkdirSync(path12.dirname(proposedPath), { recursive: true });
|
|
3349
|
+
fs14.writeFileSync(proposedPath, file.content);
|
|
3350
|
+
if (fs14.existsSync(originalPath)) {
|
|
3351
|
+
const currentPath = path12.join(CURRENT_DIR, file.path);
|
|
3352
|
+
fs14.mkdirSync(path12.dirname(currentPath), { recursive: true });
|
|
3353
|
+
fs14.copyFileSync(originalPath, currentPath);
|
|
3284
3354
|
modifiedFiles++;
|
|
3285
3355
|
stagedFiles.push({ relativePath: file.path, proposedPath, currentPath, originalPath, isNew: false });
|
|
3286
3356
|
} else {
|
|
@@ -3291,34 +3361,34 @@ function stageFiles(files, projectDir) {
|
|
|
3291
3361
|
return { newFiles, modifiedFiles, stagedFiles };
|
|
3292
3362
|
}
|
|
3293
3363
|
function cleanupStaging() {
|
|
3294
|
-
if (
|
|
3295
|
-
|
|
3364
|
+
if (fs14.existsSync(STAGED_DIR)) {
|
|
3365
|
+
fs14.rmSync(STAGED_DIR, { recursive: true, force: true });
|
|
3296
3366
|
}
|
|
3297
3367
|
}
|
|
3298
3368
|
|
|
3299
3369
|
// src/utils/review.ts
|
|
3300
3370
|
import chalk2 from "chalk";
|
|
3301
|
-
import
|
|
3371
|
+
import fs16 from "fs";
|
|
3302
3372
|
import select2 from "@inquirer/select";
|
|
3303
3373
|
import { createTwoFilesPatch } from "diff";
|
|
3304
3374
|
|
|
3305
3375
|
// src/utils/editor.ts
|
|
3306
|
-
import { execSync as
|
|
3307
|
-
import
|
|
3308
|
-
import
|
|
3376
|
+
import { execSync as execSync6, spawn as spawn3 } from "child_process";
|
|
3377
|
+
import fs15 from "fs";
|
|
3378
|
+
import path13 from "path";
|
|
3309
3379
|
import os4 from "os";
|
|
3310
3380
|
var IS_WINDOWS3 = process.platform === "win32";
|
|
3311
|
-
var DIFF_TEMP_DIR =
|
|
3381
|
+
var DIFF_TEMP_DIR = path13.join(os4.tmpdir(), "caliber-diff");
|
|
3312
3382
|
function getEmptyFilePath(proposedPath) {
|
|
3313
|
-
|
|
3314
|
-
const tempPath =
|
|
3315
|
-
|
|
3383
|
+
fs15.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
|
|
3384
|
+
const tempPath = path13.join(DIFF_TEMP_DIR, path13.basename(proposedPath));
|
|
3385
|
+
fs15.writeFileSync(tempPath, "");
|
|
3316
3386
|
return tempPath;
|
|
3317
3387
|
}
|
|
3318
3388
|
function commandExists(cmd) {
|
|
3319
3389
|
try {
|
|
3320
3390
|
const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
3321
|
-
|
|
3391
|
+
execSync6(check, { stdio: "ignore" });
|
|
3322
3392
|
return true;
|
|
3323
3393
|
} catch {
|
|
3324
3394
|
return false;
|
|
@@ -3383,8 +3453,8 @@ async function openReview(method, stagedFiles) {
|
|
|
3383
3453
|
return;
|
|
3384
3454
|
}
|
|
3385
3455
|
const fileInfos = stagedFiles.map((file) => {
|
|
3386
|
-
const proposed =
|
|
3387
|
-
const current = file.currentPath ?
|
|
3456
|
+
const proposed = fs16.readFileSync(file.proposedPath, "utf-8");
|
|
3457
|
+
const current = file.currentPath ? fs16.readFileSync(file.currentPath, "utf-8") : "";
|
|
3388
3458
|
const patch = createTwoFilesPatch(
|
|
3389
3459
|
file.isNew ? "/dev/null" : file.relativePath,
|
|
3390
3460
|
file.relativePath,
|
|
@@ -3547,7 +3617,7 @@ async function interactiveDiffExplorer(files) {
|
|
|
3547
3617
|
}
|
|
3548
3618
|
|
|
3549
3619
|
// src/commands/setup-files.ts
|
|
3550
|
-
import
|
|
3620
|
+
import fs17 from "fs";
|
|
3551
3621
|
function buildSkillContent(skill) {
|
|
3552
3622
|
const frontmatter = `---
|
|
3553
3623
|
name: ${skill.name}
|
|
@@ -3596,7 +3666,7 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
3596
3666
|
}
|
|
3597
3667
|
}
|
|
3598
3668
|
const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
|
|
3599
|
-
if (codexTargeted && !
|
|
3669
|
+
if (codexTargeted && !fs17.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
|
|
3600
3670
|
const agentRefs = [];
|
|
3601
3671
|
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
3602
3672
|
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
@@ -3613,13 +3683,13 @@ ${agentRefs.join(" ")}
|
|
|
3613
3683
|
}
|
|
3614
3684
|
|
|
3615
3685
|
// src/lib/hooks.ts
|
|
3616
|
-
import
|
|
3617
|
-
import
|
|
3618
|
-
import { execSync as
|
|
3686
|
+
import fs19 from "fs";
|
|
3687
|
+
import path14 from "path";
|
|
3688
|
+
import { execSync as execSync8 } from "child_process";
|
|
3619
3689
|
|
|
3620
3690
|
// src/lib/resolve-caliber.ts
|
|
3621
|
-
import
|
|
3622
|
-
import { execSync as
|
|
3691
|
+
import fs18 from "fs";
|
|
3692
|
+
import { execSync as execSync7 } from "child_process";
|
|
3623
3693
|
var _resolved = null;
|
|
3624
3694
|
function resolveCaliber() {
|
|
3625
3695
|
if (_resolved) return _resolved;
|
|
@@ -3630,7 +3700,7 @@ function resolveCaliber() {
|
|
|
3630
3700
|
}
|
|
3631
3701
|
try {
|
|
3632
3702
|
const whichCmd = process.platform === "win32" ? "where caliber" : "which caliber";
|
|
3633
|
-
const found =
|
|
3703
|
+
const found = execSync7(whichCmd, {
|
|
3634
3704
|
encoding: "utf-8",
|
|
3635
3705
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3636
3706
|
}).trim();
|
|
@@ -3641,7 +3711,7 @@ function resolveCaliber() {
|
|
|
3641
3711
|
} catch {
|
|
3642
3712
|
}
|
|
3643
3713
|
const binPath = process.argv[1];
|
|
3644
|
-
if (binPath &&
|
|
3714
|
+
if (binPath && fs18.existsSync(binPath)) {
|
|
3645
3715
|
_resolved = binPath;
|
|
3646
3716
|
return _resolved;
|
|
3647
3717
|
}
|
|
@@ -3657,24 +3727,24 @@ function isCaliberCommand(command, subcommandTail) {
|
|
|
3657
3727
|
}
|
|
3658
3728
|
|
|
3659
3729
|
// src/lib/hooks.ts
|
|
3660
|
-
var SETTINGS_PATH =
|
|
3730
|
+
var SETTINGS_PATH = path14.join(".claude", "settings.json");
|
|
3661
3731
|
var REFRESH_TAIL = "refresh --quiet";
|
|
3662
3732
|
var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
|
|
3663
3733
|
function getHookCommand() {
|
|
3664
3734
|
return `${resolveCaliber()} ${REFRESH_TAIL}`;
|
|
3665
3735
|
}
|
|
3666
3736
|
function readSettings() {
|
|
3667
|
-
if (!
|
|
3737
|
+
if (!fs19.existsSync(SETTINGS_PATH)) return {};
|
|
3668
3738
|
try {
|
|
3669
|
-
return JSON.parse(
|
|
3739
|
+
return JSON.parse(fs19.readFileSync(SETTINGS_PATH, "utf-8"));
|
|
3670
3740
|
} catch {
|
|
3671
3741
|
return {};
|
|
3672
3742
|
}
|
|
3673
3743
|
}
|
|
3674
3744
|
function writeSettings(settings) {
|
|
3675
|
-
const dir =
|
|
3676
|
-
if (!
|
|
3677
|
-
|
|
3745
|
+
const dir = path14.dirname(SETTINGS_PATH);
|
|
3746
|
+
if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
|
|
3747
|
+
fs19.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
3678
3748
|
}
|
|
3679
3749
|
function findHookIndex(sessionEnd) {
|
|
3680
3750
|
return sessionEnd.findIndex(
|
|
@@ -3736,20 +3806,20 @@ ${PRECOMMIT_END}`;
|
|
|
3736
3806
|
}
|
|
3737
3807
|
function getGitHooksDir() {
|
|
3738
3808
|
try {
|
|
3739
|
-
const gitDir =
|
|
3740
|
-
return
|
|
3809
|
+
const gitDir = execSync8("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3810
|
+
return path14.join(gitDir, "hooks");
|
|
3741
3811
|
} catch {
|
|
3742
3812
|
return null;
|
|
3743
3813
|
}
|
|
3744
3814
|
}
|
|
3745
3815
|
function getPreCommitPath() {
|
|
3746
3816
|
const hooksDir = getGitHooksDir();
|
|
3747
|
-
return hooksDir ?
|
|
3817
|
+
return hooksDir ? path14.join(hooksDir, "pre-commit") : null;
|
|
3748
3818
|
}
|
|
3749
3819
|
function isPreCommitHookInstalled() {
|
|
3750
3820
|
const hookPath = getPreCommitPath();
|
|
3751
|
-
if (!hookPath || !
|
|
3752
|
-
const content =
|
|
3821
|
+
if (!hookPath || !fs19.existsSync(hookPath)) return false;
|
|
3822
|
+
const content = fs19.readFileSync(hookPath, "utf-8");
|
|
3753
3823
|
return content.includes(PRECOMMIT_START);
|
|
3754
3824
|
}
|
|
3755
3825
|
function installPreCommitHook() {
|
|
@@ -3758,43 +3828,43 @@ function installPreCommitHook() {
|
|
|
3758
3828
|
}
|
|
3759
3829
|
const hookPath = getPreCommitPath();
|
|
3760
3830
|
if (!hookPath) return { installed: false, alreadyInstalled: false };
|
|
3761
|
-
const hooksDir =
|
|
3762
|
-
if (!
|
|
3831
|
+
const hooksDir = path14.dirname(hookPath);
|
|
3832
|
+
if (!fs19.existsSync(hooksDir)) fs19.mkdirSync(hooksDir, { recursive: true });
|
|
3763
3833
|
let content = "";
|
|
3764
|
-
if (
|
|
3765
|
-
content =
|
|
3834
|
+
if (fs19.existsSync(hookPath)) {
|
|
3835
|
+
content = fs19.readFileSync(hookPath, "utf-8");
|
|
3766
3836
|
if (!content.endsWith("\n")) content += "\n";
|
|
3767
3837
|
content += "\n" + getPrecommitBlock() + "\n";
|
|
3768
3838
|
} else {
|
|
3769
3839
|
content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
|
|
3770
3840
|
}
|
|
3771
|
-
|
|
3772
|
-
|
|
3841
|
+
fs19.writeFileSync(hookPath, content);
|
|
3842
|
+
fs19.chmodSync(hookPath, 493);
|
|
3773
3843
|
return { installed: true, alreadyInstalled: false };
|
|
3774
3844
|
}
|
|
3775
3845
|
function removePreCommitHook() {
|
|
3776
3846
|
const hookPath = getPreCommitPath();
|
|
3777
|
-
if (!hookPath || !
|
|
3847
|
+
if (!hookPath || !fs19.existsSync(hookPath)) {
|
|
3778
3848
|
return { removed: false, notFound: true };
|
|
3779
3849
|
}
|
|
3780
|
-
let content =
|
|
3850
|
+
let content = fs19.readFileSync(hookPath, "utf-8");
|
|
3781
3851
|
if (!content.includes(PRECOMMIT_START)) {
|
|
3782
3852
|
return { removed: false, notFound: true };
|
|
3783
3853
|
}
|
|
3784
3854
|
const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
|
|
3785
3855
|
content = content.replace(regex, "\n");
|
|
3786
3856
|
if (content.trim() === "#!/bin/sh" || content.trim() === "") {
|
|
3787
|
-
|
|
3857
|
+
fs19.unlinkSync(hookPath);
|
|
3788
3858
|
} else {
|
|
3789
|
-
|
|
3859
|
+
fs19.writeFileSync(hookPath, content);
|
|
3790
3860
|
}
|
|
3791
3861
|
return { removed: true, notFound: false };
|
|
3792
3862
|
}
|
|
3793
3863
|
|
|
3794
3864
|
// src/lib/learning-hooks.ts
|
|
3795
|
-
import
|
|
3796
|
-
import
|
|
3797
|
-
var SETTINGS_PATH2 =
|
|
3865
|
+
import fs20 from "fs";
|
|
3866
|
+
import path15 from "path";
|
|
3867
|
+
var SETTINGS_PATH2 = path15.join(".claude", "settings.json");
|
|
3798
3868
|
var HOOK_TAILS = [
|
|
3799
3869
|
{ event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
|
|
3800
3870
|
{ event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
|
|
@@ -3811,17 +3881,17 @@ function getHookConfigs() {
|
|
|
3811
3881
|
}));
|
|
3812
3882
|
}
|
|
3813
3883
|
function readSettings2() {
|
|
3814
|
-
if (!
|
|
3884
|
+
if (!fs20.existsSync(SETTINGS_PATH2)) return {};
|
|
3815
3885
|
try {
|
|
3816
|
-
return JSON.parse(
|
|
3886
|
+
return JSON.parse(fs20.readFileSync(SETTINGS_PATH2, "utf-8"));
|
|
3817
3887
|
} catch {
|
|
3818
3888
|
return {};
|
|
3819
3889
|
}
|
|
3820
3890
|
}
|
|
3821
3891
|
function writeSettings2(settings) {
|
|
3822
|
-
const dir =
|
|
3823
|
-
if (!
|
|
3824
|
-
|
|
3892
|
+
const dir = path15.dirname(SETTINGS_PATH2);
|
|
3893
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
3894
|
+
fs20.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
|
|
3825
3895
|
}
|
|
3826
3896
|
function hasLearningHook(matchers, tail) {
|
|
3827
3897
|
return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
|
|
@@ -3855,7 +3925,7 @@ function installLearningHooks() {
|
|
|
3855
3925
|
writeSettings2(settings);
|
|
3856
3926
|
return { installed: true, alreadyInstalled: false };
|
|
3857
3927
|
}
|
|
3858
|
-
var CURSOR_HOOKS_PATH =
|
|
3928
|
+
var CURSOR_HOOKS_PATH = path15.join(".cursor", "hooks.json");
|
|
3859
3929
|
var CURSOR_HOOK_EVENTS = [
|
|
3860
3930
|
{ event: "postToolUse", tail: "learn observe" },
|
|
3861
3931
|
{ event: "postToolUseFailure", tail: "learn observe --failure" },
|
|
@@ -3863,17 +3933,17 @@ var CURSOR_HOOK_EVENTS = [
|
|
|
3863
3933
|
{ event: "sessionEnd", tail: "learn finalize" }
|
|
3864
3934
|
];
|
|
3865
3935
|
function readCursorHooks() {
|
|
3866
|
-
if (!
|
|
3936
|
+
if (!fs20.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
|
|
3867
3937
|
try {
|
|
3868
|
-
return JSON.parse(
|
|
3938
|
+
return JSON.parse(fs20.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
|
|
3869
3939
|
} catch {
|
|
3870
3940
|
return { version: 1, hooks: {} };
|
|
3871
3941
|
}
|
|
3872
3942
|
}
|
|
3873
3943
|
function writeCursorHooks(config) {
|
|
3874
|
-
const dir =
|
|
3875
|
-
if (!
|
|
3876
|
-
|
|
3944
|
+
const dir = path15.dirname(CURSOR_HOOKS_PATH);
|
|
3945
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
3946
|
+
fs20.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
|
|
3877
3947
|
}
|
|
3878
3948
|
function hasCursorHook(entries, tail) {
|
|
3879
3949
|
return entries.some((e) => isCaliberCommand(e.command, tail));
|
|
@@ -3943,10 +4013,10 @@ function removeLearningHooks() {
|
|
|
3943
4013
|
|
|
3944
4014
|
// src/lib/state.ts
|
|
3945
4015
|
init_constants();
|
|
3946
|
-
import
|
|
3947
|
-
import
|
|
3948
|
-
import { execSync as
|
|
3949
|
-
var STATE_FILE =
|
|
4016
|
+
import fs21 from "fs";
|
|
4017
|
+
import path16 from "path";
|
|
4018
|
+
import { execSync as execSync9 } from "child_process";
|
|
4019
|
+
var STATE_FILE = path16.join(CALIBER_DIR, ".caliber-state.json");
|
|
3950
4020
|
function normalizeTargetAgent(value) {
|
|
3951
4021
|
if (Array.isArray(value)) return value;
|
|
3952
4022
|
if (typeof value === "string") {
|
|
@@ -3957,8 +4027,8 @@ function normalizeTargetAgent(value) {
|
|
|
3957
4027
|
}
|
|
3958
4028
|
function readState() {
|
|
3959
4029
|
try {
|
|
3960
|
-
if (!
|
|
3961
|
-
const raw = JSON.parse(
|
|
4030
|
+
if (!fs21.existsSync(STATE_FILE)) return null;
|
|
4031
|
+
const raw = JSON.parse(fs21.readFileSync(STATE_FILE, "utf-8"));
|
|
3962
4032
|
if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
|
|
3963
4033
|
return raw;
|
|
3964
4034
|
} catch {
|
|
@@ -3966,14 +4036,14 @@ function readState() {
|
|
|
3966
4036
|
}
|
|
3967
4037
|
}
|
|
3968
4038
|
function writeState(state) {
|
|
3969
|
-
if (!
|
|
3970
|
-
|
|
4039
|
+
if (!fs21.existsSync(CALIBER_DIR)) {
|
|
4040
|
+
fs21.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
3971
4041
|
}
|
|
3972
|
-
|
|
4042
|
+
fs21.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
3973
4043
|
}
|
|
3974
4044
|
function getCurrentHeadSha() {
|
|
3975
4045
|
try {
|
|
3976
|
-
return
|
|
4046
|
+
return execSync9("git rev-parse HEAD", {
|
|
3977
4047
|
encoding: "utf-8",
|
|
3978
4048
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3979
4049
|
}).trim();
|
|
@@ -4918,7 +4988,7 @@ function checkGrounding(dir) {
|
|
|
4918
4988
|
|
|
4919
4989
|
// src/scoring/checks/accuracy.ts
|
|
4920
4990
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
4921
|
-
import { execSync as
|
|
4991
|
+
import { execSync as execSync10 } from "child_process";
|
|
4922
4992
|
import { join as join5 } from "path";
|
|
4923
4993
|
function validateReferences(dir) {
|
|
4924
4994
|
const configContent = collectPrimaryConfigContent(dir);
|
|
@@ -4927,13 +4997,13 @@ function validateReferences(dir) {
|
|
|
4927
4997
|
}
|
|
4928
4998
|
function detectGitDrift(dir) {
|
|
4929
4999
|
try {
|
|
4930
|
-
|
|
5000
|
+
execSync10("git rev-parse --git-dir", { cwd: dir, stdio: ["pipe", "pipe", "pipe"] });
|
|
4931
5001
|
} catch {
|
|
4932
5002
|
return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: false };
|
|
4933
5003
|
}
|
|
4934
5004
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
|
|
4935
5005
|
try {
|
|
4936
|
-
const headTimestamp =
|
|
5006
|
+
const headTimestamp = execSync10(
|
|
4937
5007
|
"git log -1 --format=%ct HEAD",
|
|
4938
5008
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4939
5009
|
).trim();
|
|
@@ -4954,7 +5024,7 @@ function detectGitDrift(dir) {
|
|
|
4954
5024
|
let latestConfigCommitHash = null;
|
|
4955
5025
|
for (const file of configFiles) {
|
|
4956
5026
|
try {
|
|
4957
|
-
const hash =
|
|
5027
|
+
const hash = execSync10(
|
|
4958
5028
|
`git log -1 --format=%H -- "${file}"`,
|
|
4959
5029
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4960
5030
|
).trim();
|
|
@@ -4963,7 +5033,7 @@ function detectGitDrift(dir) {
|
|
|
4963
5033
|
latestConfigCommitHash = hash;
|
|
4964
5034
|
} else {
|
|
4965
5035
|
try {
|
|
4966
|
-
|
|
5036
|
+
execSync10(
|
|
4967
5037
|
`git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`,
|
|
4968
5038
|
{ cwd: dir, stdio: ["pipe", "pipe", "pipe"] }
|
|
4969
5039
|
);
|
|
@@ -4978,12 +5048,12 @@ function detectGitDrift(dir) {
|
|
|
4978
5048
|
return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: true };
|
|
4979
5049
|
}
|
|
4980
5050
|
try {
|
|
4981
|
-
const countStr =
|
|
5051
|
+
const countStr = execSync10(
|
|
4982
5052
|
`git rev-list --count ${latestConfigCommitHash}..HEAD`,
|
|
4983
5053
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4984
5054
|
).trim();
|
|
4985
5055
|
const commitsSince = parseInt(countStr, 10) || 0;
|
|
4986
|
-
const lastDate =
|
|
5056
|
+
const lastDate = execSync10(
|
|
4987
5057
|
`git log -1 --format=%ci ${latestConfigCommitHash}`,
|
|
4988
5058
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4989
5059
|
).trim();
|
|
@@ -5055,12 +5125,12 @@ function checkAccuracy(dir) {
|
|
|
5055
5125
|
|
|
5056
5126
|
// src/scoring/checks/freshness.ts
|
|
5057
5127
|
import { existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
5058
|
-
import { execSync as
|
|
5128
|
+
import { execSync as execSync11 } from "child_process";
|
|
5059
5129
|
import { join as join6 } from "path";
|
|
5060
5130
|
function getCommitsSinceConfigUpdate(dir) {
|
|
5061
5131
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
|
|
5062
5132
|
try {
|
|
5063
|
-
const headTimestamp =
|
|
5133
|
+
const headTimestamp = execSync11(
|
|
5064
5134
|
"git log -1 --format=%ct HEAD",
|
|
5065
5135
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
5066
5136
|
).trim();
|
|
@@ -5080,12 +5150,12 @@ function getCommitsSinceConfigUpdate(dir) {
|
|
|
5080
5150
|
}
|
|
5081
5151
|
for (const file of configFiles) {
|
|
5082
5152
|
try {
|
|
5083
|
-
const hash =
|
|
5153
|
+
const hash = execSync11(
|
|
5084
5154
|
`git log -1 --format=%H -- "${file}"`,
|
|
5085
5155
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
5086
5156
|
).trim();
|
|
5087
5157
|
if (hash) {
|
|
5088
|
-
const countStr =
|
|
5158
|
+
const countStr = execSync11(
|
|
5089
5159
|
`git rev-list --count ${hash}..HEAD`,
|
|
5090
5160
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
5091
5161
|
).trim();
|
|
@@ -5203,11 +5273,11 @@ function checkFreshness(dir) {
|
|
|
5203
5273
|
|
|
5204
5274
|
// src/scoring/checks/bonus.ts
|
|
5205
5275
|
import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
|
|
5206
|
-
import { execSync as
|
|
5276
|
+
import { execSync as execSync12 } from "child_process";
|
|
5207
5277
|
import { join as join7 } from "path";
|
|
5208
5278
|
function hasPreCommitHook(dir) {
|
|
5209
5279
|
try {
|
|
5210
|
-
const gitDir =
|
|
5280
|
+
const gitDir = execSync12("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
5211
5281
|
const hookPath = join7(gitDir, "hooks", "pre-commit");
|
|
5212
5282
|
const content = readFileOrNull2(hookPath);
|
|
5213
5283
|
return content ? content.includes("caliber") : false;
|
|
@@ -5321,22 +5391,22 @@ function checkBonus(dir) {
|
|
|
5321
5391
|
|
|
5322
5392
|
// src/scoring/dismissed.ts
|
|
5323
5393
|
init_constants();
|
|
5324
|
-
import
|
|
5325
|
-
import
|
|
5326
|
-
var DISMISSED_FILE =
|
|
5394
|
+
import fs22 from "fs";
|
|
5395
|
+
import path17 from "path";
|
|
5396
|
+
var DISMISSED_FILE = path17.join(CALIBER_DIR, "dismissed-checks.json");
|
|
5327
5397
|
function readDismissedChecks() {
|
|
5328
5398
|
try {
|
|
5329
|
-
if (!
|
|
5330
|
-
return JSON.parse(
|
|
5399
|
+
if (!fs22.existsSync(DISMISSED_FILE)) return [];
|
|
5400
|
+
return JSON.parse(fs22.readFileSync(DISMISSED_FILE, "utf-8"));
|
|
5331
5401
|
} catch {
|
|
5332
5402
|
return [];
|
|
5333
5403
|
}
|
|
5334
5404
|
}
|
|
5335
5405
|
function writeDismissedChecks(checks) {
|
|
5336
|
-
if (!
|
|
5337
|
-
|
|
5406
|
+
if (!fs22.existsSync(CALIBER_DIR)) {
|
|
5407
|
+
fs22.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
5338
5408
|
}
|
|
5339
|
-
|
|
5409
|
+
fs22.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
|
|
5340
5410
|
}
|
|
5341
5411
|
function getDismissedIds() {
|
|
5342
5412
|
return new Set(readDismissedChecks().map((c) => c.id));
|
|
@@ -5581,13 +5651,13 @@ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4,
|
|
|
5581
5651
|
import { join as join9, dirname as dirname2 } from "path";
|
|
5582
5652
|
|
|
5583
5653
|
// src/scanner/index.ts
|
|
5584
|
-
import
|
|
5585
|
-
import
|
|
5586
|
-
import
|
|
5654
|
+
import fs23 from "fs";
|
|
5655
|
+
import path18 from "path";
|
|
5656
|
+
import crypto3 from "crypto";
|
|
5587
5657
|
function scanLocalState(dir) {
|
|
5588
5658
|
const items = [];
|
|
5589
|
-
const claudeMdPath =
|
|
5590
|
-
if (
|
|
5659
|
+
const claudeMdPath = path18.join(dir, "CLAUDE.md");
|
|
5660
|
+
if (fs23.existsSync(claudeMdPath)) {
|
|
5591
5661
|
items.push({
|
|
5592
5662
|
type: "rule",
|
|
5593
5663
|
platform: "claude",
|
|
@@ -5596,10 +5666,10 @@ function scanLocalState(dir) {
|
|
|
5596
5666
|
path: claudeMdPath
|
|
5597
5667
|
});
|
|
5598
5668
|
}
|
|
5599
|
-
const skillsDir =
|
|
5600
|
-
if (
|
|
5601
|
-
for (const file of
|
|
5602
|
-
const filePath =
|
|
5669
|
+
const skillsDir = path18.join(dir, ".claude", "skills");
|
|
5670
|
+
if (fs23.existsSync(skillsDir)) {
|
|
5671
|
+
for (const file of fs23.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
|
|
5672
|
+
const filePath = path18.join(skillsDir, file);
|
|
5603
5673
|
items.push({
|
|
5604
5674
|
type: "skill",
|
|
5605
5675
|
platform: "claude",
|
|
@@ -5609,10 +5679,10 @@ function scanLocalState(dir) {
|
|
|
5609
5679
|
});
|
|
5610
5680
|
}
|
|
5611
5681
|
}
|
|
5612
|
-
const mcpJsonPath =
|
|
5613
|
-
if (
|
|
5682
|
+
const mcpJsonPath = path18.join(dir, ".mcp.json");
|
|
5683
|
+
if (fs23.existsSync(mcpJsonPath)) {
|
|
5614
5684
|
try {
|
|
5615
|
-
const mcpJson = JSON.parse(
|
|
5685
|
+
const mcpJson = JSON.parse(fs23.readFileSync(mcpJsonPath, "utf-8"));
|
|
5616
5686
|
if (mcpJson.mcpServers) {
|
|
5617
5687
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
5618
5688
|
items.push({
|
|
@@ -5627,8 +5697,8 @@ function scanLocalState(dir) {
|
|
|
5627
5697
|
} catch {
|
|
5628
5698
|
}
|
|
5629
5699
|
}
|
|
5630
|
-
const agentsMdPath =
|
|
5631
|
-
if (
|
|
5700
|
+
const agentsMdPath = path18.join(dir, "AGENTS.md");
|
|
5701
|
+
if (fs23.existsSync(agentsMdPath)) {
|
|
5632
5702
|
items.push({
|
|
5633
5703
|
type: "rule",
|
|
5634
5704
|
platform: "codex",
|
|
@@ -5637,12 +5707,12 @@ function scanLocalState(dir) {
|
|
|
5637
5707
|
path: agentsMdPath
|
|
5638
5708
|
});
|
|
5639
5709
|
}
|
|
5640
|
-
const codexSkillsDir =
|
|
5641
|
-
if (
|
|
5710
|
+
const codexSkillsDir = path18.join(dir, ".agents", "skills");
|
|
5711
|
+
if (fs23.existsSync(codexSkillsDir)) {
|
|
5642
5712
|
try {
|
|
5643
|
-
for (const name of
|
|
5644
|
-
const skillFile =
|
|
5645
|
-
if (
|
|
5713
|
+
for (const name of fs23.readdirSync(codexSkillsDir)) {
|
|
5714
|
+
const skillFile = path18.join(codexSkillsDir, name, "SKILL.md");
|
|
5715
|
+
if (fs23.existsSync(skillFile)) {
|
|
5646
5716
|
items.push({
|
|
5647
5717
|
type: "skill",
|
|
5648
5718
|
platform: "codex",
|
|
@@ -5655,8 +5725,8 @@ function scanLocalState(dir) {
|
|
|
5655
5725
|
} catch {
|
|
5656
5726
|
}
|
|
5657
5727
|
}
|
|
5658
|
-
const cursorrulesPath =
|
|
5659
|
-
if (
|
|
5728
|
+
const cursorrulesPath = path18.join(dir, ".cursorrules");
|
|
5729
|
+
if (fs23.existsSync(cursorrulesPath)) {
|
|
5660
5730
|
items.push({
|
|
5661
5731
|
type: "rule",
|
|
5662
5732
|
platform: "cursor",
|
|
@@ -5665,10 +5735,10 @@ function scanLocalState(dir) {
|
|
|
5665
5735
|
path: cursorrulesPath
|
|
5666
5736
|
});
|
|
5667
5737
|
}
|
|
5668
|
-
const cursorRulesDir =
|
|
5669
|
-
if (
|
|
5670
|
-
for (const file of
|
|
5671
|
-
const filePath =
|
|
5738
|
+
const cursorRulesDir = path18.join(dir, ".cursor", "rules");
|
|
5739
|
+
if (fs23.existsSync(cursorRulesDir)) {
|
|
5740
|
+
for (const file of fs23.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
|
|
5741
|
+
const filePath = path18.join(cursorRulesDir, file);
|
|
5672
5742
|
items.push({
|
|
5673
5743
|
type: "rule",
|
|
5674
5744
|
platform: "cursor",
|
|
@@ -5678,12 +5748,12 @@ function scanLocalState(dir) {
|
|
|
5678
5748
|
});
|
|
5679
5749
|
}
|
|
5680
5750
|
}
|
|
5681
|
-
const cursorSkillsDir =
|
|
5682
|
-
if (
|
|
5751
|
+
const cursorSkillsDir = path18.join(dir, ".cursor", "skills");
|
|
5752
|
+
if (fs23.existsSync(cursorSkillsDir)) {
|
|
5683
5753
|
try {
|
|
5684
|
-
for (const name of
|
|
5685
|
-
const skillFile =
|
|
5686
|
-
if (
|
|
5754
|
+
for (const name of fs23.readdirSync(cursorSkillsDir)) {
|
|
5755
|
+
const skillFile = path18.join(cursorSkillsDir, name, "SKILL.md");
|
|
5756
|
+
if (fs23.existsSync(skillFile)) {
|
|
5687
5757
|
items.push({
|
|
5688
5758
|
type: "skill",
|
|
5689
5759
|
platform: "cursor",
|
|
@@ -5696,10 +5766,10 @@ function scanLocalState(dir) {
|
|
|
5696
5766
|
} catch {
|
|
5697
5767
|
}
|
|
5698
5768
|
}
|
|
5699
|
-
const cursorMcpPath =
|
|
5700
|
-
if (
|
|
5769
|
+
const cursorMcpPath = path18.join(dir, ".cursor", "mcp.json");
|
|
5770
|
+
if (fs23.existsSync(cursorMcpPath)) {
|
|
5701
5771
|
try {
|
|
5702
|
-
const mcpJson = JSON.parse(
|
|
5772
|
+
const mcpJson = JSON.parse(fs23.readFileSync(cursorMcpPath, "utf-8"));
|
|
5703
5773
|
if (mcpJson.mcpServers) {
|
|
5704
5774
|
for (const name of Object.keys(mcpJson.mcpServers)) {
|
|
5705
5775
|
items.push({
|
|
@@ -5717,11 +5787,11 @@ function scanLocalState(dir) {
|
|
|
5717
5787
|
return items;
|
|
5718
5788
|
}
|
|
5719
5789
|
function hashFile(filePath) {
|
|
5720
|
-
const text =
|
|
5721
|
-
return
|
|
5790
|
+
const text = fs23.readFileSync(filePath, "utf-8");
|
|
5791
|
+
return crypto3.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
|
|
5722
5792
|
}
|
|
5723
5793
|
function hashJson(obj) {
|
|
5724
|
-
return
|
|
5794
|
+
return crypto3.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
|
|
5725
5795
|
}
|
|
5726
5796
|
|
|
5727
5797
|
// src/commands/recommend.ts
|
|
@@ -5732,40 +5802,40 @@ import { PostHog } from "posthog-node";
|
|
|
5732
5802
|
import chalk7 from "chalk";
|
|
5733
5803
|
|
|
5734
5804
|
// src/telemetry/config.ts
|
|
5735
|
-
import
|
|
5736
|
-
import
|
|
5805
|
+
import fs24 from "fs";
|
|
5806
|
+
import path19 from "path";
|
|
5737
5807
|
import os5 from "os";
|
|
5738
|
-
import
|
|
5739
|
-
import { execSync as
|
|
5740
|
-
var CONFIG_DIR2 =
|
|
5741
|
-
var CONFIG_FILE2 =
|
|
5808
|
+
import crypto4 from "crypto";
|
|
5809
|
+
import { execSync as execSync13 } from "child_process";
|
|
5810
|
+
var CONFIG_DIR2 = path19.join(os5.homedir(), ".caliber");
|
|
5811
|
+
var CONFIG_FILE2 = path19.join(CONFIG_DIR2, "config.json");
|
|
5742
5812
|
var runtimeDisabled = false;
|
|
5743
5813
|
function readConfig() {
|
|
5744
5814
|
try {
|
|
5745
|
-
if (!
|
|
5746
|
-
return JSON.parse(
|
|
5815
|
+
if (!fs24.existsSync(CONFIG_FILE2)) return {};
|
|
5816
|
+
return JSON.parse(fs24.readFileSync(CONFIG_FILE2, "utf-8"));
|
|
5747
5817
|
} catch {
|
|
5748
5818
|
return {};
|
|
5749
5819
|
}
|
|
5750
5820
|
}
|
|
5751
5821
|
function writeConfig(config) {
|
|
5752
|
-
if (!
|
|
5753
|
-
|
|
5822
|
+
if (!fs24.existsSync(CONFIG_DIR2)) {
|
|
5823
|
+
fs24.mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
5754
5824
|
}
|
|
5755
|
-
|
|
5825
|
+
fs24.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
5756
5826
|
}
|
|
5757
5827
|
function getMachineId() {
|
|
5758
5828
|
const config = readConfig();
|
|
5759
5829
|
if (config.machineId) return config.machineId;
|
|
5760
|
-
const machineId =
|
|
5830
|
+
const machineId = crypto4.randomUUID();
|
|
5761
5831
|
writeConfig({ ...config, machineId });
|
|
5762
5832
|
return machineId;
|
|
5763
5833
|
}
|
|
5764
5834
|
function getGitEmailHash() {
|
|
5765
5835
|
try {
|
|
5766
|
-
const email =
|
|
5836
|
+
const email = execSync13("git config user.email", { encoding: "utf-8" }).trim();
|
|
5767
5837
|
if (!email) return void 0;
|
|
5768
|
-
return
|
|
5838
|
+
return crypto4.createHash("sha256").update(email).digest("hex");
|
|
5769
5839
|
} catch {
|
|
5770
5840
|
return void 0;
|
|
5771
5841
|
}
|
|
@@ -6708,11 +6778,11 @@ function countIssuePoints(issues) {
|
|
|
6708
6778
|
}
|
|
6709
6779
|
async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
|
|
6710
6780
|
const existsCache = /* @__PURE__ */ new Map();
|
|
6711
|
-
const cachedExists = (
|
|
6712
|
-
const cached = existsCache.get(
|
|
6781
|
+
const cachedExists = (path30) => {
|
|
6782
|
+
const cached = existsCache.get(path30);
|
|
6713
6783
|
if (cached !== void 0) return cached;
|
|
6714
|
-
const result = existsSync9(
|
|
6715
|
-
existsCache.set(
|
|
6784
|
+
const result = existsSync9(path30);
|
|
6785
|
+
existsCache.set(path30, result);
|
|
6716
6786
|
return result;
|
|
6717
6787
|
};
|
|
6718
6788
|
const projectStructure = collectProjectStructure(dir);
|
|
@@ -6851,8 +6921,8 @@ async function runScoreRefineWithSpinner(setup, dir, sessionHistory) {
|
|
|
6851
6921
|
}
|
|
6852
6922
|
|
|
6853
6923
|
// src/lib/debug-report.ts
|
|
6854
|
-
import
|
|
6855
|
-
import
|
|
6924
|
+
import fs25 from "fs";
|
|
6925
|
+
import path20 from "path";
|
|
6856
6926
|
var DebugReport = class {
|
|
6857
6927
|
sections = [];
|
|
6858
6928
|
startTime;
|
|
@@ -6921,11 +6991,11 @@ var DebugReport = class {
|
|
|
6921
6991
|
lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
|
|
6922
6992
|
lines.push("");
|
|
6923
6993
|
}
|
|
6924
|
-
const dir =
|
|
6925
|
-
if (!
|
|
6926
|
-
|
|
6994
|
+
const dir = path20.dirname(outputPath);
|
|
6995
|
+
if (!fs25.existsSync(dir)) {
|
|
6996
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
6927
6997
|
}
|
|
6928
|
-
|
|
6998
|
+
fs25.writeFileSync(outputPath, lines.join("\n"));
|
|
6929
6999
|
}
|
|
6930
7000
|
};
|
|
6931
7001
|
function formatMs(ms) {
|
|
@@ -7050,9 +7120,17 @@ var ParallelTaskDisplay = class {
|
|
|
7050
7120
|
cachedCardLines = null;
|
|
7051
7121
|
cachedCardIndex = -1;
|
|
7052
7122
|
cachedCardCols = -1;
|
|
7123
|
+
cachedConnectors = null;
|
|
7053
7124
|
add(name, options) {
|
|
7054
7125
|
const index = this.tasks.length;
|
|
7055
|
-
this.tasks.push({
|
|
7126
|
+
this.tasks.push({
|
|
7127
|
+
name,
|
|
7128
|
+
status: "pending",
|
|
7129
|
+
message: "",
|
|
7130
|
+
depth: options?.depth ?? 0,
|
|
7131
|
+
pipelineLabel: options?.pipelineLabel,
|
|
7132
|
+
pipelineRow: options?.pipelineRow ?? 0
|
|
7133
|
+
});
|
|
7056
7134
|
return index;
|
|
7057
7135
|
}
|
|
7058
7136
|
start() {
|
|
@@ -7159,42 +7237,84 @@ var ParallelTaskDisplay = class {
|
|
|
7159
7237
|
const boundary = lastSpace > max * 0.5 ? lastSpace : max - 1;
|
|
7160
7238
|
return text.slice(0, boundary) + "\u2026";
|
|
7161
7239
|
}
|
|
7162
|
-
|
|
7163
|
-
const cols = process.stdout.columns || 80;
|
|
7164
|
-
const elapsed = task.startTime ? this.formatTime((task.endTime ?? Date.now()) - task.startTime) : "";
|
|
7165
|
-
const timeStr = elapsed ? ` ${chalk10.dim(elapsed)}` : "";
|
|
7166
|
-
const timePlain = elapsed ? ` ${elapsed}` : "";
|
|
7167
|
-
let icon;
|
|
7168
|
-
let nameStyle;
|
|
7169
|
-
let msgStyle;
|
|
7240
|
+
statusIcon(task) {
|
|
7170
7241
|
switch (task.status) {
|
|
7171
7242
|
case "pending":
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
icon = chalk10.cyan(SPINNER_FRAMES[this.spinnerFrame]);
|
|
7178
|
-
nameStyle = chalk10.white;
|
|
7179
|
-
msgStyle = chalk10.dim;
|
|
7180
|
-
break;
|
|
7243
|
+
return { char: "\u25CB", styled: chalk10.dim("\u25CB") };
|
|
7244
|
+
case "running": {
|
|
7245
|
+
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
|
7246
|
+
return { char: frame, styled: chalk10.cyan(frame) };
|
|
7247
|
+
}
|
|
7181
7248
|
case "done":
|
|
7182
|
-
|
|
7183
|
-
nameStyle = chalk10.white;
|
|
7184
|
-
msgStyle = chalk10.dim;
|
|
7185
|
-
break;
|
|
7249
|
+
return { char: "\u2713", styled: chalk10.green("\u2713") };
|
|
7186
7250
|
case "failed":
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
const
|
|
7193
|
-
|
|
7194
|
-
const
|
|
7251
|
+
return { char: "\u2717", styled: chalk10.red("\u2717") };
|
|
7252
|
+
}
|
|
7253
|
+
}
|
|
7254
|
+
renderPipelineHeader() {
|
|
7255
|
+
const mainTasks = this.tasks.filter((t) => t.pipelineLabel && t.pipelineRow === 0);
|
|
7256
|
+
const branchTasks = this.tasks.filter((t) => t.pipelineLabel && t.pipelineRow === 1);
|
|
7257
|
+
if (mainTasks.length === 0) return [];
|
|
7258
|
+
const arrow = " \u2192 ";
|
|
7259
|
+
const styledArrow = chalk10.dim(arrow);
|
|
7260
|
+
const renderNode = (t) => {
|
|
7261
|
+
const { char, styled: icon } = this.statusIcon(t);
|
|
7262
|
+
const label = t.pipelineLabel;
|
|
7263
|
+
const styledLabel = t.status === "pending" ? chalk10.dim(label) : label;
|
|
7264
|
+
return {
|
|
7265
|
+
plain: `[${char} ${label}]`,
|
|
7266
|
+
styled: chalk10.dim("[") + icon + " " + styledLabel + chalk10.dim("]")
|
|
7267
|
+
};
|
|
7268
|
+
};
|
|
7269
|
+
const mainNodes = mainTasks.map(renderNode);
|
|
7270
|
+
const mainLine = PREFIX + mainNodes.map((n) => n.styled).join(styledArrow);
|
|
7271
|
+
const lines = [mainLine];
|
|
7272
|
+
if (branchTasks.length > 0) {
|
|
7273
|
+
const firstNodePlainWidth = mainNodes[0].plain.length;
|
|
7274
|
+
const indent = " ".repeat(PREFIX.length + firstNodePlainWidth + arrow.length);
|
|
7275
|
+
const branchNodes = branchTasks.map(renderNode);
|
|
7276
|
+
const branchLine = indent + chalk10.dim("\u2198 ") + branchNodes.map((n) => n.styled).join(styledArrow) + chalk10.dim(" \u2197");
|
|
7277
|
+
lines.push(branchLine);
|
|
7278
|
+
}
|
|
7279
|
+
return lines;
|
|
7280
|
+
}
|
|
7281
|
+
hasSiblingAfter(startIdx, depth) {
|
|
7282
|
+
for (let i = startIdx; i < this.tasks.length; i++) {
|
|
7283
|
+
if (this.tasks[i].depth < depth) return false;
|
|
7284
|
+
if (this.tasks[i].depth === depth) return true;
|
|
7285
|
+
}
|
|
7286
|
+
return false;
|
|
7287
|
+
}
|
|
7288
|
+
getTreeConnector(index) {
|
|
7289
|
+
const task = this.tasks[index];
|
|
7290
|
+
if (task.depth === 0) return "";
|
|
7291
|
+
if (task.depth === 1) {
|
|
7292
|
+
return this.hasSiblingAfter(index + 1, 1) ? "\u251C\u2500 " : "\u2514\u2500 ";
|
|
7293
|
+
}
|
|
7294
|
+
if (task.depth === 2) {
|
|
7295
|
+
const pipe = this.hasSiblingAfter(index + 1, 1) ? "\u2502" : " ";
|
|
7296
|
+
return `${pipe} \u2514\u2500 `;
|
|
7297
|
+
}
|
|
7298
|
+
return " ".repeat(task.depth);
|
|
7299
|
+
}
|
|
7300
|
+
renderLine(task, index) {
|
|
7301
|
+
const cols = process.stdout.columns || 80;
|
|
7302
|
+
const elapsed = task.startTime ? this.formatTime((task.endTime ?? Date.now()) - task.startTime) : "";
|
|
7303
|
+
const timeStr = elapsed ? ` ${chalk10.dim(elapsed)}` : "";
|
|
7304
|
+
const timePlain = elapsed ? ` ${elapsed}` : "";
|
|
7305
|
+
const { styled: icon } = this.statusIcon(task);
|
|
7306
|
+
const nameStyle = task.status === "pending" ? chalk10.dim : chalk10.white;
|
|
7307
|
+
const msgStyle = task.status === "failed" ? chalk10.red : chalk10.dim;
|
|
7308
|
+
if (!this.cachedConnectors) {
|
|
7309
|
+
this.cachedConnectors = this.tasks.map((_, i) => this.getTreeConnector(i));
|
|
7310
|
+
}
|
|
7311
|
+
const connector = this.cachedConnectors[index];
|
|
7312
|
+
const connectorStyled = connector ? chalk10.dim(connector) : "";
|
|
7313
|
+
const paddedName = task.name.padEnd(Math.max(0, NAME_COL_WIDTH - connector.length));
|
|
7314
|
+
const usedByFixed = PREFIX.length + connector.length + 2 + NAME_COL_WIDTH + timePlain.length;
|
|
7195
7315
|
const msgMax = Math.max(cols - usedByFixed - 2, 10);
|
|
7196
7316
|
const msg = task.message ? this.smartTruncate(task.message, msgMax) : "";
|
|
7197
|
-
return `${PREFIX}${
|
|
7317
|
+
return `${PREFIX}${connectorStyled}${icon} ${nameStyle(paddedName)}${msg ? msgStyle(msg) : ""}${timeStr}`;
|
|
7198
7318
|
}
|
|
7199
7319
|
draw(initial) {
|
|
7200
7320
|
const { stdout } = process;
|
|
@@ -7202,7 +7322,15 @@ var ParallelTaskDisplay = class {
|
|
|
7202
7322
|
stdout.write(`\x1B[${this.lineCount}A`);
|
|
7203
7323
|
}
|
|
7204
7324
|
stdout.write("\x1B[0J");
|
|
7205
|
-
const
|
|
7325
|
+
const pipelineHeader = this.renderPipelineHeader();
|
|
7326
|
+
const taskLines = this.tasks.map((t, i) => this.renderLine(t, i));
|
|
7327
|
+
const lines = [];
|
|
7328
|
+
if (pipelineHeader.length > 0) {
|
|
7329
|
+
lines.push(...pipelineHeader);
|
|
7330
|
+
const cols = stdout.columns || 80;
|
|
7331
|
+
lines.push(PREFIX + chalk10.dim("\u2500".repeat(Math.min(cols - PREFIX.length * 2, 55))));
|
|
7332
|
+
}
|
|
7333
|
+
lines.push(...taskLines);
|
|
7206
7334
|
if (this.waitingEnabled && this.waitingCards.length > 0 && stdout.isTTY) {
|
|
7207
7335
|
const cols = stdout.columns || 80;
|
|
7208
7336
|
if (this.currentCard !== this.cachedCardIndex || cols !== this.cachedCardCols || !this.cachedCardLines) {
|
|
@@ -7353,21 +7481,20 @@ async function initCommand(options) {
|
|
|
7353
7481
|
let skillSearchResult = { results: [], contentMap: /* @__PURE__ */ new Map() };
|
|
7354
7482
|
let fingerprint;
|
|
7355
7483
|
const display = new ParallelTaskDisplay();
|
|
7356
|
-
const TASK_STACK = display.add("Detecting project stack");
|
|
7357
|
-
const TASK_CONFIG = display.add("Generating configs");
|
|
7358
|
-
const TASK_SKILLS_GEN = display.add("Generating skills", { depth:
|
|
7359
|
-
const TASK_SKILLS_SEARCH = wantsSkills ? display.add("Searching community skills") : -1;
|
|
7360
|
-
const TASK_SCORE_REFINE = display.add("Validating & refining setup");
|
|
7484
|
+
const TASK_STACK = display.add("Detecting project stack", { pipelineLabel: "Scan" });
|
|
7485
|
+
const TASK_CONFIG = display.add("Generating configs", { depth: 1, pipelineLabel: "Generate" });
|
|
7486
|
+
const TASK_SKILLS_GEN = display.add("Generating skills", { depth: 2, pipelineLabel: "Skills" });
|
|
7487
|
+
const TASK_SKILLS_SEARCH = wantsSkills ? display.add("Searching community skills", { depth: 1, pipelineLabel: "Search", pipelineRow: 1 }) : -1;
|
|
7488
|
+
const TASK_SCORE_REFINE = display.add("Validating & refining setup", { pipelineLabel: "Validate" });
|
|
7361
7489
|
display.start();
|
|
7362
7490
|
display.enableWaitingContent();
|
|
7363
7491
|
try {
|
|
7364
7492
|
display.update(TASK_STACK, "running");
|
|
7365
7493
|
fingerprint = await collectFingerprint(process.cwd());
|
|
7366
|
-
const
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
display.update(TASK_STACK, "done", stackSummary);
|
|
7494
|
+
const stackParts = [...fingerprint.languages, ...fingerprint.frameworks];
|
|
7495
|
+
const stackSummary = stackParts.join(", ") || "no languages";
|
|
7496
|
+
const largeRepoNote = fingerprint.fileTree.length > 5e3 ? ` (${fingerprint.fileTree.length.toLocaleString()} files, smart sampling active)` : "";
|
|
7497
|
+
display.update(TASK_STACK, "done", stackSummary + largeRepoNote);
|
|
7371
7498
|
trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
|
|
7372
7499
|
log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
|
|
7373
7500
|
if (report) {
|
|
@@ -7385,7 +7512,8 @@ async function initCommand(options) {
|
|
|
7385
7512
|
}
|
|
7386
7513
|
display.update(TASK_CONFIG, "running");
|
|
7387
7514
|
const generatePromise = (async () => {
|
|
7388
|
-
|
|
7515
|
+
let localBaseline = baselineScore;
|
|
7516
|
+
const failingForDismissal = localBaseline.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
7389
7517
|
if (failingForDismissal.length > 0) {
|
|
7390
7518
|
display.update(TASK_CONFIG, "running", "Evaluating baseline checks...");
|
|
7391
7519
|
try {
|
|
@@ -7395,7 +7523,7 @@ async function initCommand(options) {
|
|
|
7395
7523
|
const existingIds = new Set(existing.map((d) => d.id));
|
|
7396
7524
|
const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
|
|
7397
7525
|
writeDismissedChecks(merged);
|
|
7398
|
-
|
|
7526
|
+
localBaseline = computeLocalScore(process.cwd(), targetAgent);
|
|
7399
7527
|
}
|
|
7400
7528
|
} catch {
|
|
7401
7529
|
display.update(TASK_CONFIG, "running", "Skipped dismissal evaluation");
|
|
@@ -7404,11 +7532,11 @@ async function initCommand(options) {
|
|
|
7404
7532
|
let failingChecks;
|
|
7405
7533
|
let passingChecks;
|
|
7406
7534
|
let currentScore;
|
|
7407
|
-
if (hasExistingConfig &&
|
|
7408
|
-
const currentLlmFixable =
|
|
7535
|
+
if (hasExistingConfig && localBaseline.score >= 95 && !options.force) {
|
|
7536
|
+
const currentLlmFixable = localBaseline.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
|
|
7409
7537
|
failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
|
|
7410
|
-
passingChecks =
|
|
7411
|
-
currentScore =
|
|
7538
|
+
passingChecks = localBaseline.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
|
|
7539
|
+
currentScore = localBaseline.score;
|
|
7412
7540
|
}
|
|
7413
7541
|
if (report) {
|
|
7414
7542
|
const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
|
|
@@ -7602,7 +7730,7 @@ async function initCommand(options) {
|
|
|
7602
7730
|
}
|
|
7603
7731
|
const writeSpinner = ora3("Writing config files...").start();
|
|
7604
7732
|
try {
|
|
7605
|
-
if (targetAgent.includes("codex") && !
|
|
7733
|
+
if (targetAgent.includes("codex") && !fs26.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
7606
7734
|
const claude = generatedSetup.claude;
|
|
7607
7735
|
const cursor = generatedSetup.cursor;
|
|
7608
7736
|
const agentRefs = [];
|
|
@@ -7786,9 +7914,9 @@ ${agentRefs.join(" ")}
|
|
|
7786
7914
|
}
|
|
7787
7915
|
if (report) {
|
|
7788
7916
|
report.markStep("Finished");
|
|
7789
|
-
const reportPath =
|
|
7917
|
+
const reportPath = path21.join(process.cwd(), ".caliber", "debug-report.md");
|
|
7790
7918
|
report.write(reportPath);
|
|
7791
|
-
console.log(chalk11.dim(` Debug report written to ${
|
|
7919
|
+
console.log(chalk11.dim(` Debug report written to ${path21.relative(process.cwd(), reportPath)}
|
|
7792
7920
|
`));
|
|
7793
7921
|
}
|
|
7794
7922
|
}
|
|
@@ -7835,7 +7963,7 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
7835
7963
|
}
|
|
7836
7964
|
function summarizeSetup(action, setup) {
|
|
7837
7965
|
const descriptions = setup.fileDescriptions;
|
|
7838
|
-
const files = descriptions ? Object.entries(descriptions).map(([
|
|
7966
|
+
const files = descriptions ? Object.entries(descriptions).map(([path30, desc]) => ` ${path30}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
|
|
7839
7967
|
return `${action}. Files:
|
|
7840
7968
|
${files}`;
|
|
7841
7969
|
}
|
|
@@ -7969,7 +8097,7 @@ function printSetupSummary(setup) {
|
|
|
7969
8097
|
};
|
|
7970
8098
|
if (claude) {
|
|
7971
8099
|
if (claude.claudeMd) {
|
|
7972
|
-
const icon =
|
|
8100
|
+
const icon = fs26.existsSync("CLAUDE.md") ? chalk11.yellow("~") : chalk11.green("+");
|
|
7973
8101
|
const desc = getDescription("CLAUDE.md");
|
|
7974
8102
|
console.log(` ${icon} ${chalk11.bold("CLAUDE.md")}`);
|
|
7975
8103
|
if (desc) console.log(chalk11.dim(` ${desc}`));
|
|
@@ -7979,7 +8107,7 @@ function printSetupSummary(setup) {
|
|
|
7979
8107
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
7980
8108
|
for (const skill of skills) {
|
|
7981
8109
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
7982
|
-
const icon =
|
|
8110
|
+
const icon = fs26.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
|
|
7983
8111
|
const desc = getDescription(skillPath);
|
|
7984
8112
|
console.log(` ${icon} ${chalk11.bold(skillPath)}`);
|
|
7985
8113
|
console.log(chalk11.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -7990,7 +8118,7 @@ function printSetupSummary(setup) {
|
|
|
7990
8118
|
const codex = setup.codex;
|
|
7991
8119
|
if (codex) {
|
|
7992
8120
|
if (codex.agentsMd) {
|
|
7993
|
-
const icon =
|
|
8121
|
+
const icon = fs26.existsSync("AGENTS.md") ? chalk11.yellow("~") : chalk11.green("+");
|
|
7994
8122
|
const desc = getDescription("AGENTS.md");
|
|
7995
8123
|
console.log(` ${icon} ${chalk11.bold("AGENTS.md")}`);
|
|
7996
8124
|
if (desc) console.log(chalk11.dim(` ${desc}`));
|
|
@@ -8000,7 +8128,7 @@ function printSetupSummary(setup) {
|
|
|
8000
8128
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
8001
8129
|
for (const skill of codexSkills) {
|
|
8002
8130
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
8003
|
-
const icon =
|
|
8131
|
+
const icon = fs26.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
|
|
8004
8132
|
const desc = getDescription(skillPath);
|
|
8005
8133
|
console.log(` ${icon} ${chalk11.bold(skillPath)}`);
|
|
8006
8134
|
console.log(chalk11.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -8010,7 +8138,7 @@ function printSetupSummary(setup) {
|
|
|
8010
8138
|
}
|
|
8011
8139
|
if (cursor) {
|
|
8012
8140
|
if (cursor.cursorrules) {
|
|
8013
|
-
const icon =
|
|
8141
|
+
const icon = fs26.existsSync(".cursorrules") ? chalk11.yellow("~") : chalk11.green("+");
|
|
8014
8142
|
const desc = getDescription(".cursorrules");
|
|
8015
8143
|
console.log(` ${icon} ${chalk11.bold(".cursorrules")}`);
|
|
8016
8144
|
if (desc) console.log(chalk11.dim(` ${desc}`));
|
|
@@ -8020,7 +8148,7 @@ function printSetupSummary(setup) {
|
|
|
8020
8148
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
8021
8149
|
for (const skill of cursorSkills) {
|
|
8022
8150
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
8023
|
-
const icon =
|
|
8151
|
+
const icon = fs26.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
|
|
8024
8152
|
const desc = getDescription(skillPath);
|
|
8025
8153
|
console.log(` ${icon} ${chalk11.bold(skillPath)}`);
|
|
8026
8154
|
console.log(chalk11.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -8031,7 +8159,7 @@ function printSetupSummary(setup) {
|
|
|
8031
8159
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
8032
8160
|
for (const rule of rules) {
|
|
8033
8161
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
8034
|
-
const icon =
|
|
8162
|
+
const icon = fs26.existsSync(rulePath) ? chalk11.yellow("~") : chalk11.green("+");
|
|
8035
8163
|
const desc = getDescription(rulePath);
|
|
8036
8164
|
console.log(` ${icon} ${chalk11.bold(rulePath)}`);
|
|
8037
8165
|
if (desc) {
|
|
@@ -8095,8 +8223,8 @@ function ensurePermissions(fingerprint) {
|
|
|
8095
8223
|
const settingsPath = ".claude/settings.json";
|
|
8096
8224
|
let settings = {};
|
|
8097
8225
|
try {
|
|
8098
|
-
if (
|
|
8099
|
-
settings = JSON.parse(
|
|
8226
|
+
if (fs26.existsSync(settingsPath)) {
|
|
8227
|
+
settings = JSON.parse(fs26.readFileSync(settingsPath, "utf-8"));
|
|
8100
8228
|
}
|
|
8101
8229
|
} catch {
|
|
8102
8230
|
}
|
|
@@ -8105,8 +8233,8 @@ function ensurePermissions(fingerprint) {
|
|
|
8105
8233
|
if (Array.isArray(allow) && allow.length > 0) return;
|
|
8106
8234
|
permissions.allow = derivePermissions(fingerprint);
|
|
8107
8235
|
settings.permissions = permissions;
|
|
8108
|
-
if (!
|
|
8109
|
-
|
|
8236
|
+
if (!fs26.existsSync(".claude")) fs26.mkdirSync(".claude", { recursive: true });
|
|
8237
|
+
fs26.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
8110
8238
|
}
|
|
8111
8239
|
function displayTokenUsage() {
|
|
8112
8240
|
const summary = getUsageSummary();
|
|
@@ -8130,7 +8258,7 @@ function displayTokenUsage() {
|
|
|
8130
8258
|
}
|
|
8131
8259
|
function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
8132
8260
|
try {
|
|
8133
|
-
const logPath =
|
|
8261
|
+
const logPath = path21.join(process.cwd(), ".caliber", "error-log.md");
|
|
8134
8262
|
const lines = [
|
|
8135
8263
|
`# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
8136
8264
|
"",
|
|
@@ -8143,8 +8271,8 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
|
8143
8271
|
lines.push("## Error", "```", error, "```", "");
|
|
8144
8272
|
}
|
|
8145
8273
|
lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
|
|
8146
|
-
|
|
8147
|
-
|
|
8274
|
+
fs26.mkdirSync(path21.join(process.cwd(), ".caliber"), { recursive: true });
|
|
8275
|
+
fs26.writeFileSync(logPath, lines.join("\n"));
|
|
8148
8276
|
console.log(chalk11.dim(`
|
|
8149
8277
|
Error log written to .caliber/error-log.md`));
|
|
8150
8278
|
} catch {
|
|
@@ -8185,7 +8313,7 @@ function undoCommand() {
|
|
|
8185
8313
|
|
|
8186
8314
|
// src/commands/status.ts
|
|
8187
8315
|
import chalk13 from "chalk";
|
|
8188
|
-
import
|
|
8316
|
+
import fs27 from "fs";
|
|
8189
8317
|
init_config();
|
|
8190
8318
|
async function statusCommand(options) {
|
|
8191
8319
|
const config = loadConfig();
|
|
@@ -8212,7 +8340,7 @@ async function statusCommand(options) {
|
|
|
8212
8340
|
}
|
|
8213
8341
|
console.log(` Files managed: ${chalk13.cyan(manifest.entries.length.toString())}`);
|
|
8214
8342
|
for (const entry of manifest.entries) {
|
|
8215
|
-
const exists =
|
|
8343
|
+
const exists = fs27.existsSync(entry.path);
|
|
8216
8344
|
const icon = exists ? chalk13.green("\u2713") : chalk13.red("\u2717");
|
|
8217
8345
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
8218
8346
|
}
|
|
@@ -8394,13 +8522,13 @@ async function scoreCommand(options) {
|
|
|
8394
8522
|
}
|
|
8395
8523
|
|
|
8396
8524
|
// src/commands/refresh.ts
|
|
8397
|
-
import
|
|
8398
|
-
import
|
|
8525
|
+
import fs31 from "fs";
|
|
8526
|
+
import path25 from "path";
|
|
8399
8527
|
import chalk16 from "chalk";
|
|
8400
8528
|
import ora6 from "ora";
|
|
8401
8529
|
|
|
8402
8530
|
// src/lib/git-diff.ts
|
|
8403
|
-
import { execSync as
|
|
8531
|
+
import { execSync as execSync14 } from "child_process";
|
|
8404
8532
|
var MAX_DIFF_BYTES = 1e5;
|
|
8405
8533
|
var DOC_PATTERNS = [
|
|
8406
8534
|
"CLAUDE.md",
|
|
@@ -8415,7 +8543,7 @@ function excludeArgs() {
|
|
|
8415
8543
|
}
|
|
8416
8544
|
function safeExec(cmd) {
|
|
8417
8545
|
try {
|
|
8418
|
-
return
|
|
8546
|
+
return execSync14(cmd, {
|
|
8419
8547
|
encoding: "utf-8",
|
|
8420
8548
|
stdio: ["pipe", "pipe", "pipe"],
|
|
8421
8549
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -8473,37 +8601,37 @@ function collectDiff(lastSha) {
|
|
|
8473
8601
|
}
|
|
8474
8602
|
|
|
8475
8603
|
// src/writers/refresh.ts
|
|
8476
|
-
import
|
|
8477
|
-
import
|
|
8604
|
+
import fs28 from "fs";
|
|
8605
|
+
import path22 from "path";
|
|
8478
8606
|
function writeRefreshDocs(docs) {
|
|
8479
8607
|
const written = [];
|
|
8480
8608
|
if (docs.claudeMd) {
|
|
8481
|
-
|
|
8609
|
+
fs28.writeFileSync("CLAUDE.md", docs.claudeMd);
|
|
8482
8610
|
written.push("CLAUDE.md");
|
|
8483
8611
|
}
|
|
8484
8612
|
if (docs.readmeMd) {
|
|
8485
|
-
|
|
8613
|
+
fs28.writeFileSync("README.md", docs.readmeMd);
|
|
8486
8614
|
written.push("README.md");
|
|
8487
8615
|
}
|
|
8488
8616
|
if (docs.cursorrules) {
|
|
8489
|
-
|
|
8617
|
+
fs28.writeFileSync(".cursorrules", docs.cursorrules);
|
|
8490
8618
|
written.push(".cursorrules");
|
|
8491
8619
|
}
|
|
8492
8620
|
if (docs.cursorRules) {
|
|
8493
|
-
const rulesDir =
|
|
8494
|
-
if (!
|
|
8621
|
+
const rulesDir = path22.join(".cursor", "rules");
|
|
8622
|
+
if (!fs28.existsSync(rulesDir)) fs28.mkdirSync(rulesDir, { recursive: true });
|
|
8495
8623
|
for (const rule of docs.cursorRules) {
|
|
8496
|
-
const filePath =
|
|
8497
|
-
|
|
8624
|
+
const filePath = path22.join(rulesDir, rule.filename);
|
|
8625
|
+
fs28.writeFileSync(filePath, rule.content);
|
|
8498
8626
|
written.push(filePath);
|
|
8499
8627
|
}
|
|
8500
8628
|
}
|
|
8501
8629
|
if (docs.claudeSkills) {
|
|
8502
|
-
const skillsDir =
|
|
8503
|
-
if (!
|
|
8630
|
+
const skillsDir = path22.join(".claude", "skills");
|
|
8631
|
+
if (!fs28.existsSync(skillsDir)) fs28.mkdirSync(skillsDir, { recursive: true });
|
|
8504
8632
|
for (const skill of docs.claudeSkills) {
|
|
8505
|
-
const filePath =
|
|
8506
|
-
|
|
8633
|
+
const filePath = path22.join(skillsDir, skill.filename);
|
|
8634
|
+
fs28.writeFileSync(filePath, skill.content);
|
|
8507
8635
|
written.push(filePath);
|
|
8508
8636
|
}
|
|
8509
8637
|
}
|
|
@@ -8580,8 +8708,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
8580
8708
|
}
|
|
8581
8709
|
|
|
8582
8710
|
// src/learner/writer.ts
|
|
8583
|
-
import
|
|
8584
|
-
import
|
|
8711
|
+
import fs29 from "fs";
|
|
8712
|
+
import path23 from "path";
|
|
8585
8713
|
var LEARNINGS_FILE = "CALIBER_LEARNINGS.md";
|
|
8586
8714
|
var LEARNINGS_HEADER = `# Caliber Learnings
|
|
8587
8715
|
|
|
@@ -8665,16 +8793,16 @@ function deduplicateLearnedItems(existing, incoming) {
|
|
|
8665
8793
|
function writeLearnedSection(content) {
|
|
8666
8794
|
const existingSection = readLearnedSection();
|
|
8667
8795
|
const { merged, newCount, newItems } = deduplicateLearnedItems(existingSection, content);
|
|
8668
|
-
|
|
8796
|
+
fs29.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
|
|
8669
8797
|
return { newCount, newItems };
|
|
8670
8798
|
}
|
|
8671
8799
|
function writeLearnedSkill(skill) {
|
|
8672
|
-
const skillDir =
|
|
8673
|
-
if (!
|
|
8674
|
-
const skillPath =
|
|
8675
|
-
if (!skill.isNew &&
|
|
8676
|
-
const existing =
|
|
8677
|
-
|
|
8800
|
+
const skillDir = path23.join(".claude", "skills", skill.name);
|
|
8801
|
+
if (!fs29.existsSync(skillDir)) fs29.mkdirSync(skillDir, { recursive: true });
|
|
8802
|
+
const skillPath = path23.join(skillDir, "SKILL.md");
|
|
8803
|
+
if (!skill.isNew && fs29.existsSync(skillPath)) {
|
|
8804
|
+
const existing = fs29.readFileSync(skillPath, "utf-8");
|
|
8805
|
+
fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
8678
8806
|
} else {
|
|
8679
8807
|
const frontmatter = [
|
|
8680
8808
|
"---",
|
|
@@ -8683,37 +8811,37 @@ function writeLearnedSkill(skill) {
|
|
|
8683
8811
|
"---",
|
|
8684
8812
|
""
|
|
8685
8813
|
].join("\n");
|
|
8686
|
-
|
|
8814
|
+
fs29.writeFileSync(skillPath, frontmatter + skill.content);
|
|
8687
8815
|
}
|
|
8688
8816
|
return skillPath;
|
|
8689
8817
|
}
|
|
8690
8818
|
function readLearnedSection() {
|
|
8691
|
-
if (
|
|
8692
|
-
const content2 =
|
|
8819
|
+
if (fs29.existsSync(LEARNINGS_FILE)) {
|
|
8820
|
+
const content2 = fs29.readFileSync(LEARNINGS_FILE, "utf-8");
|
|
8693
8821
|
const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
8694
8822
|
return bullets || null;
|
|
8695
8823
|
}
|
|
8696
8824
|
const claudeMdPath = "CLAUDE.md";
|
|
8697
|
-
if (!
|
|
8698
|
-
const content =
|
|
8825
|
+
if (!fs29.existsSync(claudeMdPath)) return null;
|
|
8826
|
+
const content = fs29.readFileSync(claudeMdPath, "utf-8");
|
|
8699
8827
|
const startIdx = content.indexOf(LEARNED_START);
|
|
8700
8828
|
const endIdx = content.indexOf(LEARNED_END);
|
|
8701
8829
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
8702
8830
|
return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
|
|
8703
8831
|
}
|
|
8704
8832
|
function migrateInlineLearnings() {
|
|
8705
|
-
if (
|
|
8833
|
+
if (fs29.existsSync(LEARNINGS_FILE)) return false;
|
|
8706
8834
|
const claudeMdPath = "CLAUDE.md";
|
|
8707
|
-
if (!
|
|
8708
|
-
const content =
|
|
8835
|
+
if (!fs29.existsSync(claudeMdPath)) return false;
|
|
8836
|
+
const content = fs29.readFileSync(claudeMdPath, "utf-8");
|
|
8709
8837
|
const startIdx = content.indexOf(LEARNED_START);
|
|
8710
8838
|
const endIdx = content.indexOf(LEARNED_END);
|
|
8711
8839
|
if (startIdx === -1 || endIdx === -1) return false;
|
|
8712
8840
|
const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
|
|
8713
8841
|
if (!section) return false;
|
|
8714
|
-
|
|
8842
|
+
fs29.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
|
|
8715
8843
|
const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
|
|
8716
|
-
|
|
8844
|
+
fs29.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
|
|
8717
8845
|
return true;
|
|
8718
8846
|
}
|
|
8719
8847
|
|
|
@@ -8725,11 +8853,11 @@ function log2(quiet, ...args) {
|
|
|
8725
8853
|
function discoverGitRepos(parentDir) {
|
|
8726
8854
|
const repos = [];
|
|
8727
8855
|
try {
|
|
8728
|
-
const entries =
|
|
8856
|
+
const entries = fs31.readdirSync(parentDir, { withFileTypes: true });
|
|
8729
8857
|
for (const entry of entries) {
|
|
8730
8858
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
8731
|
-
const childPath =
|
|
8732
|
-
if (
|
|
8859
|
+
const childPath = path25.join(parentDir, entry.name);
|
|
8860
|
+
if (fs31.existsSync(path25.join(childPath, ".git"))) {
|
|
8733
8861
|
repos.push(childPath);
|
|
8734
8862
|
}
|
|
8735
8863
|
}
|
|
@@ -8832,7 +8960,7 @@ async function refreshCommand(options) {
|
|
|
8832
8960
|
`));
|
|
8833
8961
|
const originalDir = process.cwd();
|
|
8834
8962
|
for (const repo of repos) {
|
|
8835
|
-
const repoName =
|
|
8963
|
+
const repoName = path25.basename(repo);
|
|
8836
8964
|
try {
|
|
8837
8965
|
process.chdir(repo);
|
|
8838
8966
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
@@ -9056,7 +9184,7 @@ async function configCommand() {
|
|
|
9056
9184
|
}
|
|
9057
9185
|
|
|
9058
9186
|
// src/commands/learn.ts
|
|
9059
|
-
import
|
|
9187
|
+
import fs34 from "fs";
|
|
9060
9188
|
import chalk19 from "chalk";
|
|
9061
9189
|
|
|
9062
9190
|
// src/learner/stdin.ts
|
|
@@ -9088,8 +9216,8 @@ function readStdin() {
|
|
|
9088
9216
|
|
|
9089
9217
|
// src/learner/storage.ts
|
|
9090
9218
|
init_constants();
|
|
9091
|
-
import
|
|
9092
|
-
import
|
|
9219
|
+
import fs32 from "fs";
|
|
9220
|
+
import path26 from "path";
|
|
9093
9221
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
9094
9222
|
var DEFAULT_STATE = {
|
|
9095
9223
|
sessionId: null,
|
|
@@ -9097,15 +9225,15 @@ var DEFAULT_STATE = {
|
|
|
9097
9225
|
lastAnalysisTimestamp: null
|
|
9098
9226
|
};
|
|
9099
9227
|
function ensureLearningDir() {
|
|
9100
|
-
if (!
|
|
9101
|
-
|
|
9228
|
+
if (!fs32.existsSync(LEARNING_DIR)) {
|
|
9229
|
+
fs32.mkdirSync(LEARNING_DIR, { recursive: true });
|
|
9102
9230
|
}
|
|
9103
9231
|
}
|
|
9104
9232
|
function sessionFilePath() {
|
|
9105
|
-
return
|
|
9233
|
+
return path26.join(LEARNING_DIR, LEARNING_SESSION_FILE);
|
|
9106
9234
|
}
|
|
9107
9235
|
function stateFilePath() {
|
|
9108
|
-
return
|
|
9236
|
+
return path26.join(LEARNING_DIR, LEARNING_STATE_FILE);
|
|
9109
9237
|
}
|
|
9110
9238
|
function truncateResponse(response) {
|
|
9111
9239
|
const str = JSON.stringify(response);
|
|
@@ -9116,29 +9244,29 @@ function appendEvent(event) {
|
|
|
9116
9244
|
ensureLearningDir();
|
|
9117
9245
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
9118
9246
|
const filePath = sessionFilePath();
|
|
9119
|
-
|
|
9247
|
+
fs32.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
9120
9248
|
const count = getEventCount();
|
|
9121
9249
|
if (count > LEARNING_MAX_EVENTS) {
|
|
9122
|
-
const lines =
|
|
9250
|
+
const lines = fs32.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
9123
9251
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
9124
|
-
|
|
9252
|
+
fs32.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
9125
9253
|
}
|
|
9126
9254
|
}
|
|
9127
9255
|
function appendPromptEvent(event) {
|
|
9128
9256
|
ensureLearningDir();
|
|
9129
9257
|
const filePath = sessionFilePath();
|
|
9130
|
-
|
|
9258
|
+
fs32.appendFileSync(filePath, JSON.stringify(event) + "\n");
|
|
9131
9259
|
const count = getEventCount();
|
|
9132
9260
|
if (count > LEARNING_MAX_EVENTS) {
|
|
9133
|
-
const lines =
|
|
9261
|
+
const lines = fs32.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
9134
9262
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
9135
|
-
|
|
9263
|
+
fs32.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
9136
9264
|
}
|
|
9137
9265
|
}
|
|
9138
9266
|
function readAllEvents() {
|
|
9139
9267
|
const filePath = sessionFilePath();
|
|
9140
|
-
if (!
|
|
9141
|
-
const lines =
|
|
9268
|
+
if (!fs32.existsSync(filePath)) return [];
|
|
9269
|
+
const lines = fs32.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
9142
9270
|
const events = [];
|
|
9143
9271
|
for (const line of lines) {
|
|
9144
9272
|
try {
|
|
@@ -9150,26 +9278,26 @@ function readAllEvents() {
|
|
|
9150
9278
|
}
|
|
9151
9279
|
function getEventCount() {
|
|
9152
9280
|
const filePath = sessionFilePath();
|
|
9153
|
-
if (!
|
|
9154
|
-
const content =
|
|
9281
|
+
if (!fs32.existsSync(filePath)) return 0;
|
|
9282
|
+
const content = fs32.readFileSync(filePath, "utf-8");
|
|
9155
9283
|
return content.split("\n").filter(Boolean).length;
|
|
9156
9284
|
}
|
|
9157
9285
|
function clearSession() {
|
|
9158
9286
|
const filePath = sessionFilePath();
|
|
9159
|
-
if (
|
|
9287
|
+
if (fs32.existsSync(filePath)) fs32.unlinkSync(filePath);
|
|
9160
9288
|
}
|
|
9161
9289
|
function readState2() {
|
|
9162
9290
|
const filePath = stateFilePath();
|
|
9163
|
-
if (!
|
|
9291
|
+
if (!fs32.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
9164
9292
|
try {
|
|
9165
|
-
return JSON.parse(
|
|
9293
|
+
return JSON.parse(fs32.readFileSync(filePath, "utf-8"));
|
|
9166
9294
|
} catch {
|
|
9167
9295
|
return { ...DEFAULT_STATE };
|
|
9168
9296
|
}
|
|
9169
9297
|
}
|
|
9170
9298
|
function writeState2(state) {
|
|
9171
9299
|
ensureLearningDir();
|
|
9172
|
-
|
|
9300
|
+
fs32.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
9173
9301
|
}
|
|
9174
9302
|
function resetState() {
|
|
9175
9303
|
writeState2({ ...DEFAULT_STATE });
|
|
@@ -9177,14 +9305,14 @@ function resetState() {
|
|
|
9177
9305
|
var LOCK_FILE2 = "finalize.lock";
|
|
9178
9306
|
var LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
9179
9307
|
function lockFilePath() {
|
|
9180
|
-
return
|
|
9308
|
+
return path26.join(LEARNING_DIR, LOCK_FILE2);
|
|
9181
9309
|
}
|
|
9182
9310
|
function acquireFinalizeLock() {
|
|
9183
9311
|
ensureLearningDir();
|
|
9184
9312
|
const lockPath = lockFilePath();
|
|
9185
|
-
if (
|
|
9313
|
+
if (fs32.existsSync(lockPath)) {
|
|
9186
9314
|
try {
|
|
9187
|
-
const stat =
|
|
9315
|
+
const stat = fs32.statSync(lockPath);
|
|
9188
9316
|
if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
|
|
9189
9317
|
return false;
|
|
9190
9318
|
}
|
|
@@ -9192,7 +9320,7 @@ function acquireFinalizeLock() {
|
|
|
9192
9320
|
}
|
|
9193
9321
|
}
|
|
9194
9322
|
try {
|
|
9195
|
-
|
|
9323
|
+
fs32.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
9196
9324
|
return true;
|
|
9197
9325
|
} catch {
|
|
9198
9326
|
return false;
|
|
@@ -9201,7 +9329,7 @@ function acquireFinalizeLock() {
|
|
|
9201
9329
|
function releaseFinalizeLock() {
|
|
9202
9330
|
const lockPath = lockFilePath();
|
|
9203
9331
|
try {
|
|
9204
|
-
if (
|
|
9332
|
+
if (fs32.existsSync(lockPath)) fs32.unlinkSync(lockPath);
|
|
9205
9333
|
} catch {
|
|
9206
9334
|
}
|
|
9207
9335
|
}
|
|
@@ -9247,7 +9375,7 @@ function sanitizeSecrets(text) {
|
|
|
9247
9375
|
|
|
9248
9376
|
// src/ai/learn.ts
|
|
9249
9377
|
init_config();
|
|
9250
|
-
var
|
|
9378
|
+
var MAX_PROMPT_TOKENS = 1e5;
|
|
9251
9379
|
function formatEventsForPrompt(events) {
|
|
9252
9380
|
return events.map((e, i) => {
|
|
9253
9381
|
if (e.hook_event_name === "UserPromptSubmit") {
|
|
@@ -9295,7 +9423,7 @@ function parseAnalysisResponse(raw) {
|
|
|
9295
9423
|
}
|
|
9296
9424
|
}
|
|
9297
9425
|
async function analyzeEvents(events, existingClaudeMd, existingLearnedSection, existingSkills) {
|
|
9298
|
-
const fittedEvents = trimEventsToFit(events,
|
|
9426
|
+
const fittedEvents = trimEventsToFit(events, MAX_PROMPT_TOKENS - 1e4);
|
|
9299
9427
|
const eventsText = formatEventsForPrompt(fittedEvents);
|
|
9300
9428
|
const contextParts = [];
|
|
9301
9429
|
if (existingClaudeMd) {
|
|
@@ -9357,8 +9485,8 @@ init_config();
|
|
|
9357
9485
|
|
|
9358
9486
|
// src/learner/roi.ts
|
|
9359
9487
|
init_constants();
|
|
9360
|
-
import
|
|
9361
|
-
import
|
|
9488
|
+
import fs33 from "fs";
|
|
9489
|
+
import path27 from "path";
|
|
9362
9490
|
var DEFAULT_TOTALS = {
|
|
9363
9491
|
totalWasteTokens: 0,
|
|
9364
9492
|
totalWasteSeconds: 0,
|
|
@@ -9372,22 +9500,22 @@ var DEFAULT_TOTALS = {
|
|
|
9372
9500
|
lastSessionTimestamp: ""
|
|
9373
9501
|
};
|
|
9374
9502
|
function roiFilePath() {
|
|
9375
|
-
return
|
|
9503
|
+
return path27.join(LEARNING_DIR, LEARNING_ROI_FILE);
|
|
9376
9504
|
}
|
|
9377
9505
|
function readROIStats() {
|
|
9378
9506
|
const filePath = roiFilePath();
|
|
9379
|
-
if (!
|
|
9507
|
+
if (!fs33.existsSync(filePath)) {
|
|
9380
9508
|
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
9381
9509
|
}
|
|
9382
9510
|
try {
|
|
9383
|
-
return JSON.parse(
|
|
9511
|
+
return JSON.parse(fs33.readFileSync(filePath, "utf-8"));
|
|
9384
9512
|
} catch {
|
|
9385
9513
|
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
9386
9514
|
}
|
|
9387
9515
|
}
|
|
9388
9516
|
function writeROIStats(stats) {
|
|
9389
9517
|
ensureLearningDir();
|
|
9390
|
-
|
|
9518
|
+
fs33.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
|
|
9391
9519
|
}
|
|
9392
9520
|
function recalculateTotals(stats) {
|
|
9393
9521
|
const totals = stats.totals;
|
|
@@ -9640,7 +9768,7 @@ async function learnFinalizeCommand(options) {
|
|
|
9640
9768
|
}
|
|
9641
9769
|
async function learnInstallCommand() {
|
|
9642
9770
|
let anyInstalled = false;
|
|
9643
|
-
if (
|
|
9771
|
+
if (fs34.existsSync(".claude")) {
|
|
9644
9772
|
const r = installLearningHooks();
|
|
9645
9773
|
if (r.installed) {
|
|
9646
9774
|
console.log(chalk19.green("\u2713") + " Claude Code learning hooks installed");
|
|
@@ -9649,7 +9777,7 @@ async function learnInstallCommand() {
|
|
|
9649
9777
|
console.log(chalk19.dim(" Claude Code hooks already installed"));
|
|
9650
9778
|
}
|
|
9651
9779
|
}
|
|
9652
|
-
if (
|
|
9780
|
+
if (fs34.existsSync(".cursor")) {
|
|
9653
9781
|
const r = installCursorLearningHooks();
|
|
9654
9782
|
if (r.installed) {
|
|
9655
9783
|
console.log(chalk19.green("\u2713") + " Cursor learning hooks installed");
|
|
@@ -9658,7 +9786,7 @@ async function learnInstallCommand() {
|
|
|
9658
9786
|
console.log(chalk19.dim(" Cursor hooks already installed"));
|
|
9659
9787
|
}
|
|
9660
9788
|
}
|
|
9661
|
-
if (!
|
|
9789
|
+
if (!fs34.existsSync(".claude") && !fs34.existsSync(".cursor")) {
|
|
9662
9790
|
console.log(chalk19.yellow("No .claude/ or .cursor/ directory found."));
|
|
9663
9791
|
console.log(chalk19.dim(" Run `caliber init` first, or create the directory manually."));
|
|
9664
9792
|
return;
|
|
@@ -9730,9 +9858,9 @@ Learned items in CALIBER_LEARNINGS.md: ${chalk19.cyan(String(lineCount))}`);
|
|
|
9730
9858
|
}
|
|
9731
9859
|
|
|
9732
9860
|
// src/cli.ts
|
|
9733
|
-
var __dirname =
|
|
9861
|
+
var __dirname = path28.dirname(fileURLToPath(import.meta.url));
|
|
9734
9862
|
var pkg = JSON.parse(
|
|
9735
|
-
|
|
9863
|
+
fs35.readFileSync(path28.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
9736
9864
|
);
|
|
9737
9865
|
var program = new Command();
|
|
9738
9866
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
@@ -9806,16 +9934,16 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
|
|
|
9806
9934
|
learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
|
|
9807
9935
|
|
|
9808
9936
|
// src/utils/version-check.ts
|
|
9809
|
-
import
|
|
9810
|
-
import
|
|
9937
|
+
import fs36 from "fs";
|
|
9938
|
+
import path29 from "path";
|
|
9811
9939
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9812
|
-
import { execSync as
|
|
9940
|
+
import { execSync as execSync15 } from "child_process";
|
|
9813
9941
|
import chalk20 from "chalk";
|
|
9814
9942
|
import ora7 from "ora";
|
|
9815
9943
|
import confirm2 from "@inquirer/confirm";
|
|
9816
|
-
var __dirname_vc =
|
|
9944
|
+
var __dirname_vc = path29.dirname(fileURLToPath2(import.meta.url));
|
|
9817
9945
|
var pkg2 = JSON.parse(
|
|
9818
|
-
|
|
9946
|
+
fs36.readFileSync(path29.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
9819
9947
|
);
|
|
9820
9948
|
function getChannel(version) {
|
|
9821
9949
|
const match = version.match(/-(dev|next)\./);
|
|
@@ -9839,9 +9967,9 @@ function isNewer(registry, current) {
|
|
|
9839
9967
|
}
|
|
9840
9968
|
function getInstalledVersion() {
|
|
9841
9969
|
try {
|
|
9842
|
-
const globalRoot =
|
|
9843
|
-
const pkgPath =
|
|
9844
|
-
return JSON.parse(
|
|
9970
|
+
const globalRoot = execSync15("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
9971
|
+
const pkgPath = path29.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
9972
|
+
return JSON.parse(fs36.readFileSync(pkgPath, "utf-8")).version;
|
|
9845
9973
|
} catch {
|
|
9846
9974
|
return null;
|
|
9847
9975
|
}
|
|
@@ -9887,7 +10015,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
9887
10015
|
const tag = channel === "latest" ? latest : channel;
|
|
9888
10016
|
const spinner = ora7("Updating caliber...").start();
|
|
9889
10017
|
try {
|
|
9890
|
-
|
|
10018
|
+
execSync15(`npm install -g @rely-ai/caliber@${tag}`, {
|
|
9891
10019
|
stdio: "pipe",
|
|
9892
10020
|
timeout: 12e4,
|
|
9893
10021
|
env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
|
|
@@ -9904,7 +10032,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
9904
10032
|
console.log(chalk20.dim(`
|
|
9905
10033
|
Restarting: caliber ${args.join(" ")}
|
|
9906
10034
|
`));
|
|
9907
|
-
|
|
10035
|
+
execSync15(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
9908
10036
|
stdio: "inherit",
|
|
9909
10037
|
env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
|
|
9910
10038
|
});
|