Skip to content

Comments

Staging#1087

Merged
MrgSub merged 77 commits intomainfrom
staging
May 26, 2025
Merged

Staging#1087
MrgSub merged 77 commits intomainfrom
staging

Conversation

@MrgSub
Copy link
Collaborator

@MrgSub MrgSub commented May 26, 2025

Summary by CodeRabbit

  • New Features

    • Added bulk spam deletion: users can now delete all spam emails at once.
    • Introduced a print button in the email view for printing emails.
    • Added a reusable dialog for creating and editing email labels with color selection.
    • Added a sidebar component for organized label display.
    • Introduced phone number verification via OTP (currently disabled in UI).
    • Added new localization strings for bulk spam actions.
    • Added a utility hook for accessing previous state values.
  • Enhancements

    • Improved infinite scrolling in the email list for seamless loading.
    • Updated label color selection with a predefined palette and color mapping.
    • Refined label rendering and sidebar organization for better navigation.
    • Updated user settings schema and validation.
    • Enhanced AI sidebar integration with a new agent abstraction.
    • Improved layout and spacing in the home content section.
    • Added documentation for new features and devcontainer setup.
  • Bug Fixes

    • Ensured locale always defaults to English if not set.
    • Fixed type and prop issues in various UI components.
    • Improved error handling and user feedback for label and favorite actions.
  • Chores

    • Updated and unified ESLint and TypeScript configurations across packages.
    • Migrated database and removed deprecated package files.
    • Updated Docker and environment setup instructions.
    • Refactored and cleaned up internal code and dependencies.
  • Removals

    • Removed cookie consent and cookie utilities.
    • Deleted deprecated feature flag and signature parsing utilities.
    • Removed unused or legacy configuration and script files.

giteshsarvaiya and others added 30 commits May 12, 2025 19:15
…new environment variable for Perplexity API key
…h tool and refining system prompt instructions
MrgSub and others added 26 commits May 25, 2025 13:03
chore: remove unused Twilio configuration and add ZeroAgent and ZeroMCP to migrations
chore: add versioning for migrations with new_classes and new_sqlite_classes for v2
chore: remove duplicate entries for ZeroAgent and ZeroMCP in wrangler.jsonc
feat: enhance ZeroMCP with new tools and improved thread information handling
…on-886

feat(mail/spam): add 'Delete All Spam' button (#886)
feat: move db from packages into server
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 26, 2025

Walkthrough

This update introduces significant refactoring and feature additions across the mail and server applications. Major changes include a new bulk spam deletion feature, label color mapping, phone number verification with Twilio integration, infinite scrolling in the mail list, centralized user settings schemas, and the migration of ESLint and TypeScript configurations to shared packages. Several files and modules related to cookie consent and feature flags are removed, and new durable objects and MCP (Model Context Protocol) support are added on the server.

Changes

File(s) / Group Change Summary
.devcontainer/Dockerfile, .gitignore Updated devcontainer setup to install pnpm, ignore new devcontainer artifacts.
.env.example Added Twilio and Perplexity API-related environment variables.
MCP.md, README.md Added documentation for Zero MCP and devcontainer setup.
apps/mail/components/mail/mail-list.tsx, apps/mail/hooks/use-threads.ts, apps/mail/types/index.ts Refactored mail list to use infinite scroll; updated thread types to include historyId; updated useThread to accept historyId and invalidate cache on change.
apps/mail/components/mail/mail-display.tsx Added email printing feature with UI and print handling logic.
apps/mail/components/labels/label-dialog.tsx, apps/mail/components/ui/nav-main.tsx, apps/mail/components/ui/sidebar-labels.tsx, apps/mail/components/ui/recursive-folder.tsx Centralized label dialog and sidebar label rendering; improved type safety and simplified UI logic.
apps/mail/components/ui/app-sidebar.tsx Added phone number verification dialog using Twilio OTP; updated sidebar logic.
apps/mail/components/context/thread-context.tsx Wrapped label/favorite mutations in toast promises for better user feedback.
apps/mail/components/create/extensions.ts Removed code block, YouTube, and math extensions from editor setup.
apps/mail/components/ui/input.tsx Simplified input component props and styling; removed error prop.
apps/mail/components/ui/input-otp.tsx Updated OTP input styling and icons.
apps/mail/components/magicui/file-tree.tsx Added optional color prop to Folder component.
apps/mail/components/home/HomeContent.tsx Adjusted text/image padding and positioning for layout refinement.
apps/mail/components/mail/render-labels.tsx Updated label button styling for improved appearance.
apps/mail/components/party.tsx Commented out unused label/thread refetch logic.
apps/mail/components/ui/ai-sidebar.tsx Switched chat state management to agent abstraction; refactored imports.
apps/mail/components/(full-width)/contributors.tsx Explicitly typed fetch responses; removed global animation CSS.
apps/mail/app/root.tsx Ensured locale fallback to 'en' in loader and layout.
apps/mail/app/(routes)/settings/* Updated user settings schema imports to new server location; minor UI tweaks.
apps/mail/lib/label-colors.ts, apps/server/src/lib/driver/google-label-color-map.ts Added label color constants and mapping utilities for label color handling.
apps/mail/lib/email-utils.client.tsx, apps/mail/lib/sanitize-tip-tap-html.tsx Switched email rendering from @react-email/render to react-dom/server.
apps/mail/lib/utils.ts, apps/server/src/lib/utils.ts Removed createAIJsonContent; added header parsing utility.
apps/mail/lib/auth-client.ts, apps/mail/lib/auth-proxy.ts Switched to phone number plugin for authentication; improved error logging.
apps/server/src/lib/services.ts Added Twilio SMS sending utility with mock support.
apps/server/src/lib/driver/google.ts, apps/server/src/lib/driver/types.ts, apps/server/src/lib/driver/microsoft.ts Added historyId to threads, implemented bulk spam deletion, centralized label color mapping.
apps/server/src/lib/schemas.ts Added centralized user settings schema and defaults.
apps/server/src/lib/prompts.ts Enhanced system prompt for AI assistant with new tool usage and style rules.
apps/server/src/routes/agent/tools.ts, apps/server/src/routes/agent/utils.ts Refactored web search tool to use Perplexity; improved tool call logic and exports.
apps/server/src/routes/chat.ts, apps/server/src/main.ts Refactored chat and MCP handling into ZeroAgent/ZeroMCP classes; added durable object bindings and routes.
apps/server/src/trpc/routes/mail.ts, apps/server/src/types.ts Added mutation and response type for bulk spam deletion.
apps/server/src/db/schema.ts, apps/server/src/db/migrations/* Added phone number and verification columns to user schema; updated migration and snapshot.
apps/server/drizzle.config.ts Added Drizzle Kit config for migrations.
apps/server/eslint.config.ts, apps/mail/eslint.config.ts, packages/eslint-config/config.ts Migrated ESLint config to shared package and flat config format.
apps/server/package.json, apps/mail/package.json, pnpm-workspace.yaml Updated dependencies, scripts, and workspace catalog for new packages and tools.
apps/server/tsconfig.json, apps/mail/tsconfig.json, packages/cli/tsconfig.json, packages/tailwind-config/tsconfig.json, tsconfig.json, packages/tsconfig/base.json Centralized and modernized TypeScript configuration; removed unused configs.
apps/mail/hooks/use-previous.ts Added new usePrevious React hook for tracking previous values.
Removed: apps/mail/components/cookies/cookie-dialog.tsx, apps/mail/lib/cookie-utils.ts, apps/mail/lib/cookies.ts, apps/mail/providers/cookie-provider.tsx, apps/mail/lib/flags.ts, packages/db/*, packages/eslint-config/eslint.config.mjs, packages/eslint-config/index.js, packages/tsconfig/nextjs.json, packages/tsconfig/react-library.json, packages/db/.npmrc, packages/db/package.json, packages/db/tsconfig.json, packages/db/drizzle.config.ts, packages/db/src/user_settings_default.ts Removed cookie consent, feature flag, and legacy database/config files.
apps/server/wrangler.jsonc Added durable object bindings for ZeroAgent and ZeroMCP in all environments.
scripts/seed-style/seeder.ts Commented out all code, effectively disabling the style seeder script.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MailUI
    participant ServerAPI
    participant MailDriver
    participant Twilio

    Note over User,MailUI: Bulk Spam Deletion Feature
    User->>MailUI: Click "Delete All Spam"
    MailUI->>ServerAPI: Call deleteAllSpam mutation
    ServerAPI->>MailDriver: driver.deleteAllSpam()
    MailDriver->>MailDriver: List spam threads (batch)
    loop For each batch
        MailDriver->>MailDriver: Move threads to trash
    end
    MailDriver-->>ServerAPI: Return count of deleted threads
    ServerAPI-->>MailUI: Return success/failure message
    MailUI-->>User: Show toast with result

    Note over User,MailUI: Phone Number Verification (Twilio OTP)
    User->>MailUI: Enter phone number, submit
    MailUI->>ServerAPI: Update profile, request sendOtp
    ServerAPI->>Twilio: Send SMS with OTP
    Twilio-->>ServerAPI: SMS sent confirmation
    ServerAPI-->>MailUI: Prompt for OTP input
    User->>MailUI: Enter OTP, submit
    MailUI->>ServerAPI: Verify OTP
    ServerAPI-->>MailUI: Verification result
    MailUI-->>User: Show verification status
Loading

Possibly related PRs

Suggested reviewers

  • BlankParticle

Poem

Hopping through code with a twitch of my nose,
I see labels now colored, and spam in repose.
Infinite scroll flows, no more "Load More" pain,
Twilio sends texts, phone numbers to gain.
With MCP magic and settings anew,
This bunny says, "Bravo!"—the garden just grew!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@cloudflare-workers-and-pages
Copy link

Deploying with  Cloudflare Workers  Cloudflare Workers

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

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
zero-server-staging 7f9a1c3 May 26 2025, 06:53 PM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 27

🔭 Outside diff range comments (1)
apps/server/src/routes/agent/utils.ts (1)

38-88: 🛠️ Refactor suggestion

Good refactoring, but avoid using 'any' type.

The separation of executeFunctions from tools improves the function interface. However, the use of any type on lines 52 and 72 reduces type safety.

Consider using a generic type parameter or unknown instead:

-    ) => Promise<any>;
+    ) => Promise<unknown>;
-  let result: any;
+  let result: unknown;
♻️ Duplicate comments (1)
apps/server/src/main.ts (1)

85-98: Duplicate authorization logic (same as above)

This mount point has the same authorization pattern as /sse. The refactoring suggestion above applies here as well.

🧹 Nitpick comments (26)
apps/server/src/lib/party.ts (1)

12-15: Consider adding error handling around session retrieval
Right now, getSession will bubble up any errors from this.auth.api.getSession. You may want to wrap this call in a try/catch and handle network or auth errors gracefully (e.g. logging, returning null, etc.).

apps/mail/components/ui/sidebar.tsx (1)

263-263: Verify Tailwind scrollbar utilities and accessibility
You’ve added scrollbar-none and scrollbar-w-0 to hide the scrollbar. Make sure the Tailwind CSS scrollbar plugin (or equivalent) is enabled so these classes are recognized, and double-check that hiding the scrollbar doesn’t impair keyboard or screen-reader navigation.

.devcontainer/Dockerfile (1)

31-33: Good addition of pnpm support, but consider adding PATH configuration.

The pnpm installation using the official script is correct and aligns well with the existing Bun setup.

Consider adding pnpm to the PATH in both bashrc and zshrc for consistency with the Bun setup:

# Register Bun in bashrc and zshrc
RUN echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.bashrc
RUN echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.zshrc
+
+# Register pnpm in bashrc and zshrc  
+RUN echo 'export PNPM_HOME="$HOME/.local/share/pnpm"' >> ~/.bashrc
+RUN echo 'export PATH="$PNPM_HOME:$PATH"' >> ~/.bashrc
+RUN echo 'export PNPM_HOME="$HOME/.local/share/pnpm"' >> ~/.zshrc
+RUN echo 'export PATH="$PNPM_HOME:$PATH"' >> ~/.zshrc
.env.example (1)

32-32: Consider adding a comment for clarity.

The purpose of AUTUMN_SECRET_KEY is not immediately clear from the context.

Consider adding a comment to clarify its purpose:

+# Autumn encryption/secret key (specify purpose)
AUTUMN_SECRET_KEY=
apps/mail/components/party.tsx (1)

14-16: Remove commented code for cleaner codebase.

The commented-out refetch function destructuring suggests a successful transition to the query invalidation approach with debouncers. Since the new implementation using queryClient.invalidateQueries() is more performant and follows React Query best practices, the old code should be removed entirely.

-//   const { refetch: refetchLabels } = useLabels();
-//   const [{ refetch: refetchThreads }] = useThreads();

Also consider removing the related commented callback functions (lines 19-25) if they're no longer needed.

README.md (2)

116-116: Fix grammar: "setup" should be "set up" when used as a verb.

-   - Run `pnpm nizzy env` to setup your environment variables
+   - Run `pnpm nizzy env` to set up your environment variables
🧰 Tools
🪛 LanguageTool

[grammar] ~116-~116: The word “setup” is a noun. The verb is spelled with a white space.
Context: ...ronment** - Run pnpm nizzy env to setup your environment variables - Run `pn...

(NOUN_VERB_CONFUSION)


107-107: Add language specification to the code block.

-   ```
+   ```bash
    pnpm install
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

107-107: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

apps/server/src/lib/services.ts (1)

26-47: Consider input validation and alternative encoding methods.

The SMS sending implementation could be enhanced with:

  1. Phone number validation: Add basic E.164 format validation
  2. Message length validation: Twilio has SMS length limits
  3. Alternative to btoa: Consider using TextEncoder for better compatibility
 const send = async (to: string, body: string) => {
+  // Validate phone number format (basic E.164)
+  if (!/^\+[1-9]\d{1,14}$/.test(to)) {
+    throw new Error('Invalid phone number format. Use E.164 format (+1234567890)');
+  }
+  
+  // Validate message length (160 chars for single SMS)
+  if (body.length > 160) {
+    console.warn('Message exceeds 160 characters and may be split into multiple SMS');
+  }
+
   const response = await fetch(
     `https://api.twilio.com/2010-04-01/Accounts/${env.TWILIO_ACCOUNT_SID}/Messages.json`,
     {
       method: 'POST',
       headers: {
         'Content-Type': 'application/x-www-form-urlencoded',
-        Authorization: `Basic ${btoa(`${env.TWILIO_ACCOUNT_SID}:${env.TWILIO_AUTH_TOKEN}`)}`,
+        Authorization: `Basic ${Buffer.from(`${env.TWILIO_ACCOUNT_SID}:${env.TWILIO_AUTH_TOKEN}`).toString('base64')}`,
       },
apps/server/src/lib/utils.ts (1)

3-7: Consider renaming the function for clarity and add input validation.

The function name parseHeaders is misleading since it's creating headers rather than parsing them. Consider renaming to createAuthHeaders or buildCookieHeaders for better clarity.

Additionally, consider adding basic input validation for the token parameter.

-export const parseHeaders = (token: string) => {
+export const createAuthHeaders = (token: string) => {
+  if (!token || typeof token !== 'string') {
+    throw new Error('Token must be a non-empty string');
+  }
   const headers = new Headers();
   headers.set('Cookie', token);
   return headers;
 };
apps/server/src/trpc/routes/mail.ts (1)

258-258: Remove extra blank line.

Extra blank line should be removed for consistency.

-
apps/mail/vite.config.ts (1)

33-35: Consider more specific warmup patterns.

The warmup patterns ./app/**/* and ./components/**/* might be too broad and could include unnecessary files like test files, stories, or other non-runtime files.

Consider more specific patterns:

     warmup: {
-      ssrFiles: ['./app/**/*', './components/**/*'],
+      ssrFiles: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
     },
apps/mail/components/mail/render-labels.tsx (1)

48-48: Remove commented code.

The commented borderColor line should either be implemented or removed.

             color: label.color?.backgroundColor,
-            // borderColor: label.color?.backgroundColor,
apps/server/package.json (1)

24-76: Consider version pinning consistency.

The package uses different versioning strategies: exact versions for some packages (e.g., "@ai-sdk/perplexity": "1.1.9"), ranges for others (e.g., "eslint": "^9.27.0"), and catalog references for workspace packages.

Consider establishing a consistent versioning strategy:

  • Use exact versions for critical dependencies
  • Use ranges for development tools
  • Document the rationale in a comment or README
apps/server/src/lib/schemas.ts (1)

48-57: Consider adding validation constraints and defaults

The schema could benefit from more specific validation rules and consistent default handling.

Consider these improvements:

export const userSettingsSchema = z.object({
-  language: z.string(),
-  timezone: z.string(),
+  language: z.string().min(2).max(5).default('en'),
+  timezone: z.string().min(1).default('UTC'),
  dynamicContent: z.boolean().optional(),
  externalImages: z.boolean(),
-  customPrompt: z.string(),
+  customPrompt: z.string().max(1000).default(''),
  isOnboarded: z.boolean().optional(),
  trustedSenders: z.string().array().optional(),
  colorTheme: z.enum(['light', 'dark', 'system']).default('system'),
});

This adds length constraints for language codes, ensures timezone is not empty, limits custom prompt length, and adds appropriate defaults.

apps/mail/components/create/extensions.ts (1)

146-164: Consider documenting the removed extensions

While the removals of CodeBlockLowlight, Youtube, and Mathematics extensions streamline the editor, consider adding a comment explaining the rationale to help future maintainers understand why these were removed.

Add a comment above the defaultExtensions array:

+// Note: CodeBlockLowlight, Youtube, and Mathematics extensions were removed 
+// to simplify the editor and reduce bundle size for email composition use case
export const defaultExtensions = [
MCP.md (2)

3-3: Fix typo in heading.

"Capabilties" should be "Capabilities".

Apply this fix:

-## Capabilties
+## Capabilities

42-42: Fix typo in connection instructions.

"connecto" should be "connect to".

Apply this fix:

-You can connecto ZeroMCP using two methods:
+You can connect to ZeroMCP using two methods:
apps/mail/components/ui/recursive-folder.tsx (1)

90-90: Consider improving type safety for childLabel.

While the parent label type has been improved, childLabel is still typed as any.

Consider updating the type:

-        {label.labels?.map((childLabel: any) => (
+        {label.labels?.map((childLabel: Label & { originalLabel?: Label }) => (
apps/mail/components/ui/ai-sidebar.tsx (1)

377-380: Consider adding validation for the backend URL.

The agent configuration relies on an environment variable that might be undefined.

Add validation to ensure the backend URL is defined:

  const agent = useAgent({
    agent: 'ZeroAgent',
-    host: `${import.meta.env.VITE_PUBLIC_BACKEND_URL}`,
+    host: import.meta.env.VITE_PUBLIC_BACKEND_URL || (() => {
+      throw new Error('VITE_PUBLIC_BACKEND_URL environment variable is not defined');
+    })(),
  });
apps/mail/lib/label-colors.ts (1)

1-35: Well-structured label color palette!

The color palette is comprehensive and well-organized by categories (grayscale, warm, cool, purple, pastels). The use of as const ensures type safety and prevents accidental modifications.

Consider adding a comment or documentation about WCAG color contrast compliance, especially for the combinations with #000000 text on lighter backgrounds.

apps/server/src/routes/agent/tools.ts (1)

530-552: Enhance error handling with more context.

While the implementation correctly uses the new AI SDK, the error handling could provide more specific information about failures.

Improve error handling to include the query for debugging:

     } catch (error) {
       console.error('Error searching the web:', error);
-      throw new Error('Failed to search the web');
+      throw new Error(`Failed to search the web for query: "${query}". ${error instanceof Error ? error.message : 'Unknown error'}`);
     }
apps/server/src/lib/prompts.ts (1)

188-188: Consider consolidating redundant em dash instructions.

The instruction to avoid em dashes appears in both the style adaptation section (line 188) and strict guidelines (line 228). While redundancy can reinforce important rules, consider whether both mentions are necessary.

Also applies to: 228-228

apps/server/src/lib/driver/google-label-color-map.ts (2)

7-9: Track the TODO comment for custom color mappings.

The TODO comment should be tracked in an issue to ensure it's addressed in the future.

Would you like me to create an issue to track the implementation of custom color mappings?


74-77: Consider adding validation for the split operation.

While the current implementation handles missing parts with empty strings, consider validating that the split produces exactly 2 parts for more robust error handling.

const parts = googleKey.split('|');
+if (parts.length !== 2) {
+  continue;
+}
const backgroundColor = parts[0] || '';
const textColor = parts[1] || '';
apps/server/src/routes/chat.ts (2)

71-78: Remove commented code.

The commented code should be removed to maintain code cleanliness, unless it's temporarily needed for reference.

-  //   async onRequest(request: Request): Promise<Response> {
-  //     const token = request.headers.get('cookie');
-  //     if (!token) {
-  //       return new Response('Unauthorized', { status: 401 });
-  //     }
-  //     await this.setupAuth(token);
-  //     return this.getDataStreamResponse(() => {});
-  //   }

186-200: Optimize thread loading in listThreads tool.

The current implementation loads full thread details for each thread in the list, which could be performance-intensive for large result sets. Consider implementing pagination or limiting the detail level.

-        const content = await Promise.all(
-          result.threads.map(async (thread) => {
-            const loadedThread = await driver.get(thread.id);
-            return [
-              {
-                type: 'text' as const,
-                text: loadedThread.latest?.subject ?? '',
-              },
-              {
-                type: 'text' as const,
-                text: `ThreadId: ${thread.id}`,
-              },
-            ];
-          }),
-        );
+        const content = await Promise.all(
+          result.threads.slice(0, Math.min(result.threads.length, 5)).map(async (thread) => {
+            try {
+              const loadedThread = await driver.get(thread.id);
+              return [
+                {
+                  type: 'text' as const,
+                  text: loadedThread.latest?.subject ?? 'No subject',
+                },
+                {
+                  type: 'text' as const,
+                  text: `ThreadId: ${thread.id}`,
+                },
+              ];
+            } catch (error) {
+              return [
+                {
+                  type: 'text' as const,
+                  text: `Error loading thread ${thread.id}: ${error}`,
+                },
+              ];
+            }
+          }),
+        );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 592d699 and 7f9a1c3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (107)
  • .devcontainer/Dockerfile (1 hunks)
  • .env.example (1 hunks)
  • .gitignore (1 hunks)
  • MCP.md (1 hunks)
  • README.md (1 hunks)
  • apps/mail/app/(full-width)/contributors.tsx (1 hunks)
  • apps/mail/app/(routes)/settings/general/page.tsx (2 hunks)
  • apps/mail/app/(routes)/settings/labels/page.tsx (3 hunks)
  • apps/mail/app/(routes)/settings/privacy/page.tsx (1 hunks)
  • apps/mail/app/root.tsx (1 hunks)
  • apps/mail/components/context/thread-context.tsx (2 hunks)
  • apps/mail/components/cookies/cookie-dialog.tsx (0 hunks)
  • apps/mail/components/create/extensions.ts (1 hunks)
  • apps/mail/components/home/HomeContent.tsx (2 hunks)
  • apps/mail/components/labels/label-dialog.tsx (1 hunks)
  • apps/mail/components/magicui/file-tree.tsx (5 hunks)
  • apps/mail/components/mail/mail-display.tsx (6 hunks)
  • apps/mail/components/mail/mail-iframe.tsx (1 hunks)
  • apps/mail/components/mail/mail-list.tsx (10 hunks)
  • apps/mail/components/mail/render-labels.tsx (2 hunks)
  • apps/mail/components/motion-primitives/text-effect.tsx (0 hunks)
  • apps/mail/components/party.tsx (1 hunks)
  • apps/mail/components/ui/ai-sidebar.tsx (2 hunks)
  • apps/mail/components/ui/app-sidebar.tsx (4 hunks)
  • apps/mail/components/ui/input-otp.tsx (3 hunks)
  • apps/mail/components/ui/input.tsx (1 hunks)
  • apps/mail/components/ui/nav-main.tsx (5 hunks)
  • apps/mail/components/ui/recursive-folder.tsx (3 hunks)
  • apps/mail/components/ui/sidebar-labels.tsx (1 hunks)
  • apps/mail/components/ui/sidebar.tsx (1 hunks)
  • apps/mail/components/ui/switch.tsx (0 hunks)
  • apps/mail/eslint.config.mjs (0 hunks)
  • apps/mail/eslint.config.ts (1 hunks)
  • apps/mail/hooks/use-previous.ts (1 hunks)
  • apps/mail/hooks/use-threads.ts (2 hunks)
  • apps/mail/lib/auth-client.ts (2 hunks)
  • apps/mail/lib/auth-proxy.ts (2 hunks)
  • apps/mail/lib/cookie-utils.ts (0 hunks)
  • apps/mail/lib/cookies.ts (0 hunks)
  • apps/mail/lib/email-utils.client.tsx (2 hunks)
  • apps/mail/lib/flags.ts (0 hunks)
  • apps/mail/lib/label-colors.ts (1 hunks)
  • apps/mail/lib/sanitize-tip-tap-html.tsx (1 hunks)
  • apps/mail/lib/utils.ts (0 hunks)
  • apps/mail/locales/en.json (1 hunks)
  • apps/mail/package.json (3 hunks)
  • apps/mail/providers/cookie-provider.tsx (0 hunks)
  • apps/mail/tsconfig.json (1 hunks)
  • apps/mail/types/index.ts (3 hunks)
  • apps/mail/vite.config.ts (1 hunks)
  • apps/server/drizzle.config.ts (1 hunks)
  • apps/server/eslint.config.ts (1 hunks)
  • apps/server/package.json (2 hunks)
  • apps/server/src/ctx.ts (1 hunks)
  • apps/server/src/db/migrations/0027_vengeful_golden_guardian.sql (1 hunks)
  • apps/server/src/db/migrations/meta/0027_snapshot.json (1 hunks)
  • apps/server/src/db/migrations/meta/_journal.json (1 hunks)
  • apps/server/src/db/schema.ts (2 hunks)
  • apps/server/src/lib/auth.ts (2 hunks)
  • apps/server/src/lib/driver/google-label-color-map.ts (1 hunks)
  • apps/server/src/lib/driver/google.ts (8 hunks)
  • apps/server/src/lib/driver/microsoft.ts (2 hunks)
  • apps/server/src/lib/driver/types.ts (4 hunks)
  • apps/server/src/lib/driver/utils.ts (1 hunks)
  • apps/server/src/lib/notes-manager.ts (1 hunks)
  • apps/server/src/lib/party.ts (1 hunks)
  • apps/server/src/lib/prompts.ts (1 hunks)
  • apps/server/src/lib/schemas.ts (1 hunks)
  • apps/server/src/lib/server-utils.ts (1 hunks)
  • apps/server/src/lib/services.ts (1 hunks)
  • apps/server/src/lib/utils.ts (1 hunks)
  • apps/server/src/main.ts (3 hunks)
  • apps/server/src/overrides.d.ts (1 hunks)
  • apps/server/src/routes/agent/tools.ts (2 hunks)
  • apps/server/src/routes/agent/utils.ts (4 hunks)
  • apps/server/src/routes/chat.ts (1 hunks)
  • apps/server/src/services/writing-style-service.ts (1 hunks)
  • apps/server/src/trpc/routes/ai/compose.ts (2 hunks)
  • apps/server/src/trpc/routes/connections.ts (1 hunks)
  • apps/server/src/trpc/routes/mail.ts (3 hunks)
  • apps/server/src/trpc/routes/settings.ts (1 hunks)
  • apps/server/src/trpc/routes/shortcut.ts (1 hunks)
  • apps/server/src/trpc/trpc.ts (1 hunks)
  • apps/server/src/types.ts (1 hunks)
  • apps/server/tsconfig.json (1 hunks)
  • apps/server/wrangler.jsonc (6 hunks)
  • package.json (1 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/cli/tsconfig.json (1 hunks)
  • packages/db/.npmrc (0 hunks)
  • packages/db/drizzle.config.ts (0 hunks)
  • packages/db/package.json (0 hunks)
  • packages/db/src/user_settings_default.ts (0 hunks)
  • packages/db/tsconfig.json (0 hunks)
  • packages/eslint-config/config.ts (1 hunks)
  • packages/eslint-config/eslint.config.mjs (0 hunks)
  • packages/eslint-config/index.js (0 hunks)
  • packages/eslint-config/package.json (1 hunks)
  • packages/eslint-config/tsconfig.json (1 hunks)
  • packages/tailwind-config/tsconfig.json (1 hunks)
  • packages/tsconfig/base.json (1 hunks)
  • packages/tsconfig/nextjs.json (0 hunks)
  • packages/tsconfig/package.json (1 hunks)
  • packages/tsconfig/react-library.json (0 hunks)
  • pnpm-workspace.yaml (1 hunks)
  • scripts/seed-style/seeder.ts (1 hunks)
  • tsconfig.json (1 hunks)
⛔ Files not processed due to max files limit (1)
  • turbo.json
💤 Files with no reviewable changes (18)
  • apps/mail/components/ui/switch.tsx
  • packages/tsconfig/react-library.json
  • packages/db/.npmrc
  • apps/mail/components/motion-primitives/text-effect.tsx
  • packages/db/tsconfig.json
  • packages/db/drizzle.config.ts
  • packages/tsconfig/nextjs.json
  • apps/mail/eslint.config.mjs
  • packages/db/package.json
  • apps/mail/lib/flags.ts
  • apps/mail/lib/utils.ts
  • packages/db/src/user_settings_default.ts
  • apps/mail/components/cookies/cookie-dialog.tsx
  • apps/mail/providers/cookie-provider.tsx
  • apps/mail/lib/cookie-utils.ts
  • packages/eslint-config/eslint.config.mjs
  • apps/mail/lib/cookies.ts
  • packages/eslint-config/index.js
🧰 Additional context used
🧬 Code Graph Analysis (14)
apps/mail/app/(routes)/settings/general/page.tsx (1)
apps/mail/components/ui/select.tsx (1)
  • SelectTrigger (142-142)
apps/mail/lib/auth-proxy.ts (1)
apps/server/src/db/schema.ts (1)
  • session (29-40)
apps/mail/types/index.ts (1)
apps/server/src/types.ts (1)
  • Label (3-13)
apps/server/src/lib/auth.ts (1)
apps/server/src/lib/services.ts (1)
  • twilio (12-54)
apps/server/src/lib/driver/types.ts (1)
apps/server/src/types.ts (1)
  • DeleteAllSpamResponse (140-145)
apps/mail/components/ui/input-otp.tsx (1)
apps/mail/lib/utils.ts (1)
  • cn (51-51)
apps/mail/components/ui/input.tsx (1)
apps/mail/lib/utils.ts (1)
  • cn (51-51)
apps/server/src/trpc/routes/mail.ts (2)
apps/server/src/trpc/trpc.ts (1)
  • activeDriverProcedure (44-78)
apps/server/src/types.ts (1)
  • DeleteAllSpamResponse (140-145)
apps/server/src/main.ts (1)
apps/server/src/routes/chat.ts (1)
  • ZeroMCP (120-453)
apps/server/src/routes/agent/tools.ts (1)
apps/server/src/lib/driver/types.ts (1)
  • MailManager (39-93)
apps/server/src/routes/agent/utils.ts (2)
apps/server/src/routes/agent/shared.ts (1)
  • APPROVAL (1-4)
apps/server/src/routes/agent/tools.ts (1)
  • tools (554-572)
apps/server/src/lib/driver/google.ts (1)
apps/server/src/lib/driver/google-label-color-map.ts (2)
  • mapGoogleLabelColor (49-60)
  • mapToGoogleLabelColor (62-82)
apps/server/src/routes/chat.ts (9)
apps/server/src/lib/auth.ts (2)
  • SimpleAuth (271-271)
  • createSimpleAuth (266-268)
apps/server/src/lib/driver/types.ts (1)
  • MailManager (39-93)
apps/server/src/routes/agent/tools.ts (1)
  • tools (554-572)
apps/server/src/routes/agent/utils.ts (1)
  • processToolCalls (33-117)
apps/server/src/lib/prompts.ts (3)
  • AiChatPrompt (267-586)
  • GmailSearchAssistantSystemPrompt (233-265)
  • getCurrentDateContext (112-112)
apps/server/src/db/schema.ts (1)
  • connection (87-106)
apps/server/src/lib/utils.ts (2)
  • parseHeaders (3-7)
  • FOLDERS (9-16)
apps/server/src/db/index.ts (1)
  • createDb (5-9)
apps/server/src/lib/server-utils.ts (1)
  • connectionToDriver (37-50)
apps/mail/components/mail/mail-list.tsx (2)
apps/mail/hooks/use-threads.ts (1)
  • useThread (62-99)
apps/mail/components/mail/render-labels.tsx (1)
  • RenderLabels (8-85)
🪛 LanguageTool
README.md

[grammar] ~116-~116: The word “setup” is a noun. The verb is spelled with a white space.
Context: ...ronment** - Run pnpm nizzy env to setup your environment variables - Run `pn...

(NOUN_VERB_CONFUSION)

🪛 markdownlint-cli2 (0.17.2)
README.md

107-107: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🪛 Biome (1.9.4)
apps/mail/components/mail/mail-display.tsx

[error] 694-694: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 701-701: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

apps/server/src/routes/chat.ts

[error] 39-39: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 112-112: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 120-120: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

apps/mail/components/mail/mail-list.tsx

[error] 820-820: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Workers Builds: zero-staging
  • GitHub Check: Workers Builds: zero-server-staging
🔇 Additional comments (130)
packages/cli/package.json (1)

9-9: LGTM! Good addition for TypeScript configuration centralization.

The addition of @zero/tsconfig as a development dependency aligns with the broader TypeScript configuration refactoring effort across the repository. Using the workspace:* protocol ensures the local workspace version is used, which follows monorepo best practices.

tsconfig.json (1)

2-2:

Details

❓ Verification inconclusive

Verify TypeScript configuration resolution works without .json extension.

The removal of the .json extension from the extends path aligns with the standardization effort across the repository. However, ensure that TypeScript can properly resolve the configuration without the explicit file extension in all environments and build tools.


🏁 Script executed:

#!/bin/bash
# Description: Verify that TypeScript can resolve the @zero/tsconfig/base configuration without .json extension
# Expected: TypeScript should successfully compile and resolve the extended configuration

# Check if the tsconfig resolves correctly
npx tsc --showConfig --project tsconfig.json

Length of output: 901


🏁 Script executed:

#!/bin/bash
# Install TypeScript locally to ensure the tsc command is available
npm install typescript@latest --no-save

# Verify that TypeScript can resolve the @zero/tsconfig/base configuration without the .json extension
npx tsc --showConfig --project tsconfig.json

Length of output: 1298


Manual Verification Required: Ensure TS Config Extends Resolves Without “.json”

The removal of the .json extension from

"extends": "@zero/tsconfig/base"

relies on TypeScript’s built-in ability to resolve JSON config files without an explicit extension. Since installing and running tsc in the sandbox failed due to workspace protocols, please verify in your local or CI environment that:

  • Running npx tsc --showConfig --project tsconfig.json completes successfully without errors.
  • All downstream build tools and editors correctly pick up the extended config.
apps/mail/lib/sanitize-tip-tap-html.tsx (2)

1-1: Good switch to React's built-in server-side rendering.

Switching from @react-email/render to react-dom/server eliminates an external dependency and uses React's core utilities, which is a good architectural decision.


5-13:

Details

✅ Verification successful

Remove unnecessary async keyword since renderToString is synchronous.

The function is marked as async but renderToString is a synchronous function, unlike the previous render function which was likely asynchronous. This creates misleading function signature.

-export const sanitizeTipTapHtml = async (html: string) => {
+export const sanitizeTipTapHtml = (html: string) => {
   const clean = sanitizeHtml(html);

   return renderToString(
     <Html>
       <div dangerouslySetInnerHTML={{ __html: clean }} />
     </Html>,
   );
 };

🏁 Script executed:

#!/bin/bash
# Description: Check for any callers of sanitizeTipTapHtml that expect it to return a Promise
# Expected: Find all usages and verify they don't await this function

# Search for all usages of sanitizeTipTapHtml
rg -A 3 -B 1 "sanitizeTipTapHtml" --type tsx --type ts

Length of output: 82


Let’s broaden the search and explicitly include both .ts and .tsx files:


🏁 Script executed:

#!/bin/bash
# Search for all occurrences of sanitizeTipTapHtml and check for any awaited calls
rg -n "sanitizeTipTapHtml" -g "*.ts" -g "*.tsx"
rg -n "await sanitizeTipTapHtml" -g "*.ts" -g "*.tsx"

Length of output: 1345


To ensure there are no callsites chaining .then on this function, let’s search for any direct .then usage:


🏁 Script executed:

#!/bin/bash
# Check for any usages chaining sanitizeTipTapHtml with .then
rg -n "sanitizeTipTapHtml(.*)\\.then" -g "*.ts" -g "*.tsx"

Length of output: 59


Remove unnecessary async from sanitizeTipTapHtml in the Mail app

Since renderToString is synchronous and there are no callsites in apps/mail awaiting this function, you can safely drop the async keyword to avoid misleading consumers about its return type.

• Affected file:

  • apps/mail/lib/sanitize-tip-tap-html.tsx

Suggested diff:

-export const sanitizeTipTapHtml = async (html: string) => {
+export const sanitizeTipTapHtml = (html: string) => {
   const clean = sanitizeHtml(html);

   return renderToString(
     <Html>
       <div dangerouslySetInnerHTML={{ __html: clean }} />
     </Html>,
   );
 };
🧰 Tools
🪛 Biome (1.9.4)

[error] 10-10: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

apps/mail/components/home/HomeContent.tsx (2)

1543-1546: LGTM! Clean visual spacing improvements.

The added horizontal padding (pr-12 and pr-14) creates better visual separation between text spans, improving readability and layout consistency.


1563-1575: LGTM! Image positioning adjustments look good.

The repositioning of the snooze and star images enhances the visual layout without affecting functionality.

apps/mail/components/ui/input.tsx (2)

11-11: Good accessibility improvements with focus-visible styles.

The updated focus styles using focus-visible:ring-2 and focus-visible:ring-offset-2 follow modern accessibility patterns and provide better keyboard navigation feedback.


5-6:

Details

✅ Verification successful

Verify removal of error prop doesn't break existing usage.

The component has been simplified by removing the custom InputProps interface and error prop in favor of standard React input props. This is a cleaner approach, but could be a breaking change.


🏁 Script executed:

#!/bin/bash
# Description: Check for any usage of the error prop on Input components
# Expected: Should find no usage of error prop, or identify components that need updating

# Search for Input components with error prop
rg -A 5 -B 2 '<Input[^>]*error' --type tsx --type ts

# Search for Input imports to understand usage patterns
rg -A 3 "import.*Input.*from" --type tsx --type ts

Length of output: 163


🏁 Script executed:

#!/bin/bash
# Re-run search without relying on ripgrep's tsx type

# Search for Input components with an error prop in .ts and .tsx files
find . -type f \( -name '*.ts' -o -name '*.tsx' \) -print0 \
  | xargs -0 rg -n '<Input[^>]*error'

# Search for all imports of the Input component in .ts and .tsx files
find . -type f \( -name '*.ts' -o -name '*.tsx' \) -print0 \
  | xargs -0 rg -n 'import .*Input.* from'

Length of output: 1839


No breaking changes detected: error prop removal is safe

I searched all .ts/.tsx files importing and using the Input component and found zero occurrences of an error prop on <Input>. All existing usages will continue to work without modification.

  • Styling improvements (new focus-visible ring and offset) align with modern accessibility standards.

This simplification is safe to merge.

apps/server/src/ctx.ts (1)

4-4: LGTM! Consistent import path update.

The change from @zero/db to ./db is consistent with the broader refactoring to use local modules instead of the external package. Since this is a type-only import, there's no runtime impact.

apps/mail/components/mail/mail-iframe.tsx (1)

2-2: Approve import update for defaultUserSettings.
Switching the source to @zero/server/schemas correctly reflects the migration of user settings defaults into the server module.

Please verify that the exported defaultUserSettings still contains all expected properties (e.g., externalImages, trustedSenders, etc.) so that existingSettings is fully populated.

apps/mail/app/(routes)/settings/privacy/page.tsx (1)

11-11: Approve updated import for userSettingsSchema.
This aligns with the consolidated server‐side schema location and keeps the form validation consistent across the application.

Confirm that the shape of userSettingsSchema matches the hard‐coded defaultValues (externalImages and trustedSenders) to avoid any mismatches during form reset.

apps/server/src/trpc/routes/shortcut.ts (1)

3-3: Approve relative import for userHotkeys.
Replacing the absolute @zero/db/schema import with the local ../../db/schema correctly follows the PR’s refactoring and does not introduce functional changes.

apps/server/src/services/writing-style-service.ts (1)

3-3: Approve relative import for writingStyleMatrix.
The update from the removed @zero/db/schema to the local ../db/schema is correct and preserves existing behavior.

apps/server/src/trpc/routes/connections.ts (1)

3-3: Approve updated schema imports.
Importing connection and user from the local ../../db/schema matches the removal of @zero/db and keeps the route logic unchanged.

apps/server/src/db/migrations/meta/_journal.json (1)

194-200: LGTM! Standard migration metadata entry.

The new migration entry follows the correct format and structure consistent with existing entries. The migration appears to be for phone number verification features as indicated in the summary.

apps/server/src/lib/server-utils.ts (1)

2-2: LGTM! Consistent import path refactoring.

The change from absolute package import to relative path is part of the broader refactoring to remove the @zero/db package and use local schema definitions. The relative path is correct for this file location.

apps/server/src/lib/notes-manager.ts (1)

2-3: LGTM! Consistent import path refactoring.

The import paths have been correctly updated from absolute package imports to relative imports, consistent with the broader refactoring to remove the @zero/db package. Both the schema and type imports are properly aligned with the new local structure.

apps/server/src/trpc/trpc.ts (1)

6-6: LGTM! Consistent import path refactoring.

The import path update aligns with the broader refactoring to use local relative imports instead of the removed @zero/db package. The relative path is correct for this file location.

apps/mail/app/(routes)/settings/general/page.tsx (2)

21-21: LGTM! Schema import migration.

The import has been correctly updated from the removed @zero/db/user_settings_default package to the new server schema module @zero/server/schemas, consistent with the broader refactoring effort.


198-198: LGTM! UI alignment improvement.

Adding justify-start to the SelectTrigger className improves the alignment of the language selector content by aligning it to the left, providing better visual consistency with the icon and text layout.

apps/server/src/lib/party.ts (1)

3-3: Use centralized parseHeaders utility
This import replaces the previous local implementation. Confirm that apps/server/src/lib/utils.ts exports parseHeaders with the same header-building behavior (e.g. setting the Cookie header and any defaults) to avoid regressions.

apps/server/eslint.config.ts (1)

1-3: Centralized ESLint config import
This file correctly re-exports the shared config from @zero/eslint-config. Ensure the legacy eslint.config.mjs (if still present) is removed from apps/server to prevent conflicting configurations.

apps/mail/eslint.config.ts (1)

1-3: Centralized ESLint config re-export
This new file cleanly delegates to the shared @zero/eslint-config. Verify that the old eslint.config.mjs has been removed from apps/mail to avoid overlapping configurations.

.gitignore (1)

56-60: LGTM! Proper devcontainer artifact exclusion.

The additions correctly ignore devcontainer-related files:

  • .pnpm-store for pnpm cache directory
  • tsx-0/ for tsx temporary files
  • Well-organized with descriptive comment section

These changes align with the devcontainer setup mentioned in the broader PR changes.

apps/mail/lib/auth-client.ts (2)

10-10: Plugin instantiation updated correctly.

The change to use phoneNumberClient() in the plugins array is consistent with the import change and maintains the same function call pattern.


1-1:

Details

✅ Verification successful

LGTM! Verify server-side authentication consistency.

The import change from customSessionClient to phoneNumberClient aligns with the phone number verification feature addition.

Please verify that the server-side authentication configuration has been updated to use the corresponding phoneNumber plugin:


🏁 Script executed:

#!/bin/bash
# Description: Verify server-side auth plugin consistency
# Expected: Server should use phoneNumber plugin from better-auth/plugins

rg -A 5 -B 5 "phoneNumber.*plugin|better-auth/plugins" apps/server/

Length of output: 883


Server-side authentication plugin updated

The server now imports phoneNumber from better-auth/plugins in apps/server/src/lib/auth.ts, matching the client-side change. No further action required.

packages/tailwind-config/tsconfig.json (1)

2-2:

Details

✅ Verification successful

LGTM! Verify base config exists and consistency across configs.

The removal of .json extension follows modern TypeScript conventions and standardizes the extends path format.

Please verify that the base config exists and all TypeScript configs were updated consistently:


🏁 Script executed:

#!/bin/bash
# Description: Verify TypeScript config consistency across the monorepo
# Expected: All configs should use the same extends format and base config should exist

echo "=== Checking if base config exists ==="
fd "base.json" packages/tsconfig/ --type f

echo "=== Checking extends patterns in all tsconfig.json files ==="
fd "tsconfig.json" --type f -x cat {} \; -x echo "File: {}" \; | rg -A 1 -B 1 "extends.*@zero/tsconfig"

Length of output: 808


All TypeScript configs uniformly extend “@zero/tsconfig/base”

  • packages/tsconfig/base.json is present and accessible
  • Every tsconfig.json in the repo now uses the extension-free "@zero/tsconfig/base" format

No further action required—this change is consistent and ready to merge.

package.json (1)

21-23:

Details

✅ Verification successful

LGTM! Modern Docker CLI syntax adoption.

The update from docker-compose to docker compose follows current Docker best practices as the compose functionality is now integrated into the Docker CLI.

The commands maintain the same functionality:

  • docker:db:up: Starts database container in detached mode
  • docker:db:down: Stops and removes containers
  • docker:db:clean: Stops containers and removes volumes

Please verify that the team's Docker installations support the new syntax (Docker CLI v20.10+ required):


🌐 Web query:

What is the minimum Docker version required for "docker compose" command?

💡 Result:

The "docker compose" command (Compose V2) requires Docker Engine version 19.03 or higher as a minimum requirement. This version was introduced when Compose V2 was first released in 2020[8].

Docker Compose V2 is now integrated directly into the Docker CLI platform, replacing the older hyphenated "docker-compose" command (Compose V1)[8]. This newer version offers several advantages including improved CLI experience, better build performance with BuildKit, and ongoing feature development[8].

For those using Docker Desktop, Compose V2 is bundled with all currently supported versions, making it the easiest way to access the "docker compose" functionality[8][10]. Docker Desktop users can check which version of Compose they have by selecting "About Docker Desktop" from the Docker menu[10].

It's worth noting that Compose V1 (the "docker-compose" command) stopped receiving updates as of July 2023 and is no longer available in new releases of Docker Desktop[8]. The main syntactic difference between the two versions is that Compose V2 uses a space instead of a hyphen, so scripts should be updated to use "docker compose" rather than "docker-compose"[8].

For Linux users who already have Docker Engine and Docker CLI installed, the Docker Compose plugin can be installed separately from the command line[10]. The standalone version of Docker Compose is still available but is only supported for backward compatibility and is not recommended for new installations[10].

Citations:


Ensure Docker Engine ≥19.03 for “docker compose” Commands

The change to use the modern docker compose syntax aligns with Docker Compose V2 (integrated into the Docker CLI) and requires Docker Engine version 19.03 or higher. The behavior and flags remain identical:

  • docker:db:updocker compose -f docker-compose.db.yaml up -d
  • docker:db:downdocker compose -f docker-compose.db.yaml down
  • docker:db:cleandocker compose -f docker-compose.db.yaml down -v

Please confirm your team’s Docker installations meet the 19.03+ requirement (or are using Docker Desktop, which bundles Compose V2).

packages/eslint-config/tsconfig.json (2)

2-2: LGTM! Configuration centralization looks good.

The change from "@zero/tsconfig/base.json" to "@zero/tsconfig/base" follows Node.js module resolution conventions and aligns with the monorepo-wide TypeScript configuration centralization.


8-9:

Details

✅ Verification successful

Verify the broadened include pattern and simplified exclude.

The include pattern was changed from specific files to "**/*.ts" and exclude was simplified to only "node_modules". While this simplification is good for maintainability, ensure that:

  1. The glob pattern "**/*.ts" captures all necessary TypeScript files in this package
  2. Removing "dist" from exclude doesn't cause issues if build artifacts contain TypeScript files

🏁 Script executed:

#!/bin/bash
# Description: Verify TypeScript files in eslint-config package and check for dist directory usage

# Find all TypeScript files in the eslint-config package
echo "=== TypeScript files in eslint-config package ==="
fd -e ts . packages/eslint-config

# Check if dist directory exists and contains TypeScript files
echo "=== Checking for dist directory and TypeScript files in it ==="
if [ -d "packages/eslint-config/dist" ]; then
    echo "dist directory exists"
    fd -e ts . packages/eslint-config/dist
else
    echo "dist directory does not exist"
fi

# Check the base config file being extended
echo "=== Checking base config file ==="
if [ -f "packages/tsconfig/base.json" ]; then
    echo "Found packages/tsconfig/base.json"
    cat packages/tsconfig/base.json
elif [ -f "packages/tsconfig/base/index.json" ]; then
    echo "Found packages/tsconfig/base/index.json"
    cat packages/tsconfig/base/index.json
else
    echo "Base config not found in expected locations"
fi

Length of output: 1221


Include/Exclude Patterns Verified

  • The only .ts file in packages/eslint-config is config.ts, which is correctly picked up by "**/*.ts".
  • There is no dist/ directory in this package, so omitting it from exclude has no effect.

No changes required here.

apps/mail/lib/auth-proxy.ts (2)

18-18: Excellent improvement to error logging.

Adding the full session object to the error log provides much better debugging information for authentication issues. This will help track down session-related problems more effectively.


8-8:

Details

❓ Verification inconclusive

Verify that the empty plugins array is intentional.

The plugins array is now empty, which aligns with the authentication strategy migration mentioned in the summary. However, ensure that the phone number authentication functionality is properly configured elsewhere in the application.


🏁 Script executed:

#!/bin/bash
# Description: Verify phone number authentication configuration

# Search for phone number client configuration
echo "=== Searching for phoneNumberClient usage ==="
rg -A 5 -B 5 "phoneNumberClient" apps/mail

# Search for auth client configuration in other files
echo "=== Searching for authClient configuration ==="
rg -A 10 -B 5 "createAuthClient" apps/mail

# Check for phone number verification components
echo "=== Searching for phone verification components ==="
rg -A 5 "phone.*verify|verify.*phone|CallInboxDialog" apps/mail

Length of output: 5001


We’ve confirmed that the React client (apps/mail/lib/auth-client.ts) is correctly using phoneNumberClient(), while the server-side proxy (apps/mail/lib/auth-proxy.ts) deliberately omits all plugins—including the phone-number plugin. Verify that this is intentional, since any server-side endpoint using authProxy will not have phone number methods available unless the plugin is added.

Please check:

  • Any API routes or server handlers importing authProxy expect to call phone-number methods (e.g. .api.phoneNumber.verify).
  • If so, add phoneNumberClient() to the plugins array in auth-proxy.ts.
  • Otherwise, leave it empty to restrict the proxy to session methods only.
packages/cli/tsconfig.json (1)

2-2:

Details

✅ Verification successful

Verify that the base configuration is suitable for CLI package requirements.

The complete delegation to the base configuration promotes consistency and reduces maintenance overhead. However, CLI packages sometimes have specific requirements (like different target environments or module systems).


🏁 Script executed:

#!/bin/bash
# Description: Verify base configuration suitability for CLI package

# Check the base configuration
echo "=== Base TypeScript Configuration ==="
cat packages/tsconfig/base.json 2>/dev/null || cat packages/tsconfig/base/index.json 2>/dev/null || echo "Base config not found"

# Check CLI package structure for specific requirements
echo "=== CLI Package Structure ==="
fd -t f . packages/cli | head -20

# Look for CLI-specific build scripts or requirements
echo "=== CLI Package.json ==="
if [ -f "packages/cli/package.json" ]; then
    cat packages/cli/package.json | jq -r '.scripts, .bin, .main, .types'
fi

# Check for any executable files that might need specific compilation
echo "=== Executable files in CLI package ==="
fd -t f -x test -x {} + packages/cli | grep -E "#!/.*node" || echo "No shebang files found"

Length of output: 20207


Approve centralization: base config is suitable for CLI usage

The shared @zero/tsconfig/base already includes all necessary settings for a Node-based CLI (ESNext target, ESNext modules with bundler resolution, JSON modules, Node types, strict checks, etc.). The CLI package has no custom build scripts, shebang files, or overrides in its package.json, so no configuration was lost.

apps/server/src/trpc/routes/settings.ts (2)

4-4:

Details

✅ Verification successful

LGTM! Import path updated to use local database schema.

The import statement correctly points to the local database schema file, maintaining consistency with the package refactoring.

Let me verify that the schema file exists and exports the required userSettings:


🏁 Script executed:

#!/bin/bash
# Description: Verify that the local schema file exists and exports userSettings
# Expected: File exists and contains userSettings export

# Check if the target schema file exists
fd -t f "schema.ts" apps/server/src/db/

# Verify userSettings is exported from the schema file
ast-grep --pattern $'export const userSettings = $_'

Length of output: 799


Verified: local database schema export present

Confirmed that apps/server/src/db/schema.ts exists and exports userSettings as expected. The import statement:

import { userSettings } from '../../db/schema';

is correct.


1-1:

Details

✅ Verification successful

LGTM! Import path refactored to use local schemas.

The import statement correctly points to the new local schemas location, aligning with the migration away from the external @zero/db package.

Let me verify that the new import path resolves correctly:


🏁 Script executed:

#!/bin/bash
# Description: Verify that the local schemas file exists and exports the expected items
# Expected: File exists and contains the required exports

# Check if the target file exists
fd -t f "schemas.ts" apps/server/src/lib/

# Verify the exports are available in the schemas file
ast-grep --pattern $'export { $_ } from $_'
ast-grep --pattern $'export const defaultUserSettings = $_'
ast-grep --pattern $'export const userSettingsSchema = $_'
ast-grep --pattern $'export type UserSettings = $_'

Length of output: 1660


🏁 Script executed:

#!/bin/bash
# 1. List all import statements in the settings route
echo "Imports in apps/server/src/trpc/routes/settings.ts:"
rg '^import' -n apps/server/src/trpc/routes/settings.ts

# 2. Verify that apps/server/src/db/schema.ts exists
echo
echo "Checking for apps/server/src/db/schema.ts:"
fd -t f "schema.ts" apps/server/src/db

Length of output: 658


🏁 Script executed:

#!/bin/bash
# Verify that apps/server/src/db/schema.ts exports `userSettings`
rg -n "export .*userSettings" apps/server/src/db/schema.ts

Length of output: 123


Import paths verified and approved

  • Confirmed apps/server/src/lib/schemas.ts exists and exports defaultUserSettings, userSettingsSchema, and UserSettings.
  • Confirmed apps/server/src/db/schema.ts exists and exports userSettings.

LGTM! 🎉

.env.example (2)

25-25: LGTM! Added Perplexity API key for AI integration.

The environment variable addition supports the new Perplexity AI web search functionality mentioned in the AI summary.


34-36: LGTM! Added Twilio configuration for phone verification.

The Twilio environment variables correctly support the new phone number verification feature with proper naming conventions.

packages/tsconfig/package.json (1)

4-6: LGTM! Added explicit exports for better module resolution.

The exports field with explicit mapping to "./base.json" follows modern Node.js package standards and supports the centralized TypeScript configuration approach.

apps/server/src/db/schema.ts (3)

9-9: LGTM! Improved import organization.

Moving the unique import to be grouped with other imports from the same module improves code organization and readability.


11-11: LGTM! Import path refactored to use local schemas.

The import statement correctly points to the new local schemas location, maintaining consistency with the migration away from the external @zero/db package.


25-26:

Details

✅ Verification successful

LGTM! Well-designed phone verification schema additions.

The new fields support phone number verification functionality with appropriate constraints:

  • phoneNumber with unique constraint prevents duplicate registrations
  • phoneNumberVerified tracks verification status

Let me verify that the corresponding database migration exists:


🏁 Script executed:

#!/bin/bash
# Description: Verify that database migration exists for the new phone number fields
# Expected: Migration file exists with ALTER TABLE statements for phone_number fields

# Find recent migration files that might contain phone number changes
fd -t f -e sql . apps/server/src/db/migrations/ | head -10

# Look for migration files containing phone_number references
rg -l "phone_number" apps/server/src/db/migrations/

Length of output: 797


Migration Verified: SQL Migration Exists for Phone Number Fields

✔️ Found migration file apps/server/src/db/migrations/0027_vengeful_golden_guardian.sql containing phone_number and phone_number_verified alterations.

Everything looks good—approved!

apps/server/src/types.ts (1)

140-145: LGTM! Well-designed interface for bulk spam deletion response.

The interface properly defines required and optional fields with clear semantics:

  • Required success and message for essential response data
  • Optional count and error for additional context
  • Follows consistent naming conventions
apps/mail/app/root.tsx (2)

49-49: Good defensive programming with locale fallback.

Ensuring a fallback to 'en' prevents potential runtime issues with undefined/null locale values. This pairs well with the corresponding default in the Layout component.


56-56: Consistent locale handling with proper fallback.

The destructuring default complements the loader fallback, ensuring the Layout component always receives a valid locale value. This defensive approach prevents potential runtime issues.

apps/server/tsconfig.json (1)

2-3: LGTM! Good monorepo standardization.

The migration to a shared TypeScript base configuration is excellent for maintaining consistency across the project. The inclusion of "src/overrides.d.ts" and "drizzle.config.ts" aligns well with the other infrastructure changes in this PR.

pnpm-workspace.yaml (2)

18-24: LGTM! Proper use of onlyBuiltDependencies.

The onlyBuiltDependencies configuration is correctly used for packages that require native compilation (esbuild, sharp, workerd, etc.). This will help ensure consistent builds across different environments.


15-17:

Details

✅ Verification successful

Verify the package versions are compatible.

The new Drizzle packages (drizzle-orm: 0.43.1, drizzle-kit: 0.31.1) and Node types (@types/node: 22.15.21) should be verified for compatibility with your current setup.


🏁 Script executed:

#!/bin/bash
# Description: Check if the specified package versions exist and are compatible
# Expected: All versions should be available on npm registry

echo "Checking drizzle-orm@0.43.1..."
npm view drizzle-orm@0.43.1 version

echo "Checking drizzle-kit@0.31.1..."
npm view drizzle-kit@0.31.1 version

echo "Checking @types/node@22.15.21..."
npm view @types/node@22.15.21 version

Length of output: 355


Package version verification passed

All specified versions (drizzle-orm@0.43.1, drizzle-kit@0.31.1, @types/node@22.15.21) exist on the npm registry. Approving the workspace configuration updates.

apps/server/drizzle.config.ts (1)

10-10: LGTM! Appropriate table filtering.

The tablesFilter: ['mail0_*'] is a good practice to scope migrations to specific tables, preventing accidental operations on unrelated database objects.

apps/mail/types/index.ts (1)

109-109: LGTM! historyId addition aligns with mail driver updates.

The optional historyId property in ThreadProps.message correctly supports the enhanced thread synchronization mentioned in the summary. The nullable type (string | null) appropriately handles cases where historyId might not be available.

apps/mail/tsconfig.json (1)

2-2:

Details

✅ Verification successful

Verify that the base TypeScript configuration exists and is properly maintained.

This refactoring to extend from a centralized base configuration is a good practice for reducing duplication and improving maintainability across the monorepo.

Please run the following script to verify the base configuration exists and contains the expected compiler options:


🏁 Script executed:

#!/bin/bash
# Description: Verify the base TypeScript configuration exists and contains expected options

# Check if the base config file exists
fd "tsconfig" packages/tsconfig/ --type f

# If found, display its contents to verify it contains the removed options
if [ -f "packages/tsconfig/base.json" ]; then
  echo "=== Base TypeScript Configuration ==="
  cat packages/tsconfig/base.json
else
  echo "Base configuration not found at expected location"
  # Search for alternative locations
  fd "base" --type f --extension json | head -10
fi

Length of output: 771


Base TypeScript configuration verified

The shared config at packages/tsconfig/base.json exists and defines all of the removed compilerOptions (target, lib, strict, module, moduleResolution, etc.). The app-specific tsconfig retains only its own paths, rootDirs, include/exclude and overrides. This centralization is correct—no further changes needed.

apps/mail/lib/email-utils.client.tsx (2)

4-4: Verify import change aligns with usage.

The import changed from @react-email/render to react-dom/server, which suggests a shift from React Email's optimized rendering to standard React SSR.


265-267:

Details

❓ Verification inconclusive

Verify email rendering functionality after switching from React Email to React SSR.

This change switches from React Email's render function to React's renderToString. While both produce HTML, they may have different optimizations and output formats specifically designed for email clients.

Please run the following script to verify the email rendering still works correctly:

Consider testing email output in various email clients to ensure the switch from React Email's optimized rendering doesn't introduce compatibility issues.


🏁 Script executed:

#!/bin/bash
# Description: Search for tests or usage of the template function to ensure compatibility

# Search for tests related to email template rendering
rg -A 10 -B 5 "template.*function|renderToString" --type ts --type tsx

# Look for any existing email rendering tests
fd "test" --type f | xargs rg -l "email.*template|template.*email" 2>/dev/null || echo "No email template tests found"

# Check if there are any other imports of @react-email/render that might need updating
rg "@react-email/render" --type ts --type tsx

Length of output: 283


Verify EmailTemplate Rendering After SSR Migration

We’ve replaced React Email’s render with React’s renderToString in
apps/mail/lib/email-utils.client.tsx (around lines 265–267). No automated tests currently cover this change, so please:

  • Add unit/snapshot tests for the updated EmailTemplate output.
  • Remove any leftover @react-email/render imports.
  • Manually send sample emails (or render the HTML) in your target clients to confirm rendering hasn’t regressed.
README.md (1)

92-126: Excellent comprehensive devcontainer setup documentation.

The devcontainer setup instructions are well-structured and provide clear step-by-step guidance that mirrors the standard setup approach. This will help developers get started quickly with a consistent development environment.

🧰 Tools
🪛 LanguageTool

[grammar] ~116-~116: The word “setup” is a noun. The verb is spelled with a white space.
Context: ...ronment** - Run pnpm nizzy env to setup your environment variables - Run `pn...

(NOUN_VERB_CONFUSION)

🪛 markdownlint-cli2 (0.17.2)

107-107: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

apps/server/src/lib/driver/microsoft.ts (3)

308-308: Good implementation of historyId for API consistency.

Using lastModifiedDateTime as the historyId source makes sense for tracking message changes. The nullish coalescing operator properly handles cases where this property might not be available.


623-623: Appropriate historyId handling for drafts.

Setting historyId to null for drafts is appropriate since draft messages typically don't have the same history tracking as regular messages.


306-313:

Details

✅ Verification successful

Verify historyId property usage across the codebase.

The addition of historyId to thread objects aligns with the broader effort to standardize mail provider APIs. Ensure that consuming code properly handles this new property.

Also applies to: 621-626


🏁 Script executed:

#!/bin/bash
# Description: Verify historyId usage and type definitions across the codebase

# Check if historyId is defined in types
rg -A 5 -B 5 "historyId" apps/server/src/lib/driver/types.ts

# Look for usage of historyId in hooks or components
rg "historyId" apps/mail/hooks/ apps/mail/components/ --type ts --type tsx

# Check Google driver for similar implementation
rg -A 3 -B 3 "historyId" apps/server/src/lib/driver/google.ts

Length of output: 1518


HistoryId Property Usage Verified

All instances of the new historyId field are consistently defined and handled:

• In apps/server/src/lib/driver/types.ts, both list and listDrafts threads include historyId: string | null.
• The Google driver (apps/server/src/lib/driver/google.ts) maps historyId in both message and draft threads exactly as in Microsoft.
• No existing mail hooks or components reference historyId, so no downstream breakages are expected.

No further changes are required.

packages/eslint-config/config.ts (1)

1-1: ⚠️ Potential issue

Fix the ESLint import statement.

The import from 'eslint/config' is incorrect for modern ESLint flat config. The defineConfig and globalIgnores are not exported from this path.

Apply this fix:

-import { defineConfig, globalIgnores } from 'eslint/config';
+// Remove defineConfig import as it's not needed for flat config
+// globalIgnores can be used directly as an array

And update the export:

-export default defineConfig([
-  globalIgnores([
+export default [
+  {
+    ignores: [
     '**/node_modules/**',
     '**/dist/**',
     '**/build/**',
     '**/.react-router/**',
     '**/.well-known/**',
-  ]),
+    ]
+  },

Likely an incorrect or invalid review comment.

apps/mail/locales/en.json (1)

52-59: Well-structured localization for bulk spam deletion feature.

The new localization strings comprehensively cover the bulk spam deletion feature with:

  • Clear action labels and status messages
  • Proper plural formatting for count display
  • Confirmation dialogs for destructive actions
  • Consistent error handling messages

The implementation follows existing naming conventions and provides good user experience.

apps/server/src/overrides.d.ts (1)

1-8: Proper TypeScript declarations for Cloudflare Durable Object bindings.

The type declarations correctly define the environment interface for Cloudflare Workers with:

  • Proper namespace structure
  • Correct extension of the Fetcher type for Durable Object bindings
  • Well-typed async methods for subscription management
  • Clear parameter and return type definitions

This aligns with the new Durable Object functionality mentioned in the PR summary.

apps/server/src/lib/services.ts (1)

12-54: Well-implemented Twilio SMS service with good development experience.

The implementation provides excellent features:

  • Mock mode for development with clear logging
  • Comprehensive environment variable validation
  • Proper error handling with meaningful messages
  • Clean API interface matching Twilio's structure
apps/mail/components/ui/input-otp.tsx (4)

1-1: Good addition of 'use client' directive.

Properly marks this as a client component for Next.js, which is necessary for interactive OTP input functionality.


4-4: Appropriate icon change for OTP separator.

The change from Minus to Dot icon better represents the visual separator between OTP input groups.


44-45: Enhanced styling improves user experience.

The size increase from h-9 w-9 to h-10 w-10, removal of shadow, and improved ring styling for active slots provide better visual feedback and touch targets.


66-66: Consistent icon usage in separator.

Using the Dot icon here maintains consistency with the import change and provides a cleaner visual separator.

apps/server/src/lib/auth.ts (3)

8-8: Good refactoring to relative imports.

The migration from absolute to relative import paths improves maintainability and aligns with best practices for modular code organization.

Also applies to: 10-10, 14-14, 17-17, 23-23


82-82: Proper Twilio client initialization.

Creating the Twilio client instance using the service factory function follows the established pattern and supports both development and production environments.


85-98: Well-implemented phone number verification with proper error handling.

The phoneNumber plugin integration is correctly configured with:

  • Proper async OTP sending via Twilio
  • Comprehensive error handling with logging
  • Appropriate APIError responses for client feedback
  • Security-conscious message format

The implementation aligns well with the Twilio service from the relevant code snippets.

Consider adding rate limiting for OTP requests to prevent abuse:

 phoneNumber({
+  rateLimit: {
+    window: 60, // 1 minute
+    max: 3, // max 3 OTP requests per minute
+  },
   sendOTP: async ({ code, phoneNumber }) => {
apps/mail/hooks/use-threads.ts (3)

2-2: Appropriate imports for enhanced functionality.

Adding useQueryClient and usePrevious hook imports supports the new history tracking functionality without introducing unnecessary dependencies.

Also applies to: 7-8


62-62: Good API extension for history tracking.

Adding the optional historyId parameter maintains backward compatibility while enabling message history change detection for cache invalidation.


68-74: Excellent cache invalidation strategy.

The implementation correctly:

  • Uses usePrevious to detect historyId changes
  • Only invalidates when there's an actual change (not on initial render)
  • Targets the specific thread query for efficient cache management
  • Properly handles null/undefined values

This ensures the UI stays synchronized with message history updates while avoiding unnecessary refetches.

apps/mail/vite.config.ts (1)

42-46:

Details

✅ Verification successful

Verify SSR optimization dependencies exist.

The SSR optimization explicitly includes novel and @tiptap/extension-placeholder. Ensure these dependencies are actually used in SSR context and require optimization.


🏁 Script executed:

#!/bin/bash
# Description: Verify that the specified SSR optimization dependencies exist and are used
# Expected: Find imports/usage of these packages in the codebase

echo "Checking for 'novel' package usage:"
rg -r --type ts --type tsx "import.*novel" || echo "No novel imports found"

echo -e "\nChecking for '@tiptap/extension-placeholder' package usage:"
rg -r --type ts --type tsx "import.*@tiptap/extension-placeholder" || echo "No @tiptap/extension-placeholder imports found"

echo -e "\nChecking package.json dependencies:"
if [ -f "package.json" ]; then
  jq -r '.dependencies | keys[] | select(test("novel|@tiptap"))' package.json || echo "Dependencies not found in package.json"
fi

Length of output: 889


Let’s broaden the search to catch any import or require patterns and also look in devDependencies:


🏁 Script executed:

#!/bin/bash

echo "🔍 Searching for 'novel' import or require:"
rg "import .* from ['\"]novel['\"]" || rg "require\(['\"]novel['\"]\)" || echo "No 'novel' usage found"

echo -e "\n🔍 Searching for '@tiptap/extension-placeholder' import or require:"
rg "import .* from ['\"]@tiptap/extension-placeholder['\"]" || rg "require\(['\"]@tiptap/extension-placeholder['\"]\)" || echo "No '@tiptap/extension-placeholder' usage found"

echo -e "\n📦 Checking package.json for these deps in dependencies and devDependencies:"
jq -r '.dependencies, .devDependencies 
  | select(type == "object") 
  | keys[] 
  | select(test("novel|@tiptap/extension-placeholder"))' package.json \
  || echo "No matching entries in package.json"

Length of output: 2147


Let’s verify whether the apps/mail folder has its own package.json and declares these dependencies:


🏁 Script executed:

#!/bin/bash

echo "🔍 Searching for package.json under apps/mail:"
find apps/mail -maxdepth 2 -type f -name package.json || echo "No package.json found in apps/mail"

if [ -f apps/mail/package.json ]; then
  echo -e "\n📦 Checking apps/mail/package.json for ‘novel’ and ‘@tiptap/extension-placeholder’:"
  jq -r '
    .dependencies, .devDependencies
    | select(type == "object")
    | keys[]
    | select(test("^(novel|@tiptap/extension-placeholder)$"))
  ' apps/mail/package.json \
  || echo "No matching entries in apps/mail/package.json"
fi

Length of output: 615


SSR optimizeDeps verification ✅
Both novel and @tiptap/extension-placeholder are indeed used in the SSR code under apps/mail and declared in apps/mail/package.json, so the ssr.optimizeDeps.include list is correct.

apps/server/package.json (2)

9-13: Database management scripts look good.

The new drizzle-kit scripts provide comprehensive database management capabilities including migrations, schema pushing, and studio access.


18-19:

Details

✅ Verification successful

Verify new exports are used by consumers.

The new exports, especially "./schemas", will affect packages that import from this server package.


🏁 Script executed:

#!/bin/bash
# Description: Check if the new exports are used by other packages
# Expected: Find imports of these new exports

echo "Checking for imports of server schemas:"
rg -r --type ts --type tsx "from ['\"]@zero/server/schemas['\"]" || echo "No schema imports found"

echo -e "\nChecking for imports of auth-providers:"
rg -r --type ts --type tsx "from ['\"]@zero/server/auth-providers['\"]" || echo "No auth-providers imports found"

Length of output: 518


I noticed the initial rg calls failed due to an unrecognized tsx type. Let’s broaden the search across TS/TSX/JS/JSX files:


🏁 Script executed:

#!/bin/bash
# Search for any references to the new exports in all TS/TSX/JS/JSX files

echo "Searching for @zero/server/schemas usage..."
rg "@zero/server/schemas" -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' || echo "No schema imports found"

echo -e "\nSearching for @zero/server/auth-providers usage..."
rg "@zero/server/auth-providers" -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' || echo "No auth-providers imports found"

Length of output: 914


Verified new exports are consumed
File: apps/server/package.json Lines: 18–19

I searched for imports of @zero/server/schemas and @zero/server/auth-providers and confirmed they’re used in:

  • apps/mail/components/mail/mail-iframe.tsx
  • apps/mail/app/(routes)/settings/general/page.tsx
  • apps/mail/app/(routes)/settings/privacy/page.tsx
  • apps/mail/app/(auth)/login/page.tsx
  • apps/mail/app/(auth)/login/login-client.tsx

No further action required.

apps/mail/components/magicui/file-tree.tsx (2)

272-272: Good addition of max-width constraint.

The max-w-[124px] class helps prevent folder labels from overflowing, improving the UI layout consistency.


291-299: Improved JSX structure for count badge.

The refactored count badge rendering with explicit JSX structure is cleaner and more readable than the previous inline approach.

apps/server/wrangler.jsonc (1)

24-31: Well-structured Durable Objects configuration.

The addition of ZERO_AGENT and ZERO_MCP Durable Objects is correctly implemented:

  • Consistent bindings across all environments (local, staging, production)
  • Proper migration versioning with v2 tag
  • Appropriate use of new_sqlite_classes for SQLite-backed Durable Objects

The configuration follows Cloudflare Workers best practices.

Also applies to: 43-46, 108-115, 127-130, 199-206, 218-221

apps/server/src/trpc/routes/ai/compose.ts (3)

53-79: Improved message construction clarity.

The refactored message construction is much clearer and more maintainable than the previous conditional spreading approach. The explicit conversation flow with assistant acknowledgments provides better context for the AI model.


82-82: Verify model downgrade impact on email quality.

The change from gpt-4o to gpt-4o-mini may impact email composition quality. Ensure this change aligns with performance requirements and acceptable quality standards.

Consider testing both models to compare output quality for your email composition use case, especially for complex or professional emails.


94-95: Enhanced AI capabilities with appropriate limits.

Good additions:

  • maxSteps: 10 provides reasonable limit for tool usage
  • Increased maxTokens: 2000 allows for more comprehensive email generation
  • webSearch tool integration enables more informed email composition

Also applies to: 100-102

apps/mail/components/context/thread-context.tsx (2)

81-92: Excellent UX improvement with toast.promise pattern.

The refactoring from direct async/await to toast.promise provides better user feedback:

  • Automatic loading states
  • Consistent error handling
  • Proper cleanup in finally callback
  • Better user experience during label modifications

217-225: Consistent toast.promise implementation for favorites.

The favorites handling follows the same improved pattern:

  • Consistent error messaging based on current state
  • Proper cleanup of bulk selection state
  • Reliable data refetching after operations

This maintains consistency with the label modification pattern.

apps/server/src/main.ts (5)

3-3: LGTM on the new imports

The import of ZeroAgent and ZeroMCP from ./routes/chat is correctly structured and aligns with the new MCP functionality being introduced.


6-6: LGTM on the middleware import

The agentsMiddleware import from hono-agents is properly added to support the new agent functionality.


14-14: LGTM on the local DB import

The change from @zero/db to the local ./db module is consistent with the removal of the external package mentioned in the AI summary.


152-152: LGTM on the updated exports

The addition of ZeroAgent and ZeroMCP to the exports is correct and necessary for external usage of these classes.


100-111:

Details

❓ Verification inconclusive

Validate the middleware placement and error handling

The global agentsMiddleware is applied after the mount points, which means it won't affect the /sse and /mcp routes. This might be intentional, but consider if the cookie validation should be consistent across all agent-related endpoints.

Let me verify how this middleware interacts with the existing routes:


🏁 Script executed:

#!/bin/bash
# Description: Check for other agent-related routes and middleware usage patterns
# Expected: Find other routes that might need consistent authentication

# Search for agent-related route patterns
rg -A 3 -B 3 "agent|Agent" --type ts

# Look for other middleware usage patterns
rg -A 5 -B 2 "middleware|Middleware" --type ts

Length of output: 23753


🏁 Script executed:

#!/bin/bash
# Dump the first 200 lines of main.ts to inspect route and middleware order
sed -n '1,200p' apps/server/src/main.ts

Length of output: 4740


Confirm cookie validation coverage for all agent endpoints

The agentsMiddleware is registered after the /sse and /mcp mounts, so those routes currently bypass its cookie-based check (they use the Authorization header instead). Please verify whether you want to:

  • Enforce the same cookie validation on /sse and /mcp
    • Move the .use('*', agentsMiddleware(...)) call above the .mount('/sse') and .mount('/mcp') lines
    • Or explicitly wrap those mounts with agentsMiddleware
  • Or keep the separation (bearer-token auth for SSE/MCP vs. cookie check for other agent routes) and add a comment to clarify the intended behavior

[src/apps/server/src/main.ts lines ~30–60]

apps/server/src/lib/schemas.ts (1)

37-46: ⚠️ Potential issue

Fix circular reference in default settings definition

The defaultUserSettings object uses satisfies UserSettings but UserSettings is defined after this object, creating a forward reference issue. Additionally, some default values don't align with the schema's optional fields.

Move the type definition before the default object and fix the alignment:

+export const userSettingsSchema = z.object({
+  language: z.string(),
+  timezone: z.string(),
+  dynamicContent: z.boolean().optional(),
+  externalImages: z.boolean(),
+  customPrompt: z.string(),
+  isOnboarded: z.boolean().optional(),
+  trustedSenders: z.string().array().optional(),
+  colorTheme: z.enum(['light', 'dark', 'system']).default('system'),
+});
+
+export type UserSettings = z.infer<typeof userSettingsSchema>;

export const defaultUserSettings = {
  language: 'en',
  timezone: 'UTC',
  dynamicContent: false,
  externalImages: true,
  customPrompt: '',
  trustedSenders: [],
  isOnboarded: false,
  colorTheme: 'system',
} satisfies UserSettings;

-export const userSettingsSchema = z.object({
-  language: z.string(),
-  timezone: z.string(),
-  dynamicContent: z.boolean().optional(),
-  externalImages: z.boolean(),
-  customPrompt: z.string(),
-  isOnboarded: z.boolean().optional(),
-  trustedSenders: z.string().array().optional(),
-  colorTheme: z.enum(['light', 'dark', 'system']).default('system'),
-});
-
-export type UserSettings = z.infer<typeof userSettingsSchema>;

Likely an incorrect or invalid review comment.

apps/server/src/lib/driver/types.ts (3)

1-3: LGTM on the updated imports

The imports correctly include the new DeleteAllSpamResponse type and updated schema path. The type imports are properly structured.


92-92: LGTM on the deleteAllSpam method addition

The new deleteAllSpam() method is properly typed with the DeleteAllSpamResponse interface. This enhances the mail management capabilities by providing bulk spam deletion functionality.


49-49:

Details

✅ Verification successful

Verify historyId implementation across all mail drivers

The addition of historyId: string | null to thread objects is a good enhancement for tracking changes, but we should ensure all implementing drivers properly handle this field.

Let me check if all mail drivers implement the historyId field correctly:

Also applies to: 60-62


🏁 Script executed:

#!/bin/bash
# Description: Verify historyId implementation in mail drivers
# Expected: Find implementations in google.ts and microsoft.ts that properly set historyId

# Search for historyId usage in driver implementations
rg -A 5 -B 2 "historyId" apps/server/src/lib/driver/

# Check list and listDrafts method implementations
ast-grep --pattern $'list($$$) {
  $$$
}'

ast-grep --pattern $'listDrafts($$$) {
  $$$
}'

Length of output: 3499


Verified historyId handling in all mail drivers

Both Google and Microsoft drivers assign the historyId field in accordance with the new type:

  • google.ts

    • In list: uses thread.historyId ?? null
    • In listDrafts: uses draft.threadId ?? null
  • microsoft.ts

    • In list: uses msg.lastModifiedDateTime ?? null
    • In listDrafts: deliberately sets historyId: null (no draft history tracking)

No further changes are needed.

apps/mail/components/create/extensions.ts (2)

18-18: LGTM on UploadImagesPlugin import retention

Good decision to keep the UploadImagesPlugin from the novel package as image uploading is essential functionality for an email composer.


31-49: LGTM on the custom ExitLinkOnSpace extension

The custom extension implementation is well-structured and addresses a common UX issue where users want to exit link editing mode by pressing space. The logic correctly inserts a space and then unsets the link mark.

packages/tsconfig/base.json (1)

4-5:

Details

❓ Verification inconclusive

Verify compatibility with deployment environments and tooling.

The configuration uses modern TypeScript features that may have compatibility requirements:

  • ESNext target may not be supported in all runtime environments
  • moduleResolution: "Bundler" requires TypeScript 5.0+
  • allowImportingTsExtensions is a newer feature

Please ensure all deployment targets and build tools support these settings.

Run the following script to check TypeScript version compatibility:

Also applies to: 12-13, 19-20


🏁 Script executed:

#!/bin/bash
# Description: Verify TypeScript version across the monorepo

# Check TypeScript version in package.json files
echo "Checking TypeScript versions in package.json files:"
fd package.json --exec jq -r 'select(.devDependencies.typescript or .dependencies.typescript) | "\(.name): typescript@\(.devDependencies.typescript // .dependencies.typescript)"' 2>/dev/null || echo "No TypeScript dependencies found"

# Check for TypeScript version in root package.json
if [ -f package.json ]; then
  echo -e "\nRoot package.json TypeScript version:"
  jq -r '.devDependencies.typescript // .dependencies.typescript // "Not found"' package.json
fi

Length of output: 605


🏁 Script executed:

#!/bin/bash
# Search for lockfiles and inspect TypeScript version entries
lockfiles=(pnpm-lock.yaml package-lock.json yarn.lock)

for file in "${lockfiles[@]}"; do
  if [ -f "$file" ]; then
    echo "---- $file ----"
    # Look for the version line or package key for typescript
    grep -R -n "typescript@" "$file" || echo "No TypeScript entry found in $file"
    echo
  fi
done

Length of output: 7444


ESNext & Bundler Resolution Compatibility Confirmed

  • Monorepo is using TypeScript 5.8.3 (from pnpm-lock.yaml), so moduleResolution: "Bundler" (introduced in TS 5.0) is supported.
  • allowImportingTsExtensions remains valid and noEmit: true is already set.

Remaining action:
• Please confirm that your deployment targets or your build pipeline will correctly handle target: "ESNext" (either by down-level transpiling or by running on environments that natively support the latest ECMAScript features).

apps/mail/components/ui/recursive-folder.tsx (1)

11-19: Great type safety improvements!

The change from any to Label & { originalLabel?: Label } improves type safety and makes the component's expectations clearer.

apps/mail/components/ui/ai-sidebar.tsx (1)

382-451: Clean migration to agent-based chat architecture!

The refactoring successfully migrates from the previous useChat hook to the new agent-based system while preserving all existing functionality including error handling, response processing, and tool calls.

packages/eslint-config/package.json (2)

9-14: Clean dependency consolidation with typescript-eslint

Good job consolidating to typescript-eslint v8.32.1! This is the recommended approach as it bundles both the parser and plugin. The removal of separate @typescript-eslint/eslint-plugin and @typescript-eslint/parser packages aligns with the latest best practices.


5-7:

Details

✅ Verification successful

Good modernization with the exports field!

The migration from "main" to "exports" is a good practice for modern Node.js packages. However, ensure that all consumers of this package can handle TypeScript files directly, as you're exporting config.ts instead of a compiled JavaScript file.

Run the following script to verify that all consumers are properly configured to handle TypeScript imports:


🏁 Script executed:

#!/bin/bash
# Description: Check if consumers of @zero/eslint-config have TypeScript configured

# Find all package.json files that depend on @zero/eslint-config
fd package.json --exec grep -l "@zero/eslint-config" {} \; | while read -r file; do
  dir=$(dirname "$file")
  echo "Checking $dir for TypeScript configuration..."
  
  # Check if tsconfig.json exists
  if [ -f "$dir/tsconfig.json" ]; then
    echo "✓ TypeScript configured in $dir"
  else
    echo "⚠ No tsconfig.json found in $dir"
  fi
  
  # Check if the ESLint config file exists and can import TypeScript
  if fd -e ts -e js "eslint.config" . "$dir" --max-depth 1 | grep -q .; then
    echo "✓ ESLint config file found"
  else
    echo "⚠ No ESLint config file found"
  fi
done

Length of output: 1534


All consumers support TypeScript imports—no further action needed

I’ve verified that both apps/server and apps/mail include a tsconfig.json and have ESLint config files capable of importing TypeScript. Since all consumers of @zero/eslint-config can handle .ts exports, keeping "./config.ts" under the exports field is safe.

apps/mail/lib/label-colors.ts (1)

39-45: Type-safe color validation implementation

The validation function correctly checks both backgroundColor and textColor properties. Good use of Array.some() for efficient searching.

apps/mail/components/mail/mail-display.tsx (1)

965-987: Clean print button UI implementation

Good placement of the print button next to the email date, with proper keyboard shortcut indicator and responsive design.

apps/mail/components/ui/nav-main.tsx (3)

194-199: Improved user feedback with toast notifications

Good improvement to the user experience with more descriptive toast messages for label creation states.


243-255: Excellent refactoring with LabelDialog component!

Great job extracting the inline label creation form into a reusable LabelDialog component. This improves:

  • Code maintainability
  • Separation of concerns
  • Reusability across the application

259-263: Clean delegation to SidebarLabels component

Good modularization by delegating label rendering to the dedicated SidebarLabels component. This makes the nav component more focused and easier to maintain.

apps/mail/components/labels/label-dialog.tsx (1)

129-149: LGTM!

The color selection implementation is well-structured with proper visual feedback for hover and selected states. Good use of conditional styling and form value updates.

apps/mail/package.json (1)

121-125: LGTM!

The ESLint configuration changes properly support the centralization effort. The addition of jiti enables TypeScript config files for ESLint.

apps/server/src/routes/agent/tools.ts (1)

554-572: LGTM!

The explicit return statement improves readability for the multi-line object. All tools are properly mapped including the new webSearch tool.

apps/server/src/lib/prompts.ts (2)

155-173: LGTM!

The tool usage section provides clear, actionable instructions for the webSearch tool. The rules ensure natural integration of search results without exposing the underlying mechanics to users.


208-230: LGTM!

The output format and strict guidelines are comprehensive and well-structured. Excellent security considerations preventing exposure of internal metrics and tool invocations.

apps/server/src/lib/driver/google-label-color-map.ts (1)

49-60: LGTM!

The color mapping function correctly validates input and handles edge cases appropriately.

apps/mail/app/(routes)/settings/labels/page.tsx (2)

52-63: LGTM!

The unified submit handler correctly handles both create and update operations with appropriate user feedback.


87-102: Well-structured dialog implementation!

The LabelDialog integration properly manages state, resets the editing label on close, and provides all necessary callbacks. Good separation of concerns.

apps/mail/components/ui/sidebar-labels.tsx (3)

28-36: LGTM!

The memoized callback correctly handles label count retrieval with appropriate case-insensitive matching.


62-74: LGTM!

The label categorization logic correctly groups labels using appropriate regex patterns.


127-127: LGTM!

The bracket removal correctly strips both opening and closing brackets from label names.

apps/mail/components/ui/app-sidebar.tsx (3)

54-59: LGTM!

The phone number validation correctly enforces E.164 format with a helpful error message.


66-77: Robust phone number masking implementation!

The function properly handles edge cases and includes error handling to prevent crashes.


280-280: Verify if the phone verification dialog should be enabled.

The conditional rendering of CallInboxDialog is commented out. Please confirm if this is intentional for this release or if it should be enabled.

Is the phone verification feature ready for production, or is this commented out for a phased rollout?

apps/server/src/lib/driver/google.ts (4)

11-11: LGTM! Good centralization of color mapping logic.

Moving label color handling to dedicated mapping functions improves maintainability and consistency.


197-204: Correct implementation of historyId tracking.

The addition of historyId to thread objects with proper null fallback enables history-based synchronization as intended.


586-637: Consistent and correct bidirectional color mapping implementation.

The color mapping is properly applied:

  • mapGoogleLabelColor for data coming from Google API (getUserLabels, getLabel)
  • mapToGoogleLabelColor for data going to Google API (createLabel, updateLabel)

This ensures consistent color representation across the application.


661-703:

Details

✅ Verification successful

Well-implemented bulk spam deletion with proper pagination.

The method correctly handles large volumes of spam emails. However, I notice it removes both 'SPAM' and 'INBOX' labels on line 684.

Spam emails typically shouldn't have the INBOX label. Let's verify if this is necessary:


🏁 Script executed:

#!/bin/bash
# Check if there are other places where SPAM and INBOX labels coexist
rg -B 3 -A 3 "SPAM.*INBOX|INBOX.*SPAM" --type ts

# Look for Gmail API documentation or comments about spam label behavior
rg -i "spam.*label|label.*spam" --type ts -g "*.ts" -g "*.md"

Length of output: 3094


No changes needed for INBOX label removal

The removal of ‘INBOX’ alongside ‘SPAM’ is simply a harmless, defensive step to ensure threads are fully moved into Trash. Spam threads rarely retain the ‘INBOX’ label, so the removeLabels call is a no-op when it’s absent and has no unintended side effects.

apps/server/src/routes/agent/utils.ts (2)

10-14: LGTM! Appropriate relocation of the APPROVAL constant.

Moving the constant to where it's primarily used improves code organization.


119-129: Correctly identifies tools requiring user confirmation.

The function properly filters tools that lack automatic execution capabilities, which aligns with the confirmation workflow.

apps/mail/components/mail/mail-list.tsx (2)

87-91: Correct integration with historyId tracking.

The useThread hook now properly accepts the historyId parameter, enabling cache invalidation when thread history changes.


447-452: Improved label rendering with proper conditionals.

The replacement of MailLabels with RenderLabels and the conditional rendering logic improve the UI consistency.

apps/server/src/routes/chat.ts (1)

455-471: LGTM! Well-structured tool implementation.

The buildGmailSearchQuery tool is well-implemented using generateObject for structured output and proper schema validation. The integration with the AI model and prompt system is clean.

apps/server/src/db/migrations/meta/0027_snapshot.json (5)

568-598: Well-designed phone verification schema.

The addition of phone_number and phone_number_verified fields with proper unique constraints supports the new phone verification feature. The unique constraint on phone_number ensures data integrity.


355-357: Appropriate use of cascade delete for notes.

The onDelete: "cascade" for the note-to-user foreign key relationship is correctly configured, ensuring that user notes are automatically cleaned up when a user is deleted.


812-814: Appropriate use of cascade delete for writing style matrix.

The cascade delete for writing style matrix ensures data consistency when connections are removed, which is the correct behavior for this derived data.


206-214: Well-designed unique constraint for connections.

The unique constraint on user_id and email in the connection table properly prevents duplicate connections for the same user-email combination while allowing multiple users to connect the same email account.


671-677:

Details

✅ Verification successful

Validate default settings JSON structure.

The default JSONB value for user settings contains a comprehensive configuration. Ensure this aligns with the application's userSettingsSchema.


🏁 Script executed:

#!/bin/bash
# Description: Check if the default settings JSON matches the application schema
rg -A 10 -B 5 "userSettingsSchema|defaultUserSettings" --type ts

Length of output: 21897


Default settings JSON aligns with application schema

The JSONB default in apps/server/src/db/migrations/meta/0027_snapshot.json exactly matches the defaultUserSettings object and satisfies the userSettingsSchema in apps/server/src/lib/schemas.ts. No changes required.

Comment on lines +1 to +200
// import {
// command,
// string as stringType,
// number as numberType,
// flag,
// oneOf,
// option,
// boolean,
// subcommands,
// optional,
// } from 'cmd-ts';
// import { input, select, confirm, number as numberPrompt } from '@inquirer/prompts';
// import { updateWritingStyleMatrix } from '../services/writing-style-service';
// import professionalEmails from './styles/professional_emails.json';
// import persuasiveEmails from './styles/persuasive_emails.json';
// import friendlyEmails from './styles/friendly_emails.json';
// import conciseEmails from './styles/concise_emails.json';
// import { writingStyleMatrix } from '@zero/db/schema';
// import genZEmails from './styles/genz_emails.json';
// import { keys, take } from 'remeda';
// import { eq } from 'drizzle-orm';
// import { db } from '@zero/db';
// import pRetry from 'p-retry';
// import pAll from 'p-all';

// const mapping = {
// professional: professionalEmails,
// persuasive: persuasiveEmails,
// genz: genZEmails,
// concise: conciseEmails,
// friendly: friendlyEmails,
// } as const;

// const runSeeder = async (connectionId: string, style: keyof typeof mapping, size: number) => {
// console.warn(
// 'Seeding style matrix for connection',
// connectionId,
// 'based on',
// size,
// 'mock emails.',
// );

// const testDataSet = take(mapping[style], size);

// await pAll(
// testDataSet.map((email, index) => async () => {
// console.warn('Seeding email', index);
// await pRetry(
// async () => {
// try {
// await updateWritingStyleMatrix(connectionId, email.body);
// } catch (error) {
// console.error(error);

// throw error;
// }
// },
// {
// retries: 5,
// maxTimeout: 60_000,
// minTimeout: 1_000,
// },
// );
// }),
// { concurrency: 1 },
// );

// console.warn('Seeded style matrix for connection', connectionId);
// };

// const runResetStyleMatrix = async (connectionId: string) => {
// await db.delete(writingStyleMatrix).where(eq(writingStyleMatrix.connectionId, connectionId));
// };

// const seed = command({
// name: 'seed-style-matrix',
// args: {
// connectionId: option({
// type: optional(stringType),
// long: 'connection-id',
// short: 'c',
// description: 'Connection ID to seed the generated style matrix for',
// }),
// style: option({
// type: optional(oneOf(keys(mapping))),
// description: 'Style to seed the generated style matrix for',
// long: 'style',
// short: 's',
// }),
// size: option({
// type: optional(numberType),
// description: 'Number of emails to seed',
// long: 'size',
// short: 'n',
// defaultValue: () => {
// return 10;
// },
// }),
// resetStyleMatrix: flag({
// type: optional(boolean),
// description: 'Reset the style matrix before seeding',
// long: 'reset',
// short: 'r',
// defaultValue: () => {
// return false;
// },
// }),
// },
// handler: async (inputs) => {
// const connectionId = inputs.connectionId ?? (await getConnectionId());
// const style = inputs.style ?? (await getStyle());
// const resetStyleMatrix = inputs.resetStyleMatrix ?? (await getResetStyleMatrix(connectionId));
// const size = inputs.size ?? (await getNumberOfEmails(mapping[style].length));

// if (resetStyleMatrix) {
// await runResetStyleMatrix(connectionId);
// }

// await runSeeder(connectionId, style, size);
// },
// });

// const reset = command({
// name: 'reset',
// args: {
// connectionId: option({
// type: optional(stringType),
// long: 'connection-id',
// short: 'c',
// description: 'Connection ID to seed the generated style matrix for',
// }),
// },
// handler: async (inputs) => {
// const connectionId = inputs.connectionId ?? (await getConnectionId());

// const confirmed = await confirm({
// message: `Reset the style matrix for Connection ID (${connectionId})?`,
// });

// if (confirmed) {
// console.warn('Resetting style matrix for connection', connectionId);
// await runResetStyleMatrix(connectionId);
// console.warn('Reset style matrix for connection', connectionId);
// } else {
// console.warn('Aborted reset');
// }
// },
// });

// const getConnectionId = async () => {
// return input({
// message: 'Connection ID to seed:',
// required: true,
// validate: async (value) => {
// const connection = await db.query.connection.findFirst({
// where: (table, ops) => {
// return ops.eq(table.id, value);
// },
// columns: {
// id: true,
// },
// });

// return connection ? true : 'Invalid Connection ID';
// },
// });
// };

// const getStyle = async () => {
// return select<keyof typeof mapping>({
// message: 'Style to seed the generated style matrix for',
// choices: keys(mapping),
// });
// };

// const getResetStyleMatrix = async (connectionId: string) => {
// return confirm({
// message: `Reset the style matrix for Connection ID (${connectionId}) before seeding?`,
// default: true,
// });
// };

// const getNumberOfEmails = async (maxSize: number) => {
// return numberPrompt({
// message: 'Number of emails to seed',
// default: 10,
// max: maxSize,
// min: 0,
// required: true,
// });
// };

// export const seedStyleCommand = subcommands({
// name: 'seed-style',
// description: 'Seed style matrix for a given Connection ID',
// cmds: {
// seed,
// reset,
// },
// });
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider deleting the file instead of commenting out all content.

Commenting out the entire file creates dead code and removes the exported seedStyleCommand, which could break imports elsewhere in the codebase. If this functionality is being deprecated, consider either:

  1. Deleting the file entirely
  2. Adding a clear deprecation notice explaining why it's commented out
  3. Providing migration guidance if replacement functionality exists

🏁 Script executed:

#!/bin/bash
# Description: Check for any imports of seedStyleCommand or this seeder module
# Expected: Find all references to verify nothing breaks when this export is removed

# Search for imports of seedStyleCommand
rg -g "!scripts/seed-style/seeder.ts" "seedStyleCommand" 

# Search for imports from this file
rg -g "!scripts/seed-style/seeder.ts" "from.*scripts/seed-style/seeder" 

# Search for require statements
rg -g "!scripts/seed-style/seeder.ts" "require.*scripts/seed-style/seeder"

Length of output: 565


Update or Remove Deprecated Seeder Imports

Commenting out scripts/seed-style/seeder.ts breaks all references to seedStyleCommand. You’ll need to either fully delete the module and clean up its imports or restore it (with a deprecation notice) if you still intend to support it.

Files to update:

  • scripts/run.ts
    • import { seedStyleCommand } from './seed-style/seeder';
    • 'seed-style': seedStyleCommand,
  • scripts/README.md
    • import { seedStyleCommand } from '@zero/mail/scripts/seed-style/seeder';
    • 'seed-style': seedStyleCommand,

Recommended actions:

  1. If deprecating:
    • Delete scripts/seed-style/seeder.ts.
    • Remove or replace the above imports.
    • Update documentation to note removal of the seed-style command.
  2. If keeping (but deprecated):
    • Un-comment the file.
    • Add a clear deprecation warning at top of seeder.ts.
    • Update README to mark the command as deprecated.
  3. Ensure tests or any CI steps aren’t relying on the removed command.
🤖 Prompt for AI Agents
In scripts/seed-style/seeder.ts lines 1 to 200, the entire file is commented out
which breaks the export of seedStyleCommand and any imports relying on it. To
fix this, either fully delete this file and remove all imports of
seedStyleCommand in scripts/run.ts and scripts/README.md, updating documentation
accordingly, or restore the file by uncommenting it and adding a clear
deprecation notice at the top, then mark the command as deprecated in the
README. Also verify no tests or CI steps depend on this command.

import { getContext } from 'hono/context-storage';
import type { gmail_v1 } from '@googleapis/gmail';
import { connection } from '@zero/db/schema';
import { connection } from '../../db/schema';
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

LGTM! Import path update looks correct.

The change from absolute import @zero/db/schema to relative import ../../db/schema aligns with the broader refactoring to remove the @zero/db package. The relative path appears correct based on the file structure.


🏁 Script executed:

#!/bin/bash
# Description: Verify all @zero/db imports have been updated consistently
# Expected: Should find no remaining @zero/db imports

# Search for any remaining @zero/db imports
rg "@zero/db" --type ts --type tsx

# Verify the target schema file exists at the expected location
fd "schema" apps/server/src/db/

Length of output: 123


🏁 Script executed:

#!/bin/bash
# Search for any remaining @zero/db imports across TS and TSX files
rg "@zero/db" -g "*.ts" -g "*.tsx" || echo "No matches found"

# Confirm schema.ts still exists
ls apps/server/src/db/schema.ts

Length of output: 246


Action Required: Clean up leftover @zero/db references

The import update in apps/server/src/lib/driver/utils.ts is correct, and apps/server/src/db/schema.ts exists at the expected location. However, there are still references to the old @zero/db package in your scripts:

• scripts/seed-style/seeder.ts (commented imports):

// import { writingStyleMatrix } from '@zero/db/schema';
// import { db } from '@zero/db';

Please remove or update these references to complete the refactoring.

🤖 Prompt for AI Agents
In apps/server/src/lib/driver/utils.ts at line 4, the import path has been
correctly updated from '@zero/db/schema' to a relative path. However, to
complete the refactoring, locate the commented out imports referencing
'@zero/db' in scripts/seed-style/seeder.ts and remove or update them to use the
new relative import paths consistent with the rest of the codebase.

Comment on lines +1 to +3
ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;--> statement-breakpoint
ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean;--> statement-breakpoint
ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number"); No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enforce default and non-null for verification flag
Currently, phone_number_verified will default to NULL for existing rows, leading to tri-state logic. It’s safer to make it NOT NULL DEFAULT false. For example:

 ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;
-ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean;
+ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean NOT NULL DEFAULT false;
 ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;--> statement-breakpoint
ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean;--> statement-breakpoint
ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number");
ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;
ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean NOT NULL DEFAULT false;
ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number");
🤖 Prompt for AI Agents
In apps/server/src/db/migrations/0027_vengeful_golden_guardian.sql at lines 1 to
3, the column phone_number_verified is added without a default value or NOT NULL
constraint, allowing NULLs. Modify the ALTER TABLE statement to add
phone_number_verified as NOT NULL with a DEFAULT false to avoid tri-state logic
and ensure existing rows have a defined value.

Comment on lines +169 to +170
queryFn: () =>
fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as any),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using proper TypeScript interfaces instead of as any.

While the explicit type casting improves type safety awareness, using as any bypasses TypeScript's type checking entirely. Consider creating proper interfaces for the GitHub API responses to maintain type safety.

+// Add interfaces for GitHub API responses
+interface GitHubRepository {
+  stargazers_count: number;
+  forks_count: number;
+  subscribers_count: number;
+  open_issues_count: number;
+}
+
+interface GitHubCommit {
+  commit: {
+    author: {
+      date: string;
+    };
+  };
+}
+
+interface GitHubPullRequest {
+  // Add relevant PR fields
+}

 const { data: repoData, error: repoError } = useQuery({
   queryFn: () =>
-    fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as any),
+    fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as Promise<GitHubRepository>),
   queryKey: ['repo-data', REPOSITORY],
 });

 const { data: commitsData, error: commitsError } = useQuery({
   queryFn: () =>
     fetch(`https://api.github.com/repos/${REPOSITORY}/commits?per_page=100`).then(
-      (res) => res.json() as any,
+      (res) => res.json() as Promise<GitHubCommit[]>,
     ),
   queryKey: ['commits-data', REPOSITORY],
 });

 const { data: prsData, error: prsError } = useQuery({
   queryFn: () =>
     fetch(`https://api.github.com/repos/${REPOSITORY}/pulls?state=open`).then(
-      (res) => res.json() as any,
+      (res) => res.json() as Promise<GitHubPullRequest[]>,
     ),
   queryKey: ['prs-data', REPOSITORY],
 });

Also applies to: 176-177, 184-185

🤖 Prompt for AI Agents
In apps/mail/app/(full-width)/contributors.tsx around lines 169-170, 176-177,
and 184-185, the code uses 'as any' to cast the JSON response from the GitHub
API, which disables TypeScript's type checking. To fix this, define appropriate
TypeScript interfaces representing the expected structure of the GitHub API
responses and replace 'as any' with these interfaces in the fetch calls to
ensure proper type safety.

Comment on lines +7 to +10
if (value !== current) {
setPrevious(current);
setCurrent(value);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Avoid setState during render - causes unpredictable behavior.

Calling setState during render (lines 7-10) violates React's rules and can lead to infinite re-renders, performance issues, or unpredictable behavior. This pattern is explicitly discouraged in React documentation.

Use useRef and useEffect instead for tracking previous values:

-import { useState } from 'react';
+import { useRef, useEffect } from 'react';

-export function usePrevious<T>(value: T) {
-  const [current, setCurrent] = useState(value);
-  const [previous, setPrevious] = useState<T | null>(null);
-
-  if (value !== current) {
-    setPrevious(current);
-    setCurrent(value);
-  }
-
-  return previous;
-}
+export function usePrevious<T>(value: T) {
+  const ref = useRef<T>();
+  
+  useEffect(() => {
+    ref.current = value;
+  });
+  
+  return ref.current;
+}
🤖 Prompt for AI Agents
In apps/mail/hooks/use-previous.ts at lines 7 to 10, avoid calling setState
during render as it causes unpredictable behavior and violates React rules.
Refactor the code to use useRef to hold the previous value and update it inside
a useEffect hook that runs after render. This prevents state updates during
render and ensures the previous value is tracked correctly without triggering
re-renders.

Comment on lines +42 to +45
const connectionId = (await this.ctx.storage.get('connectionId')) as string;
if (!connectionId || !this.driver) {
throw new Error('Unauthorized');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper error handling for missing connectionId.

The current error handling throws a generic error without providing context about the authentication failure. This could make debugging difficult.

-        if (!connectionId || !this.driver) {
-          throw new Error('Unauthorized');
-        }
+        if (!connectionId) {
+          throw new Error('No connection ID found. User may not be properly authenticated.');
+        }
+        if (!this.driver) {
+          throw new Error('Mail driver not initialized. Check authentication and connection setup.');
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const connectionId = (await this.ctx.storage.get('connectionId')) as string;
if (!connectionId || !this.driver) {
throw new Error('Unauthorized');
}
const connectionId = (await this.ctx.storage.get('connectionId')) as string;
if (!connectionId) {
throw new Error('No connection ID found. User may not be properly authenticated.');
}
if (!this.driver) {
throw new Error('Mail driver not initialized. Check authentication and connection setup.');
}
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts around lines 42 to 45, the code throws a
generic error when connectionId is missing, which lacks context. Update the
error handling to throw a more descriptive error message that clearly indicates
the authentication failure due to missing connectionId. This will improve
debugging and clarity of the issue.

const _conn = await getActiveConnection().catch((err) => {
console.error('Error in getActiveConnection:', err);
throw c.json({ error: 'Failed to get active connection' }, 500);
export class ZeroMCP extends McpAgent<typeof env, {}, { cookie: string }> {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the banned {} type in ZeroMCP class declaration.

The generic parameter uses the banned {} type. Consider using a more specific type.

-export class ZeroMCP extends McpAgent<typeof env, {}, { cookie: string }> {
+export class ZeroMCP extends McpAgent<typeof env, Record<string, unknown>, { cookie: string }> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 120-120: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts at line 120, the ZeroMCP class declaration
uses the banned empty object type `{}` as a generic parameter. Replace this `{}`
with a more specific type that accurately represents the expected shape or
interface for that generic parameter to improve type safety and clarity.

} else if (canSendMessages.data.balance <= 0) {
console.log('Balance is 0 or less');
return c.json({ error: 'Insufficient plan balance' }, 403);
async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the banned {} type.

Same issue as line 39 - replace the {} type with a more specific type.

-  async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) {
+  async onChatMessage(onFinish: StreamTextOnFinishCallback<Record<string, unknown>>) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) {
async onChatMessage(onFinish: StreamTextOnFinishCallback<Record<string, unknown>>) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 112-112: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts at line 112, the use of the banned `{}` type
in the generic parameter of StreamTextOnFinishCallback should be replaced with a
more specific type that accurately represents the expected data structure.
Review the context or similar usages (like line 39) to determine the appropriate
type and update the generic accordingly to ensure type safety and clarity.

Comment on lines +376 to +386
} catch (e) {
return {
content: [
{
type: 'text',
text: 'Failed to create label',
},
],
};
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling in createLabel tool.

The error handling is too generic. Consider providing more specific error information or at least logging the error for debugging.

-        } catch (e) {
-          return {
-            content: [
-              {
-                type: 'text',
-                text: 'Failed to create label',
-              },
-            ],
-          };
-        }
+        } catch (e) {
+          console.error('Failed to create label:', e);
+          return {
+            content: [
+              {
+                type: 'text',
+                text: `Failed to create label: ${e instanceof Error ? e.message : 'Unknown error'}`,
+              },
+            ],
+          };
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e) {
return {
content: [
{
type: 'text',
text: 'Failed to create label',
},
],
};
}
},
} catch (e) {
console.error('Failed to create label:', e);
return {
content: [
{
type: 'text',
text: `Failed to create label: ${e instanceof Error ? e.message : 'Unknown error'}`,
},
],
};
}
},
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts between lines 376 and 386, the catch block for
the createLabel tool currently returns a generic error message without logging
or providing specific error details. Modify the catch block to log the caught
error for debugging purposes and, if appropriate, include more specific error
information in the returned response to improve error handling and
troubleshooting.

if (token) {
const session = await this.getSession(token);
if (session) {
const db = createDb(env.HYPERDRIVE.connectionString);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify environment variable access in class context.

The env variable is imported from 'cloudflare:workers' but accessed inside the class. Ensure this is accessible in the durable object context.


🏁 Script executed:

#!/bin/bash
# Description: Check how env is used across the codebase to ensure proper access patterns
rg -A 3 -B 3 "env\.HYPERDRIVE"

Length of output: 1809


🏁 Script executed:

#!/bin/bash
# Show the top of chat.ts to inspect imports and class definitions
sed -n '1,50p' apps/server/src/routes/chat.ts

Length of output: 1882


🏁 Script executed:

#!/bin/bash
# List top-level directories
find . -maxdepth 2 -type d | sed 's/\.\///g'

Length of output: 376


Use the Durable Object’s env in ZeroAgent

Inside apps/server/src/routes/chat.ts, the env you imported from 'cloudflare:workers' is only a type stub. In your ZeroAgent class you should use the environment passed into the constructor (this.env), not the top-level import.

Please update both occurrences of:

const db = createDb(env.HYPERDRIVE.connectionString);

to:

const db = createDb(this.env.HYPERDRIVE.connectionString);

— apps/server/src/routes/chat.ts (around line 89 and the subsequent block)

🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts around line 89, replace the usage of the
imported top-level env variable with the Durable Object's environment instance
by changing all occurrences of "env.HYPERDRIVE.connectionString" to
"this.env.HYPERDRIVE.connectionString" inside the ZeroAgent class. This ensures
the correct environment context is used within the class methods.

@MrgSub MrgSub merged commit 0b34ea5 into main May 26, 2025
4 checks passed
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.

10 participants