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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kai Zhu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# whodecided
|
|
2
|
+
|
|
3
|
+
> *because you rubber-stamped 5 decisions yesterday and don't know it.*
|
|
4
|
+
|
|
5
|
+
Your AI coding agent makes dozens of silent decisions per session - it stored the token in localStorage, skipped an edge case, defaulted page size to 20. You never saw the choice, and the diff won't show it. And half the time *you* "decided" by hitting `y` in 1.2 seconds.
|
|
6
|
+
|
|
7
|
+
**whodecided** distills those decisions out of your Claude Code / Codex sessions into a one-screen ledger you rule on like a judge. Approve or reject each; the ones you approve become precedent your agents follow next time instead of guessing.
|
|
8
|
+
|
|
9
|
+
It's a thin CLI + a `.wdd/` folder of plain text in your repo. No server, no database, no API keys - the distiller shells out to your already-authenticated `claude` / `codex` CLI.
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd your-project
|
|
15
|
+
npx whodecided review --distill-only # read-only, zero config: run over your EXISTING sessions
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That's the demo: it reads `~/.claude/projects/*.jsonl` and lists the decisions you didn't know you made. If a line makes your spine tingle, install it for real:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm i -g whodecided # gives you `wdd`
|
|
22
|
+
wdd hook install # trace test runs, pick a memory file for rules
|
|
23
|
+
wdd review # distill + open the workbench; Approve/Reject saves to the ledger
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## The loop
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
A decision happens (agent session / your keypress)
|
|
30
|
+
│ hooks auto-trace · transcript kept
|
|
31
|
+
▼
|
|
32
|
+
distill claude -p / codex exec → ledger (≤10 per branch, the "why" recovered from the transcript)
|
|
33
|
+
▼
|
|
34
|
+
review one screen, three columns:
|
|
35
|
+
⚠ AI decided, never asked
|
|
36
|
+
⚠ you didn't read (the 1.2s y)
|
|
37
|
+
✓ you decided
|
|
38
|
+
Approve / Reject each · pin the core ones as rules
|
|
39
|
+
▼
|
|
40
|
+
recall ratified rules → injected into the next task (CLAUDE.md / AGENTS.md + /recall)
|
|
41
|
+
└──→ the same decision never gets guessed twice
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The audit unit is the **branch** - `wdd review` covers the decisions inside the current PR.
|
|
45
|
+
|
|
46
|
+
## Commands
|
|
47
|
+
|
|
48
|
+
| Command | What it does |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `wdd review` | Distill, open the workbench, rule (Approve/Reject saves straight to the ledger). `--term` terminal flow, `--distill-only` read-only demo, `--html` static snapshot |
|
|
51
|
+
| `wdd recall <term>` | Search ruled precedent (only what you've ratified) |
|
|
52
|
+
| `wdd gate` | Merge gate as an exit code (ledger fresh + all silent decisions ruled); for pre-push / CI |
|
|
53
|
+
| `wdd report --md` | Audit report for a PR description |
|
|
54
|
+
| `wdd board [dirs...]` | Read-only multi-repo overview page |
|
|
55
|
+
| `wdd hook install` | Install hooks + `/recall` skill, and choose where rules are written |
|
|
56
|
+
| `wdd share <repo\|local>` | Whether `.wdd/` is tracked by git or kept local |
|
|
57
|
+
| `wdd sync` | Change / refresh the memory-file target for rules |
|
|
58
|
+
|
|
59
|
+
## How it works
|
|
60
|
+
|
|
61
|
+
**What counts as a decision:** a reasonable alternative existed, and choosing it would change behavior, security, or maintenance cost. Mechanical actions don't count.
|
|
62
|
+
|
|
63
|
+
**One ledger entry** (append-only jsonl; your ruling is a separate appended line, entries are never rewritten):
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{"id":"D1","what":"token → localStorage","why":"simplest, no SSR","by":"agent","aware":false,
|
|
67
|
+
"alternatives":["httpOnly cookie"],"files":["src/auth.ts"],"ref":"tx:a1b2:1042"}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`ref` points back into the transcript, so the ledger never re-narrates the session. Only decisions you *ruled on* become precedent - unreviewed guesses never leak into agent memory.
|
|
71
|
+
|
|
72
|
+
**Review before merge, not after.** Overturning a decision pre-merge is a cheap fix in the worktree; post-merge it's a new PR or a migration.
|
|
73
|
+
|
|
74
|
+
## Design constraints
|
|
75
|
+
|
|
76
|
+
- **No server, no database, no daemon.** The truth is plain text in your repo; `rm -rf` the tool and it all stays readable with cat/jq/grep.
|
|
77
|
+
- **It never commits for you** by default - it writes files and leaves your git history alone (opt in with `commit: on`).
|
|
78
|
+
- **Zero API keys.** The one LLM consumer shells out to your `claude` / `codex` CLI; model follows your CLI's default.
|
|
79
|
+
- **One screen.** Every default output fits a screen; ≤10 decisions per branch.
|
|
80
|
+
- Single runtime dependency (`yaml`); the HTML workbench is a self-contained file (embedded JSON, vanilla JS, no CDN, no build).
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DecisionCandidate } from "../extract/candidates.js";
|
|
2
|
+
import type { DecisionEntry, RatifyEntry } from "../ledger/schema.js";
|
|
3
|
+
import type { Watermark } from "../distill/watermark.js";
|
|
4
|
+
export interface GateStatus {
|
|
5
|
+
fresh: boolean;
|
|
6
|
+
staleSessions: string[];
|
|
7
|
+
pendingSilent: string[];
|
|
8
|
+
green: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function gateStatus(entries: DecisionEntry[], ratifies: RatifyEntry[], candidates: DecisionCandidate[], watermark: Watermark): GateStatus;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { verdictOf } from "../ledger/io.js";
|
|
2
|
+
export function gateStatus(entries, ratifies, candidates, watermark) {
|
|
3
|
+
const stale = new Set();
|
|
4
|
+
for (const c of candidates) {
|
|
5
|
+
const [, session, line] = c.ref.split(":");
|
|
6
|
+
if (session && Number(line) > (watermark[session] ?? 0))
|
|
7
|
+
stale.add(session);
|
|
8
|
+
}
|
|
9
|
+
const pendingSilent = entries
|
|
10
|
+
.filter((e) => !e.aware && verdictOf(ratifies, e.id) === undefined)
|
|
11
|
+
.map((e) => e.id);
|
|
12
|
+
return {
|
|
13
|
+
fresh: stale.size === 0,
|
|
14
|
+
staleSessions: [...stale],
|
|
15
|
+
pendingSilent,
|
|
16
|
+
green: stale.size === 0 && pendingSilent.length === 0,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/checks/gate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C,MAAM,UAAU,UAAU,CACxB,OAAwB,EACxB,QAAuB,EACvB,UAA+B,EAC/B,SAAoB;IAEpB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,aAAa,GAAG,OAAO;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;SAClE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpB,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC;QACvB,aAAa,EAAE,CAAC,GAAG,KAAK,CAAC;QACzB,aAAa;QACb,KAAK,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;KACtD,CAAC;AACJ,CAAC"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const USAGE = `whodecided (wdd) - common law for agentic coding
|
|
3
|
+
|
|
4
|
+
Usage: wdd <command> [args]
|
|
5
|
+
|
|
6
|
+
Everyday:
|
|
7
|
+
review Distill, open the workbench, rule (Approve/Reject save straight to the ledger).
|
|
8
|
+
--term terminal flow · --distill-only zero-config read-only demo · --html static snapshot
|
|
9
|
+
recall <term> Search ruled precedent (only decisions you've ratified)
|
|
10
|
+
gate Two-green merge gate (exit 0 = all green); for pre-push / CI
|
|
11
|
+
|
|
12
|
+
Setup (once):
|
|
13
|
+
hook install Install CC hooks + /recall skill, and pick the memory file for precedents
|
|
14
|
+
share <repo|local> Audit travels with the repo (committed) or stays local
|
|
15
|
+
sync Change/refresh the memory-file target (auto-syncs on each ruling otherwise)
|
|
16
|
+
|
|
17
|
+
Output & collaboration:
|
|
18
|
+
report [--md] Audit report for a PR description
|
|
19
|
+
board [dirs...] Read-only multi-repo overview page
|
|
20
|
+
apply [patch] Land a static-snapshot patch (the live workbench saves directly)
|
|
21
|
+
|
|
22
|
+
Internal (run by hooks):
|
|
23
|
+
distill Headless incremental distill
|
|
24
|
+
hook trace | autodistill PostToolUse / Stop receivers
|
|
25
|
+
`;
|
|
26
|
+
const commands = ["review", "apply", "recall", "gate", "report", "board", "share", "sync", "distill", "hook"];
|
|
27
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
28
|
+
if (!command || command === "--help" || command === "-h") {
|
|
29
|
+
process.stdout.write(USAGE);
|
|
30
|
+
process.exit(command ? 0 : 1);
|
|
31
|
+
}
|
|
32
|
+
if (!commands.includes(command)) {
|
|
33
|
+
process.stderr.write(`wdd: unknown command "${command}"\n\n${USAGE}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (command === "review") {
|
|
37
|
+
const { review } = await import("./commands/review.js");
|
|
38
|
+
process.exit(await review(rest));
|
|
39
|
+
}
|
|
40
|
+
if (command === "apply") {
|
|
41
|
+
const { apply } = await import("./commands/apply.js");
|
|
42
|
+
process.exit(apply(rest));
|
|
43
|
+
}
|
|
44
|
+
if (command === "recall") {
|
|
45
|
+
const { recall } = await import("./commands/recall.js");
|
|
46
|
+
process.exit(recall(rest));
|
|
47
|
+
}
|
|
48
|
+
if (command === "gate") {
|
|
49
|
+
const { gate } = await import("./commands/gate.js");
|
|
50
|
+
process.exit(gate(rest));
|
|
51
|
+
}
|
|
52
|
+
if (command === "report") {
|
|
53
|
+
const { report } = await import("./commands/report.js");
|
|
54
|
+
process.exit(report(rest));
|
|
55
|
+
}
|
|
56
|
+
if (command === "board") {
|
|
57
|
+
const { board } = await import("./commands/board.js");
|
|
58
|
+
process.exit(board(rest));
|
|
59
|
+
}
|
|
60
|
+
if (command === "share") {
|
|
61
|
+
const { share } = await import("./commands/share.js");
|
|
62
|
+
process.exit(share(rest));
|
|
63
|
+
}
|
|
64
|
+
if (command === "sync") {
|
|
65
|
+
const { sync } = await import("./commands/sync.js");
|
|
66
|
+
process.exit(await sync(rest));
|
|
67
|
+
}
|
|
68
|
+
if (command === "distill") {
|
|
69
|
+
const { distillCmd } = await import("./commands/distill.js");
|
|
70
|
+
process.exit(await distillCmd(rest));
|
|
71
|
+
}
|
|
72
|
+
if (command === "hook") {
|
|
73
|
+
const { hook } = await import("./commands/hook.js");
|
|
74
|
+
process.exit(await hook(rest));
|
|
75
|
+
}
|
|
76
|
+
process.stderr.write(`wdd ${command}: not implemented yet (see SPEC.md section 8)\n`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function apply(args: string[]): number;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { repoRoot } from "../git.js";
|
|
5
|
+
import { applyOps } from "../patch/apply.js";
|
|
6
|
+
import { parsePatch } from "../patch/schema.js";
|
|
7
|
+
import { IGNORED_MSG } from "./distill.js";
|
|
8
|
+
export function apply(args) {
|
|
9
|
+
const root = repoRoot(process.cwd());
|
|
10
|
+
if (!root) {
|
|
11
|
+
process.stderr.write("wdd apply: not inside a git repo\n");
|
|
12
|
+
return 1;
|
|
13
|
+
}
|
|
14
|
+
// With no path, pick up the patch the workbench just exported (newest in Downloads).
|
|
15
|
+
const file = args.find((a) => !a.startsWith("--")) ?? findExportedPatch();
|
|
16
|
+
if (!file) {
|
|
17
|
+
process.stderr.write("wdd apply: no patch given and none found in Downloads.\n" +
|
|
18
|
+
"In the workbench, rule on decisions and click Export, then run `wdd apply` again.\n");
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
let text;
|
|
22
|
+
try {
|
|
23
|
+
text = readFileSync(file, "utf8");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
process.stderr.write(`cannot read ${file}\n`);
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
if (!args.some((a) => !a.startsWith("--")))
|
|
30
|
+
process.stdout.write(`applying ${file}\n`);
|
|
31
|
+
const { values, errors } = parsePatch(text);
|
|
32
|
+
if (errors.length > 0) {
|
|
33
|
+
for (const e of errors)
|
|
34
|
+
process.stderr.write(`patch line ${e.line}: ${e.message}\n`);
|
|
35
|
+
process.stderr.write("patch rejected, nothing written\n");
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
const result = applyOps(root, values);
|
|
39
|
+
if (typeof result === "string") {
|
|
40
|
+
process.stderr.write(`patch rejected, nothing written: ${result}\n`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
process.stdout.write(`saved ${result.applied} ruling(s)${result.skipped ? `, ${result.skipped} unchanged` : ""}${result.commit ? ` → commit ${result.commit}` : ""}\n`);
|
|
44
|
+
if (result.uncommitted)
|
|
45
|
+
process.stderr.write(IGNORED_MSG + "\n");
|
|
46
|
+
if (result.overturned > 0)
|
|
47
|
+
process.stdout.write(`↳ ${result.overturned} rejected - AI won't repeat these; the code fix is separate work\n`);
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
/** The workbench downloads review.patch.jsonl; grab the newest one from Downloads. */
|
|
51
|
+
function findExportedPatch() {
|
|
52
|
+
const dir = join(homedir(), "Downloads");
|
|
53
|
+
let names;
|
|
54
|
+
try {
|
|
55
|
+
names = readdirSync(dir);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const cutoff = Date.now() - 60 * 60 * 1000; // only very recent exports, avoid stale
|
|
61
|
+
return names
|
|
62
|
+
.filter((n) => n.endsWith(".patch.jsonl"))
|
|
63
|
+
.map((n) => ({ path: join(dir, n), mtime: statSync(join(dir, n)).mtimeMs }))
|
|
64
|
+
.filter((f) => f.mtime >= cutoff)
|
|
65
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
66
|
+
.map((f) => f.path)[0];
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { gateStatus } from "../checks/gate.js";
|
|
4
|
+
import { loadWatermark, watermarkPath } from "../distill/watermark.js";
|
|
5
|
+
import { ledgerPath, readLedger, verdictOf } from "../ledger/io.js";
|
|
6
|
+
import { renderWorkbench } from "../render/html.js";
|
|
7
|
+
import { parseTrace } from "../trace/schema.js";
|
|
8
|
+
import { resolveScope } from "./scope.js";
|
|
9
|
+
/**
|
|
10
|
+
* Read-only multi-repo overview: one static page aggregating every repo's
|
|
11
|
+
* ledger, traces, and gate status. No distilling, no LLM calls; rulings
|
|
12
|
+
* happen inside each repo via `wdd review`.
|
|
13
|
+
*/
|
|
14
|
+
export function board(args) {
|
|
15
|
+
const explicit = args.filter((a) => !a.startsWith("--") && args[args.indexOf(a) - 1] !== "--out");
|
|
16
|
+
const outIdx = args.indexOf("--out");
|
|
17
|
+
const out = outIdx >= 0 ? (args[outIdx + 1] ?? "wdd-board.html") : "wdd-board.html";
|
|
18
|
+
const roots = (explicit.length > 0 ? explicit.map((p) => resolve(p)) : discover(process.cwd())).filter((p) => existsSync(ledgerPath(p)));
|
|
19
|
+
if (roots.length === 0) {
|
|
20
|
+
process.stderr.write("no repos with a .wdd/ledger.jsonl found (pass paths explicitly or run in their parent dir)\n");
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
const repos = roots.map((root) => {
|
|
24
|
+
const scope = resolveScope([], root);
|
|
25
|
+
const { entries, ratifies } = readLedger(ledgerPath(root));
|
|
26
|
+
const scoped = scope.branch ? entries.filter((e) => !e.branch || e.branch === scope.branch) : entries;
|
|
27
|
+
const tracePath = join(root, ".wdd", "trace.jsonl");
|
|
28
|
+
const slices = {};
|
|
29
|
+
for (const c of scope.candidates)
|
|
30
|
+
slices[c.ref] = c.slice.slice(0, 4000);
|
|
31
|
+
return {
|
|
32
|
+
repo: basename(root),
|
|
33
|
+
root,
|
|
34
|
+
branch: scope.branch,
|
|
35
|
+
entries: scoped.map((e) => ({ ...e, verdict: verdictOf(ratifies, e.id) })),
|
|
36
|
+
traces: existsSync(tracePath) ? parseTrace(readFileSync(tracePath, "utf8")).values : [],
|
|
37
|
+
slices,
|
|
38
|
+
gate: gateStatus(scoped, ratifies, scope.candidates, loadWatermark(watermarkPath(root))),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
const pending = repos.reduce((s, r) => s + r.entries.filter((e) => !e.verdict).length, 0);
|
|
42
|
+
writeFileSync(out, renderWorkbench({ title: `board · ${repos.length} repos`, interactive: false, repos }));
|
|
43
|
+
process.stdout.write(`board written: ${out} (${repos.length} repos, ${pending} pending rulings)\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
/** Default discovery: immediate subdirectories of cwd that carry a ledger. */
|
|
47
|
+
function discover(cwd) {
|
|
48
|
+
try {
|
|
49
|
+
return readdirSync(cwd, { withFileTypes: true })
|
|
50
|
+
.filter((d) => d.isDirectory() && !d.name.startsWith("."))
|
|
51
|
+
.map((d) => join(cwd, d.name));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.js","sourceRoot":"","sources":["../../src/commands/board.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Scope } from "./scope.js";
|
|
2
|
+
export interface DistillRunResult {
|
|
3
|
+
added: number;
|
|
4
|
+
degraded?: string;
|
|
5
|
+
uncommitted?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Incremental distill: everything past the watermark, deduped by ref,
|
|
9
|
+
* appended and committed. Shared by `wdd review` and headless `wdd distill`
|
|
10
|
+
* (which the Stop hook spawns for near-real-time logging).
|
|
11
|
+
*/
|
|
12
|
+
export declare function runIncrementalDistill(scope: Scope, root: string, progress?: boolean): Promise<DistillRunResult>;
|
|
13
|
+
/** Shown when .wdd is gitignored: data is safe on disk, just not versioned. */
|
|
14
|
+
export declare const IGNORED_MSG: string;
|
|
15
|
+
/** `wdd distill`: headless incremental distill, safe to run from hooks. */
|
|
16
|
+
export declare function distillCmd(args: string[]): Promise<number>;
|
|
17
|
+
/** Minimal stderr spinner while a blocking step runs; returns a stop function. */
|
|
18
|
+
export declare function spinner(label: string): () => void;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { distill } from "../distill/distiller.js";
|
|
3
|
+
import { loadWatermark, saveWatermark, watermarkPath } from "../distill/watermark.js";
|
|
4
|
+
import { commitFiles } from "../git.js";
|
|
5
|
+
import { appendLedgerLines, ledgerPath, nextDecisionNumber, readLedger } from "../ledger/io.js";
|
|
6
|
+
import { resolveScope } from "./scope.js";
|
|
7
|
+
/**
|
|
8
|
+
* Incremental distill: everything past the watermark, deduped by ref,
|
|
9
|
+
* appended and committed. Shared by `wdd review` and headless `wdd distill`
|
|
10
|
+
* (which the Stop hook spawns for near-real-time logging).
|
|
11
|
+
*/
|
|
12
|
+
export async function runIncrementalDistill(scope, root, progress = false) {
|
|
13
|
+
const wmFile = watermarkPath(root);
|
|
14
|
+
const watermark = loadWatermark(wmFile);
|
|
15
|
+
const fresh = scope.candidates.filter((c) => lineOf(c.ref) > (watermark[sessionOf(c.ref)] ?? 0));
|
|
16
|
+
if (fresh.length === 0) {
|
|
17
|
+
if (progress)
|
|
18
|
+
process.stderr.write("no new decisions since last review\n");
|
|
19
|
+
return { added: 0 };
|
|
20
|
+
}
|
|
21
|
+
const stop = progress
|
|
22
|
+
? spinner(`distilling ${fresh.length} new candidate(s) with ${scope.config.distill.cmd.join(" ")} — can take ~10-60s`)
|
|
23
|
+
: () => { };
|
|
24
|
+
const { entries, degraded } = await distill(fresh, scope.config.distill);
|
|
25
|
+
stop();
|
|
26
|
+
if (degraded)
|
|
27
|
+
return { added: 0, degraded };
|
|
28
|
+
let added = 0;
|
|
29
|
+
if (entries.length > 0) {
|
|
30
|
+
const file = ledgerPath(root);
|
|
31
|
+
const existing = readLedger(file).entries;
|
|
32
|
+
const existingRefs = new Set(existing.map((e) => e.ref));
|
|
33
|
+
const novel = entries.filter((e) => !existingRefs.has(e.ref));
|
|
34
|
+
let n = nextDecisionNumber(existing);
|
|
35
|
+
const byRef = new Map(scope.candidates.map((c) => [c.ref, c]));
|
|
36
|
+
const numbered = novel.map((e) => {
|
|
37
|
+
const c = byRef.get(e.ref);
|
|
38
|
+
return {
|
|
39
|
+
...e,
|
|
40
|
+
id: `D${n++}`,
|
|
41
|
+
...(scope.branch ? { branch: scope.branch } : {}),
|
|
42
|
+
...(c?.t ? { t: c.t } : {}),
|
|
43
|
+
...(c?.cwd ? { cwd: c.cwd } : {}),
|
|
44
|
+
// The model is the decider only for agent decisions; for a user
|
|
45
|
+
// decision the human decided, so recording a model would mislead.
|
|
46
|
+
...(c?.model && e.by === "agent" ? { model: c.model } : {}),
|
|
47
|
+
...(c?.latencyMs !== undefined && e.by === "user" ? { latencyMs: c.latencyMs } : {}),
|
|
48
|
+
...(c?.files && c.files.length ? { files: c.files } : {}),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
appendLedgerLines(file, numbered);
|
|
52
|
+
added = numbered.length;
|
|
53
|
+
// Auto-commit only when the user opted in; otherwise leave it in the tree.
|
|
54
|
+
if (scope.config.share === "repo" && scope.config.commit === "on") {
|
|
55
|
+
const commit = commitFiles(root, [relative(root, file)], `wdd distill: +${numbered.length} decisions`);
|
|
56
|
+
if (commit.ignored) {
|
|
57
|
+
advanceWatermark(watermark, scope.candidates);
|
|
58
|
+
saveWatermark(wmFile, watermark);
|
|
59
|
+
return { added, uncommitted: true };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
advanceWatermark(watermark, scope.candidates);
|
|
64
|
+
saveWatermark(wmFile, watermark);
|
|
65
|
+
return { added };
|
|
66
|
+
}
|
|
67
|
+
/** Shown when .wdd is gitignored: data is safe on disk, just not versioned. */
|
|
68
|
+
export const IGNORED_MSG = "⚠ .wdd is gitignored, so the audit trail is written to disk but NOT committed.\n" +
|
|
69
|
+
" The audit is meant to travel with your code - remove `.wdd` from .gitignore to version it.\n" +
|
|
70
|
+
" (Or keep it local-only; your ledger stays readable at .wdd/ledger.jsonl either way.)";
|
|
71
|
+
/** `wdd distill`: headless incremental distill, safe to run from hooks. */
|
|
72
|
+
export async function distillCmd(args) {
|
|
73
|
+
const quiet = args.includes("--quiet");
|
|
74
|
+
const scope = resolveScope(args, process.cwd());
|
|
75
|
+
if (!scope.root) {
|
|
76
|
+
if (!quiet)
|
|
77
|
+
process.stderr.write("wdd distill: not inside a git repo\n");
|
|
78
|
+
return quiet ? 0 : 1;
|
|
79
|
+
}
|
|
80
|
+
const result = await runIncrementalDistill(scope, scope.root);
|
|
81
|
+
if (!quiet) {
|
|
82
|
+
if (result.degraded)
|
|
83
|
+
process.stderr.write(`distiller degraded: ${result.degraded}\n`);
|
|
84
|
+
if (result.uncommitted)
|
|
85
|
+
process.stderr.write(IGNORED_MSG + "\n");
|
|
86
|
+
process.stdout.write(`+${result.added} decisions\n`);
|
|
87
|
+
}
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
/** Minimal stderr spinner while a blocking step runs; returns a stop function. */
|
|
91
|
+
export function spinner(label) {
|
|
92
|
+
if (!process.stderr.isTTY) {
|
|
93
|
+
process.stderr.write(label + "\n");
|
|
94
|
+
return () => { };
|
|
95
|
+
}
|
|
96
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
97
|
+
let i = 0;
|
|
98
|
+
const timer = setInterval(() => process.stderr.write(`\r${frames[i++ % frames.length]} ${label}`), 90);
|
|
99
|
+
return () => {
|
|
100
|
+
clearInterval(timer);
|
|
101
|
+
process.stderr.write("\r\x1b[K"); // clear the spinner line
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function sessionOf(ref) {
|
|
105
|
+
return ref.split(":")[1] ?? "";
|
|
106
|
+
}
|
|
107
|
+
function lineOf(ref) {
|
|
108
|
+
return Number(ref.split(":")[2] ?? 0);
|
|
109
|
+
}
|
|
110
|
+
function advanceWatermark(watermark, candidates) {
|
|
111
|
+
for (const c of candidates) {
|
|
112
|
+
const s = sessionOf(c.ref);
|
|
113
|
+
watermark[s] = Math.max(watermark[s] ?? 0, lineOf(c.ref));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=distill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distill.js","sourceRoot":"","sources":["../../src/commands/distill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { resolveScope } from "./scope.js";
|
|
5
|
+
/** Deterministic, read-only, no LLM: safe and free to run in CI. */
|
|
6
|
+
export function gate(args) {
|
|
7
|
+
const scope = resolveScope(args, process.cwd());
|
|
8
|
+
if (!scope.root) {
|
|
9
|
+
process.stderr.write("wdd gate: 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
|
+
if (status.green) {
|
|
16
|
+
process.stdout.write("gate: green (ledger fresh, all silent decisions ruled)\n");
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
if (!status.fresh) {
|
|
20
|
+
process.stdout.write(`✗ ledger stale: undistilled activity in session(s) ${status.staleSessions.join(", ")} → run wdd review\n`);
|
|
21
|
+
}
|
|
22
|
+
for (const id of status.pendingSilent) {
|
|
23
|
+
process.stdout.write(`✗ silent decision pending ruling: ${id}\n`);
|
|
24
|
+
}
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/commands/gate.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,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,oEAAoE;AACpE,MAAM,UAAU,IAAI,CAAC,IAAc;IACjC,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,mCAAmC,CAAC,CAAC;QAC1D,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,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QACjF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sDAAsD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACnI,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,EAAE,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function hook(args: string[]): Promise<number>;
|