@danieljvdm/dev-kit 0.11.3 → 0.13.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.
- package/README.md +111 -78
- package/dev-kit.example.jsonc +0 -4
- package/package.json +10 -6
- package/schema/dev-kit.schema.json +1 -46
- package/skills/build-effect-apis/SKILL.md +77 -0
- package/skills/build-effect-apis/agents/openai.yaml +4 -0
- package/skills/build-effect-apis/references/cloudflare-workers.md +71 -0
- package/skills/build-effect-apis/references/effect-atom-client.md +161 -0
- package/skills/build-effect-apis/references/effect-atom-lifecycle.md +78 -0
- package/skills/build-effect-apis/references/effect-atom-testing.md +74 -0
- package/skills/build-effect-apis/references/runtime-assembly.md +56 -0
- package/skills/build-effect-apis/references/server-and-middleware.md +174 -0
- package/skills/build-effect-apis/references/shared-contracts.md +108 -0
- package/skills/build-effect-apis/references/tanstack-start.md +86 -0
- package/skills/build-effect-apis/references/verification.md +50 -0
- package/skills/build-effect-clis/SKILL.md +61 -0
- package/skills/build-effect-clis/agents/openai.yaml +4 -0
- package/skills/build-effect-clis/references/command-design.md +93 -0
- package/skills/build-effect-clis/references/entrypoints-and-testing.md +59 -0
- package/skills/build-effect-clis/references/processes-and-platform.md +73 -0
- package/skills/dev-kit/SKILL.md +77 -48
- package/skills/effect-architecture-audit/SKILL.md +26 -0
- package/skills/effect-architecture-audit/agents/openai.yaml +4 -0
- package/skills/effect-architecture-audit/references/service-and-boundary-audit.md +150 -0
- package/skills/effect-ts/SKILL.md +21 -256
- package/skills/effect-ts/agents/openai.yaml +3 -3
- package/skills/testing/SKILL.md +5 -0
- package/src/catalog-manager.ts +16 -17
- package/src/catalog.ts +71 -16
- package/src/effect-source.ts +46 -24
- package/src/effect-tsgo.ts +86 -24
- package/src/gitignore.ts +5 -5
- package/src/index.ts +3 -6
- package/src/manifest.ts +0 -34
- package/src/node-symbolic-link.ts +2 -2
- package/src/oxfmt.js +5 -0
- package/src/oxfmt.ts +5 -0
- package/src/oxlint.js +5 -0
- package/src/oxlint.ts +5 -0
- package/src/package-skill-source.ts +51 -59
- package/src/path-digest.ts +7 -7
- package/src/project-package.ts +8 -7
- package/src/project-process-lock.ts +17 -12
- package/src/project-state.ts +1 -1
- package/src/skill-manager.ts +18 -16
- package/src/skill-selector.ts +12 -0
- package/src/sync.ts +181 -131
- package/src/tool-ignore-patterns.js +9 -0
- package/src/tool-ignore-patterns.ts +15 -0
- package/src/vendor.ts +67 -61
- package/src/vite-plus-dependency.ts +10 -11
- package/src/vite-plus-hooks.ts +24 -14
- package/src/vite-plus-quality.ts +21 -172
- package/src/vite-plus.js +81 -0
- package/src/vite-plus.ts +102 -0
- package/templates/AGENTS.md +1 -1
- package/skills/effect-ts/UPSTREAM.md +0 -28
- package/skills/effect-ts/references/atom-cache-lifecycle.md +0 -78
- package/skills/effect-ts/references/atom-http-and-invalidation.md +0 -97
- package/skills/effect-ts/references/atom-tanstack-start.md +0 -69
- package/skills/effect-ts/references/atom-testing.md +0 -67
- package/skills/effect-ts/references/audit-services.md +0 -144
- package/skills/effect-ts/references/features.md +0 -525
- package/skills/effect-ts/references/guide-atom-data-fetching.md +0 -44
- package/skills/effect-ts/references/guide-cli.md +0 -107
- package/skills/effect-ts/references/guide-datetime.md +0 -72
- package/skills/effect-ts/references/guide-effect.md +0 -440
- package/skills/effect-ts/references/guide-error-handling.md +0 -565
- package/skills/effect-ts/references/guide-http-boundaries.md +0 -55
- package/skills/effect-ts/references/guide-layers.md +0 -989
- package/skills/effect-ts/references/guide-observability.md +0 -746
- package/skills/effect-ts/references/guide-retries.md +0 -434
- package/skills/effect-ts/references/guide-schedule.md +0 -343
- package/skills/effect-ts/references/guide-schema.md +0 -664
- package/skills/effect-ts/references/guide-sql.md +0 -536
- package/skills/effect-ts/references/guide-testing.md +0 -532
- package/skills/effect-ts/references/guide-type-safety-and-boundaries.md +0 -131
- package/skills/effect-ts/references/version-and-source.md +0 -86
- package/templates/vite-plus/vite.config.ts +0 -22
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Service And Boundary Audit
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Establish authority](#establish-authority)
|
|
6
|
+
- [Build the inventory](#build-the-inventory)
|
|
7
|
+
- [Trace requirements](#trace-requirements)
|
|
8
|
+
- [Classify candidates](#classify-candidates)
|
|
9
|
+
- [Audit type boundaries](#audit-type-boundaries)
|
|
10
|
+
- [Audit test substitutes](#audit-test-substitutes)
|
|
11
|
+
- [Report findings](#report-findings)
|
|
12
|
+
|
|
13
|
+
## Establish authority
|
|
14
|
+
|
|
15
|
+
Read the repository's architecture guidance and version-matched Effect package
|
|
16
|
+
instructions. Treat installed declarations and source as the authority for API
|
|
17
|
+
signatures. Record local conventions that affect service ownership, adapter
|
|
18
|
+
placement, error translation, and testing.
|
|
19
|
+
|
|
20
|
+
## Build the inventory
|
|
21
|
+
|
|
22
|
+
Find every:
|
|
23
|
+
|
|
24
|
+
- Effect service, tag, Layer, constructor, and provisioning call.
|
|
25
|
+
- Service-shaped interface, class, dependency bag, registry, or callback.
|
|
26
|
+
- Direct use of time, randomness, IDs, configuration, credentials, HTTP,
|
|
27
|
+
persistence, filesystems, runtime bindings, or mutable globals.
|
|
28
|
+
- Test Layer, fake, in-memory implementation, and module mock.
|
|
29
|
+
- Public Effect with an `unknown` or overly broad error channel.
|
|
30
|
+
- `any`, assertion, non-null assertion, custom predicate, structural probe,
|
|
31
|
+
unvalidated JSON parse, Promise rejection mapper, and expected throw.
|
|
32
|
+
- Schema or codec that overlaps another representation of the same logical
|
|
33
|
+
model.
|
|
34
|
+
|
|
35
|
+
Record one row per service or candidate:
|
|
36
|
+
|
|
37
|
+
| Field | Question |
|
|
38
|
+
| ------------ | ---------------------------------------------------- |
|
|
39
|
+
| Owner | Which module owns the capability's meaning? |
|
|
40
|
+
| Contract | Where is its public contract defined? |
|
|
41
|
+
| Construction | Are all construction requirements visible? |
|
|
42
|
+
| Production | Who chooses the concrete implementation? |
|
|
43
|
+
| Consumers | Is the capability yielded or drilled as a value? |
|
|
44
|
+
| Boundary | Who owns decoding, narrowing, and error translation? |
|
|
45
|
+
| Tests | Is its substitute strategy intentional and honest? |
|
|
46
|
+
| Verdict | Keep, deepen, relocate, merge, remove, or create? |
|
|
47
|
+
|
|
48
|
+
Complete the inventory when each discovered capability and unsafe boundary
|
|
49
|
+
appears exactly once.
|
|
50
|
+
|
|
51
|
+
## Trace requirements
|
|
52
|
+
|
|
53
|
+
For each row:
|
|
54
|
+
|
|
55
|
+
1. Trace one caller-visible operation through every effect it performs.
|
|
56
|
+
2. Mark where each dependency first appears and whether code yields, passes,
|
|
57
|
+
captures, or concretely provides it.
|
|
58
|
+
3. Verify that the module selecting a concrete Layer owns that implementation
|
|
59
|
+
choice.
|
|
60
|
+
4. Follow every Layer requirement to a composition root or an explicit value
|
|
61
|
+
boundary.
|
|
62
|
+
5. Check version-matched Effect capabilities before recommending an
|
|
63
|
+
application wrapper.
|
|
64
|
+
|
|
65
|
+
Flag hidden requirements created by inner provisioning, dependency bags,
|
|
66
|
+
handler-builder service values, mutable registries, or Layer selection inside
|
|
67
|
+
business operations. Prefer provision at a program or subsystem edge. Avoid
|
|
68
|
+
thin exported helpers that only yield a service and forward one method.
|
|
69
|
+
|
|
70
|
+
## Classify candidates
|
|
71
|
+
|
|
72
|
+
Assign one evidence-backed classification:
|
|
73
|
+
|
|
74
|
+
- **Built-in Effect capability** — yield the existing capability directly.
|
|
75
|
+
- **Application-owned authority** — define a narrow port beside the operation
|
|
76
|
+
whose policy gives it meaning.
|
|
77
|
+
- **Technology adapter** — implement an application-owned port at the external
|
|
78
|
+
boundary.
|
|
79
|
+
- **Request or domain value** — keep deterministic, per-call data explicit.
|
|
80
|
+
- **Framework boundary** — contain framework-required state or assertions in
|
|
81
|
+
the adapter or composition root.
|
|
82
|
+
- **Pass-through abstraction** — fold it into the actual owner.
|
|
83
|
+
|
|
84
|
+
Apply the deletion test: if removing an abstraction leaves equally clear code
|
|
85
|
+
without spreading authority, resource ownership, or policy, remove it. Prefer
|
|
86
|
+
an existing owner or a merge over a generic registry.
|
|
87
|
+
|
|
88
|
+
## Audit type boundaries
|
|
89
|
+
|
|
90
|
+
Assign every `unknown` value a boundary owner.
|
|
91
|
+
|
|
92
|
+
- Reserve `unknown` for external input, foreign library output, and opaque
|
|
93
|
+
diagnostic causes.
|
|
94
|
+
- Decode structured external data once, at the earliest boundary that owns its
|
|
95
|
+
meaning.
|
|
96
|
+
- Pass decoded values and concrete error unions through internal services.
|
|
97
|
+
- Keep unavoidable framework assertions at the narrowest adapter and document
|
|
98
|
+
the contract they bridge.
|
|
99
|
+
- Remove runtime narrowing already guaranteed by the inferred type.
|
|
100
|
+
- Preserve irreducible foreign causes as diagnostic fields inside concrete
|
|
101
|
+
domain errors instead of broadening public error channels.
|
|
102
|
+
|
|
103
|
+
Prefer one source Schema per logical model. Use Schema transformations or
|
|
104
|
+
derived variants when a storage or transport representation differs without
|
|
105
|
+
changing the model's meaning. Create a separate Schema only for a real semantic
|
|
106
|
+
difference.
|
|
107
|
+
|
|
108
|
+
Keep a helper only when it owns domain policy, reusable refinement, repeated
|
|
109
|
+
non-trivial mechanics, or a meaningful observability boundary. Inline one-use
|
|
110
|
+
tag comparisons and structural checks that add no meaning.
|
|
111
|
+
|
|
112
|
+
## Audit test substitutes
|
|
113
|
+
|
|
114
|
+
Record the intended test strategy for every production service.
|
|
115
|
+
|
|
116
|
+
- Make a shared test Layer's name match the behavior it fully provides.
|
|
117
|
+
- Keep partial fixtures local instead of publishing them as general in-memory
|
|
118
|
+
implementations.
|
|
119
|
+
- Use a real local adapter when persistence, transactions, serialization, or
|
|
120
|
+
lifecycle behavior is the subject under test.
|
|
121
|
+
- Keep timing deterministic; never add wall-clock sleeps to stabilize a test.
|
|
122
|
+
- Test protocol round trips when encoding or decoding behavior is a durable,
|
|
123
|
+
regression-prone public seam.
|
|
124
|
+
|
|
125
|
+
An explicit production-only rationale is valid when a substitute would not
|
|
126
|
+
protect durable behavior.
|
|
127
|
+
|
|
128
|
+
## Report findings
|
|
129
|
+
|
|
130
|
+
Prioritize findings by impact:
|
|
131
|
+
|
|
132
|
+
- **P0** — hidden authority, unsafe runtime access, wrong implementation
|
|
133
|
+
ownership, unchecked external data, or expected failures escaping the typed
|
|
134
|
+
channel.
|
|
135
|
+
- **P1** — dependency drilling, hidden Layer requirements, duplicated
|
|
136
|
+
capabilities, manual shape discovery, unjustified assertions, pass-through
|
|
137
|
+
abstractions, or dishonest test substitutes.
|
|
138
|
+
- **P2** — naming and co-location cleanup that belongs with a nearby change.
|
|
139
|
+
|
|
140
|
+
For each finding, include:
|
|
141
|
+
|
|
142
|
+
1. File, line, or symbol evidence.
|
|
143
|
+
2. The hidden requirement or caller burden.
|
|
144
|
+
3. The smallest target shape and its owner.
|
|
145
|
+
4. Composition-root and testing impact.
|
|
146
|
+
5. Behavior and modules that must remain unchanged.
|
|
147
|
+
|
|
148
|
+
End with explicit keep decisions for pure functions, request values, framework
|
|
149
|
+
boundaries, correctly separated ports and adapters, and services whose
|
|
150
|
+
requirements already remain visible.
|
|
@@ -1,270 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: effect-ts
|
|
3
|
-
description: Use this skill
|
|
3
|
+
description: Use this skill when setting up a repository that uses the Effect Typescript library.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Step 1: Install effect
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Use the users preferred package manager:
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
```
|
|
11
|
+
pnpm add effect@beta
|
|
12
|
+
```
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
If in a monorepo, install it as a dev dependency at the root, so you can access
|
|
15
|
+
the source code from `node_modules/effect/src`.
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
```
|
|
18
|
+
pnpm add -D effect@beta
|
|
19
|
+
```
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
version-sensitive APIs, or using upstream source as evidence.
|
|
21
|
+
# Step 2: Update AGENTS.md / CLAUDE.md
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
Ensure that the agent instructions contain the following:
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
```md
|
|
26
|
+
# Learning more about the Effect
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
This repository uses the Effect Typescript library.
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
Before writing any Effect code, first read `node_modules/effect/AGENTS.md`
|
|
31
|
+
**completely**, and follow the links in the file when required.
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- you need to verify a behavior against the source
|
|
34
|
-
|
|
35
|
-
### Research Sources
|
|
36
|
-
|
|
37
|
-
1. Local skill guides first. Start with the relevant files in `./references/`
|
|
38
|
-
before doing deeper research.
|
|
39
|
-
2. Codebase patterns second. Examine similar patterns in the current project
|
|
40
|
-
before implementing. If Effect patterns already exist, follow them for
|
|
41
|
-
consistency unless they conflict with an explicit local policy in this
|
|
42
|
-
skill.
|
|
43
|
-
3. Installed package source third. Use the target repository's resolved
|
|
44
|
-
`effect` and `@effect/*` packages for exact exports, declarations, and API
|
|
45
|
-
signatures.
|
|
46
|
-
4. Version-matched upstream source last. For gaps in the guides, complex type
|
|
47
|
-
errors, unclear behavior, or implementation details, inspect the canonical
|
|
48
|
-
`Effect-TS/effect` source at the tag or commit matching the installed
|
|
49
|
-
version. A project-local source checkout is optional, never a prerequisite.
|
|
50
|
-
|
|
51
|
-
### When To Research
|
|
52
|
-
|
|
53
|
-
- Always research for services, layers, or complex dependency injection.
|
|
54
|
-
- Always research for error handling with multiple error types or complex error hierarchies.
|
|
55
|
-
- Always research for stream-based operations and reactive patterns.
|
|
56
|
-
- Always research for resource management with scoped effects and cleanup.
|
|
57
|
-
- Always research for concurrent or performance-critical code.
|
|
58
|
-
- Always research for unfamiliar testing patterns.
|
|
59
|
-
- Research when needed for complex refactors from promises or try/catch into Effect.
|
|
60
|
-
- Research when needed for new service dependencies or layer restructuring.
|
|
61
|
-
- Research when needed for custom error types or extensions of existing error hierarchies.
|
|
62
|
-
- Research when needed for integrations with external systems such as databases, APIs, or third-party services.
|
|
63
|
-
|
|
64
|
-
### Research Approach
|
|
65
|
-
|
|
66
|
-
- Focus on canonical, readable, and maintainable solutions rather than clever optimizations.
|
|
67
|
-
- Verify suggested approaches against existing codebase patterns when those
|
|
68
|
-
patterns exist.
|
|
69
|
-
- When multiple approaches are possible, prefer the most idiomatic Effect
|
|
70
|
-
solution supported by the codebase, these local policies, and version-matched
|
|
71
|
-
Effect source.
|
|
72
|
-
|
|
73
|
-
### Codebase Pattern Discovery
|
|
74
|
-
|
|
75
|
-
When working in a project that uses Effect, check for existing patterns before implementing new code:
|
|
76
|
-
|
|
77
|
-
1. Search for Effect imports and existing module usage to understand current conventions.
|
|
78
|
-
2. Identify how services and layers are structured in the project.
|
|
79
|
-
3. Note how errors are defined and propagated.
|
|
80
|
-
4. Examine how Effect code is tested in the project.
|
|
81
|
-
|
|
82
|
-
If no Effect patterns exist in the codebase, proceed using these guides and
|
|
83
|
-
canonical patterns from version-matched Effect source and examples. Do not
|
|
84
|
-
block on missing codebase patterns or a missing source checkout.
|
|
85
|
-
|
|
86
|
-
### Feature Discovery
|
|
87
|
-
|
|
88
|
-
When you need to discover available Effect modules, packages, or capabilities, search `./references/features.md` first.
|
|
89
|
-
|
|
90
|
-
- Use it to identify the right package or module for a task.
|
|
91
|
-
- Treat listed repo paths as discovery hints. Confirm them against the target
|
|
92
|
-
repository's installed version before relying on exact names or signatures.
|
|
93
|
-
- Use it before inventing custom abstractions when Effect may already provide the functionality.
|
|
94
|
-
|
|
95
|
-
### Guide Discovery
|
|
96
|
-
|
|
97
|
-
When the task touches one of these areas, consult the matching guide before implementing:
|
|
98
|
-
|
|
99
|
-
- `./references/guide-effect.md` for core `Effect` usage patterns, common constructors, composition, provisioning, and runtime boundaries
|
|
100
|
-
- `./references/guide-error-handling.md` for defining errors, schema-based errors, failure handling, defects, and interrupts
|
|
101
|
-
- `./references/guide-layers.md` for service ownership, service design, layer
|
|
102
|
-
construction, dependency visibility, composition, and provisioning
|
|
103
|
-
- `./references/guide-observability.md` for `Effect.fn`, spans, structured
|
|
104
|
-
logging, metrics, annotations, and telemetry wiring
|
|
105
|
-
- `./references/guide-retries.md` for retry policies, retry conditions, fallback strategies, and `ExecutionPlan`
|
|
106
|
-
- `./references/guide-schedule.md` for retries, repeats, backoff, polling, cron, and schedule composition
|
|
107
|
-
- `./references/guide-schema.md` for schema-first application modeling,
|
|
108
|
-
service contracts, transformations, unions, recursion, and branded types
|
|
109
|
-
- `./references/guide-datetime.md` for current time, parsing, UTC and zoned
|
|
110
|
-
values, time zones, DST-safe arithmetic, formatting, Date interoperability,
|
|
111
|
-
and deterministic `TestClock` tests
|
|
112
|
-
- `./references/guide-atom-data-fetching.md` for the core Effect Atom HTTP
|
|
113
|
-
data-fetching workflow, React hook choice, and action-lifetime ownership rules
|
|
114
|
-
- `./references/atom-cache-lifecycle.md` for Effect Atom registry scope,
|
|
115
|
-
runtime memoization, families, TTL, SWR, polling, and aggregation resets
|
|
116
|
-
- `./references/atom-http-and-invalidation.md` for `AtomHttpApi.Service`,
|
|
117
|
-
queries, mutations, reactivity keys, and invalidation
|
|
118
|
-
- `./references/atom-tanstack-start.md` only for TanStack Start provider
|
|
119
|
-
placement, SSR isolation, hydration, and focus guidance
|
|
120
|
-
- `./references/atom-testing.md` when adding or diagnosing deterministic Effect
|
|
121
|
-
Atom lifecycle tests
|
|
122
|
-
- `./references/guide-sql.md` for Effect SQL usage, transactions, resolvers, schema-aware SQL, and migrations
|
|
123
|
-
- `./references/guide-testing.md` for `@effect/vitest`, deterministic testing,
|
|
124
|
-
honest test Layers, property tests, and protocol round trips
|
|
125
|
-
- `./references/guide-cli.md` for Effect-powered command-line scripts and
|
|
126
|
-
project automation
|
|
127
|
-
- `./references/guide-http-boundaries.md` for `HttpApi` contracts, handlers,
|
|
128
|
-
DTOs, transport errors, and route boundaries
|
|
129
|
-
- `./references/audit-services.md` for a complete service and type-boundary
|
|
130
|
-
audit workflow
|
|
131
|
-
- `./references/guide-type-safety-and-boundaries.md` for `unknown`, assertions,
|
|
132
|
-
runtime shape checks, external decoding, and boundary ownership
|
|
133
|
-
|
|
134
|
-
Treat each topic guide as the single authority for that topic. Do not skip the
|
|
135
|
-
guides and jump straight to source unless source-level confirmation is needed
|
|
136
|
-
or the guides do not answer the question.
|
|
137
|
-
|
|
138
|
-
## Effect Principles
|
|
139
|
-
|
|
140
|
-
Apply these core principles when writing Effect code.
|
|
141
|
-
|
|
142
|
-
## Installation
|
|
143
|
-
|
|
144
|
-
When installing Effect v4 packages in a user repository:
|
|
145
|
-
|
|
146
|
-
- use the current `effect@beta` version only for a new v4 installation
|
|
147
|
-
- preserve the repository's resolved v4 beta for existing installations unless
|
|
148
|
-
the user asks for an upgrade
|
|
149
|
-
- keep `effect` and all v4 `@effect/*` packages on the exact same beta version
|
|
150
|
-
- install only the packages needed for the user's runtime and actual task
|
|
151
|
-
|
|
152
|
-
### Version Rules
|
|
153
|
-
|
|
154
|
-
- `effect@latest` is still the v3 release line; use `effect@beta` when creating
|
|
155
|
-
a new v4 repository.
|
|
156
|
-
- Resolve the beta tag at installation time. Do not assume the review baseline
|
|
157
|
-
is still current.
|
|
158
|
-
- If you install any v4 `@effect/*` package, make sure it and `effect` use the
|
|
159
|
-
same exact beta version.
|
|
160
|
-
- Do not mix v3 integration packages with Effect v4 packages.
|
|
161
|
-
|
|
162
|
-
### Package Selection
|
|
163
|
-
|
|
164
|
-
Choose packages based on the runtime and the work being done.
|
|
165
|
-
|
|
166
|
-
- core library: `effect@beta`
|
|
167
|
-
- Node.js runtime needs: install the matching `@effect/platform-node@beta`
|
|
168
|
-
- browser runtime needs: install the matching `@effect/platform-browser@beta`
|
|
169
|
-
- Bun runtime needs: install the matching `@effect/platform-bun@beta`
|
|
170
|
-
- Vitest integration needs: install the matching `@effect/vitest@beta`
|
|
171
|
-
- OpenTelemetry integration needs: install the matching
|
|
172
|
-
`@effect/opentelemetry@beta`
|
|
173
|
-
|
|
174
|
-
Install additional `@effect/*` packages only when the user task actually needs them.
|
|
175
|
-
|
|
176
|
-
### Practical Rule
|
|
177
|
-
|
|
178
|
-
- start with the current resolved `effect@beta`
|
|
179
|
-
- add matching v4 `@effect/*` packages only as needed by runtime and features
|
|
180
|
-
- pin the full installed Effect v4 package set to the same exact beta
|
|
181
|
-
|
|
182
|
-
### Error Handling
|
|
183
|
-
|
|
184
|
-
- Use Effect's typed error system instead of throwing exceptions.
|
|
185
|
-
- Define descriptive error types with proper error propagation.
|
|
186
|
-
- Prefer `Schema.TaggedErrorClass` when the error can be schema-defined.
|
|
187
|
-
- Use `Effect.fail`, `Effect.catchTag`, and `Effect.catch` for error control flow.
|
|
188
|
-
|
|
189
|
-
### Dependency Injection
|
|
190
|
-
|
|
191
|
-
- Implement dependency injection using services and layers.
|
|
192
|
-
- Define services with `Context.Service`.
|
|
193
|
-
- Compose layers with `Layer.merge` and `Layer.provide`.
|
|
194
|
-
- Use `Effect.provide` to inject dependencies at the edge, avoid providing locally.
|
|
195
|
-
- Keep services encapsulated; avoid exporting trivial accessor wrappers that only forward to one service method.
|
|
196
|
-
|
|
197
|
-
### Composability
|
|
198
|
-
|
|
199
|
-
- Leverage Effect composability for complex operations.
|
|
200
|
-
- Use appropriate constructors such as `Effect.succeed`, `Effect.fail`, `Effect.tryPromise`, `Effect.try`, and `Effect.sync`.
|
|
201
|
-
- Apply proper resource management with scoped effects.
|
|
202
|
-
- Chain operations with `Effect.flatMap`, `Effect.map`, and `Effect.tap`.
|
|
203
|
-
|
|
204
|
-
### Business Logic Functions
|
|
205
|
-
|
|
206
|
-
- Prefer `Effect.fn` for reusable business-logic functions that return `Effect`.
|
|
207
|
-
- Prefer `Effect.fn` over raw `Effect.gen` definitions even when the function takes no arguments.
|
|
208
|
-
- If you do not want an explicit named span, use `Effect.fn` without a span name.
|
|
209
|
-
- Do not use `Effect.fnUntraced` as the default.
|
|
210
|
-
- Use `Effect.fnUntraced` only for edge cases with a concrete low-level reason, such as measured hot-path overhead.
|
|
211
|
-
|
|
212
|
-
### TypeScript Preferences
|
|
213
|
-
|
|
214
|
-
- Do not use `any` in Effect application, service, or workflow code.
|
|
215
|
-
- Decode external values instead of asserting their shape.
|
|
216
|
-
- Isolate unavoidable compiler or framework adapter assertions at the
|
|
217
|
-
narrowest boundary and document the contract they bridge.
|
|
218
|
-
- Do not use `namespace` to hide services, layers, or mutable state.
|
|
219
|
-
- Prefer correct typing, schema-driven decoding, narrowing, and proper generic constraints instead of forcing types.
|
|
220
|
-
- If a value comes from an external boundary, validate or decode it instead of asserting its type.
|
|
221
|
-
- If a type is hard to express, simplify the design or introduce a properly typed helper instead of using unsafe TypeScript.
|
|
222
|
-
- For layers, do not hide them inside `namespace` blocks. Prefer either `static` members on the service class or plain exported layer constants.
|
|
223
|
-
|
|
224
|
-
### Date and Time
|
|
225
|
-
|
|
226
|
-
- Prefer Effect `DateTime` over vanilla JavaScript `Date` for application
|
|
227
|
-
logic. Keep `Date` as an interoperability type at external boundaries.
|
|
228
|
-
- Use `DateTime.now` inside Effect programs so current time remains driven by
|
|
229
|
-
the `Clock` service and deterministic under `TestClock`.
|
|
230
|
-
- Preserve the distinction between instants, zoned wall-clock values, and
|
|
231
|
-
date-only domain values.
|
|
232
|
-
|
|
233
|
-
### Code Quality
|
|
234
|
-
|
|
235
|
-
- Write type-safe code that leverages Effect's type system.
|
|
236
|
-
- Use `Effect.gen` for readable sequential code.
|
|
237
|
-
- Implement proper testing patterns using Effect testing utilities.
|
|
238
|
-
- Prefer existing Effect primitives before introducing custom helpers.
|
|
239
|
-
- Prefer `Schema.Class` / `Schema.TaggedClass` variants over plain `Schema.Struct` for named reusable schemas when possible.
|
|
240
|
-
|
|
241
|
-
### Explaining Solutions
|
|
242
|
-
|
|
243
|
-
When providing solutions, explain the Effect concepts being used and why they
|
|
244
|
-
fit the specific use case. If you encounter patterns not covered in local
|
|
245
|
-
references, prefer consistency with the codebase when possible and otherwise
|
|
246
|
-
rely on installed declarations and version-matched canonical Effect source.
|
|
247
|
-
|
|
248
|
-
## References
|
|
249
|
-
|
|
250
|
-
- `./references/features.md`
|
|
251
|
-
- `./references/guide-effect.md`
|
|
252
|
-
- `./references/guide-error-handling.md`
|
|
253
|
-
- `./references/guide-layers.md`
|
|
254
|
-
- `./references/guide-observability.md`
|
|
255
|
-
- `./references/guide-retries.md`
|
|
256
|
-
- `./references/guide-schedule.md`
|
|
257
|
-
- `./references/guide-schema.md`
|
|
258
|
-
- `./references/guide-datetime.md`
|
|
259
|
-
- `./references/guide-atom-data-fetching.md`
|
|
260
|
-
- `./references/atom-cache-lifecycle.md`
|
|
261
|
-
- `./references/atom-http-and-invalidation.md`
|
|
262
|
-
- `./references/atom-tanstack-start.md`
|
|
263
|
-
- `./references/atom-testing.md`
|
|
264
|
-
- `./references/guide-sql.md`
|
|
265
|
-
- `./references/guide-testing.md`
|
|
266
|
-
- `./references/guide-cli.md`
|
|
267
|
-
- `./references/guide-http-boundaries.md`
|
|
268
|
-
- `./references/audit-services.md`
|
|
269
|
-
- `./references/guide-type-safety-and-boundaries.md`
|
|
270
|
-
- `./references/version-and-source.md`
|
|
33
|
+
If you need to learn more about particular Effect apis and concepts that the
|
|
34
|
+
guide doesn't cover, search through the source code in `node_modules/effect/src`.
|
|
35
|
+
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
|
-
display_name: "Effect
|
|
3
|
-
short_description: "
|
|
4
|
-
default_prompt: "Use $effect-ts to
|
|
2
|
+
display_name: "Effect TypeScript Setup"
|
|
3
|
+
short_description: "Set up version-matched Effect guidance"
|
|
4
|
+
default_prompt: "Use $effect-ts to set up Effect and its package-bundled agent guidance."
|
package/skills/testing/SKILL.md
CHANGED
|
@@ -21,3 +21,8 @@ Write a test only when every condition holds:
|
|
|
21
21
|
If any condition fails, skip the test and use the cheapest sufficient verification instead. Moving MVP behavior often warrants no committed tests.
|
|
22
22
|
|
|
23
23
|
Test capabilities, not files. Use the fewest tests that protect the risk, and ignore coverage targets unless the user explicitly asks for them.
|
|
24
|
+
|
|
25
|
+
Never commit an intentionally failing or red-only suite. Keep time-driven tests
|
|
26
|
+
deterministic instead of stabilizing them with wall-clock sleeps. A shared fake
|
|
27
|
+
or in-memory implementation must fully provide the behavior its name promises;
|
|
28
|
+
keep partial substitutes local to the tests that need them.
|
package/src/catalog-manager.ts
CHANGED
|
@@ -36,10 +36,9 @@ export type CatalogAddOptions = CatalogCommandOptions & {
|
|
|
36
36
|
readonly dryRun?: boolean;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
class CatalogManagerError extends Schema.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
) {}
|
|
39
|
+
class CatalogManagerError extends Schema.TaggedError<CatalogManagerError>()("CatalogManagerError", {
|
|
40
|
+
message: Schema.String,
|
|
41
|
+
}) {}
|
|
43
42
|
|
|
44
43
|
const formattingOptions = { insertSpaces: true, tabSize: 2 } as const;
|
|
45
44
|
|
|
@@ -63,17 +62,17 @@ const readJsonc = Effect.fn("readCatalogManagerJsonc")(function* <A>(
|
|
|
63
62
|
const fs = yield* FileSystem.FileSystem;
|
|
64
63
|
|
|
65
64
|
if (!(yield* fs.exists(filePath))) {
|
|
66
|
-
return yield*
|
|
65
|
+
return yield* CatalogManagerError.make({ message: `file not found: ${filePath}` });
|
|
67
66
|
}
|
|
68
67
|
const raw = yield* fs.readFileString(filePath);
|
|
69
68
|
const errors: Array<ParseError> = [];
|
|
70
69
|
const parsed = parseJsonc(raw, errors, { allowTrailingComma: true });
|
|
71
70
|
|
|
72
71
|
if (errors.length > 0) {
|
|
73
|
-
return yield*
|
|
72
|
+
return yield* CatalogManagerError.make({ message: `could not parse ${filePath}` });
|
|
74
73
|
}
|
|
75
74
|
const value = yield* Schema.decodeUnknownEffect(schema)(parsed).pipe(
|
|
76
|
-
Effect.mapError((error) =>
|
|
75
|
+
Effect.mapError((error) => CatalogManagerError.make({ message: error.message })),
|
|
77
76
|
);
|
|
78
77
|
|
|
79
78
|
return { raw, value };
|
|
@@ -105,7 +104,7 @@ const selectSkills = Effect.fn("selectCatalogSkills")(function* (
|
|
|
105
104
|
const unknown = requested.filter((skill) => !available.has(skill));
|
|
106
105
|
|
|
107
106
|
if (unknown.length > 0) {
|
|
108
|
-
return yield*
|
|
107
|
+
return yield* CatalogManagerError.make({
|
|
109
108
|
message: `repository does not contain: ${unknown.join(", ")}`,
|
|
110
109
|
});
|
|
111
110
|
}
|
|
@@ -117,7 +116,7 @@ const selectSkills = Effect.fn("selectCatalogSkills")(function* (
|
|
|
117
116
|
if (requested.length > 0)
|
|
118
117
|
return { include: [...new Set(requested)], selected: [...new Set(requested)] };
|
|
119
118
|
if (!(yield* isInteractiveTerminal)) {
|
|
120
|
-
return yield*
|
|
119
|
+
return yield* CatalogManagerError.make({
|
|
121
120
|
message: "choose skills with --skill <name>, or pass --all",
|
|
122
121
|
});
|
|
123
122
|
}
|
|
@@ -194,7 +193,7 @@ export const addCatalogSource = Effect.fn("addCatalogSource")(function* (
|
|
|
194
193
|
options: CatalogAddOptions,
|
|
195
194
|
) {
|
|
196
195
|
if (options.all && (options.skills?.length ?? 0) > 0) {
|
|
197
|
-
return yield*
|
|
196
|
+
return yield* CatalogManagerError.make({ message: "use either --all or --skill, not both" });
|
|
198
197
|
}
|
|
199
198
|
const state = yield* readState(options);
|
|
200
199
|
const inspection = yield* inspectCatalogRepository({
|
|
@@ -210,12 +209,12 @@ export const addCatalogSource = Effect.fn("addCatalogSource")(function* (
|
|
|
210
209
|
const byRepository = sources.findIndex((source) => source.repository === inspection.repository);
|
|
211
210
|
|
|
212
211
|
if (byId >= 0 && sources[byId]?.repository !== inspection.repository) {
|
|
213
|
-
return yield*
|
|
212
|
+
return yield* CatalogManagerError.make({
|
|
214
213
|
message: `source id ${inspection.id} is already used by ${sources[byId]?.repository}`,
|
|
215
214
|
});
|
|
216
215
|
}
|
|
217
216
|
if (byRepository >= 0 && sources[byRepository]?.id !== inspection.id) {
|
|
218
|
-
return yield*
|
|
217
|
+
return yield* CatalogManagerError.make({
|
|
219
218
|
message: `repository is already cataloged as ${sources[byRepository]?.id}`,
|
|
220
219
|
});
|
|
221
220
|
}
|
|
@@ -226,7 +225,7 @@ export const addCatalogSource = Effect.fn("addCatalogSource")(function* (
|
|
|
226
225
|
const existing = sources[existingIndex];
|
|
227
226
|
|
|
228
227
|
if (existing === undefined) {
|
|
229
|
-
return yield*
|
|
228
|
+
return yield* CatalogManagerError.make({ message: "catalog source index is out of bounds" });
|
|
230
229
|
}
|
|
231
230
|
const approved =
|
|
232
231
|
state.lock?.value.sources.find((source) => source.id === existing.id)?.skills ?? [];
|
|
@@ -308,12 +307,12 @@ export const removeCatalogEntry = Effect.fn("removeCatalogEntry")(function* (
|
|
|
308
307
|
const owner = state.lock?.value.sources.find((source) => source.skills.includes(name));
|
|
309
308
|
|
|
310
309
|
if (!owner)
|
|
311
|
-
return yield*
|
|
310
|
+
return yield* CatalogManagerError.make({ message: `catalog entry not found: ${name}` });
|
|
312
311
|
const index = sources.findIndex((source) => source.id === owner.id);
|
|
313
312
|
const source = sources[index];
|
|
314
313
|
|
|
315
314
|
if (!source)
|
|
316
|
-
return yield*
|
|
315
|
+
return yield* CatalogManagerError.make({ message: `source not found: ${owner.id}` });
|
|
317
316
|
if (source.include.includes("*")) {
|
|
318
317
|
const exclude = [...new Set([...(source.exclude ?? []), name])];
|
|
319
318
|
|
|
@@ -342,7 +341,7 @@ export const removeCatalogEntry = Effect.fn("removeCatalogEntry")(function* (
|
|
|
342
341
|
}
|
|
343
342
|
if (!options.yes) {
|
|
344
343
|
if (!(yield* isInteractiveTerminal)) {
|
|
345
|
-
return yield*
|
|
344
|
+
return yield* CatalogManagerError.make({
|
|
346
345
|
message: "catalog removal requires --yes outside a terminal",
|
|
347
346
|
});
|
|
348
347
|
}
|
|
@@ -388,7 +387,7 @@ export const showCatalogSource = Effect.fn("showCatalogSource")(function* (
|
|
|
388
387
|
const source = state.sources.value.sources.find((candidate) => candidate.id === id);
|
|
389
388
|
|
|
390
389
|
if (!source)
|
|
391
|
-
return yield*
|
|
390
|
+
return yield* CatalogManagerError.make({ message: `catalog source not found: ${id}` });
|
|
392
391
|
const locked = state.lock?.value.sources.find((candidate) => candidate.id === id);
|
|
393
392
|
|
|
394
393
|
yield* printLine(source.id);
|