@rely-ai/caliber 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +212 -39
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -3763,19 +3763,16 @@ function displayScoreSummary(result) {
|
|
|
3763
3763
|
console.log(
|
|
3764
3764
|
chalk3.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk3.gray(` (Grade ${result.grade})`) + chalk3.gray(` \xB7 ${agentLabel}`) + chalk3.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
|
|
3765
3765
|
);
|
|
3766
|
-
const failing = result.checks.filter((c) => !c.passed
|
|
3766
|
+
const failing = result.checks.filter((c) => !c.passed);
|
|
3767
3767
|
if (failing.length > 0) {
|
|
3768
|
-
const shown = failing.slice(0,
|
|
3768
|
+
const shown = failing.slice(0, 5);
|
|
3769
3769
|
for (const check of shown) {
|
|
3770
|
-
console.log(chalk3.gray(` \u2717 ${check.name}`)
|
|
3770
|
+
console.log(chalk3.gray(` \u2717 ${check.name}`));
|
|
3771
3771
|
}
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
}
|
|
3775
|
-
}
|
|
3776
|
-
if (failing.length > 0) {
|
|
3772
|
+
const remaining = failing.length - shown.length;
|
|
3773
|
+
const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
3777
3774
|
console.log(chalk3.dim(`
|
|
3778
|
-
Run ${chalk3.reset("caliber score")} for
|
|
3775
|
+
Run ${chalk3.reset("caliber score")} for details.${moreText}`));
|
|
3779
3776
|
}
|
|
3780
3777
|
console.log("");
|
|
3781
3778
|
}
|
|
@@ -3968,6 +3965,11 @@ async function initCommand(options) {
|
|
|
3968
3965
|
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
3969
3966
|
genSpinner.succeed(`Setup generated ${chalk4.dim(`in ${timeStr}`)}`);
|
|
3970
3967
|
printSetupSummary(generatedSetup);
|
|
3968
|
+
const sessionHistory = [];
|
|
3969
|
+
sessionHistory.push({
|
|
3970
|
+
role: "assistant",
|
|
3971
|
+
content: summarizeSetup("Initial generation", generatedSetup)
|
|
3972
|
+
});
|
|
3971
3973
|
console.log(title.bold(" Step 4/4 \u2014 Review\n"));
|
|
3972
3974
|
const setupFiles = collectSetupFiles(generatedSetup);
|
|
3973
3975
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
@@ -3976,11 +3978,11 @@ async function initCommand(options) {
|
|
|
3976
3978
|
const wantsReview = await promptWantsReview();
|
|
3977
3979
|
if (wantsReview) {
|
|
3978
3980
|
const reviewMethod = await promptReviewMethod();
|
|
3979
|
-
openReview(reviewMethod, staged.stagedFiles);
|
|
3981
|
+
await openReview(reviewMethod, staged.stagedFiles);
|
|
3980
3982
|
}
|
|
3981
3983
|
let action = await promptReviewAction();
|
|
3982
3984
|
while (action === "refine") {
|
|
3983
|
-
generatedSetup = await refineLoop(generatedSetup, targetAgent);
|
|
3985
|
+
generatedSetup = await refineLoop(generatedSetup, targetAgent, sessionHistory);
|
|
3984
3986
|
if (!generatedSetup) {
|
|
3985
3987
|
cleanupStaging();
|
|
3986
3988
|
console.log(chalk4.dim("Refinement cancelled. No files were modified."));
|
|
@@ -3991,11 +3993,7 @@ async function initCommand(options) {
|
|
|
3991
3993
|
console.log(chalk4.dim(` ${chalk4.green(`${restaged.newFiles} new`)} / ${chalk4.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
|
|
3992
3994
|
`));
|
|
3993
3995
|
printSetupSummary(generatedSetup);
|
|
3994
|
-
|
|
3995
|
-
if (wantsReviewAgain) {
|
|
3996
|
-
const reviewMethod = await promptReviewMethod();
|
|
3997
|
-
openReview(reviewMethod, restaged.stagedFiles);
|
|
3998
|
-
}
|
|
3996
|
+
await openReview("terminal", restaged.stagedFiles);
|
|
3999
3997
|
action = await promptReviewAction();
|
|
4000
3998
|
}
|
|
4001
3999
|
cleanupStaging();
|
|
@@ -4095,8 +4093,7 @@ async function initCommand(options) {
|
|
|
4095
4093
|
console.log(` ${title("caliber undo")} Revert all changes from this run`);
|
|
4096
4094
|
console.log("");
|
|
4097
4095
|
}
|
|
4098
|
-
async function refineLoop(currentSetup, _targetAgent) {
|
|
4099
|
-
const history = [];
|
|
4096
|
+
async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
4100
4097
|
while (true) {
|
|
4101
4098
|
const message = await promptInput2("\nWhat would you like to change?");
|
|
4102
4099
|
if (!message || message.toLowerCase() === "done" || message.toLowerCase() === "accept") {
|
|
@@ -4105,19 +4102,29 @@ async function refineLoop(currentSetup, _targetAgent) {
|
|
|
4105
4102
|
if (message.toLowerCase() === "cancel") {
|
|
4106
4103
|
return null;
|
|
4107
4104
|
}
|
|
4105
|
+
const isValid = await classifyRefineIntent(message);
|
|
4106
|
+
if (!isValid) {
|
|
4107
|
+
console.log(chalk4.dim(" This doesn't look like a config change request."));
|
|
4108
|
+
console.log(chalk4.dim(" Describe what to add, remove, or modify in your configs."));
|
|
4109
|
+
console.log(chalk4.dim(' Type "done" to accept the current setup.\n'));
|
|
4110
|
+
continue;
|
|
4111
|
+
}
|
|
4108
4112
|
const refineSpinner = ora("Refining setup...").start();
|
|
4109
4113
|
const refineMessages = new SpinnerMessages(refineSpinner, REFINE_MESSAGES);
|
|
4110
4114
|
refineMessages.start();
|
|
4111
4115
|
const refined = await refineSetup(
|
|
4112
4116
|
currentSetup,
|
|
4113
4117
|
message,
|
|
4114
|
-
|
|
4118
|
+
sessionHistory
|
|
4115
4119
|
);
|
|
4116
4120
|
refineMessages.stop();
|
|
4117
4121
|
if (refined) {
|
|
4118
4122
|
currentSetup = refined;
|
|
4119
|
-
|
|
4120
|
-
|
|
4123
|
+
sessionHistory.push({ role: "user", content: message });
|
|
4124
|
+
sessionHistory.push({
|
|
4125
|
+
role: "assistant",
|
|
4126
|
+
content: summarizeSetup("Applied changes", refined)
|
|
4127
|
+
});
|
|
4121
4128
|
refineSpinner.succeed("Setup updated");
|
|
4122
4129
|
printSetupSummary(refined);
|
|
4123
4130
|
console.log(chalk4.dim('Type "done" to accept, or describe more changes.'));
|
|
@@ -4127,6 +4134,29 @@ async function refineLoop(currentSetup, _targetAgent) {
|
|
|
4127
4134
|
}
|
|
4128
4135
|
}
|
|
4129
4136
|
}
|
|
4137
|
+
function summarizeSetup(action, setup) {
|
|
4138
|
+
const descriptions = setup.fileDescriptions;
|
|
4139
|
+
const files = descriptions ? Object.entries(descriptions).map(([path23, desc]) => ` ${path23}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
|
|
4140
|
+
return `${action}. Files:
|
|
4141
|
+
${files}`;
|
|
4142
|
+
}
|
|
4143
|
+
async function classifyRefineIntent(message) {
|
|
4144
|
+
const fastModel = process.env.ANTHROPIC_SMALL_FAST_MODEL;
|
|
4145
|
+
try {
|
|
4146
|
+
const result = await llmJsonCall({
|
|
4147
|
+
system: `You classify whether a user message is a valid request to modify AI agent config files (CLAUDE.md, .cursorrules, skills).
|
|
4148
|
+
Valid: requests to add, remove, change, or restructure config content. Examples: "add testing commands", "remove the terraform section", "make CLAUDE.md shorter".
|
|
4149
|
+
Invalid: questions, requests to show/display something, general chat, or anything that isn't a concrete config change.
|
|
4150
|
+
Return {"valid": true} or {"valid": false}. Nothing else.`,
|
|
4151
|
+
prompt: message,
|
|
4152
|
+
maxTokens: 20,
|
|
4153
|
+
...fastModel ? { model: fastModel } : {}
|
|
4154
|
+
});
|
|
4155
|
+
return result.valid === true;
|
|
4156
|
+
} catch {
|
|
4157
|
+
return true;
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4130
4160
|
function promptInput2(question) {
|
|
4131
4161
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
4132
4162
|
return new Promise((resolve2) => {
|
|
@@ -4186,34 +4216,177 @@ async function promptReviewMethod() {
|
|
|
4186
4216
|
});
|
|
4187
4217
|
return select2({ message: "How would you like to review the changes?", choices });
|
|
4188
4218
|
}
|
|
4189
|
-
function openReview(method, stagedFiles) {
|
|
4219
|
+
async function openReview(method, stagedFiles) {
|
|
4190
4220
|
if (method === "cursor" || method === "vscode") {
|
|
4191
4221
|
openDiffsInEditor(method, stagedFiles.map((f) => ({
|
|
4192
4222
|
originalPath: f.originalPath,
|
|
4193
4223
|
proposedPath: f.proposedPath
|
|
4194
4224
|
})));
|
|
4195
4225
|
console.log(chalk4.dim(" Diffs opened in your editor.\n"));
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4226
|
+
return;
|
|
4227
|
+
}
|
|
4228
|
+
const fileInfos = stagedFiles.map((file) => {
|
|
4229
|
+
const proposed = fs17.readFileSync(file.proposedPath, "utf-8");
|
|
4230
|
+
const current = file.currentPath ? fs17.readFileSync(file.currentPath, "utf-8") : "";
|
|
4231
|
+
const patch = createTwoFilesPatch(
|
|
4232
|
+
file.isNew ? "/dev/null" : file.relativePath,
|
|
4233
|
+
file.relativePath,
|
|
4234
|
+
current,
|
|
4235
|
+
proposed
|
|
4236
|
+
);
|
|
4237
|
+
let added = 0, removed = 0;
|
|
4238
|
+
for (const line of patch.split("\n")) {
|
|
4239
|
+
if (line.startsWith("+") && !line.startsWith("+++")) added++;
|
|
4240
|
+
if (line.startsWith("-") && !line.startsWith("---")) removed++;
|
|
4241
|
+
}
|
|
4242
|
+
return {
|
|
4243
|
+
relativePath: file.relativePath,
|
|
4244
|
+
isNew: file.isNew,
|
|
4245
|
+
added,
|
|
4246
|
+
removed,
|
|
4247
|
+
lines: proposed.split("\n").length,
|
|
4248
|
+
patch
|
|
4249
|
+
};
|
|
4250
|
+
});
|
|
4251
|
+
await interactiveDiffExplorer(fileInfos);
|
|
4252
|
+
}
|
|
4253
|
+
async function interactiveDiffExplorer(files) {
|
|
4254
|
+
if (!process.stdin.isTTY) {
|
|
4255
|
+
for (const f of files) {
|
|
4256
|
+
const icon = f.isNew ? chalk4.green("+") : chalk4.yellow("~");
|
|
4257
|
+
const stats = f.isNew ? chalk4.dim(`${f.lines} lines`) : `${chalk4.green(`+${f.added}`)} ${chalk4.red(`-${f.removed}`)}`;
|
|
4258
|
+
console.log(` ${icon} ${f.relativePath} ${stats}`);
|
|
4259
|
+
}
|
|
4260
|
+
console.log("");
|
|
4261
|
+
return;
|
|
4262
|
+
}
|
|
4263
|
+
const { stdin, stdout } = process;
|
|
4264
|
+
let cursor = 0;
|
|
4265
|
+
let viewing = null;
|
|
4266
|
+
let scrollOffset = 0;
|
|
4267
|
+
let lineCount = 0;
|
|
4268
|
+
function getTermHeight() {
|
|
4269
|
+
return (stdout.rows || 24) - 4;
|
|
4270
|
+
}
|
|
4271
|
+
function renderFileList() {
|
|
4272
|
+
const lines = [];
|
|
4273
|
+
lines.push(chalk4.bold(" Review changes"));
|
|
4274
|
+
lines.push("");
|
|
4275
|
+
for (let i = 0; i < files.length; i++) {
|
|
4276
|
+
const f = files[i];
|
|
4277
|
+
const ptr = i === cursor ? chalk4.cyan(">") : " ";
|
|
4278
|
+
const icon = f.isNew ? chalk4.green("+") : chalk4.yellow("~");
|
|
4279
|
+
const stats = f.isNew ? chalk4.dim(`${f.lines} lines`) : `${chalk4.green(`+${f.added}`)} ${chalk4.red(`-${f.removed}`)}`;
|
|
4280
|
+
lines.push(` ${ptr} ${icon} ${f.relativePath} ${stats}`);
|
|
4281
|
+
}
|
|
4282
|
+
lines.push("");
|
|
4283
|
+
lines.push(chalk4.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
|
|
4284
|
+
return lines.join("\n");
|
|
4285
|
+
}
|
|
4286
|
+
function renderDiff(index) {
|
|
4287
|
+
const f = files[index];
|
|
4288
|
+
const lines = [];
|
|
4289
|
+
const header = f.isNew ? ` ${chalk4.green("+")} ${f.relativePath} ${chalk4.dim("(new file)")}` : ` ${chalk4.yellow("~")} ${f.relativePath} ${chalk4.green(`+${f.added}`)} ${chalk4.red(`-${f.removed}`)}`;
|
|
4290
|
+
lines.push(header);
|
|
4291
|
+
lines.push(chalk4.dim(" " + "\u2500".repeat(60)));
|
|
4292
|
+
const patchLines = f.patch.split("\n");
|
|
4293
|
+
const bodyLines = patchLines.slice(4);
|
|
4294
|
+
const maxVisible = getTermHeight() - 4;
|
|
4295
|
+
const visibleLines = bodyLines.slice(scrollOffset, scrollOffset + maxVisible);
|
|
4296
|
+
for (const line of visibleLines) {
|
|
4297
|
+
if (line.startsWith("+")) {
|
|
4298
|
+
lines.push(chalk4.green(" " + line));
|
|
4299
|
+
} else if (line.startsWith("-")) {
|
|
4300
|
+
lines.push(chalk4.red(" " + line));
|
|
4301
|
+
} else if (line.startsWith("@@")) {
|
|
4302
|
+
lines.push(chalk4.cyan(" " + line));
|
|
4208
4303
|
} else {
|
|
4209
|
-
|
|
4210
|
-
console.log(` ${chalk4.green("+")} ${file.relativePath} ${chalk4.dim(`${lines} lines`)}`);
|
|
4304
|
+
lines.push(chalk4.dim(" " + line));
|
|
4211
4305
|
}
|
|
4212
4306
|
}
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4307
|
+
const totalBody = bodyLines.length;
|
|
4308
|
+
if (totalBody > maxVisible) {
|
|
4309
|
+
const pct = Math.round((scrollOffset + maxVisible) / totalBody * 100);
|
|
4310
|
+
lines.push(chalk4.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
|
|
4311
|
+
}
|
|
4312
|
+
lines.push("");
|
|
4313
|
+
lines.push(chalk4.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
|
|
4314
|
+
return lines.join("\n");
|
|
4216
4315
|
}
|
|
4316
|
+
function draw(initial) {
|
|
4317
|
+
if (!initial && lineCount > 0) {
|
|
4318
|
+
stdout.write(`\x1B[${lineCount}A`);
|
|
4319
|
+
}
|
|
4320
|
+
stdout.write("\x1B[0J");
|
|
4321
|
+
const output = viewing !== null ? renderDiff(viewing) : renderFileList();
|
|
4322
|
+
stdout.write(output + "\n");
|
|
4323
|
+
lineCount = output.split("\n").length;
|
|
4324
|
+
}
|
|
4325
|
+
return new Promise((resolve2) => {
|
|
4326
|
+
console.log("");
|
|
4327
|
+
draw(true);
|
|
4328
|
+
stdin.setRawMode(true);
|
|
4329
|
+
stdin.resume();
|
|
4330
|
+
stdin.setEncoding("utf8");
|
|
4331
|
+
function cleanup() {
|
|
4332
|
+
stdin.removeListener("data", onData);
|
|
4333
|
+
stdin.setRawMode(false);
|
|
4334
|
+
stdin.pause();
|
|
4335
|
+
}
|
|
4336
|
+
function onData(key) {
|
|
4337
|
+
if (viewing !== null) {
|
|
4338
|
+
const f = files[viewing];
|
|
4339
|
+
const totalBody = f.patch.split("\n").length - 4;
|
|
4340
|
+
const maxVisible = getTermHeight() - 4;
|
|
4341
|
+
switch (key) {
|
|
4342
|
+
case "\x1B[A":
|
|
4343
|
+
scrollOffset = Math.max(0, scrollOffset - 1);
|
|
4344
|
+
draw(false);
|
|
4345
|
+
break;
|
|
4346
|
+
case "\x1B[B":
|
|
4347
|
+
scrollOffset = Math.min(Math.max(0, totalBody - maxVisible), scrollOffset + 1);
|
|
4348
|
+
draw(false);
|
|
4349
|
+
break;
|
|
4350
|
+
case " ":
|
|
4351
|
+
case "\x1B":
|
|
4352
|
+
viewing = null;
|
|
4353
|
+
scrollOffset = 0;
|
|
4354
|
+
draw(false);
|
|
4355
|
+
break;
|
|
4356
|
+
case "q":
|
|
4357
|
+
case "":
|
|
4358
|
+
cleanup();
|
|
4359
|
+
console.log("");
|
|
4360
|
+
resolve2();
|
|
4361
|
+
break;
|
|
4362
|
+
}
|
|
4363
|
+
} else {
|
|
4364
|
+
switch (key) {
|
|
4365
|
+
case "\x1B[A":
|
|
4366
|
+
cursor = (cursor - 1 + files.length) % files.length;
|
|
4367
|
+
draw(false);
|
|
4368
|
+
break;
|
|
4369
|
+
case "\x1B[B":
|
|
4370
|
+
cursor = (cursor + 1) % files.length;
|
|
4371
|
+
draw(false);
|
|
4372
|
+
break;
|
|
4373
|
+
case "\r":
|
|
4374
|
+
case "\n":
|
|
4375
|
+
viewing = cursor;
|
|
4376
|
+
scrollOffset = 0;
|
|
4377
|
+
draw(false);
|
|
4378
|
+
break;
|
|
4379
|
+
case "q":
|
|
4380
|
+
case "":
|
|
4381
|
+
cleanup();
|
|
4382
|
+
console.log("");
|
|
4383
|
+
resolve2();
|
|
4384
|
+
break;
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
}
|
|
4388
|
+
stdin.on("data", onData);
|
|
4389
|
+
});
|
|
4217
4390
|
}
|
|
4218
4391
|
async function promptReviewAction() {
|
|
4219
4392
|
return select2({
|
package/package.json
CHANGED