Skip to content

Add Oh My Pi runtime compatibility and model preservation - #93

Merged
CTristan merged 25 commits into
mainfrom
feature/omp-compatibility
May 16, 2026
Merged

Add Oh My Pi runtime compatibility and model preservation#93
CTristan merged 25 commits into
mainfrom
feature/omp-compatibility

Conversation

@CTristan

@CTristan CTristan commented May 16, 2026

Copy link
Copy Markdown
Owner
  • feat: add model provider affinity functions and tests
  • feat: add Oh My Pi (OMP) compatibility via runtime adapter
  • fix: add missing enableModelLocking to test config fixture
  • feat: OMP credential resolution, remove catch-all defaults
  • feat: OMP SQLite auth fallback and Codex credential dedup
  • Added OMP usage report conversion and fetch orchestration
  • Added tests for OMP usage report conversion
  • Removed getSelectListTheme singleton dependency from ui-helpers
  • Fix OMP module resolution error in command handlers
  • Preserve OMP default model selection during auto-switching
  • Fix OMP extension loading
  • Fix OMP mirrored dynamic imports
  • Add TypeDoc CI check
  • Refactor TypeDoc coverage check into separate script
  • Include TypeDoc configuration and API documentation

Summary by CodeRabbit

  • New Features

    • OMP runtime compatibility (Pi→OMP extension mirroring)
    • preserveDefaultModel config to control default-model preservation during selector changes
    • OMP usage reporting and provider-aware model recommendations/sorting
    • Improved widget/UI robustness across runtimes
  • Documentation

    • Added Runtime Compatibility section and dedicated OMP compatibility guide
  • Chores

    • CI enforces TypeDoc documentation coverage
  • Tests

    • Expanded test coverage for OMP flows, default-preservation, usage conversion, credentials, and provider affinity

Review Change Stack

CTristan added 18 commits April 3, 2026 16:47
Added src/adapter.ts that dynamically detects whether the extension is
running under Pi (@mariozechner) or Oh My Pi (@oh-my-pi) by probing
package availability via dynamic import() — Bun's createRequire.resolve
does not walk far enough up the directory tree for globally-installed
packages.

- Replaced direct value imports from @mariozechner packages in
  ui-helpers.ts and widget.ts with imports from ./adapter.js
- Added EXTENSION_DIR constant (.omp or .pi) replacing hardcoded .pi
  paths in config.ts, cooldown.ts, model-locks.ts, fetchers/common.ts
- Added MODEL_SELECTOR_DEBUG=1 env var for adapter resolution debugging
- Updated package.json peerDependencies with both package scopes,
  all marked optional via peerDependenciesMeta
- Type imports remain on @mariozechner (erased at compile time)
- String indirection for dynamic imports avoids TS following into
  unresolvable @oh-my-pi source during type-check
- Added modelRegistry.authStorage credential resolution to zai fetcher,
  matching the pattern used by all other fetchers (anthropic, copilot,
  gemini, codex, antigravity). OMP stores credentials in SQLite, not
  auth.json, so fetchers must query authStorage to find keys.
- Removed catch-all default mappings (kiro -> google, zai -> openai).
  Buckets must be explicitly mapped or they remain unmapped — no silent
  fallback to an arbitrary model.
- Updated fetchZaiUsage signature to accept modelRegistry parameter.
- Fixed test call sites for updated signature.
- Added SQLite-based auth loading in common.ts when running under OMP
  (falls back from legacy JSON file to OMP's SQLite auth store)
- Added credential check for Codex provider using auth storage API
- Deduplicated Codex file credentials against piAuth/registry accounts
  to avoid double-counting usage for the same account
- Added test for skipping .codex file credential when account already
  covered by piAuth
- Add OMP_PROVIDER_MAP for normalizing OMP provider IDs to extension names
- Add OMP usage report structural types (UsageReport, UsageLimit, etc.)
- Add convertOmpUsageReports() to convert OMP UsageReport[] to UsageSnapshot[]
- Add convertLimitsToWindows() to map OMP limits to extension RateWindow[]
- Add fetchOmpUsages() to delegate to authStorage.fetchUsageReports()
- Modify fetchAllUsages() to detect OMP and use built-in usage reports
- Fall back to extension fetchers for providers OMP doesn't cover (e.g. kiro)
- Import isOmp from adapter and formatReset from fetchers/common
The extension's module context may not have the theme singleton
initialized (e.g. when the host runtime mirrors the extension into
a temp directory). Instead of importing getSelectListTheme from
adapter.ts, build the select list theme inline from the callback's
theme parameter, which is always available.
Replace 8 dynamic import("./src/widget.js") calls with static import
of getWidgetState. OMP loads extensions from a temp directory where
relative paths don't resolve at runtime — static imports are handled
by the extension loader, but dynamic import() uses standard ESM
resolution against the temp path and fails with:

  Cannot find module './src/widget.js' from
  '/private/var/folders/.../omp-legacy-pi-file/...'
@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an OMP-aware runtime adapter, migrates runtime config/state paths to EXTENSION_DIR, integrates OMP auth/usage sources (SQLite) into fetchers, centralizes selector role-preservation, introduces model-provider affinity, converts several dynamic imports to static, and adds TypeDoc gating, docs, and tests.

Changes

OMP Core Adapter and Config Integration

Layer / File(s) Summary
Adapter module: OMP detection and component exports
src/adapter.ts
New adapter detects OMP via agent.settings, conditionally imports Pi or OMP UI/agent components, exports component bindings and utilities, and provides withPreservedOmpDefaultModelRole to wrap async actions for OMP default model role preservation.
Config loading and preserveDefaultModel setting
src/config.ts
Config system updated to use EXTENSION_DIR for global and project config paths, adds normalizePreserveDefaultModel validation, propagates the setting through both config scopes with isOmp fallback.
Persistence path migrations to EXTENSION_DIR
src/cooldown.ts, src/model-locks.ts, src/types.ts
Cooldown state and model lock state paths migrate from hardcoded .pi to runtime-aware EXTENSION_DIR. Config type interfaces add optional preserveDefaultModel field.

Authentication and Credential Discovery

Layer / File(s) Summary
Static imports and provider credential checks
src/credential-check.ts
Replaces dynamic imports with static top-level imports for API key resolvers; adds explicit codex branch for openai-codex API key and token payload detection.
OMP SQLite auth database access
src/fetchers/common.ts
Auth loading now reads EXTENSION_DIR/agent/auth.json first, then queries OMP's SQLite database via sqlite3 CLI when isOmp is true, aggregating provider credentials; adds execFileAsync.
Codex credential deduplication
src/fetchers/codex.ts
Centralizes credential insertion through addCredential that deduplicates by accessToken and consolidates registry/PI-auth file handling.
Zai API key resolution with modelRegistry
src/fetchers/zai.ts
Adds async resolveZaiApiKeyWithRegistry helper checking Z_AI_API_KEY, modelRegistry.authStorage.getApiKey("zai"), then piAuth; updates fetchZaiUsage signature to accept modelRegistry first.

Usage Fetching and OMP Integration

Layer / File(s) Summary
OMP usage report types and conversion
src/usage-fetchers.ts
Adds OMP report interfaces, OMP_PROVIDER_MAP, and convertOmpUsageReports() to normalize provider IDs, extract account identifiers, group limits by provider+account, and build UsageSnapshot windows with computed usedPercent and reset formatting.
OMP usage fetching orchestration
src/usage-fetchers.ts
Implements fetchOmpUsages() calling authStorage.fetchUsageReports(), filters disabled providers, and falls back to legacy fetchers for uncovered providers with per-provider timeouts; fetchAllUsages() prefers OMP when available.
Model provider affinity recommendations
src/model-provider-affinity.ts
New helper getRecommendedModelProvidersForUsageProvider and sortModelsForUsageProvider to order models by recommended providers and deterministic tie-breakers.

Selector and UI Integration

Layer / File(s) Summary
Selector OMP default role preservation
src/selector.ts
Adds setModelForSelector using withPreservedOmpDefaultModelRole(config.preserveDefaultModel, ...), centralizes pi.setModel side-effects and selfInitiatedModelChange handling in selector flows.
UI components adapter refactoring
src/ui-helpers.ts
Switches UI imports to the local adapter, constructs selectListTheme inline with a defensive symbols.cursor fallback, and removes reliance on module-level getSelectListTheme().
Wizard model provider affinity integration
src/wizard.ts
Uses sortModelsForUsageProvider when generating model options for mapping flows.
Static module imports in index.ts
index.ts
Converts prior dynamic imports into static top-level imports for getWidgetState, modelLockKey, candidateKey, and adds CooldownState type to re-exports.
Widget adapter import change
src/widget.ts
Imports truncateToWidth from local adapter instead of @mariozechner/pi-tui.

Documentation and CI Tooling

Layer / File(s) Summary
OMP compatibility and config documentation
README.md, docs/README.md, docs/omp-compatibility.md, config/model-selector.example.json
Adds Runtime Compatibility docs and OMP compatibility guide; example config adds preserveDefaultModel.
TypeDoc coverage and CI validation
package.json, scripts/ci.sh, scripts/typedoc-check.cjs, tsconfig.json
Adds typedoc tooling and plugin, expands peerDependencies, CI runs TypeDoc JSON coverage and validates against an 80% threshold via scripts/typedoc-check.cjs; tsconfig includes typedocOptions.

Test Coverage for OMP and Features

Layer / File(s) Summary
OMP adapter compatibility and regression tests
tests/adapter-omp-loader-compat.test.ts, tests/omp-default-preservation.test.ts
Tests ensure adapter uses required literal dynamic imports, validate default-role preservation behavior and error precedence of withPreservedOmpDefaultModelRole.
OMP usage conversion and fetcher tests
tests/omp-usage-conversion.test.ts, tests/omp-usage-fetchers.test.ts, tests/usage-fetchers*.test.ts
Extensive tests for convertOmpUsageReports, fetchAllUsages OMP path, kiro fallback, Codex deduplication, and updated fetchZaiUsage invocation sites.
Config, wizard, selector, and credential tests
tests/config.test.ts, tests/model-provider-affinity.test.ts, tests/wizard-config-reload.test.ts, tests/zai-registry-key.test.ts, tests/codex-credential-authstorage.test.ts
Adds preserveDefaultModel config tests, model-affinity tests, wizard mapping ordering tests, Zai registry auth resolution tests, and Codex authStorage detection tests.
Typedoc check tests
tests/typedoc-check.test.ts
Validates scripts/typedoc-check.cjs behavior across error and success scenarios.

Sequence Diagram(s)

sequenceDiagram
  participant Adapter
  participant Config
  participant Fetchers
  participant Selector
  participant Widget

  Adapter->>Config: determine EXTENSION_DIR and isOmp
  Adapter->>Fetchers: provide isOmp/EXTENSION_DIR helpers
  Fetchers->>Adapter: loadPiAuth() (auth.json or SQLite fallback)
  Fetchers->>Selector: UsageSnapshot[] (convertOmpUsageReports)
  Selector->>Adapter: withPreservedOmpDefaultModelRole(setModel)
  Selector->>Widget: renderUsageWidget(updated snapshots)
Loading

🎯 4 (Complex) | ⏱️ ~60 minutes

🐰 I hopped in adapter code so sly,
Mirrors rewrite and imports fly,
SQLite whispers auth at night,
Fetchers turn reports to widget light,
Models sorted, tests gleam bright.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/omp-compatibility

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 12

Caution

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

⚠️ Outside diff range comments (1)
src/fetchers/codex.ts (1)

94-107: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

seenAccounts is populated but not enforced before fetch.

Right now only the .codex branch consults seenAccounts, and new file credentials never add their accountId back into the set. Same-account credentials from piAuth, registry, or later auth files still survive until fetchAllCodexUsages(), so the code issues duplicate Codex usage requests before the final dedupe.

Also applies to: 126-140, 165-180

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/fetchers/codex.ts` around lines 94 - 107, The loop building Codex
credentials doesn't prevent duplicate-account fetches because seenAccounts is
only checked in the .codex branch and file-derived credentials don't add their
accountId to seenAccounts; update the credential-collection logic (around
getPiCodexAuths, the loop that constructs CodexCredential and where
registry/file branches add credentials) to consult seenAccounts before adding
any credential with an accountId and to add that accountId to seenAccounts
immediately when a credential is accepted; ensure the same check is applied in
all branches that push into credentials (piAuth, registry, file-based parsing)
so duplicate account fetches are prevented before fetchAllCodexUsages is called.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/typedoc-check.cjs`:
- Around line 2-3: The script converts thresholdText to threshold but doesn't
validate it; update the startup logic that reads const [file, thresholdText] =
process.argv.slice(2) and const threshold = Number(thresholdText) to verify
threshold is a finite number (e.g., using Number.isFinite or !Number.isNaN) and
within an expected range (0–100) before continuing; if validation fails, print a
clear error mentioning thresholdText and exit with a non‑zero code so the
percent < threshold comparison cannot silently pass on invalid input.
- Around line 10-11: The code reads and parses coverage JSON and directly
accesses coverage.percent; add defensive validation in the typedoc-check flow by
wrapping JSON.parse in a try/catch to handle malformed JSON, verify that the
parsed object (coverage) is non-null and has an own property "percent", and
ensure that Number(coverage.percent) yields a finite number; if validation
fails, log a clear error via console.error or processLogger and exit with a
non-zero code, otherwise proceed to use the validated percent value. Use the
symbols coverage, percent and the JSON read/parse block in
scripts/typedoc-check.cjs to locate where to add the try/catch,
typeof/Number.isFinite checks and the failure path.

In `@src/adapter.ts`:
- Around line 41-52: The mocks currently use "as any" (DynamicBorder, Container,
truncateToWidth, SelectList, Spacer, Text) which weakens types; remove the "as
any" casts and give each mock a proper type by importing the original
component/function types from the source (or declaring a small interface that
matches the real API) and typing the mocks accordingly (e.g., type ContainerMock
= { new(): { addChild(): void; render(): any[] } } or use Partial/Mocked types
from your test framework), and type truncateToWidth as (s: string) => string so
the mock signatures match the real implementations.

In `@src/config.ts`:
- Around line 729-732: The regex building for cleaning correctedPath incorrectly
interpolates EXTENSION_DIR into new RegExp(...) without escaping, so characters
like '.' act as wildcards; fix by escaping EXTENSION_DIR before interpolation
(create or reuse an escapeRegExp utility to replace regex metacharacters) and
use the escaped value when constructing the RegExp used in correctedPath =
originalPath.replace(new RegExp(...), ""); ensure the same escaped symbol is
used wherever EXTENSION_DIR is embedded into dynamic regexes.

In `@src/credential-check.ts`:
- Around line 137-139: The branch that accepts provider === "zai" should also
check for a Zai key stored in modelRegistry.authStorage, not only
resolveZaiApiKey(piAuth); update the conditional around provider === "zai" to
return true if resolveZaiApiKey(piAuth) OR a Zai key can be retrieved from
modelRegistry.authStorage (use the same resolution/lookup semantics you use
elsewhere for Zai keys), referencing resolveZaiApiKey, piAuth, modelRegistry,
and authStorage so registry-only keys are accepted.

In `@src/fetchers/common.ts`:
- Around line 65-67: The code uses execAsync with a shell-interpolated sqlite3
command which risks command injection via dbPath; replace the shell call with a
non-shell child process invocation (e.g., use child_process.execFile or spawn)
and pass the program and arguments as an array instead of interpolating dbPath
and SQL into a string: call execFile('sqlite3', ['-json', dbPath, 'SELECT
provider, data FROM auth_credentials']) or spawn('sqlite3', [...]) and
await/promisify the result, keeping the existing variable names (dbPath,
execAsync usage) or replacing execAsync with a promisified execFile wrapper so
the command runs without a shell and arguments are passed safely.

In `@src/ui-helpers.ts`:
- Around line 90-105: The selectListTheme currently uses unsafe any casts for
(theme as any).nav.cursor and selectListTheme as any; replace these by declaring
a narrow structural type for the symbols shape (e.g. { cursor: string }) and a
SelectList theme shape that matches the adapter, then use a runtime guard "nav"
in theme && typeof (theme as any).nav?.cursor === "string" to read
theme.nav.cursor safely (falling back to ">"), and cast selectListTheme to that
explicit theme interface when constructing new SelectList(items, Math.min(...),
selectListTheme as YourSelectListTheme). Update the references to
selectListTheme, theme.nav.cursor, and SelectList in the same area to remove all
any usages while preserving the OMP/Pi fallback behavior.

In `@src/usage-fetchers.ts`:
- Around line 152-155: The code computes usedPercent incorrectly by falling back
to limit.amount.used as a percent; update the fallback to derive a percentage
from used and limit instead. In the block using usedPercent (referencing
usedPercent, limit.amount.usedFraction, limit.amount.used and
limit.amount.limit) replace the ternary fallback so that when
limit.amount.usedFraction is undefined you compute (limit.amount.used /
limit.amount.limit) * 100, guarding against missing or zero limit.amount.limit
(e.g., return 0 or the raw used value if limit is falsy) to avoid
division-by-zero.
- Around line 107-120: The grouping currently uses a single account derived once
per report and pushes all report.limits into that bucket; instead iterate each
limit in report.limits, compute the account for that specific limit (prefer
limit.scope?.accountId, then fall back to the report-level
metadata/email/accountId/account/username), build the key
(`${provider}|${account ?? ""}`) per-limit, get-or-create the group in the
groups Map (same logic as current `let group = groups.get(key); if (!group) {
group = { provider, displayName, account, limits: [] }; groups.set(key, group);
}`) and push only that single limit into its group so snapshots are split by
each limit's account.
- Around line 168-171: Replace direct Date construction with a luxon DateTime
parse: instead of new Date(limit.window.resetsAt) create a DateTime via
DateTime.fromMillis(limit.window.resetsAt) (or fromSeconds(...) if the epoch is
in seconds), check its .isValid (not Number.isNaN), and use that DateTime to
compute window.resetDescription via formatReset (or adapt formatReset to accept
a DateTime). Keep conversion to a native Date only at the UsageSnapshot boundary
(e.g., where UsageSnapshot expects a JS Date) so window.resetsAt stores a
DateTime or is left unset if invalid; update references to window.resetsAt and
formatReset accordingly.

In `@tests/adapter-omp-loader-compat.test.ts`:
- Around line 45-48: The first test builds executableSource by manually
filtering lines starting with "//" which is inconsistent with the second test
that uses the stripComments helper; replace the manual filter with a call to
stripComments(source) (or the existing helper name used in the other test) and
assign its result to executableSource (optionally followed by .trim() or
normalizing newlines if the other test does so) so both tests use the same
comment-stripping logic; update references to the source variable and ensure
stripComments is imported/available in the test file.

In `@tests/omp-usage-conversion.test.ts`:
- Around line 323-344: The test's time-dependent assertion can flake because
Date.now() is called twice; modify the test around convertOmpUsageReports to
freeze time using fake timers and set a fixed Luxon DateTime.now() reference,
compute futureMs relative to that fixed now, call convertOmpUsageReports while
timers are frozen so formatReset/Date.now() use the same base, then restore
timers; update the test to assert win.resetsAt is a Date with getTime() ===
futureMs and resetDescription === "2h" using the fixed Luxon reference and
ensure you reference convertOmpUsageReports and formatReset in the change.

---

Outside diff comments:
In `@src/fetchers/codex.ts`:
- Around line 94-107: The loop building Codex credentials doesn't prevent
duplicate-account fetches because seenAccounts is only checked in the .codex
branch and file-derived credentials don't add their accountId to seenAccounts;
update the credential-collection logic (around getPiCodexAuths, the loop that
constructs CodexCredential and where registry/file branches add credentials) to
consult seenAccounts before adding any credential with an accountId and to add
that accountId to seenAccounts immediately when a credential is accepted; ensure
the same check is applied in all branches that push into credentials (piAuth,
registry, file-based parsing) so duplicate account fetches are prevented before
fetchAllCodexUsages is called.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5dae0fbf-54cf-4411-b7dd-6a6461fe4cea

📥 Commits

Reviewing files that changed from the base of the PR and between 5e848c7 and 350e7ba.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (34)
  • README.md
  • config/model-selector.example.json
  • docs/README.md
  • docs/omp-compatibility.md
  • index.ts
  • package.json
  • scripts/ci.sh
  • scripts/typedoc-check.cjs
  • src/adapter.ts
  • src/config.ts
  • src/cooldown.ts
  • src/credential-check.ts
  • src/fetchers/codex.ts
  • src/fetchers/common.ts
  • src/fetchers/zai.ts
  • src/model-locks.ts
  • src/model-provider-affinity.ts
  • src/selector.ts
  • src/types.ts
  • src/ui-helpers.ts
  • src/usage-fetchers.ts
  • src/widget.ts
  • src/wizard.ts
  • tests/adapter-omp-loader-compat.test.ts
  • tests/config.test.ts
  • tests/model-provider-affinity.test.ts
  • tests/omp-default-preservation.test.ts
  • tests/omp-usage-conversion.test.ts
  • tests/selector-branches.test.ts
  • tests/selector-locking-disabled.test.ts
  • tests/usage-fetchers-branches.test.ts
  • tests/usage-fetchers.test.ts
  • tests/wizard-config-reload.test.ts
  • tsconfig.json

Comment thread scripts/typedoc-check.cjs
Comment thread scripts/typedoc-check.cjs Outdated
Comment thread src/adapter.ts Outdated
Comment thread src/config.ts
Comment thread src/credential-check.ts
Comment thread src/usage-fetchers.ts Outdated
Comment thread src/usage-fetchers.ts Outdated
Comment thread src/usage-fetchers.ts Outdated
Comment thread tests/adapter-omp-loader-compat.test.ts Outdated
Comment thread tests/omp-usage-conversion.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/config-remove-mapping.test.ts`:
- Around line 188-193: After calling updateProviderSettings with an existing
invalid value, add a concrete assertion that verifies the observed behavior for
that case: e.g., immediately assert whether the call succeeds and the
stored/provider settings for "group-b" now equal the normalized/updated value
(check via the same accessor or return value you use elsewhere in the test), or
assert that the call throws/returns a validation error if that is the intended
behavior; reference updateProviderSettings and the groupId "group-b" when adding
the assertion so the test explicitly documents the expected handling of invalid
existing settings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 453e8a0b-f9b6-4732-a54c-852a408f18e3

📥 Commits

Reviewing files that changed from the base of the PR and between 350e7ba and e902858.

📒 Files selected for processing (1)
  • tests/config-remove-mapping.test.ts

Comment thread tests/config-remove-mapping.test.ts Outdated
@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@CTristan CTristan changed the title feature/omp compatibility Add Oh My Pi runtime compatibility and model preservation May 16, 2026
@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

✅ Unit tests committed locally. Commit: 39c1cbb7a8268a6a30e199abcb2781fb7a5bdd34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/omp-usage-fetchers.test.ts`:
- Around line 88-90: The test teardown should always unstub globals to avoid
leak when a test fails; update the afterEach block that currently calls
vi.resetModules() to also call vi.unstubAllGlobals() (or replace/reset order as
appropriate) so that globals are restored unconditionally after each test;
target the afterEach helper in tests/omp-usage-fetchers.test.ts and ensure
vi.unstubAllGlobals() is invoked alongside vi.resetModules().
- Line 1: Remove the unused node:fs import in the test file by deleting the
import statement that declares "fs" (the unused import at the top of
tests/omp-usage-fetchers.test.ts); if file interaction is actually required,
replace it with the specific used API or mock and update tests to reference that
symbol, otherwise simply remove the import to satisfy lint/CI.
- Around line 63-70: In makeOmpReport(), replace the use of Date.now() with
Luxon's DateTime.now().toMillis() to conform to project-wide date/time handling
(ensure DateTime from 'luxon' is imported if not already); update the fetchedAt
assignment in the makeOmpReport function to use DateTime.now().toMillis() so
tests and code use consistent time utilities.

In `@tests/typedoc-check.test.ts`:
- Around line 7-10: The SCRIPT_PATH resolution uses new
URL(import.meta.url).pathname which breaks on Windows; update
tests/typedoc-check.test.ts to use Node's fileURLToPath: import { fileURLToPath
} from "url" and replace path.dirname(new URL(import.meta.url).pathname) with
path.dirname(fileURLToPath(import.meta.url)) when computing SCRIPT_PATH so the
script path is resolved correctly across platforms.

In `@tests/zai-registry-key.test.ts`:
- Line 24: Update the test fixture's nextResetTime to use Luxon instead of
native Date: import DateTime from luxon if not already imported, then replace
the current new Date(Date.now() + 86400000).toISOString() usage in the
nextResetTime field with DateTime.now().plus({ days: 1 }).toISO() (or equivalent
Luxon expression) so the test follows the project's Luxon date/time convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 01f81602-af42-4c7a-8bd0-575bbda704c2

📥 Commits

Reviewing files that changed from the base of the PR and between e902858 and 39c1cbb.

📒 Files selected for processing (5)
  • tests/codex-credential-authstorage.test.ts
  • tests/omp-load-pi-auth.test.ts
  • tests/omp-usage-fetchers.test.ts
  • tests/typedoc-check.test.ts
  • tests/zai-registry-key.test.ts

Comment thread tests/omp-usage-fetchers.test.ts Outdated
Comment thread tests/omp-usage-fetchers.test.ts Outdated
Comment thread tests/omp-usage-fetchers.test.ts
Comment thread tests/typedoc-check.test.ts
Comment thread tests/zai-registry-key.test.ts
CTristan added 3 commits May 16, 2026 13:32
* Add defensive validation for TypeDoc coverage and OMP credentials.
* Use execFile for sqlite3 queries to avoid shell injection.
* Improve OMP usage account grouping and percentage derivation.
* Fix UI component type casting for TUI theme compatibility.
* Enhance test coverage for OMP loader and credential detection.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
tests/omp-usage-fetchers.test.ts (2)

81-83: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Always unstub globals in shared teardown for failure-safe isolation.

At Line 81-83, this suite resets modules but does not always restore global stubs. If a test fails before its manual vi.unstubAllGlobals(), the next tests inherit leaked globals.

Proposed fix
   afterEach(() => {
     vi.resetModules();
+    vi.unstubAllGlobals();
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/omp-usage-fetchers.test.ts` around lines 81 - 83, The afterEach
teardown currently only calls vi.resetModules() and can leak global stubs if a
test fails; update the shared afterEach (the teardown that contains
vi.resetModules()) to also call vi.unstubAllGlobals() (or vi.restoreAllMocks()
if appropriate) to ensure all global stubs are always restored; locate the
afterEach block in tests/omp-usage-fetchers.test.ts and add
vi.unstubAllGlobals() alongside vi.resetModules() so teardown is failure-safe.

63-63: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use Luxon instead of Date.now() in this TypeScript test helper.

Line 63 uses Date.now(), but this project standardizes on Luxon for date/time handling.

Proposed fix
 import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { DateTime } from "luxon";
@@
-    fetchedAt: Date.now(),
+    fetchedAt: DateTime.now().toMillis(),

As per coding guidelines, **/*.{ts,tsx}: "Use luxon for date/time handling throughout the project".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/omp-usage-fetchers.test.ts` at line 63, Replace the use of Date.now()
for the fetchedAt field with Luxon: import { DateTime } from 'luxon' at the top
and change fetchedAt: Date.now() to fetchedAt: DateTime.now().toMillis() (or
DateTime.now().toJSDate() if the field expects a Date object); update any
typings accordingly so the test helper uses Luxon DateTime consistently.
src/ui-helpers.ts (1)

103-106: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard theme.nav.cursor before dereferencing.

At Line 104-106, "nav" in theme is not enough to safely read .nav.cursor; this can throw if nav exists but is undefined or malformed, which breaks the UI path.

Proposed fix
       symbols: {
-        cursor:
-          "nav" in theme
-            ? (theme as unknown as { nav: { cursor: string } }).nav.cursor
-            : ">",
+        cursor:
+          typeof (theme as { nav?: { cursor?: unknown } }).nav?.cursor ===
+          "string"
+            ? (theme as { nav?: { cursor?: string } }).nav!.cursor
+            : ">",
       },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ui-helpers.ts` around lines 103 - 106, The code reads theme.nav.cursor
after only checking "nav" in theme, which can throw if theme.nav is undefined or
not an object; update the ternary to guard safely (e.g., verify theme.nav is
truthy and typeof theme.nav === "object" and 'cursor' in theme.nav) before
accessing .cursor so you fall back to ">" otherwise; locate the expression that
sets cursor (the ternary using "nav" in theme and (theme as unknown as { nav: {
cursor: string } }).nav.cursor) and replace it with a safe check that reads
cursor only when theme.nav exists and has a cursor property.
tests/typedoc-check.test.ts (1)

7-10: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use fileURLToPath for cross-platform script path resolution.

At Line 8, using .pathname can produce invalid Windows paths (e.g., /C:/...), causing this test to fail on Windows runners.

Proposed fix
 import * as path from "node:path";
+import { fileURLToPath } from "node:url";
 import { afterEach, describe, expect, it } from "vitest";
 
 const SCRIPT_PATH = path.resolve(
-  path.dirname(new URL(import.meta.url).pathname),
+  path.dirname(fileURLToPath(import.meta.url)),
   "../scripts/typedoc-check.cjs",
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/typedoc-check.test.ts` around lines 7 - 10, The SCRIPT_PATH
construction uses path.dirname(new URL(import.meta.url).pathname) which yields
POSIX-style paths like "/C:/..." on Windows; replace the pathname usage with
fileURLToPath(import.meta.url) and compute SCRIPT_PATH via
path.resolve(path.dirname(fileURLToPath(import.meta.url)),
"../scripts/typedoc-check.cjs") so path resolution is correct cross-platform —
update the reference in this test where SCRIPT_PATH is defined and import
fileURLToPath from 'url' if not already imported.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/fetchers/codex.ts`:
- Around line 96-116: The current addCredential function discards later
credentials with the same accountId (seenAccounts) which prevents trying
fallback tokens if the first is expired; change addCredential (and the similar
blocks around the other ranges) to only deduplicate by accessToken (seenTokens)
and allow multiple credentials per account by removing the accountId
early-return — i.e., stop using seenAccounts to block pushes, or replace
seenAccounts with a map accountId -> credential[] and push additional
credentials for the same accountId so the fetch logic can try fallbacks; ensure
you still add to seenTokens to avoid duplicate tokens.

In `@tests/omp-load-pi-auth.test.ts`:
- Around line 103-121: The test is mocking child_process.exec but production
uses execFileAsync (promisified execFile), so update the per-test mock to stub
child_process.execFile (or the same mocked function used at top-level) instead
of exec; specifically, change the mockImplementation in
tests/omp-load-pi-auth.test.ts to target child_process.execFile (so
execFileAsync in src/fetchers/common.ts receives the mocked behavior) and ensure
the mocked callback signature matches execFile's (err, stdout, stderr) and
returns the same mock ReturnType as the top-level setup.

---

Duplicate comments:
In `@src/ui-helpers.ts`:
- Around line 103-106: The code reads theme.nav.cursor after only checking "nav"
in theme, which can throw if theme.nav is undefined or not an object; update the
ternary to guard safely (e.g., verify theme.nav is truthy and typeof theme.nav
=== "object" and 'cursor' in theme.nav) before accessing .cursor so you fall
back to ">" otherwise; locate the expression that sets cursor (the ternary using
"nav" in theme and (theme as unknown as { nav: { cursor: string } }).nav.cursor)
and replace it with a safe check that reads cursor only when theme.nav exists
and has a cursor property.

In `@tests/omp-usage-fetchers.test.ts`:
- Around line 81-83: The afterEach teardown currently only calls
vi.resetModules() and can leak global stubs if a test fails; update the shared
afterEach (the teardown that contains vi.resetModules()) to also call
vi.unstubAllGlobals() (or vi.restoreAllMocks() if appropriate) to ensure all
global stubs are always restored; locate the afterEach block in
tests/omp-usage-fetchers.test.ts and add vi.unstubAllGlobals() alongside
vi.resetModules() so teardown is failure-safe.
- Line 63: Replace the use of Date.now() for the fetchedAt field with Luxon:
import { DateTime } from 'luxon' at the top and change fetchedAt: Date.now() to
fetchedAt: DateTime.now().toMillis() (or DateTime.now().toJSDate() if the field
expects a Date object); update any typings accordingly so the test helper uses
Luxon DateTime consistently.

In `@tests/typedoc-check.test.ts`:
- Around line 7-10: The SCRIPT_PATH construction uses path.dirname(new
URL(import.meta.url).pathname) which yields POSIX-style paths like "/C:/..." on
Windows; replace the pathname usage with fileURLToPath(import.meta.url) and
compute SCRIPT_PATH via
path.resolve(path.dirname(fileURLToPath(import.meta.url)),
"../scripts/typedoc-check.cjs") so path resolution is correct cross-platform —
update the reference in this test where SCRIPT_PATH is defined and import
fileURLToPath from 'url' if not already imported.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe203e18-c506-433a-8a4a-5f6c19d7e805

📥 Commits

Reviewing files that changed from the base of the PR and between 39c1cbb and 5822036.

📒 Files selected for processing (36)
  • scripts/typedoc-check.cjs
  • src/adapter.ts
  • src/candidates.ts
  • src/config.ts
  • src/cooldown.ts
  • src/credential-check.ts
  • src/fetchers/anthropic.ts
  • src/fetchers/antigravity.ts
  • src/fetchers/codex.ts
  • src/fetchers/common.ts
  • src/fetchers/copilot.ts
  • src/fetchers/gemini.ts
  • src/fetchers/kiro.ts
  • src/fetchers/minimax.ts
  • src/fetchers/zai.ts
  • src/model-locks.ts
  • src/model-provider-affinity.ts
  • src/selector.ts
  • src/types.ts
  • src/ui-helpers.ts
  • src/usage-fetchers.ts
  • src/widget.ts
  • src/wizard.ts
  • tests/adapter-omp-loader-compat.test.ts
  • tests/codex-credential-authstorage.test.ts
  • tests/config-remove-mapping.test.ts
  • tests/kiro.test.ts
  • tests/load-pi-auth-sqlite.test.ts
  • tests/omp-load-pi-auth.test.ts
  • tests/omp-usage-conversion.test.ts
  • tests/omp-usage-fetchers.test.ts
  • tests/provider-credential-detection.test.ts
  • tests/typedoc-check.test.ts
  • tests/usage-fetchers-branches.test.ts
  • tests/usage-fetchers.test.ts
  • tsconfig.json

Comment thread src/fetchers/codex.ts Outdated
Comment thread tests/omp-load-pi-auth.test.ts Outdated
Keep Codex credential discovery deduplicated by access token while allowing multiple distinct tokens for the same account to be tried. This preserves fallback credentials when an earlier token is expired.\n\nAdded coverage for same-account fallback behavior and updated OMP/Codex tests to match the execFile-backed auth fallback and cross-platform path handling.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/usage-fetchers-branches.test.ts`:
- Around line 765-807: Update the test case names to reflect the actual behavior
asserted: instead of saying credentials are "skipped", rename the test
containing the assertion calling fetchAllCodexUsages (the one currently titled
"should skip .codex file credential when account already covered by piAuth") to
something like "should fetch distinct credentials then deduplicate by account
(retry-then-dedup)" and update the other test around lines 809-868 similarly
(the other test that asserts toHaveBeenCalledTimes(5)) so both names describe
"fetch all distinct tokens then dedupe by account" behavior; keep tests,
assertions, and the call to fetchAllCodexUsages intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 50695ac6-325a-494e-b214-72772b4f47a4

📥 Commits

Reviewing files that changed from the base of the PR and between 5822036 and 0662161.

📒 Files selected for processing (6)
  • src/fetchers/codex.ts
  • tests/codex-same-account-fallback.test.ts
  • tests/omp-load-pi-auth.test.ts
  • tests/omp-usage-fetchers.test.ts
  • tests/typedoc-check.test.ts
  • tests/usage-fetchers-branches.test.ts

Comment thread tests/usage-fetchers-branches.test.ts Outdated
Avoid reading theme.nav.cursor unless the custom UI theme exposes an object with a cursor property, falling back to the default cursor otherwise.

Rename Codex credential tests to describe fetch-then-deduplicate behavior and cover the missing-nav cursor fallback.
@CTristan
CTristan merged commit a298b92 into main May 16, 2026
2 checks passed
@CTristan
CTristan deleted the feature/omp-compatibility branch May 16, 2026 21:43
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.

1 participant