@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
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
|
|
8
|
-
//
|
|
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.
|
|
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*
|
|
124
|
+
return yield* PackageSkillSourceError.make({
|
|
125
125
|
message: `package skill contains a symlink: ${current}`,
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
-
const info = yield* fs
|
|
129
|
-
.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
169
|
-
|
|
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
|
-
|
|
177
|
-
|
|
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*
|
|
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
|
-
|
|
191
|
-
|
|
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*
|
|
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*
|
|
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*
|
|
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*
|
|
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
|
-
|
|
219
|
-
|
|
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*
|
|
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*
|
|
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
|
-
|
|
238
|
-
|
|
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*
|
|
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*
|
|
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
|
-
|
|
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*
|
|
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
|
-
|
|
293
|
-
|
|
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*
|
|
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*
|
|
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*
|
|
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*
|
|
371
|
+
return yield* PackageSkillSourceError.make({
|
|
380
372
|
message: `package skill package is not a direct dependency: ${parsed.package}`,
|
|
381
373
|
});
|
|
382
374
|
|
package/src/path-digest.ts
CHANGED
|
@@ -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.
|
|
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*
|
|
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*
|
|
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
|
|
149
|
+
Schema.is(PathInspectionError)(cause)
|
|
150
150
|
? cause
|
|
151
|
-
:
|
|
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
|
|
161
|
+
Schema.is(PathInspectionError)(cause)
|
|
162
162
|
? cause
|
|
163
|
-
:
|
|
163
|
+
: PathInspectionError.make({ path: absolutePath, operation: "inspect", cause }),
|
|
164
164
|
),
|
|
165
165
|
);
|
|
166
166
|
});
|
package/src/project-package.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
2
2
|
|
|
3
|
-
export class ProjectPackageError extends Schema.
|
|
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*
|
|
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
|
-
|
|
34
|
-
|
|
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.
|
|
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 = `${
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
?
|
|
54
|
+
? ProjectAlreadyLockedError.make({ path: lockDir })
|
|
50
55
|
: error,
|
|
51
56
|
),
|
|
52
57
|
);
|
package/src/project-state.ts
CHANGED
|
@@ -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.
|
|
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"),
|