whodecided 0.1.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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/checks/gate.d.ts +10 -0
- package/dist/checks/gate.js +19 -0
- package/dist/checks/gate.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/apply.d.ts +1 -0
- package/dist/commands/apply.js +68 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/board.d.ts +6 -0
- package/dist/commands/board.js +57 -0
- package/dist/commands/board.js.map +1 -0
- package/dist/commands/distill.d.ts +18 -0
- package/dist/commands/distill.js +116 -0
- package/dist/commands/distill.js.map +1 -0
- package/dist/commands/gate.d.ts +2 -0
- package/dist/commands/gate.js +27 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/hook.d.ts +1 -0
- package/dist/commands/hook.js +189 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/recall.d.ts +19 -0
- package/dist/commands/recall.js +58 -0
- package/dist/commands/recall.js.map +1 -0
- package/dist/commands/report.d.ts +1 -0
- package/dist/commands/report.js +18 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/review.d.ts +1 -0
- package/dist/commands/review.js +211 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/scope.d.ts +17 -0
- package/dist/commands/scope.js +51 -0
- package/dist/commands/scope.js.map +1 -0
- package/dist/commands/share.d.ts +6 -0
- package/dist/commands/share.js +73 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/sync.d.ts +23 -0
- package/dist/commands/sync.js +214 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.js +80 -0
- package/dist/config.js.map +1 -0
- package/dist/distill/distiller.d.ts +15 -0
- package/dist/distill/distiller.js +92 -0
- package/dist/distill/distiller.js.map +1 -0
- package/dist/distill/prompt.d.ts +18 -0
- package/dist/distill/prompt.js +53 -0
- package/dist/distill/prompt.js.map +1 -0
- package/dist/distill/watermark.d.ts +5 -0
- package/dist/distill/watermark.js +22 -0
- package/dist/distill/watermark.js.map +1 -0
- package/dist/extract/candidates.d.ts +25 -0
- package/dist/extract/candidates.js +136 -0
- package/dist/extract/candidates.js.map +1 -0
- package/dist/git.d.ts +22 -0
- package/dist/git.js +78 -0
- package/dist/git.js.map +1 -0
- package/dist/jsonl.d.ts +14 -0
- package/dist/jsonl.js +30 -0
- package/dist/jsonl.js.map +1 -0
- package/dist/ledger/io.d.ts +30 -0
- package/dist/ledger/io.js +85 -0
- package/dist/ledger/io.js.map +1 -0
- package/dist/ledger/schema.d.ts +31 -0
- package/dist/ledger/schema.js +57 -0
- package/dist/ledger/schema.js.map +1 -0
- package/dist/patch/apply.d.ts +15 -0
- package/dist/patch/apply.js +63 -0
- package/dist/patch/apply.js.map +1 -0
- package/dist/patch/schema.d.ts +11 -0
- package/dist/patch/schema.js +21 -0
- package/dist/patch/schema.js.map +1 -0
- package/dist/render/html.d.ts +33 -0
- package/dist/render/html.js +593 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/md.d.ts +3 -0
- package/dist/render/md.js +39 -0
- package/dist/render/md.js.map +1 -0
- package/dist/render/term.d.ts +2 -0
- package/dist/render/term.js +40 -0
- package/dist/render/term.js.map +1 -0
- package/dist/trace/schema.d.ts +14 -0
- package/dist/trace/schema.js +25 -0
- package/dist/trace/schema.js.map +1 -0
- package/dist/transcript/locate.d.ts +10 -0
- package/dist/transcript/locate.js +30 -0
- package/dist/transcript/locate.js.map +1 -0
- package/dist/transcript/parser.d.ts +18 -0
- package/dist/transcript/parser.js +130 -0
- package/dist/transcript/parser.js.map +1 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +13 -0
- package/dist/validate.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { loadConfig } from "../config.js";
|
|
5
|
+
import { repoRoot } from "../git.js";
|
|
6
|
+
import { isRecord } from "../validate.js";
|
|
7
|
+
const RUNNER = /\b(vitest|jest|playwright|cypress|pytest)\b/;
|
|
8
|
+
const E2E_RUNNER = /\b(playwright|cypress)\b/;
|
|
9
|
+
export async function hook(args) {
|
|
10
|
+
if (args[0] === "install")
|
|
11
|
+
return install();
|
|
12
|
+
if (args[0] === "trace")
|
|
13
|
+
return trace();
|
|
14
|
+
if (args[0] === "autodistill")
|
|
15
|
+
return autodistill();
|
|
16
|
+
process.stderr.write("usage: wdd hook install | wdd hook trace | wdd hook autodistill\n");
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
async function install() {
|
|
20
|
+
const root = repoRoot(process.cwd());
|
|
21
|
+
if (!root) {
|
|
22
|
+
process.stderr.write("wdd hook install: not inside a git repo\n");
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
const dir = join(root, ".claude");
|
|
26
|
+
const file = join(dir, "settings.json");
|
|
27
|
+
mkdirSync(dir, { recursive: true });
|
|
28
|
+
let settings = {};
|
|
29
|
+
if (existsSync(file)) {
|
|
30
|
+
try {
|
|
31
|
+
settings = JSON.parse(readFileSync(file, "utf8"));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
process.stderr.write(`${file} is not valid JSON; fix it first\n`);
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const bin = wddAvailable() ? "wdd" : "npx -y whodecided";
|
|
39
|
+
const hooks = (settings.hooks ??= {});
|
|
40
|
+
const post = (hooks.PostToolUse ??= []);
|
|
41
|
+
const stop = (hooks.Stop ??= []);
|
|
42
|
+
let changed = false;
|
|
43
|
+
if (!JSON.stringify(post).includes("hook trace")) {
|
|
44
|
+
post.push({ matcher: "Bash", hooks: [{ type: "command", command: `${bin} hook trace` }] });
|
|
45
|
+
changed = true;
|
|
46
|
+
}
|
|
47
|
+
if (!JSON.stringify(stop).includes("hook autodistill")) {
|
|
48
|
+
stop.push({ hooks: [{ type: "command", command: `${bin} hook autodistill` }] });
|
|
49
|
+
changed = true;
|
|
50
|
+
}
|
|
51
|
+
if (changed) {
|
|
52
|
+
writeFileSync(file, JSON.stringify(settings, null, 2) + "\n");
|
|
53
|
+
process.stdout.write(`hooks installed in ${file}\n` +
|
|
54
|
+
"- PostToolUse: test runs traced to .wdd/trace.jsonl\n" +
|
|
55
|
+
"- Stop: per-turn auto-distill (no-op until .wdd/config.yaml sets distill.auto: turn)\n");
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
process.stdout.write("hooks already installed\n");
|
|
59
|
+
}
|
|
60
|
+
installRecallSkill(root, bin);
|
|
61
|
+
// Associate the memory file now so every future ruling auto-syncs, no extra step.
|
|
62
|
+
const { configureSync } = await import("./sync.js");
|
|
63
|
+
const { loadConfig } = await import("../config.js");
|
|
64
|
+
await configureSync(root, process.stdin.isTTY);
|
|
65
|
+
const targets = loadConfig(root).sync?.targets ?? [];
|
|
66
|
+
process.stdout.write(targets.length > 0
|
|
67
|
+
? `pinned precedents will sync to ${targets.join(", ")} on every ruling · change with wdd sync\n`
|
|
68
|
+
: "precedents: audit only (not written to any memory file) · change with wdd sync\n");
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Stop-hook receiver: the hook is the scheduler. If auto-distill is enabled,
|
|
73
|
+
* spawn a detached `wdd distill --quiet` and return immediately so the CC
|
|
74
|
+
* session is never blocked; the LLM call happens in the background.
|
|
75
|
+
*/
|
|
76
|
+
async function autodistill() {
|
|
77
|
+
try {
|
|
78
|
+
const payload = JSON.parse(await readStdin());
|
|
79
|
+
const cwd = isRecord(payload) && typeof payload.cwd === "string" ? payload.cwd : process.cwd();
|
|
80
|
+
const root = repoRoot(cwd);
|
|
81
|
+
if (!root)
|
|
82
|
+
return 0;
|
|
83
|
+
if (loadConfig(root).distill.auto !== "turn")
|
|
84
|
+
return 0;
|
|
85
|
+
const child = spawn(process.execPath, [process.argv[1] ?? "", "distill", "--quiet"], {
|
|
86
|
+
cwd: root,
|
|
87
|
+
detached: true,
|
|
88
|
+
stdio: "ignore",
|
|
89
|
+
});
|
|
90
|
+
child.unref();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// never fail the hook
|
|
94
|
+
}
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
function installRecallSkill(root, bin) {
|
|
98
|
+
const dir = join(root, ".claude", "skills", "recall");
|
|
99
|
+
mkdirSync(dir, { recursive: true });
|
|
100
|
+
writeFileSync(join(dir, "SKILL.md"), `---
|
|
101
|
+
name: recall
|
|
102
|
+
description: Check ratified decision precedents before making a design or technology decision. Use when choosing libraries, storage mechanisms, defaults, error handling strategies, or test scope.
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
Before making a decision where a reasonable alternative exists, check for precedent:
|
|
106
|
+
|
|
107
|
+
\`\`\`bash
|
|
108
|
+
${bin} recall <keyword>
|
|
109
|
+
\`\`\`
|
|
110
|
+
|
|
111
|
+
Always go through \`${bin} recall\`. Do NOT read \`.wdd/ledger.jsonl\` directly for precedent: the raw file also contains unreviewed distilled guesses, and treating those as authority would mean following your own unratified decisions. \`recall\` returns only what the user has sealed.
|
|
112
|
+
|
|
113
|
+
Only ruled decisions are precedent - a decision the user has sealed. \`recall\` returns those by default:
|
|
114
|
+
|
|
115
|
+
- ✅ affirmed: follow it, and cite its id (e.g. "following precedent D12") in your explanation.
|
|
116
|
+
- ❌ overturned: do NOT repeat that choice; pick the recorded alternative or ask.
|
|
117
|
+
- no ratified hit: there is no precedent yet. Use your best judgment and make the call - do NOT treat any pending/unreviewed entry as authority (that would be following your own unreviewed guess). This decision will itself be surfaced for the user to rule on later.
|
|
118
|
+
`);
|
|
119
|
+
process.stdout.write("/recall skill installed in .claude/skills/recall/\n");
|
|
120
|
+
}
|
|
121
|
+
function wddAvailable() {
|
|
122
|
+
try {
|
|
123
|
+
execFileSync("which", ["wdd"], { stdio: "ignore" });
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** PostToolUse receiver. Must never disturb the session: always exits 0, stays silent. */
|
|
131
|
+
async function trace() {
|
|
132
|
+
try {
|
|
133
|
+
const payload = JSON.parse(await readStdin());
|
|
134
|
+
if (!isRecord(payload) || payload.tool_name !== "Bash")
|
|
135
|
+
return 0;
|
|
136
|
+
const input = isRecord(payload.tool_input) ? payload.tool_input : {};
|
|
137
|
+
const command = typeof input.command === "string" ? input.command : "";
|
|
138
|
+
if (!RUNNER.test(command))
|
|
139
|
+
return 0;
|
|
140
|
+
const response = isRecord(payload.tool_response) ? payload.tool_response : {};
|
|
141
|
+
const output = [response.stdout, response.stderr].filter((s) => typeof s === "string").join("\n");
|
|
142
|
+
const cwd = typeof payload.cwd === "string" ? payload.cwd : process.cwd();
|
|
143
|
+
const root = repoRoot(cwd);
|
|
144
|
+
if (!root)
|
|
145
|
+
return 0;
|
|
146
|
+
const event = {
|
|
147
|
+
t: new Date().toISOString(),
|
|
148
|
+
type: "test_run",
|
|
149
|
+
kind: E2E_RUNNER.test(command) ? "e2e" : "unit",
|
|
150
|
+
cmd: command.slice(0, 200),
|
|
151
|
+
exit: detectExit(output),
|
|
152
|
+
...counts(output),
|
|
153
|
+
cwd,
|
|
154
|
+
};
|
|
155
|
+
const dir = join(root, ".wdd");
|
|
156
|
+
if (!existsSync(dir)) {
|
|
157
|
+
mkdirSync(dir, { recursive: true });
|
|
158
|
+
writeFileSync(join(dir, ".gitignore"), ".cache/\n");
|
|
159
|
+
}
|
|
160
|
+
appendFileSync(join(dir, "trace.jsonl"), JSON.stringify(event) + "\n");
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// never fail the hook
|
|
164
|
+
}
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
function detectExit(output) {
|
|
168
|
+
const explicit = /Exit code (\d+)/.exec(output);
|
|
169
|
+
if (explicit)
|
|
170
|
+
return Number(explicit[1]);
|
|
171
|
+
return /\b(\d+) failed/.test(output) && !/\b0 failed/.test(output) ? 1 : 0;
|
|
172
|
+
}
|
|
173
|
+
function counts(output) {
|
|
174
|
+
const pass = /(\d+) passed/.exec(output);
|
|
175
|
+
const fail = /(\d+) failed/.exec(output);
|
|
176
|
+
return {
|
|
177
|
+
...(pass ? { pass: Number(pass[1]) } : {}),
|
|
178
|
+
...(fail ? { fail: Number(fail[1]) } : {}),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function readStdin() {
|
|
182
|
+
return new Promise((resolve) => {
|
|
183
|
+
let data = "";
|
|
184
|
+
process.stdin.on("data", (d) => (data += d.toString()));
|
|
185
|
+
process.stdin.on("end", () => resolve(data));
|
|
186
|
+
setTimeout(() => resolve(data), 3000);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DecisionEntry, RatifyEntry } from "../ledger/schema.js";
|
|
2
|
+
export interface RecallHit {
|
|
3
|
+
entry: DecisionEntry;
|
|
4
|
+
verdict: "accept" | "reject" | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface RecallQuery {
|
|
7
|
+
term: string;
|
|
8
|
+
branch?: string | undefined;
|
|
9
|
+
includePending?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The precedent invariant: a hit is precedent only if a human ruled on it.
|
|
13
|
+
* Distillation is a filing, not law; the ratify line is the seal. So this
|
|
14
|
+
* excludes pending (unruled) entries by default, which stops an agent from
|
|
15
|
+
* treating its own unreviewed guess as authority. `includePending` is a
|
|
16
|
+
* human-only inspection escape hatch and is never used by the /recall skill.
|
|
17
|
+
*/
|
|
18
|
+
export declare function recallHits(entries: DecisionEntry[], ratifies: RatifyEntry[], q: RecallQuery): RecallHit[];
|
|
19
|
+
export declare function recall(args: string[]): number;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { repoRoot } from "../git.js";
|
|
2
|
+
import { ledgerPath, readLedger, verdictOf } from "../ledger/io.js";
|
|
3
|
+
const MAX_HITS = 20;
|
|
4
|
+
/**
|
|
5
|
+
* The precedent invariant: a hit is precedent only if a human ruled on it.
|
|
6
|
+
* Distillation is a filing, not law; the ratify line is the seal. So this
|
|
7
|
+
* excludes pending (unruled) entries by default, which stops an agent from
|
|
8
|
+
* treating its own unreviewed guess as authority. `includePending` is a
|
|
9
|
+
* human-only inspection escape hatch and is never used by the /recall skill.
|
|
10
|
+
*/
|
|
11
|
+
export function recallHits(entries, ratifies, q) {
|
|
12
|
+
const term = q.term.toLowerCase();
|
|
13
|
+
return entries
|
|
14
|
+
.map((entry) => ({ entry, verdict: verdictOf(ratifies, entry.id) }))
|
|
15
|
+
.filter(({ entry, verdict }) => {
|
|
16
|
+
if (q.branch && entry.branch !== q.branch)
|
|
17
|
+
return false;
|
|
18
|
+
if (!q.includePending && verdict === undefined)
|
|
19
|
+
return false;
|
|
20
|
+
return haystack(entry).includes(term);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function recall(args) {
|
|
24
|
+
const term = args.find((a) => !a.startsWith("--"));
|
|
25
|
+
if (!term) {
|
|
26
|
+
process.stderr.write("usage: wdd recall <term> [--branch <name>] [--all]\n");
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
const branch = args.includes("--branch") ? args[args.indexOf("--branch") + 1] : undefined;
|
|
30
|
+
const includePending = args.includes("--all") || args.includes("--pending");
|
|
31
|
+
const root = repoRoot(process.cwd());
|
|
32
|
+
if (!root) {
|
|
33
|
+
process.stderr.write("wdd recall: not inside a git repo\n");
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
const { entries, ratifies } = readLedger(ledgerPath(root));
|
|
37
|
+
const hits = recallHits(entries, ratifies, { term, branch, includePending });
|
|
38
|
+
if (hits.length === 0) {
|
|
39
|
+
const pending = includePending
|
|
40
|
+
? 0
|
|
41
|
+
: recallHits(entries, ratifies, { term, branch, includePending: true }).length;
|
|
42
|
+
process.stdout.write(`no ratified precedent for "${term}"`);
|
|
43
|
+
process.stdout.write(pending > 0 ? ` (${pending} pending, see --all)\n` : "\n");
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
for (const { entry, verdict } of hits.slice(0, MAX_HITS)) {
|
|
47
|
+
const mark = verdict === "accept" ? "✅" : verdict === "reject" ? "❌" : "⏳";
|
|
48
|
+
const parts = [entry.what, entry.why, entry.model, entry.branch, entry.ref].filter(Boolean);
|
|
49
|
+
process.stdout.write(`${mark} ${entry.id.padEnd(4)} ${parts.join(" · ")}\n`);
|
|
50
|
+
}
|
|
51
|
+
if (hits.length > MAX_HITS)
|
|
52
|
+
process.stdout.write(`(+${hits.length - MAX_HITS} more)\n`);
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
function haystack(e) {
|
|
56
|
+
return [e.id, e.what, e.why, e.note, ...(e.alternatives ?? [])].join(" ").toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=recall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall.js","sourceRoot":"","sources":["../../src/commands/recall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function report(args: string[]): number;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { loadWatermark, watermarkPath } from "../distill/watermark.js";
|
|
2
|
+
import { gateStatus } from "../checks/gate.js";
|
|
3
|
+
import { ledgerPath, readLedger } from "../ledger/io.js";
|
|
4
|
+
import { renderMd } from "../render/md.js";
|
|
5
|
+
import { resolveScope } from "./scope.js";
|
|
6
|
+
export function report(args) {
|
|
7
|
+
const scope = resolveScope(args, process.cwd());
|
|
8
|
+
if (!scope.root) {
|
|
9
|
+
process.stderr.write("wdd report: not inside a git repo\n");
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
const { entries, ratifies } = readLedger(ledgerPath(scope.root));
|
|
13
|
+
const scoped = scope.branch ? entries.filter((e) => !e.branch || e.branch === scope.branch) : entries;
|
|
14
|
+
const status = gateStatus(scoped, ratifies, scope.candidates, loadWatermark(watermarkPath(scope.root)));
|
|
15
|
+
process.stdout.write(renderMd(scoped, ratifies, status, scope.branch ?? "repo") + "\n");
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,MAAM,CAAC,IAAc;IACnC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACtG,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,EAAE,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACxF,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function review(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { parseTrace } from "../trace/schema.js";
|
|
6
|
+
import { createInterface } from "node:readline/promises";
|
|
7
|
+
import { distill } from "../distill/distiller.js";
|
|
8
|
+
import { spinner } from "./distill.js";
|
|
9
|
+
import { isPinned, ledgerPath, noteOf, readLedger, verdictOf } from "../ledger/io.js";
|
|
10
|
+
import { applyOps } from "../patch/apply.js";
|
|
11
|
+
import { renderWorkbench } from "../render/html.js";
|
|
12
|
+
import { renderDocket } from "../render/term.js";
|
|
13
|
+
import { IGNORED_MSG, runIncrementalDistill } from "./distill.js";
|
|
14
|
+
import { resolveScope } from "./scope.js";
|
|
15
|
+
export async function review(args) {
|
|
16
|
+
const distillOnly = args.includes("--distill-only");
|
|
17
|
+
process.stderr.write("scanning your Claude Code sessions…\n");
|
|
18
|
+
const scope = resolveScope(args, process.cwd());
|
|
19
|
+
if (scope.sessionCount === 0) {
|
|
20
|
+
process.stderr.write(`no CC sessions found for ${process.cwd()} in the last ${scope.days} days\n`);
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
process.stderr.write(`${scope.sessionCount} session(s) · ${scope.candidates.length} decision candidate(s)\n`);
|
|
24
|
+
if (distillOnly || !scope.root) {
|
|
25
|
+
if (!distillOnly) {
|
|
26
|
+
process.stderr.write("not inside a git repo; running read-only (--distill-only)\n");
|
|
27
|
+
}
|
|
28
|
+
return distillOnlyPath(scope.candidates, header(scope.sessionCount, scope.days, scope.branch), scope.config.distill);
|
|
29
|
+
}
|
|
30
|
+
const root = scope.root;
|
|
31
|
+
const result = await runIncrementalDistill(scope, root, true);
|
|
32
|
+
if (result.degraded)
|
|
33
|
+
process.stderr.write(`distiller degraded (${result.degraded}); ledger not updated\n`);
|
|
34
|
+
else if (result.added > 0)
|
|
35
|
+
process.stderr.write(`distilled +${result.added} new decision(s)\n`);
|
|
36
|
+
if (result.uncommitted)
|
|
37
|
+
process.stderr.write(IGNORED_MSG + "\n");
|
|
38
|
+
const { entries, ratifies, errors } = readLedger(ledgerPath(root));
|
|
39
|
+
for (const e of errors)
|
|
40
|
+
process.stderr.write(`ledger line ${e.line} skipped: ${e.message}\n`);
|
|
41
|
+
const scoped = scope.branch ? entries.filter((e) => !e.branch || e.branch === scope.branch) : entries;
|
|
42
|
+
if (scoped.length === 0) {
|
|
43
|
+
process.stdout.write("no decisions on the ledger for this scope\n");
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
const head = header(scope.sessionCount, scope.days, scope.branch, scoped.length);
|
|
47
|
+
// Terminal three-column + interactive ratify, only when explicitly asked.
|
|
48
|
+
if (args.includes("--term")) {
|
|
49
|
+
process.stdout.write(renderDocket(scoped, head) + "\n");
|
|
50
|
+
const pending = scoped.filter((e) => !e.aware && verdictOf(ratifies, e.id) === undefined);
|
|
51
|
+
if (pending.length === 0 || !process.stdin.isTTY || !process.stdout.isTTY)
|
|
52
|
+
return 0;
|
|
53
|
+
return ratifyLoop(root, pending);
|
|
54
|
+
}
|
|
55
|
+
// Build the workbench data once; serve it live (default) or write it static.
|
|
56
|
+
const slices = {};
|
|
57
|
+
for (const c of scope.candidates)
|
|
58
|
+
slices[c.ref] = c.slice.slice(0, 4000);
|
|
59
|
+
const tracePath = join(root, ".wdd", "trace.jsonl");
|
|
60
|
+
const traces = existsSync(tracePath) ? parseTrace(readFileSync(tracePath, "utf8")).values : [];
|
|
61
|
+
const repoName = root.split("/").pop() ?? root;
|
|
62
|
+
const repoView = {
|
|
63
|
+
repo: repoName,
|
|
64
|
+
root,
|
|
65
|
+
branch: scope.branch,
|
|
66
|
+
entries: scoped.map((e) => ({
|
|
67
|
+
...e,
|
|
68
|
+
verdict: verdictOf(ratifies, e.id),
|
|
69
|
+
...(noteOf(ratifies, e.id) ? { ruleNote: noteOf(ratifies, e.id) } : {}),
|
|
70
|
+
...(isPinned(ratifies, e.id) ? { pinned: true } : {}),
|
|
71
|
+
})),
|
|
72
|
+
traces,
|
|
73
|
+
slices,
|
|
74
|
+
};
|
|
75
|
+
const title = scope.branch ? `${repoName} · ${scope.branch}` : repoName;
|
|
76
|
+
const memory = scope.config.sync?.targets ?? [];
|
|
77
|
+
// Static snapshot: --html, or non-interactive (CI). Rulings export → wdd apply.
|
|
78
|
+
const staticMode = args.includes("--html") || !process.stdout.isTTY;
|
|
79
|
+
if (staticMode) {
|
|
80
|
+
const dir = join(root, ".wdd", "reports");
|
|
81
|
+
mkdirSync(dir, { recursive: true });
|
|
82
|
+
const file = join(dir, `${(scope.branch ?? "repo").replace(/[^a-zA-Z0-9]/g, "-")}-${dateStamp()}.html`);
|
|
83
|
+
writeFileSync(file, renderWorkbench({ title, interactive: false, live: false, memory, repos: [repoView] }));
|
|
84
|
+
process.stdout.write(`snapshot: ${file}\nread-only · open it to view or Download as Markdown · run wdd review to make rulings\n`);
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
// Default: ephemeral local server — rulings POST straight to the ledger. No
|
|
88
|
+
// daemon: it dies when you Ctrl-C. This is the only surface that accepts writes.
|
|
89
|
+
const html = renderWorkbench({ title, interactive: true, live: true, memory, repos: [repoView] });
|
|
90
|
+
return serveWorkbench(html, root, !args.includes("--no-open"));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Serve the workbench on 127.0.0.1:<random port> until Ctrl-C. GET / returns
|
|
94
|
+
* the page; POST /apply lands rulings through the one write path (applyOps).
|
|
95
|
+
* Stdlib http only, no dependency, localhost-only, no persistence.
|
|
96
|
+
*/
|
|
97
|
+
function serveWorkbench(html, root, open) {
|
|
98
|
+
const server = createServer((req, res) => {
|
|
99
|
+
if (req.method === "GET") {
|
|
100
|
+
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
101
|
+
res.end(html);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (req.method === "POST" && req.url === "/apply") {
|
|
105
|
+
let body = "";
|
|
106
|
+
req.on("data", (d) => (body += d));
|
|
107
|
+
req.on("end", () => {
|
|
108
|
+
res.setHeader("content-type", "application/json");
|
|
109
|
+
try {
|
|
110
|
+
const result = applyOps(root, JSON.parse(body));
|
|
111
|
+
res.end(JSON.stringify(typeof result === "string" ? { error: result } : result));
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
res.statusCode = 400;
|
|
115
|
+
res.end(JSON.stringify({ error: e instanceof Error ? e.message : String(e) }));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
res.statusCode = 404;
|
|
121
|
+
res.end();
|
|
122
|
+
});
|
|
123
|
+
return new Promise((resolve) => {
|
|
124
|
+
server.listen(0, "127.0.0.1", () => {
|
|
125
|
+
const addr = server.address();
|
|
126
|
+
const url = `http://127.0.0.1:${typeof addr === "object" && addr ? addr.port : 0}/`;
|
|
127
|
+
process.stdout.write(`workbench: ${url}\nrule there — Approve/Reject save straight to the ledger · Ctrl-C when done\n`);
|
|
128
|
+
if (open)
|
|
129
|
+
openInBrowser(url);
|
|
130
|
+
});
|
|
131
|
+
const stop = () => {
|
|
132
|
+
server.close();
|
|
133
|
+
resolve(0);
|
|
134
|
+
};
|
|
135
|
+
process.on("SIGINT", stop);
|
|
136
|
+
process.on("SIGTERM", stop);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** Open a URL/file in the default browser, detached; best-effort. */
|
|
140
|
+
function openInBrowser(target) {
|
|
141
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
142
|
+
try {
|
|
143
|
+
spawn(cmd, [target], { detached: true, stdio: "ignore", shell: process.platform === "win32" }).unref();
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function ratifyLoop(root, pending) {
|
|
151
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
152
|
+
const ops = [];
|
|
153
|
+
try {
|
|
154
|
+
for (const e of pending) {
|
|
155
|
+
const answer = (await rl.question(`${e.id} ${e.what} [a]ccept [r]eject [n]ote [s]kip [q]uit > `)).trim();
|
|
156
|
+
if (answer === "q")
|
|
157
|
+
break;
|
|
158
|
+
if (answer === "a")
|
|
159
|
+
ops.push({ op: "ratify", target: e.id, verdict: "accept" });
|
|
160
|
+
else if (answer === "r")
|
|
161
|
+
ops.push({ op: "ratify", target: e.id, verdict: "reject" });
|
|
162
|
+
else if (answer === "n") {
|
|
163
|
+
const note = await rl.question("note > ");
|
|
164
|
+
const verdict = (await rl.question("verdict [a/r] > ")).trim() === "r" ? "reject" : "accept";
|
|
165
|
+
ops.push({ op: "ratify", target: e.id, verdict, note });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
rl.close();
|
|
171
|
+
}
|
|
172
|
+
if (ops.length === 0)
|
|
173
|
+
return 0;
|
|
174
|
+
const result = applyOps(root, ops);
|
|
175
|
+
if (typeof result === "string") {
|
|
176
|
+
process.stderr.write(`apply failed: ${result}\n`);
|
|
177
|
+
return 1;
|
|
178
|
+
}
|
|
179
|
+
process.stdout.write(`saved ${result.applied} ruling(s)${result.commit ? ` → commit ${result.commit}` : ""}\n`);
|
|
180
|
+
if (result.uncommitted)
|
|
181
|
+
process.stderr.write(IGNORED_MSG + "\n");
|
|
182
|
+
if (result.overturned > 0)
|
|
183
|
+
process.stdout.write(`↳ ${result.overturned} rejected - AI won't repeat these; the code fix is separate work\n`);
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
async function distillOnlyPath(candidates, head, opts) {
|
|
187
|
+
if (candidates.length === 0) {
|
|
188
|
+
process.stdout.write("no decision candidates found\n");
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
const stop = spinner(`distilling ${candidates.length} candidate(s) with ${opts.cmd.join(" ")} — can take ~10-60s`);
|
|
192
|
+
const { entries, degraded } = await distill(candidates, opts);
|
|
193
|
+
stop();
|
|
194
|
+
if (degraded) {
|
|
195
|
+
process.stderr.write(`distiller degraded (${degraded}); showing raw candidates\n\n`);
|
|
196
|
+
for (const c of candidates.filter((c) => c.kind !== "turn")) {
|
|
197
|
+
process.stdout.write(` ${c.aware ? "✓" : "⚠"} [${c.kind}] ${c.summary} (${c.ref})\n`);
|
|
198
|
+
}
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
process.stdout.write(renderDocket(entries, head) + "\n");
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
function header(sessions, days, branch, count) {
|
|
205
|
+
const parts = [count !== undefined ? `${count} decisions` : "", `${sessions} session(s)`, branch ? `branch ${branch}` : `last ${days}d`].filter(Boolean);
|
|
206
|
+
return `${process.cwd().split("/").pop()} [${parts.join(" | ")}]`;
|
|
207
|
+
}
|
|
208
|
+
function dateStamp() {
|
|
209
|
+
return new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Config } from "../config.js";
|
|
2
|
+
import { type DecisionCandidate } from "../extract/candidates.js";
|
|
3
|
+
export interface Scope {
|
|
4
|
+
root?: string;
|
|
5
|
+
branch?: string;
|
|
6
|
+
days: number;
|
|
7
|
+
sessionCount: number;
|
|
8
|
+
candidates: DecisionCandidate[];
|
|
9
|
+
config: Config;
|
|
10
|
+
}
|
|
11
|
+
export declare function numberFlag(args: string[], name: string): number | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The shared read-only pipeline head: locate -> parse -> extract.
|
|
14
|
+
* On a feature branch the window starts at the merge-base ("this PR's
|
|
15
|
+
* decisions"); on the default branch it falls back to a day window.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveScope(args: string[], cwd: string): Scope;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { loadConfig } from "../config.js";
|
|
4
|
+
import { DISTILLER_SENTINEL } from "../distill/prompt.js";
|
|
5
|
+
import { branchSinceTime, currentBranch, repoRoot, worktreePaths } from "../git.js";
|
|
6
|
+
import { locateSessions } from "../transcript/locate.js";
|
|
7
|
+
import { parseTranscript } from "../transcript/parser.js";
|
|
8
|
+
import { extractCandidates } from "../extract/candidates.js";
|
|
9
|
+
export function numberFlag(args, name) {
|
|
10
|
+
const i = args.indexOf(name);
|
|
11
|
+
if (i < 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
const value = Number(args[i + 1]);
|
|
14
|
+
return Number.isFinite(value) ? value : undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The shared read-only pipeline head: locate -> parse -> extract.
|
|
18
|
+
* On a feature branch the window starts at the merge-base ("this PR's
|
|
19
|
+
* decisions"); on the default branch it falls back to a day window.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveScope(args, cwd) {
|
|
22
|
+
const root = repoRoot(cwd);
|
|
23
|
+
const config = loadConfig(root);
|
|
24
|
+
const branch = root ? currentBranch(root) : undefined;
|
|
25
|
+
const since = root ? branchSinceTime(root) : undefined;
|
|
26
|
+
const days = numberFlag(args, "--days") ??
|
|
27
|
+
(since ? Math.max(1, Math.ceil((Date.now() - Date.parse(since)) / 86_400_000)) : config.review.days);
|
|
28
|
+
const sessions = numberFlag(args, "--sessions") ?? config.review.sessions;
|
|
29
|
+
// Sessions may live under any worktree of this repo, each with its own project slug.
|
|
30
|
+
const roots = root ? [...new Set([root, ...worktreePaths(root)])] : [cwd];
|
|
31
|
+
const projectsDir = process.env.WDD_PROJECTS_DIR ? { projectsDir: process.env.WDD_PROJECTS_DIR } : {};
|
|
32
|
+
const files = [...new Set(roots.flatMap((r) => locateSessions({ cwd: r, days, sessions, ...projectsDir })))].slice(0, sessions);
|
|
33
|
+
const candidates = [];
|
|
34
|
+
let sessionCount = 0;
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const text = readFileSync(file, "utf8");
|
|
37
|
+
// Skip whodecided's own `claude -p` distiller sessions, or it audits its own output.
|
|
38
|
+
if (text.includes(DISTILLER_SENTINEL))
|
|
39
|
+
continue;
|
|
40
|
+
sessionCount++;
|
|
41
|
+
const session = basename(file, ".jsonl").slice(0, 8);
|
|
42
|
+
let events = parseTranscript(session, text);
|
|
43
|
+
if (since)
|
|
44
|
+
events = events.filter((e) => !e.t || Date.parse(e.t) >= Date.parse(since));
|
|
45
|
+
if (branch)
|
|
46
|
+
events = events.filter((e) => !e.branch || e.branch === branch);
|
|
47
|
+
candidates.push(...extractCandidates(events, config.heuristics));
|
|
48
|
+
}
|
|
49
|
+
return { ...(root ? { root } : {}), ...(branch ? { branch } : {}), days, sessionCount, candidates, config };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/commands/scope.ts"],"names":[],"mappings":"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"}
|