Conversation
Add @praha/byethrow as devDependency for functional error handling to replace traditional try-catch patterns
…throw Result type Replace JSON.parse try-catch blocks with Result.try() for better functional error handling in main data processing loops
…type Replace monitoring loop try-catch with Result.try() for better functional error handling in live monitoring command
…ethrow Result type Replace JSON.parse try-catch with Result.try() for better functional error handling while keeping Promise.catch() for async file operations
Properly use Result.try() with async file reading by creating a wrapped function and calling it, rather than reverting to Promise.catch()
- Replace \!Result.isSuccess with more readable Result.isFailure - Fix Result.try function call pattern by creating wrapper function and calling it - Use early return pattern (continue) instead of ternary operators for better readability - All tests pass and TypeScript compilation succeeds
Document the preference for using @praha/byethrow Result type over traditional try-catch patterns with best practices and usage guidelines
WalkthroughThis update comprehensively refactors error handling throughout the codebase to use the Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant FileSystem/Network
participant Result
Note over Caller,Result: Example: JSON parsing with Result.try
Caller->>Result: Result.try(() => JSON.parse(line))
alt Success
Result-->>Caller: Success(parsedObject)
Caller->>Caller: Continue processing
else Failure
Result-->>Caller: Failure(error)
Caller->>Caller: Skip line or log error
end
sequenceDiagram
participant LiveMonitor
participant FileSystem
participant Result
Note over LiveMonitor,Result: Reading and parsing files
loop For each file
LiveMonitor->>Result: Result.try(async () => readFile(file))
alt File read succeeds
Result-->>LiveMonitor: Success(fileContent)
LiveMonitor->>Result: Result.try(() => JSON.parse(line))
alt Parse succeeds
Result-->>LiveMonitor: Success(parsedLine)
LiveMonitor->>LiveMonitor: Validate and accumulate
else Parse fails
Result-->>LiveMonitor: Failure(error)
LiveMonitor->>LiveMonitor: Skip line
end
else File read fails
Result-->>LiveMonitor: Failure(error)
LiveMonitor->>LiveMonitor: Skip file
end
end
Possibly related PRs
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | 67e2952 | Jun 29 2025, 08:50 PM |
There was a problem hiding this comment.
Summary of Changes
Hello @ryoppippi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces a significant shift in our error handling strategy by adopting a functional approach using the @praha/byethrow library's Result type. The change aims to enhance code clarity, type safety, and composability by replacing imperative try-catch blocks with explicit success/failure representations. All existing tests continue to pass, ensuring no behavioral regressions.
Highlights
- Dependency Addition: I've added the
@praha/byethrowlibrary, along with its MCP counterpart, to the project dependencies (package.json,bun.lock, and.mcp.json). This library provides aResulttype for functional error handling. - Error Handling Refactor: I've refactored traditional
try-catchblocks across 11 locations in 5 files (src/debug.ts,src/data-loader.ts,src/pricing-fetcher.ts,src/_live-monitor.ts,src/commands/_blocks.live.ts) to utilize the newResult.try()pattern. This includes error handling for JSON parsing, file reading, and network operations. - Code Readability and Type Safety: The refactor leverages
Result.isFailure()for clearer error checking and improves type safety by explicitly representing success and failure states, aligning with functional programming principles. - Documentation Update: I've updated
CLAUDE.mdto include new guidelines for error handling, recommending the@praha/byethrowResult type over traditionaltry-catchfor most scenarios.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
commit: |
| }); | ||
| const fileReader = Result.try({ | ||
| try: async () => readFile(file, 'utf-8'), | ||
| catch: () => new Error('File read failed'), |
There was a problem hiding this comment.
To improve debuggability, it's better to preserve the original error from readFile instead of creating a new generic Error. This provides more context on why the file read failed (e.g., 'file not found', 'permission denied'). You can achieve this by passing the error through in the catch block.
| catch: () => new Error('File read failed'), | |
| catch: error => error, |
| catch { | ||
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), |
There was a problem hiding this comment.
To aid in debugging, it's better to preserve the original error from JSON.parse. The default error provides specific details about what went wrong with the parsing (e.g., position of the syntax error), which is more useful than a generic 'Invalid JSON' message.
| catch: () => new Error('Invalid JSON'), | |
| catch: error => error, |
| markAsProcessed(uniqueHash, processedHashes); | ||
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), |
There was a problem hiding this comment.
| const data = result.data; | ||
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), |
| const result = usageDataSchema.safeParse(parsed); | ||
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Pull Request Overview
A refactor to adopt functional error handling using @praha/byethrow across the codebase.
- Added
@praha/byethrowdependencies. - Replaced traditional
try-catchblocks withResult.try()wrappers andResult.isFailure()checks. - Documented new error-handling guidelines in
CLAUDE.md.
Reviewed Changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pricing-fetcher.ts | Wrapped fetch and fallback logic in Result.try() patterns |
| src/debug.ts | Migrated JSON parsing to Result.try() and dropped try-catch |
| src/data-loader.ts | Updated JSON parsing loops to use Result.try() for invalid lines |
| src/commands/_blocks.live.ts | Wrapped monitoring loop in Result.try() and handle aborts |
| src/_live-monitor.ts | Converted file reads and JSON parsing to use Result.try() |
| package.json | Added @praha/byethrow and @praha/byethrow-mcp dependencies |
| CLAUDE.md | Added functional error-handling guidelines |
| .mcp.json | Configured MCP settings for @praha/byethrow |
Comments suppressed due to low confidence (2)
src/pricing-fetcher.ts:68
- [nitpick]
fallbackWrapperis ambiguous. Consider renaming to something likeloadOfflinePricingResultWrapperorofflinePricingOperationto clarify its purpose.
const fallbackWrapper = Result.try({
src/debug.ts:114
- [nitpick]
parseParseris unclear—rename toparseJsonWrapperorsafeJsonParseto better reflect that it's a JSON parsing helper.
const parseParser = Result.try({
| while (!abortController.signal.aborted) { | ||
| const now = Date.now(); | ||
| const timeSinceLastRender = now - lastRenderTime; | ||
| const monitoringResult = await Result.try({ |
There was a problem hiding this comment.
Non-Abort errors in the monitoring loop are swallowed after checking for AbortError. Add logging or rethrow unexpected errors to avoid silent failures.
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), | ||
| }); | ||
|
|
||
| if (!result.success) { | ||
| continue; | ||
| } | ||
| const parseResult = parseParser(); |
There was a problem hiding this comment.
The JSON.parse wrapper pattern is repeated across several modules. Consider extracting a reusable safeJsonParse helper to reduce duplication and improve readability.
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (1)
CLAUDE.md (1)
112-121: Excellent documentation of the new error handling conventions with minor grammatical improvements needed.The error handling guidelines are comprehensive and clearly document the new functional approach being adopted. This will help maintain consistency across the codebase.
Consider these minor grammatical improvements:
-Keep traditional try-catch only for: file I/O with complex error handling, legacy code that's hard to refactor +Keep traditional try-catch only for file I/O with complex error handling or legacy code that's difficult to refactor
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
.mcp.json(1 hunks)CLAUDE.md(1 hunks)package.json(1 hunks)src/_live-monitor.ts(2 hunks)src/commands/_blocks.live.ts(2 hunks)src/data-loader.ts(4 hunks)src/debug.ts(2 hunks)src/pricing-fetcher.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
`**/*.ts`: Use .ts extensions for local file imports (e.g., import { foo } from ...
**/*.ts: Use .ts extensions for local file imports (e.g., import { foo } from './utils.ts').
No console.log allowed except where explicitly disabled with eslint-disable; use logger.ts instead.
Tests are written directly in the same files as the source code, not in separate test files. Use in-source testing pattern with if (import.meta.vitest != null) blocks.
Dynamic imports using await import() should only be used within test blocks to avoid tree-shaking issues.
Only export constants, functions, and types that are actually used by other modules. Internal/private constants that are only used within the same file should NOT be exported.
Variables should start with lowercase (camelCase), types with uppercase (PascalCase), and constants can use UPPER_SNAKE_CASE.
After making any code changes, always run bun run format, bun typecheck, and bun run test to ensure code quality.
File paths must always use Node.js path utilities for cross-platform compatibility.
Dependencies should always be added as devDependencies unless explicitly requested otherwise.
📄 Source: CodeRabbit Inference Engine (CLAUDE.md)
List of files the instruction was applied to:
src/commands/_blocks.live.tssrc/_live-monitor.tssrc/pricing-fetcher.tssrc/debug.tssrc/data-loader.ts
`**/_*.ts`: Internal files should use underscore prefix (e.g., _types.ts, _utils.ts, _consts.ts).
**/_*.ts: Internal files should use underscore prefix (e.g., _types.ts, _utils.ts, _consts.ts).
📄 Source: CodeRabbit Inference Engine (CLAUDE.md)
List of files the instruction was applied to:
src/commands/_blocks.live.tssrc/_live-monitor.ts
🧠 Learnings (7)
package.json (1)
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Linting and formatting are enforced via ESLint with tab indentation and double quotes; TypeScript strict mode and bundler module resolution are required.
.mcp.json (1)
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Linting and formatting are enforced via ESLint with tab indentation and double quotes; TypeScript strict mode and bundler module resolution are required.
CLAUDE.md (1)
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Linting and formatting are enforced via ESLint with tab indentation and double quotes; TypeScript strict mode and bundler module resolution are required.
src/_live-monitor.ts (3)
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: The CLI tool architecture separates concerns: data loading (data-loader.ts), token aggregation (calculate-cost.ts), command execution (commands/), and CLI entry (index.ts).
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Linting and formatting are enforced via ESLint with tab indentation and double quotes; TypeScript strict mode and bundler module resolution are required.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Raw usage data is parsed from JSONL files with timestamp, token counts, and pre-calculated costs, and is aggregated into daily, monthly, session, or 5-hour billing block summaries.
src/pricing-fetcher.ts (3)
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Cost calculations depend on LiteLLM's pricing database; model names must exactly match LiteLLM's entries.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Tests depend on real pricing data from LiteLLM; always verify new model names exist in LiteLLM before adding tests.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: The application cannot calculate costs for models not supported by LiteLLM; test failures may indicate model name mismatches or missing pricing data.
src/debug.ts (5)
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Mock data for tests is created using fs-fixture with createFixture() to simulate Claude data directories.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Linting and formatting are enforced via ESLint with tab indentation and double quotes; TypeScript strict mode and bundler module resolution are required.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Raw usage data is parsed from JSONL files with timestamp, token counts, and pre-calculated costs, and is aggregated into daily, monthly, session, or 5-hour billing block summaries.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Error handling for JSONL parsing should silently skip malformed lines to ensure robustness.
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: The CLI tool architecture separates concerns: data loading (data-loader.ts), token aggregation (calculate-cost.ts), command execution (commands/), and CLI entry (index.ts).
src/data-loader.ts (4)
<retrieved_learning>
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Raw usage data is parsed from JSONL files with timestamp, token counts, and pre-calculated costs, and is aggregated into daily, monthly, session, or 5-hour billing block summaries.
</retrieved_learning>
<retrieved_learning>
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: The CLI tool architecture separates concerns: data loading (data-loader.ts), token aggregation (calculate-cost.ts), command execution (commands/), and CLI entry (index.ts).
</retrieved_learning>
<retrieved_learning>
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Error handling for JSONL parsing should silently skip malformed lines to ensure robustness.
</retrieved_learning>
<retrieved_learning>
Learnt from: CR
PR: ryoppippi/ccusage#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-23T13:20:08.531Z
Learning: Mock data for tests is created using fs-fixture with createFixture() to simulate Claude data directories.
</retrieved_learning>
🧬 Code Graph Analysis (5)
src/commands/_blocks.live.ts (2)
src/_consts.ts (1)
MIN_RENDER_INTERVAL_MS(110-110)src/_live-rendering.ts (3)
delayWithAbort(36-38)renderWaitingState(44-54)renderActiveBlock(60-68)
src/_live-monitor.ts (1)
src/data-loader.ts (3)
usageDataSchema(125-140)createUniqueHash(471-481)calculateCostForEntry(563-595)
src/pricing-fetcher.ts (3)
src/logger.ts (1)
logger(18-18)src/_consts.ts (1)
LITELLM_PRICING_URL(7-8)src/_types.ts (2)
ModelPricing(122-122)modelPricingSchema(112-117)
src/debug.ts (2)
src/data-loader.ts (1)
usageDataSchema(125-140)src/_consts.ts (1)
DEBUG_MATCH_THRESHOLD_PERCENT(38-38)
src/data-loader.ts (1)
src/logger.ts (1)
logger(18-18)
🪛 LanguageTool
CLAUDE.md
[typographical] ~119-~119: Do not use a colon (:) before a series that is introduced by a preposition (‘for’). Remove the colon or add a noun or a noun phrase after the preposition.
Context: ...ll it - Keep traditional try-catch only for: file I/O with complex error handling, l...
(RP_COLON)
[style] ~119-~119: To elevate your writing, try using a synonym here.
Context: ...plex error handling, legacy code that's hard to refactor - Always use `Result.isFail...
(HARD_TO)
🪛 ESLint
src/commands/_blocks.live.ts
[error] 56-86: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 56-86: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 56-56: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 56-56: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 58-58: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 58-58: Unsafe member access .signal on an error typed value.
(ts/no-unsafe-member-access)
[error] 64-64: Unsafe member access .signal on an error typed value.
(ts/no-unsafe-member-access)
[error] 73-73: Unsafe member access .signal on an error typed value.
(ts/no-unsafe-member-access)
[error] 82-82: Unsafe member access .signal on an error typed value.
(ts/no-unsafe-member-access)
[error] 85-85: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 88-88: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 88-88: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 88-88: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 89-89: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 89-89: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
src/_live-monitor.ts
[error] 95-98: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 95-95: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 95-95: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 96-96: Unsafe return of a value of type error.
(ts/no-unsafe-return)
[error] 96-96: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 100-100: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 100-100: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 101-101: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 101-101: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 101-101: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 106-106: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 106-106: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 107-110: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 107-110: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 107-109: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 107-108: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 108-108: Unsafe member access .trim on an error typed value.
(ts/no-unsafe-member-access)
[error] 109-109: Unsafe member access .split on an error typed value.
(ts/no-unsafe-member-access)
[error] 110-110: Unsafe member access .filter on an error typed value.
(ts/no-unsafe-member-access)
[error] 110-110: Unsafe member access .length on an any value.
(ts/no-unsafe-member-access)
[error] 113-116: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 113-113: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 113-113: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 114-114: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 118-118: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 118-118: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 119-119: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 119-119: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 119-119: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 124-124: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 124-124: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 125-125: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 125-125: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 128-128: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 128-128: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 140-146: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 141-141: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 150-150: Unsafe argument of type error typed assigned to a parameter of type string | number | Date.
(ts/no-unsafe-argument)
[error] 150-150: Unsafe member access .timestamp on an error typed value.
(ts/no-unsafe-member-access)
[error] 152-152: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 152-152: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 153-153: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 153-153: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 154-154: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 154-154: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 155-155: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 155-155: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 158-158: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 158-158: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 159-159: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 159-159: Unsafe member access .version on an error typed value.
(ts/no-unsafe-member-access)
src/pricing-fetcher.ts
[error] 68-71: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 68-68: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 68-68: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 70-70: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 73-73: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 73-73: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 74-74: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 74-74: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 74-74: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 75-75: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 75-75: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 75-75: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 76-76: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 76-76: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 80-80: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 80-80: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 81-81: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 81-81: Unsafe member access .info on an error typed value.
(ts/no-unsafe-member-access)
[error] 81-81: Unsafe member access .size on an error typed value.
(ts/no-unsafe-member-access)
[error] 82-82: Unsafe return of a value of type error.
(ts/no-unsafe-return)
[error] 100-128: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 100-100: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 100-100: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 102-102: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 102-102: Unsafe member access .warn on an error typed value.
(ts/no-unsafe-member-access)
[error] 103-103: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 103-103: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 104-104: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 104-104: Unsafe member access .ok on an error typed value.
(ts/no-unsafe-member-access)
[error] 105-105: Unsafe member access .statusText on an error typed value.
(ts/no-unsafe-member-access)
[error] 108-108: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 108-108: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 108-108: Unsafe member access .json on an error typed value.
(ts/no-unsafe-member-access)
[error] 115-115: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 115-115: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 115-115: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 116-116: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 116-116: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 117-117: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 124-124: Unsafe member access .info on an error typed value.
(ts/no-unsafe-member-access)
[error] 127-127: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 130-130: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 130-130: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 131-131: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 131-131: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 131-131: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 132-132: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 135-135: Unsafe return of a value of type error.
(ts/no-unsafe-return)
[error] 135-135: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
src/debug.ts
[error] 114-117: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 114-114: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 114-114: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 115-115: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 119-119: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 119-119: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 120-120: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 120-120: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 120-120: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 124-124: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 124-124: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 126-126: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 126-126: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 130-130: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 130-130: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 135-135: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 136-136: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 137-137: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 141-141: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 141-141: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 143-143: Unsafe argument of type error typed assigned to a parameter of type { input_tokens: number; output_tokens: number; cache_creation_input_tokens?: number | undefined; cache_read_input_tokens?: number | undefined; }.
(ts/no-unsafe-argument)
[error] 143-143: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 144-144: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 148-148: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 150-150: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 150-150: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 153-153: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 162-162: Unsafe member access .version on an error typed value.
(ts/no-unsafe-member-access)
[error] 163-163: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 163-163: Unsafe member access .version on an error typed value.
(ts/no-unsafe-member-access)
[error] 184-184: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 184-184: Unsafe member access .version on an error typed value.
(ts/no-unsafe-member-access)
[error] 196-196: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 196-196: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 196-196: Unsafe member access .basename on an error typed value.
(ts/no-unsafe-member-access)
[error] 197-197: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 197-197: Unsafe member access .timestamp on an error typed value.
(ts/no-unsafe-member-access)
[error] 198-198: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 199-199: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 199-199: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 203-203: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 203-203: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 211-211: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
src/data-loader.ts
[error] 666-669: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 666-666: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 666-666: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 667-667: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 671-671: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 671-671: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 672-672: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 672-672: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 672-672: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 677-677: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 677-677: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 677-677: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 677-677: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 678-678: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 678-678: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 681-681: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 681-681: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 693-693: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 693-693: Unsafe member access .timestamp on an error typed value.
(ts/no-unsafe-member-access)
[error] 696-698: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 698-698: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 700-700: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 700-700: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 700-700: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 700-700: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 830-833: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 830-830: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 830-830: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 831-831: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 835-835: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 835-835: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 836-836: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 836-836: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 836-836: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 841-841: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 841-841: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 841-841: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 841-841: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 842-842: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 842-842: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 845-845: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 845-845: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 858-860: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 860-860: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 863-863: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 865-865: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 866-866: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 867-867: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 868-868: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 868-868: Unsafe member access .timestamp on an error typed value.
(ts/no-unsafe-member-access)
[error] 869-869: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 869-869: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 1060-1063: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1060-1060: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1060-1060: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 1061-1061: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 1062-1062: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 1065-1065: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1065-1065: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1066-1066: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 1066-1066: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1066-1066: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1068-1068: Unsafe member access .debug on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 1072-1072: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1072-1072: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1072-1072: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 1072-1072: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 1073-1073: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 1073-1073: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 1076-1076: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1076-1076: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 1088-1090: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1090-1090: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 1093-1093: Unsafe argument of type error typed assigned to a parameter of type string | number | Date.
(ts/no-unsafe-argument)
[error] 1093-1093: Unsafe member access .timestamp on an error typed value.
(ts/no-unsafe-member-access)
[error] 1095-1095: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1095-1095: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 1096-1096: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1096-1096: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 1097-1097: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1097-1097: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 1098-1098: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1098-1098: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 1100-1100: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1101-1101: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1101-1101: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 1102-1102: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1102-1102: Unsafe member access .version on an error typed value.
(ts/no-unsafe-member-access)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Socket Security: Pull Request Alerts
- GitHub Check: Workers Builds: ccusage-guide
🔇 Additional comments (11)
package.json (1)
65-66: LGTM! Dependencies added correctly for functional error handling.The addition of
@praha/byethrowand@praha/byethrow-mcpas devDependencies aligns with the PR objective of adopting functional error handling. The version specifications look appropriate for the refactoring being implemented..mcp.json (1)
26-33: LGTM! MCP server configuration added correctly.The new
@praha/byethrowMCP server configuration follows the established pattern and properly integrates the byethrow functionality into the development environment.src/commands/_blocks.live.ts (2)
11-11: Import added correctly for functional error handling.The Result import from
@praha/byethrowsupports the new functional error handling pattern being adopted.
56-102: No TypeScript issues with Result.try() usageThe
@praha/byethrowpackage ships complete.d.tsfiles (e.g.,dist/cjs/index.d.tsandfunctions/try.d.ts), and a fulltsc --noEmitrun on the repo reports zero errors. TheResult.try()API is fully typed and safe—so the original type-safety concern does not apply.Likely an incorrect or invalid review comment.
src/_live-monitor.ts (1)
15-15: Import added correctly for functional error handling.The Result import supports the functional error handling refactor being implemented across the codebase.
src/data-loader.ts (2)
24-24: LGTM: Clean import additionThe import of
Resultfrom@praha/byethrowis properly added and follows the established import pattern.
57-57: Good: Logger import is properly usedThe logger import is correctly used in the
loadSessionBlockDatafunction for debug logging, which aligns with the coding guidelines that prohibit console.log usage.src/debug.ts (4)
12-12: LGTM: Import added for functional error handlingThe import of
Resultfrom@praha/byethrowaligns with the PR objective to standardize functional error handling across the codebase.
124-130: LGTM: Schema validation correctly uses parsed resultThe schema validation properly uses
parseResult.valueto access the successfully parsed JSON and maintains the pattern of skipping invalid entries.
153-185: LGTM: Statistics tracking improvementsThe refactoring to explicitly initialize counters and update statistics improves code clarity and maintainability. The logic correctly handles both model and version statistics with proper null coalescing.
114-122: ✅ Result.try() usage in src/debug.ts is correctThe
Result.try()invocation matches the established pattern across the codebase (seesrc/data-loader.ts,src/_live-monitor.ts,src/pricing-fetcher.ts) and aligns with the@praha/byethrowusage documented in CLAUDE.md. No TypeScript type errors were found for version ^0.3.0, so no fixes are required.
| const fileReader = Result.try({ | ||
| try: async () => readFile(file, 'utf-8'), | ||
| catch: () => new Error('File read failed'), | ||
| }); | ||
|
|
||
| const fileResult = await fileReader(); | ||
| if (Result.isFailure(fileResult)) { | ||
| // Skip files that can't be read | ||
| continue; | ||
| } | ||
|
|
||
| const content = fileResult.value; | ||
| const lines = content | ||
| .trim() | ||
| .split('\n') | ||
| .filter(line => line.length > 0); | ||
|
|
||
| for (const line of lines) { | ||
| try { | ||
| const parsed = JSON.parse(line) as unknown; | ||
| const result = usageDataSchema.safeParse(parsed); | ||
| if (!result.success) { | ||
| continue; | ||
| } | ||
| const data = result.data; | ||
|
|
||
| // Check for duplicates | ||
| const uniqueHash = createUniqueHash(data); | ||
| if (uniqueHash != null && this.processedHashes.has(uniqueHash)) { | ||
| continue; | ||
| } | ||
| if (uniqueHash != null) { | ||
| this.processedHashes.add(uniqueHash); | ||
| } | ||
|
|
||
| // Calculate cost if needed | ||
| const costUSD: number = await (this.config.mode === 'display' | ||
| ? Promise.resolve(data.costUSD ?? 0) | ||
| : calculateCostForEntry( | ||
| data, | ||
| this.config.mode, | ||
| this.fetcher!, | ||
| )); | ||
|
|
||
| // Add entry | ||
| this.allEntries.push({ | ||
| timestamp: new Date(data.timestamp), | ||
| usage: { | ||
| inputTokens: data.message.usage.input_tokens ?? 0, | ||
| outputTokens: data.message.usage.output_tokens ?? 0, | ||
| cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0, | ||
| cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0, | ||
| }, | ||
| costUSD, | ||
| model: data.message.model ?? '<synthetic>', | ||
| version: data.version, | ||
| }); | ||
| } | ||
| catch { | ||
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), | ||
| }); | ||
|
|
||
| const parseResult = parseParser(); | ||
| if (Result.isFailure(parseResult)) { | ||
| // Skip malformed lines | ||
| continue; | ||
| } | ||
|
|
||
| const result = usageDataSchema.safeParse(parseResult.value); | ||
| if (!result.success) { | ||
| continue; | ||
| } | ||
| const data = result.data; | ||
|
|
||
| // Check for duplicates | ||
| const uniqueHash = createUniqueHash(data); | ||
| if (uniqueHash != null && this.processedHashes.has(uniqueHash)) { | ||
| continue; | ||
| } | ||
| if (uniqueHash != null) { | ||
| this.processedHashes.add(uniqueHash); | ||
| } | ||
|
|
||
| // Calculate cost if needed | ||
| const costUSD: number = await (this.config.mode === 'display' | ||
| ? Promise.resolve(data.costUSD ?? 0) | ||
| : calculateCostForEntry( | ||
| data, | ||
| this.config.mode, | ||
| this.fetcher!, | ||
| )); | ||
|
|
||
| // Add entry | ||
| this.allEntries.push({ | ||
| timestamp: new Date(data.timestamp), | ||
| usage: { | ||
| inputTokens: data.message.usage.input_tokens ?? 0, | ||
| outputTokens: data.message.usage.output_tokens ?? 0, | ||
| cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0, | ||
| cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0, | ||
| }, | ||
| costUSD, | ||
| model: data.message.model ?? '<synthetic>', | ||
| version: data.version, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Functional error handling refactor is logically sound but has critical type safety issues.
The refactor successfully replaces try-catch blocks with the Result.try() pattern, maintaining the same robust error handling behavior (skipping unreadable files and malformed JSON lines). The logic correctly processes only successful results and continues on failures.
However, the same TypeScript type safety issues present in src/commands/_blocks.live.ts are evident here, where the Result type is being treated as any or error types.
The type safety issues need to be resolved across all files using the Result type. This appears to be a systemic issue with either:
- Missing or incorrect type definitions for
@praha/byethrow - TypeScript configuration not properly recognizing the Result types
- Incorrect usage of the Result API
Please ensure proper typing is established before merging to maintain type safety guarantees.
🧰 Tools
🪛 ESLint
[error] 95-98: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 95-95: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 95-95: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 96-96: Unsafe return of a value of type error.
(ts/no-unsafe-return)
[error] 96-96: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 100-100: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 100-100: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 101-101: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 101-101: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 101-101: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 106-106: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 106-106: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 107-110: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 107-110: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 107-109: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 107-108: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 108-108: Unsafe member access .trim on an error typed value.
(ts/no-unsafe-member-access)
[error] 109-109: Unsafe member access .split on an error typed value.
(ts/no-unsafe-member-access)
[error] 110-110: Unsafe member access .filter on an error typed value.
(ts/no-unsafe-member-access)
[error] 110-110: Unsafe member access .length on an any value.
(ts/no-unsafe-member-access)
[error] 113-116: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 113-113: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 113-113: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 114-114: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 118-118: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 118-118: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 119-119: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 119-119: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 119-119: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 124-124: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 124-124: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 125-125: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 125-125: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 128-128: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 128-128: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 140-146: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 141-141: Unsafe member access .costUSD on an error typed value.
(ts/no-unsafe-member-access)
[error] 150-150: Unsafe argument of type error typed assigned to a parameter of type string | number | Date.
(ts/no-unsafe-argument)
[error] 150-150: Unsafe member access .timestamp on an error typed value.
(ts/no-unsafe-member-access)
[error] 152-152: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 152-152: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 153-153: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 153-153: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 154-154: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 154-154: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 155-155: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 155-155: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 158-158: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 158-158: Unsafe member access .message on an error typed value.
(ts/no-unsafe-member-access)
[error] 159-159: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 159-159: Unsafe member access .version on an error typed value.
(ts/no-unsafe-member-access)
🤖 Prompt for AI Agents
In src/_live-monitor.ts between lines 95 and 161, the use of Result.try() and
related Result API calls lacks proper TypeScript type safety, causing the Result
type to be treated as any or error types. To fix this, explicitly type the
Result.try() calls with the expected return types, ensure the Result type is
correctly imported and used from @praha/byethrow, and verify that your
TypeScript configuration supports these types. Adjust the code to handle the
typed Result objects properly, avoiding any implicit any or error type
assumptions, so that type safety is preserved throughout the error handling
logic.
| */ | ||
|
|
||
| import type { ModelPricing } from './_types.ts'; | ||
| import { Result } from '@praha/byethrow'; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify TypeScript definitions for @praha/byethrow.
The functional error handling approach is a good improvement, but the numerous TypeScript safety warnings suggest potential issues with the library's type definitions.
🏁 Script executed:
#!/bin/bash
# Check if @praha/byethrow has proper TypeScript definitions
npm info @praha/byethrow
# Check if there are type definition files in node_modules
fd -t f "*.d.ts" node_modules/@praha/byethrow/ || echo "No TypeScript definitions found"
# Check the package.json for types field
cat node_modules/@praha/byethrow/package.json | jq '.types // .typings // "No types field found"'Length of output: 1117
Missing TypeScript definitions for @praha/byethrow
It looks like @praha/[email protected] doesn’t ship any .d.ts files nor declare a types/typings field, which is why you’re seeing unsafe-any warnings. To restore full type safety when using Result:
• Have the library publish proper declaration files (e.g. index.d.ts) and set "types": "index.d.ts" in its package.json, or
• Provide a scoped ambient module in our codebase as a stop-gap (declare module '@praha/byethrow';), understanding that it relaxes type checks.
Either way, we need type definitions in place before approving this refactor.
🤖 Prompt for AI Agents
In src/pricing-fetcher.ts at line 12, the import of Result from
'@praha/byethrow' lacks TypeScript type definitions, causing unsafe-any
warnings. To fix this, either coordinate with the library maintainers to publish
proper .d.ts files and update their package.json with a "types" field, or
temporarily add a scoped ambient module declaration (declare module
'@praha/byethrow';) in our codebase to suppress type errors while awaiting
official typings.
| const fetchWrapper = Result.try({ | ||
| try: async () => { | ||
| logger.warn('Fetching latest model pricing from LiteLLM...'); | ||
| const response = await fetch(LITELLM_PRICING_URL); | ||
| if (!response.ok) { | ||
| throw new Error(`Failed to fetch pricing data: ${response.statusText}`); | ||
| } | ||
|
|
||
| for (const [modelName, modelData] of Object.entries( | ||
| data as Record<string, unknown>, | ||
| )) { | ||
| if (typeof modelData === 'object' && modelData !== null) { | ||
| const parsed = modelPricingSchema.safeParse(modelData); | ||
| if (parsed.success) { | ||
| pricing.set(modelName, parsed.data); | ||
| const data = await response.json(); | ||
| const pricing = new Map<string, ModelPricing>(); | ||
|
|
||
| for (const [modelName, modelData] of Object.entries( | ||
| data as Record<string, unknown>, | ||
| )) { | ||
| if (typeof modelData === 'object' && modelData !== null) { | ||
| const parsed = modelPricingSchema.safeParse(modelData); | ||
| if (parsed.success) { | ||
| pricing.set(modelName, parsed.data); | ||
| } | ||
| // Skip models that don't match our schema | ||
| } | ||
| // Skip models that don't match our schema | ||
| } | ||
| } | ||
|
|
||
| this.cachedPricing = pricing; | ||
| logger.info(`Loaded pricing for ${pricing.size} models`); | ||
| return pricing; | ||
| } | ||
| catch (error) { | ||
| return this.handleFallbackToCachedPricing(error); | ||
| this.cachedPricing = pricing; | ||
| logger.info(`Loaded pricing for ${pricing.size} models`); | ||
| return pricing; | ||
| }, | ||
| catch: error => error, | ||
| }); | ||
|
|
||
| const fetchResult = await fetchWrapper(); | ||
| if (Result.isFailure(fetchResult)) { | ||
| return this.handleFallbackToCachedPricing(fetchResult.error); | ||
| } | ||
|
|
||
| return fetchResult.value; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Excellent refactor of complex async operation to Result pattern.
This refactor successfully converts a complex try-catch block with multiple failure points (fetch, JSON parsing, schema validation) into a functional Result pattern while preserving all original behavior including proper error handling and fallback logic.
To address the TypeScript safety warnings, consider adding explicit typing to the Result operations:
- const fetchWrapper = Result.try({
+ const fetchWrapper = Result.try<Map<string, ModelPricing>, Error>({
try: async () => {
logger.warn('Fetching latest model pricing from LiteLLM...');
const response = await fetch(LITELLM_PRICING_URL);
if (!response.ok) {
throw new Error(`Failed to fetch pricing data: ${response.statusText}`);
}
const data = await response.json();
const pricing = new Map<string, ModelPricing>();
for (const [modelName, modelData] of Object.entries(
data as Record<string, unknown>,
)) {
if (typeof modelData === 'object' && modelData !== null) {
const parsed = modelPricingSchema.safeParse(modelData);
if (parsed.success) {
pricing.set(modelName, parsed.data);
}
// Skip models that don't match our schema
}
}
this.cachedPricing = pricing;
logger.info(`Loaded pricing for ${pricing.size} models`);
return pricing;
},
catch: error => error,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const fetchWrapper = Result.try({ | |
| try: async () => { | |
| logger.warn('Fetching latest model pricing from LiteLLM...'); | |
| const response = await fetch(LITELLM_PRICING_URL); | |
| if (!response.ok) { | |
| throw new Error(`Failed to fetch pricing data: ${response.statusText}`); | |
| } | |
| for (const [modelName, modelData] of Object.entries( | |
| data as Record<string, unknown>, | |
| )) { | |
| if (typeof modelData === 'object' && modelData !== null) { | |
| const parsed = modelPricingSchema.safeParse(modelData); | |
| if (parsed.success) { | |
| pricing.set(modelName, parsed.data); | |
| const data = await response.json(); | |
| const pricing = new Map<string, ModelPricing>(); | |
| for (const [modelName, modelData] of Object.entries( | |
| data as Record<string, unknown>, | |
| )) { | |
| if (typeof modelData === 'object' && modelData !== null) { | |
| const parsed = modelPricingSchema.safeParse(modelData); | |
| if (parsed.success) { | |
| pricing.set(modelName, parsed.data); | |
| } | |
| // Skip models that don't match our schema | |
| } | |
| // Skip models that don't match our schema | |
| } | |
| } | |
| this.cachedPricing = pricing; | |
| logger.info(`Loaded pricing for ${pricing.size} models`); | |
| return pricing; | |
| } | |
| catch (error) { | |
| return this.handleFallbackToCachedPricing(error); | |
| this.cachedPricing = pricing; | |
| logger.info(`Loaded pricing for ${pricing.size} models`); | |
| return pricing; | |
| }, | |
| catch: error => error, | |
| }); | |
| const fetchResult = await fetchWrapper(); | |
| if (Result.isFailure(fetchResult)) { | |
| return this.handleFallbackToCachedPricing(fetchResult.error); | |
| } | |
| return fetchResult.value; | |
| } | |
| const fetchWrapper = Result.try<Map<string, ModelPricing>, Error>({ | |
| try: async () => { | |
| logger.warn('Fetching latest model pricing from LiteLLM...'); | |
| const response = await fetch(LITELLM_PRICING_URL); | |
| if (!response.ok) { | |
| throw new Error(`Failed to fetch pricing data: ${response.statusText}`); | |
| } | |
| const data = await response.json(); | |
| const pricing = new Map<string, ModelPricing>(); | |
| for (const [modelName, modelData] of Object.entries( | |
| data as Record<string, unknown>, | |
| )) { | |
| if (typeof modelData === 'object' && modelData !== null) { | |
| const parsed = modelPricingSchema.safeParse(modelData); | |
| if (parsed.success) { | |
| pricing.set(modelName, parsed.data); | |
| } | |
| // Skip models that don't match our schema | |
| } | |
| } | |
| this.cachedPricing = pricing; | |
| logger.info(`Loaded pricing for ${pricing.size} models`); | |
| return pricing; | |
| }, | |
| catch: error => error, | |
| }); |
🧰 Tools
🪛 ESLint
[error] 100-128: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 100-100: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 100-100: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 102-102: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 102-102: Unsafe member access .warn on an error typed value.
(ts/no-unsafe-member-access)
[error] 103-103: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 103-103: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 104-104: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 104-104: Unsafe member access .ok on an error typed value.
(ts/no-unsafe-member-access)
[error] 105-105: Unsafe member access .statusText on an error typed value.
(ts/no-unsafe-member-access)
[error] 108-108: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 108-108: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 108-108: Unsafe member access .json on an error typed value.
(ts/no-unsafe-member-access)
[error] 115-115: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 115-115: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 115-115: Unsafe member access .safeParse on an error typed value.
(ts/no-unsafe-member-access)
[error] 116-116: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 116-116: Unsafe member access .success on an error typed value.
(ts/no-unsafe-member-access)
[error] 117-117: Unsafe member access .data on an error typed value.
(ts/no-unsafe-member-access)
[error] 124-124: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 124-124: Unsafe member access .info on an error typed value.
(ts/no-unsafe-member-access)
[error] 127-127: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 130-130: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 130-130: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 131-131: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 131-131: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 131-131: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 132-132: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 135-135: Unsafe return of a value of type error.
(ts/no-unsafe-return)
[error] 135-135: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
🤖 Prompt for AI Agents
In src/pricing-fetcher.ts around lines 100 to 136, the Result.try and related
Result operations lack explicit TypeScript typings, which can cause safety
warnings. To fix this, add explicit generic type parameters to the Result.try
call and any other Result methods used here, specifying the expected success and
error types. This will ensure TypeScript can correctly infer types and eliminate
safety warnings while preserving the existing error handling and fallback logic.
| const fallbackWrapper = Result.try({ | ||
| try: async () => this.loadOfflinePricing(), | ||
| catch: error => error, | ||
| }); | ||
|
|
||
| const fallbackResult = await fallbackWrapper(); | ||
| if (Result.isFailure(fallbackResult)) { | ||
| logger.error('Failed to load cached pricing data as fallback:', fallbackResult.error); | ||
| logger.error('Original fetch error:', originalError); | ||
| throw new Error('Could not fetch model pricing data and fallback data is unavailable'); | ||
| } | ||
|
|
||
| const fallbackPricing = fallbackResult.value; | ||
| logger.info(`Using cached pricing data for ${fallbackPricing.size} models`); | ||
| return fallbackPricing; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Well-implemented functional error handling refactor.
The refactor correctly implements the Result pattern while maintaining the original error handling logic. The fallback mechanism is preserved, and the error logging provides appropriate context.
Consider adding type assertions or proper typing to address the TypeScript safety warnings:
- const fallbackWrapper = Result.try({
+ const fallbackWrapper = Result.try<Map<string, ModelPricing>, Error>({
try: async () => this.loadOfflinePricing(),
catch: error => error,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const fallbackWrapper = Result.try({ | |
| try: async () => this.loadOfflinePricing(), | |
| catch: error => error, | |
| }); | |
| const fallbackResult = await fallbackWrapper(); | |
| if (Result.isFailure(fallbackResult)) { | |
| logger.error('Failed to load cached pricing data as fallback:', fallbackResult.error); | |
| logger.error('Original fetch error:', originalError); | |
| throw new Error('Could not fetch model pricing data and fallback data is unavailable'); | |
| } | |
| const fallbackPricing = fallbackResult.value; | |
| logger.info(`Using cached pricing data for ${fallbackPricing.size} models`); | |
| return fallbackPricing; | |
| } | |
| const fallbackWrapper = Result.try<Map<string, ModelPricing>, Error>({ | |
| try: async () => this.loadOfflinePricing(), | |
| catch: error => error, | |
| }); | |
| const fallbackResult = await fallbackWrapper(); | |
| if (Result.isFailure(fallbackResult)) { | |
| logger.error('Failed to load cached pricing data as fallback:', fallbackResult.error); | |
| logger.error('Original fetch error:', originalError); | |
| throw new Error('Could not fetch model pricing data and fallback data is unavailable'); | |
| } | |
| const fallbackPricing = fallbackResult.value; | |
| logger.info(`Using cached pricing data for ${fallbackPricing.size} models`); | |
| return fallbackPricing; |
🧰 Tools
🪛 ESLint
[error] 68-71: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 68-68: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 68-68: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 70-70: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 73-73: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 73-73: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 74-74: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 74-74: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 74-74: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 75-75: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 75-75: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 75-75: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 76-76: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 76-76: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 80-80: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 80-80: Unsafe member access .value on an error typed value.
(ts/no-unsafe-member-access)
[error] 81-81: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 81-81: Unsafe member access .info on an error typed value.
(ts/no-unsafe-member-access)
[error] 81-81: Unsafe member access .size on an error typed value.
(ts/no-unsafe-member-access)
[error] 82-82: Unsafe return of a value of type error.
(ts/no-unsafe-return)
🤖 Prompt for AI Agents
In src/pricing-fetcher.ts around lines 68 to 83, add explicit type annotations
or assertions to the fallbackWrapper and fallbackResult variables to ensure
TypeScript correctly infers their types. This will eliminate safety warnings by
clearly defining the expected Result type returned by the try method and the
structure of fallbackResult, improving type safety without changing the existing
error handling logic.
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), | ||
| }); | ||
|
|
||
| // Check for duplicate message + request ID combination | ||
| const uniqueHash = createUniqueHash(data); | ||
| if (isDuplicateEntry(uniqueHash, processedHashes)) { | ||
| // Skip duplicate message | ||
| continue; | ||
| } | ||
| const parseResult = parseParser(); | ||
| if (Result.isFailure(parseResult)) { | ||
| // Skip invalid JSON lines | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Same TypeScript type safety issues as loadDailyUsageData
This implementation has identical type safety problems to the previous function.
Apply the same fix as suggested for loadDailyUsageData:
- const parseParser = Result.try({
- try: () => JSON.parse(line) as unknown,
- catch: () => new Error('Invalid JSON'),
- });
-
- const parseResult = parseParser();
- if (Result.isFailure(parseResult)) {
+ const parseResult = Result.try(() => JSON.parse(line) as unknown);
+ if (Result.isFailure(parseResult)) {
// Skip invalid JSON lines
continue;
}
const result = usageDataSchema.safeParse(parseResult.value);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const parseParser = Result.try({ | |
| try: () => JSON.parse(line) as unknown, | |
| catch: () => new Error('Invalid JSON'), | |
| }); | |
| // Check for duplicate message + request ID combination | |
| const uniqueHash = createUniqueHash(data); | |
| if (isDuplicateEntry(uniqueHash, processedHashes)) { | |
| // Skip duplicate message | |
| continue; | |
| } | |
| const parseResult = parseParser(); | |
| if (Result.isFailure(parseResult)) { | |
| // Skip invalid JSON lines | |
| continue; | |
| } | |
| const parseResult = Result.try(() => JSON.parse(line) as unknown); | |
| if (Result.isFailure(parseResult)) { | |
| // Skip invalid JSON lines | |
| continue; | |
| } | |
| const result = usageDataSchema.safeParse(parseResult.value); |
🧰 Tools
🪛 ESLint
[error] 830-833: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 830-830: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 830-830: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 831-831: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 835-835: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 835-835: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 836-836: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 836-836: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 836-836: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
🤖 Prompt for AI Agents
In src/data-loader.ts around lines 830 to 839, the JSON parsing uses a generic
unknown type which lacks proper TypeScript type safety. To fix this, replace the
unknown type with a specific interface or type that represents the expected JSON
structure, and update the JSON.parse call to cast to that type. This ensures
type safety and prevents runtime errors by validating the parsed data against
the expected type.
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: () => new Error('Invalid JSON'), | ||
| }); | ||
|
|
||
| const date = formatDate(data.timestamp); | ||
| // If fetcher is available, calculate cost based on mode and tokens | ||
| // If fetcher is null, use pre-calculated costUSD or default to 0 | ||
| const cost = fetcher != null | ||
| ? await calculateCostForEntry(data, mode, fetcher) | ||
| : data.costUSD ?? 0; | ||
| const parseResult = parseParser(); | ||
| if (Result.isFailure(parseResult)) { | ||
| // Skip invalid JSON lines | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Address TypeScript type safety issues with Result usage
The functional error handling pattern is correct, but there are significant TypeScript type safety issues that need to be resolved.
The static analysis is flagging multiple unsafe type operations. Apply this diff to improve type safety:
- const parseParser = Result.try({
- try: () => JSON.parse(line) as unknown,
- catch: () => new Error('Invalid JSON'),
- });
-
- const parseResult = parseParser();
- if (Result.isFailure(parseResult)) {
+ const parseResult = Result.try(() => JSON.parse(line) as unknown);
+ if (Result.isFailure(parseResult)) {
// Skip invalid JSON lines
continue;
}
const result = usageDataSchema.safeParse(parseResult.value);This should resolve the type safety issues while maintaining the same functionality.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const parseParser = Result.try({ | |
| try: () => JSON.parse(line) as unknown, | |
| catch: () => new Error('Invalid JSON'), | |
| }); | |
| const date = formatDate(data.timestamp); | |
| // If fetcher is available, calculate cost based on mode and tokens | |
| // If fetcher is null, use pre-calculated costUSD or default to 0 | |
| const cost = fetcher != null | |
| ? await calculateCostForEntry(data, mode, fetcher) | |
| : data.costUSD ?? 0; | |
| const parseResult = parseParser(); | |
| if (Result.isFailure(parseResult)) { | |
| // Skip invalid JSON lines | |
| continue; | |
| } | |
| const parseResult = Result.try(() => JSON.parse(line) as unknown); | |
| if (Result.isFailure(parseResult)) { | |
| // Skip invalid JSON lines | |
| continue; | |
| } | |
| const result = usageDataSchema.safeParse(parseResult.value); |
🧰 Tools
🪛 ESLint
[error] 666-669: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 666-666: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 666-666: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 667-667: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 671-671: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 671-671: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 672-672: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 672-672: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 672-672: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
🤖 Prompt for AI Agents
In src/data-loader.ts around lines 666 to 675, the current use of Result.try
with JSON.parse has TypeScript type safety issues due to unsafe type assertions.
To fix this, explicitly type the Result.try call to reflect that it returns a
Result with the parsed JSON type or an Error. Adjust the try function to return
the correct type without using 'as unknown', and ensure the catch function
returns an Error. This will improve static type checking while preserving the
existing error handling logic.
| const parseParser = Result.try({ | ||
| try: () => JSON.parse(line) as unknown, | ||
| catch: error => error, | ||
| }); | ||
|
|
||
| const cost = fetcher != null | ||
| ? await calculateCostForEntry(data, mode, fetcher) | ||
| : data.costUSD ?? 0; | ||
| const parseResult = parseParser(); | ||
| if (Result.isFailure(parseResult)) { | ||
| // Skip invalid JSON lines but log for debugging purposes | ||
| logger.debug(`Skipping invalid JSON line in 5-hour blocks: ${parseResult.error instanceof Error ? parseResult.error.message : String(parseResult.error)}`); | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Fix type safety issues and inconsistent error handling
This implementation has both the same TypeScript issues and an inconsistent error handling pattern compared to the other two functions.
Apply this diff to fix both issues:
- const parseParser = Result.try({
- try: () => JSON.parse(line) as unknown,
- catch: error => error,
- });
-
- const parseResult = parseParser();
- if (Result.isFailure(parseResult)) {
- // Skip invalid JSON lines but log for debugging purposes
- logger.debug(`Skipping invalid JSON line in 5-hour blocks: ${parseResult.error instanceof Error ? parseResult.error.message : String(parseResult.error)}`);
+ const parseResult = Result.try(() => JSON.parse(line) as unknown);
+ if (Result.isFailure(parseResult)) {
+ // Skip invalid JSON lines but log for debugging purposes
+ logger.debug(`Skipping invalid JSON line in 5-hour blocks: ${parseResult.error instanceof Error ? parseResult.error.message : 'Invalid JSON'}`);
continue;
}
const result = usageDataSchema.safeParse(parseResult.value);Note: The inconsistent catch: error => error pattern differs from the other functions and may cause additional type issues.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const parseParser = Result.try({ | |
| try: () => JSON.parse(line) as unknown, | |
| catch: error => error, | |
| }); | |
| const cost = fetcher != null | |
| ? await calculateCostForEntry(data, mode, fetcher) | |
| : data.costUSD ?? 0; | |
| const parseResult = parseParser(); | |
| if (Result.isFailure(parseResult)) { | |
| // Skip invalid JSON lines but log for debugging purposes | |
| logger.debug(`Skipping invalid JSON line in 5-hour blocks: ${parseResult.error instanceof Error ? parseResult.error.message : String(parseResult.error)}`); | |
| continue; | |
| } | |
| const parseResult = Result.try(() => JSON.parse(line) as unknown); | |
| if (Result.isFailure(parseResult)) { | |
| // Skip invalid JSON lines but log for debugging purposes | |
| logger.debug(`Skipping invalid JSON line in 5-hour blocks: ${parseResult.error instanceof Error ? parseResult.error.message : 'Invalid JSON'}`); | |
| continue; | |
| } | |
| const result = usageDataSchema.safeParse(parseResult.value); |
🧰 Tools
🪛 ESLint
[error] 1060-1063: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1060-1060: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1060-1060: Unsafe member access .try on an error typed value.
(ts/no-unsafe-member-access)
[error] 1061-1061: Unsafe argument of type error typed assigned to a parameter of type string.
(ts/no-unsafe-argument)
[error] 1062-1062: Unsafe return of a value of type any.
(ts/no-unsafe-return)
[error] 1065-1065: Unsafe assignment of an error typed value.
(ts/no-unsafe-assignment)
[error] 1065-1065: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1066-1066: Unexpected any value in conditional. An explicit comparison or type conversion is required.
(ts/strict-boolean-expressions)
[error] 1066-1066: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1066-1066: Unsafe member access .isFailure on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe call of a(n) error type typed value.
(ts/no-unsafe-call)
[error] 1068-1068: Unsafe member access .debug on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
[error] 1068-1068: Unsafe member access .error on an error typed value.
(ts/no-unsafe-member-access)
🤖 Prompt for AI Agents
In src/data-loader.ts around lines 1060 to 1070, the current JSON parsing uses a
catch handler that returns the error directly, causing type safety issues and
inconsistent error handling compared to other functions. To fix this, update the
catch handler to wrap the error in a consistent failure result or error type as
used elsewhere, ensuring the parseParser function returns a uniform result type.
Adjust the error handling logic accordingly to maintain type safety and
consistency.
| stats.matches++; | ||
| modelStat.matches++; | ||
| // Consider it a match if within the defined threshold (to account for floating point) | ||
| if (percentDiff < DEBUG_MATCH_THRESHOLD_PERCENT) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix threshold inconsistency between model and version matching
There's an inconsistency in threshold usage:
- Line 172: Uses
DEBUG_MATCH_THRESHOLD_PERCENTconstant for version-level matching - Line 188: Uses hardcoded
0.1for model-level matching
Both should use the same threshold for consistency.
Apply this diff to use the constant consistently:
- // Consider it a match if within 0.1% difference (to account for floating point)
- if (percentDiff < 0.1) {
+ // Consider it a match if within the defined threshold (to account for floating point)
+ if (percentDiff < DEBUG_MATCH_THRESHOLD_PERCENT) {Also applies to: 188-188
🤖 Prompt for AI Agents
In src/debug.ts at lines 172 and 188, replace the hardcoded threshold value 0.1
used for model-level matching with the constant DEBUG_MATCH_THRESHOLD_PERCENT to
ensure consistent threshold usage across both version-level and model-level
matching.
Summary
Add @praha/byethrow dependency and replace traditional try-catch blocks with Result.try() for functional error handling across 11 locations in 5 files.
Key Changes
Files Modified
Benefits
Test Status
✅ TypeScript compilation succeeds
✅ All tests pass (210/210)
✅ ESLint formatting applied
Summary by CodeRabbit
New Features
@praha/byethrowpackage and related configuration for enhanced error handling.Refactor
Resultpattern for error handling across multiple modules, improving code clarity and reliability.Documentation
Resulttype to the code style notes.Chores
@praha/byethrowand@praha/byethrow-mcp.