@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,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
- ```