@sawbuck/reins 0.2.0 → 0.3.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/bin/reins.mjs +47 -1
- package/package.json +1 -1
package/bin/reins.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
|
7
7
|
import { join, dirname } from "node:path";
|
|
8
8
|
import { scan, resolveSessionPath, pairs } from "../scan.mjs";
|
|
9
9
|
import { score, backend, harvestScore } from "../judge.mjs";
|
|
10
|
-
import { harvest, resolveSessions } from "../wizard.mjs";
|
|
10
|
+
import { harvest, resolveSessions, aggregateCues } from "../wizard.mjs";
|
|
11
11
|
|
|
12
12
|
const argv = process.argv.slice(2);
|
|
13
13
|
const flag = (n) => { const i = argv.indexOf(n); return i > -1 ? argv[i + 1] : null; };
|
|
@@ -67,6 +67,52 @@ It reads every turn-pair with a model. On the local ollama default that is free;
|
|
|
67
67
|
process.exit(0);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// ---- `reins cues`: real-time cue inventory. Classify THIS session's turns into the cue
|
|
71
|
+
// structure and accumulate .sawbuck/cues.json. --append scores only the new turns since last
|
|
72
|
+
// run (the per-turn path), and carries cues across sessions in this repo. One judge call per
|
|
73
|
+
// new turn; free on local ollama. The batch cross-session cold-start is `reins wizard`. ----
|
|
74
|
+
if (argv[0] === "cues") {
|
|
75
|
+
if (has("--help") || has("-h")) {
|
|
76
|
+
process.stdout.write(`reins cues: accumulate your cue inventory as you work
|
|
77
|
+
|
|
78
|
+
Usage: reins cues [--append] [--session <path>] [--judge <b>] [--max N] [--json]
|
|
79
|
+
|
|
80
|
+
--append score only the new turns since the last run, merge into .sawbuck/cues.json
|
|
81
|
+
(the per-turn path; carries cues across sessions in this repo)
|
|
82
|
+
--max N without --append, cap the turns scored (default 400)
|
|
83
|
+
--judge <b> ollama:<model> (default, free, local) | haiku | anthropic:<model> | openai:<model>
|
|
84
|
+
|
|
85
|
+
Free on the local ollama default. Seed from your whole history once with: reins wizard.
|
|
86
|
+
`);
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
89
|
+
if (flag("--judge")) process.env.SAWBUCK_JUDGE = flag("--judge");
|
|
90
|
+
const b = backend();
|
|
91
|
+
const sess = resolveSessionPath(flag("--session"));
|
|
92
|
+
if (!sess) { process.stderr.write("reins cues: no session transcript found\n"); process.exit(2); }
|
|
93
|
+
let ctext = ""; try { ctext = readFileSync(sess, "utf8"); } catch { process.stderr.write("reins cues: cannot read " + sess + "\n"); process.exit(2); }
|
|
94
|
+
const allC = pairs(ctext);
|
|
95
|
+
const cout = join(process.cwd(), ".sawbuck", "cues.json");
|
|
96
|
+
let prior = { session: "", lastPairs: 0, items: [] };
|
|
97
|
+
if (has("--append")) { try { const p = JSON.parse(readFileSync(cout, "utf8")); if (p && Array.isArray(p.items)) prior = { session: p.session || "", lastPairs: p.lastPairs || 0, items: p.items }; } catch { /* fresh */ } }
|
|
98
|
+
const startIdx = has("--append") && prior.session === sess ? prior.lastPairs : 0; // same session = resume; new session = score all its pairs
|
|
99
|
+
let fresh = allC.slice(startIdx);
|
|
100
|
+
if (!has("--append")) { const m = parseInt(flag("--max"), 10) || 400; if (fresh.length > m) fresh = fresh.slice(-m); }
|
|
101
|
+
const items = has("--append") ? prior.items.slice() : [];
|
|
102
|
+
const sid = sess.split("/").pop();
|
|
103
|
+
for (const { prior: a, user: u } of fresh) { let r = null; try { r = await harvestScore(a, u); } catch {} items.push({ session: sid, result: r }); }
|
|
104
|
+
const capped = items.slice(-1500);
|
|
105
|
+
const agg = aggregateCues(capped);
|
|
106
|
+
const rec = { at: new Date().toISOString(), backend: b, session: sess, lastPairs: allC.length, pairs: capped.length, ...agg, items: capped };
|
|
107
|
+
try { mkdirSync(dirname(cout), { recursive: true }); writeFileSync(cout, JSON.stringify(rec, null, 2) + "\n"); } catch { process.stderr.write("reins cues: could not write " + cout + "\n"); }
|
|
108
|
+
if (has("--json")) { const { items: _omit, ...pub } = rec; process.stdout.write(JSON.stringify(pub, null, 2) + "\n"); process.exit(0); }
|
|
109
|
+
const top = agg.cues.filter((c) => c.count >= 2 || c.gen > 0).slice(0, 10);
|
|
110
|
+
process.stdout.write(`\n reins · cues (judge: ${b})\n ${agg.steers} steers over ${agg.scored} scored turns · ${top.length} cues\n`);
|
|
111
|
+
for (const c of top) process.stdout.write(` ${("[" + c.axis + "]").padEnd(12)} ${(c.cue || "(unnamed)").padEnd(32)} · ${c.sessions} sess · ${c.count}x\n`);
|
|
112
|
+
process.stdout.write(` wrote ${cout}\n\n`);
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
|
|
70
116
|
if (has("--help") || has("-h")) {
|
|
71
117
|
process.stdout.write(`reins: measure how much you steer your agent this session
|
|
72
118
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sawbuck/reins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Reins: measure how much you steer your AI coding agent. A per-turn steering-pressure judge over your session transcript, pluggable backend (Haiku / local ollama / any OpenAI-compatible). The LLM half of the reins steering layer; keeps sawbuck's core offline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|