@rely-ai/caliber 1.20.0-dev.1773687255 → 1.20.0-dev.1773690658
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 +304 -35
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -149,13 +149,14 @@ __export(constants_exports, {
|
|
|
149
149
|
CALIBER_DIR: () => CALIBER_DIR,
|
|
150
150
|
LEARNING_DIR: () => LEARNING_DIR,
|
|
151
151
|
LEARNING_MAX_EVENTS: () => LEARNING_MAX_EVENTS,
|
|
152
|
+
LEARNING_ROI_FILE: () => LEARNING_ROI_FILE,
|
|
152
153
|
LEARNING_SESSION_FILE: () => LEARNING_SESSION_FILE,
|
|
153
154
|
LEARNING_STATE_FILE: () => LEARNING_STATE_FILE,
|
|
154
155
|
MANIFEST_FILE: () => MANIFEST_FILE
|
|
155
156
|
});
|
|
156
157
|
import path9 from "path";
|
|
157
158
|
import os2 from "os";
|
|
158
|
-
var AUTH_DIR, CALIBER_DIR, MANIFEST_FILE, BACKUPS_DIR, LEARNING_DIR, LEARNING_SESSION_FILE, LEARNING_STATE_FILE, LEARNING_MAX_EVENTS;
|
|
159
|
+
var AUTH_DIR, CALIBER_DIR, MANIFEST_FILE, BACKUPS_DIR, LEARNING_DIR, LEARNING_SESSION_FILE, LEARNING_STATE_FILE, LEARNING_MAX_EVENTS, LEARNING_ROI_FILE;
|
|
159
160
|
var init_constants = __esm({
|
|
160
161
|
"src/constants.ts"() {
|
|
161
162
|
"use strict";
|
|
@@ -167,6 +168,7 @@ var init_constants = __esm({
|
|
|
167
168
|
LEARNING_SESSION_FILE = "current-session.jsonl";
|
|
168
169
|
LEARNING_STATE_FILE = "state.json";
|
|
169
170
|
LEARNING_MAX_EVENTS = 500;
|
|
171
|
+
LEARNING_ROI_FILE = "roi-stats.json";
|
|
170
172
|
}
|
|
171
173
|
});
|
|
172
174
|
|
|
@@ -219,8 +221,8 @@ var init_lock = __esm({
|
|
|
219
221
|
|
|
220
222
|
// src/cli.ts
|
|
221
223
|
import { Command } from "commander";
|
|
222
|
-
import
|
|
223
|
-
import
|
|
224
|
+
import fs34 from "fs";
|
|
225
|
+
import path27 from "path";
|
|
224
226
|
import { fileURLToPath } from "url";
|
|
225
227
|
|
|
226
228
|
// src/commands/init.ts
|
|
@@ -2240,15 +2242,15 @@ init_config();
|
|
|
2240
2242
|
// src/utils/dependencies.ts
|
|
2241
2243
|
import { readFileSync } from "fs";
|
|
2242
2244
|
import { join } from "path";
|
|
2243
|
-
function readFileOrNull(
|
|
2245
|
+
function readFileOrNull(path29) {
|
|
2244
2246
|
try {
|
|
2245
|
-
return readFileSync(
|
|
2247
|
+
return readFileSync(path29, "utf-8");
|
|
2246
2248
|
} catch {
|
|
2247
2249
|
return null;
|
|
2248
2250
|
}
|
|
2249
2251
|
}
|
|
2250
|
-
function readJsonOrNull(
|
|
2251
|
-
const content = readFileOrNull(
|
|
2252
|
+
function readJsonOrNull(path29) {
|
|
2253
|
+
const content = readFileOrNull(path29);
|
|
2252
2254
|
if (!content) return null;
|
|
2253
2255
|
try {
|
|
2254
2256
|
return JSON.parse(content);
|
|
@@ -5329,12 +5331,12 @@ var AGENT_DISPLAY_NAMES = {
|
|
|
5329
5331
|
codex: "Codex"
|
|
5330
5332
|
};
|
|
5331
5333
|
var CATEGORY_LABELS = {
|
|
5332
|
-
existence: "FILES & SETUP",
|
|
5333
|
-
quality: "QUALITY",
|
|
5334
|
-
grounding: "GROUNDING",
|
|
5335
|
-
accuracy: "ACCURACY",
|
|
5336
|
-
freshness: "FRESHNESS & SAFETY",
|
|
5337
|
-
bonus: "BONUS"
|
|
5334
|
+
existence: { icon: "\u{1F4C1}", label: "FILES & SETUP" },
|
|
5335
|
+
quality: { icon: "\u26A1", label: "QUALITY" },
|
|
5336
|
+
grounding: { icon: "\u{1F3AF}", label: "GROUNDING" },
|
|
5337
|
+
accuracy: { icon: "\u{1F50D}", label: "ACCURACY" },
|
|
5338
|
+
freshness: { icon: "\u{1F6E1}\uFE0F", label: "FRESHNESS & SAFETY" },
|
|
5339
|
+
bonus: { icon: "\u2B50", label: "BONUS" }
|
|
5338
5340
|
};
|
|
5339
5341
|
var CATEGORY_ORDER = ["existence", "quality", "grounding", "accuracy", "freshness", "bonus"];
|
|
5340
5342
|
function gradeColor(grade) {
|
|
@@ -5353,20 +5355,51 @@ function gradeColor(grade) {
|
|
|
5353
5355
|
return chalk6.white;
|
|
5354
5356
|
}
|
|
5355
5357
|
}
|
|
5358
|
+
var GRADIENT_COLORS = ["#ef4444", "#f97316", "#eab308", "#22c55e"];
|
|
5356
5359
|
function progressBar(score, max, width = 40) {
|
|
5357
5360
|
const filled = Math.round(score / max * width);
|
|
5358
5361
|
const empty = width - filled;
|
|
5359
|
-
|
|
5362
|
+
let bar = "";
|
|
5363
|
+
for (let i = 0; i < filled; i++) {
|
|
5364
|
+
const position = i / (width - 1);
|
|
5365
|
+
const colorIndex = Math.min(
|
|
5366
|
+
GRADIENT_COLORS.length - 1,
|
|
5367
|
+
Math.floor(position * GRADIENT_COLORS.length)
|
|
5368
|
+
);
|
|
5369
|
+
bar += chalk6.hex(GRADIENT_COLORS[colorIndex])("\u2593");
|
|
5370
|
+
}
|
|
5371
|
+
bar += chalk6.gray("\u2591".repeat(empty));
|
|
5360
5372
|
return bar;
|
|
5361
5373
|
}
|
|
5362
5374
|
function formatCheck(check) {
|
|
5363
|
-
const
|
|
5364
|
-
const
|
|
5365
|
-
const
|
|
5375
|
+
const isPartial = !check.passed && check.earnedPoints > 0;
|
|
5376
|
+
const isNegative = check.earnedPoints < 0;
|
|
5377
|
+
const lostPoints = check.maxPoints - check.earnedPoints;
|
|
5378
|
+
const icon = check.passed ? chalk6.green("\u2713") : isPartial ? chalk6.yellow("~") : isNegative ? chalk6.red("\u2717") : chalk6.gray("\u2717");
|
|
5379
|
+
let points;
|
|
5380
|
+
if (check.passed) {
|
|
5381
|
+
points = chalk6.green(`+${check.earnedPoints}`.padStart(4));
|
|
5382
|
+
} else if (isNegative) {
|
|
5383
|
+
points = chalk6.red(`${check.earnedPoints}`.padStart(4));
|
|
5384
|
+
} else if (isPartial) {
|
|
5385
|
+
points = chalk6.yellow(`${check.earnedPoints}/${check.maxPoints}`.padStart(5));
|
|
5386
|
+
} else {
|
|
5387
|
+
points = chalk6.gray(`0/${check.maxPoints}`.padStart(5));
|
|
5388
|
+
}
|
|
5389
|
+
const name = check.passed ? chalk6.white(check.name) : isNegative ? chalk6.red(check.name) : isPartial ? chalk6.white(check.name) : chalk6.gray(check.name);
|
|
5366
5390
|
const detail = check.detail ? chalk6.gray(` (${check.detail})`) : "";
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5391
|
+
let suggestion = "";
|
|
5392
|
+
if (!check.passed && check.suggestion) {
|
|
5393
|
+
const suggColor = isNegative ? chalk6.red : chalk6.yellow;
|
|
5394
|
+
suggestion = suggColor(`
|
|
5395
|
+
\u2192 ${check.suggestion}`);
|
|
5396
|
+
}
|
|
5397
|
+
let recovery = "";
|
|
5398
|
+
if (isPartial && lostPoints > 0) {
|
|
5399
|
+
recovery = chalk6.yellow(`
|
|
5400
|
+
\u2191 Fix this for +${lostPoints} more points`);
|
|
5401
|
+
}
|
|
5402
|
+
return ` ${icon} ${name.padEnd(38)}${points}${detail}${suggestion}${recovery}`;
|
|
5370
5403
|
}
|
|
5371
5404
|
function displayScore(result) {
|
|
5372
5405
|
const gc = gradeColor(result.grade);
|
|
@@ -5383,14 +5416,32 @@ function displayScore(result) {
|
|
|
5383
5416
|
for (const category of CATEGORY_ORDER) {
|
|
5384
5417
|
const summary = result.categories[category];
|
|
5385
5418
|
const categoryChecks = result.checks.filter((c) => c.category === category);
|
|
5419
|
+
const { icon, label } = CATEGORY_LABELS[category];
|
|
5420
|
+
const gap = summary.max - summary.earned;
|
|
5421
|
+
const gapLabel = gap > 0 ? chalk6.yellow(` (-${gap} available)`) : "";
|
|
5386
5422
|
console.log(
|
|
5387
|
-
chalk6.gray(` ${
|
|
5423
|
+
chalk6.gray(` ${icon} ${label}`) + chalk6.gray(" ".repeat(Math.max(1, 43 - label.length))) + chalk6.white(`${summary.earned}`) + chalk6.gray(` / ${summary.max}`) + gapLabel
|
|
5388
5424
|
);
|
|
5389
5425
|
for (const check of categoryChecks) {
|
|
5390
5426
|
console.log(formatCheck(check));
|
|
5391
5427
|
}
|
|
5392
5428
|
console.log("");
|
|
5393
5429
|
}
|
|
5430
|
+
formatTopImprovements(result.checks);
|
|
5431
|
+
}
|
|
5432
|
+
function formatTopImprovements(checks) {
|
|
5433
|
+
const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({ name: c.name, potential: c.maxPoints - c.earnedPoints })).sort((a, b) => b.potential - a.potential).slice(0, 5);
|
|
5434
|
+
if (improvable.length === 0) return;
|
|
5435
|
+
console.log(chalk6.gray(" \u2500 TOP IMPROVEMENTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5436
|
+
console.log("");
|
|
5437
|
+
for (let i = 0; i < improvable.length; i++) {
|
|
5438
|
+
const item = improvable[i];
|
|
5439
|
+
const num = chalk6.gray(`${i + 1}.`);
|
|
5440
|
+
const label = chalk6.white(item.name.padEnd(42));
|
|
5441
|
+
const pts = chalk6.yellow(`+${item.potential} pts`);
|
|
5442
|
+
console.log(` ${num} ${label}${pts}`);
|
|
5443
|
+
}
|
|
5444
|
+
console.log("");
|
|
5394
5445
|
}
|
|
5395
5446
|
function displayScoreSummary(result) {
|
|
5396
5447
|
const gc = gradeColor(result.grade);
|
|
@@ -5757,6 +5808,36 @@ function trackSkillsInstalled(count) {
|
|
|
5757
5808
|
function trackUndoExecuted() {
|
|
5758
5809
|
trackEvent("undo_executed");
|
|
5759
5810
|
}
|
|
5811
|
+
function trackLearnSessionAnalyzed(props) {
|
|
5812
|
+
trackEvent("learn_session_analyzed", {
|
|
5813
|
+
event_count: props.eventCount,
|
|
5814
|
+
failure_count: props.failureCount,
|
|
5815
|
+
correction_count: props.correctionCount,
|
|
5816
|
+
had_learnings_available: props.hadLearningsAvailable,
|
|
5817
|
+
learnings_available_count: props.learningsAvailableCount,
|
|
5818
|
+
new_learnings_produced: props.newLearningsProduced,
|
|
5819
|
+
waste_tokens: props.wasteTokens
|
|
5820
|
+
});
|
|
5821
|
+
}
|
|
5822
|
+
function trackLearnROISnapshot(props) {
|
|
5823
|
+
trackEvent("learn_roi_snapshot", {
|
|
5824
|
+
total_waste_tokens: props.totalWasteTokens,
|
|
5825
|
+
total_sessions: props.totalSessions,
|
|
5826
|
+
sessions_with_learnings: props.sessionsWithLearnings,
|
|
5827
|
+
sessions_without_learnings: props.sessionsWithoutLearnings,
|
|
5828
|
+
failure_rate_with_learnings: props.failureRateWithLearnings,
|
|
5829
|
+
failure_rate_without_learnings: props.failureRateWithoutLearnings,
|
|
5830
|
+
estimated_savings_tokens: props.estimatedSavingsTokens,
|
|
5831
|
+
learning_count: props.learningCount
|
|
5832
|
+
});
|
|
5833
|
+
}
|
|
5834
|
+
function trackLearnNewLearning(props) {
|
|
5835
|
+
trackEvent("learn_new_learning", {
|
|
5836
|
+
observation_type: props.observationType,
|
|
5837
|
+
waste_tokens: props.wasteTokens,
|
|
5838
|
+
source_event_count: props.sourceEventCount
|
|
5839
|
+
});
|
|
5840
|
+
}
|
|
5760
5841
|
|
|
5761
5842
|
// src/commands/recommend.ts
|
|
5762
5843
|
function detectLocalPlatforms() {
|
|
@@ -7084,7 +7165,7 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
7084
7165
|
}
|
|
7085
7166
|
function summarizeSetup(action, setup) {
|
|
7086
7167
|
const descriptions = setup.fileDescriptions;
|
|
7087
|
-
const files = descriptions ? Object.entries(descriptions).map(([
|
|
7168
|
+
const files = descriptions ? Object.entries(descriptions).map(([path29, desc]) => ` ${path29}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
|
|
7088
7169
|
return `${action}. Files:
|
|
7089
7170
|
${files}`;
|
|
7090
7171
|
}
|
|
@@ -8285,7 +8366,7 @@ async function configCommand() {
|
|
|
8285
8366
|
}
|
|
8286
8367
|
|
|
8287
8368
|
// src/commands/learn.ts
|
|
8288
|
-
import
|
|
8369
|
+
import fs33 from "fs";
|
|
8289
8370
|
import chalk18 from "chalk";
|
|
8290
8371
|
|
|
8291
8372
|
// src/learner/stdin.ts
|
|
@@ -8555,9 +8636,124 @@ ${eventsText}`;
|
|
|
8555
8636
|
});
|
|
8556
8637
|
return parseAnalysisResponse(raw);
|
|
8557
8638
|
}
|
|
8639
|
+
function calculateSessionWaste(events) {
|
|
8640
|
+
let totalWasteTokens = 0;
|
|
8641
|
+
let failureCount = 0;
|
|
8642
|
+
let promptCount = 0;
|
|
8643
|
+
for (const event of events) {
|
|
8644
|
+
if (event.hook_event_name === "PostToolUseFailure") {
|
|
8645
|
+
const te = event;
|
|
8646
|
+
const inputStr = JSON.stringify(te.tool_input);
|
|
8647
|
+
const responseStr = typeof te.tool_response === "object" && "_truncated" in te.tool_response ? String(te.tool_response._truncated) : JSON.stringify(te.tool_response);
|
|
8648
|
+
totalWasteTokens += estimateTokens(inputStr + responseStr);
|
|
8649
|
+
failureCount++;
|
|
8650
|
+
} else if (event.hook_event_name === "UserPromptSubmit") {
|
|
8651
|
+
promptCount++;
|
|
8652
|
+
}
|
|
8653
|
+
}
|
|
8654
|
+
return { totalWasteTokens, failureCount, promptCount };
|
|
8655
|
+
}
|
|
8558
8656
|
|
|
8559
8657
|
// src/commands/learn.ts
|
|
8560
8658
|
init_config();
|
|
8659
|
+
|
|
8660
|
+
// src/learner/roi.ts
|
|
8661
|
+
init_constants();
|
|
8662
|
+
import fs32 from "fs";
|
|
8663
|
+
import path26 from "path";
|
|
8664
|
+
var DEFAULT_TOTALS = {
|
|
8665
|
+
totalWasteTokens: 0,
|
|
8666
|
+
totalSessionsWithLearnings: 0,
|
|
8667
|
+
totalSessionsWithoutLearnings: 0,
|
|
8668
|
+
totalFailuresWithLearnings: 0,
|
|
8669
|
+
totalFailuresWithoutLearnings: 0,
|
|
8670
|
+
estimatedSavingsTokens: 0,
|
|
8671
|
+
firstSessionTimestamp: "",
|
|
8672
|
+
lastSessionTimestamp: ""
|
|
8673
|
+
};
|
|
8674
|
+
function roiFilePath() {
|
|
8675
|
+
return path26.join(LEARNING_DIR, LEARNING_ROI_FILE);
|
|
8676
|
+
}
|
|
8677
|
+
function readROIStats() {
|
|
8678
|
+
const filePath = roiFilePath();
|
|
8679
|
+
if (!fs32.existsSync(filePath)) {
|
|
8680
|
+
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
8681
|
+
}
|
|
8682
|
+
try {
|
|
8683
|
+
return JSON.parse(fs32.readFileSync(filePath, "utf-8"));
|
|
8684
|
+
} catch {
|
|
8685
|
+
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
8686
|
+
}
|
|
8687
|
+
}
|
|
8688
|
+
function writeROIStats(stats) {
|
|
8689
|
+
ensureLearningDir();
|
|
8690
|
+
fs32.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
|
|
8691
|
+
}
|
|
8692
|
+
function recalculateTotals(stats) {
|
|
8693
|
+
const totals = stats.totals;
|
|
8694
|
+
totals.totalWasteTokens = stats.learnings.reduce((sum, l) => sum + l.wasteTokens, 0);
|
|
8695
|
+
totals.totalSessionsWithLearnings = 0;
|
|
8696
|
+
totals.totalSessionsWithoutLearnings = 0;
|
|
8697
|
+
totals.totalFailuresWithLearnings = 0;
|
|
8698
|
+
totals.totalFailuresWithoutLearnings = 0;
|
|
8699
|
+
for (const s of stats.sessions) {
|
|
8700
|
+
if (s.hadLearningsAvailable) {
|
|
8701
|
+
totals.totalSessionsWithLearnings++;
|
|
8702
|
+
totals.totalFailuresWithLearnings += s.failureCount;
|
|
8703
|
+
} else {
|
|
8704
|
+
totals.totalSessionsWithoutLearnings++;
|
|
8705
|
+
totals.totalFailuresWithoutLearnings += s.failureCount;
|
|
8706
|
+
}
|
|
8707
|
+
}
|
|
8708
|
+
totals.estimatedSavingsTokens = totals.totalWasteTokens * totals.totalSessionsWithLearnings;
|
|
8709
|
+
if (stats.sessions.length > 0) {
|
|
8710
|
+
totals.firstSessionTimestamp = stats.sessions[0].timestamp;
|
|
8711
|
+
totals.lastSessionTimestamp = stats.sessions[stats.sessions.length - 1].timestamp;
|
|
8712
|
+
}
|
|
8713
|
+
}
|
|
8714
|
+
var MAX_SESSIONS = 500;
|
|
8715
|
+
var MAX_LEARNINGS = 1e3;
|
|
8716
|
+
function recordSession(summary, learnings) {
|
|
8717
|
+
const stats = readROIStats();
|
|
8718
|
+
stats.sessions.push(summary);
|
|
8719
|
+
if (learnings?.length) {
|
|
8720
|
+
stats.learnings.push(...learnings);
|
|
8721
|
+
}
|
|
8722
|
+
if (stats.sessions.length > MAX_SESSIONS) {
|
|
8723
|
+
stats.sessions = stats.sessions.slice(-MAX_SESSIONS);
|
|
8724
|
+
}
|
|
8725
|
+
if (stats.learnings.length > MAX_LEARNINGS) {
|
|
8726
|
+
stats.learnings = stats.learnings.slice(-MAX_LEARNINGS);
|
|
8727
|
+
}
|
|
8728
|
+
recalculateTotals(stats);
|
|
8729
|
+
writeROIStats(stats);
|
|
8730
|
+
return stats;
|
|
8731
|
+
}
|
|
8732
|
+
function formatROISummary(stats) {
|
|
8733
|
+
const t = stats.totals;
|
|
8734
|
+
const totalSessions = t.totalSessionsWithLearnings + t.totalSessionsWithoutLearnings;
|
|
8735
|
+
if (totalSessions === 0) return "";
|
|
8736
|
+
const lines = ["ROI Summary"];
|
|
8737
|
+
lines.push(` Sessions tracked: ${totalSessions}`);
|
|
8738
|
+
lines.push(` Sessions with learnings: ${t.totalSessionsWithLearnings}`);
|
|
8739
|
+
if (t.totalSessionsWithoutLearnings > 0) {
|
|
8740
|
+
const rateWithout = t.totalSessionsWithoutLearnings > 0 ? (t.totalFailuresWithoutLearnings / t.totalSessionsWithoutLearnings).toFixed(1) : "0.0";
|
|
8741
|
+
lines.push(` Failure rate (no learnings): ${rateWithout}/session`);
|
|
8742
|
+
}
|
|
8743
|
+
if (t.totalSessionsWithLearnings > 0) {
|
|
8744
|
+
const rateWith = (t.totalFailuresWithLearnings / t.totalSessionsWithLearnings).toFixed(1);
|
|
8745
|
+
lines.push(` Failure rate (with learnings): ${rateWith}/session`);
|
|
8746
|
+
}
|
|
8747
|
+
if (t.totalWasteTokens > 0) {
|
|
8748
|
+
lines.push(` Total waste captured: ${t.totalWasteTokens.toLocaleString()} tokens`);
|
|
8749
|
+
}
|
|
8750
|
+
if (t.estimatedSavingsTokens > 0) {
|
|
8751
|
+
lines.push(` Estimated savings: ~${t.estimatedSavingsTokens.toLocaleString()} tokens`);
|
|
8752
|
+
}
|
|
8753
|
+
return lines.join("\n");
|
|
8754
|
+
}
|
|
8755
|
+
|
|
8756
|
+
// src/commands/learn.ts
|
|
8561
8757
|
var MIN_EVENTS_FOR_ANALYSIS = 25;
|
|
8562
8758
|
async function learnObserveCommand(options) {
|
|
8563
8759
|
try {
|
|
@@ -8636,18 +8832,82 @@ async function learnFinalizeCommand(options) {
|
|
|
8636
8832
|
existingSkills
|
|
8637
8833
|
);
|
|
8638
8834
|
analyzed = true;
|
|
8835
|
+
const waste = calculateSessionWaste(events);
|
|
8836
|
+
const existingLearnedItems = existingLearnedSection ? existingLearnedSection.split("\n").filter((l) => l.startsWith("- ")).length : 0;
|
|
8837
|
+
const hadLearnings = existingLearnedItems > 0;
|
|
8838
|
+
let newLearningsProduced = 0;
|
|
8839
|
+
let roiLearningEntries = [];
|
|
8639
8840
|
if (response.claudeMdLearnedSection || response.skills?.length) {
|
|
8640
8841
|
const result = writeLearnedContent({
|
|
8641
8842
|
claudeMdLearnedSection: response.claudeMdLearnedSection,
|
|
8642
8843
|
skills: response.skills
|
|
8643
8844
|
});
|
|
8845
|
+
newLearningsProduced = result.newItemCount;
|
|
8644
8846
|
if (result.newItemCount > 0) {
|
|
8645
|
-
|
|
8847
|
+
const wasteLabel = waste.totalWasteTokens > 0 ? ` (~${waste.totalWasteTokens.toLocaleString()} wasted tokens captured)` : "";
|
|
8848
|
+
console.log(chalk18.dim(`caliber: learned ${result.newItemCount} new pattern${result.newItemCount === 1 ? "" : "s"}${wasteLabel}`));
|
|
8646
8849
|
for (const item of result.newItems) {
|
|
8647
8850
|
console.log(chalk18.dim(` + ${item.replace(/^- /, "").slice(0, 80)}`));
|
|
8648
8851
|
}
|
|
8852
|
+
const wastePerLearning = Math.round(waste.totalWasteTokens / result.newItemCount);
|
|
8853
|
+
const TYPE_RE = /^\*\*\[([^\]]+)\]\*\*/;
|
|
8854
|
+
const learningEntries = result.newItems.map((item) => {
|
|
8855
|
+
const clean = item.replace(/^- /, "");
|
|
8856
|
+
const typeMatch = clean.match(TYPE_RE);
|
|
8857
|
+
return {
|
|
8858
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8859
|
+
observationType: typeMatch ? typeMatch[1] : "unknown",
|
|
8860
|
+
summary: clean.replace(TYPE_RE, "").trim().slice(0, 80),
|
|
8861
|
+
wasteTokens: wastePerLearning,
|
|
8862
|
+
sourceEventCount: events.length
|
|
8863
|
+
};
|
|
8864
|
+
});
|
|
8865
|
+
for (const entry of learningEntries) {
|
|
8866
|
+
trackLearnNewLearning({
|
|
8867
|
+
observationType: entry.observationType,
|
|
8868
|
+
wasteTokens: entry.wasteTokens,
|
|
8869
|
+
sourceEventCount: entry.sourceEventCount
|
|
8870
|
+
});
|
|
8871
|
+
}
|
|
8872
|
+
roiLearningEntries = learningEntries;
|
|
8649
8873
|
}
|
|
8650
8874
|
}
|
|
8875
|
+
const sessionSummary = {
|
|
8876
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8877
|
+
sessionId: readState2().sessionId || "unknown",
|
|
8878
|
+
eventCount: events.length,
|
|
8879
|
+
failureCount: waste.failureCount,
|
|
8880
|
+
promptCount: waste.promptCount,
|
|
8881
|
+
hadLearningsAvailable: hadLearnings,
|
|
8882
|
+
learningsCount: existingLearnedItems,
|
|
8883
|
+
newLearningsProduced
|
|
8884
|
+
};
|
|
8885
|
+
const roiStats = recordSession(sessionSummary, roiLearningEntries);
|
|
8886
|
+
trackLearnSessionAnalyzed({
|
|
8887
|
+
eventCount: events.length,
|
|
8888
|
+
failureCount: waste.failureCount,
|
|
8889
|
+
correctionCount: waste.promptCount,
|
|
8890
|
+
hadLearningsAvailable: hadLearnings,
|
|
8891
|
+
learningsAvailableCount: existingLearnedItems,
|
|
8892
|
+
newLearningsProduced,
|
|
8893
|
+
wasteTokens: waste.totalWasteTokens
|
|
8894
|
+
});
|
|
8895
|
+
const t = roiStats.totals;
|
|
8896
|
+
const totalSessions = t.totalSessionsWithLearnings + t.totalSessionsWithoutLearnings;
|
|
8897
|
+
trackLearnROISnapshot({
|
|
8898
|
+
totalWasteTokens: t.totalWasteTokens,
|
|
8899
|
+
totalSessions,
|
|
8900
|
+
sessionsWithLearnings: t.totalSessionsWithLearnings,
|
|
8901
|
+
sessionsWithoutLearnings: t.totalSessionsWithoutLearnings,
|
|
8902
|
+
failureRateWithLearnings: t.totalSessionsWithLearnings > 0 ? t.totalFailuresWithLearnings / t.totalSessionsWithLearnings : 0,
|
|
8903
|
+
failureRateWithoutLearnings: t.totalSessionsWithoutLearnings > 0 ? t.totalFailuresWithoutLearnings / t.totalSessionsWithoutLearnings : 0,
|
|
8904
|
+
estimatedSavingsTokens: t.estimatedSavingsTokens,
|
|
8905
|
+
learningCount: roiStats.learnings.length
|
|
8906
|
+
});
|
|
8907
|
+
if (t.estimatedSavingsTokens > 0) {
|
|
8908
|
+
const totalLearnings = existingLearnedItems + newLearningsProduced;
|
|
8909
|
+
console.log(chalk18.dim(`caliber: ${totalLearnings} learnings active \u2014 est. ~${t.estimatedSavingsTokens.toLocaleString()} tokens saved across ${t.totalSessionsWithLearnings} sessions`));
|
|
8910
|
+
}
|
|
8651
8911
|
} catch (err) {
|
|
8652
8912
|
if (options?.force) {
|
|
8653
8913
|
console.error(chalk18.red("caliber: finalize failed \u2014"), err instanceof Error ? err.message : err);
|
|
@@ -8662,7 +8922,7 @@ async function learnFinalizeCommand(options) {
|
|
|
8662
8922
|
}
|
|
8663
8923
|
async function learnInstallCommand() {
|
|
8664
8924
|
let anyInstalled = false;
|
|
8665
|
-
if (
|
|
8925
|
+
if (fs33.existsSync(".claude")) {
|
|
8666
8926
|
const r = installLearningHooks();
|
|
8667
8927
|
if (r.installed) {
|
|
8668
8928
|
console.log(chalk18.green("\u2713") + " Claude Code learning hooks installed");
|
|
@@ -8671,7 +8931,7 @@ async function learnInstallCommand() {
|
|
|
8671
8931
|
console.log(chalk18.dim(" Claude Code hooks already installed"));
|
|
8672
8932
|
}
|
|
8673
8933
|
}
|
|
8674
|
-
if (
|
|
8934
|
+
if (fs33.existsSync(".cursor")) {
|
|
8675
8935
|
const r = installCursorLearningHooks();
|
|
8676
8936
|
if (r.installed) {
|
|
8677
8937
|
console.log(chalk18.green("\u2713") + " Cursor learning hooks installed");
|
|
@@ -8680,7 +8940,7 @@ async function learnInstallCommand() {
|
|
|
8680
8940
|
console.log(chalk18.dim(" Cursor hooks already installed"));
|
|
8681
8941
|
}
|
|
8682
8942
|
}
|
|
8683
|
-
if (!
|
|
8943
|
+
if (!fs33.existsSync(".claude") && !fs33.existsSync(".cursor")) {
|
|
8684
8944
|
console.log(chalk18.yellow("No .claude/ or .cursor/ directory found."));
|
|
8685
8945
|
console.log(chalk18.dim(" Run `caliber init` first, or create the directory manually."));
|
|
8686
8946
|
return;
|
|
@@ -8740,12 +9000,21 @@ async function learnStatusCommand() {
|
|
|
8740
9000
|
console.log(`
|
|
8741
9001
|
Learned items in CALIBER_LEARNINGS.md: ${chalk18.cyan(String(lineCount))}`);
|
|
8742
9002
|
}
|
|
9003
|
+
const roiStats = readROIStats();
|
|
9004
|
+
const roiSummary = formatROISummary(roiStats);
|
|
9005
|
+
if (roiSummary) {
|
|
9006
|
+
console.log();
|
|
9007
|
+
console.log(chalk18.bold(roiSummary.split("\n")[0]));
|
|
9008
|
+
for (const line of roiSummary.split("\n").slice(1)) {
|
|
9009
|
+
console.log(line);
|
|
9010
|
+
}
|
|
9011
|
+
}
|
|
8743
9012
|
}
|
|
8744
9013
|
|
|
8745
9014
|
// src/cli.ts
|
|
8746
|
-
var __dirname =
|
|
9015
|
+
var __dirname = path27.dirname(fileURLToPath(import.meta.url));
|
|
8747
9016
|
var pkg = JSON.parse(
|
|
8748
|
-
|
|
9017
|
+
fs34.readFileSync(path27.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
8749
9018
|
);
|
|
8750
9019
|
var program = new Command();
|
|
8751
9020
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
@@ -8819,16 +9088,16 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
|
|
|
8819
9088
|
learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
|
|
8820
9089
|
|
|
8821
9090
|
// src/utils/version-check.ts
|
|
8822
|
-
import
|
|
8823
|
-
import
|
|
9091
|
+
import fs35 from "fs";
|
|
9092
|
+
import path28 from "path";
|
|
8824
9093
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8825
9094
|
import { execSync as execSync14 } from "child_process";
|
|
8826
9095
|
import chalk19 from "chalk";
|
|
8827
9096
|
import ora6 from "ora";
|
|
8828
9097
|
import confirm2 from "@inquirer/confirm";
|
|
8829
|
-
var __dirname_vc =
|
|
9098
|
+
var __dirname_vc = path28.dirname(fileURLToPath2(import.meta.url));
|
|
8830
9099
|
var pkg2 = JSON.parse(
|
|
8831
|
-
|
|
9100
|
+
fs35.readFileSync(path28.resolve(__dirname_vc, "..", "package.json"), "utf-8")
|
|
8832
9101
|
);
|
|
8833
9102
|
function getChannel(version) {
|
|
8834
9103
|
const match = version.match(/-(dev|next)\./);
|
|
@@ -8853,8 +9122,8 @@ function isNewer(registry, current) {
|
|
|
8853
9122
|
function getInstalledVersion() {
|
|
8854
9123
|
try {
|
|
8855
9124
|
const globalRoot = execSync14("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
8856
|
-
const pkgPath =
|
|
8857
|
-
return JSON.parse(
|
|
9125
|
+
const pkgPath = path28.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
9126
|
+
return JSON.parse(fs35.readFileSync(pkgPath, "utf-8")).version;
|
|
8858
9127
|
} catch {
|
|
8859
9128
|
return null;
|
|
8860
9129
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rely-ai/caliber",
|
|
3
|
-
"version": "1.20.0-dev.
|
|
3
|
+
"version": "1.20.0-dev.1773690658",
|
|
4
4
|
"description": "Analyze your codebase and generate optimized AI agent configs (CLAUDE.md, .cursorrules, skills) — no API key needed",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|