@danieljvdm/dev-kit 0.11.3 → 0.12.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 (74) hide show
  1. package/README.md +70 -76
  2. package/dev-kit.example.jsonc +0 -4
  3. package/package.json +10 -6
  4. package/schema/dev-kit.schema.json +1 -46
  5. package/skills/build-effect-apis/SKILL.md +77 -0
  6. package/skills/build-effect-apis/agents/openai.yaml +4 -0
  7. package/skills/build-effect-apis/references/cloudflare-workers.md +71 -0
  8. package/skills/build-effect-apis/references/effect-atom-client.md +161 -0
  9. package/skills/build-effect-apis/references/effect-atom-lifecycle.md +78 -0
  10. package/skills/build-effect-apis/references/effect-atom-testing.md +74 -0
  11. package/skills/build-effect-apis/references/runtime-assembly.md +56 -0
  12. package/skills/build-effect-apis/references/server-and-middleware.md +174 -0
  13. package/skills/build-effect-apis/references/shared-contracts.md +108 -0
  14. package/skills/build-effect-apis/references/tanstack-start.md +86 -0
  15. package/skills/build-effect-apis/references/verification.md +50 -0
  16. package/skills/dev-kit/SKILL.md +58 -46
  17. package/skills/effect-architecture-audit/SKILL.md +26 -0
  18. package/skills/effect-architecture-audit/agents/openai.yaml +4 -0
  19. package/skills/effect-architecture-audit/references/service-and-boundary-audit.md +150 -0
  20. package/skills/effect-ts/SKILL.md +21 -256
  21. package/skills/effect-ts/agents/openai.yaml +3 -3
  22. package/skills/testing/SKILL.md +5 -0
  23. package/src/catalog-manager.ts +16 -17
  24. package/src/catalog.ts +71 -16
  25. package/src/effect-source.ts +46 -24
  26. package/src/effect-tsgo.ts +49 -24
  27. package/src/gitignore.ts +5 -5
  28. package/src/index.ts +0 -6
  29. package/src/manifest.ts +0 -34
  30. package/src/node-symbolic-link.ts +2 -2
  31. package/src/oxfmt.js +5 -0
  32. package/src/oxfmt.ts +5 -0
  33. package/src/oxlint.js +5 -0
  34. package/src/oxlint.ts +5 -0
  35. package/src/package-skill-source.ts +51 -59
  36. package/src/path-digest.ts +7 -7
  37. package/src/project-package.ts +8 -7
  38. package/src/project-process-lock.ts +17 -12
  39. package/src/project-state.ts +1 -1
  40. package/src/skill-manager.ts +16 -14
  41. package/src/skill-selector.ts +12 -0
  42. package/src/sync.ts +170 -120
  43. package/src/tool-ignore-patterns.js +9 -0
  44. package/src/tool-ignore-patterns.ts +15 -0
  45. package/src/vendor.ts +67 -61
  46. package/src/vite-plus-dependency.ts +10 -11
  47. package/src/vite-plus-hooks.ts +24 -14
  48. package/src/vite-plus-quality.ts +21 -172
  49. package/src/vite-plus.js +81 -0
  50. package/src/vite-plus.ts +102 -0
  51. package/templates/AGENTS.md +1 -1
  52. package/skills/effect-ts/UPSTREAM.md +0 -28
  53. package/skills/effect-ts/references/atom-cache-lifecycle.md +0 -78
  54. package/skills/effect-ts/references/atom-http-and-invalidation.md +0 -97
  55. package/skills/effect-ts/references/atom-tanstack-start.md +0 -69
  56. package/skills/effect-ts/references/atom-testing.md +0 -67
  57. package/skills/effect-ts/references/audit-services.md +0 -144
  58. package/skills/effect-ts/references/features.md +0 -525
  59. package/skills/effect-ts/references/guide-atom-data-fetching.md +0 -44
  60. package/skills/effect-ts/references/guide-cli.md +0 -107
  61. package/skills/effect-ts/references/guide-datetime.md +0 -72
  62. package/skills/effect-ts/references/guide-effect.md +0 -440
  63. package/skills/effect-ts/references/guide-error-handling.md +0 -565
  64. package/skills/effect-ts/references/guide-http-boundaries.md +0 -55
  65. package/skills/effect-ts/references/guide-layers.md +0 -989
  66. package/skills/effect-ts/references/guide-observability.md +0 -746
  67. package/skills/effect-ts/references/guide-retries.md +0 -434
  68. package/skills/effect-ts/references/guide-schedule.md +0 -343
  69. package/skills/effect-ts/references/guide-schema.md +0 -664
  70. package/skills/effect-ts/references/guide-sql.md +0 -536
  71. package/skills/effect-ts/references/guide-testing.md +0 -532
  72. package/skills/effect-ts/references/guide-type-safety-and-boundaries.md +0 -131
  73. package/skills/effect-ts/references/version-and-source.md +0 -86
  74. package/templates/vite-plus/vite.config.ts +0 -22
@@ -1,536 +0,0 @@
1
- # SQL Guide
2
-
3
- This guide covers Effect SQL. Apply the persistence authority, adapter
4
- ownership, dependency visibility, Schema, and honest test-layer policies from
5
- the focused local guides as well.
6
-
7
- Key source files:
8
-
9
- - `packages/effect/src/unstable/sql/SqlClient.ts`
10
- - `packages/effect/src/unstable/sql/Migrator.ts`
11
- - `packages/effect/src/unstable/sql/SqlResolver.ts`
12
- - `packages/effect/src/unstable/sql/SqlSchema.ts`
13
- - `packages/effect/src/unstable/sql/SqlModel.ts`
14
- - `packages/effect/src/unstable/sql/SqlError.ts`
15
-
16
- ## Preferred Rule
17
-
18
- When a project uses Effect, prefer the Effect SQL modules over directly coupling business code to a native SQL driver API.
19
-
20
- Prefer:
21
-
22
- - `effect/unstable/sql/SqlClient`
23
- - `effect/unstable/sql/Migrator`
24
- - `effect/unstable/sql/SqlResolver`
25
- - `effect/unstable/sql/SqlSchema`
26
- - `effect/unstable/sql/SqlModel`
27
-
28
- Over:
29
-
30
- - embedding raw driver calls directly in business services
31
- - hand-rolling transactions in service methods
32
- - ad hoc migration scripts disconnected from the Effect runtime
33
-
34
- Why:
35
-
36
- - transactions are integrated into the Effect model
37
- - spans and SQL observability are built in
38
- - SQL errors stay typed and consistent
39
- - schema decoding and request resolution compose better
40
- - layers and services stay portable across runtimes and tests
41
-
42
- ## Mental Model
43
-
44
- The Effect SQL stack is organized around:
45
-
46
- - `SqlClient` as the main database capability
47
- - `withTransaction` for transaction boundaries
48
- - `SqlResolver` for request-style batched and validated access
49
- - `SqlSchema` and `SqlModel` for schema-aware query/model patterns
50
- - `Migrator` for managed migrations
51
-
52
- The business layer should depend on Effect SQL abstractions, not on a raw driver object.
53
-
54
- ## `SqlClient`
55
-
56
- `SqlClient` is the primary service for executing SQL.
57
-
58
- Repo reference:
59
-
60
- - `packages/effect/src/unstable/sql/SqlClient.ts`
61
-
62
- Use it when:
63
-
64
- - you need to execute queries
65
- - you need transactions
66
- - you want SQL operations to participate in Effect spans and context
67
-
68
- Important capabilities from the repo:
69
-
70
- - transaction support with `withTransaction`
71
- - connection reservation with `reserve`
72
- - reactive queries
73
- - integration with transaction-scoped context
74
-
75
- ## Typed Queries
76
-
77
- Prefer typed SQL queries instead of leaving row shapes implicit.
78
-
79
- The repo uses typed query literals like:
80
-
81
- ```ts
82
- const rows = yield * sql<{ id: number; name: string }>`SELECT * FROM test`;
83
- ```
84
-
85
- This is the first level of typed SQL usage and is already better than untyped row access.
86
-
87
- Use typed query literals when:
88
-
89
- - the row shape is small and obvious
90
- - the query is local and does not justify a reusable schema
91
- - you want immediate row typing without introducing extra helpers
92
-
93
- Avoid:
94
-
95
- - leaving query results untyped and then recovering shape with unsafe assertions
96
- - using `as` on rows after query execution
97
-
98
- ## Schema Integration
99
-
100
- Prefer integrating SQL with Schema whenever the row shape matters or the query result crosses a meaningful boundary.
101
-
102
- Why:
103
-
104
- - Schema validates the shape rather than trusting the database blindly
105
- - row decoding stays explicit and typed
106
- - the same schema can often be reused for transport, domain, or contract layers
107
- - this avoids unsafe row assertions such as `as TodoRow`
108
-
109
- ### Prefer schema-decoded results over `as`-based rows
110
-
111
- Avoid this pattern:
112
-
113
- ```ts
114
- const row = yield * sql`SELECT id, title FROM todos WHERE id = ${id}`;
115
- const todo = row[0] as TodoRow;
116
- ```
117
-
118
- Prefer:
119
-
120
- - a typed SQL query plus Schema decoding
121
- - or a SQL helper such as `SqlResolver`, `SqlSchema`, or `SqlModel` when appropriate
122
-
123
- Example boundary decode:
124
-
125
- ```ts
126
- const TodoRow = Schema.Struct({
127
- id: Schema.Number,
128
- title: Schema.String,
129
- completed: Schema.Boolean,
130
- });
131
-
132
- const decodeTodoRows = Schema.decodeUnknownEffect(Schema.Array(TodoRow));
133
- ```
134
-
135
- Then keep the query and decoding together in one SQL-aware operation.
136
-
137
- ### `SqlResolver` + Schema
138
-
139
- `SqlResolver` is one of the clearest examples of SQL and Schema integration in the canonical source.
140
-
141
- It uses:
142
-
143
- - a `Request` schema for validating resolver input
144
- - a `Result` schema for validating query output
145
-
146
- Example shape from the repo tests:
147
-
148
- ```ts
149
- const resolver = SqlResolver.findById({
150
- Id: Schema.Number,
151
- Result: Schema.Struct({
152
- id: Schema.Number,
153
- name: Schema.String,
154
- }),
155
- ResultId: (row) => row.id,
156
- execute: (ids) => sql`SELECT * FROM test WHERE id IN ${sql.in(ids)}`,
157
- });
158
- ```
159
-
160
- This is a preferred pattern when:
161
-
162
- - multiple IDs are fetched together
163
- - request batching is useful
164
- - the query contract should be schema-validated
165
-
166
- ### `SqlSchema` and `SqlModel`
167
-
168
- Use `SqlSchema` and `SqlModel` when you want tighter schema integration with SQL itself.
169
-
170
- They are preferred over hand-written row types when:
171
-
172
- - the row shape is central to the module
173
- - you want reusable schema-aware model logic
174
- - manual row mapping is becoming repetitive
175
-
176
- ## Prefer SQL Services Over Native Driver Services
177
-
178
- Avoid this pattern:
179
-
180
- ```ts
181
- class TodoService extends Context.Service<TodoService, { ... }>()("TodoService") {
182
- static readonly layer = Layer.effect(this)(
183
- Effect.acquireRelease(
184
- Effect.try({ try: () => new Database("todos.sqlite") })
185
- )
186
- )
187
- }
188
- ```
189
-
190
- Why this is usually a bad pattern in an Effect codebase:
191
-
192
- - the service is now tightly coupled to one runtime-specific database client
193
- - you lose the shared SQL abstraction that the Effect repo already provides
194
- - transaction and query conventions become ad hoc
195
- - it is easier to drift away from typed SQL errors, SQL tracing, and reusable query helpers
196
-
197
- Prefer a layer that provides `SqlClient`, and let domain services depend on that.
198
-
199
- ## Domain Services Should Depend On `SqlClient`
200
-
201
- Good pattern:
202
-
203
- ```ts
204
- import * as Context from "effect/Context";
205
- import * as Effect from "effect/Effect";
206
- import * as SqlClient from "effect/unstable/sql/SqlClient";
207
-
208
- class TodoRepo extends Context.Service<TodoRepo>()("TodoRepo", {
209
- make: Effect.succeed({
210
- getById: Effect.fn("TodoRepo.getById")(function* (id: number) {
211
- const sql = yield* SqlClient.SqlClient;
212
- return yield* sql`SELECT id, title, completed FROM todos WHERE id = ${id}`;
213
- }),
214
- }),
215
- }) {}
216
- ```
217
-
218
- Why this is better:
219
-
220
- - the domain service depends on an Effect SQL capability
221
- - SQL stays observable and transactional
222
- - the SQL client implementation can be provided separately from the business service
223
-
224
- ## Transactions
225
-
226
- Yield `SqlClient.SqlClient`, then use the service's `sql.withTransaction`
227
- method for transaction boundaries.
228
-
229
- Repo reference:
230
-
231
- - `packages/effect/src/unstable/sql/SqlClient.ts`
232
-
233
- Prefer:
234
-
235
- ```ts
236
- const createAndAudit = Effect.fn("TodoRepo.createAndAudit")(function* (title: string) {
237
- const sql = yield* SqlClient.SqlClient;
238
-
239
- return yield* sql.withTransaction(
240
- Effect.gen(function* () {
241
- yield* sql`INSERT INTO todos ${sql.insert({ title, completed: false })}`;
242
- yield* sql`INSERT INTO audit_log ${sql.insert({ event: "todo_created" })}`;
243
- }),
244
- );
245
- });
246
- ```
247
-
248
- Avoid:
249
-
250
- - manual `BEGIN` / `COMMIT` / `ROLLBACK` in application service code
251
- - driver-specific transaction logic spread across multiple service methods
252
-
253
- ## Query Composition
254
-
255
- Prefer keeping query logic inside SQL-aware services or repositories.
256
-
257
- Good patterns:
258
-
259
- - keep queries close to the service that owns the behavior
260
- - use named business operations for multi-step workflows
261
- - use small local helpers only when they improve clarity
262
-
263
- Avoid exposing one exported accessor function per SQL service method if it only forwards to the service.
264
-
265
- Bad:
266
-
267
- ```ts
268
- export const createTodo = Effect.fn(function* (title: string) {
269
- const todos = yield* TodoRepo;
270
- return yield* todos.create(title);
271
- });
272
- ```
273
-
274
- Prefer:
275
-
276
- - use the service method directly within the owning workflow
277
- - or export a real business operation that adds behavior beyond simple forwarding
278
-
279
- ## SQL Resolvers
280
-
281
- Use `SqlResolver` when request-style batching or schema-validated request/response handling is useful.
282
-
283
- Repo reference:
284
-
285
- - `packages/effect/src/unstable/sql/SqlResolver.ts`
286
-
287
- It is especially good for:
288
-
289
- - batched lookup patterns
290
- - `findById`-style resolvers
291
- - grouped query resolution
292
- - integrating SQL with request batching patterns
293
-
294
- Important repo pattern:
295
-
296
- - request schema validates inputs
297
- - result schema validates outputs
298
- - execution remains effectful and transactional
299
-
300
- This is one of the strongest typed-query patterns in the repo and should be preferred over ad hoc batched row mapping when the query fits the resolver model.
301
-
302
- ## SQL Schemas And Models
303
-
304
- When schema-aware SQL helpers fit the task, prefer them over hand-mapped rows.
305
-
306
- Look at:
307
-
308
- - `SqlSchema`
309
- - `SqlModel`
310
-
311
- These are good fits when:
312
-
313
- - the row shape matters strongly
314
- - schema-based decode/encode should stay aligned with database access
315
- - you want to reduce ad hoc row mapping logic
316
-
317
- Avoid overusing manual `type Row = { ... }` plus custom conversion if the schema-aware modules already express the shape clearly.
318
-
319
- Preferred order for query typing:
320
-
321
- 1. schema-aware SQL module such as `SqlResolver`, `SqlSchema`, or `SqlModel` when it fits
322
- 2. typed query literals plus Schema decoding when the query is local
323
- 3. only use manual row mapping when the first two options are clearly heavier than the problem
324
-
325
- ## Migrations
326
-
327
- Use `Migrator` for migrations.
328
-
329
- Repo reference:
330
-
331
- - `packages/effect/src/unstable/sql/Migrator.ts`
332
-
333
- The repo shows these best practices:
334
-
335
- - maintain a dedicated migrations table
336
- - load migrations through a managed loader
337
- - run migrations through the Effect runtime
338
- - keep migration execution observable with logs and spans
339
- - use SQL client transaction and locking semantics handled by the migrator
340
-
341
- Important behavior in the canonical source:
342
-
343
- - migrations table creation is dialect-aware
344
- - duplicate migration IDs are detected
345
- - concurrent migration runs are guarded
346
- - each migration is logged and wrapped in a span
347
-
348
- ### Concrete Migration Loader Example
349
-
350
- The runtime-specific SQL migrator packages expose `fromRecord(...)` to define migrations from an ordered record.
351
-
352
- Example shape:
353
-
354
- ```ts
355
- import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator";
356
- import * as Effect from "effect/Effect";
357
-
358
- const migrations = SqliteMigrator.fromRecord({
359
- "1_create_todos": Effect.gen(function* () {
360
- yield* sql`
361
- CREATE TABLE todos (
362
- id INTEGER PRIMARY KEY NOT NULL,
363
- title TEXT NOT NULL,
364
- completed INTEGER NOT NULL DEFAULT 0
365
- )
366
- `.withoutTransform;
367
- }),
368
- "2_add_todo_index": Effect.gen(function* () {
369
- yield* sql`
370
- CREATE INDEX todos_completed_idx ON todos (completed)
371
- `.withoutTransform;
372
- }),
373
- });
374
- ```
375
-
376
- This matches the model used by the canonical migrator implementation:
377
-
378
- - each migration has a numeric prefix and descriptive name
379
- - each migration resolves to an `Effect`
380
- - migrations are ordered by ID
381
-
382
- ### Running Migrations Directly
383
-
384
- Use the runtime-specific `run(...)` helper when you want a startup effect that runs migrations explicitly.
385
-
386
- Example shape:
387
-
388
- ```ts
389
- import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator";
390
-
391
- const runMigrations = SqliteMigrator.run({
392
- loader: migrations,
393
- });
394
- ```
395
-
396
- This is a good fit when:
397
-
398
- - startup explicitly runs migrations before launching the main app
399
- - deployment tooling runs migrations as a separate command
400
- - you want migration results as an ordinary `Effect`
401
-
402
- The return value includes the applied migration IDs and names.
403
-
404
- ### Running Migrations As A Layer
405
-
406
- Use the runtime-specific `layer(...)` helper when migrations should run as part of top-level infrastructure setup.
407
-
408
- Example shape:
409
-
410
- ```ts
411
- import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator";
412
-
413
- const MigrationLayer = SqliteMigrator.layer({
414
- loader: migrations,
415
- });
416
- ```
417
-
418
- From the canonical packages, this is implemented as `Layer.effectDiscard(run(options))`.
419
-
420
- That means:
421
-
422
- - the layer performs the migration effect
423
- - it does not provide a new service of its own
424
- - it is intended to be composed into startup infrastructure
425
-
426
- ### Concrete Startup Composition Example
427
-
428
- Preferred shape:
429
-
430
- ```ts
431
- const SqlLayer = SqliteClient.layer({ filename: "todos.sqlite" });
432
-
433
- const MigrationLayer = SqliteMigrator.layer({
434
- loader: migrations,
435
- });
436
-
437
- const MigratedSqlLayer = Layer.merge(SqlLayer, MigrationLayer.pipe(Layer.provide(SqlLayer)));
438
- ```
439
-
440
- This keeps the structure explicit:
441
-
442
- - one layer provides the SQL client
443
- - one layer runs migrations
444
- - the merged layer represents a migrated SQL environment
445
-
446
- If the same migrated SQL environment is reused in tests, create it once and reuse the layer value.
447
-
448
- ### Migration Best Practices
449
-
450
- - use stable numeric migration IDs
451
- - keep migration files ordered and unique
452
- - do not hand-roll a separate migrations subsystem if `Migrator` already fits the project
453
- - keep migration execution at startup or a dedicated operational boundary
454
- - do not bury migration execution inside arbitrary service construction unless startup is explicitly the right place
455
-
456
- ### Preferred Migration Boundary
457
-
458
- Good pattern:
459
-
460
- - construct the SQL layer
461
- - run migrations once at startup or deployment entry
462
- - then run the main application
463
-
464
- Concrete shapes:
465
-
466
- - separate startup effect: `SqliteMigrator.run({ loader })`
467
- - startup layer: `SqliteMigrator.layer({ loader })`
468
- - migrated environment layer: merge the SQL client layer with the migration layer provided by that client layer
469
-
470
- Avoid:
471
-
472
- - opportunistic migrations inside ordinary request handlers
473
- - schema creation hidden inside unrelated business service constructors
474
-
475
- ## Errors
476
-
477
- Prefer SQL errors that stay inside the Effect SQL model as long as possible.
478
-
479
- Use domain-level translation only where it helps the business boundary.
480
-
481
- Good:
482
-
483
- - SQL layer or repository works with `SqlError` and schema decode failures where appropriate
484
- - higher-level service translates expected cases into domain errors when needed
485
-
486
- Avoid:
487
-
488
- - converting every SQL error immediately into a string
489
- - hiding SQL failure details too early
490
-
491
- ## Observability
492
-
493
- The canonical SQL modules already integrate with spans and transaction context.
494
-
495
- This is another reason to prefer them over raw driver usage.
496
-
497
- Good pattern:
498
-
499
- - use `SqlClient` and `withTransaction`
500
- - keep business operations wrapped with `Effect.fn`
501
- - add explicit spans only where business-level detail matters beyond the built-in SQL spans
502
-
503
- ## Layering Pattern
504
-
505
- Preferred layering shape:
506
-
507
- 1. runtime-specific database layer provides `SqlClient`
508
- 2. migrations run at startup boundary
509
- 3. domain repository/service depends on `SqlClient`
510
- 4. top-level application layer composes the database layer with the business layers
511
-
512
- This keeps:
513
-
514
- - driver choice at the edge
515
- - SQL capability in the middle
516
- - business logic above it
517
-
518
- ## Anti-Patterns
519
-
520
- - embedding a native driver directly in business services when Effect SQL modules are available
521
- - hand-rolling transactions with raw SQL statements in service methods
522
- - hiding schema creation inside unrelated service constructors
523
- - exporting one trivial accessor function per repository/service method
524
- - converting SQL errors to strings too early
525
- - bypassing `Migrator` when the project already uses Effect SQL
526
- - creating ad hoc migration effects without a stable loader shape when `fromRecord(...)` already fits the project
527
- - scattering migration execution across multiple subsystems instead of one explicit startup boundary
528
-
529
- ## Good Repo Examples To Study
530
-
531
- - `packages/effect/src/unstable/sql/SqlClient.ts`
532
- - `packages/effect/src/unstable/sql/Migrator.ts`
533
- - `packages/effect/src/unstable/sql/SqlResolver.ts`
534
- - `packages/effect/src/unstable/sql/SqlSchema.ts`
535
- - `packages/effect/src/unstable/sql/SqlModel.ts`
536
- - `packages/effect/src/unstable/sql/SqlError.ts`