Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/planning/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "planning",
"version": "0.56.3",
"version": "0.57.0",
"userConfig": {
"surface": {
"type": "string",
Expand Down
17 changes: 17 additions & 0 deletions plugins/planning/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
All notable changes to the `planning` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.57.0] - 2026-10-01

### Added

- **`round.sh stop` ends the data dir's `watch.sh`.** Each poll sends the watcher's process id, the lease records it, and `stop` signals it only when its command line is a `watch.sh` for that data dir (nothing is signaled on Windows). A poll refused after `stop` exits 3 at once instead of retrying ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **`apply` warns when no watcher holds the lease.** It still writes and exits 0, and prints `no watcher armed; N unhandled events` to stderr ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **`round.sh status` prints a `round drift:` line for a seeded question whose stored round differs from its ledger cell, and `repair-rounds` rewrites only those rounds** ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **`note-reply --needs-answer` pins a Notes line as a loose end with a reply box until you reply, however many Claude notes follow it** ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **The page shows a line diff of a changed restatement against the newest confirmed revision and keeps a `Restatement changed, needs your Confirm` banner until it gets a verdict.** Confirm says it ticks no commitment and links to the commitment list ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **A note that names one option by its label (`Rec`, `#1`, `option 2`, `(a)`) asks `Did you mean Accept with note?` before it is saved** ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **New Needs-you items raise a dismissible toast, including `Interview complete`, and a browser notification is offered only on a click.** The tab title counts Needs-you items only, and the page keeps the finish text in the browser so a tab that cannot reach the server still shows it, and a finish kept for another data dir on the same port is replaced, not shown ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).

### Changed

- **`add` and `add-round` give a question with no `stage` the newest question's stage and warn, naming the stage and round used** ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).
- **Page polish.** The rail preview skips hold bookkeeping, the id column has one width, the Pending filter covers every hold, Activity no longer relists ids its text links, and a note posted with no reply target reads `Claude posted in Notes` ([#5569](https://github.com/melodic-software/claude-code-plugins/issues/5569)).

## [0.56.3] - 2026-10-01

### Fixed
Expand Down
14 changes: 7 additions & 7 deletions plugins/planning/skills/interview/context/surface.md

Large diffs are not rendered by default.

15 changes: 8 additions & 7 deletions plugins/planning/surface/README.md

Large diffs are not rendered by default.

29 changes: 27 additions & 2 deletions plugins/planning/surface/exporters.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,13 +807,27 @@ def bullets(text):
def ledger_row(n, qid, status, title, res):
"""A brief row for a question only the ledger has, in the shape register() gives a page one."""
lead = LEAD.match(res)
body = clean(lead.group(2) if lead else res)
text = lead.group(2) if lead else res
body = note = clean(text)
try:
named = parse_named(text, f"ledger row {n}")
except SystemExit:
named = None
if named:
fields, marked = named
body = clean(readable(status, fields, marked))
answer = fields.get("answer") or ""
note = clean(
answer.removeprefix("deferred: ")
if answer.startswith("deferred: ")
else fields.get("note") or body
)
return {
"n": n,
"q": {"id": qid, "short": clean(title), "title": clean(title)},
"status": status,
"readable": body,
"note": body,
"note": note,
"reserved": "USER-RESERVED" in body,
"confirmed": [],
"unconfirmed": [],
Expand Down Expand Up @@ -1131,6 +1145,17 @@ def round_of(cell):
return (int(m.group()) if m else 1), False


def round_drift(doc):
"""[(id, stored round, round its seeded ledger cell reads as, cell)] for each seeded question
whose round differs from its meta.seededFrom.roundCells entry read with round_of."""
cells = ((doc.get("meta") or {}).get("seededFrom") or {}).get("roundCells") or {}
return [
(q["id"], q.get("round", 1), round_of(cells[q["id"]])[0], cells[q["id"]])
for q in doc.get("questions") or []
if q["id"] in cells and q.get("round", 1) != round_of(cells[q["id"]])[0]
]


def scan_register(lines):
"""(heads, rows) over a ledger's lines outside fenced blocks: the index of every heading
naming the open-question register, and (index, row match) for each row under the first."""
Expand Down
Loading
Loading