@martinffx/atelier 2.0.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 (81) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +94 -253
  3. package/package.json +1 -1
  4. package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
  5. package/skills/atelier-setup/SKILL.md +80 -0
  6. package/skills/code-review/references/reviewers.md +3 -3
  7. package/skills/code-review/references/rq.md +6 -6
  8. package/skills/spec-brainstorm/SKILL.md +5 -5
  9. package/skills/spec-implement/SKILL.md +2 -3
  10. package/skills/spec-plan/SKILL.md +21 -29
  11. package/skills/spec-plan/references/plan_template.md +77 -0
  12. package/skills/python-architecture/SKILL.md +0 -148
  13. package/skills/python-architecture/references/data-modeling.md +0 -558
  14. package/skills/python-architecture/references/ddd.md +0 -569
  15. package/skills/python-architecture/references/functional-core.md +0 -337
  16. package/skills/python-build-tools/SKILL.md +0 -153
  17. package/skills/python-build-tools/references/basedpyright.md +0 -321
  18. package/skills/python-build-tools/references/ruff.md +0 -225
  19. package/skills/python-build-tools/references/uv.md +0 -257
  20. package/skills/python-fastapi/SKILL.md +0 -184
  21. package/skills/python-fastapi/references/api-design.md +0 -563
  22. package/skills/python-fastapi/references/dependencies.md +0 -479
  23. package/skills/python-fastapi/references/middleware.md +0 -475
  24. package/skills/python-fastapi/references/validation.md +0 -497
  25. package/skills/python-modern-python/SKILL.md +0 -201
  26. package/skills/python-modern-python/references/async.md +0 -76
  27. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  28. package/skills/python-modern-python/references/typing.md +0 -96
  29. package/skills/python-monorepo/SKILL.md +0 -146
  30. package/skills/python-monorepo/references/docker.md +0 -515
  31. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  32. package/skills/python-monorepo/references/workspace-config.md +0 -341
  33. package/skills/python-sqlalchemy/SKILL.md +0 -119
  34. package/skills/python-sqlalchemy/references/async.md +0 -51
  35. package/skills/python-sqlalchemy/references/models.md +0 -67
  36. package/skills/python-sqlalchemy/references/queries.md +0 -57
  37. package/skills/python-temporal/SKILL.md +0 -128
  38. package/skills/python-temporal/references/patterns.md +0 -87
  39. package/skills/python-temporal/references/testing.md +0 -54
  40. package/skills/python-testing/SKILL.md +0 -161
  41. package/skills/python-testing/references/boundaries.md +0 -449
  42. package/skills/python-testing/references/mocking.md +0 -449
  43. package/skills/python-testing/references/pytest.md +0 -524
  44. package/skills/typescript-api-design/SKILL.md +0 -396
  45. package/skills/typescript-api-design/references/error-responses.md +0 -469
  46. package/skills/typescript-build-tools/SKILL.md +0 -447
  47. package/skills/typescript-build-tools/references/biome.md +0 -436
  48. package/skills/typescript-build-tools/references/bun.md +0 -432
  49. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  50. package/skills/typescript-build-tools/references/vitest.md +0 -518
  51. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  52. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  53. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  54. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  55. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  56. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  57. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  58. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  59. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  60. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  61. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  62. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  63. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  64. package/skills/typescript-effect-ts/SKILL.md +0 -341
  65. package/skills/typescript-effect-ts/references/core.md +0 -412
  66. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  67. package/skills/typescript-effect-ts/references/resources.md +0 -476
  68. package/skills/typescript-effect-ts/references/schema.md +0 -536
  69. package/skills/typescript-effect-ts/references/services.md +0 -461
  70. package/skills/typescript-fastify/SKILL.md +0 -405
  71. package/skills/typescript-fastify/references/plugins.md +0 -329
  72. package/skills/typescript-fastify/references/typeid.md +0 -315
  73. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  74. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  75. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  76. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  77. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  78. package/skills/typescript-testing/SKILL.md +0 -353
  79. package/skills/typescript-testing/references/mocking.md +0 -675
  80. package/skills/typescript-testing/references/msw.md +0 -852
  81. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,476 +0,0 @@
1
- # Resource Management in Effect
2
-
3
- Effect provides powerful primitives for managing resources that need cleanup, ensuring they're always released even on failure or interruption.
4
-
5
- ## acquireRelease - Basic Resource Pattern
6
-
7
- The core pattern for resource management:
8
-
9
- ```typescript
10
- import { Effect } from "effect"
11
-
12
- // Define a resource with acquisition and release
13
- const withFile = (path: string) =>
14
- Effect.acquireRelease(
15
- // Acquire: runs to get the resource
16
- Effect.sync(() => {
17
- console.log(`Opening file: ${path}`)
18
- return { path, handle: fs.openSync(path, "r") }
19
- }),
20
- // Release: always runs when scope closes
21
- (file) => Effect.sync(() => {
22
- console.log(`Closing file: ${file.path}`)
23
- fs.closeSync(file.handle)
24
- })
25
- )
26
- ```
27
-
28
- ### Using Resources with Scope
29
-
30
- ```typescript
31
- import { Effect } from "effect"
32
-
33
- // Effect.scoped provides a scope and runs release after use
34
- const program = Effect.scoped(
35
- Effect.gen(function* () {
36
- const file = yield* withFile("/path/to/file")
37
- const content = yield* readFile(file)
38
- return content
39
- })
40
- )
41
- // File is automatically closed after reading
42
-
43
- Effect.runPromise(program)
44
- ```
45
-
46
- ### Resource Guarantees
47
-
48
- - **Release always runs** - Even if the using code fails or throws
49
- - **Release runs on interruption** - If the fiber is interrupted
50
- - **Typed errors** - Release errors are tracked in the type system
51
-
52
- ## acquireUseRelease - Inline Pattern
53
-
54
- For one-off resource usage:
55
-
56
- ```typescript
57
- import { Effect } from "effect"
58
-
59
- const readConfig = Effect.acquireUseRelease(
60
- // Acquire
61
- Effect.sync(() => fs.openSync("config.json", "r")),
62
- // Use
63
- (handle) => Effect.sync(() => {
64
- const content = fs.readFileSync(handle, "utf-8")
65
- return JSON.parse(content)
66
- }),
67
- // Release
68
- (handle) => Effect.sync(() => fs.closeSync(handle))
69
- )
70
-
71
- // No explicit scoping needed - handled internally
72
- const config = await Effect.runPromise(readConfig)
73
- ```
74
-
75
- ## Multiple Resources
76
-
77
- ### Sequential Acquisition
78
-
79
- ```typescript
80
- import { Effect } from "effect"
81
-
82
- const program = Effect.scoped(
83
- Effect.gen(function* () {
84
- // Resources acquired in order
85
- const db = yield* withDatabaseConnection()
86
- const cache = yield* withCacheConnection()
87
- const queue = yield* withMessageQueue()
88
-
89
- // Use all three...
90
- yield* doWork(db, cache, queue)
91
-
92
- // Released in reverse order: queue → cache → db
93
- })
94
- )
95
- ```
96
-
97
- ### Parallel Acquisition
98
-
99
- ```typescript
100
- import { Effect } from "effect"
101
-
102
- const program = Effect.scoped(
103
- Effect.gen(function* () {
104
- // Acquire resources in parallel
105
- const [db, cache, queue] = yield* Effect.all([
106
- withDatabaseConnection(),
107
- withCacheConnection(),
108
- withMessageQueue()
109
- ], { concurrency: "unbounded" })
110
-
111
- yield* doWork(db, cache, queue)
112
- })
113
- )
114
- ```
115
-
116
- ## Scope - Manual Control
117
-
118
- For more control over resource lifecycle:
119
-
120
- ```typescript
121
- import { Effect, Scope } from "effect"
122
-
123
- const program = Effect.gen(function* () {
124
- // Create a manual scope
125
- const scope = yield* Scope.make()
126
-
127
- // Add resources to scope
128
- const db = yield* Scope.extend(scope)(withDatabaseConnection())
129
- const cache = yield* Scope.extend(scope)(withCacheConnection())
130
-
131
- // Use resources...
132
- yield* doWork(db, cache)
133
-
134
- // Manually close scope when done
135
- yield* Scope.close(scope, Exit.succeed(void 0))
136
- })
137
- ```
138
-
139
- ### Scope Forking
140
-
141
- ```typescript
142
- import { Effect, Scope } from "effect"
143
-
144
- const program = Effect.gen(function* () {
145
- // Fork scope to create child scope
146
- const parentScope = yield* Effect.scope
147
- const childScope = yield* Scope.fork(parentScope)
148
-
149
- // Resources in child scope
150
- const tempFile = yield* Scope.extend(childScope)(withTempFile())
151
-
152
- // Close child scope (releases tempFile)
153
- yield* Scope.close(childScope, Exit.succeed(void 0))
154
-
155
- // Parent scope continues...
156
- })
157
- ```
158
-
159
- ## Resource Finalization
160
-
161
- ### Ensuring Finalization
162
-
163
- ```typescript
164
- import { Effect } from "effect"
165
-
166
- const program = Effect.gen(function* () {
167
- yield* doWork()
168
- }).pipe(
169
- // Runs regardless of success/failure
170
- Effect.ensuring(
171
- Effect.sync(() => console.log("Cleanup complete"))
172
- )
173
- )
174
- ```
175
-
176
- ### onExit - Conditional Finalization
177
-
178
- ```typescript
179
- import { Effect, Exit } from "effect"
180
-
181
- const program = effect.pipe(
182
- Effect.onExit((exit) => {
183
- if (Exit.isSuccess(exit)) {
184
- return Effect.sync(() => console.log("Success:", exit.value))
185
- } else {
186
- return Effect.sync(() => console.log("Failed:", exit.cause))
187
- }
188
- })
189
- )
190
- ```
191
-
192
- ### addFinalizer - Add to Current Scope
193
-
194
- ```typescript
195
- import { Effect } from "effect"
196
-
197
- const program = Effect.scoped(
198
- Effect.gen(function* () {
199
- // Add finalizer to current scope
200
- yield* Effect.addFinalizer((exit) =>
201
- Effect.sync(() => {
202
- console.log("Cleaning up, exit was:", Exit.isSuccess(exit))
203
- })
204
- )
205
-
206
- yield* doWork()
207
- })
208
- )
209
- ```
210
-
211
- ## Common Resource Patterns
212
-
213
- ### Database Connection Pool
214
-
215
- ```typescript
216
- import { Effect, Layer, Scope } from "effect"
217
-
218
- interface ConnectionPool {
219
- getConnection: () => Effect.Effect<Connection, PoolError>
220
- release: (conn: Connection) => Effect.Effect<void>
221
- }
222
-
223
- const makeConnectionPool = (config: PoolConfig) =>
224
- Effect.acquireRelease(
225
- // Create pool
226
- Effect.sync(() => {
227
- console.log("Creating connection pool...")
228
- return {
229
- connections: [] as Connection[],
230
- getConnection: () => Effect.sync(() => createConnection()),
231
- release: (conn) => Effect.sync(() => releaseToPool(conn))
232
- }
233
- }),
234
- // Close all connections
235
- (pool) => Effect.sync(() => {
236
- console.log("Closing all pool connections...")
237
- pool.connections.forEach(conn => conn.close())
238
- })
239
- )
240
-
241
- const ConnectionPoolLive = Layer.scoped(
242
- ConnectionPool,
243
- makeConnectionPool({ size: 10 })
244
- )
245
- ```
246
-
247
- ### File Handle
248
-
249
- ```typescript
250
- import { Effect } from "effect"
251
- import * as fs from "fs/promises"
252
-
253
- const withFile = (path: string, flags: string) =>
254
- Effect.acquireRelease(
255
- Effect.tryPromise({
256
- try: () => fs.open(path, flags),
257
- catch: (e) => new FileOpenError(path, e)
258
- }),
259
- (handle) => Effect.promise(() => handle.close())
260
- )
261
-
262
- const readFile = (path: string) =>
263
- Effect.scoped(
264
- Effect.gen(function* () {
265
- const handle = yield* withFile(path, "r")
266
- const content = yield* Effect.tryPromise({
267
- try: () => handle.readFile("utf-8"),
268
- catch: (e) => new FileReadError(path, e)
269
- })
270
- return content
271
- })
272
- )
273
- ```
274
-
275
- ### HTTP Client with Cleanup
276
-
277
- ```typescript
278
- import { Effect } from "effect"
279
-
280
- const withHttpClient = Effect.acquireRelease(
281
- Effect.sync(() => {
282
- console.log("Creating HTTP client...")
283
- return new HttpClient({
284
- timeout: 30000,
285
- keepAlive: true
286
- })
287
- }),
288
- (client) => Effect.sync(() => {
289
- console.log("Destroying HTTP client...")
290
- client.destroy()
291
- })
292
- )
293
-
294
- const fetchData = (url: string) =>
295
- Effect.scoped(
296
- Effect.gen(function* () {
297
- const client = yield* withHttpClient
298
- const response = yield* Effect.tryPromise({
299
- try: () => client.get(url),
300
- catch: (e) => new FetchError(url, e)
301
- })
302
- return response.data
303
- })
304
- )
305
- ```
306
-
307
- ### Temporary Directory
308
-
309
- ```typescript
310
- import { Effect } from "effect"
311
- import * as fs from "fs/promises"
312
- import * as os from "os"
313
- import * as path from "path"
314
-
315
- const withTempDir = Effect.acquireRelease(
316
- Effect.tryPromise({
317
- try: async () => {
318
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), "app-"))
319
- console.log(`Created temp dir: ${dir}`)
320
- return dir
321
- },
322
- catch: (e) => new TempDirError(e)
323
- }),
324
- (dir) => Effect.tryPromise({
325
- try: async () => {
326
- console.log(`Removing temp dir: ${dir}`)
327
- await fs.rm(dir, { recursive: true, force: true })
328
- },
329
- catch: () => void 0 // Ignore cleanup errors
330
- })
331
- )
332
-
333
- const processWithTempFiles = Effect.scoped(
334
- Effect.gen(function* () {
335
- const tempDir = yield* withTempDir
336
-
337
- // Create temp files in directory
338
- const tempFile = path.join(tempDir, "data.json")
339
- yield* Effect.tryPromise({
340
- try: () => fs.writeFile(tempFile, JSON.stringify(data)),
341
- catch: (e) => new WriteError(e)
342
- })
343
-
344
- // Process...
345
- const result = yield* processFile(tempFile)
346
-
347
- return result
348
- // Temp dir and all contents deleted automatically
349
- })
350
- )
351
- ```
352
-
353
- ### Lock/Mutex
354
-
355
- ```typescript
356
- import { Effect, Ref, Deferred } from "effect"
357
-
358
- const withLock = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
359
- Effect.gen(function* () {
360
- const lock = yield* Ref.make(false)
361
-
362
- // Acquire lock
363
- yield* Effect.repeatUntil(
364
- Ref.getAndSet(lock, true),
365
- (acquired) => acquired === false
366
- )
367
-
368
- // Use with guaranteed release
369
- return yield* effect.pipe(
370
- Effect.ensuring(Ref.set(lock, false))
371
- )
372
- })
373
- ```
374
-
375
- ## Interruption Safety
376
-
377
- ### Making Resources Interruption-Safe
378
-
379
- ```typescript
380
- import { Effect } from "effect"
381
-
382
- const criticalOperation = Effect.gen(function* () {
383
- const resource = yield* acquireResource()
384
-
385
- // This section cannot be interrupted
386
- yield* Effect.uninterruptible(
387
- Effect.gen(function* () {
388
- yield* step1(resource)
389
- yield* step2(resource)
390
- yield* step3(resource)
391
- })
392
- )
393
-
394
- yield* releaseResource(resource)
395
- })
396
- ```
397
-
398
- ### Interruptible Regions
399
-
400
- ```typescript
401
- import { Effect } from "effect"
402
-
403
- const program = Effect.uninterruptible(
404
- Effect.gen(function* () {
405
- yield* criticalSetup()
406
-
407
- // Allow interruption in this region
408
- yield* Effect.interruptible(
409
- longRunningTask()
410
- )
411
-
412
- yield* criticalCleanup()
413
- })
414
- )
415
- ```
416
-
417
- ## Best Practices
418
-
419
- 1. **Use acquireRelease for resources** - Never rely on manual cleanup
420
- 2. **Scope resources appropriately** - Keep scopes as small as practical
421
- 3. **Order matters** - Resources release in reverse acquisition order
422
- 4. **Handle release errors** - Release should not throw; log and continue
423
- 5. **Use Layer.scoped for services** - Service lifecycle tied to app lifecycle
424
- 6. **Test resource cleanup** - Verify resources release on failure paths
425
- 7. **Avoid nested scopes when possible** - Flatten for clarity
426
- 8. **Make critical sections uninterruptible** - Protect invariants
427
-
428
- ## Common Mistakes
429
-
430
- ### Forgetting to Scope
431
-
432
- ```typescript
433
- // Bad: resource never released
434
- const bad = Effect.gen(function* () {
435
- const file = yield* withFile("data.txt")
436
- return yield* readContent(file)
437
- })
438
-
439
- // Good: scoped ensures release
440
- const good = Effect.scoped(
441
- Effect.gen(function* () {
442
- const file = yield* withFile("data.txt")
443
- return yield* readContent(file)
444
- })
445
- )
446
- ```
447
-
448
- ### Releasing in Acquire
449
-
450
- ```typescript
451
- // Bad: release in acquire, not as finalizer
452
- const bad = Effect.sync(() => {
453
- const conn = createConnection()
454
- return { conn, close: () => conn.close() } // Caller must remember
455
- })
456
-
457
- // Good: automatic release
458
- const good = Effect.acquireRelease(
459
- Effect.sync(() => createConnection()),
460
- (conn) => Effect.sync(() => conn.close())
461
- )
462
- ```
463
-
464
- ### Swallowing Release Errors
465
-
466
- ```typescript
467
- // Acceptable: log but don't fail
468
- const resource = Effect.acquireRelease(
469
- acquire,
470
- (r) => release(r).pipe(
471
- Effect.catchAll((error) =>
472
- Effect.sync(() => console.error("Release error:", error))
473
- )
474
- )
475
- )
476
- ```