opencode-effect-enforcer 0.2.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 (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +278 -0
  3. package/guidance/effect-first-development.md +1247 -0
  4. package/guidance/post__effect-and-the-near-inexpressible-majesty-of-layers.md +490 -0
  5. package/guidance/post__parse-dont-validate.md +109 -0
  6. package/guidance/progressive-disclosure-guidance.md +38 -0
  7. package/package.json +63 -0
  8. package/patterns/avoid-any.md +37 -0
  9. package/patterns/avoid-data-tagged-error.md +34 -0
  10. package/patterns/avoid-direct-json.md +51 -0
  11. package/patterns/avoid-direct-tag-checks.md +54 -0
  12. package/patterns/avoid-expect-in-if.md +52 -0
  13. package/patterns/avoid-mutable-state.md +70 -0
  14. package/patterns/avoid-native-fetch.md +61 -0
  15. package/patterns/avoid-node-imports.md +86 -0
  16. package/patterns/avoid-non-null-assertion.md +44 -0
  17. package/patterns/avoid-object-type.md +46 -0
  18. package/patterns/avoid-option-getorthrow.md +39 -0
  19. package/patterns/avoid-platform-coupling.md +43 -0
  20. package/patterns/avoid-process-env.md +43 -0
  21. package/patterns/avoid-react-hooks.md +73 -0
  22. package/patterns/avoid-schema-suffix.md +45 -0
  23. package/patterns/avoid-sync-fs.md +68 -0
  24. package/patterns/avoid-try-catch.md +47 -0
  25. package/patterns/avoid-ts-ignore.md +38 -0
  26. package/patterns/avoid-untagged-errors.md +67 -0
  27. package/patterns/avoid-yield-ref.md +46 -0
  28. package/patterns/casting-awareness.md +46 -0
  29. package/patterns/context-tag-extends.md +84 -0
  30. package/patterns/effect-catchall-default.md +61 -0
  31. package/patterns/effect-promise-vs-trypromise.md +47 -0
  32. package/patterns/effect-run-in-body.md +58 -0
  33. package/patterns/imperative-loops.md +76 -0
  34. package/patterns/prefer-arr-sort.md +52 -0
  35. package/patterns/prefer-duration-values.md +56 -0
  36. package/patterns/prefer-effect-fn.md +161 -0
  37. package/patterns/prefer-match-over-switch.md +48 -0
  38. package/patterns/prefer-option-over-null.md +56 -0
  39. package/patterns/prefer-redacted-config.md +70 -0
  40. package/patterns/prefer-schema-class.md +54 -0
  41. package/patterns/require-effect-concurrency.md +83 -0
  42. package/patterns/stream-large-files.md +63 -0
  43. package/patterns/throw-in-effect-gen.md +62 -0
  44. package/patterns/use-clock-service.md +45 -0
  45. package/patterns/use-command-executor-service.md +54 -0
  46. package/patterns/use-console-service.md +54 -0
  47. package/patterns/use-filesystem-service.md +59 -0
  48. package/patterns/use-http-client-service.md +77 -0
  49. package/patterns/use-path-service.md +53 -0
  50. package/patterns/use-random-service.md +45 -0
  51. package/patterns/use-temp-file-scoped.md +66 -0
  52. package/patterns/vm-in-wrong-file.md +51 -0
  53. package/patterns/yield-in-for-loop.md +61 -0
  54. package/skills/effect-ai-chat/SKILL.md +472 -0
  55. package/skills/effect-ai-language-model/SKILL.md +652 -0
  56. package/skills/effect-ai-prompt/SKILL.md +752 -0
  57. package/skills/effect-ai-provider/SKILL.md +668 -0
  58. package/skills/effect-ai-streaming/SKILL.md +418 -0
  59. package/skills/effect-ai-tool/SKILL.md +1132 -0
  60. package/skills/effect-atom-rpc/SKILL.md +488 -0
  61. package/skills/effect-atom-state/SKILL.md +640 -0
  62. package/skills/effect-batching/SKILL.md +614 -0
  63. package/skills/effect-cache/SKILL.md +570 -0
  64. package/skills/effect-cli/SKILL.md +523 -0
  65. package/skills/effect-command-executor/SKILL.md +675 -0
  66. package/skills/effect-concurrency-testing/SKILL.md +612 -0
  67. package/skills/effect-config/SKILL.md +580 -0
  68. package/skills/effect-context-witness/SKILL.md +274 -0
  69. package/skills/effect-domain-modeling/SKILL.md +1212 -0
  70. package/skills/effect-domain-predicates/SKILL.md +867 -0
  71. package/skills/effect-error-handling/SKILL.md +1581 -0
  72. package/skills/effect-fiber/SKILL.md +731 -0
  73. package/skills/effect-filesystem/SKILL.md +624 -0
  74. package/skills/effect-graph/SKILL.md +571 -0
  75. package/skills/effect-http-api/SKILL.md +1760 -0
  76. package/skills/effect-http-client/SKILL.md +989 -0
  77. package/skills/effect-http-server/SKILL.md +920 -0
  78. package/skills/effect-incremental-migration/SKILL.md +362 -0
  79. package/skills/effect-layer-design/SKILL.md +642 -0
  80. package/skills/effect-managed-runtime/SKILL.md +395 -0
  81. package/skills/effect-mcp-server/SKILL.md +608 -0
  82. package/skills/effect-observability/SKILL.md +719 -0
  83. package/skills/effect-optics/SKILL.md +554 -0
  84. package/skills/effect-parallelization/SKILL.md +668 -0
  85. package/skills/effect-path/SKILL.md +296 -0
  86. package/skills/effect-pattern-matching/SKILL.md +914 -0
  87. package/skills/effect-platform-abstraction/SKILL.md +1175 -0
  88. package/skills/effect-platform-layers/SKILL.md +514 -0
  89. package/skills/effect-pubsub-event-bus/SKILL.md +384 -0
  90. package/skills/effect-react-composition/SKILL.md +986 -0
  91. package/skills/effect-react-vm/SKILL.md +675 -0
  92. package/skills/effect-rpc-api/SKILL.md +624 -0
  93. package/skills/effect-rpc-client/SKILL.md +666 -0
  94. package/skills/effect-rpc-cluster/SKILL.md +1623 -0
  95. package/skills/effect-rpc-server/SKILL.md +767 -0
  96. package/skills/effect-scheduling/SKILL.md +124 -0
  97. package/skills/effect-schema-composition/SKILL.md +975 -0
  98. package/skills/effect-schema-v4/SKILL.md +691 -0
  99. package/skills/effect-scope/SKILL.md +682 -0
  100. package/skills/effect-service-implementation/SKILL.md +656 -0
  101. package/skills/effect-socket/SKILL.md +703 -0
  102. package/skills/effect-sql/SKILL.md +781 -0
  103. package/skills/effect-stream/SKILL.md +765 -0
  104. package/skills/effect-testing/SKILL.md +1331 -0
  105. package/skills/effect-typeclass-design/SKILL.md +161 -0
  106. package/skills/effect-wide-events/Article.md +66 -0
  107. package/skills/effect-wide-events/SKILL.md +95 -0
  108. package/skills/effect-workflow/SKILL.md +810 -0
  109. package/src/agent-policy.ts +22 -0
  110. package/src/enforcer.ts +104 -0
  111. package/src/frontmatter.ts +34 -0
  112. package/src/guidance.ts +66 -0
  113. package/src/index.ts +38 -0
  114. package/src/pattern-catalog.ts +115 -0
  115. package/src/pattern-matcher.ts +178 -0
  116. package/src/pattern.ts +97 -0
  117. package/src/skills.ts +29 -0
  118. package/src/write-projection.ts +66 -0
@@ -0,0 +1,296 @@
1
+ ---
2
+ name: effect-path
3
+ description: Use effect Path for platform-abstract file path operations including joining, resolving, and URL conversion.
4
+ ---
5
+
6
+ # path
7
+
8
+ Use effect Path abstraction for platform-abstract file path operations. Apply this skill when working with file paths, joining segments, resolving absolute paths, or converting between file URLs and paths. `Path.layer` supplies POSIX semantics from `effect`; Node.js and Bun platform layers provide host-specific path semantics. `@effect/platform-browser` does not provide a `BrowserPath` layer, so browser code should provide `Path.layer` or a custom layer explicitly.
9
+
10
+ ## Import Pattern
11
+
12
+ ```typescript
13
+ import { Path } from 'effect';
14
+ ```
15
+
16
+ ## Service Injection
17
+
18
+ ```typescript
19
+ import { Path } from 'effect';
20
+ import { Effect } from 'effect';
21
+
22
+ const program = Effect.gen(function* () {
23
+ const path = yield* Path.Path;
24
+ });
25
+ ```
26
+
27
+ ## Path Separator
28
+
29
+ ```typescript
30
+ import { Path } from 'effect';
31
+ import { Effect } from 'effect';
32
+
33
+ // Get platform-specific separator
34
+ const program = Effect.gen(function* () {
35
+ const path = yield* Path.Path;
36
+ const separator = path.sep; // "/" on Unix, "\" on Windows
37
+ });
38
+ ```
39
+
40
+ ## Path Operations
41
+
42
+ ### join - Combine path segments
43
+
44
+ ```typescript
45
+ import { Path } from 'effect';
46
+ import { Effect } from 'effect';
47
+
48
+ const program = Effect.gen(function* () {
49
+ const path = yield* Path.Path;
50
+ const fullPath = path.join('src', 'components', 'Button.tsx');
51
+ // "src/components/Button.tsx" on Unix
52
+ // "src\components\Button.tsx" on Windows
53
+ });
54
+ ```
55
+
56
+ ### resolve - Convert to absolute path
57
+
58
+ ```typescript
59
+ import { Path } from 'effect';
60
+ import { Effect } from 'effect';
61
+
62
+ const program = Effect.gen(function* () {
63
+ const path = yield* Path.Path;
64
+ const absolutePath = path.resolve('src', 'index.ts');
65
+ // "/Users/username/project/src/index.ts" on Unix
66
+ // "C:\Users\username\project\src\index.ts" on Windows
67
+ });
68
+ ```
69
+
70
+ ### normalize - Clean up path
71
+
72
+ ```typescript
73
+ import { Path } from 'effect';
74
+ import { Effect } from 'effect';
75
+
76
+ const program = Effect.gen(function* () {
77
+ const path = yield* Path.Path;
78
+ const clean = path.normalize('/foo/bar//baz/asdf/quux/..');
79
+ // "/foo/bar/baz/asdf"
80
+ });
81
+ ```
82
+
83
+ ### dirname - Get directory portion
84
+
85
+ ```typescript
86
+ import { Path } from 'effect';
87
+ import { Effect } from 'effect';
88
+
89
+ const program = Effect.gen(function* () {
90
+ const path = yield* Path.Path;
91
+ const dir = path.dirname('/foo/bar/baz.txt');
92
+ // "/foo/bar"
93
+ });
94
+ ```
95
+
96
+ ### basename - Get file name
97
+
98
+ ```typescript
99
+ import { Path } from 'effect';
100
+ import { Effect } from 'effect';
101
+
102
+ const program = Effect.gen(function* () {
103
+ const path = yield* Path.Path;
104
+ const name = path.basename('/foo/bar/baz.txt');
105
+ // "baz.txt"
106
+
107
+ const nameWithoutExt = path.basename('/foo/bar/baz.txt', '.txt');
108
+ // "baz"
109
+ });
110
+ ```
111
+
112
+ ### extname - Get file extension
113
+
114
+ ```typescript
115
+ import { Path } from 'effect';
116
+ import { Effect } from 'effect';
117
+
118
+ const program = Effect.gen(function* () {
119
+ const path = yield* Path.Path;
120
+ const ext = path.extname('/foo/bar/baz.txt');
121
+ // ".txt"
122
+ });
123
+ ```
124
+
125
+ ### parse - Decompose path into components
126
+
127
+ ```typescript
128
+ import { Path } from 'effect';
129
+ import { Effect } from 'effect';
130
+
131
+ const program = Effect.gen(function* () {
132
+ const path = yield* Path.Path;
133
+ const parsed = path.parse('/home/user/dir/file.txt');
134
+ // {
135
+ // root: "/",
136
+ // dir: "/home/user/dir",
137
+ // base: "file.txt",
138
+ // ext: ".txt",
139
+ // name: "file"
140
+ // }
141
+ });
142
+ ```
143
+
144
+ ### format - Construct path from components
145
+
146
+ ```typescript
147
+ import { Path } from 'effect';
148
+ import { Effect } from 'effect';
149
+
150
+ const program = Effect.gen(function* () {
151
+ const path = yield* Path.Path;
152
+ const fullPath = path.format({
153
+ root: '/',
154
+ dir: '/home/user/dir',
155
+ base: 'file.txt'
156
+ });
157
+ // "/home/user/dir/file.txt"
158
+ });
159
+ ```
160
+
161
+ ### isAbsolute - Check if path is absolute
162
+
163
+ ```typescript
164
+ import { Path } from 'effect';
165
+ import { Effect } from 'effect';
166
+
167
+ const program = Effect.gen(function* () {
168
+ const path = yield* Path.Path;
169
+ const isAbs = path.isAbsolute('/foo/bar');
170
+ // true on Unix
171
+ const isRel = path.isAbsolute('foo/bar');
172
+ // false
173
+ });
174
+ ```
175
+
176
+ ### relative - Get relative path
177
+
178
+ ```typescript
179
+ import { Path } from 'effect';
180
+ import { Effect } from 'effect';
181
+
182
+ const program = Effect.gen(function* () {
183
+ const path = yield* Path.Path;
184
+ const relPath = path.relative(
185
+ '/data/orandea/test/aaa',
186
+ '/data/orandea/impl/bbb'
187
+ );
188
+ // "../../impl/bbb"
189
+ });
190
+ ```
191
+
192
+ ## URL Conversions (Effectful)
193
+
194
+ Both operations can fail with `BadArgument` error.
195
+
196
+ ### fromFileUrl - Convert file URL to path
197
+
198
+ ```typescript
199
+ import { Path } from 'effect';
200
+ import { Effect } from 'effect';
201
+
202
+ const program = Effect.gen(function* () {
203
+ const path = yield* Path.Path;
204
+ const filePath = yield* path.fromFileUrl(
205
+ new URL('file:///home/user/file.txt')
206
+ );
207
+ // "/home/user/file.txt" on Unix
208
+ // "C:\home\user\file.txt" on Windows
209
+ });
210
+ ```
211
+
212
+ ### toFileUrl - Convert path to file URL
213
+
214
+ ```typescript
215
+ import { Path } from 'effect';
216
+ import { Effect } from 'effect';
217
+
218
+ const program = Effect.gen(function* () {
219
+ const path = yield* Path.Path;
220
+ const fileUrl = yield* path.toFileUrl('/home/user/file.txt');
221
+ // URL object with href "file:///home/user/file.txt"
222
+ });
223
+ ```
224
+
225
+ ## Complete Example
226
+
227
+ ```typescript
228
+ import { Path } from 'effect';
229
+ import { Effect } from 'effect';
230
+
231
+ const buildOutputPath = Effect.gen(function* () {
232
+ const path = yield* Path.Path;
233
+
234
+ // Join segments
235
+ const srcPath = path.join('src', 'index.ts');
236
+
237
+ // Resolve to absolute
238
+ const absoluteSrc = path.resolve(srcPath);
239
+
240
+ // Get directory and basename
241
+ const dir = path.dirname(absoluteSrc);
242
+ const base = path.basename(absoluteSrc, '.ts');
243
+
244
+ // Build output path
245
+ const outputPath = path.join(dir, '..', 'dist', `${base}.js`);
246
+
247
+ // Normalize
248
+ return path.normalize(outputPath);
249
+ });
250
+ ```
251
+
252
+ ## File-System Migration Loaders
253
+
254
+ In Effect v4, `Migrator.fromFileSystem(directory)` requires both `FileSystem.FileSystem` and `Path.Path`. Migration modules are imported through `path.toFileUrl(path.join(directory, file))` so absolute Windows paths are valid ESM specifiers.
255
+
256
+ ```typescript
257
+ import { FileSystem, Path } from 'effect';
258
+ import * as Migrator from 'effect/unstable/sql/Migrator';
259
+
260
+ const loader: Migrator.Loader<FileSystem.FileSystem | Path.Path> =
261
+ Migrator.fromFileSystem('./migrations');
262
+ ```
263
+
264
+ Aggregate layers such as `NodeServices.layer` and `BunServices.layer` already provide both requirements. If wiring individual layers, provide both the file-system layer and the host-aware path layer. On Windows, do not use the core POSIX `Path.layer` for a Windows migration directory; use the runtime platform's path layer so drive letters and separators are converted correctly.
265
+
266
+ ### toNamespacedPath - Convert to namespaced path
267
+
268
+ ```typescript
269
+ import { Path } from 'effect';
270
+ import { Effect } from 'effect';
271
+
272
+ const program = Effect.gen(function* () {
273
+ const path = yield* Path.Path;
274
+ // On POSIX, returns the path unchanged.
275
+ // On Windows, converts to a \\?\-prefixed namespaced path
276
+ // that allows longer path lengths.
277
+ const namespaced = path.toNamespacedPath('/foo/bar/baz.txt');
278
+ });
279
+ ```
280
+
281
+ ## DO
282
+
283
+ - Import Path from effect
284
+ - Use `path.sep` for platform-specific separators
285
+ - Use `path.join()` to combine path segments
286
+ - Use `path.resolve()` to get absolute paths
287
+ - Handle errors from `fromFileUrl` and `toFileUrl` with Effect error handling
288
+ - Pass a `URL` object (not a string) to `fromFileUrl`
289
+
290
+ ## DON'T
291
+
292
+ - Import `node:path` directly (breaks portability)
293
+ - Hardcode "/" or "\\" separators
294
+ - Manually concatenate paths with string operations
295
+ - Assume file URL format without using conversion utilities
296
+ - Pass a string to `fromFileUrl` — it requires a `URL` object