You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.9 KiB
Markdown
97 lines
2.9 KiB
Markdown
---
|
|
# nbd-d9dh
|
|
title: Add 'nbd graph' CLI subcommand
|
|
status: completed
|
|
type: feature
|
|
priority: normal
|
|
created_at: 2026-03-10T23:30:31Z
|
|
updated_at: 2026-03-10T23:30:32Z
|
|
blocked_by:
|
|
- nbd-csdh
|
|
- nbd-17dp
|
|
---
|
|
|
|
Wire up the `graph` subcommand in `src/main.rs` to expose the ASCII dependency graph and JSON output.
|
|
|
|
## Motivation
|
|
|
|
With `src/graph.rs` and the rendering functions in `display.rs` implemented, this ticket connects them to the CLI so users (and agents) can invoke `nbd graph`.
|
|
|
|
## CLI interface
|
|
|
|
```sh
|
|
nbd graph # full dependency forest (all tickets)
|
|
nbd graph <id> # subtree rooted at the given ticket ID (or unique prefix)
|
|
nbd graph --json # machine-readable adjacency list (all tickets)
|
|
nbd graph <id> --json # machine-readable subtree
|
|
nbd graph --filter type=bug # forest of only bug tickets and their deps
|
|
```
|
|
|
|
## Clap definition (add to `Commands` enum in main.rs)
|
|
|
|
```rust
|
|
/// Draw an ASCII dependency graph of all tickets, or a subtree rooted at a
|
|
/// specific ticket.
|
|
///
|
|
/// Without an ID, renders every ticket as a dependency forest (roots first,
|
|
/// dependencies indented below). With an ID, renders only the subtree reachable
|
|
/// from that ticket via its dependencies.
|
|
Graph {
|
|
/// Optional ticket ID or unique prefix to use as the graph root.
|
|
///
|
|
/// When omitted, the full dependency forest is rendered.
|
|
id: Option<String>,
|
|
|
|
/// Filter tickets by field before building the graph: repeatable `key=value` pairs.
|
|
///
|
|
/// Applied to the full ticket list before graph construction.
|
|
/// Keys: `status`, `type`, `priority`, `title`. Values support globs.
|
|
#[arg(long = "filter", value_name = "KEY=VALUE")]
|
|
filter: Vec<String>,
|
|
}
|
|
```
|
|
|
|
## Handler: `cmd_graph`
|
|
|
|
```rust
|
|
async fn cmd_graph(id: Option<String>, filter_args: Vec<String>, json: bool) -> store::Result<()>
|
|
```
|
|
|
|
Steps:
|
|
1. `find_nbd_root()` and `list_tickets(&root).await?`.
|
|
2. Apply `parse_filters(&filter_args)?` to narrow the ticket list.
|
|
3. `let graph = TicketGraph::build(&tickets);`
|
|
4. If `id` is `Some`:
|
|
a. Resolve `id` via `resolve_id(&root, &id).await?`.
|
|
b. If `json`: print `graph.to_subtree_json_value(&id)` (or similar — see graph.rs ticket for the JSON shape).
|
|
c. Else: `display::print_subtree(&graph, &id)`.
|
|
5. If `id` is `None`:
|
|
a. If `json`: print `graph.to_json_value()`.
|
|
b. Else: `display::print_graph(&graph)`.
|
|
|
|
## JSON output shapes
|
|
|
|
**Full graph (`nbd graph --json`):**
|
|
```json
|
|
{
|
|
"nodes": [
|
|
{"id": "a3f9c2", "title": "Fix login bug", "status": "todo", "priority": 8, "dependencies": ["b7d41e"]},
|
|
...
|
|
],
|
|
"edges": [
|
|
{"from": "a3f9c2", "to": "b7d41e"},
|
|
...
|
|
]
|
|
}
|
|
```
|
|
|
|
**Subtree (`nbd graph <id> --json`):**
|
|
Same shape as full graph but only including nodes and edges reachable from `<id>`.
|
|
|
|
## Files touched
|
|
- `src/main.rs` — `Commands::Graph` variant, `cmd_graph`, dispatch in `dispatch()`
|
|
|
|
## Depends on
|
|
- `9c9ebe` — graph computation module
|
|
- `e14172` — ASCII rendering functions
|