@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.
Files changed (79) hide show
  1. package/README.md +111 -78
  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/build-effect-clis/SKILL.md +61 -0
  17. package/skills/build-effect-clis/agents/openai.yaml +4 -0
  18. package/skills/build-effect-clis/references/command-design.md +93 -0
  19. package/skills/build-effect-clis/references/entrypoints-and-testing.md +59 -0
  20. package/skills/build-effect-clis/references/processes-and-platform.md +73 -0
  21. package/skills/dev-kit/SKILL.md +77 -48
  22. package/skills/effect-architecture-audit/SKILL.md +26 -0
  23. package/skills/effect-architecture-audit/agents/openai.yaml +4 -0
  24. package/skills/effect-architecture-audit/references/service-and-boundary-audit.md +150 -0
  25. package/skills/effect-ts/SKILL.md +21 -256
  26. package/skills/effect-ts/agents/openai.yaml +3 -3
  27. package/skills/testing/SKILL.md +5 -0
  28. package/src/catalog-manager.ts +16 -17
  29. package/src/catalog.ts +71 -16
  30. package/src/effect-source.ts +46 -24
  31. package/src/effect-tsgo.ts +86 -24
  32. package/src/gitignore.ts +5 -5
  33. package/src/index.ts +3 -6
  34. package/src/manifest.ts +0 -34
  35. package/src/node-symbolic-link.ts +2 -2
  36. package/src/oxfmt.js +5 -0
  37. package/src/oxfmt.ts +5 -0
  38. package/src/oxlint.js +5 -0
  39. package/src/oxlint.ts +5 -0
  40. package/src/package-skill-source.ts +51 -59
  41. package/src/path-digest.ts +7 -7
  42. package/src/project-package.ts +8 -7
  43. package/src/project-process-lock.ts +17 -12
  44. package/src/project-state.ts +1 -1
  45. package/src/skill-manager.ts +18 -16
  46. package/src/skill-selector.ts +12 -0
  47. package/src/sync.ts +181 -131
  48. package/src/tool-ignore-patterns.js +9 -0
  49. package/src/tool-ignore-patterns.ts +15 -0
  50. package/src/vendor.ts +67 -61
  51. package/src/vite-plus-dependency.ts +10 -11
  52. package/src/vite-plus-hooks.ts +24 -14
  53. package/src/vite-plus-quality.ts +21 -172
  54. package/src/vite-plus.js +81 -0
  55. package/src/vite-plus.ts +102 -0
  56. package/templates/AGENTS.md +1 -1
  57. package/skills/effect-ts/UPSTREAM.md +0 -28
  58. package/skills/effect-ts/references/atom-cache-lifecycle.md +0 -78
  59. package/skills/effect-ts/references/atom-http-and-invalidation.md +0 -97
  60. package/skills/effect-ts/references/atom-tanstack-start.md +0 -69
  61. package/skills/effect-ts/references/atom-testing.md +0 -67
  62. package/skills/effect-ts/references/audit-services.md +0 -144
  63. package/skills/effect-ts/references/features.md +0 -525
  64. package/skills/effect-ts/references/guide-atom-data-fetching.md +0 -44
  65. package/skills/effect-ts/references/guide-cli.md +0 -107
  66. package/skills/effect-ts/references/guide-datetime.md +0 -72
  67. package/skills/effect-ts/references/guide-effect.md +0 -440
  68. package/skills/effect-ts/references/guide-error-handling.md +0 -565
  69. package/skills/effect-ts/references/guide-http-boundaries.md +0 -55
  70. package/skills/effect-ts/references/guide-layers.md +0 -989
  71. package/skills/effect-ts/references/guide-observability.md +0 -746
  72. package/skills/effect-ts/references/guide-retries.md +0 -434
  73. package/skills/effect-ts/references/guide-schedule.md +0 -343
  74. package/skills/effect-ts/references/guide-schema.md +0 -664
  75. package/skills/effect-ts/references/guide-sql.md +0 -536
  76. package/skills/effect-ts/references/guide-testing.md +0 -532
  77. package/skills/effect-ts/references/guide-type-safety-and-boundaries.md +0 -131
  78. package/skills/effect-ts/references/version-and-source.md +0 -86
  79. package/templates/vite-plus/vite.config.ts +0 -22
package/src/index.ts CHANGED
@@ -11,20 +11,14 @@ export {
11
11
  EffectTsgoSetupSchema,
12
12
  type HarnessTarget,
13
13
  TargetConfigSchema,
14
- type VitePlusQualityConfigSetup,
15
- VitePlusQualityConfigSetupSchema,
16
14
  type VitePlusQualitySetup,
17
15
  VitePlusQualitySetupSchema,
18
- type VitePlusQualityTypecheckSetup,
19
- VitePlusQualityTypecheckSetupSchema,
20
16
  type VitePlusQualityWorkflowSetup,
21
17
  VitePlusQualityWorkflowSetupSchema,
22
18
  type VitePlusQualityWorkflowStep,
23
19
  VitePlusQualityWorkflowStepSchema,
24
20
  type VitePlusSetup,
25
21
  VitePlusSetupSchema,
26
- type VitePlusTypecheckStrategy,
27
- VitePlusTypecheckStrategySchema,
28
22
  } from "./manifest.ts";
29
23
  export {
30
24
  applyEffectSourcePlan,
@@ -49,13 +43,16 @@ export {
49
43
  EFFECT_TSGO_PLUGIN_NAME,
50
44
  EFFECT_TSGO_TYPESCRIPT_VERSION,
51
45
  EFFECT_TSGO_VERSION,
46
+ type EffectTsgoDiagnosticSeverity,
52
47
  EffectTsgoDependencyError,
53
48
  InvalidEffectTsgoPackageNameError,
54
49
  type EffectTsgoPatchOptions,
55
50
  type EffectTsgoPatchPlan,
51
+ type EffectTsgoPluginConfig,
56
52
  EffectTsgoPatchCommandError,
57
53
  patchEffectTsgo,
58
54
  planEffectTsgoPatch,
55
+ recommendedEffectTsgoPlugin,
59
56
  } from "./effect-tsgo.ts";
60
57
  export {
61
58
  ExternalSkillSourceSchema,
package/src/manifest.ts CHANGED
@@ -53,22 +53,6 @@ export const VitePlusHooksSetupSchema = Schema.Struct({
53
53
  enabled: Schema.optional(Schema.Boolean),
54
54
  });
55
55
 
56
- export const VitePlusTypecheckStrategySchema = Schema.Literals(["single-project", "workspace"]);
57
- export type VitePlusTypecheckStrategy = typeof VitePlusTypecheckStrategySchema.Type;
58
-
59
- export const VitePlusQualityTypecheckSetupSchema = Schema.Struct({
60
- strategy: Schema.optional(VitePlusTypecheckStrategySchema),
61
- concurrency: Schema.optional(Schema.Int),
62
- packages: Schema.optional(Schema.Array(Schema.String)),
63
- });
64
- export type VitePlusQualityTypecheckSetup = typeof VitePlusQualityTypecheckSetupSchema.Type;
65
-
66
- export const VitePlusQualityConfigSetupSchema = Schema.Struct({
67
- enabled: Schema.optional(Schema.Boolean),
68
- typecheck: Schema.optional(VitePlusQualityTypecheckSetupSchema),
69
- });
70
- export type VitePlusQualityConfigSetup = typeof VitePlusQualityConfigSetupSchema.Type;
71
-
72
56
  export const VitePlusQualityWorkflowStepSchema = Schema.Struct({
73
57
  name: Schema.String,
74
58
  run: Schema.Array(Schema.String),
@@ -83,7 +67,6 @@ export const VitePlusQualityWorkflowSetupSchema = Schema.Struct({
83
67
  export type VitePlusQualityWorkflowSetup = typeof VitePlusQualityWorkflowSetupSchema.Type;
84
68
 
85
69
  export const VitePlusQualitySetupSchema = Schema.Struct({
86
- config: Schema.optional(VitePlusQualityConfigSetupSchema),
87
70
  workflow: Schema.optional(VitePlusQualityWorkflowSetupSchema),
88
71
  });
89
72
  export type VitePlusQualitySetup = typeof VitePlusQualitySetupSchema.Type;
@@ -153,14 +136,6 @@ export type NormalizedManifest = {
153
136
  readonly enabled: boolean;
154
137
  };
155
138
  readonly quality: {
156
- readonly config: {
157
- readonly enabled: boolean;
158
- readonly typecheck: {
159
- readonly strategy: VitePlusTypecheckStrategy;
160
- readonly concurrency: number;
161
- readonly packages: ReadonlyArray<string>;
162
- };
163
- };
164
139
  readonly workflow: {
165
140
  readonly enabled: boolean;
166
141
  readonly beforeChecks: ReadonlyArray<VitePlusQualityWorkflowStep>;
@@ -201,7 +176,6 @@ export const normalizeManifest = (manifest: DevKitManifest): NormalizedManifest
201
176
  }
202
177
  }
203
178
  const quality = manifest.setup?.vitePlus?.quality;
204
- const typecheck = quality?.config?.typecheck;
205
179
 
206
180
  return {
207
181
  exclude: manifest.exclude ?? [],
@@ -230,14 +204,6 @@ export const normalizeManifest = (manifest: DevKitManifest): NormalizedManifest
230
204
  enabled: manifest.setup?.vitePlus?.hooks?.enabled ?? false,
231
205
  },
232
206
  quality: {
233
- config: {
234
- enabled: quality?.config?.enabled ?? false,
235
- typecheck: {
236
- strategy: typecheck?.strategy ?? "single-project",
237
- concurrency: typecheck?.concurrency ?? 4,
238
- packages: typecheck?.packages ?? [],
239
- },
240
- },
241
207
  workflow: {
242
208
  enabled: quality?.workflow?.enabled ?? false,
243
209
  beforeChecks: quality?.workflow?.beforeChecks ?? [],
@@ -4,8 +4,8 @@ export type SymbolicLinkObservation =
4
4
  | { readonly kind: "missing" | "not-symlink" }
5
5
  | { readonly kind: "symlink"; readonly target: string };
6
6
 
7
- // Effect beta.102's Node FileSystem adapter maps readlink(2) EINVAL to Unknown.
8
- // Keep that runtime-specific normalization at this narrow adapter boundary.
7
+ // Effect's Node FileSystem adapter maps readlink(2) EINVAL to Unknown. Keep
8
+ // that runtime-specific normalization at this narrow adapter boundary.
9
9
  const isNotSymbolicLink = (error: PlatformError.PlatformError): boolean => {
10
10
  if (error.reason._tag !== "Unknown") return false;
11
11
  const cause = error.reason.cause;
package/src/oxfmt.js CHANGED
@@ -4,9 +4,14 @@
4
4
  * This file is intentionally plain JavaScript because Node does not strip
5
5
  * TypeScript from packages in node_modules when tools load their config.
6
6
  */
7
+ import { devKitToolIgnorePatterns } from "./tool-ignore-patterns.js";
8
+
9
+ export { devKitToolIgnorePatterns } from "./tool-ignore-patterns.js";
10
+
7
11
  export const recommendedOxfmtConfig = {
8
12
  arrowParens: "always",
9
13
  endOfLine: "lf",
14
+ ignorePatterns: [...devKitToolIgnorePatterns],
10
15
  printWidth: 100,
11
16
  semi: true,
12
17
  singleQuote: false,
package/src/oxfmt.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import type { OxfmtConfig } from "oxfmt";
2
2
 
3
+ import { devKitToolIgnorePatterns } from "./tool-ignore-patterns.ts";
4
+
5
+ export { devKitToolIgnorePatterns } from "./tool-ignore-patterns.ts";
6
+
3
7
  /**
4
8
  * Canonical formatting defaults for standalone Oxfmt and Vite+ projects.
5
9
  *
@@ -9,6 +13,7 @@ import type { OxfmtConfig } from "oxfmt";
9
13
  export const recommendedOxfmtConfig = {
10
14
  arrowParens: "always",
11
15
  endOfLine: "lf",
16
+ ignorePatterns: [...devKitToolIgnorePatterns],
12
17
  printWidth: 100,
13
18
  semi: true,
14
19
  singleQuote: false,
package/src/oxlint.js CHANGED
@@ -4,7 +4,12 @@
4
4
  * This file is intentionally plain JavaScript because Node does not strip
5
5
  * TypeScript from packages in node_modules when Vite+ loads vite.config.ts.
6
6
  */
7
+ import { devKitToolIgnorePatterns } from "./tool-ignore-patterns.js";
8
+
9
+ export { devKitToolIgnorePatterns } from "./tool-ignore-patterns.js";
10
+
7
11
  export const recommendedOxlintConfig = {
12
+ ignorePatterns: [...devKitToolIgnorePatterns],
8
13
  options: {
9
14
  typeAware: true,
10
15
  },
package/src/oxlint.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import type { OxlintConfig } from "oxlint";
2
2
 
3
+ import { devKitToolIgnorePatterns } from "./tool-ignore-patterns.ts";
4
+
5
+ export { devKitToolIgnorePatterns } from "./tool-ignore-patterns.ts";
6
+
3
7
  /**
4
8
  * High-signal Oxlint defaults for TypeScript projects.
5
9
  *
@@ -8,6 +12,7 @@ import type { OxlintConfig } from "oxlint";
8
12
  * without losing nested configuration.
9
13
  */
10
14
  export const recommendedOxlintConfig = {
15
+ ignorePatterns: [...devKitToolIgnorePatterns],
11
16
  options: {
12
17
  typeAware: true,
13
18
  },
@@ -5,7 +5,7 @@ import { readDirectDependencyNames } from "./project-package.ts";
5
5
  import { isSkillName, parseSkillSelector } from "./skill-selector.ts";
6
6
  import { isTypeScriptPackageName } from "./typescript-package-name.ts";
7
7
 
8
- export class PackageSkillSourceError extends Schema.TaggedErrorClass<PackageSkillSourceError>()(
8
+ export class PackageSkillSourceError extends Schema.TaggedError<PackageSkillSourceError>()(
9
9
  "PackageSkillSourceError",
10
10
  { message: Schema.String },
11
11
  ) {}
@@ -121,26 +121,24 @@ const rejectNestedSymlinks = Effect.fn("rejectPackageSkillSymlinks")(function* (
121
121
 
122
122
  if (current === undefined) continue;
123
123
  if ((yield* observeSymbolicLink(current)).kind === "symlink") {
124
- return yield* new PackageSkillSourceError({
124
+ return yield* PackageSkillSourceError.make({
125
125
  message: `package skill contains a symlink: ${current}`,
126
126
  });
127
127
  }
128
- const info = yield* fs
129
- .stat(current)
130
- .pipe(
131
- Effect.mapError(
132
- () =>
133
- new PackageSkillSourceError({ message: `could not inspect package skill: ${current}` }),
134
- ),
135
- );
128
+ const info = yield* fs.stat(current).pipe(
129
+ Effect.mapError(() =>
130
+ PackageSkillSourceError.make({
131
+ message: `could not inspect package skill: ${current}`,
132
+ }),
133
+ ),
134
+ );
136
135
 
137
136
  if (info.type !== "Directory") continue;
138
137
  for (const entry of yield* fs
139
138
  .readDirectory(current)
140
139
  .pipe(
141
- Effect.mapError(
142
- () =>
143
- new PackageSkillSourceError({ message: `could not read package skill: ${current}` }),
140
+ Effect.mapError(() =>
141
+ PackageSkillSourceError.make({ message: `could not read package skill: ${current}` }),
144
142
  ),
145
143
  ))
146
144
  pending.push(path.join(current, entry));
@@ -163,80 +161,75 @@ const loadInstalledPackageSkills = Effect.fn("loadInstalledPackageSkills")(funct
163
161
  const path = yield* Path.Path;
164
162
  const packageLink = path.join(projectDir, "node_modules", ...packageName.split("/"));
165
163
  const packageRoot = yield* fs.realPath(packageLink).pipe(
166
- Effect.mapError(
167
- () =>
168
- new PackageSkillSourceError({
169
- message: `package skill package is not installed: ${packageName}`,
170
- }),
164
+ Effect.mapError(() =>
165
+ PackageSkillSourceError.make({
166
+ message: `package skill package is not installed: ${packageName}`,
167
+ }),
171
168
  ),
172
169
  );
173
170
  const packageInfo = yield* fs.stat(packageRoot).pipe(
174
- Effect.mapError(
175
- () =>
176
- new PackageSkillSourceError({
177
- message: `could not inspect package skill package: ${packageName}`,
178
- }),
171
+ Effect.mapError(() =>
172
+ PackageSkillSourceError.make({
173
+ message: `could not inspect package skill package: ${packageName}`,
174
+ }),
179
175
  ),
180
176
  );
181
177
 
182
178
  if (packageInfo.type !== "Directory")
183
- return yield* new PackageSkillSourceError({
179
+ return yield* PackageSkillSourceError.make({
184
180
  message: `package skill package is not a directory: ${packageName}`,
185
181
  });
186
182
  const metadata = yield* fs.readFileString(path.join(packageRoot, "package.json")).pipe(
187
183
  Effect.flatMap(Schema.decodeUnknownEffect(PackageMetadataSchema)),
188
- Effect.mapError(
189
- () =>
190
- new PackageSkillSourceError({
191
- message: `invalid package.json for package skill package: ${packageName}`,
192
- }),
184
+ Effect.mapError(() =>
185
+ PackageSkillSourceError.make({
186
+ message: `invalid package.json for package skill package: ${packageName}`,
187
+ }),
193
188
  ),
194
189
  );
195
190
 
196
191
  if (metadata.name !== packageName)
197
- return yield* new PackageSkillSourceError({
192
+ return yield* PackageSkillSourceError.make({
198
193
  message: `package.json name does not match package skill package: ${packageName}`,
199
194
  });
200
195
  if (!isSafePackageVersion(metadata.version))
201
- return yield* new PackageSkillSourceError({
196
+ return yield* PackageSkillSourceError.make({
202
197
  message: `package.json has an invalid version for package skill package: ${packageName}`,
203
198
  });
204
199
  if (!hasIntentDiscoveryMetadata(metadata))
205
- return yield* new PackageSkillSourceError({
200
+ return yield* PackageSkillSourceError.make({
206
201
  message: `package does not declare Intent-compatible discovery metadata: ${packageName}`,
207
202
  });
208
203
  const skillsPath = "skills";
209
204
  const skillsLink = path.join(packageLink, skillsPath);
210
205
 
211
206
  if ((yield* observeSymbolicLink(skillsLink)).kind === "symlink")
212
- return yield* new PackageSkillSourceError({
207
+ return yield* PackageSkillSourceError.make({
213
208
  message: `package skills path is a symlink: ${packageName}/${skillsPath}`,
214
209
  });
215
210
  const skillsRoot = yield* fs.realPath(skillsLink).pipe(
216
- Effect.mapError(
217
- () =>
218
- new PackageSkillSourceError({
219
- message: `package skill package has no skills directory: ${packageName}`,
220
- }),
211
+ Effect.mapError(() =>
212
+ PackageSkillSourceError.make({
213
+ message: `package skill package has no skills directory: ${packageName}`,
214
+ }),
221
215
  ),
222
216
  );
223
217
 
224
218
  if (!isContained(path, packageRoot, skillsRoot))
225
- return yield* new PackageSkillSourceError({
219
+ return yield* PackageSkillSourceError.make({
226
220
  message: `package skills path resolves outside package root: ${packageName}/${skillsPath}`,
227
221
  });
228
222
  const skillsInfo = yield* fs.stat(skillsRoot);
229
223
 
230
224
  if (skillsInfo.type !== "Directory")
231
- return yield* new PackageSkillSourceError({
225
+ return yield* PackageSkillSourceError.make({
232
226
  message: `package skills path is not a directory: ${packageName}/${skillsPath}`,
233
227
  });
234
228
  const names = (yield* fs.readDirectory(skillsRoot).pipe(
235
- Effect.mapError(
236
- () =>
237
- new PackageSkillSourceError({
238
- message: `package skill package has no readable skills directory: ${packageName}`,
239
- }),
229
+ Effect.mapError(() =>
230
+ PackageSkillSourceError.make({
231
+ message: `package skill package has no readable skills directory: ${packageName}`,
232
+ }),
240
233
  ),
241
234
  ))
242
235
  .filter(isSkillName)
@@ -259,21 +252,21 @@ const inspectPackageSkill = Effect.fn("inspectInstalledPackageSkill")(function*
259
252
  const path = yield* Path.Path;
260
253
 
261
254
  if (!isSkillName(name)) {
262
- return yield* new PackageSkillSourceError({ message: `invalid package skill name: ${name}` });
255
+ return yield* PackageSkillSourceError.make({ message: `invalid package skill name: ${name}` });
263
256
  }
264
257
  const selector = `${installed.package}#${name}`;
265
258
  const linkPath = path.join(installed.packageLink, "skills", name);
266
259
 
267
260
  if ((yield* observeSymbolicLink(linkPath)).kind === "symlink") {
268
- return yield* new PackageSkillSourceError({
261
+ return yield* PackageSkillSourceError.make({
269
262
  message: `package skill contains a symlink: ${selector}`,
270
263
  });
271
264
  }
272
265
  const skillRoot = yield* fs
273
266
  .realPath(linkPath)
274
267
  .pipe(
275
- Effect.mapError(
276
- () => new PackageSkillSourceError({ message: `package skill does not exist: ${selector}` }),
268
+ Effect.mapError(() =>
269
+ PackageSkillSourceError.make({ message: `package skill does not exist: ${selector}` }),
277
270
  ),
278
271
  );
279
272
 
@@ -281,29 +274,28 @@ const inspectPackageSkill = Effect.fn("inspectInstalledPackageSkill")(function*
281
274
  !isContained(path, installed.skillsRoot, skillRoot) ||
282
275
  (yield* fs.stat(skillRoot)).type !== "Directory"
283
276
  ) {
284
- return yield* new PackageSkillSourceError({
277
+ return yield* PackageSkillSourceError.make({
285
278
  message: `package skill is not a contained directory: ${selector}`,
286
279
  });
287
280
  }
288
281
  yield* rejectNestedSymlinks(skillRoot);
289
282
  const document = yield* fs.readFileString(path.join(skillRoot, "SKILL.md")).pipe(
290
- Effect.mapError(
291
- () =>
292
- new PackageSkillSourceError({
293
- message: `package skill is missing SKILL.md: ${selector}`,
294
- }),
283
+ Effect.mapError(() =>
284
+ PackageSkillSourceError.make({
285
+ message: `package skill is missing SKILL.md: ${selector}`,
286
+ }),
295
287
  ),
296
288
  );
297
289
 
298
290
  if (skillName(document) !== name) {
299
- return yield* new PackageSkillSourceError({
291
+ return yield* PackageSkillSourceError.make({
300
292
  message: `package skill SKILL.md name must match directory: ${selector}`,
301
293
  });
302
294
  }
303
295
  const description = skillDescription(document);
304
296
 
305
297
  if (description === undefined) {
306
- return yield* new PackageSkillSourceError({
298
+ return yield* PackageSkillSourceError.make({
307
299
  message: `package skill SKILL.md must declare a description: ${selector}`,
308
300
  });
309
301
  }
@@ -370,13 +362,13 @@ export const resolvePackageSkillSelector = Effect.fn("resolvePackageSkillSelecto
370
362
  const parsed = parseSkillSelector(selector);
371
363
 
372
364
  if (parsed?.type !== "package")
373
- return yield* new PackageSkillSourceError({
365
+ return yield* PackageSkillSourceError.make({
374
366
  message: `invalid package skill selector: ${selector}`,
375
367
  });
376
368
  const directDependencies = yield* readDirectDependencyNames(projectDir);
377
369
 
378
370
  if (!directDependencies.includes(parsed.package))
379
- return yield* new PackageSkillSourceError({
371
+ return yield* PackageSkillSourceError.make({
380
372
  message: `package skill package is not a direct dependency: ${parsed.package}`,
381
373
  });
382
374
 
@@ -9,7 +9,7 @@ export type ObservedPath =
9
9
  | { readonly kind: "missing" }
10
10
  | { readonly kind: "file" | "directory" | "symlink"; readonly digest: Digest };
11
11
 
12
- export class PathInspectionError extends Schema.TaggedErrorClass<PathInspectionError>()(
12
+ export class PathInspectionError extends Schema.TaggedError<PathInspectionError>()(
13
13
  "PathInspectionError",
14
14
  {
15
15
  path: Schema.String,
@@ -124,7 +124,7 @@ const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
124
124
  const child = yield* digestFileSystemPath(childPath, fileMode);
125
125
 
126
126
  if (child.kind === "missing") {
127
- return yield* new PathInspectionError({
127
+ return yield* PathInspectionError.make({
128
128
  path: childPath,
129
129
  operation: "inspect a stable directory tree",
130
130
  cause: "path disappeared during inspection",
@@ -136,7 +136,7 @@ const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
136
136
  return { kind: "directory", digest: yield* digestFrames(frames) };
137
137
  }
138
138
 
139
- return yield* new PathInspectionError({
139
+ return yield* PathInspectionError.make({
140
140
  path: absolutePath,
141
141
  operation: "inspect unsupported filesystem entry",
142
142
  cause: info.type,
@@ -146,9 +146,9 @@ const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
146
146
  export const observePath = Effect.fn("observeManagedPath")(function* (absolutePath: string) {
147
147
  return yield* digestFileSystemPath(absolutePath, canonicalFileMode).pipe(
148
148
  Effect.mapError((cause) =>
149
- cause instanceof PathInspectionError
149
+ Schema.is(PathInspectionError)(cause)
150
150
  ? cause
151
- : new PathInspectionError({ path: absolutePath, operation: "inspect", cause }),
151
+ : PathInspectionError.make({ path: absolutePath, operation: "inspect", cause }),
152
152
  ),
153
153
  );
154
154
  });
@@ -158,9 +158,9 @@ export const observePathWithRawModes = Effect.fn("observeManagedPathWithRawModes
158
158
  ) {
159
159
  return yield* digestFileSystemPath(absolutePath, rawFileMode).pipe(
160
160
  Effect.mapError((cause) =>
161
- cause instanceof PathInspectionError
161
+ Schema.is(PathInspectionError)(cause)
162
162
  ? cause
163
- : new PathInspectionError({ path: absolutePath, operation: "inspect", cause }),
163
+ : PathInspectionError.make({ path: absolutePath, operation: "inspect", cause }),
164
164
  ),
165
165
  );
166
166
  });
@@ -1,6 +1,6 @@
1
1
  import { Effect, FileSystem, Path, Schema } from "effect";
2
2
 
3
- export class ProjectPackageError extends Schema.TaggedErrorClass<ProjectPackageError>()(
3
+ export class ProjectPackageError extends Schema.TaggedError<ProjectPackageError>()(
4
4
  "ProjectPackageError",
5
5
  { message: Schema.String },
6
6
  ) {}
@@ -24,15 +24,16 @@ export const readProjectPackage = Effect.fn("readProjectPackage")(function* (pro
24
24
  const manifestPath = path.join(projectDir, "package.json");
25
25
 
26
26
  if (!(yield* fs.exists(manifestPath))) {
27
- return yield* new ProjectPackageError({ message: `package.json not found: ${manifestPath}` });
27
+ return yield* ProjectPackageError.make({
28
+ message: `package.json not found: ${manifestPath}`,
29
+ });
28
30
  }
29
31
  const manifest = yield* fs.readFileString(manifestPath).pipe(
30
32
  Effect.flatMap(Schema.decodeUnknownEffect(ProjectPackageSchema)),
31
- Effect.mapError(
32
- () =>
33
- new ProjectPackageError({
34
- message: `invalid project package.json: ${manifestPath}`,
35
- }),
33
+ Effect.mapError(() =>
34
+ ProjectPackageError.make({
35
+ message: `invalid project package.json: ${manifestPath}`,
36
+ }),
36
37
  ),
37
38
  );
38
39
 
@@ -4,7 +4,7 @@ import { DEV_KIT_VERSION } from "./tool-metadata.ts";
4
4
 
5
5
  export const PROJECT_PROCESS_LOCK_PATH = ".dev-kit/apply.lock";
6
6
 
7
- export class ProjectAlreadyLockedError extends Schema.TaggedErrorClass<ProjectAlreadyLockedError>()(
7
+ export class ProjectAlreadyLockedError extends Schema.TaggedError<ProjectAlreadyLockedError>()(
8
8
  "ProjectAlreadyLockedError",
9
9
  { path: Schema.String },
10
10
  ) {
@@ -13,6 +13,15 @@ export class ProjectAlreadyLockedError extends Schema.TaggedErrorClass<ProjectAl
13
13
  }
14
14
  }
15
15
 
16
+ const ProjectProcessLockOwnerSchema = Schema.fromJsonString(
17
+ Schema.Struct({
18
+ version: Schema.Literal(1),
19
+ toolVersion: Schema.String,
20
+ token: Schema.String,
21
+ startedAt: Schema.String,
22
+ }),
23
+ );
24
+
16
25
  export const acquireProjectProcessLock = Effect.fn("acquireProjectProcessLock")(function* (
17
26
  projectDir: string,
18
27
  ) {
@@ -24,16 +33,12 @@ export const acquireProjectProcessLock = Effect.fn("acquireProjectProcessLock")(
24
33
  const ownerPath = path.join(lockDir, "owner.json");
25
34
  const token = yield* crypto.randomUUIDv7;
26
35
  const startedAt = DateTime.formatIso(yield* DateTime.now);
27
- const ownerContents = `${JSON.stringify(
28
- {
29
- version: 1,
30
- toolVersion: DEV_KIT_VERSION,
31
- token,
32
- startedAt,
33
- },
34
- null,
35
- 2,
36
- )}\n`;
36
+ const ownerContents = `${yield* Schema.encodeEffect(ProjectProcessLockOwnerSchema)({
37
+ version: 1,
38
+ toolVersion: DEV_KIT_VERSION,
39
+ token,
40
+ startedAt,
41
+ }).pipe(Effect.orDie)}\n`;
37
42
 
38
43
  return yield* Effect.acquireRelease(
39
44
  Effect.gen(function* () {
@@ -46,7 +51,7 @@ export const acquireProjectProcessLock = Effect.fn("acquireProjectProcessLock")(
46
51
  .pipe(
47
52
  Effect.mapError((error) =>
48
53
  error.reason._tag === "AlreadyExists"
49
- ? new ProjectAlreadyLockedError({ path: lockDir })
54
+ ? ProjectAlreadyLockedError.make({ path: lockDir })
50
55
  : error,
51
56
  ),
52
57
  );
@@ -50,7 +50,7 @@ export const ManagedClaudeInstructionsOutputSchema = Schema.Struct({
50
50
  export type ManagedClaudeInstructionsOutput = typeof ManagedClaudeInstructionsOutputSchema.Type;
51
51
 
52
52
  export const ManagedGeneratedFileOutputSchema = Schema.Struct({
53
- resourceId: Schema.Literals(["setup:vite-plus-config", "setup:vite-plus-github-actions"]),
53
+ resourceId: Schema.Literal("setup:vite-plus-github-actions"),
54
54
  path: Schema.String,
55
55
  sourcePath: Schema.String,
56
56
  mode: Schema.Literal("copy"),