hive-forge: timeline verb — issue/PR audit trail (closes #783)

last unstarted piece of the original #694 epic. agents kept falling
back to curl for 'who closed this?' / 'when was this labelled?'
archaeology because view + comments only surface the body + comments,
not the structured timeline events (label adds, assignments, closes,
reopens, pushes, commit refs, review submissions, milestone changes).

separate verb rather than view --timeline because:
- composes naturally with view <n> / comments <n>
- keeps existing verb output shapes stable (no script breakage)
- argus on #770 already noted view's output is busy

human-readable by default ('**actor @ ts**: <summary>'), --json for
raw piping. unknown event types fall through to a '[<type>]'
placeholder so a forge schema bump doesn't panic the verb.

--tail N is a follow-up: timeline endpoint doesn't expose a total-count
field so the count-then-page strategy from #770 doesn't apply
directly.

6 tests cover comment / label add/remove / close / unknown-type
placeholder / missing-user fallback.
This commit is contained in:
damocles 2026-05-31 15:04:27 +02:00 committed by mara
commit 8f9866f5e1
3 changed files with 310 additions and 0 deletions

View file

@ -91,6 +91,10 @@ enum Verb {
Diff(verbs::diff::Args),
/// Get or set this user's watch subscription on a repo.
Subscription(verbs::subscription::Args),
/// List timeline events on an issue or PR (closes, label adds,
/// assignments, commit refs, pushes, etc.) — the audit trail
/// `view` + `comments` don't surface (closes #783).
Timeline(verbs::timeline::Args),
/// Upload a file as an attachment to an issue.
AttachIssue(verbs::attach::IssueArgs),
/// Upload a file as an attachment to a comment.
@ -123,6 +127,7 @@ fn main() -> Result<()> {
Verb::TreeSha(a) => verbs::tree_sha::run(&client, a),
Verb::Diff(a) => verbs::diff::run(&client, a),
Verb::Subscription(a) => verbs::subscription::run(&client, a),
Verb::Timeline(a) => verbs::timeline::run(&client, a),
Verb::AttachIssue(a) => verbs::attach::run_issue(&client, a),
Verb::AttachComment(a) => verbs::attach::run_comment(&client, a),
}