@martinffx/atelier 1.4.0 → 3.0.0

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 (93) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +95 -220
  3. package/agents/architect.md +6 -6
  4. package/agents/oracle.md +1 -1
  5. package/agents/{recon.md → sentinel.md} +3 -3
  6. package/dist/atelier.js +167 -26
  7. package/package.json +2 -1
  8. package/skills/atelier-orchestrator/SKILL.md +180 -0
  9. package/skills/atelier-setup/SKILL.md +80 -0
  10. package/skills/code-review/SKILL.md +2 -2
  11. package/skills/code-review/references/reviewers.md +3 -3
  12. package/skills/code-review/references/rq.md +9 -9
  13. package/skills/code-subagents/SKILL.md +44 -75
  14. package/skills/code-subagents/references/batch-reviewer-prompt.md +44 -0
  15. package/skills/code-subagents/references/implementor-prompt.md +10 -11
  16. package/skills/spec-brainstorm/SKILL.md +21 -16
  17. package/skills/spec-finish/SKILL.md +14 -14
  18. package/skills/spec-implement/SKILL.md +42 -42
  19. package/skills/spec-plan/SKILL.md +72 -26
  20. package/skills/spec-plan/references/plan_template.md +77 -0
  21. package/skills/code-subagents/references/code-quality-reviewer-prompt.md +0 -48
  22. package/skills/code-subagents/references/spec-reviewer-prompt.md +0 -62
  23. package/skills/python-architecture/SKILL.md +0 -148
  24. package/skills/python-architecture/references/data-modeling.md +0 -558
  25. package/skills/python-architecture/references/ddd.md +0 -569
  26. package/skills/python-architecture/references/functional-core.md +0 -337
  27. package/skills/python-build-tools/SKILL.md +0 -153
  28. package/skills/python-build-tools/references/basedpyright.md +0 -321
  29. package/skills/python-build-tools/references/ruff.md +0 -225
  30. package/skills/python-build-tools/references/uv.md +0 -257
  31. package/skills/python-fastapi/SKILL.md +0 -184
  32. package/skills/python-fastapi/references/api-design.md +0 -563
  33. package/skills/python-fastapi/references/dependencies.md +0 -479
  34. package/skills/python-fastapi/references/middleware.md +0 -475
  35. package/skills/python-fastapi/references/validation.md +0 -497
  36. package/skills/python-modern-python/SKILL.md +0 -201
  37. package/skills/python-modern-python/references/async.md +0 -76
  38. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  39. package/skills/python-modern-python/references/typing.md +0 -96
  40. package/skills/python-monorepo/SKILL.md +0 -146
  41. package/skills/python-monorepo/references/docker.md +0 -515
  42. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  43. package/skills/python-monorepo/references/workspace-config.md +0 -341
  44. package/skills/python-sqlalchemy/SKILL.md +0 -119
  45. package/skills/python-sqlalchemy/references/async.md +0 -51
  46. package/skills/python-sqlalchemy/references/models.md +0 -67
  47. package/skills/python-sqlalchemy/references/queries.md +0 -57
  48. package/skills/python-temporal/SKILL.md +0 -128
  49. package/skills/python-temporal/references/patterns.md +0 -87
  50. package/skills/python-temporal/references/testing.md +0 -54
  51. package/skills/python-testing/SKILL.md +0 -161
  52. package/skills/python-testing/references/boundaries.md +0 -449
  53. package/skills/python-testing/references/mocking.md +0 -449
  54. package/skills/python-testing/references/pytest.md +0 -524
  55. package/skills/spec-orchestrator/SKILL.md +0 -145
  56. package/skills/typescript-api-design/SKILL.md +0 -396
  57. package/skills/typescript-api-design/references/error-responses.md +0 -469
  58. package/skills/typescript-build-tools/SKILL.md +0 -447
  59. package/skills/typescript-build-tools/references/biome.md +0 -436
  60. package/skills/typescript-build-tools/references/bun.md +0 -432
  61. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  62. package/skills/typescript-build-tools/references/vitest.md +0 -518
  63. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  64. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  65. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  66. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  67. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  68. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  69. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  70. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  71. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  72. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  73. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  74. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  75. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  76. package/skills/typescript-effect-ts/SKILL.md +0 -341
  77. package/skills/typescript-effect-ts/references/core.md +0 -412
  78. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  79. package/skills/typescript-effect-ts/references/resources.md +0 -476
  80. package/skills/typescript-effect-ts/references/schema.md +0 -536
  81. package/skills/typescript-effect-ts/references/services.md +0 -461
  82. package/skills/typescript-fastify/SKILL.md +0 -405
  83. package/skills/typescript-fastify/references/plugins.md +0 -329
  84. package/skills/typescript-fastify/references/typeid.md +0 -315
  85. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  86. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  87. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  88. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  89. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  90. package/skills/typescript-testing/SKILL.md +0 -353
  91. package/skills/typescript-testing/references/mocking.md +0 -675
  92. package/skills/typescript-testing/references/msw.md +0 -852
  93. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,398 +0,0 @@
1
- ---
2
- name: typescript-drizzle-orm
3
- description: Type-safe SQL with Drizzle ORM in TypeScript. Use when defining database schemas, writing queries, setting up relations, running migrations, or working with PostgreSQL/MySQL/SQLite/Cloudflare D1/Durable Objects data layers.
4
- user-invocable: false
5
- ---
6
-
7
- # Drizzle ORM
8
-
9
- Lightweight, type-safe ORM with SQL-like and relational query APIs for PostgreSQL, MySQL, SQLite, Cloudflare D1, and Durable Objects.
10
-
11
- ## Quick Start (PostgreSQL)
12
-
13
- ```typescript
14
- import {
15
- pgTable,
16
- serial,
17
- text,
18
- integer,
19
- timestamp,
20
- boolean,
21
- varchar,
22
- uuid,
23
- primaryKey,
24
- unique,
25
- index
26
- } from 'drizzle-orm/pg-core'
27
-
28
- export const users = pgTable('users', {
29
- id: serial('id').primaryKey(),
30
- name: text('name').notNull(),
31
- email: varchar('email', { length: 255 }).notNull().unique(),
32
- age: integer('age'),
33
- isActive: boolean('is_active').default(true),
34
- createdAt: timestamp('created_at').defaultNow().notNull(),
35
- updatedAt: timestamp('updated_at').$onUpdate(() => new Date()),
36
- })
37
-
38
- export const posts = pgTable('posts', {
39
- id: serial('id').primaryKey(),
40
- title: text('title').notNull(),
41
- content: text('content'),
42
- authorId: integer('author_id')
43
- .notNull()
44
- .references(() => users.id, { onDelete: 'cascade' }),
45
- createdAt: timestamp('created_at').defaultNow().notNull(),
46
- })
47
- ```
48
-
49
- See [references/postgresql.md](./references/postgresql.md) for detailed PostgreSQL patterns.
50
-
51
- ## Quick Start (SQLite/D1)
52
-
53
- ```typescript
54
- import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
55
-
56
- export const users = sqliteTable('users', {
57
- id: text('id').primaryKey(),
58
- name: text('name').notNull(),
59
- email: text('email').notNull(),
60
- isActive: integer('is_active', { mode: 'boolean' }).default(true),
61
- createdAt: text('created_at').notNull(),
62
- })
63
-
64
- export const posts = sqliteTable('posts', {
65
- id: text('id').primaryKey(),
66
- title: text('title').notNull(),
67
- content: text('content'),
68
- authorId: text('author_id')
69
- .notNull()
70
- .references(() => users.id, { onDelete: 'cascade' }),
71
- createdAt: text('created_at').notNull(),
72
- })
73
- ```
74
-
75
- See [references/sqlite.md](./references/sqlite.md) for SQLite patterns and [references/cloudflare.md](./references/cloudflare.md) for D1 and Durable Objects.
76
-
77
- ## Type Inference
78
-
79
- ```typescript
80
- // Infer types from schema - no manual interfaces needed
81
- export type User = typeof users.$inferSelect
82
- export type NewUser = typeof users.$inferInsert
83
-
84
- export type Post = typeof posts.$inferSelect
85
- export type NewPost = typeof posts.$inferInsert
86
- ```
87
-
88
- ## Relations
89
-
90
- ```typescript
91
- import { relations } from 'drizzle-orm'
92
-
93
- export const usersRelations = relations(users, ({ many }) => ({
94
- posts: many(posts),
95
- }))
96
-
97
- export const postsRelations = relations(posts, ({ one }) => ({
98
- author: one(users, {
99
- fields: [posts.authorId],
100
- references: [users.id],
101
- }),
102
- }))
103
- ```
104
-
105
- ## SQL-like Queries
106
-
107
- ```typescript
108
- import { eq, and, or, gt, like, isNull, desc, asc } from 'drizzle-orm'
109
-
110
- // Select all
111
- const allUsers = await db.select().from(users)
112
-
113
- // Select specific columns
114
- const names = await db.select({ name: users.name }).from(users)
115
-
116
- // Where clause
117
- const activeUsers = await db
118
- .select()
119
- .from(users)
120
- .where(eq(users.isActive, true))
121
-
122
- // Multiple conditions
123
- const filtered = await db
124
- .select()
125
- .from(users)
126
- .where(and(
127
- eq(users.isActive, true),
128
- gt(users.age, 18)
129
- ))
130
-
131
- // Like/pattern matching
132
- const matching = await db
133
- .select()
134
- .from(users)
135
- .where(like(users.email, '%@example.com'))
136
-
137
- // Order and limit
138
- const recent = await db
139
- .select()
140
- .from(posts)
141
- .orderBy(desc(posts.createdAt))
142
- .limit(10)
143
-
144
- // Joins
145
- const postsWithAuthors = await db
146
- .select({
147
- postTitle: posts.title,
148
- authorName: users.name,
149
- })
150
- .from(posts)
151
- .leftJoin(users, eq(posts.authorId, users.id))
152
- ```
153
-
154
- ## Relational Queries
155
-
156
- ```typescript
157
- // Requires schema with relations passed to drizzle()
158
- const db = drizzle(pool, { schema })
159
-
160
- // Find many with relations
161
- const usersWithPosts = await db.query.users.findMany({
162
- with: {
163
- posts: true,
164
- },
165
- })
166
-
167
- // Partial columns + nested relations
168
- const partial = await db.query.users.findMany({
169
- columns: {
170
- id: true,
171
- name: true,
172
- },
173
- with: {
174
- posts: {
175
- columns: {
176
- title: true,
177
- createdAt: true,
178
- },
179
- },
180
- },
181
- })
182
-
183
- // Find first
184
- const user = await db.query.users.findFirst({
185
- where: eq(users.id, 1),
186
- with: { posts: true },
187
- })
188
-
189
- // Exclude columns
190
- const withoutEmail = await db.query.users.findMany({
191
- columns: {
192
- email: false, // exclude
193
- },
194
- })
195
- ```
196
-
197
- ## Insert
198
-
199
- ```typescript
200
- // Single insert
201
- const [newUser] = await db
202
- .insert(users)
203
- .values({ name: 'Alice', email: 'alice@example.com' })
204
- .returning()
205
-
206
- // Multiple insert
207
- await db.insert(users).values([
208
- { name: 'Bob', email: 'bob@example.com' },
209
- { name: 'Carol', email: 'carol@example.com' },
210
- ])
211
-
212
- // Upsert (on conflict)
213
- await db
214
- .insert(users)
215
- .values({ name: 'Alice', email: 'alice@example.com' })
216
- .onConflictDoUpdate({
217
- target: users.email,
218
- set: { name: 'Alice Updated' },
219
- })
220
- ```
221
-
222
- ## Update
223
-
224
- ```typescript
225
- await db
226
- .update(users)
227
- .set({ isActive: false })
228
- .where(eq(users.id, 1))
229
-
230
- // Update with returning
231
- const [updated] = await db
232
- .update(users)
233
- .set({ name: 'New Name' })
234
- .where(eq(users.id, 1))
235
- .returning()
236
- ```
237
-
238
- ## Delete
239
-
240
- ```typescript
241
- await db.delete(users).where(eq(users.id, 1))
242
-
243
- // Delete with returning
244
- const [deleted] = await db
245
- .delete(users)
246
- .where(eq(users.id, 1))
247
- .returning()
248
- ```
249
-
250
- ## Transactions
251
-
252
- ```typescript
253
- await db.transaction(async (tx) => {
254
- const [user] = await tx
255
- .insert(users)
256
- .values({ name: 'Alice', email: 'alice@example.com' })
257
- .returning()
258
-
259
- await tx.insert(posts).values({
260
- title: 'First Post',
261
- authorId: user.id,
262
- })
263
- })
264
- ```
265
-
266
- ## Entity Pattern
267
-
268
- Domain entities encapsulate data transformations between API, domain, and database layers.
269
-
270
- ```typescript
271
- import type { InferInsertModel, InferSelectModel } from 'drizzle-orm'
272
- import type { users } from './schema'
273
-
274
- type UserRecord = InferSelectModel<typeof users>
275
- type UserInsert = InferInsertModel<typeof users>
276
-
277
- class UserEntity {
278
- public readonly id: string
279
- public readonly name: string
280
- public readonly email: string
281
- public readonly createdAt: Date
282
-
283
- private constructor(data: UserEntityData) {
284
- Object.assign(this, data)
285
- }
286
-
287
- // API request → Entity
288
- static fromRequest(rq: CreateUserRequest, id?: string): UserEntity {
289
- return new UserEntity({
290
- id: id ?? crypto.randomUUID(),
291
- name: rq.name,
292
- email: rq.email,
293
- createdAt: new Date(),
294
- })
295
- }
296
-
297
- // DB record → Entity
298
- static fromRecord(record: UserRecord): UserEntity {
299
- return new UserEntity({
300
- id: record.id,
301
- name: record.name,
302
- email: record.email,
303
- createdAt: record.createdAt,
304
- })
305
- }
306
-
307
- // Entity → DB insert
308
- toRecord(): UserInsert {
309
- return {
310
- id: this.id,
311
- name: this.name,
312
- email: this.email,
313
- createdAt: this.createdAt,
314
- }
315
- }
316
-
317
- // Entity → API response
318
- toResponse(): UserResponse {
319
- return {
320
- id: this.id,
321
- name: this.name,
322
- email: this.email,
323
- createdAt: this.createdAt.toISOString(),
324
- }
325
- }
326
- }
327
- ```
328
-
329
- See [references/entity-pattern.md](./references/entity-pattern.md) for detailed examples.
330
-
331
- ## Repository Pattern
332
-
333
- Repositories wrap database access with error handling and business logic.
334
-
335
- ```typescript
336
- import { eq, and } from 'drizzle-orm'
337
- import { users } from './schema'
338
- import { UserEntity } from './entities/UserEntity'
339
-
340
- class UserRepo {
341
- constructor(private db: DrizzleDB) {}
342
-
343
- async getById(id: string): Promise<UserEntity> {
344
- const record = await this.db.query.users.findFirst({
345
- where: eq(users.id, id),
346
- })
347
- if (!record) throw new NotFoundError('User not found')
348
- return UserEntity.fromRecord(record)
349
- }
350
-
351
- async create(entity: UserEntity): Promise<UserEntity> {
352
- try {
353
- const [record] = await this.db
354
- .insert(users)
355
- .values(entity.toRecord())
356
- .returning()
357
- return UserEntity.fromRecord(record)
358
- } catch (error) {
359
- throw handleDBError(error, { userId: entity.id })
360
- }
361
- }
362
-
363
- async update(entity: UserEntity): Promise<UserEntity> {
364
- const [record] = await this.db
365
- .update(users)
366
- .set(entity.toRecord())
367
- .where(eq(users.id, entity.id))
368
- .returning()
369
- if (!record) throw new NotFoundError('User not found')
370
- return UserEntity.fromRecord(record)
371
- }
372
- }
373
- ```
374
-
375
- See [references/repository-pattern.md](./references/repository-pattern.md) for detailed examples.
376
-
377
- ## Database-Specific Guides
378
-
379
- For database-specific patterns, connection setup, migrations, and testing:
380
-
381
- - **[PostgreSQL patterns](./references/postgresql.md)** - Connection, migrations, column types, error codes, optimistic locking
382
- - **[SQLite patterns](./references/sqlite.md)** - Schema definition, type differences, better-sqlite3 testing
383
- - **[Cloudflare D1 & Durable Objects](./references/cloudflare.md)** - D1 connection, DO SQLite, testing with vitest-pool-workers, D1 vs DO decision guide
384
-
385
- ## Guidelines
386
-
387
- 1. Define schema in dedicated `schema.ts` file(s)
388
- 2. Use `$inferSelect` and `$inferInsert` for types - don't duplicate
389
- 3. Always define relations for nested queries with `db.query`
390
- 4. Pass `{ schema }` to `drizzle()` to enable relational queries
391
- 5. Use SQL-like API (`db.select()`) for complex joins
392
- 6. Use relational API (`db.query`) for nested data fetching
393
- 7. Foreign keys need explicit `references(() => table.column)`
394
- 8. Use `returning()` to get inserted/updated/deleted rows
395
- 9. Wrap database access in Repository classes for error handling
396
- 10. Use Entity classes for all data transformations (fromRequest, fromRecord, toRecord, toResponse)
397
- 11. Add `lockVersion` column for optimistic locking on mutable resources
398
- 12. Handle DB errors with specific error types (23505=conflict, 23503=not found, 40001/OC000=retry)