mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
* refactor(usage): share the session/daily fold between Codex and OpenCode The Codex and OpenCode scanners each carried their own byte-identical copy of the ~325-line aggregation pipeline (createEmptySession, the three breakdown folds, finalizeSessions, mergeSessions, mergeDailyAggregates). Two copies means a token-accounting fix — a bucket that double-counts, a merge that drops a breakdown row — lands in one provider and silently not the other. The copies had already started to drift in comments only; the next drift would have been in arithmetic. The providers differ in exactly one dimension: the extra metric folded alongside the token counters (Codex `hasInferredPricing`, OpenCode `estimatedCostUsd`). That is now injected as an empty/fromEvent/fold triple, so the shared code stays generic without collapsing the two record schemas into a nullable union. The clone strategy stays per-provider (`cloneSessionForMerge` vs `structuredClone`) rather than being unified on the assumption that the difference is accidental. `usage-provider-contract.ts` is the seam a plugin-contributed usage source will implement. It is deliberately generic over each provider's record types: Claude bills per turn while Codex/OpenCode bill per event, and `cachedInput` is a subset of `input` for the latter but a peer bucket for Claude, so a single normalized record would push nullable handling onto every consumer. No behavior change. Emitted objects are byte-identical, including key insertion order — verified by diffing JSON.stringify of the scan output before and after across mixed models, mixed locations, an inferred-pricing flip, and null vs non-null cost. Persisted field names and schemaVersion are untouched, so caches do not invalidate. * refactor(usage): make the provider contract load-bearing and dedupe worktree refs Follow-up to the aggregation extraction, addressing three review points. `UsageProvider`/`UsageScanResult` were declaration-only, which is the same speculative-interface problem #12077 just deleted 8,900 lines of. They are now implemented by both real providers via `satisfies`, so the seam is typechecked against actual scan functions rather than asserted. The blocker was that codex returns `processedFiles` and opencode returns `processedDatabases`; rather than rename persisted-adjacent fields, the source key is a type parameter, so each provider keeps its own on-disk name and the contract still binds. Verified the constraint bites: swapping the key to 'processedSources' fails typecheck. `schemaVersion` is part of provider identity in the contract, so each provider's SCHEMA_VERSION constant (with its cache-invalidation rationale) moves into the provider module and the store imports it. Values are unchanged (codex 5, opencode 2) and the stores compare them exactly as before, so no cache invalidates. This also keeps store -> provider -> scanner acyclic. `UsageWorktreeRef` collided with the existing export in usage-worktree-metadata (3 fields, no repoId). Two different exported types under one name in src/main is worse than the duplication being removed, so the scan-input type is now `UsageScanWorktreeRef`; usage-worktree-metadata is untouched. `createWorktreeRefs` was triplicated. Codex, OpenCode, and Claude copies are byte-identical apart from the return type name (verified by diff), and all three ref types have the same four fields, so one shared copy replaces all three. This is the only change to claude-usage/. No behavior change: same functions, same arguments, same call order. The store tests' `./scanner` mock still intercepts scanning because the provider captures the mocked binding; their now-inert `createWorktreeRefs` mock key is dropped so it does not read as still mocking something.
24 lines
749 B
TypeScript
24 lines
749 B
TypeScript
import type { UsageProvider } from '../usage/usage-provider-contract'
|
|
import { scanOpenCodeUsageDatabases } from './scanner'
|
|
import type {
|
|
OpenCodeUsageDailyAggregate,
|
|
OpenCodeUsagePersistedDatabase,
|
|
OpenCodeUsageSession
|
|
} from './types'
|
|
|
|
// Why: v2 adds per-database session ownership (stale sibling-copy dedupe).
|
|
// Older caches were built without it and can carry doubled sessions (#8006).
|
|
export const OPENCODE_USAGE_SCHEMA_VERSION = 2
|
|
|
|
export const openCodeUsageProvider = {
|
|
id: 'opencode',
|
|
label: 'OpenCode',
|
|
schemaVersion: OPENCODE_USAGE_SCHEMA_VERSION,
|
|
scan: scanOpenCodeUsageDatabases
|
|
} satisfies UsageProvider<
|
|
'processedDatabases',
|
|
OpenCodeUsagePersistedDatabase,
|
|
OpenCodeUsageSession,
|
|
OpenCodeUsageDailyAggregate
|
|
>
|