haansi 0.1.55 → 0.1.56
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/haansi.js +281 -19
- package/package.json +1 -1
package/dist/haansi.js
CHANGED
|
@@ -95,7 +95,7 @@ var require_package = __commonJS({
|
|
|
95
95
|
"package.json"(exports2, module2) {
|
|
96
96
|
module2.exports = {
|
|
97
97
|
name: "haansi",
|
|
98
|
-
version: "0.1.
|
|
98
|
+
version: "0.1.56",
|
|
99
99
|
description: "Haansi CLI - Session collector and MCP server for Claude Code & OpenAI Codex",
|
|
100
100
|
bin: {
|
|
101
101
|
haansi: "./dist/haansi.js"
|
|
@@ -19220,6 +19220,16 @@ var init_exclusions = __esm({
|
|
|
19220
19220
|
model: ["operational", "The model name the replay ran with."],
|
|
19221
19221
|
run_ref: ["not-personal", "A link to the customer's CI run."]
|
|
19222
19222
|
}),
|
|
19223
|
+
...exchangeExclusions(INTEL, "replay_task_results", {
|
|
19224
|
+
inputs_fingerprint: [
|
|
19225
|
+
"derived",
|
|
19226
|
+
"A SHA-256 of the task's inputs the replay ran on; not reversible."
|
|
19227
|
+
],
|
|
19228
|
+
arm: ["operational", "Closed CHECK vocabulary (baseline, haansi)."],
|
|
19229
|
+
agent: ["operational", "The agent CLI's name, e.g. claude-code."],
|
|
19230
|
+
model: ["operational", "The model name the replay ran with."],
|
|
19231
|
+
run_ref: ["not-personal", "A link to the customer's CI run."]
|
|
19232
|
+
}),
|
|
19223
19233
|
...exchangeExclusions(INTEL, "replay_tasks", {
|
|
19224
19234
|
process_id: [
|
|
19225
19235
|
"join-key",
|
|
@@ -26570,6 +26580,9 @@ var init_table_registry = __esm({
|
|
|
26570
26580
|
entry("intelligence", INTELLIGENCE_DB, "stored_replay_tasks", "direct", {
|
|
26571
26581
|
scopingColumn: "organization_id"
|
|
26572
26582
|
}),
|
|
26583
|
+
entry("intelligence", INTELLIGENCE_DB, "replay_task_results", "direct", {
|
|
26584
|
+
scopingColumn: "organization_id"
|
|
26585
|
+
}),
|
|
26573
26586
|
// A person's revert verdicts, the checks that validate a change and the
|
|
26574
26587
|
// replay commands, per repository (outcome evidence v2 plan).
|
|
26575
26588
|
entry("intelligence", INTELLIGENCE_DB, "revert_labels", "direct", {
|
|
@@ -85201,8 +85214,11 @@ __export(replay_calibrate_exports, {
|
|
|
85201
85214
|
RUNTIMES: () => RUNTIMES,
|
|
85202
85215
|
calibrate: () => calibrate,
|
|
85203
85216
|
calibrateTask: () => calibrateTask,
|
|
85217
|
+
calibrateTaskOptions: () => calibrateTaskOptions,
|
|
85218
|
+
cliVersion: () => cliVersion,
|
|
85204
85219
|
environmentOf: () => environmentOf,
|
|
85205
85220
|
parseCalibrateArgs: () => parseCalibrateArgs,
|
|
85221
|
+
repositoryOf: () => repositoryOf,
|
|
85206
85222
|
runCalibration: () => runCalibration,
|
|
85207
85223
|
runnerOf: () => runnerOf
|
|
85208
85224
|
});
|
|
@@ -85245,6 +85261,19 @@ function parseCalibrateArgs(argv) {
|
|
|
85245
85261
|
errors.push("--timeout-min must be a positive number.");
|
|
85246
85262
|
return { options, errors };
|
|
85247
85263
|
}
|
|
85264
|
+
function calibrateTaskOptions(run3, commands) {
|
|
85265
|
+
return {
|
|
85266
|
+
setupCmd: commands.setupCmd,
|
|
85267
|
+
testCmd: commands.testCmd,
|
|
85268
|
+
repoCommands: false,
|
|
85269
|
+
runs: 2,
|
|
85270
|
+
force: false,
|
|
85271
|
+
limit: run3.limit,
|
|
85272
|
+
timeoutMs: run3.timeoutMs,
|
|
85273
|
+
runRef: run3.runRef,
|
|
85274
|
+
dryRun: run3.dryRun
|
|
85275
|
+
};
|
|
85276
|
+
}
|
|
85248
85277
|
function runnerOf(env) {
|
|
85249
85278
|
if (env.ImageOS && env.ImageVersion)
|
|
85250
85279
|
return `${env.ImageOS}-${env.ImageVersion}`;
|
|
@@ -85357,12 +85386,16 @@ async function calibrateTask(deps, options, commands, task) {
|
|
|
85357
85386
|
}
|
|
85358
85387
|
return done("fails_at_base_passes_at_target");
|
|
85359
85388
|
}
|
|
85360
|
-
async function
|
|
85389
|
+
async function repositoryOf(deps) {
|
|
85361
85390
|
const remote = await deps.git(["remote", "get-url", "origin"], deps.repoDir);
|
|
85362
85391
|
const repository = remote.code === 0 ? repositoryFromRemote(remote.output) : null;
|
|
85363
85392
|
if (!repository)
|
|
85364
85393
|
throw new Error("Run from a clone of the repository (no origin remote).");
|
|
85365
|
-
|
|
85394
|
+
return repository;
|
|
85395
|
+
}
|
|
85396
|
+
async function runCalibration(options, deps, preloaded) {
|
|
85397
|
+
const repository = await repositoryOf(deps);
|
|
85398
|
+
const set2 = preloaded ?? await deps.getReplaySet(repository);
|
|
85366
85399
|
const repo = options.repoCommands ? set2.repoCommands : null;
|
|
85367
85400
|
const setupCmd = options.setupCmd ?? repo?.setupCommand ?? null;
|
|
85368
85401
|
const testCmd = options.testCmd || repo?.testCommand || "";
|
|
@@ -85372,17 +85405,12 @@ async function runCalibration(options, deps) {
|
|
|
85372
85405
|
);
|
|
85373
85406
|
const environment = await environmentOf(deps, { setupCmd, testCmd });
|
|
85374
85407
|
const calibrations = [];
|
|
85408
|
+
const states = /* @__PURE__ */ new Map();
|
|
85375
85409
|
let reused = 0;
|
|
85376
85410
|
let skipped = 0;
|
|
85377
85411
|
const tasks = options.limit ? set2.tasks.slice(0, options.limit) : set2.tasks;
|
|
85378
85412
|
for (const task of tasks) {
|
|
85379
85413
|
const label = task.name ?? task.taskKey;
|
|
85380
|
-
const c = task.calibration;
|
|
85381
|
-
if (!options.force && c && c.inputsFingerprint === task.inputsFingerprint && c.envFingerprint === environment.fingerprint) {
|
|
85382
|
-
reused += 1;
|
|
85383
|
-
deps.log(`= ${c.state.padEnd(7)} ${label} (calibrated already)`);
|
|
85384
|
-
continue;
|
|
85385
|
-
}
|
|
85386
85414
|
if (!SHA.test(task.baseSha) || !SHA.test(task.targetSha)) {
|
|
85387
85415
|
skipped += 1;
|
|
85388
85416
|
deps.log(`skip ${label}: its commits are not commit ids`);
|
|
@@ -85400,6 +85428,13 @@ async function runCalibration(options, deps) {
|
|
|
85400
85428
|
deps.log(`skip ${label}: a test path is not usable`);
|
|
85401
85429
|
continue;
|
|
85402
85430
|
}
|
|
85431
|
+
const c = task.calibration;
|
|
85432
|
+
if (!options.force && c && c.inputsFingerprint === task.inputsFingerprint && c.envFingerprint === environment.fingerprint) {
|
|
85433
|
+
reused += 1;
|
|
85434
|
+
states.set(task.taskId, c.state);
|
|
85435
|
+
deps.log(`= ${c.state.padEnd(7)} ${label} (calibrated already)`);
|
|
85436
|
+
continue;
|
|
85437
|
+
}
|
|
85403
85438
|
if (!await ensureCommit(deps, task.baseSha) || !await ensureCommit(deps, task.targetSha)) {
|
|
85404
85439
|
skipped += 1;
|
|
85405
85440
|
deps.log(`skip ${label}: its commits are not reachable from origin`);
|
|
@@ -85412,12 +85447,13 @@ async function runCalibration(options, deps) {
|
|
|
85412
85447
|
task
|
|
85413
85448
|
);
|
|
85414
85449
|
calibrations.push(result);
|
|
85450
|
+
states.set(task.taskId, result.state);
|
|
85415
85451
|
deps.log(
|
|
85416
85452
|
`${result.state.padEnd(7)} ${label}: ${result.reason.replace(/_/g, " ")} (base ${result.runs.base.join(",") || "-"}; target ${result.runs.target.join(",") || "-"})`
|
|
85417
85453
|
);
|
|
85418
85454
|
}
|
|
85419
85455
|
if (options.dryRun || calibrations.length === 0)
|
|
85420
|
-
return { calibrations, reused, skipped, recorded: null };
|
|
85456
|
+
return { calibrations, reused, skipped, recorded: null, states };
|
|
85421
85457
|
let recorded = 0;
|
|
85422
85458
|
for (let i = 0; i < calibrations.length; i += REPORT_CHUNK) {
|
|
85423
85459
|
const out = await deps.report({
|
|
@@ -85431,7 +85467,7 @@ async function runCalibration(options, deps) {
|
|
|
85431
85467
|
`Haansi did not record ${out.refused.length} calibration(s): their task changed since it was listed.`
|
|
85432
85468
|
);
|
|
85433
85469
|
}
|
|
85434
|
-
return { calibrations, reused, skipped, recorded };
|
|
85470
|
+
return { calibrations, reused, skipped, recorded, states };
|
|
85435
85471
|
}
|
|
85436
85472
|
async function calibrate(argv) {
|
|
85437
85473
|
if (argv.includes("--help")) {
|
|
@@ -85526,6 +85562,178 @@ them all.`;
|
|
|
85526
85562
|
}
|
|
85527
85563
|
});
|
|
85528
85564
|
|
|
85565
|
+
// src/commands/replay-tasks.ts
|
|
85566
|
+
var replay_tasks_exports = {};
|
|
85567
|
+
__export(replay_tasks_exports, {
|
|
85568
|
+
areaOf: () => areaOf,
|
|
85569
|
+
cardPrompt: () => cardPrompt,
|
|
85570
|
+
changedFiles: () => changedFiles,
|
|
85571
|
+
overlapOf: () => overlapOf,
|
|
85572
|
+
runStoredReplays: () => runStoredReplays
|
|
85573
|
+
});
|
|
85574
|
+
function cardPrompt(task, feedback) {
|
|
85575
|
+
return [
|
|
85576
|
+
"# Task",
|
|
85577
|
+
"",
|
|
85578
|
+
task.card.problem,
|
|
85579
|
+
"",
|
|
85580
|
+
"## Done when",
|
|
85581
|
+
"",
|
|
85582
|
+
task.card.acceptance,
|
|
85583
|
+
...task.card.area ? ["", "## Part of the code", "", task.card.area] : [],
|
|
85584
|
+
"",
|
|
85585
|
+
...feedback ? [FEEDBACK_HEADER, "", "```", feedback, "```", ""] : [],
|
|
85586
|
+
"Work in this repository as it is now. Do not look at later commits or other branches."
|
|
85587
|
+
].join("\n");
|
|
85588
|
+
}
|
|
85589
|
+
function areaOf(path2) {
|
|
85590
|
+
const dirs = path2.split("/").slice(0, -1);
|
|
85591
|
+
return dirs.length ? dirs.slice(0, 2).join("/") : ".";
|
|
85592
|
+
}
|
|
85593
|
+
async function changedFiles(deps, dir, baseSha) {
|
|
85594
|
+
const lines = (out) => out.code === 0 ? out.output.split("\n").map((l) => l.trim()).filter(Boolean) : [];
|
|
85595
|
+
const diff = await deps.git(
|
|
85596
|
+
["diff", "--name-only", "--no-renames", baseSha],
|
|
85597
|
+
dir
|
|
85598
|
+
);
|
|
85599
|
+
const added = await deps.git(
|
|
85600
|
+
["ls-files", "--others", "--exclude-standard"],
|
|
85601
|
+
dir
|
|
85602
|
+
);
|
|
85603
|
+
return [.../* @__PURE__ */ new Set([...lines(diff), ...lines(added)])].filter((f) => !f.startsWith(".haansi-replay/")).sort();
|
|
85604
|
+
}
|
|
85605
|
+
function overlapOf(changed, task) {
|
|
85606
|
+
const tests = new Set(task.testFiles);
|
|
85607
|
+
const mine = new Set(changed.filter((f) => !tests.has(f)));
|
|
85608
|
+
const theirs = new Set(task.targetFiles.filter((f) => !tests.has(f)));
|
|
85609
|
+
const both = [...mine].filter((f) => theirs.has(f)).length;
|
|
85610
|
+
const myAreas = new Set([...mine].map(areaOf));
|
|
85611
|
+
const theirAreas = new Set([...theirs].map(areaOf));
|
|
85612
|
+
const bothAreas = [...myAreas].filter((a) => theirAreas.has(a)).length;
|
|
85613
|
+
const known = mine.size > 0 && theirs.size > 0;
|
|
85614
|
+
return {
|
|
85615
|
+
filePrecision: known ? share(both, mine.size) : null,
|
|
85616
|
+
fileRecall: known ? share(both, theirs.size) : null,
|
|
85617
|
+
areaPrecision: known ? share(bothAreas, myAreas.size) : null,
|
|
85618
|
+
areaRecall: known ? share(bothAreas, theirAreas.size) : null,
|
|
85619
|
+
changedFiles: mine.size
|
|
85620
|
+
};
|
|
85621
|
+
}
|
|
85622
|
+
async function runStoredReplays(options, deps) {
|
|
85623
|
+
const repository = await repositoryOf(deps);
|
|
85624
|
+
const set2 = await deps.getReplaySet(repository);
|
|
85625
|
+
const repo = options.repoCommands ? set2.repoCommands : null;
|
|
85626
|
+
const setupCmd = options.setupCmd ?? repo?.setupCommand ?? null;
|
|
85627
|
+
const testCmd = options.testCmd || repo?.testCommand || "";
|
|
85628
|
+
if (!testCmd)
|
|
85629
|
+
throw new Error(
|
|
85630
|
+
`No test command: pass --test-cmd, or set one for ${repository} in Haansi.`
|
|
85631
|
+
);
|
|
85632
|
+
if (set2.tasks.length === 0) {
|
|
85633
|
+
deps.log(
|
|
85634
|
+
`No replay tasks for ${repository} yet: they need a card (replay task cards on for the organization).`
|
|
85635
|
+
);
|
|
85636
|
+
return { results: [], notValid: 0, recorded: null };
|
|
85637
|
+
}
|
|
85638
|
+
const { states } = await runCalibration(
|
|
85639
|
+
calibrateTaskOptions(options, { setupCmd, testCmd }),
|
|
85640
|
+
{ ...deps, report: deps.reportCalibration },
|
|
85641
|
+
set2
|
|
85642
|
+
);
|
|
85643
|
+
const valid = set2.tasks.filter(
|
|
85644
|
+
(t) => states.get(t.taskId) === "valid" && t.testFiles.length > 0 && t.testFiles.every(safeTestFile) && SHA.test(t.baseSha) && SHA.test(t.targetSha)
|
|
85645
|
+
);
|
|
85646
|
+
const notValid = set2.tasks.length - valid.length;
|
|
85647
|
+
let arms = options.arms;
|
|
85648
|
+
if (arms.includes("haansi")) {
|
|
85649
|
+
deps.log(
|
|
85650
|
+
"The with-Haansi arm on stored tasks needs Haansi answering as of each task's start; running the baseline arm only."
|
|
85651
|
+
);
|
|
85652
|
+
arms = arms.filter((a) => a !== "haansi");
|
|
85653
|
+
}
|
|
85654
|
+
const chosen = options.limit ? valid.slice(0, options.limit) : valid;
|
|
85655
|
+
const results = [];
|
|
85656
|
+
for (const task of chosen) {
|
|
85657
|
+
const label = task.name ?? task.taskKey;
|
|
85658
|
+
const asTask = {
|
|
85659
|
+
taskId: task.taskId,
|
|
85660
|
+
// Names the clone's directory.
|
|
85661
|
+
processId: task.taskId,
|
|
85662
|
+
name: label,
|
|
85663
|
+
repository: task.repository,
|
|
85664
|
+
baseSha: task.baseSha,
|
|
85665
|
+
targetPr: task.targetPr,
|
|
85666
|
+
targetSha: task.targetSha,
|
|
85667
|
+
testFiles: task.testFiles,
|
|
85668
|
+
context: []
|
|
85669
|
+
};
|
|
85670
|
+
for (const arm of arms) {
|
|
85671
|
+
let changed = [];
|
|
85672
|
+
try {
|
|
85673
|
+
const r = await replayArm(
|
|
85674
|
+
deps,
|
|
85675
|
+
{ ...options, setupCmd, testCmd },
|
|
85676
|
+
asTask,
|
|
85677
|
+
arm,
|
|
85678
|
+
null,
|
|
85679
|
+
(feedback) => cardPrompt(task, feedback),
|
|
85680
|
+
async (dir) => {
|
|
85681
|
+
changed = await changedFiles(deps, dir, task.baseSha);
|
|
85682
|
+
}
|
|
85683
|
+
);
|
|
85684
|
+
const overlap = overlapOf(changed, task);
|
|
85685
|
+
results.push({
|
|
85686
|
+
taskId: task.taskId,
|
|
85687
|
+
cardVersion: task.card.version,
|
|
85688
|
+
inputsFingerprint: task.inputsFingerprint,
|
|
85689
|
+
arm,
|
|
85690
|
+
passed: r.passed,
|
|
85691
|
+
attempts: r.attempts,
|
|
85692
|
+
maxAttempts: r.maxAttempts,
|
|
85693
|
+
durationMs: r.durationMs,
|
|
85694
|
+
overlap
|
|
85695
|
+
});
|
|
85696
|
+
deps.log(
|
|
85697
|
+
`${r.passed ? "pass" : "fail"} ${arm.padEnd(8)} ${label} (${r.attempts}/${r.maxAttempts} attempts; files ${pct(overlap.fileRecall)} of the target's, ${pct(overlap.filePrecision)} of its own on target)`
|
|
85698
|
+
);
|
|
85699
|
+
} catch (err2) {
|
|
85700
|
+
deps.log(
|
|
85701
|
+
`error ${arm} ${label}: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
85702
|
+
);
|
|
85703
|
+
}
|
|
85704
|
+
}
|
|
85705
|
+
}
|
|
85706
|
+
if (options.dryRun || results.length === 0)
|
|
85707
|
+
return { results, notValid, recorded: null };
|
|
85708
|
+
let recorded = 0;
|
|
85709
|
+
for (let i = 0; i < results.length; i += REPORT_CHUNK2) {
|
|
85710
|
+
const out = await deps.reportResults({
|
|
85711
|
+
agent: options.agentName,
|
|
85712
|
+
model: options.model,
|
|
85713
|
+
runRef: options.runRef,
|
|
85714
|
+
results: results.slice(i, i + REPORT_CHUNK2)
|
|
85715
|
+
});
|
|
85716
|
+
recorded += out.recorded;
|
|
85717
|
+
if (out.refused.length)
|
|
85718
|
+
deps.log(
|
|
85719
|
+
`Haansi did not record ${out.refused.length} result(s): their task's card or inputs changed during the run.`
|
|
85720
|
+
);
|
|
85721
|
+
}
|
|
85722
|
+
return { results, notValid, recorded };
|
|
85723
|
+
}
|
|
85724
|
+
var FEEDBACK_HEADER, REPORT_CHUNK2, share, pct;
|
|
85725
|
+
var init_replay_tasks = __esm({
|
|
85726
|
+
"src/commands/replay-tasks.ts"() {
|
|
85727
|
+
"use strict";
|
|
85728
|
+
init_replay_calibrate();
|
|
85729
|
+
init_replay();
|
|
85730
|
+
FEEDBACK_HEADER = "Your previous attempt did not pass the tests. Their output ends with:";
|
|
85731
|
+
REPORT_CHUNK2 = 200;
|
|
85732
|
+
share = (part, whole) => whole === 0 ? null : Math.round(part / whole * 1e3) / 1e3;
|
|
85733
|
+
pct = (v) => v === null ? "n/a" : `${Math.round(v * 100)}%`;
|
|
85734
|
+
}
|
|
85735
|
+
});
|
|
85736
|
+
|
|
85529
85737
|
// src/commands/replay.ts
|
|
85530
85738
|
var replay_exports = {};
|
|
85531
85739
|
__export(replay_exports, {
|
|
@@ -85585,8 +85793,8 @@ function parseReplayArgs(argv) {
|
|
|
85585
85793
|
else if (!sub && !a.startsWith("-")) sub = a;
|
|
85586
85794
|
else errors.push(`Unknown option: ${a}`);
|
|
85587
85795
|
}
|
|
85588
|
-
if (!/^[0-9a-f-]{36}$/i.test(options.familyId))
|
|
85589
|
-
errors.push("--family
|
|
85796
|
+
if (options.familyId && !/^[0-9a-f-]{36}$/i.test(options.familyId))
|
|
85797
|
+
errors.push("--family must be a family's id.");
|
|
85590
85798
|
if (!options.agentCmd) errors.push("--agent-cmd is required.");
|
|
85591
85799
|
if (!options.testCmd && !options.repoCommands)
|
|
85592
85800
|
errors.push(
|
|
@@ -85694,7 +85902,7 @@ async function cleanClone(deps, dir, sha, unreachable) {
|
|
|
85694
85902
|
function cleanCheckout(deps, dir, task) {
|
|
85695
85903
|
return cleanClone(deps, dir, task.baseSha, task.targetSha);
|
|
85696
85904
|
}
|
|
85697
|
-
async function replayArm(deps, options, task, arm, playbook) {
|
|
85905
|
+
async function replayArm(deps, options, task, arm, playbook, promptOf = (feedback) => replayPrompt(task, arm, feedback), inspect) {
|
|
85698
85906
|
const started = deps.now();
|
|
85699
85907
|
const dir = (0, import_node_path10.join)(
|
|
85700
85908
|
deps.workDir(),
|
|
@@ -85730,7 +85938,7 @@ async function replayArm(deps, options, task, arm, playbook) {
|
|
|
85730
85938
|
);
|
|
85731
85939
|
let feedback = null;
|
|
85732
85940
|
for (let attempt = 1; attempt <= options.attempts; attempt++) {
|
|
85733
|
-
const prompt2 =
|
|
85941
|
+
const prompt2 = promptOf(feedback);
|
|
85734
85942
|
deps.writeFile(promptFile, prompt2);
|
|
85735
85943
|
const agentAt = deps.now();
|
|
85736
85944
|
deps.log(
|
|
@@ -85764,6 +85972,7 @@ async function replayArm(deps, options, task, arm, playbook) {
|
|
|
85764
85972
|
deps.log(` ${line}`);
|
|
85765
85973
|
}
|
|
85766
85974
|
if (test.code === 0) {
|
|
85975
|
+
if (inspect) await inspect(dir);
|
|
85767
85976
|
return {
|
|
85768
85977
|
processId: task.processId,
|
|
85769
85978
|
arm,
|
|
@@ -85780,6 +85989,7 @@ async function replayArm(deps, options, task, arm, playbook) {
|
|
|
85780
85989
|
}
|
|
85781
85990
|
feedback = test.output.slice(-FEEDBACK_CHARS);
|
|
85782
85991
|
}
|
|
85992
|
+
if (inspect) await inspect(dir);
|
|
85783
85993
|
return {
|
|
85784
85994
|
processId: task.processId,
|
|
85785
85995
|
arm,
|
|
@@ -85949,6 +86159,10 @@ async function replay(argv) {
|
|
|
85949
86159
|
}
|
|
85950
86160
|
const token = resolveToken5();
|
|
85951
86161
|
const apiUrl2 = apiUrl();
|
|
86162
|
+
if (!options.familyId) {
|
|
86163
|
+
await replayStored(options, token, apiUrl2);
|
|
86164
|
+
return;
|
|
86165
|
+
}
|
|
85952
86166
|
const work = (0, import_node_fs11.mkdtempSync)((0, import_node_path10.join)((0, import_node_os10.tmpdir)(), "haansi-replay-"));
|
|
85953
86167
|
try {
|
|
85954
86168
|
const { results, skipped, recorded } = await runReplays(options, {
|
|
@@ -85983,6 +86197,48 @@ Baseline: ${passed("baseline")}/${ran("baseline")} passed \xB7 With Haansi: ${pa
|
|
|
85983
86197
|
(0, import_node_fs11.rmSync)(work, { recursive: true, force: true });
|
|
85984
86198
|
}
|
|
85985
86199
|
}
|
|
86200
|
+
async function replayStored(options, token, apiUrl2) {
|
|
86201
|
+
const { runStoredReplays: runStoredReplays2 } = await Promise.resolve().then(() => (init_replay_tasks(), replay_tasks_exports));
|
|
86202
|
+
const { cliVersion: cliVersion2 } = await Promise.resolve().then(() => (init_replay_calibrate(), replay_calibrate_exports));
|
|
86203
|
+
const work = (0, import_node_fs11.mkdtempSync)((0, import_node_path10.join)((0, import_node_os10.tmpdir)(), "haansi-replay-"));
|
|
86204
|
+
try {
|
|
86205
|
+
const { results, notValid, recorded } = await runStoredReplays2(options, {
|
|
86206
|
+
...localDeps(work),
|
|
86207
|
+
getReplaySet: (repository) => apiGet3(
|
|
86208
|
+
`/memory/replays/tasks?repository=${encodeURIComponent(repository)}`,
|
|
86209
|
+
token,
|
|
86210
|
+
apiUrl2
|
|
86211
|
+
),
|
|
86212
|
+
reportCalibration: async (body) => await apiPost2(
|
|
86213
|
+
"/memory/replays/tasks/calibration",
|
|
86214
|
+
body,
|
|
86215
|
+
token,
|
|
86216
|
+
apiUrl2
|
|
86217
|
+
),
|
|
86218
|
+
reportResults: async (body) => await apiPost2(
|
|
86219
|
+
"/memory/replays/tasks/results",
|
|
86220
|
+
body,
|
|
86221
|
+
token,
|
|
86222
|
+
apiUrl2
|
|
86223
|
+
),
|
|
86224
|
+
env: process.env,
|
|
86225
|
+
cliVersion: cliVersion2()
|
|
86226
|
+
});
|
|
86227
|
+
const passed = results.filter((r) => r.passed).length;
|
|
86228
|
+
console.log(
|
|
86229
|
+
`
|
|
86230
|
+
Baseline: ${passed}/${results.length} passed \xB7 ${notValid} task(s) not valid to replay`
|
|
86231
|
+
);
|
|
86232
|
+
console.log(
|
|
86233
|
+
recorded === null ? options.dryRun ? "Dry run: nothing reported." : "Nothing to report." : `Reported ${recorded} result(s) to Haansi.`
|
|
86234
|
+
);
|
|
86235
|
+
} catch (err2) {
|
|
86236
|
+
console.error(err2 instanceof Error ? err2.message : String(err2));
|
|
86237
|
+
process.exitCode = 1;
|
|
86238
|
+
} finally {
|
|
86239
|
+
(0, import_node_fs11.rmSync)(work, { recursive: true, force: true });
|
|
86240
|
+
}
|
|
86241
|
+
}
|
|
85986
86242
|
var import_node_child_process4, import_node_fs11, import_node_os10, import_node_path10, SHA, ARMS, FEEDBACK_CHARS, FAILURE_LINES2, REPLAY_BRANCH, USAGE2;
|
|
85987
86243
|
var init_replay = __esm({
|
|
85988
86244
|
"src/commands/replay.ts"() {
|
|
@@ -85998,7 +86254,7 @@ var init_replay = __esm({
|
|
|
85998
86254
|
FEEDBACK_CHARS = 6e3;
|
|
85999
86255
|
FAILURE_LINES2 = 8;
|
|
86000
86256
|
REPLAY_BRANCH = "replay";
|
|
86001
|
-
USAGE2 = `Usage: haansi replay run --family <id> --agent-cmd "<cmd>" --test-cmd "<cmd>"
|
|
86257
|
+
USAGE2 = `Usage: haansi replay run [--family <id>] --agent-cmd "<cmd>" --test-cmd "<cmd>"
|
|
86002
86258
|
[--setup-cmd "<cmd>"] [--attempts 3] [--arms baseline,haansi] [--limit n]
|
|
86003
86259
|
[--cutoff <date>] [--timeout-min 30]
|
|
86004
86260
|
[--agent-name <name>] [--model <name>] [--run-ref <url>] [--dry-run]
|
|
@@ -86006,6 +86262,11 @@ var init_replay = __esm({
|
|
|
86006
86262
|
|
|
86007
86263
|
haansi replay calibrate --test-cmd "<cmd>" [--setup-cmd "<cmd>"] (see --help)
|
|
86008
86264
|
|
|
86265
|
+
Without --family, runs this repository's stored replay tasks: calibrates them
|
|
86266
|
+
first, then replays the valid ones with their task card as the prompt, graded
|
|
86267
|
+
by the target's tests and where the change landed. With --family, replays that
|
|
86268
|
+
problem family's tasks with and without its playbook.
|
|
86269
|
+
|
|
86009
86270
|
--repo-commands uses the setup and test commands an org admin set for the
|
|
86010
86271
|
repository in Haansi (Settings \u2192 Data sources) for any not given here.
|
|
86011
86272
|
|
|
@@ -86231,9 +86492,10 @@ Commands:
|
|
|
86231
86492
|
digest. [--date YYYY-MM-DD] [--workstream <id>]
|
|
86232
86493
|
digest [--week|--month|--since YYYY-MM-DD]
|
|
86233
86494
|
Your weekly digest (default: the latest week)
|
|
86234
|
-
replay run --
|
|
86235
|
-
Replay
|
|
86236
|
-
|
|
86495
|
+
replay run --agent-cmd "<cmd>" --test-cmd "<cmd>" [--family <id>]
|
|
86496
|
+
Replay this repository's tasks in your CI (or a
|
|
86497
|
+
problem family's, with and without its playbook)
|
|
86498
|
+
and report the results
|
|
86237
86499
|
replay calibrate --test-cmd "<cmd>"
|
|
86238
86500
|
Check this repository's replay tasks are valid: their
|
|
86239
86501
|
tests fail at the start and pass at the fix
|