Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generated by Scripts/regenerate-codex-parser-hash.sh. Do not edit by hand.

enum CodexParserHash {
static let value = "7378e1f7e954ea1f"
static let value = "6f689d90f8eedcbd"
}
7 changes: 7 additions & 0 deletions Sources/CodexBarCore/Vendored/CostUsage/CostUsageCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ struct CostUsageFileUsage: Codable {
var codexWorkspaceContentFingerprint: String?
var codexRows: [CostUsageScanner.CodexUsageRow]?
var claudeRows: [CostUsageScanner.ClaudeUsageRow]?
/// Identity and target size for an in-progress bounded Codex parse.
var codexScanFileId: String?
var codexScanTargetSize: Int64?
var codexScanComplete: Bool?
var codexJSONLResumeState: CostUsageJsonl.ResumeState?
/// Compact relevant events retained while a subagent rollout awaits full-shape classification.
var codexBufferedSubagentLines: [CostUsageScanner.CodexBufferedFastLine]?
}

struct CostUsageCodexSessionMetadata: Codable, Equatable {
Expand Down
90 changes: 79 additions & 11 deletions Sources/CodexBarCore/Vendored/CostUsage/CostUsageJsonl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,23 @@ enum CostUsageJsonl {
let wasTruncated: Bool
}

private struct JSONTailState {
private enum ScalarState {
struct ResumeState: Codable {
let offset: Int64
fileprivate let lineStartOffset: Int64
fileprivate let prefix: Data
fileprivate let lineBytes: Int
fileprivate let truncated: Bool
fileprivate let jsonTailState: JSONTailState
}

struct ScanProgress {
let committedOffset: Int64
let readOffset: Int64
let resumeState: ResumeState?
}

fileprivate struct JSONTailState: Codable {
private enum ScalarState: Codable {
case notScalar
case trueLiteral(Int)
case falseLiteral(Int)
Expand All @@ -16,7 +31,7 @@ enum CostUsageJsonl {
case invalid
}

private enum NumberState {
private enum NumberState: Codable {
private enum ByteKind {
case zero
case digit
Expand Down Expand Up @@ -234,6 +249,7 @@ enum CostUsageJsonl {
offset: offset,
maxLineBytes: maxLineBytes,
prefixBytes: prefixBytes,
maxBytesToRead: nil,
checkCancellation: nil,
onLine: onLine)
}
Expand All @@ -244,25 +260,51 @@ enum CostUsageJsonl {
offset: Int64 = 0,
maxLineBytes: Int,
prefixBytes: Int,
maxBytesToRead: Int64? = nil,
checkCancellation: (() throws -> Void)? = nil,
onLine: (Line) -> Void) throws
-> Int64
{
try self.scanBounded(
fileURL: fileURL,
offset: offset,
maxLineBytes: maxLineBytes,
prefixBytes: prefixBytes,
maxBytesToRead: maxBytesToRead,
resumeState: nil,
checkCancellation: checkCancellation,
onLine: onLine).committedOffset
}

// swiftlint:disable:next function_parameter_count
static func scanBounded(
fileURL: URL,
offset: Int64 = 0,
maxLineBytes: Int,
prefixBytes: Int,
maxBytesToRead: Int64?,
resumeState: ResumeState?,
checkCancellation: (() throws -> Void)? = nil,
onLine: (Line) -> Void) throws -> ScanProgress
{
let handle = try FileHandle(forReadingFrom: fileURL)
defer { try? handle.close() }

let startOffset = max(0, offset)
let startOffset = resumeState?.offset ?? max(0, offset)
if startOffset > 0 {
try handle.seek(toOffset: UInt64(startOffset))
}

var current = Data()
var current = resumeState?.prefix ?? Data()
current.reserveCapacity(4 * 1024)
var lineBytes = 0
var truncated = false
var lineBytes = resumeState?.lineBytes ?? 0
var truncated = resumeState?.truncated ?? false
var bytesRead: Int64 = 0
var committedOffset = startOffset
var jsonTailState = JSONTailState()
var lineStartOffset = resumeState?.lineStartOffset ?? startOffset
var committedOffset = lineStartOffset
var jsonTailState = resumeState?.jsonTailState ?? JSONTailState()
let fileSize = (try? FileManager.default.attributesOfItem(atPath: fileURL.path)[.size] as? NSNumber)?
.int64Value

func appendSegment(_ bytes: UnsafePointer<UInt8>, count: Int) {
guard count > 0 else { return }
Expand All @@ -288,6 +330,17 @@ enum CostUsageJsonl {
jsonTailState.reset()
}

func currentResumeState() -> ResumeState? {
guard lineBytes > 0 else { return nil }
return ResumeState(
offset: startOffset + bytesRead,
lineStartOffset: lineStartOffset,
prefix: current,
lineBytes: lineBytes,
truncated: truncated,
jsonTailState: jsonTailState)
}

func hasCompleteJSONTail() -> Bool {
guard jsonTailState.isStructurallyComplete else { return false }
if truncated {
Expand All @@ -301,12 +354,23 @@ enum CostUsageJsonl {

while true {
try checkCancellation?()
let remaining = maxBytesToRead.map { max(0, $0 - bytesRead) }
if remaining == 0 {
if let fileSize, startOffset + bytesRead >= fileSize, hasCompleteJSONTail() {
flushLine()
committedOffset = startOffset + bytesRead
lineStartOffset = committedOffset
}
break
}
let reachedEOF = try autoreleasepool {
let chunk = try handle.read(upToCount: 256 * 1024) ?? Data()
let readCount = min(256 * 1024, Int(remaining ?? Int64(256 * 1024)))
let chunk = try handle.read(upToCount: readCount) ?? Data()
if chunk.isEmpty {
if hasCompleteJSONTail() {
flushLine()
committedOffset = startOffset + bytesRead
lineStartOffset = committedOffset
}
return true
}
Expand All @@ -323,6 +387,7 @@ enum CostUsageJsonl {
appendSegment(base.advanced(by: segmentStart), count: index - segmentStart)
flushLine()
committedOffset = chunkStartOffset + Int64(index + 1)
lineStartOffset = committedOffset
segmentStart = index + 1
} else {
jsonTailState.append(base[index])
Expand All @@ -341,6 +406,9 @@ enum CostUsageJsonl {
try checkCancellation?()
}

return committedOffset
return ScanProgress(
committedOffset: committedOffset,
readOffset: startOffset + bytesRead,
resumeState: currentResumeState())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,12 @@ extension CostUsageScanner {
codexPriorityTokens: [String: [String: Int]]? = nil,
codexTurnIDs: [String]? = nil,
codexRows: [CodexUsageRow]? = nil,
claudeRows: [ClaudeUsageRow]? = nil) -> CostUsageFileUsage
claudeRows: [ClaudeUsageRow]? = nil,
codexScanFileId: String? = nil,
codexScanTargetSize: Int64? = nil,
codexScanComplete: Bool? = nil,
codexJSONLResumeState: CostUsageJsonl.ResumeState? = nil,
codexBufferedSubagentLines: [CodexBufferedFastLine]? = nil) -> CostUsageFileUsage
{
CostUsageFileUsage(
mtimeUnixMs: mtimeUnixMs,
Expand Down Expand Up @@ -333,7 +338,12 @@ extension CostUsageScanner {
codexPriorityTokens: codexPriorityTokens,
codexTurnIDs: codexTurnIDs,
codexRows: codexRows,
claudeRows: claudeRows)
claudeRows: claudeRows,
codexScanFileId: codexScanFileId,
codexScanTargetSize: codexScanTargetSize,
codexScanComplete: codexScanComplete,
codexJSONLResumeState: codexJSONLResumeState,
codexBufferedSubagentLines: codexBufferedSubagentLines)
}

static func needsCodexCostCache(_ usage: CostUsageFileUsage) -> Bool {
Expand Down Expand Up @@ -950,6 +960,7 @@ extension CostUsageScanner {
let needsSessionId = cached.sessionId == nil
guard cached.mtimeUnixMs == input.metadata.mtimeUnixMs,
cached.size == input.metadata.size,
cached.codexScanComplete != false,
!needsSessionId,
!context.forceFullScan
else { return false }
Expand Down Expand Up @@ -1025,7 +1036,8 @@ extension CostUsageScanner {
input: CodexFileScanInput,
context: CodexFileScanContext,
cache: inout CostUsageCache,
state: inout CodexScanState) throws -> Bool
state: inout CodexScanState,
maxBytesToRead: Int64? = nil) throws -> Bool
{
try context.checkCancellation?()
guard let cached = input.cached, cached.sessionId != nil, !context.forceFullScan else { return false }
Expand All @@ -1035,13 +1047,24 @@ extension CostUsageScanner {
}
// Subagent shape depends on the complete lineage prefix. Appended metadata can change an
// independent counter into a copied-prefix rollout, so a tail-only parse is not sound.
if try Self.codexFileIsSubagentThread(
let startOffset = cached.parsedBytes ?? cached.size
let hasMatchingResumeOffset = cached.codexJSONLResumeState?.offset == nil
|| cached.codexJSONLResumeState?.offset == startOffset
let isResumablePartial = cached.codexScanComplete == false
&& cached.codexScanFileId != nil
&& cached.codexScanFileId == input.metadata.fileId
&& cached.codexScanTargetSize == input.metadata.size
&& cached.mtimeUnixMs == input.metadata.mtimeUnixMs
&& hasMatchingResumeOffset
if cached.codexScanComplete == false, !isResumablePartial {
return false
}
if !isResumablePartial, try Self.codexFileIsSubagentThread(
fileURL: input.fileURL,
checkCancellation: context.checkCancellation)
{
return false
}
let startOffset = cached.parsedBytes ?? cached.size
let initialCountedTotals = cached.lastCountedTotals ?? cached.lastTotals
let initialRawTotalsBaseline = cached.lastRawTotalsBaseline ?? cached.lastTotals
let initialHasDivergentTotals = cached.hasDivergentTotals ?? (cached.lastTotals == nil)
Expand All @@ -1051,11 +1074,13 @@ extension CostUsageScanner {
(cached.hasInterleavedTotals == true && cached.lastRawTotalsWatermark == nil)
|| (cached.lastRawTotalsWatermark != nil && cached.hasInterleavedTotals == nil)
|| (initialHasDivergentTotals && cached.lastRawTotalsWatermark == nil)
let canIncremental = input.metadata.size > cached.size && startOffset > 0
let canIncremental = startOffset > 0
&& startOffset <= input.metadata.size
&& initialCountedTotals != nil
&& cached.forkedFromId == nil
&& !hasIncompleteInterleaveState
&& (isResumablePartial
|| (input.metadata.size > cached.size
&& initialCountedTotals != nil
&& cached.forkedFromId == nil
&& !hasIncompleteInterleaveState))
guard canIncremental else { return false }

let delta = try Self.parseCodexFileCancellable(
Expand All @@ -1071,8 +1096,11 @@ extension CostUsageScanner {
initialHasInterleavedTotals: cached.hasInterleavedTotals ?? false,
initialCodexTurnID: cached.lastCodexTurnID,
initialCodexUsageRowIndex: Self.nextCodexUsageRowIndex(cached.codexRows),
initialBufferedSubagentLines: cached.codexBufferedSubagentLines,
initialJSONLResumeState: cached.codexJSONLResumeState,
maxBytesToRead: maxBytesToRead,
checkCancellation: context.checkCancellation)
if delta.forkedFromId != nil {
if delta.forkedFromId != nil, !isResumablePartial {
return false
}
let migrated = Self.codexFileUsageWithCostCache(cached, context: context)
Expand All @@ -1086,6 +1114,10 @@ extension CostUsageScanner {
let codexSession = cachedSessionMetadata.merging(delta.codexSession)
let sessionId = codexSession.sessionId ?? delta.sessionId ?? cached.sessionId
let projectPath = delta.projectPath ?? cached.projectPath
let forkBaselineDependencyKey = Self.codexForkBaselineDependencyKey(
parentSessionId: delta.forkedFromId,
dependsOnParentTotals: delta.dependsOnParentTotals,
inheritedResolver: context.resources.inheritedResolver)
let canonicalProjectPath = delta.projectPath.map {
context.resources.projectPathResolver.canonicalProjectPath(for: $0)
} ?? cached.canonicalProjectPath ?? context.resources.projectPathResolver.canonicalProjectPath(for: projectPath)
Expand Down Expand Up @@ -1153,6 +1185,7 @@ extension CostUsageScanner {
lastCodexTurnID: delta.lastCodexTurnID,
sessionId: sessionId,
forkedFromId: codexSession.forkedFromId ?? delta.forkedFromId ?? migratedCached.forkedFromId,
forkBaselineDependencyKey: forkBaselineDependencyKey ?? migratedCached.forkBaselineDependencyKey,
projectPath: projectPath,
canonicalProjectPath: canonicalProjectPath,
codexSession: codexSession.isEmpty ? nil : codexSession,
Expand Down Expand Up @@ -1181,7 +1214,12 @@ extension CostUsageScanner {
Self.mergeCodexRows(retainedCachedRows, rows: uniqueRows, sessionId: sessionId) ?? [],
priorityTurns: context.resources.priorityTurns,
modelsDevCatalog: context.resources.modelsDevCatalog,
modelsDevCacheRoot: context.resources.modelsDevCacheRoot))
modelsDevCacheRoot: context.resources.modelsDevCacheRoot),
codexScanFileId: input.metadata.fileId,
codexScanTargetSize: input.metadata.size,
codexScanComplete: delta.parsedBytes >= input.metadata.size && delta.jsonlResumeState == nil,
codexJSONLResumeState: delta.jsonlResumeState,
codexBufferedSubagentLines: delta.bufferedSubagentLines)
.refreshingCodexWorkspaceUsageFingerprint()
Self.rememberScannedCodexFile(
input: input,
Expand All @@ -1196,7 +1234,8 @@ extension CostUsageScanner {
input: CodexFileScanInput,
context: CodexFileScanContext,
cache: inout CostUsageCache,
state: inout CodexScanState) throws
state: inout CodexScanState,
maxBytesToRead: Int64? = nil) throws
{
try context.checkCancellation?()
if let cached = input.cached {
Expand All @@ -1210,6 +1249,7 @@ extension CostUsageScanner {
let parsed = try Self.parseCodexFileCancellable(
fileURL: input.fileURL,
range: context.range,
maxBytesToRead: maxBytesToRead,
inheritedTotalsResolver: context.resources.inheritedResolver.inheritedTotals(for:atOrBefore:),
checkCancellation: context.checkCancellation)
let forkBaselineDependencyKey = Self.codexForkBaselineDependencyKey(
Expand Down Expand Up @@ -1238,7 +1278,8 @@ extension CostUsageScanner {
if let sessionId,
state.contributingSessionIds.contains(sessionId),
uniqueRows.isEmpty,
usageDays.isEmpty
usageDays.isEmpty,
parsed.bufferedSubagentLines == nil
{
cache.files.removeValue(forKey: input.metadata.path)
return
Expand Down Expand Up @@ -1320,7 +1361,12 @@ extension CostUsageScanner {
Self.mergeCodexRows(migratedCached?.codexRows, rows: uniqueRows, sessionId: sessionId) ?? [],
priorityTurns: context.resources.priorityTurns,
modelsDevCatalog: context.resources.modelsDevCatalog,
modelsDevCacheRoot: context.resources.modelsDevCacheRoot))
modelsDevCacheRoot: context.resources.modelsDevCacheRoot),
codexScanFileId: input.metadata.fileId,
codexScanTargetSize: input.metadata.size,
codexScanComplete: parsed.parsedBytes >= input.metadata.size && parsed.jsonlResumeState == nil,
codexJSONLResumeState: parsed.jsonlResumeState,
codexBufferedSubagentLines: parsed.bufferedSubagentLines)
.refreshingCodexWorkspaceUsageFingerprint()
Self.applyFileDays(cache: &cache, fileDays: cache.files[input.metadata.path]?.days ?? [:], sign: 1)
Self.rememberScannedCodexFile(
Expand Down
Loading