feat: add prompt templates feature#1844
feat: add prompt templates feature#1844Prethish-Kumar wants to merge 4 commits intogeneralaction:mainfrom
Conversation
Replace the single reviewPrompt app setting with a dedicated prompt_templates database table, full CRUD in Settings, and multi-template buttons in the ContextBar. - New SQLite table with Drizzle ORM and auto-generated migration - PromptTemplateService with full CRUD, validation, and atomic reorder tx - RPC controller registered under promptTemplates namespace - React Query hook usePromptTemplates for list/create/update/delete/reorder - New 'Prompts' tab in Settings with CRUD UI, reorder, duplicate, delete - ContextBar renders a button per template with one-click paste into chat - Migrate existing reviewPrompt setting into first template on startup - Seed 4 default starter templates for new users - Add empty state with starter quick-add buttons - Add inline delete confirmation - Add character counts on name and text inputs - Update context-actions tests for template-based actions
Greptile SummaryThis PR replaces the single
Confidence Score: 4/5Safe to merge with the ContextBar overflow fixed before the feature ships broadly One P1 finding: the ContextBar renders all template buttons in a non-scrolling fixed-height row, making templates unreachable past ~5–8 items. Backend logic and migration are solid. Score is capped at 4 by the P1. src/renderer/features/tasks/conversations/context-bar.tsx — needs overflow handling for the template button row
|
| Filename | Overview |
|---|---|
| src/renderer/features/tasks/conversations/context-bar.tsx | Renders all template buttons in a fixed-height flex row with no overflow handling; with 20 max templates the bar will clip, making buttons inaccessible |
| src/main/core/prompt-templates/service.ts | CRUD service with validation, server-side cap, and atomic reorder transaction; validation gap — subset reorder is silently accepted |
| src/main/core/prompt-templates/service.test.ts | 10 well-structured service tests; missing coverage for MAX_PROMPT_TEMPLATES enforcement |
| src/shared/prompt-templates.ts | Shared constants and interfaces correctly deduplicated; both service and frontend now import from this single source |
| src/main/index.ts | Migration from reviewPrompt to templates is safe; seeds STARTER_PROMPT_TEMPLATES on first run |
| src/renderer/features/settings/components/PromptTemplatesSettingsCard.tsx | Full CRUD UI with inline confirmation, character counts, and starter quick-add; imports from shared constants |
| src/renderer/features/settings/use-prompt-templates.ts | React Query hook wiring create/update/delete/reorder mutations with cache invalidation; looks correct |
| drizzle/0008_harsh_overlord.sql | New prompt_templates table with correct schema and sort_order index |
| src/main/core/prompt-templates/controller.ts | Thin RPC controller delegating all calls to the service; no issues |
Sequence Diagram
sequenceDiagram
participant UI as PromptTemplatesSettingsCard
participant Hook as usePromptTemplates
participant RPC as promptTemplatesController
participant Svc as PromptTemplateService
participant DB as SQLite (prompt_templates)
UI->>Hook: create(name, text)
Hook->>RPC: rpc.promptTemplates.create(input)
RPC->>Svc: create(input)
Svc->>DB: SELECT COUNT(*) cap check
Svc->>DB: SELECT MAX(sort_order)
Svc->>DB: INSERT
Svc-->>RPC: PromptTemplate
RPC-->>Hook: PromptTemplate
Hook->>Hook: invalidateQueries(['promptTemplates'])
UI->>Hook: reorder([id2, id1])
Hook->>RPC: rpc.promptTemplates.reorder(ids)
RPC->>Svc: reorder(ids)
Svc->>DB: SELECT id WHERE id IN (...)
Svc->>DB: TRANSACTION UPDATE sort_order per id
Svc-->>RPC: void
Note over UI,DB: ContextBar also calls usePromptTemplates and renders one button per template
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
src/renderer/features/tasks/conversations/context-bar.tsx:59-81
**ContextBar overflows with many templates**
The template buttons are rendered in a single fixed-height flex row (`h-[41px]`) without `overflow-x-auto` or any wrapping strategy. With the service cap at 20 templates and each button being roughly 80–130 px wide, users with more than ~5–8 templates will see buttons clipped at the edge of the bar with no way to reach them — making those templates permanently inaccessible without reducing the count. Consider adding `overflow-x-auto` to the container div, or capping the number of rendered template buttons in the UI regardless of the stored count.
### Issue 2 of 3
src/main/core/prompt-templates/service.ts:126-133
**Partial reorder silently accepted when IDs are a subset of all templates**
The guard validates that every ID in the input exists in the DB, but it does not check that the input covers *all* templates. A caller can pass a valid subset of IDs and only those rows get their `sort_order` updated — the omitted templates retain their old values, silently creating an inconsistent ordering. Given that the UI always sends the full list this is currently benign, but the service contract is weaker than the PR description implies.
```suggestion
const [totalRow] = await this.db.select({ value: count() }).from(promptTemplates);
if (ids.length !== totalRow.value) {
throw new Error('Reorder list must include all existing prompt templates');
}
const existingRows = await this.db
.select({ id: promptTemplates.id })
.from(promptTemplates)
.where(inArray(promptTemplates.id, ids));
if (existingRows.length !== ids.length) {
throw new Error('One or more prompt templates were not found');
}
```
### Issue 3 of 3
src/main/core/prompt-templates/service.test.ts:67-71
**No test for the MAX_PROMPT_TEMPLATES server-side cap**
The service now enforces a server-side cap in `create()`, but none of the tests exercise that path. A test that creates 20 templates and then expects the 21st call to reject would confirm the guard is actually reachable.
```suggestion
it('rejects text over 4000 chars', async () => {
await expect(service.create({ name: 'valid', text: 'x'.repeat(4001) })).rejects.toThrow(
'Template text must be 4000 characters or fewer'
);
});
it('rejects create when template limit is reached', async () => {
const { MAX_PROMPT_TEMPLATES } = await import('@shared/prompt-templates');
for (let i = 0; i < MAX_PROMPT_TEMPLATES; i++) {
await service.create({ name: `T${i}`, text: 'text' });
}
await expect(service.create({ name: 'Over', text: 'limit' })).rejects.toThrow(
`You can create up to ${MAX_PROMPT_TEMPLATES} templates`
);
});
```
Reviews (2): Last reviewed commit: "fix: address prompt template review gaps" | Re-trigger Greptile
|
@greptile |
Summary
Replace the single global
reviewPromptsetting workflow with a Prompt Templates system. Users can create, edit, reorder, and delete reusable prompt templates, then insert them from one-click actions in the task ContextBar.PR Review Gaps Addressed
MAX_PROMPT_TEMPLATES) so direct RPC calls cannot bypass UI limits.update()and now return the updated model from known state.reorder()to validate payload integrity:src/shared/prompt-templates.tsso main-process seeding and renderer empty-state stay in sync.Final Polish Before Merge
aria-labels to icon-only actions in template settings.What changed
prompt_templatesSQLite table with Drizzle ORM schema + auto-generated migration.PromptTemplateServicewith CRUD, validation, and atomicreordertransaction + RPC controller.usePromptTemplatesReact Query hookreviewPromptvalue is migrated to the first template on startup; new users get 4 starter templates.ReviewPromptSettingsCard.tsx; legacyreviewPromptschema/default remains for compatibility/migration.context-actions.test.ts.Validation
pnpm run format✅pnpm run lint✅ (0 errors; existing warnings only)pnpm run typecheck✅pnpm run test✅ (73/73 files, 490 tests)