opencastle 0.9.2 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +12 -69
  2. package/dist/cli/doctor.d.ts.map +1 -1
  3. package/dist/cli/doctor.js +13 -7
  4. package/dist/cli/doctor.js.map +1 -1
  5. package/dist/cli/init.d.ts.map +1 -1
  6. package/dist/cli/init.js +2 -1
  7. package/dist/cli/init.js.map +1 -1
  8. package/dist/cli/init.test.d.ts +17 -0
  9. package/dist/cli/init.test.d.ts.map +1 -0
  10. package/dist/cli/init.test.js +881 -0
  11. package/dist/cli/init.test.js.map +1 -0
  12. package/dist/cli/mcp.d.ts +9 -0
  13. package/dist/cli/mcp.d.ts.map +1 -1
  14. package/dist/cli/mcp.js +56 -0
  15. package/dist/cli/mcp.js.map +1 -1
  16. package/dist/cli/run/adapters/copilot.d.ts +10 -2
  17. package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
  18. package/dist/cli/run/adapters/copilot.js +83 -56
  19. package/dist/cli/run/adapters/copilot.js.map +1 -1
  20. package/dist/cli/run.js +2 -2
  21. package/dist/cli/run.js.map +1 -1
  22. package/dist/cli/stack-config-update.test.d.ts +2 -0
  23. package/dist/cli/stack-config-update.test.d.ts.map +1 -0
  24. package/dist/cli/stack-config-update.test.js +185 -0
  25. package/dist/cli/stack-config-update.test.js.map +1 -0
  26. package/dist/cli/stack-config.d.ts +27 -0
  27. package/dist/cli/stack-config.d.ts.map +1 -1
  28. package/dist/cli/stack-config.js +80 -27
  29. package/dist/cli/stack-config.js.map +1 -1
  30. package/dist/cli/types.d.ts +1 -1
  31. package/dist/cli/types.d.ts.map +1 -1
  32. package/dist/cli/update.d.ts.map +1 -1
  33. package/dist/cli/update.js +184 -17
  34. package/dist/cli/update.js.map +1 -1
  35. package/dist/orchestrator/plugins/astro/config.d.ts +3 -0
  36. package/dist/orchestrator/plugins/astro/config.d.ts.map +1 -0
  37. package/dist/orchestrator/plugins/astro/config.js +27 -0
  38. package/dist/orchestrator/plugins/astro/config.js.map +1 -0
  39. package/dist/orchestrator/plugins/chrome-devtools/config.js +2 -2
  40. package/dist/orchestrator/plugins/chrome-devtools/config.js.map +1 -1
  41. package/dist/orchestrator/plugins/contentful/config.js +1 -1
  42. package/dist/orchestrator/plugins/contentful/config.js.map +1 -1
  43. package/dist/orchestrator/plugins/convex/config.js +1 -1
  44. package/dist/orchestrator/plugins/convex/config.js.map +1 -1
  45. package/dist/orchestrator/plugins/cypress/config.d.ts +3 -0
  46. package/dist/orchestrator/plugins/cypress/config.d.ts.map +1 -0
  47. package/dist/orchestrator/plugins/cypress/config.js +15 -0
  48. package/dist/orchestrator/plugins/cypress/config.js.map +1 -0
  49. package/dist/orchestrator/plugins/figma/config.d.ts +3 -0
  50. package/dist/orchestrator/plugins/figma/config.d.ts.map +1 -0
  51. package/dist/orchestrator/plugins/figma/config.js +33 -0
  52. package/dist/orchestrator/plugins/figma/config.js.map +1 -0
  53. package/dist/orchestrator/plugins/index.d.ts.map +1 -1
  54. package/dist/orchestrator/plugins/index.js +20 -0
  55. package/dist/orchestrator/plugins/index.js.map +1 -1
  56. package/dist/orchestrator/plugins/jira/config.d.ts.map +1 -1
  57. package/dist/orchestrator/plugins/jira/config.js +2 -3
  58. package/dist/orchestrator/plugins/jira/config.js.map +1 -1
  59. package/dist/orchestrator/plugins/linear/config.js +2 -2
  60. package/dist/orchestrator/plugins/linear/config.js.map +1 -1
  61. package/dist/orchestrator/plugins/netlify/config.d.ts +3 -0
  62. package/dist/orchestrator/plugins/netlify/config.d.ts.map +1 -0
  63. package/dist/orchestrator/plugins/netlify/config.js +30 -0
  64. package/dist/orchestrator/plugins/netlify/config.js.map +1 -0
  65. package/dist/orchestrator/plugins/nextjs/config.d.ts +3 -0
  66. package/dist/orchestrator/plugins/nextjs/config.d.ts.map +1 -0
  67. package/dist/orchestrator/plugins/nextjs/config.js +35 -0
  68. package/dist/orchestrator/plugins/nextjs/config.js.map +1 -0
  69. package/dist/orchestrator/plugins/nx/config.d.ts.map +1 -1
  70. package/dist/orchestrator/plugins/nx/config.js +2 -3
  71. package/dist/orchestrator/plugins/nx/config.js.map +1 -1
  72. package/dist/orchestrator/plugins/playwright/config.d.ts +3 -0
  73. package/dist/orchestrator/plugins/playwright/config.d.ts.map +1 -0
  74. package/dist/orchestrator/plugins/playwright/config.js +25 -0
  75. package/dist/orchestrator/plugins/playwright/config.js.map +1 -0
  76. package/dist/orchestrator/plugins/prisma/config.d.ts +3 -0
  77. package/dist/orchestrator/plugins/prisma/config.d.ts.map +1 -0
  78. package/dist/orchestrator/plugins/prisma/config.js +25 -0
  79. package/dist/orchestrator/plugins/prisma/config.js.map +1 -0
  80. package/dist/orchestrator/plugins/resend/config.d.ts +3 -0
  81. package/dist/orchestrator/plugins/resend/config.d.ts.map +1 -0
  82. package/dist/orchestrator/plugins/resend/config.js +46 -0
  83. package/dist/orchestrator/plugins/resend/config.js.map +1 -0
  84. package/dist/orchestrator/plugins/sanity/config.d.ts.map +1 -1
  85. package/dist/orchestrator/plugins/sanity/config.js +1 -2
  86. package/dist/orchestrator/plugins/sanity/config.js.map +1 -1
  87. package/dist/orchestrator/plugins/slack/config.js +1 -1
  88. package/dist/orchestrator/plugins/slack/config.js.map +1 -1
  89. package/dist/orchestrator/plugins/strapi/config.js +1 -1
  90. package/dist/orchestrator/plugins/strapi/config.js.map +1 -1
  91. package/dist/orchestrator/plugins/supabase/config.d.ts.map +1 -1
  92. package/dist/orchestrator/plugins/supabase/config.js +1 -2
  93. package/dist/orchestrator/plugins/supabase/config.js.map +1 -1
  94. package/dist/orchestrator/plugins/teams/config.d.ts.map +1 -1
  95. package/dist/orchestrator/plugins/teams/config.js +1 -2
  96. package/dist/orchestrator/plugins/teams/config.js.map +1 -1
  97. package/dist/orchestrator/plugins/turborepo/config.d.ts +3 -0
  98. package/dist/orchestrator/plugins/turborepo/config.d.ts.map +1 -0
  99. package/dist/orchestrator/plugins/turborepo/config.js +15 -0
  100. package/dist/orchestrator/plugins/turborepo/config.js.map +1 -0
  101. package/dist/orchestrator/plugins/types.d.ts +7 -7
  102. package/dist/orchestrator/plugins/types.d.ts.map +1 -1
  103. package/dist/orchestrator/plugins/vercel/config.d.ts.map +1 -1
  104. package/dist/orchestrator/plugins/vercel/config.js +2 -3
  105. package/dist/orchestrator/plugins/vercel/config.js.map +1 -1
  106. package/dist/orchestrator/plugins/vitest/config.d.ts +3 -0
  107. package/dist/orchestrator/plugins/vitest/config.d.ts.map +1 -0
  108. package/dist/orchestrator/plugins/vitest/config.js +15 -0
  109. package/dist/orchestrator/plugins/vitest/config.js.map +1 -0
  110. package/package.json +2 -1
  111. package/src/cli/doctor.ts +14 -7
  112. package/src/cli/init.test.ts +1141 -0
  113. package/src/cli/init.ts +2 -1
  114. package/src/cli/mcp.ts +77 -1
  115. package/src/cli/run/adapters/copilot.ts +86 -58
  116. package/src/cli/run.ts +2 -2
  117. package/src/cli/stack-config-update.test.ts +210 -0
  118. package/src/cli/stack-config.ts +110 -37
  119. package/src/cli/types.ts +1 -1
  120. package/src/cli/update.ts +230 -23
  121. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  122. package/src/orchestrator/agents/api-designer.agent.md +1 -11
  123. package/src/orchestrator/agents/architect.agent.md +1 -9
  124. package/src/orchestrator/agents/content-engineer.agent.md +1 -5
  125. package/src/orchestrator/agents/copywriter.agent.md +1 -9
  126. package/src/orchestrator/agents/data-expert.agent.md +2 -6
  127. package/src/orchestrator/agents/database-engineer.agent.md +1 -6
  128. package/src/orchestrator/agents/developer.agent.md +2 -12
  129. package/src/orchestrator/agents/devops-expert.agent.md +1 -5
  130. package/src/orchestrator/agents/documentation-writer.agent.md +1 -4
  131. package/src/orchestrator/agents/performance-expert.agent.md +1 -5
  132. package/src/orchestrator/agents/release-manager.agent.md +1 -11
  133. package/src/orchestrator/agents/researcher.agent.md +1 -4
  134. package/src/orchestrator/agents/security-expert.agent.md +2 -7
  135. package/src/orchestrator/agents/seo-specialist.agent.md +1 -10
  136. package/src/orchestrator/agents/testing-expert.agent.md +2 -11
  137. package/src/orchestrator/agents/ui-ux-expert.agent.md +3 -10
  138. package/src/orchestrator/customizations/README.md +2 -1
  139. package/src/orchestrator/customizations/agents/skill-matrix.json +106 -0
  140. package/src/orchestrator/customizations/agents/skill-matrix.md +58 -121
  141. package/src/orchestrator/instructions/general.instructions.md +1 -1
  142. package/src/orchestrator/plugins/astro/SKILL.md +288 -0
  143. package/src/orchestrator/plugins/astro/config.ts +28 -0
  144. package/src/orchestrator/plugins/chrome-devtools/config.ts +2 -2
  145. package/src/orchestrator/plugins/contentful/config.ts +1 -1
  146. package/src/orchestrator/plugins/convex/config.ts +1 -1
  147. package/src/orchestrator/plugins/cypress/SKILL.md +145 -0
  148. package/src/orchestrator/plugins/cypress/config.ts +16 -0
  149. package/src/orchestrator/plugins/figma/SKILL.md +85 -0
  150. package/src/orchestrator/plugins/figma/config.ts +34 -0
  151. package/src/orchestrator/plugins/index.ts +20 -0
  152. package/src/orchestrator/plugins/jira/config.ts +2 -3
  153. package/src/orchestrator/plugins/linear/config.ts +2 -2
  154. package/src/orchestrator/plugins/netlify/SKILL.md +134 -0
  155. package/src/orchestrator/plugins/netlify/config.ts +31 -0
  156. package/src/orchestrator/plugins/nextjs/SKILL.md +376 -0
  157. package/src/orchestrator/plugins/nextjs/config.ts +36 -0
  158. package/src/orchestrator/plugins/nx/config.ts +2 -3
  159. package/src/orchestrator/plugins/playwright/SKILL.md +191 -0
  160. package/src/orchestrator/plugins/playwright/config.ts +26 -0
  161. package/src/orchestrator/plugins/prisma/SKILL.md +137 -0
  162. package/src/orchestrator/plugins/prisma/config.ts +26 -0
  163. package/src/orchestrator/plugins/resend/SKILL.md +187 -0
  164. package/src/orchestrator/plugins/resend/config.ts +47 -0
  165. package/src/orchestrator/plugins/sanity/config.ts +1 -2
  166. package/src/orchestrator/plugins/slack/config.ts +1 -1
  167. package/src/orchestrator/plugins/strapi/config.ts +1 -1
  168. package/src/orchestrator/plugins/supabase/config.ts +1 -2
  169. package/src/orchestrator/plugins/teams/config.ts +1 -2
  170. package/src/orchestrator/plugins/turborepo/SKILL.md +121 -0
  171. package/src/orchestrator/plugins/turborepo/config.ts +16 -0
  172. package/src/orchestrator/plugins/types.ts +7 -7
  173. package/src/orchestrator/plugins/vercel/SKILL.md +99 -0
  174. package/src/orchestrator/plugins/vercel/config.ts +2 -3
  175. package/src/orchestrator/plugins/vitest/SKILL.md +166 -0
  176. package/src/orchestrator/plugins/vitest/config.ts +16 -0
  177. package/src/orchestrator/prompts/bootstrap-customizations.prompt.md +6 -4
  178. package/src/orchestrator/prompts/create-skill.prompt.md +6 -7
  179. package/src/orchestrator/prompts/generate-task-spec.prompt.md +1 -1
  180. package/src/orchestrator/skills/agent-hooks/SKILL.md +2 -2
  181. package/src/orchestrator/skills/memory-merger/SKILL.md +1 -1
  182. package/src/orchestrator/skills/nextjs-patterns/SKILL.md +0 -200
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: prisma-database
3
+ description: "Prisma ORM schema design, migrations, client generation, and query patterns. Use when designing database schemas, writing migrations, querying data, or managing Prisma Client."
4
+ ---
5
+
6
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .github/customizations/ directory instead. -->
7
+
8
+ # Prisma Database
9
+
10
+ Prisma-specific schema design, migration, and query patterns. For project-specific database schema and connection details, see [database-config.md](../../customizations/stack/database-config.md).
11
+
12
+ ## Commands
13
+
14
+ ```bash
15
+ npx prisma init # Initialize Prisma in the project
16
+ npx prisma generate # Generate Prisma Client from schema
17
+ npx prisma migrate dev # Create and apply migration (dev)
18
+ npx prisma migrate deploy # Apply pending migrations (production)
19
+ npx prisma migrate reset # Reset database and apply all migrations
20
+ npx prisma db push # Push schema changes without migration
21
+ npx prisma db pull # Introspect database into schema
22
+ npx prisma db seed # Run seed script
23
+ npx prisma studio # Open visual database editor
24
+ npx prisma format # Format schema file
25
+ npx prisma validate # Validate schema syntax
26
+ ```
27
+
28
+ ## Schema Design
29
+
30
+ ```prisma
31
+ // prisma/schema.prisma
32
+ generator client {
33
+ provider = "prisma-client-js"
34
+ }
35
+
36
+ datasource db {
37
+ provider = "postgresql"
38
+ url = env("DATABASE_URL")
39
+ }
40
+
41
+ model User {
42
+ id String @id @default(cuid())
43
+ email String @unique
44
+ name String?
45
+ posts Post[]
46
+ createdAt DateTime @default(now())
47
+ updatedAt DateTime @updatedAt
48
+
49
+ @@index([email])
50
+ @@map("users")
51
+ }
52
+
53
+ model Post {
54
+ id String @id @default(cuid())
55
+ title String
56
+ content String?
57
+ published Boolean @default(false)
58
+ author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
59
+ authorId String
60
+
61
+ @@index([authorId])
62
+ @@map("posts")
63
+ }
64
+ ```
65
+
66
+ ### Schema Best Practices
67
+
68
+ - Use `cuid()` or `uuid()` for IDs — never auto-increment in distributed systems
69
+ - Always add `createdAt` and `updatedAt` timestamps
70
+ - Use `@map` and `@@map` to control database table/column names
71
+ - Add `@@index` for frequently queried columns
72
+ - Use `onDelete: Cascade` where appropriate
73
+ - Define relations explicitly with `@relation`
74
+ - Use enums for constrained string values
75
+
76
+ ## Migration Rules
77
+
78
+ 1. Always use `prisma migrate dev` in development — never `db push` for schema changes that need history
79
+ 2. Name migrations descriptively: `npx prisma migrate dev --name add_reviews_table`
80
+ 3. Review generated SQL before applying — Prisma auto-generates but may need manual adjustments
81
+ 4. Test migrations locally before deploying
82
+ 5. Use `prisma migrate deploy` in CI/CD — never `migrate dev` in production
83
+ 6. Write seed scripts for development data in `prisma/seed.ts`
84
+ 7. Never edit applied migration files — create new migrations instead
85
+ 8. Run `prisma generate` after every schema change to update the client
86
+
87
+ ## Query Patterns
88
+
89
+ ### Basic CRUD
90
+
91
+ ```typescript
92
+ import { PrismaClient } from '@prisma/client';
93
+ const prisma = new PrismaClient();
94
+
95
+ // Create
96
+ const user = await prisma.user.create({
97
+ data: { email: 'user@example.com', name: 'Alice' },
98
+ });
99
+
100
+ // Read (with relations)
101
+ const userWithPosts = await prisma.user.findUnique({
102
+ where: { id: userId },
103
+ include: { posts: true },
104
+ });
105
+
106
+ // Update
107
+ const updated = await prisma.user.update({
108
+ where: { id: userId },
109
+ data: { name: 'Updated Name' },
110
+ });
111
+
112
+ // Delete
113
+ await prisma.user.delete({ where: { id: userId } });
114
+ ```
115
+
116
+ ### Singleton Pattern
117
+
118
+ ```typescript
119
+ // lib/prisma.ts
120
+ import { PrismaClient } from '@prisma/client';
121
+
122
+ const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
123
+
124
+ export const prisma = globalForPrisma.prisma ?? new PrismaClient();
125
+
126
+ if (process.env.NODE_ENV !== 'production') {
127
+ globalForPrisma.prisma = prisma;
128
+ }
129
+ ```
130
+
131
+ ### Best Practices
132
+
133
+ - Always use the singleton pattern to avoid connection pool exhaustion
134
+ - Use `select` instead of `include` when you only need specific fields
135
+ - Use transactions (`prisma.$transaction`) for multi-step operations
136
+ - Paginate large result sets with `skip` and `take`
137
+ - Handle unique constraint violations with try/catch on `P2002` error code
@@ -0,0 +1,26 @@
1
+ import type { PluginConfig } from '../types.js';
2
+
3
+ export const config: PluginConfig = {
4
+ id: 'prisma',
5
+ name: 'Prisma',
6
+ category: 'tech',
7
+ subCategory: 'database',
8
+ label: 'Prisma',
9
+ hint: 'Type-safe ORM, migrations, schema management',
10
+ skillName: 'prisma-database',
11
+ mcpServerKey: 'Prisma',
12
+ mcpConfig: {
13
+ type: 'stdio',
14
+ command: 'npx',
15
+ args: ['-y', '@anthropic/prisma-mcp@latest'],
16
+ },
17
+ authType: 'none',
18
+ envVars: [],
19
+ agentToolMap: {
20
+ 'database-engineer': ['prisma/*'],
21
+ 'developer': ['prisma/*'],
22
+ },
23
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#prisma',
24
+ officialDocs: 'https://www.prisma.io/docs',
25
+ mcpPackage: '@anthropic/prisma-mcp',
26
+ };
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: resend-email
3
+ description: "Resend transactional email patterns, React Email templates, domain configuration, and webhook handling. Use when sending emails, building email templates, or configuring email delivery."
4
+ ---
5
+
6
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .github/customizations/ directory instead. -->
7
+
8
+ # Resend Email
9
+
10
+ Resend-specific email sending patterns and React Email template conventions.
11
+
12
+ ## Setup
13
+
14
+ ```bash
15
+ npm install resend
16
+ npm install @react-email/components # For React Email templates
17
+ ```
18
+
19
+ ### Client Initialization
20
+
21
+ ```typescript
22
+ // lib/resend.ts
23
+ import { Resend } from 'resend';
24
+
25
+ if (!process.env.RESEND_API_KEY) {
26
+ throw new Error('RESEND_API_KEY is required');
27
+ }
28
+
29
+ export const resend = new Resend(process.env.RESEND_API_KEY);
30
+ ```
31
+
32
+ ## Sending Emails
33
+
34
+ ### Basic Send
35
+
36
+ ```typescript
37
+ import { resend } from '@/lib/resend';
38
+
39
+ await resend.emails.send({
40
+ from: 'App <no-reply@yourdomain.com>',
41
+ to: ['user@example.com'],
42
+ subject: 'Welcome to our app',
43
+ html: '<p>Welcome! Your account is ready.</p>',
44
+ });
45
+ ```
46
+
47
+ ### With React Email Template
48
+
49
+ ```typescript
50
+ import { resend } from '@/lib/resend';
51
+ import { WelcomeEmail } from '@/emails/welcome';
52
+
53
+ await resend.emails.send({
54
+ from: 'App <no-reply@yourdomain.com>',
55
+ to: ['user@example.com'],
56
+ subject: 'Welcome to our app',
57
+ react: WelcomeEmail({ name: 'Alice' }),
58
+ });
59
+ ```
60
+
61
+ ## React Email Templates
62
+
63
+ ### Template Structure
64
+
65
+ ```
66
+ emails/
67
+ ├── welcome.tsx
68
+ ├── password-reset.tsx
69
+ ├── invoice.tsx
70
+ └── components/
71
+ ├── header.tsx
72
+ ├── footer.tsx
73
+ └── button.tsx
74
+ ```
75
+
76
+ ### Template Pattern
77
+
78
+ ```tsx
79
+ // emails/welcome.tsx
80
+ import {
81
+ Html, Head, Body, Container, Section,
82
+ Heading, Text, Button, Img, Hr,
83
+ } from '@react-email/components';
84
+
85
+ interface WelcomeEmailProps {
86
+ name: string;
87
+ loginUrl?: string;
88
+ }
89
+
90
+ export function WelcomeEmail({
91
+ name,
92
+ loginUrl = 'https://app.example.com/login',
93
+ }: WelcomeEmailProps) {
94
+ return (
95
+ <Html lang="en">
96
+ <Head />
97
+ <Body style={bodyStyle}>
98
+ <Container style={containerStyle}>
99
+ <Heading style={headingStyle}>Welcome, {name}!</Heading>
100
+ <Text style={textStyle}>
101
+ Your account has been created successfully.
102
+ </Text>
103
+ <Section style={{ textAlign: 'center' as const }}>
104
+ <Button href={loginUrl} style={buttonStyle}>
105
+ Get Started
106
+ </Button>
107
+ </Section>
108
+ <Hr style={hrStyle} />
109
+ <Text style={footerStyle}>
110
+ © 2026 Your App. All rights reserved.
111
+ </Text>
112
+ </Container>
113
+ </Body>
114
+ </Html>
115
+ );
116
+ }
117
+
118
+ const bodyStyle = { backgroundColor: '#f6f9fc', fontFamily: 'sans-serif' };
119
+ const containerStyle = { margin: '0 auto', padding: '40px 20px', maxWidth: '580px' };
120
+ const headingStyle = { fontSize: '24px', color: '#1a1a1a' };
121
+ const textStyle = { fontSize: '16px', color: '#4a4a4a', lineHeight: '26px' };
122
+ const buttonStyle = {
123
+ backgroundColor: '#3b82f6', color: '#fff', fontSize: '16px',
124
+ padding: '12px 24px', borderRadius: '6px', textDecoration: 'none',
125
+ };
126
+ const hrStyle = { borderColor: '#e6e6e6', margin: '32px 0' };
127
+ const footerStyle = { fontSize: '12px', color: '#999' };
128
+
129
+ export default WelcomeEmail;
130
+ ```
131
+
132
+ ### Preview Templates
133
+
134
+ ```bash
135
+ npx email dev # Start React Email dev server at localhost:3000
136
+ ```
137
+
138
+ ## Domain Configuration
139
+
140
+ 1. Add your domain at resend.com → Domains
141
+ 2. Configure DNS records (SPF, DKIM, DMARC) as instructed
142
+ 3. Wait for domain verification (usually < 1 hour)
143
+ 4. Use `from: 'Name <no-reply@yourdomain.com>'` in sends
144
+
145
+ ## Webhook Handling
146
+
147
+ ```typescript
148
+ // app/api/webhooks/resend/route.ts
149
+ import { Webhook } from 'resend';
150
+
151
+ export async function POST(request: Request) {
152
+ const body = await request.text();
153
+ const signature = request.headers.get('svix-signature');
154
+
155
+ const webhook = new Webhook(process.env.RESEND_WEBHOOK_SECRET!);
156
+ const event = webhook.verify(body, {
157
+ 'svix-id': request.headers.get('svix-id')!,
158
+ 'svix-timestamp': request.headers.get('svix-timestamp')!,
159
+ 'svix-signature': signature!,
160
+ });
161
+
162
+ switch (event.type) {
163
+ case 'email.delivered':
164
+ // Handle successful delivery
165
+ break;
166
+ case 'email.bounced':
167
+ // Handle bounce — remove from mailing list
168
+ break;
169
+ case 'email.complained':
170
+ // Handle spam complaint — unsubscribe immediately
171
+ break;
172
+ }
173
+
174
+ return new Response('OK', { status: 200 });
175
+ }
176
+ ```
177
+
178
+ ## Best Practices
179
+
180
+ - Always use a verified custom domain — never send from `onboarding@resend.dev` in production
181
+ - Use React Email templates for complex emails — plain HTML for simple transactional messages
182
+ - Handle bounces and complaints via webhooks — remove invalid addresses promptly
183
+ - Use `RESEND_API_KEY` as an environment variable — never commit it
184
+ - Test emails locally with React Email dev server before deploying
185
+ - Set appropriate `from` addresses: `no-reply@` for transactional, named sender for marketing
186
+ - Include unsubscribe links where legally required (CAN-SPAM, GDPR)
187
+ - Keep email templates responsive — test in major email clients
@@ -0,0 +1,47 @@
1
+ import type { PluginConfig } from '../types.js';
2
+
3
+ export const config: PluginConfig = {
4
+ id: 'resend',
5
+ name: 'Resend',
6
+ category: 'tech',
7
+ subCategory: 'email',
8
+ label: 'Resend',
9
+ hint: 'Transactional email API with React templates',
10
+ skillName: 'resend-email',
11
+ mcpServerKey: 'Resend',
12
+ mcpConfig: {
13
+ type: 'stdio',
14
+ command: 'npx',
15
+ args: ['-y', 'resend-mcp'],
16
+ envFile: '${workspaceFolder}/.env',
17
+ },
18
+ authType: 'env-token',
19
+ envVars: [
20
+ {
21
+ name: 'RESEND_API_KEY',
22
+ hint: 'Generate at resend.com → API Keys',
23
+ },
24
+ ],
25
+ agentToolMap: {
26
+ 'developer': [
27
+ 'resend_send_email', 'resend_batch_send_email', 'resend_get_email',
28
+ 'resend_list_emails', 'resend_cancel_email', 'resend_update_email',
29
+ ],
30
+ 'devops-expert': [
31
+ 'resend_create_domain', 'resend_list_domains', 'resend_get_domain',
32
+ 'resend_verify_domain', 'resend_update_domain', 'resend_remove_domain',
33
+ 'resend_create_api_key', 'resend_list_api_keys', 'resend_remove_api_key',
34
+ 'resend_create_webhook', 'resend_list_webhooks', 'resend_get_webhook',
35
+ 'resend_update_webhook', 'resend_remove_webhook',
36
+ ],
37
+ 'data-expert': [
38
+ 'resend_create_contact', 'resend_list_contacts', 'resend_get_contact',
39
+ 'resend_update_contact', 'resend_remove_contact',
40
+ 'resend_create_broadcast', 'resend_list_broadcasts', 'resend_get_broadcast',
41
+ 'resend_send_broadcast',
42
+ ],
43
+ },
44
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#resend',
45
+ officialDocs: 'https://resend.com/docs',
46
+ mcpPackage: 'resend-mcp',
47
+ };
@@ -38,7 +38,6 @@ export const config: PluginConfig = {
38
38
  'sanity/list_projects',
39
39
  ],
40
40
  },
41
- docsUrl: null,
41
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#sanity',
42
42
  officialDocs: 'https://www.sanity.io/docs',
43
- mcpPackage: null,
44
43
  };
@@ -29,7 +29,7 @@ export const config: PluginConfig = {
29
29
  'team-lead': ['slack/*'],
30
30
  'release-manager': ['slack/*'],
31
31
  },
32
- docsUrl: '/guides/plugins#slack',
32
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#slack',
33
33
  officialDocs: 'https://api.slack.com/docs',
34
34
  mcpPackage: '@kazuph/mcp-slack',
35
35
  };
@@ -35,7 +35,7 @@ export const config: PluginConfig = {
35
35
  'strapi/get_entry', 'strapi/create_entry', 'strapi/update_entry',
36
36
  ],
37
37
  },
38
- docsUrl: null,
38
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#strapi',
39
39
  officialDocs: 'https://docs.strapi.io/',
40
40
  mcpPackage: 'strapi-mcp',
41
41
  };
@@ -28,7 +28,6 @@ export const config: PluginConfig = {
28
28
  'supabase/list_migrations', 'supabase/get_project',
29
29
  ],
30
30
  },
31
- docsUrl: null,
31
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#supabase',
32
32
  officialDocs: 'https://supabase.com/docs',
33
- mcpPackage: null,
34
33
  };
@@ -31,9 +31,8 @@ export const config: PluginConfig = {
31
31
  'Teams/mcp_graph_teams_listChannelMessages',
32
32
  ],
33
33
  },
34
- docsUrl: null,
34
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#teams',
35
35
  officialDocs: 'https://learn.microsoft.com/en-us/microsoftteams/',
36
- mcpPackage: null,
37
36
  mcpInputs: [
38
37
  {
39
38
  id: 'tenant_id',
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: turborepo-monorepo
3
+ description: "Turborepo monorepo commands, pipeline configuration, caching strategies, and task orchestration. Use when running builds, tests, linting, or any development commands in a Turborepo monorepo."
4
+ ---
5
+
6
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .github/customizations/ directory instead. -->
7
+
8
+ # Turborepo Monorepo
9
+
10
+ ## Commands
11
+
12
+ ### Running Tasks
13
+
14
+ ```bash
15
+ turbo run build # Build all packages
16
+ turbo run test # Test all packages
17
+ turbo run lint # Lint all packages
18
+ turbo run build --filter=web # Build specific package
19
+ turbo run build --filter=./apps/* # Build all apps
20
+ turbo run build --filter=...[HEAD~1] # Only affected since last commit
21
+ ```
22
+
23
+ ### Common Patterns
24
+
25
+ ```bash
26
+ turbo run build test lint # Run multiple tasks
27
+ turbo run build --dry-run # Preview what would run
28
+ turbo run build --graph # Visualize task graph
29
+ turbo run build --force # Ignore cache, rebuild all
30
+ turbo run build --concurrency=4 # Limit parallelism
31
+ ```
32
+
33
+ ### Forbidden Commands
34
+
35
+ ```bash
36
+ # NEVER use these directly — always go through turbo:
37
+ npm run build # Skips caching and parallelism
38
+ cd apps/web && npm test # Skips dependency resolution
39
+ ```
40
+
41
+ ## Pipeline Configuration (turbo.json)
42
+
43
+ ```json
44
+ {
45
+ "$schema": "https://turbo.build/schema.json",
46
+ "tasks": {
47
+ "build": {
48
+ "dependsOn": ["^build"],
49
+ "outputs": ["dist/**", ".next/**"]
50
+ },
51
+ "test": {
52
+ "dependsOn": ["build"],
53
+ "inputs": ["src/**", "test/**"]
54
+ },
55
+ "lint": {
56
+ "dependsOn": ["^build"]
57
+ },
58
+ "dev": {
59
+ "cache": false,
60
+ "persistent": true
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### Key Concepts
67
+
68
+ - `^build` — run `build` in dependencies first (topological)
69
+ - `dependsOn` — declare task dependencies
70
+ - `outputs` — files to cache (miss = rebuild)
71
+ - `inputs` — files to hash for cache key (default: all tracked files)
72
+ - `cache: false` — never cache (use for `dev`, `start`)
73
+ - `persistent: true` — long-running tasks (dev servers)
74
+
75
+ ## Caching
76
+
77
+ ### Local Cache
78
+
79
+ Turborepo caches task outputs automatically in `node_modules/.cache/turbo`. Cache keys are computed from:
80
+
81
+ 1. Task inputs (source files)
82
+ 2. Environment variables
83
+ 3. Dependencies' build outputs
84
+ 4. `turbo.json` configuration
85
+
86
+ ### Remote Cache
87
+
88
+ ```bash
89
+ turbo login # Authenticate
90
+ turbo link # Link project to remote cache
91
+ turbo run build --remote-only # Force remote cache usage
92
+ ```
93
+
94
+ - Shares cache across CI and team members
95
+ - Vercel Remote Cache or self-hosted (Ducktape, TurboCache)
96
+ - Set `TURBO_TOKEN` and `TURBO_TEAM` in CI environment
97
+
98
+ ## Package Workspace Structure
99
+
100
+ ```
101
+ monorepo/
102
+ ├── turbo.json
103
+ ├── package.json # Root workspace config
104
+ ├── apps/
105
+ │ ├── web/ # Next.js app
106
+ │ └── docs/ # Documentation site
107
+ ├── packages/
108
+ │ ├── ui/ # Shared UI components
109
+ │ ├── config/ # Shared config (ESLint, TS)
110
+ │ └── utils/ # Shared utilities
111
+ ```
112
+
113
+ ## Best Practices
114
+
115
+ - Always use `turbo run` instead of directly invoking package scripts
116
+ - Define `outputs` for every cacheable task — missing outputs mean missing cache
117
+ - Use `--filter` to scope commands to affected packages
118
+ - Set `inputs` to narrow cache keys and avoid unnecessary rebuilds
119
+ - Use `--dry-run` to debug pipeline configuration
120
+ - Add `TURBO_TOKEN` and `TURBO_TEAM` to CI for remote caching
121
+ - Never commit `.turbo/` or `node_modules/.cache/turbo`
@@ -0,0 +1,16 @@
1
+ import type { PluginConfig } from '../types.js';
2
+
3
+ export const config: PluginConfig = {
4
+ id: 'turborepo',
5
+ name: 'Turborepo',
6
+ category: 'tech',
7
+ subCategory: 'codebase-tool',
8
+ label: 'Turborepo',
9
+ hint: 'Monorepo build system with remote caching',
10
+ skillName: 'turborepo-monorepo',
11
+ authType: 'none',
12
+ envVars: [],
13
+ agentToolMap: {},
14
+ docsUrl: 'https://www.opencastle.dev/docs/plugins#turborepo',
15
+ officialDocs: 'https://turbo.build/repo/docs',
16
+ };
@@ -13,7 +13,7 @@ export interface PluginConfig {
13
13
  category: 'tech' | 'team';
14
14
 
15
15
  /** Sub-category for grouping */
16
- subCategory: 'cms' | 'database' | 'deployment' | 'monorepo' | 'tracker' | 'notifications' | 'testing';
16
+ subCategory: 'cms' | 'database' | 'deployment' | 'framework' | 'codebase-tool' | 'task-management' | 'notifications' | 'testing' | 'e2e-testing' | 'design' | 'email';
17
17
 
18
18
  /** Label shown in the `npx opencastle init` multiselect */
19
19
  label: string;
@@ -24,11 +24,11 @@ export interface PluginConfig {
24
24
  /** Skill directory name (matches the old skills/ dirname). null if no skill. */
25
25
  skillName: string | null;
26
26
 
27
- /** MCP server key used in the generated MCP config. null if no MCP server. */
28
- mcpServerKey: string | null;
27
+ /** MCP server key used in the generated MCP config. Omit if no MCP server. */
28
+ mcpServerKey?: string;
29
29
 
30
- /** Raw MCP server config */
31
- mcpConfig: McpServerConfig;
30
+ /** Raw MCP server config (required when mcpServerKey is set) */
31
+ mcpConfig?: McpServerConfig;
32
32
 
33
33
  /** Authentication type */
34
34
  authType: 'oauth' | 'env-token' | 'none';
@@ -46,8 +46,8 @@ export interface PluginConfig {
46
46
  /** Official product documentation URL */
47
47
  officialDocs: string;
48
48
 
49
- /** NPM package for the MCP server (null for HTTP/OAuth servers) */
50
- mcpPackage: string | null;
49
+ /** NPM package for the MCP server (omit for HTTP/OAuth servers or plugins without MCP) */
50
+ mcpPackage?: string;
51
51
 
52
52
  /** Whether this plugin should be preselected in the init prompt */
53
53
  preselected?: boolean;