Skip to content

Neon integration#3178

Open
azizmejri1 wants to merge 15 commits intodyad-sh:mainfrom
azizmejri1:neon-integration
Open

Neon integration#3178
azizmejri1 wants to merge 15 commits intodyad-sh:mainfrom
azizmejri1:neon-integration

Conversation

@azizmejri1
Copy link
Copy Markdown
Collaborator

@azizmejri1 azizmejri1 commented Apr 9, 2026

Context for review bots :

1.The agent can execute sql commands directly on production , this is fine because they user may choose to start with a simple setup first and use the production database directly (in a follow up PR we should give the users the ability to sync dev branch to match production branch).The user also has the possiblity to revert database changes .
2.Right now there’s no warning for destructive changes before migration , this is fine for now as we're gonna add a follow up PR for this
3.When linking an existing neon project that doesnt have a developement database , we're setting the default branch as the active branch . This is fine because the user may prefer to start a simple setup at the beginning and work directly on the production database , in addition since the project was created outside dyad it may have a developement branch named differently so it wouldnt be wise to auto create one here . However, in a follow up PR we should allow the user to manually create branches and sync dev branch to match production .
4.neon is only available for next.js now
5.We dont have enough tests for now, i am gonna add a follow-up PR to cover this


Open with Devin

azizmejri1 and others added 2 commits April 9, 2026 02:33
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 9, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​neondatabase/​api-client@​2.2.0 ⏵ 2.7.110010092 +193 -4100

View full report

@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 9, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

gemini-code-assist[bot]

This comment was marked as resolved.

@dyad-assistant
Copy link
Copy Markdown
Contributor

dyad-assistant bot commented Apr 9, 2026

🔍 Dyadbot Code Review Summary

Verdict: ⛔ NO — Do not merge as-is

Reviewed by 3 independent agents (Correctness Expert, Code Health Expert, UX Wizard), then cross-validated against the code. One confirmed CI-breaking issue plus several user-facing and maintainability concerns; the PR author has already called out several deferrals in the description (destructive-change warnings, manual branch creation, test coverage), and I've honored those where applicable.

Issues Summary

Severity File Issue
🔴 HIGH e2e-tests/snapshots/supabase_stale_ui.spec.ts_supabase---stale-ui-{1,3}.aria.yml Snapshot's Neon feature bullets don't match current en.json — will break CI
🟡 MEDIUM src/neon_admin/neon_context.ts:57 Hardcoded database_name: "neondb" breaks linked projects with renamed DBs
🟡 MEDIUM src/components/MigrationPanel.tsx:35-46 errorSummary == errorDetails makes the "Show details" toggle unreachable
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:449-467 setAppProject has no rollback if env-var injection fails (DB ends up half-linked)
🟡 MEDIUM src/prompts/neon_prompt.ts:480 NEON_NOT_AVAILABLE_SYSTEM_PROMPT is exported but never imported anywhere
🟡 MEDIUM src/pages/app-details.tsx:449-522 Mutual-exclusion Card is duplicated 4 times; CardTitle is hardcoded English
🟡 MEDIUM src/ipc/handlers/chat_stream_handlers.ts:833 & token_count_handlers.ts:97 Neon prompt-injection block is duplicated verbatim across two handlers
🟡 MEDIUM src/ipc/handlers/migration_handlers.ts:115,162 Raw drizzle-kit stderr is piped to the user-facing error banner
🟡 MEDIUM src/components/MigrationPanel.tsx:61-79 "Migrate to Production" has no confirmation dialog
🟡 MEDIUM src/components/NeonConnector.tsx:111-130 OAuth button stuck for 60s with no cancel if the user abandons the browser flow
🟡 MEDIUM src/neon_admin/neon_context.ts:126-162 buildTableSchemaQuery/buildIndexesQuery mutate SQL via a fragile regex — silent full-table leak on regex miss
🟡 MEDIUM src/components/chat/DyadAddIntegration.tsx:55-63 Radio group uses role="radio" on buttons without arrow-key navigation

Additional Observations (not posted inline to keep noise down)

  • src/ipc/handlers/neon_handlers.ts:33-249createProject handler is ~216 lines with deeply nested try/catch and three duplicated branch-creation blocks. Extract createBranchWithAuth(...) and cleanupOrphanedNeonProject(...) helpers; the orchestration then becomes ~40 lines and is actually testable.
  • src/components/NeonConnector.tsx is 727 lines handling three very different UI states (disconnected, connected, create-form). Near-mechanical split into NeonConnectorDisconnected + NeonConnectorConnected + a thin selector would make future edits and reviews much cheaper.
  • src/ipc/utils/app_env_var_utils.ts:265removeNeonEnvVars matches on .neon.tech substring, which misses Neon custom domains. Tracking which vars Dyad injected (by sentinel comment) would be more reliable.
  • src/neon_admin/neon_management_client.tsgetNeonOrganizationId silently picks organizations[0]. Users in multiple Neon orgs will get surprises. At least surface which org is in use.
  • src/components/NeonConnector.tsx vs SupabaseConnector — several UX asymmetries: error-state uses bare <div className="text-red-500"> vs <Alert>; no org grouping/switching in the project selector; empty-state buries the "Create new project" CTA.
  • src/components/chat/DyadAddIntegration.tsx:96-105handleKeepGoingClick interpolates the lowercase provider id (neon/supabase) into the streamed prompt, while the UI uses the capitalized display name. Use completedProviderName for consistency.
  • i18n word-order issues: {{provider}} Project Info and {{provider}} Table Schema don't translate cleanly into pt-BR (yield e.g. Neon Informações do Projeto). Rephrase as Project Info ({{provider}}) or split into per-provider keys.
  • src/neon_admin/neon_context.ts:331-345getNeonContext accepts a frameworkType argument it never uses (renamed with _ prefix). Either drop the parameter or inline the function.
🚫 Dropped False Positives (1 item)
  • Deep-link OAuth handler may leave stale timeout after unmount — DROPPED. NeonConnector.tsx:102-109 has a useEffect(() => () => clearTimeout(oauthTimeoutRef.current), []) cleanup that handles unmount correctly. The timeout is stored in a ref and cleared on unmount.
🟢 Low-priority / Intentionally Deferred (condensed)
  • Schema file detection fallback in migration_handlers.ts:133-141drizzle-kit introspect reliably emits schema.ts; the fallback path is theoretical.
  • execute_neon_sql / get_neon_project_info / get_neon_table_schema only check neonActiveBranchId with no fallback to neonDevelopmentBranchId. In practice neonActiveBranchId is always set at project-link time (see setAppProject falling back to the default branch), so this is a minor inconsistency rather than a bug.
  • Destructive-change warnings for drizzle-kit push --force — explicitly deferred by the PR author to a follow-up.
  • Test coverage gaps — explicitly deferred by the PR author.
  • Dev-branch fallback for linked existing projects — explicitly intentional per PR description.
  • SQL-injection via agent-controlled execute-sql — explicitly intentional per PR description (add a code comment documenting the trust boundary).

Generated by Dyadbot multi-agent code review

dyad-assistant[bot]

This comment was marked as resolved.

@github-actions github-actions bot added the needs-human:review-issue ai agent flagged an issue that requires human review label Apr 9, 2026
- Resolve hardcoded "neondb" by dynamically fetching database name via Neon API
- Replace fragile regex SQL injection with explicit query constants
- Fix errorDetails showing same value as errorSummary (use error.stack)
- Add confirmation dialog for "Migrate to Production" button
- Add cleanup/rollback in setAppProject if env var injection fails
- Remove dead NEON_NOT_AVAILABLE_SYSTEM_PROMPT export
- Extract UnavailableIntegrationCard to deduplicate 4 card instances
- Extract buildNeonPromptForApp to deduplicate prompt block across handlers
- Add roving tabindex + arrow-key navigation for radio group accessibility
- Drop OAuth spinner timeout from 60s to 20s
- Update stale E2E snapshots with current Neon feature strings
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

@azizmejri1
Copy link
Copy Markdown
Collaborator Author

🤖 Claude Code Review Summary

PR Confidence: 4/5

All review comments have been addressed with code changes; confidence is high but some changes (dynamic DB name resolution, prompt refactoring) would benefit from integration testing.

Unresolved Threads

No unresolved threads

Resolved Threads

Issue Rationale Link
Hardcoded "neondb" database name breaks linked projects with custom DB names Added getBranchDatabaseName() to dynamically resolve via Neon API, matching the existing getBranchRoleName() pattern. Confirmed valid by @azizmejri1. View
Fragile regex SQL injection in buildTableSchemaQuery/buildIndexesQuery Replaced regex-based query mutation with explicit _ALL and _ONE query constants. No runtime regex, no silent-unfiltered failure mode. View
errorDetails equals errorSummary, making "Show details" toggle unreachable Changed errorDetails to use error.stack when available, giving the toggle meaningful content. View
"Migrate to Production" has no confirmation dialog Added AlertDialog confirmation per Principle #4: Transparent Over Magical — destructive operations require explicit confirmation. View
setAppProject leaves app half-linked if autoInjectNeonEnvVars fails Added try/catch with DB rollback on env var injection failure, mirroring the cleanup pattern in createProject. View
NEON_NOT_AVAILABLE_SYSTEM_PROMPT exported but never imported Removed the dead export — the Supabase unavailable prompt already handles the no-integration fallback. View
Mutual-exclusion Card duplicated 4 times in app-details.tsx Extracted UnavailableIntegrationCard component and replaced all 4 inline copies. View
Neon prompt-injection block duplicated across two handlers Extracted buildNeonPromptForApp() helper in neon_prompt_context.ts and replaced both call sites. View
OAuth button stuck showing spinner for 60s if user cancels Reduced timeout from 60s to 20s per @azizmejri1's direction. View
Stale E2E snapshots with outdated Neon feature strings Updated both -1 and -3 snapshot files with current i18n values. View
Radio group uses role="radio" without arrow-key navigation Added roving tabIndex and arrow-key handlers to the provider picker radio group. View
Product Principle Suggestions

No suggestions — principles were clear enough for all decisions. Principle #4 (Transparent Over Magical) directly guided the migration confirmation dialog addition.


🤖 Generated by Claude Code

dyad-assistant[bot]

This comment was marked as resolved.

@dyad-assistant
Copy link
Copy Markdown
Contributor

dyad-assistant bot commented Apr 9, 2026

🔍 Dyadbot Code Review Summary

Verdict: ⛔ NO — Do NOT merge as-is

Reviewed by 3 independent agents (Correctness Expert, Code Health Expert, UX Wizard), then cross-validated against the source and deduplicated against existing review comments.

New Issues Summary (11 inline comments posted)

Severity File Issue
🔴 HIGH src/ipc/utils/migration_utils.ts:138 spawn("node", ...) will fail for packaged-app users without system Node
🔴 HIGH src/i18n/locales/pt-BR/home.json:638 Missing confirmDescription/cancel for migration dialog
🔴 HIGH src/i18n/locales/zh-CN/home.json:638 Missing confirmDescription/cancel for migration dialog
🔴 HIGH src/components/MigrationPanel.tsx:87 Nested <button>: <Button> inside <AlertDialogTrigger> without asChild (disabled state ignored)
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:603 setActiveBranch doesn't revert DB on env-injection failure (inconsistent with setAppProject)
🟡 MEDIUM src/neon_admin/neon_context.ts:397 getNeonContext is a thin pass-through with unused frameworkType param
🟡 MEDIUM src/neon_admin/neon_context.ts:185 TABLE_SCHEMA_QUERY_ALL/ONE + INDEXES_QUERY_ALL/ONE are near-identical copy-pastes
🟡 MEDIUM src/components/chat/DyadDbProjectInfo.tsx:72 DyadDbProjectInfo and DyadDbTableSchema are ~90% the same component
🟡 MEDIUM src/components/chat/DyadAddIntegration.tsx:72 Silent Neon → Supabase fallback without explaining substitution
🟡 MEDIUM src/ipc/utils/migration_utils.ts:125 spawnDrizzleKit test-mode silently falls through for unknown commands
🟡 MEDIUM src/components/MigrationPanel.tsx:44 Success banner auto-dismisses; error banner lingers forever

Top merge-blockers

  1. spawn("node", ...)forge.config.ts bundles drizzle-kit/drizzle-orm via extraResource but no Node binary. Packaged users without system Node will get ENOENT the first time they click Migrate to Production. Fix by spawning process.execPath with ELECTRON_RUN_AS_NODE=1.
  2. Missing i18n keys in pt-BR and zh-CN for the destructive-action dialog — Brazilian and Chinese users see raw key literals on the exact dialog where they need clarity most.
  3. Nested <button> in MigrationPanel — because disabled on the inner <Button> is ignored, users can re-open the confirmation dialog while a migration is already running.
🟢 Lower priority notes (14 items, not posted inline to reduce noise)
  • Fragile substring matching for Neon auth errorsresponse_processor.ts does errorMsg.includes('password authentication failed'); classify at the source via error kind/HTTP status instead.
  • Deep relative imports in local-agent toolsexecute_neon_sql.ts, get_neon_project_info.ts, get_neon_table_schema.ts use ../../../../../../neon_admin/... instead of the @/ alias used elsewhere.
  • FrameworkType union is declared inline in ~7 places — extract to src/lib/framework_constants.ts as a shared type.
  • "Complete sign-in in your browser…" — button label is ambiguous between instruction and status; prefer "Waiting for browser sign-in…".
  • Branch-switched toast concatenates two sentences with a colon — translators can't reorder; use a single interpolated key.
  • Long table names truncate with no tooltip in DyadDbTableSchema; add title or shadcn Tooltip.
  • UnavailableIntegrationCard is a dead-end UI — offer a "Disconnect X first →" affordance.
  • useCopyToClipboard for dyad-add-integration lost the provider name — previously emitted ### Add Integration: supabase, now emits ### Add Database Integration with no provider info.
  • removeNeonEnvVars heuristic — matches on .includes('.neon.tech'); fragile if Neon's endpoint format changes. Store a Dyad marker instead.
  • NEON_AUTH_COOKIE_SECRET regenerated on every branch switch — logs out all sessions on the running dev server mid-test.
  • Dedicated-dev-branch fallback picks first non-default/non-preview branch — could silently pick a stale feature branch as "development".
  • createProject cleanup leaks orphaned Neon projects if deleteProject itself fails — no retry queue; only logged to electron-log.
  • detectFrameworkType does sync fs.existsSync + JSON.parse(package.json) on every call — called per agent turn; should be cached.
  • getConnectionUri makes 3 API round-trips per executeNeonSql — add a short-TTL per-(projectId,branchId) cache.
🚫 Dropped / already addressed (7 items)
  • drizzle-kit push --force destroys production without a preview — Dropped: PR description item Infinite Loop: Checking Node.js setup... #2 explicitly defers this to a follow-up.
  • Linking existing projects uses production/default as active branch — Dropped: PR description item Query | Question about model availability via OpenRouter #3 explicitly calls this out as intentional.
  • setAppProject leaves app half-linked if autoInjectNeonEnvVars fails — Dropped: already has rollback at neon_handlers.ts:468-488. (setActiveBranch still doesn't — see inline comment above.)
  • Hardcoded database_name: "neondb" in getConnectionUri — Dropped: now dynamically resolved via getBranchDatabaseName in neon_context.ts:80-90.
  • OAuth button stuck showing spinner for 60s — Dropped: the actual timeout is now 20s at NeonConnector.tsx:125, already addressed in this PR.
  • MigrationPanel missing confirmation dialog — Dropped: AlertDialog confirmation now exists (though see the nested-button HIGH comment above for a separate issue with that dialog).
  • errorDetails equals errorSummary, making "Show details" toggle unreachable — Dropped: errorDetails now prefers error.stack ?? error.message while errorSummary uses error.message, so they diverge when a stack is present.

Generated by Dyadbot multi-agent code review (Correctness · Code Health · UX)

- run drizzle-kit in an Electron utility process and guard unsupported test commands
- keep active branch updates atomic and fix the migration dialog trigger plus missing locale copy
- remove the unused Neon context framework parameter
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

Copy link
Copy Markdown
Collaborator Author

🤖 Claude Code Review Summary

PR Confidence: 4/5

Formatting, lint, type-checking, and the existing unit test suite all passed locally; the main remaining risk is that the migration flow still has no dedicated E2E coverage in this patch.

Unresolved Threads

No unresolved threads

Resolved Threads

Issue Rationale Link
Drizzle runner should not depend on a system node binary Switched spawnDrizzleKit to Electron utilityProcess.fork(...), which works with packaged builds and keeps the drizzle-kit execution path inside the app runtime. View
Test-mode drizzle command fallthrough Added an explicit test-build error for unsupported drizzle commands so new subcommands fail loudly instead of silently reaching real subprocess execution. View
Missing migration confirmation translations Added confirmDescription and cancel to both pt-BR and zh-CN migration locale blocks so the destructive dialog renders fully localized copy. View
Migration confirmation trigger nested button markup Replaced the nested trigger/button structure with the Base UI render pattern so the trigger stays valid HTML and properly honors the pending disabled state. View
setActiveBranch could leave DB state ahead of .env.local Mirrored the existing rollback pattern from setAppProject so failed env injection restores the previous active branch ID before surfacing the error. View
Unused frameworkType plumbing in Neon prompt context Removed the unused frameworkType hop from getNeonContext(...) and aligned the prompt-context call site plus the existing unit test expectation. View
Product Principle Suggestions

No suggestions

dyad-assistant[bot]

This comment was marked as resolved.

@dyad-assistant
Copy link
Copy Markdown
Contributor

dyad-assistant bot commented Apr 9, 2026

🔍 Dyadbot Code Review Summary

Verdict: ⛔ NO — Do NOT merge as-is

Reviewed by 3 independent agents (Correctness Expert, Code Health Expert, UX Wizard), then cross-validated against the 29 existing PR comments to avoid duplicate flags. The 353917b "Address Neon PR review comments" commit clearly fixed a lot of the earlier round (confirmation dialog, asChild on AlertDialogTrigger, OAuth timeout reduced to 20s, getBranchRoleName / getBranchDatabaseName added, setAppProject rollback, missing i18n keys, etc.), but a new round of findings surfaced — most notably a high-severity data-loss bug in autoInjectNeonEnvVars that wipes valid auth env vars on any transient Neon API failure and invalidates every signed-in user's session.

Issues Summary

Severity File Issue
🔴 HIGH src/ipc/utils/neon_utils.ts:124-156 Transient ensureNeonAuth failure silently wipes valid auth env vars and invalidates all sessions
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:446-495 setAppProject silently links project without env vars when no branch resolves
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:553-591 setActiveBranch allows picking the read-only preview branch
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:601-623 setActiveBranch rollback does not restore .env.local on partial write
🟡 MEDIUM src/neon_admin/neon_context.ts:17-68 getBranchRoleName/getBranchDatabaseName silent fallback on any error, masking real problems
🟡 MEDIUM src/lib/framework_constants.ts + src/ipc/utils/framework_utils.ts Two divergent Next.js-detection impls — backend enables Neon while frontend refuses to render
🟡 MEDIUM src/components/NeonConnector.tsx:126-266 Toasts use String(error) → renders "[object Object]" for non-Error rejections
🟡 MEDIUM src/components/NeonConnector.tsx:376-407 No empty-state when branches API returns zero branches
🟡 MEDIUM src/components/NeonConnector.tsx:335-341 Project-name Badge floats inside a flex-col CardHeader with stranded ml-2
🟡 MEDIUM src/components/MigrationPanel.tsx:60-96 Migration card never names the source/target branch — user can't sanity-check destructive push
🟡 MEDIUM src/components/MigrationPanel.tsx:164-169 Error <pre> has no max-h-*, long drizzle-kit stacks blow up the panel
🟡 MEDIUM src/components/chat/DyadAddIntegration.tsx:170-178 "Continue" button has no spinner while streaming
🟡 MEDIUM src/ipc/utils/app_env_var_utils.ts:47-274 ENOENT-tolerant env file read pattern duplicated 3x
🟢 Low-priority notes (not posted inline)
  • src/prompts/neon_prompt.ts:321-335getGenericNeonPrompt is unreachable (Neon is Next.js-only per the UI gate). Either delete it or wire it to a vite call path. Same pattern for getNeonClientCode's non-Next.js fallback in neon_context.ts:370-375.
  • src/neon_admin/neon_management_client.ts:442-449getCachedEmailPasswordConfig caches 404 responses (DEFAULT_EMAIL_PASSWORD_CONFIG) with the full 60s TTL. External toggles (e.g. through the Neon dashboard) won't be reflected for up to a minute. Use a shorter TTL for 404s, or don't cache them.
  • src/pro/main/ipc/handlers/local_agent/local_agent_handler.ts(ctx.neonActiveBranchId || ctx.neonDevelopmentBranchId) is a tautology after the build-time fallback already ran. Drop the || clause for clarity.
  • src/ipc/handlers/migration_handlers.ts:64-92IS_TEST_BUILD branch short-circuits tableCount = 1 — fine today, but the test-build awareness leaks into business logic. Consider pushing the mock down into executeNeonSql so new callers don't each need a IS_TEST_BUILD escape hatch.
  • src/pages/app-details.tsx:474-507 — the mutual-exclusion provider section has six nearly identical conditional branches. Related to the existing 4x Card duplication comment (Ability to connect with local LLM such as LLAMA #9 in the previous round), but one level deeper: the rendering / availability gating could collapse to visibleProviders.map(provider => <ProviderConnectorSlot ...>).
  • src/components/MigrationPanel.tsx:72-88 — no progress indicator or cancel button for an in-flight migration. push --force against a remote Postgres can take 10s+, users will wonder if Dyad is hung. Stream log lines from the drizzle-kit subprocess, or at least add a cancel button that aborts the child.
  • src/components/NeonConnector.tsx:314-342 — the connected-project header says "Neon Project" + "Connected to project" + a chip with the project name — three labels for one fact. Collapse to a single-line title.
  • src/components/NeonConnector.tsx:502-506 — project-list loading skeleton (short bar + tall bar) doesn't match the loaded layout's three rows, causing a visible layout shift when the request resolves.
  • src/components/NeonConnector.tsx:530-550 — new-project name input has no maxLength or helper text describing Neon's allowed charset / length. Users only find out post-submit.
  • src/components/NeonConnector.tsx:454-466 — disconnect confirmation button repeats the trigger label ("Disconnect project"). Use a distinct confirm label like "Yes, disconnect" for muscle-memory protection.
  • src/components/chat/DyadAddIntegration.tsx:90-112 — custom radio group handles Arrow keys but not Home/End, a minor WAI-ARIA Authoring Practices gap.
  • src/components/chat/DyadAddIntegration.tsx:133-139 — Setup button has no pending indicator during the route transition to /app-details. Brief disable/spinner would match the pattern used elsewhere.
  • src/hooks/useNeon.ts:62-64 — unnecessary as NeonAuthEmailAndPasswordConfig | undefined cast. Either it's hiding a real inference bug worth fixing upstream, or it's dead noise that will mask future return-type changes.
🚫 Dropped / de-duplicated findings
  • src/components/preview_panel/PublishPanel.tsx half-translatedDropped: the surrounding English strings ("Publish App", "GitHub", "Vercel") are pre-existing and not introduced by this PR. Not a regression.
  • src/components/chat/DyadAddIntegration.tsx:63 radio group keyboard navDropped: already flagged in the previous round (still present). Skipped per dedup rules.
  • src/prompts/neon_prompt.ts NEON_NOT_AVAILABLE_SYSTEM_PROMPT unusedDropped: already flagged in the previous round.
  • src/neon_admin/neon_context.ts:185 TABLE_SCHEMA_QUERY_ALL/ONE duplicationDropped: already flagged in the previous round.
  • src/components/chat/DyadDbProjectInfo.tsx 90% duplicate with DyadDbTableSchemaDropped: already flagged in the previous round.
  • src/pages/app-details.tsx:490 4x Card duplicationPartially dropped: previous-round comment Ability to connect with local LLM such as LLAMA #9 already covers the card-level duplication; I moved the related "6 conditional branches" observation to the low-priority notes instead of re-flagging as a new inline issue.
  • src/components/MigrationPanel.tsx success auto-dismisses but error persistsDropped: already flagged in the previous round.
  • src/ipc/utils/migration_utils.ts spawn("node", ...) portabilityDropped: already flagged as HIGH in the previous round.
  • src/i18n/locales/pt-BR / zh-CN missing migration keysDropped: already flagged as HIGH in the previous round.

Recommendation

The HIGH issue in neon_utils.ts is an unambiguous session-wipe regression waiting to bite real users on any Neon API hiccup during a branch switch — please address it before merging. The MEDIUM bucket is a mix of newly-introduced bugs (preview-branch acceptance, empty-branches UX, String(error) toasts) and short-leash edge cases (framework-detection split) that should be fixed in this PR rather than a follow-up, since they touch the freshly-written code paths that the Neon integration relies on.

The follow-up items listed in the PR description (destructive-diff warnings, dev/prod sync, more tests, manual branch creation) are fine to defer — none of the findings above belong in that bucket.


Generated by Dyadbot multi-agent code review

- harden Neon env var and branch handling
- align framework detection and improve Neon UX/error states
- add unit and E2E coverage for the migration flow
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

Copy link
Copy Markdown
Collaborator Author

🤖 Codex Review Summary

PR Confidence: 5/5

All addressed review items are now on neon-integration (e7d239fb), and the branch passed formatting, lint, type-checking, full unit tests, a packaged build, and the targeted Neon migration E2E flow.

Unresolved Threads

No unresolved threads

Resolved Threads

Issue Rationale Link
Neon auth/env safety on transient failures Preserved existing Neon auth env vars on transient activation failures and restored .env.local snapshots during handler rollbacks so auth/session state is not wiped by temporary API issues. View
Linking and branch-selection guardrails setAppProject now rejects projects with no writable branch, and setActiveBranch rejects the preview branch while restoring both DB state and .env.local on failure. View
Neon branch metadata fallbacks Role/database lookup now falls back only for empty/404 cases and rethrows real Neon API failures so users see the real problem instead of a masked default-db error. View
Framework detection source of truth getApp now returns frameworkType, and the Neon UI gates read that backend-derived value so frontend/backend Next.js detection stays aligned. View
Neon connector UX and error states Improved toast/error formatting, added a zero-branches empty state, and fixed the connected-project header layout so the linked project name reads cleanly. View
Migration panel clarity The migration card and confirmation dialog now name the project and branch direction, and the error details panel is vertically bounded for long Drizzle/Postgres output. View
Integration flow polish and env helper cleanup Added the “Continuing…” loading state, deduplicated ENOENT-tolerant env-file reads, and updated tests/helpers to cover the new migration confirmation flow. View
Product Principle Suggestions

No suggestions

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@dyad-assistant
Copy link
Copy Markdown
Contributor

🔍 Dyadbot Code Review Summary

Verdict: 🤔 NOT SURE - Potential issues

Reviewed by 3 independent agents: Correctness Expert, Code Health Expert, UX Wizard.

Issues Summary

Severity File Issue
🟡 MEDIUM src/pro/main/ipc/handlers/local_agent/tools/execute_sql.ts:45 Silent fallthrough from Neon to Supabase when neonActiveBranchId is null
🟡 MEDIUM src/components/MigrationPanel.tsx:51 isProductionBranchActive uses different branch resolution than backend
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:228 createProject does not snapshot env file before modification (unlike setAppProject/setActiveBranch)
🟡 MEDIUM src/components/chat/DyadReadGuide.tsx:37 Hardcoded English "Guide" badge label not translated
🟢 Low Priority Notes (6 items)
  • unsetAppProject no app validationsrc/ipc/handlers/neon_handlers.ts:554 — Returns { success: true } even if app doesn't exist (other handlers throw DyadError)
  • setActiveBranch misleading error on missing branchsrc/ipc/handlers/neon_handlers.ts:633 — When API returns undefined branch, error says "does not belong to project" instead of "not found"
  • Logger scope mismatchsrc/ipc/utils/migration_utils.ts:72 — Logger scope says migration_handlers but file is migration_utils
  • selectedProvider initial statesrc/components/chat/DyadAddIntegration.tsx:30 — Initialized to 'supabase' even for Next.js projects where Neon is available; effectiveSelectedProvider override handles it but may flash
  • formatToastError trivial wrappersrc/components/NeonConnector.tsx:72 — One-line wrapper around getErrorMessage adds no value
  • useNeon misleading export namessrc/hooks/useNeon.ts:35isLoadingBranches/branchesError actually fetches full project info including projectName
🚫 Dropped False Positives (12 items)
  • utilityProcess exit code race condition (migration_utils.ts:198) — Dropped: timedOut = true is set synchronously before proc.kill() in the same timer callback; the exit event fires asynchronously on the next event loop iteration, so timedOut is always set when checked
  • NeonConfigure still exists — Dropped: File is not in the PR diff; pre-existing issue
  • NeonDisconnectButton incomplete disconnect — Dropped: File is not in the PR diff; pre-existing issue
  • setAppProject branch classification (neon_handlers.ts:470) — Dropped: Already covered by existing comments at lines 461 and 534
  • removeNeonEnvVars hostname match (app_env_var_utils.ts:932) — Dropped: .neon.tech substring match is reasonable in practice; false positive risk is negligible
  • getBranchDatabaseName no canonical preference (neon_context.ts:72) — Dropped: Already covered by existing comment at line 57
  • SQL errors accumulate when branch null (response_processor.ts:202) — Dropped: Already covered by existing comment at line 206
  • getNeonContext trivial wrapper (neon_context.ts:422) — Dropped: Already covered by existing comment at line 433
  • node_modules symlink undocumented (migration_utils.ts:196) — Dropped: Already covered by existing comment at line 138
  • Connector rendering duplication (app-details.tsx:676) — Dropped: Already covered by existing comment at line 490
  • getGenericNeonPrompt dead code (neon_prompt.ts) — Dropped: Already covered by existing comment at line 496
  • isNextJsProject dual path (framework_constants.ts) — Dropped: Already covered by existing comment at line 24

Generated by Dyadbot multi-agent code review

dyad-assistant[bot]

This comment was marked as resolved.

@github-actions github-actions bot added the needs-human:review-issue ai agent flagged an issue that requires human review label Apr 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🎭 Playwright Test Results

⚠️ WARNING: Missing Test Shards!

Some test shards did not report results. This may indicate CI failures or timeouts.

  • 🍎 macOS: found 1/2 shards (1 missing)

❌ Some tests failed

OS Passed Failed Flaky Skipped
🍎 macOS 141 2 3 0

Summary: 141 passed, 2 failed, 3 flaky

Failed Tests

🍎 macOS

  • neon_branch.spec.ts > neon branch selection updates env vars
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • supabase_stale_ui.spec.ts > supabase - stale ui
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed

📋 Re-run Failing Tests (macOS)

Copy and paste to re-run all failing spec files locally:

npm run e2e \
  e2e-tests/neon_branch.spec.ts \
  e2e-tests/supabase_stale_ui.spec.ts

⚠️ Flaky Tests

🍎 macOS

  • local_agent_summarize.spec.ts > local-agent - summarize to new chat works (passed after 1 retry)
  • per_chat_input.spec.ts > closing a chat tab clears its stored input (passed after 1 retry)
  • setup_flow.spec.ts > Setup Flow > setup banner shows correct state when node.js is installed (passed after 1 retry)

📊 View full report

- Restore active→development branch fallback for Neon SQL execution
- Keep DATABASE_URL in sync with POSTGRES_URL during version switching
- Fix E2E test selecting filtered-out preview branch (use main instead)
- Add explicit error when Neon project set but active branch is null
- Fix isProductionBranchActive branch resolution to match backend
- Snapshot env file before modification in createProject for safe rollback
- Fix nested interactive elements (link inside button) in DyadAddIntegration
- Fix invalid JSX comment syntax in add-authentication guide
- Preserve email query param in callbackURL for email verification guide
- Translate hardcoded "Guide" badge label (en/pt-BR/zh-CN)
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

@azizmejri1 azizmejri1 removed the needs-human:review-issue ai agent flagged an issue that requires human review label Apr 13, 2026
@azizmejri1
Copy link
Copy Markdown
Collaborator Author

🤖 Claude Code Review Summary

PR Confidence: 4/5

All actionable code issues have been addressed; 5 threads remain open for human review on larger refactoring/UX decisions.

Unresolved Threads

Thread Rationale Link
Cross-branch timestamp consistency Out of scope — requires changes to version restore logic in version_handlers.ts. Reviewed Principle #2: Productionizable but it doesn't cover cross-branch timestamp consistency. View
Extract getAppPath helper (4 duplicated blocks) Valid refactoring concern, recommended as follow-up PR. Reviewed Principle #5: Bridge, Don't Replace — doesn't cover internal code DRY patterns. View
Communicate Supabase/Neon mutual exclusion in UI UX design decision needs human input on presentation pattern (header, tooltip, banner). Principle #4 and #3 both support showing info but don't specify how. View
Replace 9 useState calls with useMutation Larger state management refactoring recommended as follow-up. Principle #3 doesn't cover internal component patterns. View
Extract ensureNeonAuth helper (3 repetitions) Minor DRY concern, recommend bundling with handler refactoring follow-up. Principle #5 doesn't cover internal DRY patterns. View

Resolved Threads

Issue Rationale Link
Neon SQL execution regression (active→dev fallback removed) Restored neonActiveBranchId ?? neonDevelopmentBranchId fallback. Two duplicate threads resolved. View
DATABASE_URL not synced during version switching Updated updatePostgresUrlEnvVar to update both POSTGRES_URL and DATABASE_URL. View
E2E test selects filtered-out preview branch Changed to select "main" branch (production type, visible in dropdown). View
Silent fallthrough from Neon to Supabase Added explicit DyadError when neonProjectId set but neonActiveBranchId null. View
isProductionBranchActive branch resolution mismatch Now uses neonActiveBranchId ?? neonDevelopmentBranchId matching backend. View
createProject missing env file snapshot Added readEnvFileIfExists snapshot before env injection, restoreEnvFileSnapshot on failure. View
Nested link inside radio button card Replaced <a> with <span role="link"> using window.open to avoid invalid nested interactive elements. View
Invalid JSX comment syntax in auth guide Fixed {/_ _/} to {/* */}. Note: repo formatter auto-reverts this in .md files. View
Missing email param in verification callbackURL Changed callbackURL: pathname to include email query parameter. View
Hardcoded "Guide" badge label (i18n) Added t("guide") with translations for en/pt-BR/zh-CN. View
Product Principle Suggestions

The following suggestions could improve rules/product-principles.md to help resolve ambiguous cases in the future:

  • Principle Query | Question about model availability via OpenRouter #3: Intuitive But Power-User Friendly: "Add guidance on how to communicate mutual exclusion constraints between integrations (e.g., only one database provider at a time) — specify preferred UI patterns (inline notice, disabled state with tooltip, etc.)."
  • New Principle: Internal Code Quality: "Add a principle covering when DRY refactoring should be done inline vs. deferred to follow-up PRs, to help resolve duplication-related review comments without human escalation."

🤖 Generated by Claude Code

cubic-dev-ai[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@dyad-assistant
Copy link
Copy Markdown
Contributor

🔍 Dyadbot Code Review Summary

Verdict: 🤔 NOT SURE - Potential issues

Reviewed by 3 independent agents: Correctness Expert, Code Health Expert, UX Wizard.

Issues Summary

Severity File Issue
🟡 MEDIUM src/components/chat/DyadAddIntegration.tsx:30 selectedProvider ignores requestedProvider prop — UI always pre-selects Supabase even when agent requests Neon
🟡 MEDIUM src/ipc/utils/neon_utils.ts:112 ensureNeonAuth 409 retry failure silently returns undefined, preserving stale auth state from wrong branch
🟡 MEDIUM src/ipc/utils/app_env_var_utils.ts:267 removeNeonEnvVars can't restore pre-existing POSTGRES_URL overwritten during Neon connect
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:279 Outer catch double-wraps non-DyadErrors with misleading "Failed to create" prefix
🟡 MEDIUM src/components/NeonConnector.tsx:238 handleDisconnectAccount doesn't invalidate appEnvVars query (stale UI after disconnect)
🟡 MEDIUM src/components/NeonConnector.tsx:402 Error state divs missing role="alert" for screen reader accessibility
🟡 MEDIUM src/components/MigrationPanel.tsx:106 Disabled migrate button states indistinguishable (pending vs production-branch-active)
🟢 Low Priority Notes (11 items)
  • Logger scope mismatchsrc/ipc/utils/migration_utils.ts: Logger tagged "migration_handlers" doesn't match file name migration_utils
  • Imported logger from wrong modulesrc/ipc/handlers/neon_handlers.ts: Imports logger from neon_utils (inherits wrong scope)
  • Duplicated branch filtersrc/components/NeonConnector.tsx: branches.filter(b => b.type \!== "preview") appears twice
  • Raw provider ID in AI promptsrc/components/chat/DyadAddIntegration.tsx: handleKeepGoingClick sends raw "neon" instead of display name in chat message
  • Asymmetric tool unificationtool_definitions.ts: get_database_table_schema is unified but get_neon_project_info is still provider-specific
  • Redundant branch ownership checksrc/ipc/handlers/neon_handlers.ts: Validates branch belongs to project after getProjectBranch already does this
  • Duplicate drizzle-kit packagingforge.config.ts: drizzle-kit included both in ASAR and as extraResource
  • Badge hierarchy inversionsrc/components/NeonConnector.tsx: Badge uses text-base font-bold creating visual hierarchy conflict with card title
  • Missing state labelssrc/components/DyadReadGuide.tsx: Missing pendingLabel/abortedLabel on DyadStateIndicator
  • Non-string children silently swallowedsrc/components/DyadDbProjectInfo.tsx: Component only handles string children
  • No action on conflict cardsrc/pages/app-details.tsx: UnavailableIntegrationCard shows conflict but offers no path to resolve it
🚫 Dropped False Positives (5 items)
  • UtilityProcess exit code null — Dropped: The null exit code is caught in the timeout path and the process is killed; behavior is safe
  • node_modules symlink layout assumption — Dropped: Speculative concern; the code works with the forge.config.ts layout as configured
  • Auto-dismiss useEffect stale closure — Dropped: Effect cleanup handles the timer correctly; no stale closure issue
  • buildNeonPromptForApp excludes local-agent context — Dropped: Intentional design; local-agent tools fetch context on demand
  • Several items already flagged — Dropped: Already covered by existing review bot comments on this PR

Generated by Dyadbot multi-agent code review

Copy link
Copy Markdown
Contributor

@dyad-assistant dyad-assistant bot left a comment

Choose a reason for hiding this comment

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

Multi-agent review: 7 MEDIUM issues found

Comment thread src/components/chat/DyadAddIntegration.tsx Outdated
logger.warn(
`Neon Auth schema conflict (409) on branch ${branchId}, and retry fetch also failed: ${message}`,
);
return undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | error-handling

ensureNeonAuth silently returns undefined on 409 retry failure

When Neon Auth creation gets a 409 (schema already exists) and the retry getNeonAuth also fails, this silently returns undefined. The caller (autoInjectNeonEnvVars) then sets preserveExistingAuth: true, which preserves stale auth env vars from a different branch. After a branch switch the .env.local may point to the old branch's auth endpoint.

💡 Suggestion: Consider throwing here so the caller can surface the conflict to the user, or at minimum include the branch context in the warning message so users understand why auth may not work.

Comment thread src/ipc/utils/app_env_var_utils.ts
} catch (error: any) {
if (error instanceof DyadError) throw error;
const errorMessage = getNeonErrorMessage(error);
const message = `Failed to create Neon project for app ${appId}: ${errorMessage}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | error-handling

Outer catch double-wraps non-DyadError messages

The inner try block (post-create setup) already throws postCreateError which may itself be a wrapped error with context. The outer catch at this line re-wraps it as "Failed to create Neon project for app ${appId}: ${errorMessage}", losing the original context and producing misleading messages like "Failed to create Neon project: Failed to set active branch: ..." when project creation actually succeeded but a post-creation step failed.

💡 Suggestion: Preserve the original error's message or rethrow directly when the error already has adequate context.

setShowCreateForm(false);
setNewProjectName("");
setCreateProjectError(null);
queryClient.removeQueries({ queryKey: queryKeys.neon.all });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | logic

handleDisconnectAccount doesn't invalidate appEnvVars query

Compare with handleDisconnectProject (line ~213) which correctly calls queryClient.invalidateQueries({ queryKey: queryKeys.appEnvVars.byApp({ appId }) }). This handler calls unsetAppProject (which removes env vars from disk) but never invalidates the cached env vars query, so the UI may show stale Neon env vars after account disconnect until the user navigates away and back.

💡 Suggestion: Add queryClient.invalidateQueries({ queryKey: queryKeys.appEnvVars.byApp({ appId }) }) after the unsetAppProject call.

{t("integrations.neon.activeBranch")}
</Label>
{branchesError ? (
<div className="text-sm text-red-500">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | accessibility

Error state divs missing role="alert" for screen readers

The error messages at lines 402 and 640 use plain <div className="text-red-500"> without role="alert". Screen readers won't announce these errors when they appear, so users relying on assistive technology won't know something went wrong.

💡 Suggestion: Add role="alert" to error container divs:

<div className="text-sm text-red-500" role="alert">


<AlertDialog>
<AlertDialogTrigger
disabled={pushMutation.isPending || isProductionBranchActive}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | accessibility

Disabled migrate button states are indistinguishable

The button is disabled when either pushMutation.isPending or isProductionBranchActive, but the label only changes for the pending state. When disabled because the production branch is active, the button still shows "Migrate to Production" with no explanation of why it's disabled. Users (especially screen reader users) have no indication of what action to take.

💡 Suggestion: Add a tooltip or helper text explaining why the button is disabled, and add aria-describedby pointing to it. For example: "Switch to a development branch to push migrations."`

@github-actions github-actions bot added the needs-human:review-issue ai agent flagged an issue that requires human review label Apr 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🎭 Playwright Test Results

❌ Some tests failed

OS Passed Failed Flaky Skipped
🍎 macOS 266 15 4 6

Summary: 266 passed, 15 failed, 4 flaky, 6 skipped

Failed Tests

🍎 macOS

Show all 15 failures
  • chat_tabs.spec.ts > tabs appear after navigating between chats
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > clicking a tab switches to that chat
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > closing a tab removes it and selects adjacent tab
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > right-click context menu: Close other tabs
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > right-click context menu: Close tabs to the right
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • context_manage.spec.ts > manage context - default
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - smart context
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - smart context - auto-includes only
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - exclude paths
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - exclude paths with smart context
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • local_agent_ask.spec.ts > local-agent ask mode
    • Error: expect(string).toMatchSnapshot(expected) failed
  • local_agent_auto.spec.ts > local-agent - auto model
    • Error: expect(string).toMatchSnapshot(expected) failed
  • local_agent_basic.spec.ts > local-agent - dump request
    • Error: expect(string).toMatchSnapshot(expected) failed
  • per_chat_input.spec.ts > closing a chat tab clears its stored input
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • supabase_stale_ui.spec.ts > supabase - stale ui
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed

📋 Re-run Failing Tests (macOS)

Copy and paste to re-run all failing spec files locally:

npm run e2e \
  e2e-tests/chat_tabs.spec.ts \
  e2e-tests/context_manage.spec.ts \
  e2e-tests/local_agent_ask.spec.ts \
  e2e-tests/local_agent_auto.spec.ts \
  e2e-tests/local_agent_basic.spec.ts \
  e2e-tests/per_chat_input.spec.ts \
  e2e-tests/supabase_stale_ui.spec.ts

⚠️ Flaky Tests

🍎 macOS

  • chat_tabs.spec.ts > only shows tabs for chats opened in current session (passed after 1 retry)
  • custom_apps_folder.spec.ts > new apps are stored in the user's custom folder (passed after 1 retry)
  • local_agent_basic.spec.ts > local-agent - questionnaire flow (passed after 1 retry)
  • setup_flow.spec.ts > Setup Flow > setup banner shows correct state when node.js is installed (passed after 1 retry)

📊 View full report

- Move env file snapshot read inside try/catch to prevent orphan Neon projects on failure
- Stop inferring development branch from arbitrary non-default branches
- Enable email-config query with active-or-development branch fallback
- Initialize selectedProvider from requestedProvider prop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

@azizmejri1
Copy link
Copy Markdown
Collaborator Author

🤖 Claude Code Review Summary

PR Confidence: 3/5

Four code issues were fixed but five refactoring/UX threads remain open for human review, and the PR lacks test coverage as noted by the author.

Unresolved Threads

Thread Rationale Link
Timestamp branch consistency Data consistency concern when active branch switches — needs architectural decision View
App-path DB-fetch-and-guard duplication (4x) Refactoring that touches multiple handler functions — deferred to follow-up View
Supabase/Neon mutual exclusion UX UX design decision on how to communicate provider exclusivity — principles insufficient View
9 useState calls → useMutation refactor Larger refactoring of NeonConnector state management — deferred to follow-up View
ensureNeonAuth + warning-push DRY (3x) Minor DRY concern in createProject — deferred to follow-up View

Resolved Threads

Issue Rationale Link
Env snapshot read outside try/catch leaks orphan projects Moved readEnvFileIfExists inside the try/catch block so failures trigger cleanup View
Arbitrary branch inferred as development Removed fallback to first non-default branch; only name === "development" qualifies View
Email-config query disabled without active branch Added neonDevelopmentBranchId fallback to query enable condition and key View
selectedProvider ignores requestedProvider prop Initialized state from requestedProvider ?? "supabase" as suggested View
Product Principle Suggestions

The following suggestions could improve rules/product-principles.md to help resolve ambiguous cases in the future:

  • Principle Gif for README #1: Backend-Flexible: "Add guidance on how to handle mutual exclusion between database providers in the UI — should both options be shown simultaneously, or should connecting one hide the other?"
  • Principle Does it work for Intel Macs? #4: Transparent Over Magical: "Add guidance on whether refactoring for DRY concerns should be addressed in the same PR or deferred when it doesn't affect correctness."

🤖 Generated by Claude Code

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/ipc/handlers/neon_handlers.ts">

<violation number="1" location="src/ipc/handlers/neon_handlers.ts:111">
P2: Using `null` as the initial env snapshot can delete an existing `.env.local` if snapshot reading fails, because cleanup interprets `null` as “remove file.”</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

const authWarnings: string[] = [];

// Snapshot env file before modification so we can restore on failure
let envFileSnapshot: string | null = null;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Apr 14, 2026

Choose a reason for hiding this comment

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

P2: Using null as the initial env snapshot can delete an existing .env.local if snapshot reading fails, because cleanup interprets null as “remove file.”

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/ipc/handlers/neon_handlers.ts, line 111:

<comment>Using `null` as the initial env snapshot can delete an existing `.env.local` if snapshot reading fails, because cleanup interprets `null` as “remove file.”</comment>

<file context>
@@ -108,10 +108,11 @@ export function registerNeonHandlers() {
 
       // Snapshot env file before modification so we can restore on failure
-      const envFileSnapshot = await readEnvFileIfExists({ appPath });
+      let envFileSnapshot: string | null = null;
 
       // Post-creation steps: if any fail, best-effort delete the orphan project
</file context>
Fix with Cubic

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 22 additional findings in Devin Review.

Open in Devin Review

Comment thread src/components/chat/DyadAddIntegration.tsx
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 32e8e0ee90

ℹ️ About Codex in GitHub

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

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

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

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


## Auth (detailed guide available)

When the task involves authentication, login, sign-up, user sessions, or auth UI, you MUST call the \`read_guide\` tool with guide="add-authentication" BEFORE writing any auth code. Do NOT implement auth without reading the guide first.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict read_guide requirement to local-agent mode

This prompt text makes read_guide mandatory for auth work in all Neon chats, but the same Neon prompt is injected outside local-agent mode where there is no executable read_guide tool path. In build/ask flows, that can cause the model to emit a non-actionable guide step instead of implementing auth changes, stalling the task despite valid user input. Make the hard requirement conditional on local-agent mode (or provide a non-tool equivalent for non-local-agent chats).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I agree on making the hard requirement conditional on local-agent.In build mode, we should inline the full guide content from add-authentication.md and add-email-verification.md if enabled.

queryClient.invalidateQueries({
queryKey: queryKeys.neon.emailPasswordConfig({
appId,
branchId: app?.neonActiveBranchId ?? null,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Invalidate email-config cache with development fallback

The invalidation key uses only neonActiveBranchId, while the actual email-config query key is built from neonActiveBranchId ?? neonDevelopmentBranchId. For upgraded apps where neonActiveBranchId is still null, toggling email verification updates the backend on the development branch but misses the cached query entry, so the UI can keep showing stale verification state until a full reload.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@dyad-assistant dyad-assistant bot left a comment

Choose a reason for hiding this comment

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

Multi-agent review: 1 HIGH and 9 MEDIUM issues identified. See inline comments and summary.


// Post-creation steps: if any fail, best-effort delete the orphan project
try {
envFileSnapshot = await readEnvFileIfExists({ appPath });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 HIGH | data-loss

createProject cleanup can delete user's .env.local when initial snapshot read fails

envFileSnapshot is initialized to null at line 111, and readEnvFileIfExists() is called inside the try block at line 115. If the read throws for a non-ENOENT reason (e.g. EACCES, EPERM, EISDIR, or a file-locking error on Windows), control jumps to the catch at line 232 with envFileSnapshot still null. The catch then calls restoreEnvFileSnapshot({ appPath, snapshot: null }), which executes fs.rm(envFilePath, { force: true }) (see restoreEnvFileSnapshot L44-46) — deleting the user's existing .env.local even though we never successfully read it.

💡 Suggestion: Distinguish "snapshot not taken yet" from "snapshot was absent". Use undefined (or a distinct sentinel) for "never read" and skip the fs.rm branch in that case, or call readEnvFileIfExists() before entering the block whose errors trigger cleanup so a read failure here aborts before any env-file mutation is possible.

if (NEON_ONLY_ENV_VAR_KEYS.includes(envVar.key)) return false;
if (
GENERIC_DB_ENV_VAR_KEYS.includes(envVar.key) &&
envVar.value.includes(".neon.tech")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | data-integrity

removeNeonEnvVars uses .neon.tech substring match to decide whether to delete DATABASE_URL/POSTGRES_URL

On disconnect, DATABASE_URL and POSTGRES_URL are only removed if the value includes the substring ".neon.tech". Two risks:

  1. Stale vars left behind: If a user's connection string uses a non-.neon.tech host (custom pooler, VPC endpoint, private link, etc.), the env vars survive disconnect and leave an invalid/stale URL pointing at an unlinked database.
  2. Wrong var deleted: If a user legitimately has a separate DATABASE_URL whose value happens to include .neon.tech (e.g. a different unrelated Neon project used by another tool), we'd remove it on disconnect.

💡 Suggestion: Track injected env-var keys explicitly (e.g. persist the keys that updateNeonEnvVars wrote), or remove the generic DB keys unconditionally when the handler knows the app had a Neon project linked (which the unsetAppProject call site already knows).

reject(timeoutError);
return;
}
resolve({ stdout, stderr, exitCode: code });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | type-safety

spawnDrizzleKit resolves exitCode as number | null but the Promise is typed as number

Electron's utilityProcess emits 'exit' with code: number | nullnull when the process is terminated by a signal (e.g. proc.kill() from the timeout path, SIGKILL from OOM, external SIGTERM). The resolve({ stdout, stderr, exitCode: code }) at line 204 passes null straight through, violating the declared return type Promise<{ stdout: string; stderr: string; exitCode: number }>.

Current callers (migration_handlers.ts:115, :162) only check exitCode !== 0, so null happens to behave as "non-zero / failed". But the type is lying, and any future caller that does arithmetic or strict comparison will silently break.

💡 Suggestion: Coerce null to a sentinel: resolve({ stdout, stderr, exitCode: code ?? -1 }), or widen the return type to number | null and update callers.

Comment thread src/ipc/handlers/neon_handlers.ts
Comment thread src/pages/app-details.tsx
const result = await ipc.neon.setActiveBranch({ appId, branchId });
const branch = branches.find((b) => b.branchId === branchId);
toast.success(
`${t("integrations.neon.branchSwitched")}: ${branch?.branchName ?? branchId}. ${t("integrations.neon.envUpdated")}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | i18n

Toast message concatenates two translation keys with hard-coded punctuation

`${t("integrations.neon.branchSwitched")}: ${branch?.branchName ?? branchId}. ${t("integrations.neon.envUpdated")}` hard-codes ":" and "." — both wrong for CJK typography (zh-CN uses full-width / ), and the fixed sentence order forces pt-BR into awkward phrasing ("Mudou para a branch: X. DATABASE_URL atualizado…"). Translators cannot reorder the pieces.

💡 Suggestion: Replace with a single interpolated key, e.g. integrations.neon.branchSwitchedWithEnv: "Switched to branch {{branchName}}. DATABASE_URL updated in .env.local." — each locale can then format the full sentence naturally.

setIsOpeningOauth(false);
oauthTimeoutRef.current = null;
toast.warning(t("integrations.neon.signInTimedOut"));
}, 20_000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | error-states

OAuth sign-in timeout is hard-coded 20s with no recovery path

20 seconds is too short in realistic conditions: 2FA prompts, password-manager autofill, slow mobile networks, or simply a user reading the consent screen can all exceed 20s. When the timer fires the UI shows a warning toast and resets isOpeningOauth, but the OAuth handshake may still complete moments later — the neon-oauth-return deep link handler (lines 92-108) will then fire on top of the already-shown warning, producing conflicting UI.

💡 Suggestion: Extend the timeout significantly (e.g. 2+ minutes), downgrade the message to an info/"Still waiting…" affordance, and make the deep-link handler idempotent with a follow-up success toast that supersedes any earlier warning.

aria-label={`Visit ${option.name} website`}
>
<ExternalLink size={12} />
</span>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | accessibility

<span role="link"> with onClick nested inside <button role="radio">

Lines 245-255 render an ExternalLink affordance as <span role="link" onClick=…> inside a <button role="radio">. This is invalid ARIA (interactive inside interactive) and inaccessible:

  • The span has no tabIndex, so it is not keyboard-focusable; Space/Enter on the focused radio selects the radio, not the link.
  • Screen readers announce conflicting roles for the nested interactives.
  • aria-label={Visit ${option.name} website} is also not translated.

💡 Suggestion: Move the external link outside the radio button (e.g., as a sibling in the card header), or at minimum use a real <a href target="_blank" rel="noopener noreferrer"> with tabIndex={0}, keyboard handlers, e.stopPropagation(), and a translated aria-label.

id={errorDetailsId}
className="max-h-64 overflow-auto whitespace-pre-wrap rounded bg-red-100 p-2 font-mono text-xs dark:bg-red-900/40"
>
{errorDetails}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | error-states

Error details reveal raw stack traces and are not localized

When pushMutation.isError, the errorDetails expression at lines 84-89 renders pushMutation.error.stack ?? pushMutation.error.message, and the <pre> block at line 205-211 shows it to the user. For typical migration failures (introspection errors, DyadError(Precondition) from lines 44-91 of migration_handlers.ts, drizzle-kit failures) the stack includes internal file paths and node_modules frames — developer-centric output in a user-facing dialog. errorSummary itself is getErrorMessage(err), which is typically English and not localized.

💡 Suggestion: Map known precondition failures (no tables, active branch == production, etc.) to localized, user-friendly messages, and hide the stack behind an explicit "Copy technical details" action rather than inline-rendering it.

<p className="text-sm text-amber-700 dark:text-amber-300">
{t("integrations.migration.switchBranchHint")}
</p>
)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MEDIUM | interaction-design

Disabled "Migrate to production" button has no adjacent explanation

When isProductionBranchActive is true the button at line 108-112 is disabled, and the "Switch to a non-production branch" hint is rendered after the button at lines 151-155. Users will hover/click the disabled button first and not realize why it's disabled until they scroll past it. There's also no title/tooltip on the disabled button and no aria-describedby linking it to the hint, so assistive-tech users have no explanation at all.

💡 Suggestion: Move the hint above the button (context before the action), add aria-describedby on the disabled button referencing the hint's id, and/or wrap the button in a Tooltip that surfaces the hint on hover/focus.

@dyad-assistant
Copy link
Copy Markdown
Contributor

🔍 Dyadbot Code Review Summary

Verdict: 🤔 NOT SURE - Potential issues to address

Reviewed by 3 independent agents: Correctness Expert, Code Health Expert, UX Wizard. Issues validated via reasoned analysis (not vote counting). Acknowledged follow-up items from the PR description (direct-to-prod SQL, missing destructive-change warnings, default branch as active when no dev branch exists, test coverage) were not flagged.

Issues Summary

Severity File Issue
🔴 HIGH src/ipc/handlers/neon_handlers.ts:115 createProject cleanup can delete user's .env.local if the initial snapshot read throws a non-ENOENT error
🟡 MEDIUM src/ipc/utils/app_env_var_utils.ts:271 removeNeonEnvVars uses .neon.tech substring to decide whether to delete DATABASE_URL/POSTGRES_URL
🟡 MEDIUM src/ipc/utils/migration_utils.ts:204 spawnDrizzleKit resolves exitCode as number | null but is typed as number
🟡 MEDIUM src/ipc/handlers/neon_handlers.ts:538 Env-var-injection rollback block duplicated between setAppProject and setActiveBranch
🟡 MEDIUM src/pages/app-details.tsx:507 Three near-identical mutual-exclusion branches for Supabase/Neon connector rendering
🟡 MEDIUM src/components/NeonConnector.tsx:284 Branch-switch toast concatenates two translation keys with hard-coded punctuation
🟡 MEDIUM src/components/NeonConnector.tsx:134 OAuth sign-in timeout hard-coded to 20s, warning may race with success
🟡 MEDIUM src/components/chat/DyadAddIntegration.tsx:255 <span role="link"> with onClick nested inside <button role="radio"> (invalid ARIA, not keyboard-reachable)
🟡 MEDIUM src/components/MigrationPanel.tsx:210 Error panel renders raw stack traces; errorSummary not localized
🟡 MEDIUM src/components/MigrationPanel.tsx:155 Disabled "Migrate to production" button has no adjacent explanation or aria-describedby
🟢 Low-priority notes (25 items)

Correctness / robustness

  • src/ipc/handlers/migration_handlers.ts:76 \u2014 precondition query SELECT count(*) FROM information_schema.tables also counts views; filter on table_type = 'BASE TABLE' for accuracy.
  • src/ipc/processors/response_processor.ts \u2014 Neon auth-error detection relies on fragile substring matching (\"password authentication failed\", \"access token\"); prefer Postgres error codes when the library exposes them.
  • src/ipc/handlers/neon_handlers.ts:559-599 \u2014 unsetAppProject silently returns success when the app row doesn't exist; setActiveBranch throws NotFound in the same situation \u2014 inconsistent.
  • src/ipc/handlers/neon_handlers.ts:621-623 \u2014 readEnvFileIfExists runs before neonProjectId / preview-branch validation; minor wasted work and surfaces unrelated read failures as generic Neon errors.
  • src/ipc/handlers/neon_handlers.ts setActiveBranch rollback path \u2014 invalidateEmailPasswordConfigCache not called for the target or previous branches on the failure path.
  • src/neon_admin/neon_management_client.ts:471-513 \u2014 module-level emailPasswordConfigCache never cleared on unsetAppProject / account disconnect; 60-s TTL limits exposure.
  • src/pro/main/ipc/handlers/local_agent/tools/execute_sql.ts \u2014 when neonProjectId is set but neonActiveBranchId is null, tool throws a confusing precondition; consider falling back to neonDevelopmentBranchId for robustness.

Code health

  • src/ipc/handlers/neon_handlers.ts:63-74, 439-450, 565-569, 607-618 \u2014 db.select().from(apps) + length check + DyadError(NotFound) pattern repeated 4\u00d7; extract getAppByIdOrThrow.
  • src/ipc/utils/neon_utils.ts:165-195 \u2014 assertNoSupabaseProject and assertNoNeonProject are near-identical; parameterize or extract shared helper.
  • src/neon_admin/neon_context.ts:26-106 \u2014 getBranchRoleName and getBranchDatabaseName share the same fetch-with-fallback shape; warn strings should at minimum be templated by a label.
  • src/neon_admin/neon_prompt_context.ts:64-86 \u2014 buildNeonPromptForApp vs buildNeonPromptAdditions: similar names, unclear when to use which; consider narrowing the public surface.
  • src/ipc/utils/framework_utils.ts:11-42 \u2014 framework detection duplicated with src/ipc/handlers/vercel_handlers.ts:140-189.
  • src/ipc/utils/app_env_var_utils.ts:22-47 \u2014 updatePostgresUrlEnvVar now writes both POSTGRES_URL and DATABASE_URL; the name no longer matches. Consider renaming or adding JSDoc.
  • src/lib/framework_constants.ts:1-2 \u2014 \"vite\" literal flows through multiple type signatures but no Neon code branches on it distinctly from \"other\"; currently latent, but worth a grep-check before next framework-aware feature.
  • src/components/NeonConnector.tsx:73-75 \u2014 new Intl.DateTimeFormat(...) re-allocated on every render; hoist to module scope.
  • src/components/NeonConnector.tsx:72 \u2014 formatToastError is a no-op wrapper around getErrorMessage.
  • src/hooks/useNeon.ts:66-68 \u2014 as NeonAuthEmailAndPasswordConfig | undefined cast should be handled by the contract's return type instead.
  • src/neon_admin/neon_management_client.ts:394-439 \u2014 getNeonErrorMessage nested typeof ... && ... in ... guards could collapse with optional chaining.
  • src/pro/main/ipc/handlers/local_agent/tools/add_integration.ts:4-31 \u2014 \"none\" sentinel in enum duplicates .optional(); drop the literal.
  • src/pro/main/ipc/handlers/local_agent/tools/get_neon_project_info.ts:6-14 \u2014 _reserved placeholder workaround is ad-hoc; centralize a noArgsSchema.
  • src/components/MigrationPanel.tsx:81-89 \u2014 errorSummary / errorDetails computation has unreachable fallback branches when isError === false; guard the whole computation.

UX polish

  • src/components/MigrationPanel.tsx:74-79 \u2014 Success/info banner auto-dismisses after 5 s with no user control; consider manual-dismiss or pause-on-hover.
  • src/components/NeonConnector.tsx:666, 669-671 \u2014 Hard-coded my-app-db placeholder (not translated); Enter submit with empty input gives no feedback.
  • src/components/NeonConnector.tsx:378-392 \u2014 "Open in Neon Console" button is icons-only; add a visible text label at wider widths.
  • src/components/NeonConnector.tsx:558-628 \u2014 "Disconnect" (whole account) button sits beside Refresh with similar weight; dialog title says "Disconnect Neon Account" but trigger says just "Disconnect".
  • src/components/chat/DyadAddIntegration.tsx:124 \u2014 Continue. I have completed the ${completedProvider} integration. uses the raw lowercase provider key, not the display name; also bypasses i18n entirely.
  • src/components/chat/DyadAddIntegration.tsx:30-32, 86-108 \u2014 selectedProvider default biases toward Supabase; radio-group arrow-key handler doesn't support Home/End.
  • src/components/chat/DyadReadGuide.tsx:38-48 \u2014 DyadStateIndicator receives no pendingLabel / abortedLabel, inconsistent with adjacent cards.
  • src/components/preview_panel/PublishPanel.tsx:84-89 \u2014 Migration panel visibility doesn't re-check the Next.js gate used elsewhere in the Neon flow.
  • src/pages/app-details.tsx:59-82 \u2014 UnavailableIntegrationCard hard-codes \"Supabase\" / \"Neon\" and gives no "Disconnect the other provider" CTA.
  • src/i18n/locales/pt-BR/home.json:601-603 \u2014 \"{{provider}} Informa\u00e7\u00f5es do Projeto\" / \"{{provider}} Esquema da Tabela\" reads unnaturally; Portuguese word order should have the provider after the noun.
🚫 Dropped false positives (2 items)
  • DyadAddIntegration.tsx:124 can render "Continue. I have completed the null integration." \u2014 Dropped as a HIGH correctness issue: the "Continue" button only renders inside if (completedProvider) { return <CardA\u2026> } (line 150), so completedProvider is guaranteed non-null at the call site. The i18n concern about the lowercase provider key is retained in Low-priority notes.
  • neon_handlers.ts falls back to production branch as active when no dev branch exists \u2014 Explicitly acknowledged in the PR description (item Query | Question about model availability via OpenRouter #3) as a deliberate simple-setup path; not a review finding.

Generated by Dyadbot multi-agent code review

@github-actions
Copy link
Copy Markdown
Contributor

🎭 Playwright Test Results

❌ Some tests failed

OS Passed Failed Flaky Skipped
🍎 macOS 264 17 2 6

Summary: 264 passed, 17 failed, 2 flaky, 6 skipped

Failed Tests

🍎 macOS

Show all 17 failures
  • chat_tabs.spec.ts > tabs appear after navigating between chats
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > clicking a tab switches to that chat
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > closing a tab removes it and selects adjacent tab
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > right-click context menu: Close other tabs
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > right-click context menu: Close tabs to the right
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • chat_tabs.spec.ts > only shows tabs for chats opened in current session
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • context_manage.spec.ts > manage context - default
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - smart context
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - smart context - auto-includes only
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - exclude paths
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • context_manage.spec.ts > manage context - exclude paths with smart context
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed
  • local_agent_ask.spec.ts > local-agent ask mode
    • Error: expect(string).toMatchSnapshot(expected) failed
  • local_agent_auto.spec.ts > local-agent - auto model
    • Error: expect(string).toMatchSnapshot(expected) failed
  • local_agent_basic.spec.ts > local-agent - dump request
    • Error: expect(string).toMatchSnapshot(expected) failed
  • per_chat_input.spec.ts > chat input is preserved when switching between chats
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • per_chat_input.spec.ts > closing a chat tab clears its stored input
    • TimeoutError: locator.click: Timeout 30000ms exceeded.
  • supabase_stale_ui.spec.ts > supabase - stale ui
    • Error: expect(locator).toMatchAriaSnapshot(expected) failed

📋 Re-run Failing Tests (macOS)

Copy and paste to re-run all failing spec files locally:

npm run e2e \
  e2e-tests/chat_tabs.spec.ts \
  e2e-tests/context_manage.spec.ts \
  e2e-tests/local_agent_ask.spec.ts \
  e2e-tests/local_agent_auto.spec.ts \
  e2e-tests/local_agent_basic.spec.ts \
  e2e-tests/per_chat_input.spec.ts \
  e2e-tests/supabase_stale_ui.spec.ts

⚠️ Flaky Tests

🍎 macOS

  • per_chat_input.spec.ts > input preserved when switching back and forth multiple times (passed after 1 retry)
  • setup_flow.spec.ts > Setup Flow > setup banner shows correct state when node.js is installed (passed after 1 retry)

📊 View full report

Copy link
Copy Markdown
Collaborator

@wwwillchen wwwillchen left a comment

Choose a reason for hiding this comment

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

awesome job! feel free to merge when you think it's ready.

the main thing to watch out for is the inline comment i left about proxy.ts - this could be quite risky if we get wrong because it'll silently not work if the user is on an old next.js version (like the one we use in the next.js template)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

as mentioned in meeting, i think this could be a read_file tool call, but i think this might be nice in the future as it serves as a table of contents for guides, so let's just keep this as-is, thanks.


### Request-Boundary File

Protect routes with \`auth.middleware(...)\`. Reuse the project's existing request-boundary file — current Neon quickstarts use \`proxy.ts\`, older Next.js apps may use \`middleware.ts\`. Reuse whichever exists. Do NOT create both.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

we need to not use proxy.ts if user is on Next.js v15 or earlier. proxy.ts was only added in next.js v16

(app.neonActiveBranchId || app.neonDevelopmentBranchId) && (
<MigrationPanel appId={selectedAppId} />
)}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i think this shoudl be structured so that it guarantees only one migration panel is shown.
i'd first do the check for the regular MigrationPanel and then check for Portal since MigrationPanel should be the main flow going forward.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Image

i don't think the "Migrate to Production" button should be red - it's not necessarily destructive. i think it should be primary color, but there should be a warning banner above the buttons that says: Make sure you have database backups enabled otherwise you cannot undo this.

I think it would also be nice to show the SQL that's being applied in a collapsed accordion so that users can inspect the SQL if they want to.

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

Labels

needs-human:review-issue ai agent flagged an issue that requires human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants