112 lines
4.3 KiB
Python
112 lines
4.3 KiB
Python
"""
|
|
One pack per commit, for whoever writes the message.
|
|
|
|
This is the interface to the expensive reader, and it is a directory of
|
|
markdown rather than a network call. The tool does not know how to reach a
|
|
model and does not want to: an agent already in this repo reads the briefs and
|
|
writes titles and bodies back into plan.json, which keeps the messages editable
|
|
before a single commit exists and keeps an API key out of a tool that otherwise
|
|
runs offline.
|
|
|
|
What travels is the reasoning already in the code — each file's opening
|
|
comment — and not the file. That is both what makes the pack cheap and what
|
|
makes the message right: a commit message reconstructed from a diff restates
|
|
the diff, and the thing worth recording was never in the diff. It was in the
|
|
comment explaining why the port offsets have to match another project's, or why
|
|
the ignore rules exist before the code they exclude.
|
|
"""
|
|
|
|
import json
|
|
|
|
from .census import INDEX_FILE, state_dir
|
|
from .order import plan_path
|
|
|
|
BRIEF_DIR = "briefs"
|
|
|
|
WHY_CHARS = 700 # an opening comment past this is an essay; the head carries it
|
|
MAX_LISTED = 40
|
|
|
|
|
|
HEADER = """# {n:02d} — {slug}
|
|
|
|
**{count} file(s), commit {n} of {total}.**
|
|
|
|
Write a title and a body for this commit, then put them in
|
|
`{plan}` under group {n} as `"title"` and `"body"`.
|
|
|
|
- The title says what this commit establishes, in the repo's own words.
|
|
- The body carries the **why** — take it from the reasoning already in the
|
|
comments below. Do not restate the diff; the diff is already in the commit.
|
|
- If a file below does not belong in this commit, move its path to another
|
|
group in plan.json. The grouping is a proposal.
|
|
"""
|
|
|
|
|
|
def _fmt_why(text):
|
|
text = (text or "").strip()
|
|
if not text:
|
|
return "_(no opening comment)_"
|
|
if len(text) > WHY_CHARS:
|
|
text = text[:WHY_CHARS].rsplit("\n", 1)[0] + "\n…"
|
|
return "\n".join("> " + line if line.strip() else ">" for line in text.split("\n"))
|
|
|
|
|
|
def write_briefs(out, quiet=False):
|
|
state = state_dir(out)
|
|
plan = json.loads(plan_path(out).read_text())
|
|
index = json.loads((state / INDEX_FILE).read_text())
|
|
files = index["files"]
|
|
groups = plan["groups"]
|
|
|
|
# Which commit each path lands in, so a dependency can be named by the
|
|
# commit that introduced it rather than by a bare path. "stands on 04" is
|
|
# the sentence the ordering exists to make true.
|
|
landed = {p: g["n"] for g in groups for p in g["paths"]}
|
|
|
|
out_dir = state / BRIEF_DIR
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
for stale in out_dir.glob("*.md"):
|
|
stale.unlink()
|
|
|
|
for g in groups:
|
|
lines = [HEADER.format(n=g["n"], slug=g["slug"], count=len(g["paths"]),
|
|
total=len(groups), plan=plan_path(out))]
|
|
|
|
earlier, later = {}, set()
|
|
for p in g["paths"]:
|
|
for dep in files.get(p, {}).get("refs", []):
|
|
n = landed.get(dep)
|
|
if n is None or dep in g["paths"]:
|
|
continue
|
|
(earlier.setdefault(n, set()).add(dep) if n < g["n"] else later.add(dep))
|
|
|
|
if earlier:
|
|
lines.append("\n## Stands on\n")
|
|
for n in sorted(earlier):
|
|
names = ", ".join(f"`{d}`" for d in sorted(earlier[n])[:MAX_LISTED])
|
|
lines.append(f"- commit {n:02d}: {names}")
|
|
if later:
|
|
# Worth stating plainly rather than hiding: it is the one thing a
|
|
# reader of the finished history would notice and the tool cannot
|
|
# fix, because the fix is a judgement about which comes first.
|
|
names = ", ".join(f"`{d}`" for d in sorted(later)[:MAX_LISTED])
|
|
lines.append("\n## Forward references (this commit names things not yet committed)\n")
|
|
lines.append(f"- {names}")
|
|
|
|
lines.append("\n## Files\n")
|
|
for p in g["paths"]:
|
|
e = files.get(p, {})
|
|
meta = f"{e.get('role', '?')}, {e.get('lines', 0)} lines"
|
|
if e.get("binary"):
|
|
meta += ", binary"
|
|
lines.append(f"\n### `{p}`\n\n_{meta}_\n")
|
|
lines.append(_fmt_why(e.get("why")))
|
|
|
|
path = out_dir / f"{g['n']:02d}-{g['slug']}.md"
|
|
path.write_text("\n".join(lines) + "\n")
|
|
|
|
if not quiet:
|
|
print(f"Wrote {len(groups)} briefs -> {out_dir}")
|
|
print(f"Read them, then write title and body into {plan_path(out)}.")
|
|
return out_dir
|