Lift runOverhead into @relayburn/sdk (closes #235)#236
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2f7ea96ef7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| const resolved = resolveProject(projectPath); | ||
| const q = { project: resolved.projectKey ?? projectPath }; | ||
| if (opts.since) q.since = opts.since; |
There was a problem hiding this comment.
Parse relative --since values before ledger query
overhead()/overheadTrim() document since as accepting relative windows like 30d, but this code forwards opts.since directly into the ledger query. The ledger filter compares timestamps lexicographically (e.g. turn.ts < q.since in packages/ledger/src/adapters/file-adapter.ts), so passing 30d/7d silently filters out essentially all turns and returns near-zero attribution. This makes the new SDK API produce incorrect results for documented inputs unless callers pre-convert to ISO themselves.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 9fa7e45 — the SDK now normalizes since (accepts both ISO timestamps and relative ranges like 7d/4w/2m) before passing to the ledger query. Direct SDK callers get the same forgiving shape CLI users have. Also tightened the .d.ts doc to describe the accepted forms.
Closes #235. Follow-up to #232 (which made @relayburn/sdk the canonical in-process query surface). The burn overhead verb is now a thin presenter over two new SDK functions; the discovery + ingest + ledger query + attribution pipeline lives in one place so a future burn__overhead MCP tool (and embedders) can call it without re-implementing it. @relayburn/sdk: - overhead({ project, since?, kind? }) returns the per-file + per-section attribution shape burn overhead --json now consumes (project / files / perFile / grandTotal). - overheadTrim({ project, since?, kind?, top?, includeDiff?, sinceLabel? }) returns trim recommendations with projected savings and (by default) embedded unified diffs — the shape burn overhead trim --json now consumes. Pass includeDiff: false to skip the per-file disk reads when you only need recommendation rows. - Both reuse the existing loadTurnsViaArchive helper, so they get the same archive-with-fallback strategy summary / sessionCost have. - New OverheadFileSummary / OverheadPerFileEntry / OverheadSectionCost / OverheadAttributionDetail types declared in index.d.ts so consumers don't have to reach into @relayburn/analyze for the attribution shape. @relayburn/cli: - Adds @relayburn/sdk as a dep. - runOverhead / runTrim drop ~280 lines of inline gather + attribution + JSON shaping; both now call the SDK and only own flag parsing, --since string→ISO conversion, and TTY/diff rendering. - CLI keeps an OverheadDeps { ingestAll? } injection seam so tests can stub out the real ingest pass (which would otherwise read the user's ~/.claude / ~/.codex / ~/.opencode session stores during unit tests). - Test rewritten: appendTurns into an isolated RELAYBURN_HOME, stub ingestAll, run the CLI, assert the exact same JSON shape the pre-refactor test asserted against. Wire shape unchanged for both burn overhead --json and burn overhead trim --json (verified by the existing JSON-mode tests). Tests: 889/889 pass. Note: this PR is stacked on top of #232 (claude/sdk-drives-mcp); expect to rebase against main once that merges. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI fix:
- @relayburn/sdk now declares @relayburn/reader as a workspace dep.
The SDK started importing resolveProject from @relayburn/reader in
this PR, but the dep wasn't listed in package.json. pnpm hoists
workspace packages locally so the import worked in dev, but
--frozen-lockfile + strict module resolution on CI surfaced
ERR_MODULE_NOT_FOUND. This caused all four MCP / CLI test files
that import compiled SDK code to crash at load time.
Codex review (P1):
- summary() / overhead() / overheadTrim() now accept both an ISO
timestamp AND a relative range (24h, 7d, 4w, 2m) for `since`. The
SDK normalizes both forms internally before querying the ledger.
Previously a raw relative string ("7d") fell through to the
ledger's lexical timestamp comparison and silently filtered every
turn out (since '7' > '2' lexically), returning near-zero
attribution with no error. Direct SDK callers (and future MCP
tools) now get the same forgiving input shape CLI users have.
- CLI overhead command no longer pre-converts --since to ISO; passes
the raw user string to the SDK and the SDK handles normalization.
Drops the `sinceLabel` opts plumbing the previous attempt added.
Devin review:
- Tighten OverheadTrimOptions.includeDiff doc — previous text "Skip
the unified-diff text ... Default true" wrongly described the
opposite of the actual behavior (true = include).
- Tighten OverheadOptions.since / SummaryOptions.since docs to
describe the actual accepted shapes.
Tests: 889/889 pass locally with --frozen-lockfile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2f7ea96 to
9fa7e45
Compare
Closes #235. Follow-up to #232 (which made
@relayburn/sdkthe canonical in-process query surface). Applies the same pattern — CLI verb → pure SDK function + thin presenter — toburn overheadandburn overhead trim.What changed
@relayburn/sdk— two new functions, both in-process pure data:Both reuse the
loadTurnsViaArchivehelper from #232 so they get the same archive-with-fallback strategysummary/sessionCostalready have.overheadTrimincludes a unified-diff string per recommendation by default (matchesburn overhead trim --json); passincludeDiff: falseto skip the per-file disk reads when only recommendation rows are needed.New types declared in
index.d.tsso consumers don't have to reach into@relayburn/analyzefor the attribution shape:OverheadFileSummary,OverheadPerFileEntry,OverheadSectionCost,OverheadAttributionDetail, plus theOverheadResult/OverheadTrimResult/ option types.@relayburn/cli— adds@relayburn/sdkas a workspace dep.runOverhead/runTrimdrop ~280 lines of inline gather + attribution + JSON shaping; both now call the SDK and only own flag parsing,--sincestring→ISO conversion, and TTY/diff rendering. CLI keeps a narrowOverheadDeps { ingestAll? }injection seam (only ingest, not the whole pipeline) so tests can stub out the real ingest pass — without it, an isolatedRELAYBURN_HOMEtest still triggers a real read of the user's~/.claude/~/.codex/~/.opencodestores.Wire shape unchanged. Both
burn overhead --jsonandburn overhead trim --jsonemit the same payload they did before; the existing JSON-mode test was rewritten to use a real ledger (appendTurnsinto a tmpRELAYBURN_HOME) instead of dep-injection ofqueryAll/loadPricing, and asserts the same exact shape.Test plan
pnpm run buildcleanpnpm run test— 889/889 passburn overheadandburn overhead trim --top 3against a real project produce the same TTY output as beforeOut of scope
burn__overheadMCP tool. That's a separate PR — should be ~30 lines once this lands (zod schema →await sdk.overhead(input)→ return).compare) and Lift runHotspots into @relayburn/sdk as hotspots() (proper) #234 (hotspots) — same refactor pattern, separate PRs.🤖 Generated with Claude Code