feat(worktree): add per-task DB target env#941
feat(worktree): add per-task DB target env#941naaa760 wants to merge 1 commit intogeneralaction:mainfrom
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@naaa760 is attempting to deploy a commit to the General Action Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR adds per-task database target configuration to worktrees, allowing each task to have its own
Confidence Score: 2/5
|
| Filename | Overview |
|---|---|
| drizzle/0010_add_db_target_to_tasks.sql | Manually created migration file with no corresponding journal entry or snapshot in drizzle/meta/. This violates the project's critical rule to always use drizzle-kit generate for migrations. |
| src/main/db/schema.ts | Adds dbTarget text column to tasks table. Schema change is correct and the column is properly nullable for backward compatibility. |
| src/main/services/DatabaseService.ts | Adds dbTarget to saveTask with careful backward-compatible handling using hasOwnProperty check, and maps it in task row retrieval. |
| src/main/services/TaskLifecycleService.ts | Adds DB lookup in buildLifecycleEnv to pass dbTarget into getTaskEnvVars. Introduces an extra async DB call on every lifecycle env build. |
| src/main/services/ptyManager.ts | Adds DB-related env vars to the PTY forwarding allowlist for SSH and direct spawn paths. Clean implementation using a Set-based check. |
| src/main/services/worktreeIpc.ts | Passes dbTarget through worktree creation by spreading it onto the worktree response object. Ad-hoc approach since WorktreeInfo doesn't have a dbTarget field. |
| src/renderer/components/ChatInterface.tsx | Adds dbTarget to env vars computation and displays a DB target badge in the task header. Uses React's auto-escaping for user input safely. |
| src/renderer/components/TaskAdvancedSettings.tsx | Adds "DB target" textarea field in advanced settings with clear placeholder and description. Follows existing UI patterns. |
| src/renderer/lib/taskCreationService.ts | Threads dbTarget through both single-agent and multi-agent task creation flows, persisting it to DB and worktree creation. |
| src/shared/task/envVars.ts | Core logic for parsing dbTarget (JSON or plain string) and injecting DATABASE_URL, DB_URL, DB_NAME, DATABASE_NAME, DB_PROFILE, DATABASE_PROFILE env vars. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["TaskModal\n(user enters dbTarget)"] --> B["taskCreationService\n(passes dbTarget to IPC)"]
B --> C{"Use worktree?"}
C -- Yes --> D["worktreeIpc\n(worktree:create)"]
D --> E["WorktreeService\ncreateWorktree"]
E --> F["Return worktree + dbTarget"]
C -- No --> F2["Use project path directly"]
F --> G["DatabaseService.saveTask\n(persist dbTarget to DB)"]
F2 --> G
G --> H["Task activated in UI"]
H --> I["getTaskEnvVars\n(parseDbTarget)"]
I --> J{"JSON or\nplain string?"}
J -- JSON --> K["Extract url, name, profile"]
J -- Plain string --> L["Treat as url"]
K --> M["Set DATABASE_URL, DB_URL,\nDB_NAME, DATABASE_NAME,\nDB_PROFILE, DATABASE_PROFILE"]
L --> M
M --> N["PTY Manager\n(shouldForwardTaskEnvVar)"]
N --> O["Terminal / Agent Process"]
Last reviewed commit: 2c51390
| ALTER TABLE `tasks` ADD COLUMN `db_target` text; | ||
| --> statement-breakpoint |
There was a problem hiding this comment.
Manually created migration file
This migration file was created manually without running drizzle-kit generate. The drizzle/meta/_journal.json has no entry for 0010_add_db_target_to_tasks (it stops at idx 9 / 0009_add_ssh_support), and there is no corresponding snapshot file in drizzle/meta/.
Per the project's critical rules in CLAUDE.md: "NEVER modify drizzle/meta/ or numbered migration files — always use drizzle-kit generate". While this rule focuses on modifying existing files, the intended workflow is to always generate migrations via drizzle-kit generate after modifying schema.ts. A hand-written migration without the journal/snapshot metadata will cause Drizzle's migration runner to skip this file, meaning the db_target column will never be added to existing databases.
Please run pnpm exec drizzle-kit generate after the schema change to produce a properly tracked migration.
Context Used: Context from dashboard - CLAUDE.md (source)
| function parseDbTarget(dbTarget: string | null | undefined): DbTargetConfig | null { | ||
| if (!dbTarget) return null; | ||
|
|
||
| try { | ||
| const parsed = JSON.parse(dbTarget); | ||
| if (typeof parsed === 'object' && parsed !== null) { | ||
| return parsed as DbTargetConfig; | ||
| } | ||
| } catch { | ||
| return { url: dbTarget }; | ||
| } | ||
|
|
||
| return null; | ||
| } |
There was a problem hiding this comment.
Valid JSON object parsed as string falls through silently
When the input is a valid JSON value that is not an object (e.g., a JSON array ["a","b"] or a JSON number 42), JSON.parse succeeds but the typeof parsed === 'object' check passes for arrays (since typeof [] === 'object'). An array input would be cast to DbTargetConfig and then properties like .url would be undefined, causing silent no-op behavior. Consider adding an !Array.isArray(parsed) check:
| function parseDbTarget(dbTarget: string | null | undefined): DbTargetConfig | null { | |
| if (!dbTarget) return null; | |
| try { | |
| const parsed = JSON.parse(dbTarget); | |
| if (typeof parsed === 'object' && parsed !== null) { | |
| return parsed as DbTargetConfig; | |
| } | |
| } catch { | |
| return { url: dbTarget }; | |
| } | |
| return null; | |
| } | |
| function parseDbTarget(dbTarget: string | null | undefined): DbTargetConfig | null { | |
| if (!dbTarget) return null; | |
| try { | |
| const parsed = JSON.parse(dbTarget); | |
| if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) { | |
| return parsed as DbTargetConfig; | |
| } | |
| } catch { | |
| return { url: dbTarget }; | |
| } | |
| return null; | |
| } |
| args.baseRef | ||
| ); | ||
| return { success: true, worktree }; | ||
| return { success: true, worktree: { ...worktree, dbTarget: args.dbTarget ?? null } }; |
There was a problem hiding this comment.
dbTarget not persisted to task in worktreeIpc
For the local (non-remote) worktree creation path, dbTarget is spread onto the returned worktree object as an ad-hoc property ({ ...worktree, dbTarget: args.dbTarget ?? null }). The WorktreeInfo interface returned by worktreeService.createWorktree() does not include dbTarget, so this relies on the untyped worktree?: any return type in the IPC definition.
This works at runtime because taskCreationService.ts reads worktree.dbTarget from the response, but it's fragile — if WorktreeInfo is ever typed more strictly at the IPC boundary, this will silently break. Consider either adding dbTarget to WorktreeInfo or documenting that this field is only passed through via the IPC response (not a worktree property).
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
add per-worktree database target configuration
Problem
Solution
Usage
Backward compatibility
fix : #935