diff --git a/src/main.ts b/src/main.ts index c708ad1..cc562e7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -462,6 +462,14 @@ program .option('--no-optimize', 'Skip optimize findings (menubar-json only, faster)') .action(async (opts) => { assertFormat(opts.format, ['terminal', 'menubar-json', 'json'], 'status') + if (opts.day && (opts.from || opts.to)) { + process.stderr.write('error: --day cannot be combined with --from or --to\n') + process.exit(1) + } + if (opts.days && (opts.day || opts.from || opts.to)) { + process.stderr.write('error: --days cannot be combined with --day, --from, or --to\n') + process.exit(1) + } await loadPricing() const pf = opts.provider const fp = (p: ProjectSummary[]) => filterProjectsByName(p, opts.project, opts.exclude) diff --git a/src/providers/forge.ts b/src/providers/forge.ts index f80c8d1..27931e9 100644 --- a/src/providers/forge.ts +++ b/src/providers/forge.ts @@ -194,13 +194,13 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars const inputTokens = Math.max(0, promptTokens - cachedInputTokens) if (inputTokens === 0 && outputTokens === 0) continue + const model = typeof text?.model === 'string' ? text.model : 'unknown' const calls = toolCalls(text?.tool_calls) const { tools, bashCommands, firstCallId } = extractToolsAndCommands(calls) - const deduplicationKey = `forge:${row.conversation_id}:${firstCallId ?? i}` + const stableId = firstCallId ?? `${model}:${promptTokens}:${outputTokens}:${i}` + const deduplicationKey = `forge:${row.conversation_id}:${stableId}` if (seenKeys.has(deduplicationKey)) continue seenKeys.add(deduplicationKey) - - const model = typeof text?.model === 'string' ? text.model : 'unknown' yield { provider: 'forge', model, diff --git a/src/session-cache.ts b/src/session-cache.ts index fde4676..53f7a78 100644 --- a/src/session-cache.ts +++ b/src/session-cache.ts @@ -182,6 +182,7 @@ function validateCall(c: unknown): c is CachedCall { && isStringArray(o['tools']) && isStringArray(o['bashCommands']) && isStringArray(o['skills']) + && (o['subagentTypes'] === undefined || isStringArray(o['subagentTypes'])) && isOptionalString(o['project']) && isOptionalString(o['projectPath']) && (o['toolSequence'] === undefined || (Array.isArray(o['toolSequence']) && (o['toolSequence'] as unknown[]).every(s => isToolCallArray(s))))