15 Commits (83d5abde8af9ae2f75c0d9b2891a9ed9b30ef82c)

Author SHA1 Message Date
Elijah Voigt 6d40671f28 fix(nbd): fix graph orientation to show goals at root, prerequisites as leaves
Roots are now tickets with no dependents (nobody depends on them —
top-level goals), and the ASCII tree traverses dependency edges so
prerequisites appear indented beneath the goal that needs them.

JSON edges are now {from: dependent, to: dependency} rather than
{from: blocker, to: blocked}.

All graph-related unit and integration tests updated to match the
new semantics.

Closes #668150

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 61ac72aee4 fix(nbd): change graph repeat-node marker from [cycle] to * [8b4041]
The [cycle] label was misleading — a node marked this way is not
necessarily in a true cycle, it is simply a shared dependency appearing
in multiple branches of the tree. The `*` marker is more neutral and
concise.

Changes: render_node in display.rs, test in tests.rs, README.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 8f4d25b141 feat(nbd): render tickets as TOML frontmatter markdown [4036aa]
Replace the key-value table format with TOML frontmatter + body when
printing tickets to stdout (nbd read, nbd create, nbd archive, nbd next
— all non-JSON paths). The --json output is unchanged.

New format:
  +++
  id = "a3f9c2"
  title = "Fix login bug"
  priority = 8
  status = "in_progress"
  ticket_type = "bug"
  dependencies = ["b7d41e"]
  +++
  Body text here.

Changes:
- display.rs: add DisplayFrontmatter struct, rewrite format_ticket using
  toml::to_string with id prepended as first frontmatter key
- tests.rs: update format_ticket_joins_dependencies and
  format_ticket_empty_dependencies for the new format
- integration.rs: update TestEnv::create to use --json for reliable
  ID extraction instead of parsing the key-value text format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 05beff7752 feat(nbd): split archive/closed — archive=archived, closed=cancelled [feb901]
`nbd archive` now sets status to `archived` (completed, soft-deleted)
instead of `closed`. The `closed` status is reserved for tickets that
will not be completed (cancelled, superseded, won't-fix).

Both statuses count as resolved for dependency purposes and are excluded
from `nbd list`, `nbd ready`, and `nbd next` by default.

Changes:
- Add `Status::Archived` variant (serialises as "archived")
- `cmd_archive`: sets `Status::Archived` instead of `Status::Closed`
- `parse_status`: add "archived" arm
- `cmd_list`, `cmd_ready`, `cmd_next`: exclude/resolve `Archived`
- `display`, `graph`, `filter`: add `Archived` arm to `status_str`
- Tests: rename/update archive tests, add archived/closed test variants
- Docs: update README.md and CLAUDE.md status tables and descriptions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 7e311d6b47 feat(nbd): add backlog status to tickets [c12091]
Adds a new `backlog` Status variant for tickets that are created but
intentionally deferred. Backlog tickets are excluded from `nbd list`,
`nbd ready`, and `nbd next` by default, but unlike `done` and `closed`
they do not count as resolved for dependency purposes — a ticket whose
dependency is `backlog` remains blocked.

Visible via `--all` or `--filter status=backlog`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt 7aa547633f feat(nbd): show diff output on nbd update without --json [5f1495]
When `nbd update` is run without `--json`, print a git-diff-style
+/- summary of changed fields instead of the full ticket.

- Add `format_diff` and `print_diff` to display.rs
- Capture `old` ticket snapshot in `cmd_update` before mutations
- Use `print_diff` for the non-JSON branch of `cmd_update`
- Add unit tests (4) and integration tests (3) covering diff output,
  JSON fallback, and the no-changes case

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt b0359c4392 feat(nbd): add 'nbd graph' CLI subcommand [9ad11f]
Wires up the graph command in main.rs with cmd_graph(). Supports
full dependency forest (nbd graph), subtree by ID/prefix (nbd graph
<id>), --filter narrowing, and --json machine-readable output. Fixes
tree-rendering indentation bug (child_base vs prefix separation).
Updates README.md and CLAUDE.md with graph command documentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt d5697d5c4e feat(nbd): add ASCII graph rendering to display.rs [e14172]
Adds format_graph, print_graph, format_subtree, and print_subtree.
Renders dependency forest with box-drawing characters (├──, └──, │).
Cycle-safe via visited HashSet; repeated nodes labelled [cycle].
8 unit tests covering single tickets, chains, branching, subtrees,
cycles, unknown IDs, and the empty graph.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt deecdba592 feat(nbd): add archive command and Closed status [1939a7]
Add Status::Closed variant serialised as "closed", providing a
soft-delete for tickets that should be hidden from normal listings.

- nbd archive <id>: sets status to closed (sugar for update --status closed)
- nbd list: excludes closed tickets by default (same as done)
- nbd list --all: bypasses default status exclusion, shows everything
- nbd list --filter status=closed: shows only closed tickets
- Closed tickets count as resolved for dependency purposes (unblock dependents)
- nbd ready / nbd next: closed tickets excluded from actionable set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt fa60cb844d feat(nbd): add nbd next subcommand [fc6df4]
Adds `nbd next` which selects the single highest-priority ready ticket.
Supports `--filter` narrowing, `--json` output as `{"next": ...}` or
`{"next": null}` when nothing is ready. Makes `ticket_to_json_value`
pub(crate) for reuse. Adds 7 integration tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt dbab0f466c feat(nbd): wire --filter flag into list, ready, and migrate commands [887344]
Add repeatable --filter KEY=VALUE option to nbd list, nbd ready, and
nbd migrate. Filters are parsed into a TicketFilter and applied in each
command handler. Different keys are ANDed; same key with multiple values
is ORed; values support glob wildcards.

- store: add skipped field to MigrateReport; migrate_tickets accepts
  a &TicketFilter and skips non-matching tickets
- display: format_migrate_report shows optional Skipped line;
  format_migrate_report_json includes skipped key
- filter: suppress dead_code on is_empty/has_status_filter (public API
  reserved for future done-exclusion feature)
- tests: update MigrateReport literals and migrate_tickets call sites;
  add unit tests for skipped formatting; add 14 integration tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt df71fc9e09 feat(nbd): implement nbd migrate command [0f51af]
Adds `nbd migrate` to bring ticket files on disk into conformance with
the current serde schema. Re-serialises every *.json file through the
current Ticket model — removing stale fields (e.g. old \"id\" key),
adding new fields with their defaults, and normalising formatting.

- store: MigrateReport struct and migrate_tickets() function
- display: format/print_migrate_report and _json variants
- main: Migrate command with --dry-run flag and cmd_migrate handler
- 6 unit tests (rewrites old format, already-current, dry-run, invalid JSON, empty store, no tickets dir)
- 4 integration tests (rewrite, dry-run, parse error tolerance, --json output)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt f1715d18eb feat(nbd): remove id from ticket JSON body; inject from filename [d1634a]
The ticket id is now stored only in the filename stem (.nbd/tickets/{id}.json).
`id` is annotated with `#[serde(skip)]` so it is never written to disk,
eliminating the consistency hazard of id-in-body vs. filename disagreement.

- ticket.rs: add `#[serde(skip)]` to `Ticket::id`
- store.rs: `read_ticket` and `list_tickets` inject id from filename stem
- display.rs: `ticket_to_json_value` re-inserts id for CLI `--json` output
- tests.rs: new unit tests for omission, injection, and old-format compat
- integration.rs: assert written files lack "id"; assert read --json has id

Backwards-compatible: old files with "id" in JSON body still parse correctly
(serde ignores the unknown field), so existing stores work without migration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt e9b6e97116 feat(nbd): implement display layer (Phase 4)
Add output formatting for tickets via display.rs:
- print_ticket / format_ticket: key-value table view
- print_ticket_json / format_ticket_json: pretty JSON
- print_list / format_list: compact summary table with header
- print_list_json / format_list_json: JSON array output

format_* variants return String for testability. Unit tests added
covering field presence, dependency joining, header row, and JSON
validity. All 26 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
Elijah Voigt a7adc1659c feat(nbd): scaffold crate with module stubs and dependencies
Creates Cargo.toml with clap, async-std, serde/serde_json and tempfile
dev-dep. Adds placeholder src/{main,ticket,store,display,tests}.rs and
tests/integration.rs with rustdoc module comments. Phase 1 complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago