Skip to content

Remove shims - #11

Merged
kenryu42 merged 7 commits into
mainfrom
remove-shims
Aug 1, 2026
Merged

Remove shims#11
kenryu42 merged 7 commits into
mainfrom
remove-shims

Conversation

@kenryu42

@kenryu42 kenryu42 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added secure multi-account management with login, logout, renaming, activation, per-session selection, quota tracking, and automatic account rotation.
    • Added migration support for existing account and model settings.
    • Added native text-and-image input support, including Composer 2.5.
    • Added session-aware authentication for image generation.
  • Changes

    • Removed legacy vision descriptions, web search, shell, file, and search tool integrations.
  • Documentation

    • Updated configuration, security, account management, migration, image handling, and troubleshooting guidance.

kenryu42 added 5 commits July 30, 2026 10:39
Drop the text-only image description path now that Composer 2.5
supports images natively, and clean related config, docs, and tests.
Why:
- Grok models now consume Pi native tool schemas and no longer require Cursor-compatible aliases.

What:
- Remove compatibility tool registration, scoping, delegation, and related dependencies.
- Keep image_gen preference synchronization across model and session changes.
- Remove obsolete shim documentation and tests.

Validation:
- bun run check (263 tests)
Why:
- Keep one Grok CLI provider while separate Pi sessions use separate logged-in accounts.

What:
- Store account credentials in the extension vault and route each request through the session selection.
- Migrate only released main-branch grok-cli-N credentials and saved model settings.
- Protect login, quota, and file updates from concurrent session races.

Validation:
- bun run check
Why:
- The hover glow ring drew round corners over a squircle card, so the ring separated from the card edge at each corner.

What:
- Let the ring pseudo-element inherit corner-shape, not only border-radius.

Validation:
- bun run check
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR replaces legacy provider, vision, web-search, and compatibility-tool systems with a versioned account vault, session-scoped routing, migration support, native image input, and unified grok-cli provider handling.

Changes

Account vault and migration

Layer / File(s) Summary
Documentation and dependencies
CONFIGURATION.md, README.md, SECURITY.md, package.json, knip.json
Documentation describes account vault storage, account management, native image input, and migration. Dependencies and keywords remove vision and web-access references.
Configuration and Imagine settings
src/config.ts, tests/config.test.ts
Configuration version 3 stores only Imagine settings. Parsing accepts versions 1–3 and normalizes to imagine-only defaults. Migration removes legacy vision files when settings migrate.
Storage with file locking
src/storage.ts, tests/storage.test.ts
File locking uses tokenized lock files with PID and age checks, recovery markers, and 30-second timeouts. Account-vault and config-backup paths replace legacy vision paths.
Account vault storage and validation
src/provider/accountVault.ts, tests/provider/accountVault.test.ts
Account vault defines credential, account, and vault schemas. Validation enforces unique IDs and slots, required credentials, permanent Account 1, and active-account selection. Mutations use locked atomic writes with mode 0600.
Account migration from legacy configuration
src/provider/accountMigration.ts, tests/provider/accountMigration.test.ts
Migration imports released accounts, validates metadata, preserves backups, normalizes labels and slots, migrates quota caches by account ID, and marks the active account. File locks prevent concurrent migration races.
Account routing and token refresh
src/provider/accountRouting.ts, tests/provider/accountRouting.test.ts
Routing resolves accounts from the environment token or vault, normalizes base URLs, orchestrates token refresh with deduplication by account revision, validates login state, and persists refreshed credentials.
Session-scoped account selection
src/provider/sessionAccountSelection.ts, tests/provider/sessionAccountSelection.test.ts
Session selection resolves valid account IDs from custom entries, prioritizes environment tokens and vault credentials, restores persisted selections, and clears state on logout.
Request-account ownership tracking
src/provider/requestOwnership.ts
Message ownership maps assistant responses to their originating account IDs using a WeakMap, supporting quota refresh and exhaustion attribution.
Image generation with token resolution
src/imagine/*, src/models/catalog.ts, tests/imagine/*
Image generation accepts optional token resolvers injected at registration and execution time, allowing session-scoped authentication. syncImageToolPreference applies persisted settings. Composer 2.5 supports image input.
Provider registration and routing
src/provider/register.ts, tests/provider/register.test.ts
Provider registration creates one grok-cli provider with vault-backed OAuth, environment-token detection, marker credentials for existing accounts, and per-session streaming. Login persists new credentials with revision checks; refresh bypasses OAuth for markers or environment tokens.
Account exhaustion rotation
src/provider/rotation.ts, tests/provider/rotation.test.ts
Rotation uses vault credentials and session selection to rotate between logged-in, non-exhausted accounts. Exhaustion detection is restricted to grok-cli and records the originating account. Environment tokens bypass rotation.
Usage and quota caching
src/provider/usage.ts, src/provider/quotaCache.ts, tests/provider/quotaCache.test.ts, tests/provider/usage.test.ts
Usage command injects account-route resolution, routes billing requests through the selected account, and stores quota by account ID with conditional locking. Cache persistence verifies the account remains current; route failures show cached quota with the error reason.
Account management and credentials
src/provider/accounts.ts, tests/provider/accounts.test.ts
Account operations add/rename accounts using UUIDs, activate, login with OAuth, logout, refresh, and remove accounts. All mutations update vault credentials, revisions, active-account fallbacks, session selection, and quota caches. Snapshots expose connection state, status, labels, permanence, and cached quota data.
Dashboard account operations and display
src/provider/dashboard/app.js, src/provider/dashboard/server.ts, src/provider/dashboard/app.css, tests/provider/dashboard.test.ts
Dashboard uses opaque account IDs for login state, account mutations, card identity, and quota keys. Login endpoints create accounts, track revisions, and remove failed accounts. Account cards display slot metadata, environment mode, connection status, and conditional actions for permanent-account and environment-token restrictions.
Saved model provider migration
src/provider/modelMigration.ts, tests/provider/modelMigration.test.ts
Saved provider settings migrate legacy grok-cli-* provider names to grok-cli and deduplicate enabled models. Migration is idempotent and returns status with optional warnings.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Session
  participant AccountRoute as Account Route Resolver
  participant AccountVault as Account Vault
  participant GrokProvider as Grok Provider
  Session->>AccountRoute: Resolve session account
  AccountRoute->>AccountVault: Read account credentials
  AccountVault-->>AccountRoute: Return account snapshot
  AccountRoute-->>GrokProvider: Return token and base URL
  GrokProvider->>GrokProvider: Stream Grok request
  GrokProvider-->>Session: Associate response with account
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the removal of legacy tool, vision, and provider shims, which is a major part of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch remove-shims

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.

@greptile-apps

greptile-apps Bot commented Aug 1, 2026

Copy link
Copy Markdown

Greptile Summary

The PR removes compatibility tool and vision-routing shims while consolidating legacy provider aliases into one grok-cli provider backed by a locked account vault.

  • Migrates legacy accounts, credentials, quotas, configuration, and model settings.
  • Introduces per-session account selection, request ownership, and vault-based quota rotation.
  • Routes Imagine authentication through the selected session account.
  • Marks Composer 2.5 as accepting native image input and updates user/security documentation.
  • Removes custom file, shell, search, web-search, tool-scoping, and vision implementations and their tests.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect remaining after reviewing migration, request routing, rotation, and dashboard security paths.

The new vault writes are locked and atomic, migration retries preserve recoverability, session requests capture account ownership, and dashboard mutations retain capability, same-origin, and CSRF enforcement.

Important Files Changed

Filename Overview
src/provider/accountMigration.ts Adds locked, retry-safe migration of legacy provider accounts, credentials, quota keys, and configuration into the new vault layout.
src/provider/accountVault.ts Adds validated account-vault persistence using interprocess locks, atomic replacement, and restrictive filesystem modes.
src/provider/register.ts Replaces provider aliases and shim registration with one vault-routed provider and session-aware request authentication.
src/provider/rotation.ts Reworks exhaustion rotation around captured account IDs and per-session account selection.
src/provider/sessionAccountSelection.ts Persists account choices in session entries while maintaining live per-session selections.
src/provider/dashboard/server.ts Updates dashboard routes for vault account IDs while retaining capability, origin, CSRF, host, and method protections.
src/config.ts Reduces v3 configuration to Imagine settings and preserves supported legacy migration behavior.
src/models/catalog.ts Declares native image input support for Composer 2.5.
package.json Removes dependencies and optional peer integration used only by deleted compatibility shims.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Legacy v1/v2 configuration] --> B[Acquire migration lock]
  B --> C[Copy OAuth credentials into account vault]
  C --> D[Preserve legacy configuration backup]
  D --> E[Migrate quota keys to account IDs]
  E --> F[Write v3 non-account configuration]
  F --> G[Rewrite saved provider aliases]
  G --> H[Register single grok-cli provider]
  H --> I[Restore per-session account selection]
  I --> J[Resolve and capture request account]
  J --> K{Balance exhausted?}
  K -- No --> L[Complete request]
  K -- Yes --> M[Select eligible vault account]
  M --> J
Loading

Reviews (1): Last reviewed commit: "fix(dashboard): match hover ring corners..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e96576c8ca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/provider/accountRouting.ts Outdated
if (selected) latest.activeAccountId = selected.id;
});
}
if (Date.now() < account.credential.expires - 120_000) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid applying the OAuth refresh skew twice

OAuth login and refresh already store expires 120 seconds early in src/auth/oauth.ts, but this condition subtracts another 120 seconds. Normal credentials are therefore refreshed four minutes before their real expiry, and tokens lasting four minutes or less trigger a refresh on every route resolution, increasing latency and exposing otherwise valid requests to refresh failures. Treat the stored expiry as already skewed, or remove the skew when credentials are created.

Useful? React with 👍 / 👎.

Comment thread src/provider/dashboard/server.ts Outdated
job.resolveManualCode('');
if (removeOnFailure) {
newAccountIds.delete(id);
await manager.remove(ctx, id).catch(() => undefined);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve accounts authenticated by another dashboard

When two Pi/dashboard processes start the first login for a newly added account, one can successfully store the credential and increment its revision while the creator's attempt subsequently fails the revision check. Because removeOnFailure was captured when the account was created, this unconditional cleanup then deletes the account and the credential saved by the successful process. Remove it only if the account is still unauthenticated and unchanged from its creation revision.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🧹 Nitpick comments (14)
tests/stateTestHelpers.ts (1)

20-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify deferred to hold one resolver.

The Promise executor runs synchronously, so the array always holds exactly one resolver. A single variable states the intent more directly and removes the optional-call fallback.

♻️ Proposed simplification
 export function deferred<T>() {
-  const resolvers: ((value: T) => void)[] = [];
-  const promise = new Promise<T>((resolve) => resolvers.push(resolve));
-  return { promise, resolve: (value: T) => resolvers[0]?.(value) };
+  let resolve!: (value: T) => void;
+  const promise = new Promise<T>((resolver) => {
+    resolve = resolver;
+  });
+  return { promise, resolve };
 }
🤖 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/stateTestHelpers.ts` around lines 20 - 24, Update deferred to store its
Promise resolver in a single variable rather than the resolvers array, then have
the returned resolve function call that resolver directly without optional
chaining. Preserve the existing promise and generic value behavior.
tests/provider/accounts.test.ts (1)

53-53: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse useEnvironmentToken for token teardown.

Lines 53 and 147-150 reimplement the save-and-restore logic that useEnvironmentToken in tests/stateTestHelpers.ts already provides. The other suites in this PR use that helper. Reusing it removes the duplicated teardown and keeps one behavior for the variable.

♻️ Proposed consolidation
 import {
   deferred,
   oauthCredential,
   setAccount1Credential,
+  useEnvironmentToken,
   useTempHome,
 } from '../stateTestHelpers.js';
-const originalToken = process.env.GROK_CLI_OAUTH_TOKEN;
 const setupHome = useTempHome();
+const setToken = useEnvironmentToken();
 beforeEach(() => {
   setupHome();
-  delete process.env.GROK_CLI_OAUTH_TOKEN;
+  setToken(undefined);
-afterEach(() => {
-  if (originalToken === undefined) delete process.env.GROK_CLI_OAUTH_TOKEN;
-  else process.env.GROK_CLI_OAUTH_TOKEN = originalToken;
-});

Also applies to: 147-150

🤖 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/provider/accounts.test.ts` at line 53, Replace the manual
GROK_CLI_OAUTH_TOKEN save-and-restore logic around the affected test setup and
teardown with the existing useEnvironmentToken helper from
tests/stateTestHelpers.ts. Update both the originalToken declaration and the
cleanup at lines 147-150, preserving the current token setup behavior while
delegating restoration to the shared helper.
tests/provider/sessionAccountSelection.test.ts (1)

29-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Isolate GROK_CLI_OAUTH_TOKEN in this suite.

accountId in src/provider/sessionAccountSelection.ts returns ACCOUNT_1_ID immediately when GROK_CLI_OAUTH_TOKEN is set. If that variable exists in the developer environment, the first two tests fail for an unrelated reason. useEnvironmentToken from tests/stateTestHelpers.ts clears and restores the variable.

♻️ Proposed isolation
-import { useTempHome } from '../stateTestHelpers.js';
+import { useEnvironmentToken, useTempHome } from '../stateTestHelpers.js';
 
 const setupHome = useTempHome();
+const setToken = useEnvironmentToken();
 beforeEach(async () => {
   setupHome();
+  setToken(undefined);
🤖 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/provider/sessionAccountSelection.test.ts` around lines 29 - 31, Update
the session account selection test setup around beforeEach to use
useEnvironmentToken from stateTestHelpers, ensuring GROK_CLI_OAUTH_TOKEN is
cleared for the suite and restored afterward. Preserve the existing setupHome
and mutateAccountVault initialization flow.
tests/provider/register.test.ts (1)

269-285: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Pi credential fixtures are duplicated across two test files. Both files write .pi/agent/auth.json with a grok-cli OAuth entry, and both build the same vault-marker credential. The shared root cause is a missing fixture helper in tests/stateTestHelpers.ts, which this PR already introduces for other shared test state. Add writePiCredential and a marker helper there, then import them in both suites.

  • tests/provider/register.test.ts#L269-L285: remove local writeAuth and writeMarker, and import the shared helpers instead.
  • tests/provider/accounts.test.ts#L103-L123: remove local writePiCredential and connectPi, and import the shared helpers instead.
🤖 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/provider/register.test.ts` around lines 269 - 285, The Pi credential
fixtures are duplicated across both test suites. In tests/stateTestHelpers.ts,
add shared writePiCredential and vault-marker helpers; in
tests/provider/register.test.ts lines 269-285, remove local writeAuth and
writeMarker and import the shared helpers; in tests/provider/accounts.test.ts
lines 103-123, remove local writePiCredential and connectPi and import the
shared helpers instead.
src/provider/quotaCache.ts (1)

122-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Accept a path override for consistency.

saveQuotaUsage and removeQuotaUsage accept a path parameter, but saveQuotaUsageWhen always uses the default cache path. This blocks path-isolated tests for the conditional write path and makes the module API inconsistent.

♻️ Proposed refactor
 export function saveQuotaUsageWhen(
   accountId: string,
   usage: BillingUsage,
   shouldSave: () => boolean,
+  path = getQuotaCachePath(),
 ) {
   return updateQuotaCache((cache) => {
     if (!shouldSave()) return false;
     storeQuota(cache, accountId, usage, new Date().toISOString());
     return true;
-  });
+  }, path);
 }
🤖 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/provider/quotaCache.ts` around lines 122 - 132, Update saveQuotaUsageWhen
to accept an optional path override, pass it through to updateQuotaCache, and
preserve the default path behavior when omitted so its API matches
saveQuotaUsage and removeQuotaUsage.
src/provider/accountVault.ts (2)

231-237: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the intermediate vault variable.

current is already the value to clone. The let and the assignment add no behavior.

♻️ Proposed change
 export function getAccountVault() {
-  let vault: AccountVault | undefined;
-  return withVaultLock((current) => {
-    vault = current;
-    return structuredClone(vault);
-  }, false);
+  return withVaultLock((current) => structuredClone(current), false);
 }

As per coding guidelines: "Reduce total variable count by inlining when a value is only used once" and "Prefer const over let".

🤖 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/provider/accountVault.ts` around lines 231 - 237, In getAccountVault,
remove the intermediate vault declaration and assignment, and return a
structuredClone of the withVaultLock callback’s current value directly. Preserve
the existing lock invocation and false argument.

Source: Coding guidelines


117-118: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Report a distinct reason when the vault root is not an object.

Both branches emit unsupported version. A truncated or replaced file that parses to an array or a string then produces a misleading error.

♻️ Proposed change
-  if (!isObject(value)) return invalid('unsupported version');
+  if (!isObject(value)) return invalid('the vault must contain a JSON object');
   if (value.version !== 1) invalid('unsupported version');
🤖 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/provider/accountVault.ts` around lines 117 - 118, Update the validation
around the vault root in the account-vault parsing flow: have the
!isObject(value) branch report a distinct invalid-root/object error, while
retaining unsupported version only for the value.version !== 1 branch.
tests/provider/accountMigration.test.ts (1)

231-267: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a case for an unsupported config version.

readReleasedConfig throws for any version other than 1, 2, or 3. src/provider/register.ts converts that rejection into migrationError, which blocks login and streaming. No test pins that contract. Add a case that writes { version: 4 } and asserts the rejection.

🤖 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/provider/accountMigration.test.ts` around lines 231 - 267, Extend the
migration tests around migrateReleasedAccounts to write a released configuration
with version 4 and assert that the operation rejects with migrationError. Use
the existing setup and configuration-writing helpers, and pin the
unsupported-version behavior without changing handling for supported versions.
tests/config.test.ts (1)

125-133: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The permission-based test can fail when the suite runs as root.

chmodSync(paths(home).pi, 0o500) does not block writes for uid 0. In a root container the migration succeeds and result.warning is undefined. Skip the test when process.getuid?.() === 0, or simulate the failure with a non-directory path as tests/storage.test.ts Line 68 does.

🤖 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/config.test.ts` around lines 125 - 133, Make the “preserves a legacy
file when the destination is not writable” test reliable under root by skipping
it when process.getuid?.() === 0, or replace the chmod-based setup with the
non-directory-path failure approach used in storage tests. Keep the existing
migration warning assertion for environments where the failure is actually
simulated.
tests/storage.test.ts (1)

120-149: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the conditional branch and assert acquisition directly.

The barrier records a live pid with an epoch mtime, so recoveryInProgress deletes it and the first acquisition attempt succeeds. pending is therefore already settled when Promise.race runs, and the queueMicrotask resolver loses. The !result.acquired branch is dead, yet Line 145 asserts result.acquired is true. If microtask ordering ever shifts, the test takes the dead branch and then fails at Line 145.

💚 Proposed simplification
-      const pending = acquireFileLock(getQuotaCachePath());
-      const result = await Promise.race([
-        pending.then((release) => ({ acquired: true as const, release })),
-        new Promise<{ acquired: false }>((resolve) => {
-          queueMicrotask(() => resolve({ acquired: false }));
-        }),
-      ]);
-      if (!result.acquired) {
-        rmSync(recoveryPath, { force: true });
-        await vi.advanceTimersByTimeAsync(25);
-        await (await pending)();
-      } else {
-        await result.release();
-      }
-      expect(existsSync(recoveryPath)).toBe(false);
-      expect(result.acquired).toBe(true);
+      const release = await acquireFileLock(getQuotaCachePath());
+      await release();
+      expect(existsSync(recoveryPath)).toBe(false);
+      expect(existsSync(lockPath)).toBe(false);

This also removes the else statement and the unused rmSync path.

🤖 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/storage.test.ts` around lines 120 - 149, Update the test around
acquireFileLock to await the pending lock acquisition directly, remove the
Promise.race and queueMicrotask logic, and eliminate the conditional
release/removal branch. Assert that the recovery barrier is absent after
releasing the acquired lock, preserving cleanup of fake timers in the existing
finally block.

Source: Coding guidelines

tests/provider/package.test.ts (1)

40-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the redundant dependency assertions.

Line 42 asserts that dependencies is absent. The jiti and typebox checks on lines 40-41 can never fail after that, so they add noise.

♻️ Proposed refactor
-    expect(packageJson.dependencies?.jiti).toBeUndefined();
-    expect(packageJson.dependencies?.typebox).toBeUndefined();
     expect(packageJson.dependencies).toBeUndefined();
🤖 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/provider/package.test.ts` around lines 40 - 43, Remove the redundant
jiti and typebox dependency assertions from the packageJson checks, keeping the
dependencies absence assertion and the existing devDependencies assertion in the
relevant package test.
src/provider/dashboard/app.js (1)

785-787: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename provider-based identifiers to account identifiers.

These variables now hold account IDs, but the names still say provider (pendingProviders, the provider loop variable, and dataset.provider at line 675). The mismatch makes the ID contract harder to follow after this migration. Rename them to pendingAccountIds, accountId, and dataset.accountId, and update the matching selectors at lines 769-775 and 816-823.

🤖 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/provider/dashboard/app.js` around lines 785 - 787, Rename the account-ID
variables throughout the relevant flow: change pendingProviders to
pendingAccountIds, the loop variable provider to accountId, and dataset.provider
to dataset.accountId. Update all matching references and selectors, including
the sections around the pending-account selection and subsequent lookup logic,
while preserving behavior.
src/provider/accounts.ts (2)

363-366: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Select the environment account by ID.

The environment path refreshes accounts[0] positionally. resolveAccountRoute reports the environment route as ACCOUNT_1_ID, and snapshot marks the environment account by account.id === ACCOUNT_1_ID. If the vault order ever differs from that assumption, the quota is stored under the wrong account. Select by ID to keep all three code paths consistent.

♻️ Proposed refactor
       const accounts = environment
-        ? [getAccountVaultSync().accounts[0]].filter(Boolean)
+        ? getAccountVaultSync().accounts.filter((account) => account.id === ACCOUNT_1_ID)
         : getAccountVaultSync().accounts.filter((account) => account.credential);
🤖 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/provider/accounts.ts` around lines 363 - 366, Update the environment
branch in the account selection flow to choose the account whose id matches
ACCOUNT_1_ID instead of using accounts[0]. Preserve the existing filtering
behavior and leave the non-environment credential filtering unchanged, keeping
it consistent with resolveAccountRoute and snapshot.

234-236: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove or repurpose the unused Grok account shims.

resolveGrokProvider and handleModelSelect are no-op helpers; runtime code only calls accountManagement.handleModelSelect(), and tests only import this surface as part of the account export. Replace them with a shared no-op/no-op implementation if the contract is needed, or remove the exports and dependent imports/tests.

🤖 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/provider/accounts.ts` around lines 234 - 236, Remove or repurpose the
no-op account shims resolveGrokProvider and handleModelSelect in the accounts
export: either provide one shared no-op implementation where the contract
requires it, or delete these exports and update all dependent imports and tests,
preserving the runtime accountManagement.handleModelSelect() path.
🤖 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/config.ts`:
- Around line 179-200: Update the legacy cleanup logic in the
consolidated-config branch so a recognized legacy Imagine setting is not
discarded when the consolidated config omits the imagine key. Before unlinking
legacyPath, either persist the legacy value into the consolidated configuration
or retain the legacy file when the raw parsed config does not define imagine;
preserve consolidated-config precedence when the key is present.

In `@src/provider/accountMigration.ts`:
- Around line 141-163: Make migrateQuota asynchronous and acquire the same
quota-cache lock used by updateQuotaCache via
acquireFileLock(getQuotaCachePath()) before reading the cache, holding it
through the migration rewrite and releasing it afterward. Preserve the existing
validation and migration behavior, and update the call site to await
migrateQuota(accountIds).

In `@src/provider/dashboard/server.ts`:
- Around line 388-395: Update the rejection handler around the job state
assignment and account cleanup so removal occurs only when removeOnFailure is
true and controller.signal.aborted is false. Preserve the cancelled state and
account row for explicit login cancellation while retaining cleanup for other
failures.

In `@src/provider/modelMigration.ts`:
- Around line 8-11: Update migrateSettings so SettingsManager.create receives
directory as the real cwd and agent directory, ensuring flush() persists changes
to directory/settings.json; preserve the existing migration flow and avoid using
the temporary .pi-grok-cli-migration path as the cwd.

In `@src/provider/sessionAccountSelection.ts`:
- Around line 35-46: Make restore in the session account selection
implementation safe when invoked detached by removing its this-dependent
accountId call, or by binding restore at every callback registration such as
sessionSelection.on or pi.on. Prefer directly deriving the session ID from
ctx.sessionManager when calling accountId, while preserving the existing
selection restore and deletion behavior.

In `@src/provider/usage.ts`:
- Around line 34-38: Update the route resolution handling around resolveRoute so
its caught error message is preserved and included in the user notification
alongside the existing formatQuota output. Keep the no-route return behavior,
and ensure the actionable reason from resolveAccountRoute is surfaced instead of
being discarded.

In `@src/storage.ts`:
- Around line 30-49: Update abandonedLock in src/storage.ts#L30-L49 to parse and
validate the lock owner before applying the mtime threshold; for a valid PID,
return !processIsRunning(pid), using LOCK_STALE_MS only when the owner cannot be
identified. Update the corresponding test case in tests/storage.test.ts#L96-L118
to use a non-running PID or rename it to explicitly describe the bounded mtime
behavior.
- Around line 113-141: Update the acquisition loop around recoveryInProgress to
check the elapsed timeout once at the start of every iteration, before sleeping
or attempting the lock. Reuse LOCK_STALE_MS for the deadline and preserve the
existing timeout error; remove the duplicate 30-second literal from the EEXIST
branch so recovery polling and lock contention share the same limit.

In `@tests/imagine/helpers.ts`:
- Around line 10-12: Update the cleanup call in the afterEach hook to pass
force: true to rmSync, ensuring missing temporary directories do not fail test
cleanup while preserving recursive removal.

In `@tests/provider/register.test.ts`:
- Around line 994-1008: Update the quota-cache assertion in the successful OAuth
login test to check the seeded `'account-1'` entry instead of `'grok-cli'`. Keep
the existing login invocation and success expectations unchanged, and verify
that loadQuotaCache().accounts['account-1'] is undefined after login.
- Around line 720-747: Update the concurrent stream assertion in the test around
streamSimple to avoid relying on mockProviderStream call order. Associate each
recorded API key with its session ID from the call arguments, then assert the
resulting mapping contains session-a → one and session-b → two while preserving
the existing stream behavior.

In `@tests/stateTestHelpers.ts`:
- Around line 41-54: Update the returned setup function in useTempHome to add
each mkdtempSync-created directory to the dirs collection before returning it,
so the existing afterEach cleanup removes all temporary directories.

In `@tests/storage.test.ts`:
- Around line 96-118: Update the stale-lock test around acquireFileLock to avoid
asserting mtime-first reclamation when the lock contains the current
process.pid. Make the test represent a genuinely stale or non-running owner
while still verifying recovery after the lock timeout, and preserve the release
and lock-file removal assertions.

---

Nitpick comments:
In `@src/provider/accounts.ts`:
- Around line 363-366: Update the environment branch in the account selection
flow to choose the account whose id matches ACCOUNT_1_ID instead of using
accounts[0]. Preserve the existing filtering behavior and leave the
non-environment credential filtering unchanged, keeping it consistent with
resolveAccountRoute and snapshot.
- Around line 234-236: Remove or repurpose the no-op account shims
resolveGrokProvider and handleModelSelect in the accounts export: either provide
one shared no-op implementation where the contract requires it, or delete these
exports and update all dependent imports and tests, preserving the runtime
accountManagement.handleModelSelect() path.

In `@src/provider/accountVault.ts`:
- Around line 231-237: In getAccountVault, remove the intermediate vault
declaration and assignment, and return a structuredClone of the withVaultLock
callback’s current value directly. Preserve the existing lock invocation and
false argument.
- Around line 117-118: Update the validation around the vault root in the
account-vault parsing flow: have the !isObject(value) branch report a distinct
invalid-root/object error, while retaining unsupported version only for the
value.version !== 1 branch.

In `@src/provider/dashboard/app.js`:
- Around line 785-787: Rename the account-ID variables throughout the relevant
flow: change pendingProviders to pendingAccountIds, the loop variable provider
to accountId, and dataset.provider to dataset.accountId. Update all matching
references and selectors, including the sections around the pending-account
selection and subsequent lookup logic, while preserving behavior.

In `@src/provider/quotaCache.ts`:
- Around line 122-132: Update saveQuotaUsageWhen to accept an optional path
override, pass it through to updateQuotaCache, and preserve the default path
behavior when omitted so its API matches saveQuotaUsage and removeQuotaUsage.

In `@tests/config.test.ts`:
- Around line 125-133: Make the “preserves a legacy file when the destination is
not writable” test reliable under root by skipping it when process.getuid?.()
=== 0, or replace the chmod-based setup with the non-directory-path failure
approach used in storage tests. Keep the existing migration warning assertion
for environments where the failure is actually simulated.

In `@tests/provider/accountMigration.test.ts`:
- Around line 231-267: Extend the migration tests around migrateReleasedAccounts
to write a released configuration with version 4 and assert that the operation
rejects with migrationError. Use the existing setup and configuration-writing
helpers, and pin the unsupported-version behavior without changing handling for
supported versions.

In `@tests/provider/accounts.test.ts`:
- Line 53: Replace the manual GROK_CLI_OAUTH_TOKEN save-and-restore logic around
the affected test setup and teardown with the existing useEnvironmentToken
helper from tests/stateTestHelpers.ts. Update both the originalToken declaration
and the cleanup at lines 147-150, preserving the current token setup behavior
while delegating restoration to the shared helper.

In `@tests/provider/package.test.ts`:
- Around line 40-43: Remove the redundant jiti and typebox dependency assertions
from the packageJson checks, keeping the dependencies absence assertion and the
existing devDependencies assertion in the relevant package test.

In `@tests/provider/register.test.ts`:
- Around line 269-285: The Pi credential fixtures are duplicated across both
test suites. In tests/stateTestHelpers.ts, add shared writePiCredential and
vault-marker helpers; in tests/provider/register.test.ts lines 269-285, remove
local writeAuth and writeMarker and import the shared helpers; in
tests/provider/accounts.test.ts lines 103-123, remove local writePiCredential
and connectPi and import the shared helpers instead.

In `@tests/provider/sessionAccountSelection.test.ts`:
- Around line 29-31: Update the session account selection test setup around
beforeEach to use useEnvironmentToken from stateTestHelpers, ensuring
GROK_CLI_OAUTH_TOKEN is cleared for the suite and restored afterward. Preserve
the existing setupHome and mutateAccountVault initialization flow.

In `@tests/stateTestHelpers.ts`:
- Around line 20-24: Update deferred to store its Promise resolver in a single
variable rather than the resolvers array, then have the returned resolve
function call that resolver directly without optional chaining. Preserve the
existing promise and generic value behavior.

In `@tests/storage.test.ts`:
- Around line 120-149: Update the test around acquireFileLock to await the
pending lock acquisition directly, remove the Promise.race and queueMicrotask
logic, and eliminate the conditional release/removal branch. Assert that the
recovery barrier is absent after releasing the acquired lock, preserving cleanup
of fake timers in the existing finally block.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bfe9631-0021-4fda-aa6e-bf8c7f6a7c87

📥 Commits

Reviewing files that changed from the base of the PR and between 5a2cbd8 and e96576c.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (78)
  • CONFIGURATION.md
  • README.md
  • SECURITY.md
  • knip.json
  • package.json
  • src/config.ts
  • src/imagine/register.ts
  • src/imagine/tool.ts
  • src/imagine/workflow.ts
  • src/models/catalog.ts
  • src/provider/accountMigration.ts
  • src/provider/accountRouting.ts
  • src/provider/accountVault.ts
  • src/provider/accounts.ts
  • src/provider/dashboard/app.css
  • src/provider/dashboard/app.js
  • src/provider/dashboard/server.ts
  • src/provider/modelMigration.ts
  • src/provider/quotaCache.ts
  • src/provider/register.ts
  • src/provider/requestOwnership.ts
  • src/provider/rotation.ts
  • src/provider/sessionAccountSelection.ts
  • src/provider/toolScope.ts
  • src/provider/usage.ts
  • src/storage.ts
  • src/tools/files.ts
  • src/tools/glob.ts
  • src/tools/read.ts
  • src/tools/register.ts
  • src/tools/rendering.ts
  • src/tools/search.ts
  • src/tools/shell.ts
  • src/tools/webSearch.ts
  • src/tools/webSearchDelegate.ts
  • src/vision/cache.ts
  • src/vision/describe.ts
  • src/vision/register.ts
  • tests/config.test.ts
  • tests/imagine/config.test.ts
  • tests/imagine/helpers.ts
  • tests/imagine/preview.test.ts
  • tests/imagine/register.test.ts
  • tests/imagine/save.test.ts
  • tests/imagine/tool.test.ts
  • tests/models/catalog.test.ts
  • tests/provider/accountMigration.test.ts
  • tests/provider/accountRouting.test.ts
  • tests/provider/accountVault.test.ts
  • tests/provider/accounts.test.ts
  • tests/provider/dashboard.test.ts
  • tests/provider/modelMigration.test.ts
  • tests/provider/package.test.ts
  • tests/provider/quotaCache.test.ts
  • tests/provider/register.test.ts
  • tests/provider/rotation.test.ts
  • tests/provider/sessionAccountSelection.test.ts
  • tests/provider/toolScope.integration.test.ts
  • tests/provider/toolScope.test.ts
  • tests/stateTestHelpers.ts
  • tests/storage.test.ts
  • tests/tools/files.test.ts
  • tests/tools/glob.test.ts
  • tests/tools/nativeAdapter.integration.test.ts
  • tests/tools/read.test.ts
  • tests/tools/register.test.ts
  • tests/tools/rendering.test.ts
  • tests/tools/search.test.ts
  • tests/tools/shell.test.ts
  • tests/tools/toolTestHelpers.ts
  • tests/tools/webSearch.test.ts
  • tests/tools/webSearchDelegate.test.ts
  • tests/tools/webSearchDelegateRetry.test.ts
  • tests/vision/cache.test.ts
  • tests/vision/config.test.ts
  • tests/vision/describe.test.ts
  • tests/vision/helpers.ts
  • tests/vision/register.test.ts
💤 Files with no reviewable changes (32)
  • src/tools/register.ts
  • src/tools/shell.ts
  • src/tools/files.ts
  • src/tools/webSearch.ts
  • src/tools/rendering.ts
  • src/tools/glob.ts
  • src/vision/describe.ts
  • src/tools/read.ts
  • src/vision/cache.ts
  • src/tools/webSearchDelegate.ts
  • src/provider/toolScope.ts
  • tests/tools/register.test.ts
  • tests/tools/nativeAdapter.integration.test.ts
  • tests/tools/glob.test.ts
  • tests/vision/config.test.ts
  • tests/vision/cache.test.ts
  • src/tools/search.ts
  • tests/provider/toolScope.test.ts
  • tests/tools/rendering.test.ts
  • tests/tools/files.test.ts
  • tests/vision/register.test.ts
  • tests/tools/webSearchDelegateRetry.test.ts
  • tests/tools/toolTestHelpers.ts
  • tests/tools/webSearch.test.ts
  • tests/provider/toolScope.integration.test.ts
  • tests/tools/webSearchDelegate.test.ts
  • src/vision/register.ts
  • tests/tools/search.test.ts
  • tests/vision/describe.test.ts
  • tests/vision/helpers.ts
  • tests/tools/read.test.ts
  • tests/tools/shell.test.ts

Comment thread src/config.ts
Comment thread src/provider/accountMigration.ts Outdated
Comment thread src/provider/dashboard/server.ts
Comment on lines +8 to +11
async function migrateSettings(directory: string) {
if (!existsSync(join(directory, 'settings.json'))) return false;
const settings = SettingsManager.create(join(directory, '.pi-grok-cli-migration'), directory);
const current = settings.getGlobalSettings();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the SettingsManager.create signature and the file each argument controls.
rg -nP -B 5 -A 40 'static create' --glob '**/@earendil-works/pi-coding-agent/**' | head -120
rg -nP -A 10 'getGlobalSettings|setDefaultProvider|setEnabledModels|drainErrors' --glob '**/@earendil-works/pi-coding-agent/**/*.d.ts' | head -60

Repository: kenryu42/pi-grok-cli

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | sed -n '1,120p'

echo "== locate modelMigration and settings files =="
fd -a 'modelMigration|SettingsManager|.*settings.*|.*provider.*' . | sed -n '1,200p'

echo "== search SettingsManager references =="
rg -n "SettingsManager|modelMigration|migrateSettings|pi-grok-cli-migration|getGlobalSettings|setDefaultProvider|setEnabledModels|drainErrors|existsSync|join\\(" . --glob '!node_modules' --glob '!dist' --glob '!build' || true

Repository: kenryu42/pi-grok-cli

Length of output: 21050


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package.json =="
cat -n package.json

echo "== lock/package settings excerpts =="
rg -n "`@earendil-works/pi-coding-agent`|pi-coding-agent|SettingsManager|agentDir" package.json bun.lock --glob '!node_modules' --glob '!.release-tools/**' || true

echo "== modelMigration source =="
cat -n src/provider/modelMigration.ts

echo "== modelMigration tests =="
cat -n tests/provider/modelMigration.test.ts

echo "== local package metadata =="
node - <<'JS'
const fs = require('fs');
const path = require('path');
const pkg = JSON.parse(fs.readFileSync('package.json','utf8'));
console.log(JSON.stringify({
  imports: pkg.imports,
  alias: pkg._metabuddy?.imports,
  dependencies: pkg.dependencies,
  devDependencies: pkg.devDependencies
}, null, 2));
JS

echo "== check for vendored package files =="
fd -a '`@earendil-works`|pi-coding-agent' . | sed -n '1,80p' || true

Repository: kenryu42/pi-grok-cli

Length of output: 10175


🌐 Web query:

@earendil-works/pi-coding-agent 0.80.9 SettingsManager.create agentDir cwd getGlobalSettings flush

💡 Result:

In the @earendil-works/pi-coding-agent SDK, SettingsManager provides a centralized way to manage and persist agent configurations, which are merged from global (~/.pi/agent/settings.json) and project-specific (.pi/settings.json) files [1][2]. SettingsManager.create(cwd?: string, agentDir?: string) This is a static factory method used to initialize a SettingsManager that loads and merges settings from the file system [2][3][4]. - cwd: An optional string representing the current working directory, used to locate project-specific settings [2][5]. It defaults to process.cwd [5]. - agentDir: An optional string representing the directory where global settings are stored [2][5]. It typically defaults to a standard configuration path (often resolved via getAgentDir) [5]. getGlobalSettings This method returns a deep clone of the current global settings object [5][6]. Because SettingsManager handles merging of global and project settings internally, this method allows you to specifically inspect the global configuration scope [2][5]. flush Since setters in SettingsManager update the internal memory state synchronously but enqueue persistence writes (file I/O) asynchronously to optimize performance, flush is used to ensure durability [7][2][3]. You should call await settingsManager.flush whenever you need a strict durability boundary, such as before exiting the process or validating that changes have been written to disk in a test environment [2][3]. General Workflow 1. Initialization: Create the manager using SettingsManager.create(cwd) [7][2]. 2. Manipulation: Use provided setter methods (e.g., setQuietStartup, applyOverrides) to modify settings in memory [7][2][8]. 3. Durability: Call await settingsManager.flush to persist changes to the file system [7][2]. 4. Error Handling: Because persistence is asynchronous, I/O errors are not thrown immediately; use settingsManager.drainErrors to retrieve and handle any recorded configuration errors [7][2][3].

Citations:


🌐 Web query:

npm @earendil-works/pi-coding-agent 0.80.9 dist/core/settings-manager.d.ts

💡 Result:

The file dist/core/settings-manager.d.ts is part of the @earendil-works/pi-coding-agent package, a minimal terminal coding agent harness [1][2]. In version 0.80.9, released on July 16, 2026, this component is responsible for managing both global and project-specific settings [3][4][5]. The SettingsManager class facilitates loading, merging, and persisting user configurations [6][7]. It supports two configuration locations: 1. Global settings: Located at ~/.pi/agent/settings.json [7]. 2. Project settings: Located at.pi/settings.json [7]. Project settings automatically override global settings, with nested objects merged during the configuration process [7]. The SDK allows programmatic access to this functionality via the SettingsManager API, enabling developers to create agent sessions with custom configurations, including in-memory settings for testing without file I/O [6][8][9]. For further implementation details, you can refer to the official source code [5] and documentation [6][7] in the earendil-works/pi repository.

Citations:


🌐 Web query:

raw.githubusercontent.com/earendil-works/pi v0.80.9 packages/coding-agent/src/core/settings-manager.ts create getGlobalSettings flush

💡 Result:

In the earendil-works/pi repository, the SettingsManager class within packages/coding-agent/src/core/settings-manager.ts handles global and project-specific configuration [1]. The create method is a static factory function used to instantiate the SettingsManager [1][2]. It loads and merges settings from two sources: 1. Global: ~/.pi/agent/settings.json [2] 2. Project: <cwd>/.pi/settings.json [2] The SettingsManager class does not have a method named getGlobalSettings. Instead, it exposes the merged settings via a settings property (which combines global and project settings, with project settings taking precedence) and tracks them internally via globalSettings and projectSettings fields [1][2]. Regarding flush, the SettingsManager uses a writeQueue (a Promise chain) to manage asynchronous I/O operations and ensure settings are saved correctly [1]. While there is no explicit public method named flush, saving behavior is triggered by various setter methods (e.g., setDefaultProjectTrust) which call an internal save() method [1][3]. The save() method typically orchestrates the writing of modified global settings back to the filesystem [1][2][3].

Citations:


🌐 Web query:

raw.githubusercontent.com/earendil-works/pi v0.80.9 packages/coding-agent/dist/sdk.d.ts SettingsManager create getGlobalSettings

💡 Result:

In the @earendil-works/pi repository, the SettingsManager class provides functionality for managing application configuration [1][2]. The create and getGlobalSettings methods are part of this management system [1][2]. Specifically, SettingsManager.create(cwd, agentDir) is used to instantiate a settings manager, where cwd is the working directory and agentDir is the directory where global settings (like auth.json or models.json) are stored [1][2]. Within the coding agent SDK, this is often used to initialize the environment for an agent session [1][3]. While the exact method signature in v0.80.9 may vary, the established pattern in the @earendil-works/pi codebase—as seen in its SDK definitions—is: SettingsManager.create(cwd?: string, agentDir?: string): SettingsManager Once a SettingsManager instance is created, you can access global settings. If getGlobalSettings is implemented on the instance, it typically retrieves the persisted global configuration for the agent [1][2]. For most users and developers, the SettingsManager is handled internally by the coding agent when you run the pi command or initialize a session using createAgentSession [4][3]. If you are working directly with the SDK, you would typically use these managers to configure the session as shown in the package documentation [1][3]: const loader = new DefaultResourceLoader({ cwd: process.cwd, agentDir: getAgentDir, settingsManager: SettingsManager.create, });

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== fetch 0.80.9 sdk.d.ts =="
curl -fsSL 'https://cdn.jsdelivr.net/npm/@earendil-works/pi-coding-agent@0.80.9/dist/sdk.d.ts' -o /tmp/sdk.d.ts
sed -n '1,220p' /tmp/sdk.d.ts

echo "== fetch 0.80.9 settings manager source =="
curl -fsSL 'https://raw.githubusercontent.com/earendil-works/pi/v0.80.9/packages/coding-agent/src/core/settings-manager.ts' -o /tmp/settings-manager.ts
rg -n "static create|getGlobalSettings|flush|getGlobal|agent" /tmp/settings-manager.ts
sed -n '1,260p' /tmp/settings-manager.ts

Repository: kenryu42/pi-grok-cli

Length of output: 237


🌐 Web query:

unpkg @earendil-works/pi-coding-agent 0.80.9 dist/sdk.d.ts

💡 Result:

The package @earendil-works/pi-coding-agent, version 0.80.9, was released on July 16, 2026 [1][2][3]. The file dist/sdk.d.ts is contained within this package, which provides the SDK for the Pi coding agent [4][5]. You can access the TypeScript definition file directly through the unpkg CDN at the following URL: https://unpkg.com/browse/@earendil-works/pi-coding-agent@0.80.9/dist/sdk.d.ts The Pi coding agent toolkit is a minimal terminal harness used for building AI-driven coding workflows [6][7]. The SDK included in the @earendil-works/pi-coding-agent package allows for programmatic access to agent capabilities, such as session management and model runtime execution [5]. Developers typically use this package by installing it via npm [8][7] or by defining it as a peer dependency when creating custom extensions [9][10]. Note that newer versions of this package have been released since 0.80.9 [2][8][11]. For the latest features and documentation, it is recommended to refer to the official repository at https://github.com/earendil-works/pi [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== npm package metadata =="
npm view `@earendil-works/pi-coding-agent`@0.80.9 dist.tarball name version --json

echo "== fetch package manifests and declarations =="
python3 - <<'PY'
import json,urllib.request,urllib.error,io,tarfile,zipfile,os
url='https://registry.npmjs.org/@earendil-works%2Fpi-coding-agent/0.80.9'
try:
    meta=json.load(urllib.request.urlopen(url,timeout=20))
except Exception as e:
    print("ERR meta", e)
    raise
print("tarball", meta["dist"]["tarball"])
tarball=meta["dist"]["tarball"]
data=urllib.request.urlopen(tarball,timeout=30).read()
print("bytes", len(data))
t=tarfile.open(fileobj=io.BytesIO(data),mode='r:gz')
names=[m.name for m in t if m.filetype==tarfile.RegFileType]
names=[n for n in names if ("dist/sdk.d.ts" in n or "dist/core/settings-manager" in n or "settings-manager.ts" in n or "package.json" in n)]
for n in names:
    print("FOUND", n)
print("--- package.json ---")
print(t.extractfile("package.json").read().decode())
print("--- sdk.d.ts excerpts ---")
sdk=t.extractfile("dist/sdk.d.ts").read().decode(errors="ignore")
for line_i,line in enumerate(sdk.splitlines(),1):
    if "SettingsManager" in line or "create" in line or "getGlobalSettings" in line or "flush" in line or "drainErrors" in line:
        print(line_i, line)
print("--- settings-manager.ts excerpts ---")
sm=t.extractfile("packages/coding-agent/src/core/settings-manager.ts").read().decode(errors="ignore")
for line_i,line in enumerate(sm.splitlines(),1):
    if line_i<=80 or 80 <= line_i <=220:
        print(line_i, line)
PY

Repository: kenryu42/pi-grok-cli

Length of output: 3149


🌐 Web query:

@earendil-works pi coding agent 0.80.9 SettingsManager.create

💡 Result:

In the @earendil-works/pi-coding-agent toolkit (version 0.80.9 and later), SettingsManager.create is a static factory method used to initialize a settings manager that handles the configuration for agent sessions [1][2][3]. Key details regarding SettingsManager.create include: Functionality: It loads settings from the filesystem by merging global and project-level configuration files [1][2]. Signature: SettingsManager.create(cwd?, agentDir?) [1][2]. Parameters: cwd (optional): The current working directory from which to load project settings [1][3]. agentDir (optional): A custom directory path for agent settings [1][2]. Usage: It is typically used when configuring an agent session via createAgentSession [1][2]. For example, to load default settings: const { session } = await createAgentSession({ settingsManager: SettingsManager.create, }); You can also use it to define custom directories: const { session } = await createAgentSession({ settingsManager: SettingsManager.create("/custom/cwd", "/custom/agent"), }); If you need to test without interacting with the filesystem, you can use SettingsManager.inMemory(settings?) instead [1][2][3]. Note that settings changes made via the manager are synchronous for in-memory state but enqueue persistence writes asynchronously; calling await settingsManager.flush is recommended to ensure durability [1][2][3].

Citations:


Keep the migration tied to the real settings path.

With SettingsManager.create(cwd, agentDir), this call swaps the locations: cwd is directory/.pi-grok-cli-migration, so flush() persists to the temporary migration directory instead of directory/settings.json. The project then migrates an in-memory-only copy. Reuse SettingsManager.create(directory, directory) or copy directory/settings.json into the temporary agent directory first.

🤖 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/provider/modelMigration.ts` around lines 8 - 11, Update migrateSettings
so SettingsManager.create receives directory as the real cwd and agent
directory, ensuring flush() persists changes to directory/settings.json;
preserve the existing migration flow and avoid using the temporary
.pi-grok-cli-migration path as the cwd.

Comment thread src/provider/sessionAccountSelection.ts
Comment thread tests/imagine/helpers.ts
Comment thread tests/provider/register.test.ts Outdated
Comment thread tests/provider/register.test.ts
Comment thread tests/stateTestHelpers.ts
Comment thread tests/storage.test.ts Outdated
Why:
- Stored OAuth expiry was skewed twice, and failed dashboard login cleanup could remove an account authenticated by another process.

What:
- Treat stored OAuth expiry as already skewed.
- Remove a new account after login failure only when its revision is unchanged and it has no credential.
- Add regression tests for both cases.

Validation:
- bun run test -- tests/provider/accountRouting.test.ts tests/provider/dashboard.test.ts
- bun run check
- autoreview --mode local

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/provider/accounts.ts (1)

552-554: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the else branch.

Return after activation. Then perform login after the conditional.

Proposed change
-        if (!account.authenticated) await manager.login(ctx, account.id, interaction);
-        else await manager.activate(ctx, account.id);
+        if (account.authenticated) {
+          await manager.activate(ctx, account.id);
+          return;
+        }
+        await manager.login(ctx, account.id, interaction);

As per coding guidelines, “Avoid else statements. Prefer early returns.”

🤖 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/provider/accounts.ts` around lines 552 - 554, Update the authentication
flow around manager.login and manager.activate to remove the else branch: when
account.authenticated is true, await manager.activate(ctx, account.id) and
return immediately; otherwise continue after the conditional to perform
manager.login(ctx, account.id, interaction).

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@src/provider/accounts.ts`:
- Around line 552-554: Update the authentication flow around manager.login and
manager.activate to remove the else branch: when account.authenticated is true,
await manager.activate(ctx, account.id) and return immediately; otherwise
continue after the conditional to perform manager.login(ctx, account.id,
interaction).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7051ade9-a86f-4eed-8a44-b1280b2df6ec

📥 Commits

Reviewing files that changed from the base of the PR and between e96576c and 360acd8.

📒 Files selected for processing (25)
  • src/config.ts
  • src/provider/accountMigration.ts
  • src/provider/accountRouting.ts
  • src/provider/accountVault.ts
  • src/provider/accounts.ts
  • src/provider/dashboard/app.js
  • src/provider/dashboard/server.ts
  • src/provider/quotaCache.ts
  • src/provider/sessionAccountSelection.ts
  • src/provider/usage.ts
  • src/storage.ts
  • tests/config.test.ts
  • tests/imagine/helpers.ts
  • tests/provider/accountMigration.test.ts
  • tests/provider/accountRouting.test.ts
  • tests/provider/accountVault.test.ts
  • tests/provider/accounts.test.ts
  • tests/provider/dashboard.test.ts
  • tests/provider/package.test.ts
  • tests/provider/quotaCache.test.ts
  • tests/provider/register.test.ts
  • tests/provider/sessionAccountSelection.test.ts
  • tests/provider/usage.test.ts
  • tests/stateTestHelpers.ts
  • tests/storage.test.ts
💤 Files with no reviewable changes (1)
  • tests/provider/package.test.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • tests/provider/quotaCache.test.ts
  • tests/imagine/helpers.ts
  • src/provider/accountRouting.ts
  • src/provider/usage.ts
  • src/storage.ts
  • src/provider/sessionAccountSelection.ts
  • tests/provider/sessionAccountSelection.test.ts
  • src/provider/quotaCache.ts
  • src/provider/accountMigration.ts
  • src/provider/dashboard/app.js
  • tests/provider/accounts.test.ts
  • src/config.ts

@kenryu42
kenryu42 merged commit 2b90506 into main Aug 1, 2026
3 checks passed
@kenryu42
kenryu42 deleted the remove-shims branch August 1, 2026 09:36
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