Skip to content

Conversation

@ryoppippi
Copy link
Owner

@ryoppippi ryoppippi commented Jan 9, 2026

Summary

Fix date truncation in amp, opencode, codex, and pi CLI apps by adding dateFormatter to ResponsiveTable configuration.

What Changed

  • terminal package: Add formatDateCompact function for consistent date formatting across all packages
  • ccusage: Re-export formatDateCompact from the shared terminal package (removes duplication)
  • amp/opencode/codex/pi: Configure dateFormatter in all table views to properly format dates when terminal is narrow

Why

Previously, ccusage formatted dates nicely in tables, but amp, opencode, codex, and pi apps were showing truncated dates because they weren't using the dateFormatter option. This change ensures all CLI apps have consistent date display behaviour.

Test Plan

  • pnpm run format passes
  • pnpm typecheck passes
  • pnpm run test passes (all 337 tests)

Summary by CodeRabbit

  • Improvements
    • Date formatting has been standardized across all report types (daily, monthly, session, and weekly reports) to display in a more compact format for improved readability and visual consistency throughout the application.

✏️ Tip: You can customize this high-level summary in your review settings.

…rmatting

Move formatDateCompact from ccusage to the shared terminal package so
all apps can use consistent date formatting in tables. This function
formats dates as "YYYY\nMM-DD" for compact table display when terminal
width is limited.

The function handles both YYYY-MM-DD and ISO timestamp formats, with
optional timezone and locale parameters.
Replace local formatDateCompact implementation with a re-export from
@ccusage/terminal/table. This removes code duplication and ensures
consistent date formatting across all packages.

Move related tests to the terminal package where the implementation
now lives.
Add dateFormatter option to ResponsiveTable in all CLI apps to ensure
dates are properly formatted when terminal width is narrow. Previously,
dates were being truncated because the dateFormatter was not configured.

This change imports formatDateCompact from @ccusage/terminal and passes
it to the table configuration, matching the behaviour of ccusage.

Affected commands:
- amp: daily, monthly, session
- opencode: daily, monthly, session, weekly
- codex: daily, monthly, session
- pi: daily, monthly, session
@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

The PR adds a new formatDateCompact utility function to format dates in compact "YYYY\nMM-DD" form and consolidates its implementation in a shared package. This formatter is then imported and wired as a dateFormatter option into ResponsiveTable configurations across multiple command files in different applications.

Changes

Cohort / File(s) Summary
Shared date formatting utility
packages/terminal/src/table.ts
Added new exported function formatDateCompact(dateStr: string, timezone?: string, locale?: string) that formats dates into compact "YYYY\nMM-DD" form with timezone and locale support. Includes default locale constant (en-CA) and Intl.DateTimeFormat helper (+76 lines)
Date utilities refactoring
apps/ccusage/src/_date-utils.ts
Removed local formatDateCompact implementation and unused valibot dependencies; added re-export of formatDateCompact from @ccusage/terminal/table. Consolidated date formatting logic into shared package (net -64 lines)
AMP command formatters
apps/amp/src/commands/daily.ts, monthly.ts, session.ts
Added import of formatDateCompact and wired dateFormatter: (dateStr: string) => formatDateCompact(dateStr) option into ResponsiveTable constructor for each file
Codex command formatters
apps/codex/src/commands/daily.ts, monthly.ts, session.ts
Added import of formatDateCompact and wired dateFormatter option into ResponsiveTable configurations
OpenCode command formatters
apps/opencode/src/commands/daily.ts, monthly.ts, session.ts, weekly.ts
Added import of formatDateCompact and wired dateFormatter option into ResponsiveTable for each command
Pi command formatters
apps/pi/src/commands/daily.ts, monthly.ts, session.ts
Replaced identity passthrough dateFormatter with formatDateCompact invocation in respective table configurations

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related PRs

Poem

🐰 A formatter hops through every command with glee,
Compact dates now dance in "YYYY\nMM-DD" spree,
From tables to terminals, the formatter's shared with care,
Consistency blooms across the codebase everywhere! 📅✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding dateFormatter configuration to prevent date truncation in table displays across multiple apps.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide bd48861 Jan 09 2026, 01:21 PM

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 9, 2026

Open in StackBlitz

@ccusage/amp

npm i https://pkg.pr.new/ryoppippi/ccusage/@ccusage/amp@788

ccusage

npm i https://pkg.pr.new/ryoppippi/ccusage@788

@ccusage/codex

npm i https://pkg.pr.new/ryoppippi/ccusage/@ccusage/codex@788

@ccusage/mcp

npm i https://pkg.pr.new/ryoppippi/ccusage/@ccusage/mcp@788

@ccusage/opencode

npm i https://pkg.pr.new/ryoppippi/ccusage/@ccusage/opencode@788

@ccusage/pi

npm i https://pkg.pr.new/ryoppippi/ccusage/@ccusage/pi@788

commit: bd48861

@ryoppippi ryoppippi merged commit 09bf536 into main Jan 9, 2026
16 of 17 checks passed
@ryoppippi ryoppippi deleted the fix/date-truncation-in-tables branch January 9, 2026 13:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/opencode/src/commands/daily.ts (1)

1-15: Simplify dateFormatter and fix local import extensions for consistency.

  • Line 138-139: Replace dateFormatter: (dateStr: string) => formatDateCompact(dateStr) with dateFormatter: formatDateCompact (the signatures are compatible).
  • Lines 13-14: Add .ts extensions to local imports ('../cost-utils.ts' and '../data-loader.ts') to match the project convention already used in other files.
Proposed changes
-import { calculateCostForEntry } from '../cost-utils';
-import { loadOpenCodeMessages } from '../data-loader';
+import { calculateCostForEntry } from '../cost-utils.ts';
+import { loadOpenCodeMessages } from '../data-loader.ts';
 			compactThreshold: 100,
 			forceCompact: Boolean(ctx.values.compact),
 			style: { head: ['cyan'] },
-			dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+			dateFormatter: formatDateCompact,
 		});
apps/pi/src/commands/daily.ts (1)

2-9: Pass --timezone parameter to formatDateCompact in table rendering.

The --timezone/-z CLI option is defined (lines 31–35) and passed to the data loader (line 56), but the table formatter ignores it. formatDateCompact accepts and respects a timezone parameter, so pass it here for the date display to honor the user's timezone choice.

Proposed change
 			const table = createUsageReportTable({
 				firstColumnName: 'Date',
-				dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+				dateFormatter: (dateStr: string) => formatDateCompact(dateStr, ctx.values.timezone),
 			});

Note: This same issue exists in monthly.ts and session.ts—all three should be updated consistently.

🤖 Fix all issues with AI agents
In @packages/terminal/src/table.ts:
- Around line 31-54: Update the JSDoc for formatDateCompact to match the actual
default locale used in code: replace the incorrect "defaults to sv-SE for
YYYY-MM-DD format" text with a statement that it defaults to DEFAULT_LOCALE
(en-CA) or explicitly "defaults to en-CA" so the comment reflects the
implementation using DEFAULT_LOCALE.
🧹 Nitpick comments (5)
apps/amp/src/commands/daily.ts (1)

2-9: Use dateFormatter: formatDateCompact (no need for a wrapper).

formatDateCompact already matches (dateStr: string) => string, so you can pass it directly.

Proposed change
 			compactThreshold: 100,
 			forceCompact: Boolean(ctx.values.compact),
 			style: { head: ['cyan'] },
-			dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+			dateFormatter: formatDateCompact,
 		});

Also applies to: 146-165

apps/opencode/src/commands/monthly.ts (1)

138-138: Correct implementation with an optional simplification.

The dateFormatter option is correctly wired to use formatDateCompact, achieving the PR objective of preventing date truncation in narrow terminals.

♻️ Optional: Simplify arrow function wrapper

Since formatDateCompact already matches the expected signature, you can pass it directly:

-			dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+			dateFormatter: formatDateCompact,

This same simplification applies to all similar usages across the other command files in this PR (amp/session.ts, codex/session.ts, codex/daily.ts, opencode/session.ts).

apps/pi/src/commands/monthly.ts (1)

104-104: Optional: Simplify the dateFormatter wrapper.

The wrapper function (dateStr: string) => formatDateCompact(dateStr) is redundant since formatDateCompact already has the same signature. You can pass the function directly.

♻️ Simplify to direct reference
-				dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+				dateFormatter: formatDateCompact,
apps/codex/src/commands/monthly.ts (1)

133-133: Optional: Simplify the dateFormatter wrapper.

The wrapper function is redundant. You can pass formatDateCompact directly since it already matches the expected signature.

♻️ Simplify to direct reference
-				dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+				dateFormatter: formatDateCompact,
apps/opencode/src/commands/weekly.ts (1)

163-163: Optional: Simplify the dateFormatter wrapper.

The wrapper function is redundant and can be replaced with a direct reference to formatDateCompact.

♻️ Simplify to direct reference
-			dateFormatter: (dateStr: string) => formatDateCompact(dateStr),
+			dateFormatter: formatDateCompact,
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae115c3 and bd48861.

📒 Files selected for processing (15)
  • apps/amp/src/commands/daily.ts
  • apps/amp/src/commands/monthly.ts
  • apps/amp/src/commands/session.ts
  • apps/ccusage/src/_date-utils.ts
  • apps/codex/src/commands/daily.ts
  • apps/codex/src/commands/monthly.ts
  • apps/codex/src/commands/session.ts
  • apps/opencode/src/commands/daily.ts
  • apps/opencode/src/commands/monthly.ts
  • apps/opencode/src/commands/session.ts
  • apps/opencode/src/commands/weekly.ts
  • apps/pi/src/commands/daily.ts
  • apps/pi/src/commands/monthly.ts
  • apps/pi/src/commands/session.ts
  • packages/terminal/src/table.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Import conventions: Use .ts extensions for local file imports (e.g., import { foo } from './utils.ts')
Use ESLint for linting and formatting with tab indentation and double quotes
No console.log allowed except where explicitly disabled with eslint-disable
Use camelCase for variable names (e.g., usageDataSchema, modelBreakdownSchema)
Use PascalCase for type names (e.g., UsageData, ModelBreakdown)
Use UPPER_SNAKE_CASE for constants (e.g., DEFAULT_CLAUDE_CODE_PATH)
Only export constants, functions, and types that are actually used by other modules - do not export internal/private constants used only within the same file
Prefer @praha/byethrow Result type over traditional try-catch for functional error handling
Use Result.try() for wrapping operations that may throw (JSON parsing, etc.)
Use Result.isFailure() for checking errors (more readable than !Result.isSuccess())
Use early return pattern (if (Result.isFailure(result)) continue;) instead of ternary operators with Result types
NEVER use await import() dynamic imports anywhere in the codebase - this causes tree-shaking issues
Do not use console.log - use logger.ts instead
Vitest globals (describe, it, expect) are available automatically without imports in test blocks
NEVER use await import() dynamic imports in vitest test blocks - this is particularly problematic for test execution
All test files must use current Claude 4 models (claude-sonnet-4-20250514, claude-opus-4-20250514), not outdated Claude 3 models
Model names in tests must exactly match LiteLLM's pricing database entries

Files:

  • apps/codex/src/commands/session.ts
  • apps/amp/src/commands/monthly.ts
  • apps/opencode/src/commands/monthly.ts
  • apps/pi/src/commands/session.ts
  • apps/pi/src/commands/daily.ts
  • apps/amp/src/commands/daily.ts
  • apps/opencode/src/commands/session.ts
  • apps/codex/src/commands/monthly.ts
  • packages/terminal/src/table.ts
  • apps/ccusage/src/_date-utils.ts
  • apps/amp/src/commands/session.ts
  • apps/opencode/src/commands/daily.ts
  • apps/pi/src/commands/monthly.ts
  • apps/codex/src/commands/daily.ts
  • apps/opencode/src/commands/weekly.ts
apps/amp/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (apps/amp/CLAUDE.md)

NEVER use await import() dynamic imports anywhere, especially in test blocks in Amp CLI

Files:

  • apps/amp/src/commands/monthly.ts
  • apps/amp/src/commands/daily.ts
  • apps/amp/src/commands/session.ts
apps/opencode/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/opencode/CLAUDE.md)

apps/opencode/**/*.{ts,tsx,js,jsx}: Message structure must include tokens.input, tokens.output, tokens.cache.read, and tokens.cache.write fields
Map token fields: inputTokenstokens.input, outputTokenstokens.output, cacheReadInputTokenstokens.cache.read, cacheCreationInputTokenstokens.cache.write
Calculate costs using model pricing data when pre-calculated cost field is not present in OpenCode messages
Reuse shared packages (@ccusage/terminal, @ccusage/internal) wherever possible
Data discovery relies on OPENCODE_DATA_DIR environment variable with default path ~/.local/share/opencode
Place all vitest blocks alongside implementation files via if (import.meta.vitest != null) guards

apps/opencode/**/*.{ts,tsx,js,jsx}: Use meaningful variable and function names that clearly describe their purpose
Add JSDoc comments to exported functions and classes to document their purpose, parameters, and return values
Prefer const for variables that won't be reassigned; use let for variables that will be reassigned
Use immutable data structures and avoid mutation where possible

Files:

  • apps/opencode/src/commands/monthly.ts
  • apps/opencode/src/commands/session.ts
  • apps/opencode/src/commands/daily.ts
  • apps/opencode/src/commands/weekly.ts
apps/opencode/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/opencode/AGENTS.md)

Avoid using any type in TypeScript; use explicit types or generics instead

Files:

  • apps/opencode/src/commands/monthly.ts
  • apps/opencode/src/commands/session.ts
  • apps/opencode/src/commands/daily.ts
  • apps/opencode/src/commands/weekly.ts
apps/pi/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/pi/CLAUDE.md)

apps/pi/src/**/*.{ts,tsx}: Prefer @praha/byethrow Result type over try-catch for error handling
Use .ts extensions for local imports
Only export what's actually used from modules
NEVER use await import() dynamic imports anywhere in the codebase

Files:

  • apps/pi/src/commands/session.ts
  • apps/pi/src/commands/daily.ts
  • apps/pi/src/commands/monthly.ts
apps/ccusage/src/**/*.ts

📄 CodeRabbit inference engine (apps/ccusage/CLAUDE.md)

apps/ccusage/src/**/*.ts: Write tests in-source using if (import.meta.vitest != null) blocks instead of separate test files
Use Vitest globals (describe, it, expect) without imports in test blocks
In tests, use current Claude 4 models (sonnet-4, opus-4)
Use fs-fixture with createFixture() to simulate Claude data in tests
Only export symbols that are actually used by other modules
Do not use console.log; use the logger utilities from src/logger.ts instead

Files:

  • apps/ccusage/src/_date-utils.ts
apps/ccusage/**/*.ts

📄 CodeRabbit inference engine (apps/ccusage/CLAUDE.md)

apps/ccusage/**/*.ts: NEVER use await import() dynamic imports anywhere (especially in tests)
Prefer @praha/byethrow Result type for error handling instead of try-catch
Use .ts extensions for local imports (e.g., import { foo } from './utils.ts')

Files:

  • apps/ccusage/src/_date-utils.ts
**/_*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use underscore prefix for internal files (e.g., _types.ts, _utils.ts, _consts.ts)

Files:

  • apps/ccusage/src/_date-utils.ts
🧠 Learnings (13)
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/**/*.ts : Use `.ts` extensions for local imports (e.g., `import { foo } from './utils.ts'`)

Applied to files:

  • apps/pi/src/commands/session.ts
  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T12:35:27.240Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/amp/CLAUDE.md:0-0
Timestamp: 2026-01-09T12:35:27.240Z
Learning: Reuse shared packages ccusage/terminal and ccusage/internal wherever possible in Amp CLI

Applied to files:

  • apps/amp/src/commands/daily.ts
  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T11:07:17.610Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.610Z
Learning: Applies to apps/opencode/**/*.{ts,tsx,js,jsx} : Reuse shared packages (`ccusage/terminal`, `ccusage/internal`) wherever possible

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Only export symbols that are actually used by other modules

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-17T18:29:15.764Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/mcp/CLAUDE.md:0-0
Timestamp: 2025-09-17T18:29:15.764Z
Learning: Applies to apps/mcp/**/*.ts : Only export what is actually used

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Do not use console.log; use the logger utilities from `src/logger.ts` instead

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Write tests in-source using `if (import.meta.vitest != null)` blocks instead of separate test files

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T12:22:39.520Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.520Z
Learning: Applies to **/*.ts : Only export constants, functions, and types that are actually used by other modules - do not export internal/private constants used only within the same file

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T12:07:00.515Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/pi/CLAUDE.md:0-0
Timestamp: 2026-01-09T12:07:00.515Z
Learning: Applies to apps/pi/src/**/*.{ts,tsx} : Only export what's actually used from modules

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Use Vitest globals (`describe`, `it`, `expect`) without imports in test blocks

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T11:07:17.610Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.610Z
Learning: Applies to apps/opencode/**/*.test.{ts,tsx,js,jsx} : Vitest globals are enabled - use `describe`, `it`, `expect` directly without imports

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-17T18:29:15.764Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/mcp/CLAUDE.md:0-0
Timestamp: 2025-09-17T18:29:15.764Z
Learning: Applies to apps/mcp/**/*.{test,spec}.ts : Vitest globals enabled: use `describe`, `it`, `expect` directly without importing them

Applied to files:

  • apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T11:07:17.610Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.610Z
Learning: Applies to apps/opencode/**/*.test.{ts,tsx,js,jsx} : Use `fs-fixture` with `using` statement to ensure cleanup in tests

Applied to files:

  • apps/ccusage/src/_date-utils.ts
🧬 Code graph analysis (3)
apps/pi/src/commands/session.ts (1)
packages/terminal/src/table.ts (1)
  • formatDateCompact (38-54)
apps/pi/src/commands/daily.ts (1)
packages/terminal/src/table.ts (1)
  • formatDateCompact (38-54)
apps/pi/src/commands/monthly.ts (1)
packages/terminal/src/table.ts (1)
  • formatDateCompact (38-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: ccusage-guide
🔇 Additional comments (14)
apps/amp/src/commands/monthly.ts (1)

2-9: Remove unnecessary dateFormatter option—it won't apply to YYYY-MM month values.

The ResponsiveTable applies dateFormatter only to first-column cells matching YYYY-MM-DD format. Since data.month is YYYY-MM (line 169), the formatter is never invoked. Remove the unused dateFormatter option at line 164 to clarify intent.

Likely an incorrect or invalid review comment.

apps/pi/src/commands/session.ts (1)

3-10: Review comment is invalid—dateFormatter will not crash on session names due to proper validation.

The code safely applies dateFormatter only to cells in the first column that match the date pattern ^\d{4}-\d{2}-\d{2}$ (via isDateString() check). Session names like truncated project paths will not match this pattern and will be skipped. No crash risk exists.

Likely an incorrect or invalid review comment.

apps/opencode/src/commands/monthly.ts (1)

5-5: LGTM! Import follows shared package conventions.

The formatDateCompact import from the shared @ccusage/terminal/table package is correct and aligns with the coding guideline to reuse shared packages.

apps/amp/src/commands/session.ts (1)

5-5: LGTM! Consistent implementation of date formatting.

The import and usage of formatDateCompact are correct and follow the same pattern as other commands in this PR, enabling consistent date display in narrow terminals.

Also applies to: 173-173

apps/codex/src/commands/session.ts (1)

5-5: LGTM! Date formatter correctly integrated.

The formatDateCompact import and dateFormatter option are correctly implemented, aligning with the PR objective to prevent date truncation in the session command's table output.

Also applies to: 153-153

apps/opencode/src/commands/session.ts (1)

5-5: LGTM! Consistent date formatting integration.

The formatDateCompact import and usage are correct and follow the established pattern across the codebase for preventing date truncation in table displays.

Also applies to: 156-156

apps/codex/src/commands/daily.ts (1)

5-5: LGTM! Date formatter properly configured.

The import and usage of formatDateCompact are correct and consistent with the other command files in this PR, successfully addressing the date truncation issue in narrow terminals.

Also applies to: 131-131

apps/pi/src/commands/monthly.ts (1)

5-5: LGTM: Import added correctly.

The import follows the project's pattern of reusing shared packages from @ccusage/terminal.

apps/codex/src/commands/monthly.ts (1)

5-5: LGTM: Import added correctly.

The import follows the project's pattern of reusing shared packages.

apps/opencode/src/commands/weekly.ts (1)

5-5: LGTM: Import added correctly.

The import follows the established pattern.

packages/terminal/src/table.ts (2)

7-29: LGTM: Well-structured date formatting helpers.

The DEFAULT_LOCALE and createDatePartsFormatter helper are well-designed with clear documentation.


1082-1107: LGTM: Comprehensive test coverage.

The tests cover the key scenarios including timezone handling, format variations, and default locale behavior.

apps/ccusage/src/_date-utils.ts (2)

13-14: LGTM: Clean re-export pattern.

The re-export of formatDateCompact from the shared terminal package eliminates code duplication and centralizes the implementation. This aligns with the project's guideline to reuse shared packages wherever possible.

Based on learnings, reusing shared packages is a documented best practice for this codebase.


159-159: LGTM: Tests properly relocated.

The comment correctly documents that tests for formatDateCompact are now maintained in the source package, avoiding test duplication.

Comment on lines +31 to +54
/**
* Formats a date string to compact format with year on first line and month-day on second
* @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp)
* @param timezone - Timezone to use for formatting (pass undefined to use system timezone)
* @param locale - Locale to use for formatting (defaults to sv-SE for YYYY-MM-DD format)
* @returns Formatted date string with newline separator (YYYY\nMM-DD)
*/
export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string {
// Check if input is in YYYY-MM-DD format
const isSimpleDateFormat = /^\d{4}-\d{2}-\d{2}$/.test(dateStr);
// For YYYY-MM-DD format, append T00:00:00 to parse as local date
// Without this, new Date('YYYY-MM-DD') interprets as UTC midnight
const date = isSimpleDateFormat
? timezone != null
? new Date(`${dateStr}T00:00:00Z`)
: new Date(`${dateStr}T00:00:00`)
: new Date(dateStr);
const formatter = createDatePartsFormatter(timezone, locale ?? DEFAULT_LOCALE);
const parts = formatter.formatToParts(date);
const year = parts.find((p) => p.type === 'year')?.value ?? '';
const month = parts.find((p) => p.type === 'month')?.value ?? '';
const day = parts.find((p) => p.type === 'day')?.value ?? '';
return `${year}\n${month}-${day}`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix JSDoc inconsistency.

Line 35 mentions "defaults to sv-SE for YYYY-MM-DD format" but the code actually uses DEFAULT_LOCALE which is en-CA. The implementation is correct, but the documentation is outdated.

📝 Fix the JSDoc comment
 /**
  * Formats a date string to compact format with year on first line and month-day on second
  * @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp)
  * @param timezone - Timezone to use for formatting (pass undefined to use system timezone)
- * @param locale - Locale to use for formatting (defaults to sv-SE for YYYY-MM-DD format)
+ * @param locale - Locale to use for formatting (defaults to en-CA for YYYY-MM-DD format)
  * @returns Formatted date string with newline separator (YYYY\nMM-DD)
  */
 export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string {
📝 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.

Suggested change
/**
* Formats a date string to compact format with year on first line and month-day on second
* @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp)
* @param timezone - Timezone to use for formatting (pass undefined to use system timezone)
* @param locale - Locale to use for formatting (defaults to sv-SE for YYYY-MM-DD format)
* @returns Formatted date string with newline separator (YYYY\nMM-DD)
*/
export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string {
// Check if input is in YYYY-MM-DD format
const isSimpleDateFormat = /^\d{4}-\d{2}-\d{2}$/.test(dateStr);
// For YYYY-MM-DD format, append T00:00:00 to parse as local date
// Without this, new Date('YYYY-MM-DD') interprets as UTC midnight
const date = isSimpleDateFormat
? timezone != null
? new Date(`${dateStr}T00:00:00Z`)
: new Date(`${dateStr}T00:00:00`)
: new Date(dateStr);
const formatter = createDatePartsFormatter(timezone, locale ?? DEFAULT_LOCALE);
const parts = formatter.formatToParts(date);
const year = parts.find((p) => p.type === 'year')?.value ?? '';
const month = parts.find((p) => p.type === 'month')?.value ?? '';
const day = parts.find((p) => p.type === 'day')?.value ?? '';
return `${year}\n${month}-${day}`;
}
/**
* Formats a date string to compact format with year on first line and month-day on second
* @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp)
* @param timezone - Timezone to use for formatting (pass undefined to use system timezone)
* @param locale - Locale to use for formatting (defaults to en-CA for YYYY-MM-DD format)
* @returns Formatted date string with newline separator (YYYY\nMM-DD)
*/
export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string {
// Check if input is in YYYY-MM-DD format
const isSimpleDateFormat = /^\d{4}-\d{2}-\d{2}$/.test(dateStr);
// For YYYY-MM-DD format, append T00:00:00 to parse as local date
// Without this, new Date('YYYY-MM-DD') interprets as UTC midnight
const date = isSimpleDateFormat
? timezone != null
? new Date(`${dateStr}T00:00:00Z`)
: new Date(`${dateStr}T00:00:00`)
: new Date(dateStr);
const formatter = createDatePartsFormatter(timezone, locale ?? DEFAULT_LOCALE);
const parts = formatter.formatToParts(date);
const year = parts.find((p) => p.type === 'year')?.value ?? '';
const month = parts.find((p) => p.type === 'month')?.value ?? '';
const day = parts.find((p) => p.type === 'day')?.value ?? '';
return `${year}\n${month}-${day}`;
}
🤖 Prompt for AI Agents
In @packages/terminal/src/table.ts around lines 31 - 54, Update the JSDoc for
formatDateCompact to match the actual default locale used in code: replace the
incorrect "defaults to sv-SE for YYYY-MM-DD format" text with a statement that
it defaults to DEFAULT_LOCALE (en-CA) or explicitly "defaults to en-CA" so the
comment reflects the implementation using DEFAULT_LOCALE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants