@danieljvdm/dev-kit 0.11.3 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -76
- 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/dev-kit/SKILL.md +58 -46
- 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 +49 -24
- package/src/gitignore.ts +5 -5
- package/src/index.ts +0 -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 +16 -14
- package/src/skill-selector.ts +12 -0
- package/src/sync.ts +170 -120
- 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/effect-tsgo.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { printStatus, withSpinner } from "./cli-ui.ts";
|
|
|
5
5
|
import { acquireProjectProcessLock } from "./project-process-lock.ts";
|
|
6
6
|
import { isTypeScriptPackageName } from "./typescript-package-name.ts";
|
|
7
7
|
|
|
8
|
-
export const EFFECT_TSGO_VERSION = "0.
|
|
8
|
+
export const EFFECT_TSGO_VERSION = "0.33.0";
|
|
9
9
|
export const EFFECT_TSGO_TYPESCRIPT_VERSION = "7.0.2";
|
|
10
10
|
export const EFFECT_TSGO_PLUGIN_NAME = "@effect/language-service";
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@ export type EffectTsgoPatchOptions = {
|
|
|
18
18
|
|
|
19
19
|
export type EffectTsgoPatchPlan = {
|
|
20
20
|
readonly alreadyPatched: boolean;
|
|
21
|
+
readonly unpatchArgs?: ReadonlyArray<string>;
|
|
21
22
|
readonly projectDir: string;
|
|
22
23
|
readonly executable: string;
|
|
23
24
|
readonly args: ReadonlyArray<string>;
|
|
@@ -26,7 +27,7 @@ export type EffectTsgoPatchPlan = {
|
|
|
26
27
|
readonly typescriptVersion: string;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
export class EffectTsgoDependencyError extends Schema.
|
|
30
|
+
export class EffectTsgoDependencyError extends Schema.TaggedError<EffectTsgoDependencyError>()(
|
|
30
31
|
"EffectTsgoDependencyError",
|
|
31
32
|
{
|
|
32
33
|
packageName: Schema.String,
|
|
@@ -41,7 +42,7 @@ export class EffectTsgoDependencyError extends Schema.TaggedErrorClass<EffectTsg
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
export class EffectTsgoPatchCommandError extends Schema.
|
|
45
|
+
export class EffectTsgoPatchCommandError extends Schema.TaggedError<EffectTsgoPatchCommandError>()(
|
|
45
46
|
"EffectTsgoPatchCommandError",
|
|
46
47
|
{
|
|
47
48
|
command: Schema.String,
|
|
@@ -56,7 +57,7 @@ export class EffectTsgoPatchCommandError extends Schema.TaggedErrorClass<EffectT
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
export class InvalidEffectTsgoPackageNameError extends Schema.
|
|
60
|
+
export class InvalidEffectTsgoPackageNameError extends Schema.TaggedError<InvalidEffectTsgoPackageNameError>()(
|
|
60
61
|
"InvalidEffectTsgoPackageNameError",
|
|
61
62
|
{ packageName: Schema.String },
|
|
62
63
|
) {
|
|
@@ -82,15 +83,15 @@ const readExactPackageVersion = Effect.fn("readExactEffectTsgoPackageVersion")(f
|
|
|
82
83
|
.readFileString(manifestPath)
|
|
83
84
|
.pipe(
|
|
84
85
|
Effect.catchReason("PlatformError", "NotFound", () =>
|
|
85
|
-
Effect.fail(
|
|
86
|
+
Effect.fail(EffectTsgoDependencyError.make({ packageName, expectedVersion })),
|
|
86
87
|
),
|
|
87
88
|
);
|
|
88
|
-
const manifest = yield* Schema.
|
|
89
|
-
Effect.mapError(() =>
|
|
89
|
+
const manifest = yield* Schema.decodeEffect(PackageVersionSchema)(contents).pipe(
|
|
90
|
+
Effect.mapError(() => EffectTsgoDependencyError.make({ packageName, expectedVersion })),
|
|
90
91
|
);
|
|
91
92
|
|
|
92
93
|
if (manifest.version !== expectedVersion) {
|
|
93
|
-
return yield*
|
|
94
|
+
return yield* EffectTsgoDependencyError.make({
|
|
94
95
|
packageName,
|
|
95
96
|
expectedVersion,
|
|
96
97
|
actualVersion: manifest.version,
|
|
@@ -115,7 +116,7 @@ const resolveEffectTsgoExecutable = Effect.fn("resolveEffectTsgoExecutable")(fun
|
|
|
115
116
|
if (yield* fs.exists(candidate)) return candidate;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
return yield*
|
|
119
|
+
return yield* EffectTsgoDependencyError.make({
|
|
119
120
|
packageName: "@effect/tsgo",
|
|
120
121
|
expectedVersion: EFFECT_TSGO_VERSION,
|
|
121
122
|
});
|
|
@@ -140,7 +141,7 @@ const findNodeModulesRoot = (path: Path.Path, packageJsonPath: string): string |
|
|
|
140
141
|
}
|
|
141
142
|
};
|
|
142
143
|
|
|
143
|
-
const
|
|
144
|
+
const inspectEffectTsgoPatch = Effect.fn("inspectEffectTsgoPatch")(function* (
|
|
144
145
|
projectDir: string,
|
|
145
146
|
typescriptPackage: string,
|
|
146
147
|
) {
|
|
@@ -153,22 +154,28 @@ const isEffectTsgoPatched = Effect.fn("isEffectTsgoPatched")(function* (
|
|
|
153
154
|
const typescriptNodeModules = findNodeModulesRoot(path, typescriptPackageJson);
|
|
154
155
|
const effectNodeModules = findNodeModulesRoot(path, effectTsgoPackageJson);
|
|
155
156
|
|
|
156
|
-
if (typescriptNodeModules === undefined || effectNodeModules === undefined)
|
|
157
|
+
if (typescriptNodeModules === undefined || effectNodeModules === undefined) {
|
|
158
|
+
return { alreadyPatched: false, hasBackup: false };
|
|
159
|
+
}
|
|
157
160
|
|
|
158
161
|
const typescriptScope = path.join(typescriptNodeModules, "@typescript");
|
|
159
162
|
const effectScope = path.join(effectNodeModules, "@effect");
|
|
160
163
|
|
|
161
|
-
if (!(yield* fs.exists(typescriptScope)) || !(yield* fs.exists(effectScope)))
|
|
164
|
+
if (!(yield* fs.exists(typescriptScope)) || !(yield* fs.exists(effectScope))) {
|
|
165
|
+
return { alreadyPatched: false, hasBackup: false };
|
|
166
|
+
}
|
|
162
167
|
|
|
163
168
|
const executableName = path.sep === "\\" ? "tsc.exe" : "tsc";
|
|
164
169
|
const effectExecutableNames =
|
|
165
170
|
path.sep === "\\" ? ["tsc.exe", "tsc-next.exe"] : ["tsc", "tsc-next"];
|
|
171
|
+
let hasBackup = false;
|
|
166
172
|
|
|
167
173
|
for (const entry of yield* fs.readDirectory(typescriptScope)) {
|
|
168
174
|
if (!entry.startsWith("typescript-")) continue;
|
|
169
175
|
const platform = entry.slice("typescript-".length);
|
|
170
176
|
const installedPath = path.join(typescriptScope, entry, "lib", executableName);
|
|
171
177
|
|
|
178
|
+
if (yield* fs.exists(`${installedPath}.original`)) hasBackup = true;
|
|
172
179
|
if (!(yield* fs.exists(installedPath))) continue;
|
|
173
180
|
const installedDigest = yield* digestFileContents(installedPath);
|
|
174
181
|
|
|
@@ -184,12 +191,12 @@ const isEffectTsgoPatched = Effect.fn("isEffectTsgoPatched")(function* (
|
|
|
184
191
|
(yield* fs.exists(effectBinaryPath)) &&
|
|
185
192
|
installedDigest === (yield* digestFileContents(effectBinaryPath))
|
|
186
193
|
) {
|
|
187
|
-
return true;
|
|
194
|
+
return { alreadyPatched: true, hasBackup };
|
|
188
195
|
}
|
|
189
196
|
}
|
|
190
197
|
}
|
|
191
198
|
|
|
192
|
-
return false;
|
|
199
|
+
return { alreadyPatched: false, hasBackup };
|
|
193
200
|
});
|
|
194
201
|
|
|
195
202
|
export const planEffectTsgoPatch = Effect.fn("planEffectTsgoPatch")(function* (
|
|
@@ -201,7 +208,7 @@ export const planEffectTsgoPatch = Effect.fn("planEffectTsgoPatch")(function* (
|
|
|
201
208
|
const typescriptPackage = options.typescriptPackage ?? "typescript";
|
|
202
209
|
|
|
203
210
|
if (!isTypeScriptPackageName(typescriptPackage)) {
|
|
204
|
-
return yield*
|
|
211
|
+
return yield* InvalidEffectTsgoPackageNameError.make({ packageName: typescriptPackage });
|
|
205
212
|
}
|
|
206
213
|
const effectTsgoVersion = yield* readExactPackageVersion(
|
|
207
214
|
projectDir,
|
|
@@ -214,15 +221,22 @@ export const planEffectTsgoPatch = Effect.fn("planEffectTsgoPatch")(function* (
|
|
|
214
221
|
EFFECT_TSGO_TYPESCRIPT_VERSION,
|
|
215
222
|
);
|
|
216
223
|
const executable = yield* resolveEffectTsgoExecutable(projectDir);
|
|
224
|
+
const patchState = yield* inspectEffectTsgoPatch(projectDir, typescriptPackage);
|
|
225
|
+
const typescriptPackageArgs =
|
|
226
|
+
typescriptPackage === "typescript" ? [] : ["--typescript-package", typescriptPackage];
|
|
217
227
|
|
|
218
228
|
return {
|
|
219
|
-
alreadyPatched:
|
|
229
|
+
alreadyPatched: patchState.alreadyPatched,
|
|
230
|
+
...(patchState.hasBackup && !patchState.alreadyPatched
|
|
231
|
+
? { unpatchArgs: ["unpatch", "--typescript", ...typescriptPackageArgs] }
|
|
232
|
+
: {}),
|
|
220
233
|
projectDir,
|
|
221
234
|
executable,
|
|
222
235
|
args: [
|
|
223
236
|
"patch",
|
|
237
|
+
"--typescript",
|
|
224
238
|
...(options.force ? ["--force"] : []),
|
|
225
|
-
...
|
|
239
|
+
...typescriptPackageArgs,
|
|
226
240
|
],
|
|
227
241
|
effectTsgoVersion,
|
|
228
242
|
typescriptPackage,
|
|
@@ -230,12 +244,13 @@ export const planEffectTsgoPatch = Effect.fn("planEffectTsgoPatch")(function* (
|
|
|
230
244
|
} satisfies EffectTsgoPatchPlan;
|
|
231
245
|
});
|
|
232
246
|
|
|
233
|
-
|
|
234
|
-
|
|
247
|
+
const runEffectTsgoCommand = Effect.fn("runEffectTsgoCommand")(function* (
|
|
248
|
+
executable: string,
|
|
249
|
+
args: ReadonlyArray<string>,
|
|
250
|
+
projectDir: string,
|
|
235
251
|
) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
cwd: plan.projectDir,
|
|
252
|
+
const child = yield* ChildProcess.make(executable, args, {
|
|
253
|
+
cwd: projectDir,
|
|
239
254
|
stderr: "pipe",
|
|
240
255
|
stdout: "pipe",
|
|
241
256
|
});
|
|
@@ -246,14 +261,24 @@ export const applyEffectTsgoPatchPlan = Effect.fn("applyEffectTsgoPatchPlan")(fu
|
|
|
246
261
|
const trimmed = output.trim();
|
|
247
262
|
|
|
248
263
|
if (exitCode !== 0) {
|
|
249
|
-
return yield*
|
|
250
|
-
command: [
|
|
264
|
+
return yield* EffectTsgoPatchCommandError.make({
|
|
265
|
+
command: [executable, ...args].join(" "),
|
|
251
266
|
exitCode,
|
|
252
267
|
output: trimmed,
|
|
253
268
|
});
|
|
254
269
|
}
|
|
255
270
|
});
|
|
256
271
|
|
|
272
|
+
export const applyEffectTsgoPatchPlan = Effect.fn("applyEffectTsgoPatchPlan")(function* (
|
|
273
|
+
plan: EffectTsgoPatchPlan,
|
|
274
|
+
) {
|
|
275
|
+
if (plan.alreadyPatched) return;
|
|
276
|
+
if (plan.unpatchArgs !== undefined) {
|
|
277
|
+
yield* runEffectTsgoCommand(plan.executable, plan.unpatchArgs, plan.projectDir);
|
|
278
|
+
}
|
|
279
|
+
yield* runEffectTsgoCommand(plan.executable, plan.args, plan.projectDir);
|
|
280
|
+
});
|
|
281
|
+
|
|
257
282
|
export const patchEffectTsgo = Effect.fn("patchEffectTsgo")(function* (
|
|
258
283
|
options: EffectTsgoPatchOptions = {},
|
|
259
284
|
) {
|
package/src/gitignore.ts
CHANGED
|
@@ -22,7 +22,7 @@ export type GitignorePatch = {
|
|
|
22
22
|
readonly added: ReadonlyArray<string>;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export class UnsafeGitignorePathError extends Schema.
|
|
25
|
+
export class UnsafeGitignorePathError extends Schema.TaggedError<UnsafeGitignorePathError>()(
|
|
26
26
|
"UnsafeGitignorePathError",
|
|
27
27
|
{
|
|
28
28
|
path: Schema.String,
|
|
@@ -34,7 +34,7 @@ export class UnsafeGitignorePathError extends Schema.TaggedErrorClass<UnsafeGiti
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export class GitignoreConflictError extends Schema.
|
|
37
|
+
export class GitignoreConflictError extends Schema.TaggedError<GitignoreConflictError>()(
|
|
38
38
|
"GitignoreConflictError",
|
|
39
39
|
{ path: Schema.String },
|
|
40
40
|
) {
|
|
@@ -94,7 +94,7 @@ const planGitignorePatch = Effect.fn("planGitignorePatch")(function* (
|
|
|
94
94
|
const observation = yield* observeSymbolicLink(gitignorePath);
|
|
95
95
|
|
|
96
96
|
if (observation.kind === "symlink") {
|
|
97
|
-
return yield*
|
|
97
|
+
return yield* UnsafeGitignorePathError.make({
|
|
98
98
|
path: gitignorePath,
|
|
99
99
|
reason: "the file is a symlink",
|
|
100
100
|
});
|
|
@@ -107,7 +107,7 @@ const planGitignorePatch = Effect.fn("planGitignorePatch")(function* (
|
|
|
107
107
|
const info = yield* fs.stat(gitignorePath);
|
|
108
108
|
|
|
109
109
|
if (info.type !== "File") {
|
|
110
|
-
return yield*
|
|
110
|
+
return yield* UnsafeGitignorePathError.make({
|
|
111
111
|
path: gitignorePath,
|
|
112
112
|
reason: "the path is not a regular file",
|
|
113
113
|
});
|
|
@@ -152,7 +152,7 @@ const applyGitignorePatch = Effect.fn("applyGitignorePatch")(function* (
|
|
|
152
152
|
: currentObservation.kind !== "missing";
|
|
153
153
|
|
|
154
154
|
if (changed) {
|
|
155
|
-
return yield*
|
|
155
|
+
return yield* GitignoreConflictError.make({ path: patch.path });
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
let backedUp = false;
|
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,
|
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
|
|