Skip to content

Commit 05283c4

Browse files
committed
feat(cli): nodetool timeline versions commands and harness coverage
Adds a local-DB timeline versions command group — list, show, create, restore, delete — with --json output. restore mirrors the tRPC router's semantics: pre-restore snapshot, CAS write of document and render settings, then a static validation verdict on the restored document. Registers a timeline-versions harness entry so the timeline surface owns the version-history paths, and documents the commands in CLAUDE.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFVn8LPnkLRAGYUE3ucuKA
1 parent 9967644 commit 05283c4

8 files changed

Lines changed: 1017 additions & 43 deletions

File tree

CLAUDE.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,26 @@ the verdict is ok. Validation and report rules live in
647647
`@nodetool-ai/execution/timeline-debug`; the CLI keeps target resolution, the
648648
interaction script, and the bundle.
649649

650+
`timeline versions` reads and writes a sequence's snapshot history against the
651+
local database — manual saves, the autosaves `timeline.update` writes at most
652+
every five minutes, and the pre-restore snapshot that makes a restore undoable.
653+
All five subcommands take `--json`.
654+
655+
```bash
656+
npm run dev:nodetool -- timeline versions list <timeline_id> --save-type manual --limit 10
657+
npm run dev:nodetool -- timeline versions show <timeline_id> 3 --json
658+
npm run dev:nodetool -- timeline versions create <timeline_id> --name "before the recut"
659+
npm run dev:nodetool -- timeline versions restore <timeline_id> 3
660+
npm run dev:nodetool -- timeline versions delete <timeline_id> 3 --yes
661+
```
662+
663+
`restore` mirrors the tRPC router: it snapshots the current state as a
664+
`restore` version, CAS-writes the old document and its render settings back
665+
onto the sequence, then runs the same static check `timeline validate` runs. An
666+
old document is restored against today's schema, so what it used to pass is not
667+
what it passes now — a restore whose document no longer validates exits
668+
non-zero and prints the issues.
669+
650670
### Script voicing tools (no workflow, no browser)
651671

652672
An agent voices a script and cuts it without authoring a workflow:
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Human-readable rendering of a `TimelineValidation`, shared by
3+
* `timeline validate` and `timeline versions restore` — a restored document is
4+
* checked and reported exactly the way a validated one is.
5+
*/
6+
import type {
7+
TimelineDebugIssue,
8+
TimelineValidation
9+
} from "@nodetool-ai/execution/timeline-debug";
10+
11+
/** Headline, then one line per issue — errors before warnings. */
12+
export function renderTimelineValidation(
13+
validation: TimelineValidation
14+
): string[] {
15+
const errors = validation.errors.length;
16+
const warnings = validation.warnings.length;
17+
const mark = validation.ok ? (warnings ? "⚠️" : "✅") : "❌";
18+
const lines = ["", `${mark} ${errors} error(s), ${warnings} warning(s)`];
19+
if (errors + warnings === 0) return lines;
20+
21+
lines.push("");
22+
for (const issue of [...validation.errors, ...validation.warnings]) {
23+
lines.push(` ${formatTimelineIssue(issue)}`);
24+
}
25+
return lines;
26+
}
27+
28+
function formatTimelineIssue(issue: TimelineDebugIssue): string {
29+
const tag = issue.severity === "error" ? "error" : "warn ";
30+
const where =
31+
issue.clipId != null
32+
? ` [clip ${issue.clipId}]`
33+
: issue.trackId != null
34+
? ` [track ${issue.trackId}]`
35+
: issue.path != null
36+
? ` [${issue.path}]`
37+
: "";
38+
return `${tag} ${issue.message}${where} (${issue.code})`;
39+
}

0 commit comments

Comments
 (0)