@plazmodium/odin 0.3.2-beta → 0.3.4-beta

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 (73) hide show
  1. package/README.md +82 -11
  2. package/builtin/ODIN.md +1045 -0
  3. package/builtin/agent-definitions/README.md +170 -0
  4. package/builtin/agent-definitions/_shared-context.md +377 -0
  5. package/builtin/agent-definitions/architect.md +627 -0
  6. package/builtin/agent-definitions/builder.md +716 -0
  7. package/builtin/agent-definitions/discovery.md +293 -0
  8. package/builtin/agent-definitions/documenter.md +238 -0
  9. package/builtin/agent-definitions/guardian.md +1049 -0
  10. package/builtin/agent-definitions/integrator.md +363 -0
  11. package/builtin/agent-definitions/planning.md +236 -0
  12. package/builtin/agent-definitions/product.md +405 -0
  13. package/builtin/agent-definitions/release.md +430 -0
  14. package/builtin/agent-definitions/reviewer.md +447 -0
  15. package/builtin/agent-definitions/watcher.md +402 -0
  16. package/builtin/skills/api/graphql/SKILL.md +548 -0
  17. package/builtin/skills/api/grpc/SKILL.md +554 -0
  18. package/builtin/skills/api/rest-api/SKILL.md +469 -0
  19. package/builtin/skills/api/trpc/SKILL.md +503 -0
  20. package/builtin/skills/architecture/clean-architecture/SKILL.md +141 -0
  21. package/builtin/skills/architecture/domain-driven-design/SKILL.md +129 -0
  22. package/builtin/skills/architecture/event-driven/SKILL.md +145 -0
  23. package/builtin/skills/architecture/microservices/SKILL.md +143 -0
  24. package/builtin/skills/architecture/tla-precheck/SKILL.md +171 -0
  25. package/builtin/skills/backend/golang-gin/SKILL.md +141 -0
  26. package/builtin/skills/backend/nodejs-express/SKILL.md +277 -0
  27. package/builtin/skills/backend/nodejs-fastify/SKILL.md +152 -0
  28. package/builtin/skills/backend/python-django/SKILL.md +128 -0
  29. package/builtin/skills/backend/python-fastapi/SKILL.md +140 -0
  30. package/builtin/skills/database/mongodb/SKILL.md +132 -0
  31. package/builtin/skills/database/postgresql/SKILL.md +120 -0
  32. package/builtin/skills/database/prisma-orm/SKILL.md +366 -0
  33. package/builtin/skills/database/redis/SKILL.md +140 -0
  34. package/builtin/skills/database/supabase/SKILL.md +416 -0
  35. package/builtin/skills/devops/aws/SKILL.md +382 -0
  36. package/builtin/skills/devops/docker/SKILL.md +359 -0
  37. package/builtin/skills/devops/github-actions/SKILL.md +435 -0
  38. package/builtin/skills/devops/kubernetes/SKILL.md +459 -0
  39. package/builtin/skills/devops/terraform/SKILL.md +453 -0
  40. package/builtin/skills/frontend/alpine-dev/SKILL.md +27 -0
  41. package/builtin/skills/frontend/angular-dev/SKILL.md +28 -0
  42. package/builtin/skills/frontend/astro-dev/SKILL.md +28 -0
  43. package/builtin/skills/frontend/htmx-dev/SKILL.md +28 -0
  44. package/builtin/skills/frontend/nextjs-dev/SKILL.md +470 -0
  45. package/builtin/skills/frontend/react-patterns/SKILL.md +166 -0
  46. package/builtin/skills/frontend/svelte-dev/SKILL.md +28 -0
  47. package/builtin/skills/frontend/tailwindcss/SKILL.md +131 -0
  48. package/builtin/skills/frontend/vuejs-dev/SKILL.md +28 -0
  49. package/builtin/skills/generic-dev/SKILL.md +307 -0
  50. package/builtin/skills/testing/cypress/SKILL.md +372 -0
  51. package/builtin/skills/testing/jest/SKILL.md +176 -0
  52. package/builtin/skills/testing/playwright/SKILL.md +341 -0
  53. package/builtin/skills/testing/unit-tests-eval-sdd/SKILL.md +73 -0
  54. package/builtin/skills/testing/unit-tests-sdd/SKILL.md +83 -0
  55. package/builtin/skills/testing/vitest/SKILL.md +249 -0
  56. package/dist/adapters/skills/filesystem.d.ts.map +1 -1
  57. package/dist/adapters/skills/filesystem.js +2 -18
  58. package/dist/adapters/skills/filesystem.js.map +1 -1
  59. package/dist/builtin-assets.d.ts +8 -0
  60. package/dist/builtin-assets.d.ts.map +1 -0
  61. package/dist/builtin-assets.js +90 -0
  62. package/dist/builtin-assets.js.map +1 -0
  63. package/dist/init.js +69 -11
  64. package/dist/init.js.map +1 -1
  65. package/dist/schemas.d.ts +1 -1
  66. package/dist/server.js +1 -1
  67. package/dist/server.js.map +1 -1
  68. package/dist/tools/prepare-phase-context.d.ts.map +1 -1
  69. package/dist/tools/prepare-phase-context.js +5 -0
  70. package/dist/tools/prepare-phase-context.js.map +1 -1
  71. package/dist/types.d.ts +3 -0
  72. package/dist/types.d.ts.map +1 -1
  73. package/package.json +5 -3
@@ -0,0 +1,366 @@
1
+ ---
2
+ name: prisma-orm
3
+ description: Prisma ORM expertise for type-safe database access, schema design, migrations, and query optimization
4
+ category: database
5
+ version: "5.x"
6
+ depends_on:
7
+ - postgresql
8
+ compatible_with:
9
+ - mysql
10
+ - nodejs-express
11
+ - nextjs-dev
12
+ - typescript
13
+ ---
14
+
15
+ # Prisma ORM Development
16
+
17
+ ## Overview
18
+
19
+ Prisma is a next-generation ORM for Node.js and TypeScript that provides type-safe database access, automated migrations, and an intuitive data modeling language.
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ prisma/
25
+ ├── schema.prisma # Database schema
26
+ ├── migrations/ # Migration history
27
+ │ └── 20240115_init/
28
+ │ └── migration.sql
29
+ └── seed.ts # Database seeding
30
+
31
+ src/
32
+ ├── lib/
33
+ │ └── prisma.ts # Prisma client singleton
34
+ └── services/
35
+ └── user.service.ts # Using Prisma client
36
+ ```
37
+
38
+ ## Schema Design
39
+
40
+ ### Basic Schema
41
+
42
+ ```prisma
43
+ // prisma/schema.prisma
44
+ generator client {
45
+ provider = "prisma-client-js"
46
+ }
47
+
48
+ datasource db {
49
+ provider = "postgresql"
50
+ url = env("DATABASE_URL")
51
+ }
52
+
53
+ model User {
54
+ id String @id @default(uuid())
55
+ email String @unique
56
+ name String?
57
+ password String
58
+ role Role @default(USER)
59
+ posts Post[]
60
+ profile Profile?
61
+ createdAt DateTime @default(now()) @map("created_at")
62
+ updatedAt DateTime @updatedAt @map("updated_at")
63
+
64
+ @@map("users")
65
+ }
66
+
67
+ model Post {
68
+ id String @id @default(uuid())
69
+ title String
70
+ content String?
71
+ published Boolean @default(false)
72
+ author User @relation(fields: [authorId], references: [id])
73
+ authorId String @map("author_id")
74
+ categories Category[]
75
+ createdAt DateTime @default(now()) @map("created_at")
76
+ updatedAt DateTime @updatedAt @map("updated_at")
77
+
78
+ @@index([authorId])
79
+ @@map("posts")
80
+ }
81
+
82
+ model Profile {
83
+ id String @id @default(uuid())
84
+ bio String?
85
+ avatar String?
86
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
87
+ userId String @unique @map("user_id")
88
+
89
+ @@map("profiles")
90
+ }
91
+
92
+ model Category {
93
+ id String @id @default(uuid())
94
+ name String @unique
95
+ posts Post[]
96
+
97
+ @@map("categories")
98
+ }
99
+
100
+ enum Role {
101
+ USER
102
+ ADMIN
103
+ MODERATOR
104
+ }
105
+ ```
106
+
107
+ ## Prisma Client Setup
108
+
109
+ ```typescript
110
+ // src/lib/prisma.ts
111
+ import { PrismaClient } from '@prisma/client';
112
+
113
+ const globalForPrisma = globalThis as unknown as {
114
+ prisma: PrismaClient | undefined;
115
+ };
116
+
117
+ export const prisma = globalForPrisma.prisma ?? new PrismaClient({
118
+ log: process.env.NODE_ENV === 'development'
119
+ ? ['query', 'error', 'warn']
120
+ : ['error'],
121
+ });
122
+
123
+ if (process.env.NODE_ENV !== 'production') {
124
+ globalForPrisma.prisma = prisma;
125
+ }
126
+
127
+ export default prisma;
128
+ ```
129
+
130
+ ## Common Query Patterns
131
+
132
+ ### CRUD Operations
133
+
134
+ ```typescript
135
+ import prisma from '@/lib/prisma';
136
+
137
+ // Create
138
+ const user = await prisma.user.create({
139
+ data: {
140
+ email: 'user@example.com',
141
+ name: 'John Doe',
142
+ password: hashedPassword,
143
+ },
144
+ });
145
+
146
+ // Read (single)
147
+ const user = await prisma.user.findUnique({
148
+ where: { id: userId },
149
+ });
150
+
151
+ // Read (with relations)
152
+ const userWithPosts = await prisma.user.findUnique({
153
+ where: { id: userId },
154
+ include: {
155
+ posts: true,
156
+ profile: true,
157
+ },
158
+ });
159
+
160
+ // Read (many with filtering)
161
+ const users = await prisma.user.findMany({
162
+ where: {
163
+ email: { contains: '@company.com' },
164
+ role: 'USER',
165
+ },
166
+ orderBy: { createdAt: 'desc' },
167
+ take: 10,
168
+ skip: 0,
169
+ });
170
+
171
+ // Update
172
+ const updated = await prisma.user.update({
173
+ where: { id: userId },
174
+ data: { name: 'Jane Doe' },
175
+ });
176
+
177
+ // Delete
178
+ await prisma.user.delete({
179
+ where: { id: userId },
180
+ });
181
+ ```
182
+
183
+ ### Select Specific Fields
184
+
185
+ ```typescript
186
+ const users = await prisma.user.findMany({
187
+ select: {
188
+ id: true,
189
+ email: true,
190
+ name: true,
191
+ // password intentionally excluded
192
+ },
193
+ });
194
+ ```
195
+
196
+ ### Nested Writes
197
+
198
+ ```typescript
199
+ // Create user with profile
200
+ const user = await prisma.user.create({
201
+ data: {
202
+ email: 'user@example.com',
203
+ name: 'John',
204
+ password: hash,
205
+ profile: {
206
+ create: {
207
+ bio: 'Developer',
208
+ },
209
+ },
210
+ },
211
+ include: { profile: true },
212
+ });
213
+
214
+ // Create post with categories
215
+ const post = await prisma.post.create({
216
+ data: {
217
+ title: 'My Post',
218
+ content: 'Content...',
219
+ authorId: userId,
220
+ categories: {
221
+ connectOrCreate: [
222
+ {
223
+ where: { name: 'Tech' },
224
+ create: { name: 'Tech' },
225
+ },
226
+ ],
227
+ },
228
+ },
229
+ });
230
+ ```
231
+
232
+ ### Transactions
233
+
234
+ ```typescript
235
+ // Sequential transaction
236
+ const [user, post] = await prisma.$transaction([
237
+ prisma.user.create({ data: userData }),
238
+ prisma.post.create({ data: postData }),
239
+ ]);
240
+
241
+ // Interactive transaction
242
+ const result = await prisma.$transaction(async (tx) => {
243
+ const user = await tx.user.create({ data: userData });
244
+
245
+ if (someCondition) {
246
+ throw new Error('Rollback!');
247
+ }
248
+
249
+ const post = await tx.post.create({
250
+ data: { ...postData, authorId: user.id },
251
+ });
252
+
253
+ return { user, post };
254
+ });
255
+ ```
256
+
257
+ ### Aggregations
258
+
259
+ ```typescript
260
+ // Count
261
+ const count = await prisma.user.count({
262
+ where: { role: 'USER' },
263
+ });
264
+
265
+ // Group by
266
+ const postsByUser = await prisma.post.groupBy({
267
+ by: ['authorId'],
268
+ _count: { id: true },
269
+ orderBy: { _count: { id: 'desc' } },
270
+ });
271
+
272
+ // Aggregate
273
+ const stats = await prisma.post.aggregate({
274
+ _count: true,
275
+ _avg: { views: true },
276
+ _max: { views: true },
277
+ });
278
+ ```
279
+
280
+ ## Migrations
281
+
282
+ ```bash
283
+ # Create migration
284
+ npx prisma migrate dev --name add_user_role
285
+
286
+ # Apply migrations (production)
287
+ npx prisma migrate deploy
288
+
289
+ # Reset database (development only!)
290
+ npx prisma migrate reset
291
+
292
+ # Generate client after schema changes
293
+ npx prisma generate
294
+ ```
295
+
296
+ ## Best Practices
297
+
298
+ 1. **Use singleton pattern** - Prevent connection pool exhaustion
299
+ 2. **Select only needed fields** - Reduce data transfer
300
+ 3. **Use transactions for related writes** - Ensure data consistency
301
+ 4. **Add indexes for query fields** - `@@index([fieldName])`
302
+ 5. **Use `@map` for snake_case** - Keep DB conventions, use camelCase in code
303
+ 6. **Archive instead of delete** - Add `isArchived Boolean @default(false)` and `archivedAt DateTime?` for recoverable records. "Soft delete" is a misnomer - use archive terminology to match real-world concepts
304
+ 7. **Always include `updatedAt`** - Use `@updatedAt` for automatic tracking
305
+
306
+ ## Gotchas & Pitfalls
307
+
308
+ - **N+1 queries** - Use `include` or `select` with relations, not separate queries
309
+ - **Connection limits** - Use singleton pattern, especially in serverless
310
+ - **Migration conflicts** - Don't edit existing migrations, create new ones
311
+ - **Type mismatches** - Run `prisma generate` after schema changes
312
+ - **Forgetting indexes** - Add `@@index` for frequently queried fields
313
+ - **BigInt serialization** - JSON.stringify doesn't handle BigInt, convert to string
314
+
315
+ ## Integration with Next.js
316
+
317
+ ```typescript
318
+ // app/api/users/route.ts
319
+ import prisma from '@/lib/prisma';
320
+ import { NextResponse } from 'next/server';
321
+
322
+ export async function GET() {
323
+ const users = await prisma.user.findMany({
324
+ select: { id: true, email: true, name: true },
325
+ });
326
+ return NextResponse.json(users);
327
+ }
328
+ ```
329
+
330
+ ## Seeding
331
+
332
+ ```typescript
333
+ // prisma/seed.ts
334
+ import { PrismaClient } from '@prisma/client';
335
+
336
+ const prisma = new PrismaClient();
337
+
338
+ async function main() {
339
+ await prisma.user.upsert({
340
+ where: { email: 'admin@example.com' },
341
+ update: {},
342
+ create: {
343
+ email: 'admin@example.com',
344
+ name: 'Admin',
345
+ password: 'hashed_password',
346
+ role: 'ADMIN',
347
+ },
348
+ });
349
+ }
350
+
351
+ main()
352
+ .catch((e) => {
353
+ console.error(e);
354
+ process.exit(1);
355
+ })
356
+ .finally(() => prisma.$disconnect());
357
+ ```
358
+
359
+ ```json
360
+ // package.json
361
+ {
362
+ "prisma": {
363
+ "seed": "ts-node prisma/seed.ts"
364
+ }
365
+ }
366
+ ```
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: redis
3
+ description: Redis in-memory data store patterns for caching, sessions, queues, and real-time features
4
+ category: database
5
+ version: "7.x"
6
+ compatible_with:
7
+ - nodejs-express
8
+ - nodejs-fastify
9
+ - python-fastapi
10
+ - python-django
11
+ - golang-gin
12
+ ---
13
+
14
+ # Redis
15
+
16
+ ## Overview
17
+
18
+ Redis is an in-memory data structure store used as a cache, message broker, and database. This skill covers caching patterns, data structures, and common use cases.
19
+
20
+ ## Common Use Cases
21
+
22
+ ### Caching
23
+
24
+ ```typescript
25
+ // Cache-aside pattern (most common)
26
+ async function getUser(id: string): Promise<User> {
27
+ const cacheKey = `user:${id}`;
28
+
29
+ // 1. Check cache
30
+ const cached = await redis.get(cacheKey);
31
+ if (cached) return JSON.parse(cached);
32
+
33
+ // 2. Cache miss → fetch from DB
34
+ const user = await db.users.findById(id);
35
+ if (!user) throw new NotFoundError();
36
+
37
+ // 3. Populate cache with TTL
38
+ await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600); // 1 hour
39
+
40
+ return user;
41
+ }
42
+
43
+ // Invalidate on mutation
44
+ async function updateUser(id: string, data: UpdateUserDto): Promise<User> {
45
+ const user = await db.users.update(id, data);
46
+ await redis.del(`user:${id}`); // Invalidate cache
47
+ return user;
48
+ }
49
+ ```
50
+
51
+ ### Sessions
52
+
53
+ ```typescript
54
+ // Store session data with TTL
55
+ await redis.set(`session:${sessionId}`, JSON.stringify({
56
+ userId: user.id,
57
+ role: user.role,
58
+ loginAt: Date.now(),
59
+ }), 'EX', 86400); // 24 hours
60
+
61
+ // Retrieve
62
+ const session = JSON.parse(await redis.get(`session:${sessionId}`) || 'null');
63
+ ```
64
+
65
+ ### Rate Limiting
66
+
67
+ ```typescript
68
+ // Sliding window rate limiter
69
+ async function checkRateLimit(ip: string, limit: number, windowSec: number): Promise<boolean> {
70
+ const key = `ratelimit:${ip}`;
71
+ const current = await redis.incr(key);
72
+
73
+ if (current === 1) {
74
+ await redis.expire(key, windowSec);
75
+ }
76
+
77
+ return current <= limit;
78
+ }
79
+ ```
80
+
81
+ ### Pub/Sub
82
+
83
+ ```typescript
84
+ // Publisher
85
+ await redis.publish('notifications', JSON.stringify({
86
+ userId: '123',
87
+ type: 'new_message',
88
+ payload: { from: 'Jane', text: 'Hello' },
89
+ }));
90
+
91
+ // Subscriber
92
+ const sub = redis.duplicate();
93
+ await sub.subscribe('notifications');
94
+ sub.on('message', (channel, message) => {
95
+ const notification = JSON.parse(message);
96
+ sendToWebSocket(notification.userId, notification);
97
+ });
98
+ ```
99
+
100
+ ## Data Structures
101
+
102
+ ```bash
103
+ # Strings — basic key-value, counters
104
+ SET user:123:name "John"
105
+ INCR page:views:homepage
106
+
107
+ # Hashes — object-like storage (memory efficient)
108
+ HSET user:123 name "John" email "john@example.com" role "admin"
109
+ HGET user:123 email
110
+
111
+ # Lists — queues, recent items
112
+ LPUSH queue:emails '{"to":"john@..."}'
113
+ RPOP queue:emails
114
+
115
+ # Sets — unique collections, tags
116
+ SADD post:456:tags "javascript" "react" "tutorial"
117
+ SISMEMBER post:456:tags "react"
118
+
119
+ # Sorted Sets — leaderboards, time-series
120
+ ZADD leaderboard 1500 "player1" 2300 "player2"
121
+ ZREVRANGE leaderboard 0 9 WITHSCORES # Top 10
122
+ ```
123
+
124
+ ## Best Practices
125
+
126
+ 1. **Use key namespaces** — `entity:id:field` pattern (`user:123:profile`)
127
+ 2. **Always set TTL** — prevent unbounded memory growth; use `EX` or `EXPIREAT`
128
+ 3. **Use pipelines** — batch multiple commands in one round trip
129
+ 4. **Prefer hashes** for objects — more memory-efficient than separate string keys
130
+ 5. **Avoid large keys** — break large values into smaller structures or use Streams
131
+ 6. **Use Lua scripts** for atomic operations — `EVAL` guarantees atomicity
132
+ 7. **Monitor memory** — use `INFO memory` and set `maxmemory-policy` (e.g., `allkeys-lru`)
133
+
134
+ ## Gotchas
135
+
136
+ - **No built-in persistence guarantees** — RDB snapshots + AOF help, but Redis is not a primary database
137
+ - **Single-threaded** — long-running commands (KEYS *, large SORT) block all clients; use SCAN instead
138
+ - **Pub/Sub is fire-and-forget** — messages are lost if no subscriber is listening; use Streams for durability
139
+ - **Serialization overhead** — JSON.stringify/parse adds latency; consider MessagePack for large payloads
140
+ - **Connection limits** — each subscriber needs its own connection; use connection pooling