@danieljvdm/dev-kit 0.17.0 → 1.0.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 +148 -648
- package/package.json +19 -62
- package/skills/dev-kit/SKILL.md +42 -213
- package/skills/dev-kit/agents/openai.yaml +2 -2
- package/skills/dev-kit/references/cloudflare-worker-api.md +37 -0
- package/skills/dev-kit/references/default-typescript-repository.md +43 -0
- package/skills/dev-kit/references/legacy-eject.md +46 -0
- package/skills/dev-kit/references/repository-setup.md +53 -0
- package/skills/dev-kit/references/skills.md +35 -0
- package/src/bin/dev-kit.ts +153 -134
- package/src/catalog-manager.ts +23 -18
- package/src/catalog.ts +8 -5
- package/src/cli-ui.ts +2 -2
- package/src/effect-tsgo.ts +10 -6
- package/src/eject.ts +715 -0
- package/src/gitignore.ts +6 -3
- package/src/legacy-project.ts +67 -0
- package/src/oxfmt.ts +1 -4
- package/src/oxlint-plugin-anti-slop/LICENSE +21 -0
- package/src/oxlint-plugin-anti-slop/index.ts +43 -0
- package/src/oxlint-plugin-anti-slop/rules/no-chained-type-assertions.ts +79 -0
- package/src/oxlint-plugin-anti-slop/rules/no-conditional-empty-object-spread.ts +51 -0
- package/src/oxlint-plugin-anti-slop/rules/no-known-value-widening.ts +267 -0
- package/src/oxlint-plugin-anti-slop/rules/no-module-mocking.ts +105 -0
- package/src/oxlint-plugin-anti-slop/rules/no-object-parameters.ts +141 -0
- package/src/oxlint-plugin-anti-slop/rules/no-reflect-apply.ts +28 -0
- package/src/oxlint-plugin-anti-slop/rules/no-reflect-get.ts +28 -0
- package/src/oxlint-plugin-anti-slop/rules/no-runtime-typeof.ts +25 -0
- package/src/oxlint-plugin-anti-slop/rules/no-shape-in-symbol-names.ts +38 -0
- package/src/oxlint-plugin-anti-slop/rules/no-unknown-parameters.ts +86 -0
- package/src/oxlint-plugin-anti-slop/rules/no-unknown-returns.ts +125 -0
- package/src/oxlint-plugin-anti-slop/rules/no-unknown-type-aliases.ts +73 -0
- package/src/oxlint-plugin-anti-slop/rules/no-unsafe-dictionary-type.ts +139 -0
- package/src/oxlint-plugin-anti-slop/rules/no-widen-then-assert.ts +396 -0
- package/src/oxlint-plugin-anti-slop/rules/require-safety-comment-for-type-assertion.ts +61 -0
- package/src/oxlint-plugin-anti-slop/runtime.js +1209 -0
- package/src/oxlint-plugin-anti-slop/shared/dictionary-types.ts +555 -0
- package/src/oxlint-plugin-anti-slop/shared/reflect-method.ts +40 -0
- package/src/oxlint.ts +26 -14
- package/src/package-skill-source.ts +17 -25
- package/src/path-digest.ts +62 -1
- package/src/project-package.ts +14 -12
- package/src/project-skills.ts +722 -0
- package/src/tool-metadata.ts +0 -2
- package/src/vendor.ts +35 -21
- package/src/vite-plus.ts +1 -3
- package/dev-kit.example.jsonc +0 -22
- package/schema/dev-kit.schema.json +0 -218
- package/schema/skill-sources.schema.json +0 -83
- package/src/index.ts +0 -125
- package/src/manifest.ts +0 -216
- package/src/oxfmt.js +0 -23
- package/src/oxlint-plugin-effect.d.ts +0 -17
- package/src/oxlint-plugin-style.d.ts +0 -8
- package/src/oxlint.js +0 -94
- package/src/project-state.ts +0 -122
- package/src/scaffold.ts +0 -79
- package/src/skill-manager.ts +0 -515
- package/src/sync.ts +0 -1919
- package/src/tool-ignore-patterns.js +0 -9
- package/src/vite-plus-dependency.ts +0 -69
- package/src/vite-plus-hooks.ts +0 -175
- package/src/vite-plus-workflow.ts +0 -82
- package/src/vite-plus.js +0 -88
- package/src/worktrunk-config.ts +0 -88
- package/templates/AGENTS.md +0 -11
- package/templates/vite-plus/github-actions-check.yml +0 -51
- package/templates/worktrunk/wt.toml +0 -27
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, FileSystem, Path, Result, Schema } from "effect";
|
|
1
|
+
import { Effect, FileSystem, Option, Path, Result, Schema } from "effect";
|
|
2
2
|
|
|
3
3
|
import { observeSymbolicLink } from "./node-symbolic-link.ts";
|
|
4
4
|
import { readDirectDependencyNames } from "./project-package.ts";
|
|
@@ -34,33 +34,25 @@ const PackageMetadataSchema = Schema.fromJsonString(
|
|
|
34
34
|
}),
|
|
35
35
|
);
|
|
36
36
|
|
|
37
|
-
const
|
|
38
|
-
|
|
37
|
+
const DiscoveryLocationSchema = Schema.String.check(Schema.isPattern(/\S/));
|
|
38
|
+
const IntentDiscoveryMetadataSchema = Schema.Struct({
|
|
39
|
+
version: Schema.Literal(1),
|
|
40
|
+
repo: DiscoveryLocationSchema,
|
|
41
|
+
docs: DiscoveryLocationSchema,
|
|
42
|
+
});
|
|
43
|
+
const RepositoryDiscoveryMetadataSchema = Schema.Union([
|
|
44
|
+
DiscoveryLocationSchema,
|
|
45
|
+
Schema.Struct({ url: DiscoveryLocationSchema }),
|
|
46
|
+
]);
|
|
47
|
+
const decodeIntentDiscoveryMetadata = Schema.decodeUnknownOption(IntentDiscoveryMetadataSchema);
|
|
48
|
+
const decodeRepositoryDiscoveryMetadata = Schema.decodeUnknownOption(
|
|
49
|
+
RepositoryDiscoveryMetadataSchema,
|
|
50
|
+
);
|
|
39
51
|
|
|
40
52
|
const hasIntentDiscoveryMetadata = (metadata: typeof PackageMetadataSchema.Type): boolean => {
|
|
41
|
-
|
|
53
|
+
if (Option.isSome(decodeIntentDiscoveryMetadata(metadata.intent))) return true;
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
typeof intent === "object" &&
|
|
45
|
-
intent !== null &&
|
|
46
|
-
"version" in intent &&
|
|
47
|
-
intent.version === 1 &&
|
|
48
|
-
"repo" in intent &&
|
|
49
|
-
nonEmptyString(intent.repo) &&
|
|
50
|
-
"docs" in intent &&
|
|
51
|
-
nonEmptyString(intent.docs)
|
|
52
|
-
) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
const repository = metadata.repository;
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
nonEmptyString(repository) ||
|
|
59
|
-
(typeof repository === "object" &&
|
|
60
|
-
repository !== null &&
|
|
61
|
-
"url" in repository &&
|
|
62
|
-
nonEmptyString(repository.url))
|
|
63
|
-
);
|
|
55
|
+
return Option.isSome(decodeRepositoryDiscoveryMetadata(metadata.repository));
|
|
64
56
|
};
|
|
65
57
|
|
|
66
58
|
const isSafePackageVersion = (value: string): boolean =>
|
package/src/path-digest.ts
CHANGED
|
@@ -23,13 +23,14 @@ export class PathInspectionError extends Schema.TaggedError<PathInspectionError>
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const textEncoder = new TextEncoder();
|
|
26
|
+
const isString = Schema.is(Schema.String);
|
|
26
27
|
|
|
27
28
|
// Git preserves only the executable distinction for regular files. Canonicalizing
|
|
28
29
|
// the remaining bits keeps digests stable across checkout and copy umasks.
|
|
29
30
|
const canonicalFileMode = (mode: number): number => ((mode & 0o111) === 0 ? 0o644 : 0o755);
|
|
30
31
|
|
|
31
32
|
const frame = (value: string | Uint8Array): Uint8Array => {
|
|
32
|
-
const bytes =
|
|
33
|
+
const bytes = isString(value) ? textEncoder.encode(value) : value;
|
|
33
34
|
const framed = new Uint8Array(4 + bytes.length);
|
|
34
35
|
|
|
35
36
|
new DataView(framed.buffer).setUint32(0, bytes.length);
|
|
@@ -152,6 +153,66 @@ export const observePath = Effect.fn("observeManagedPath")(function* (absolutePa
|
|
|
152
153
|
);
|
|
153
154
|
});
|
|
154
155
|
|
|
156
|
+
export const observeDirectoryWithoutEntry = Effect.fn("observeDirectoryWithoutEntry")(function* (
|
|
157
|
+
absolutePath: string,
|
|
158
|
+
excludedEntry: string,
|
|
159
|
+
) {
|
|
160
|
+
const fs = yield* FileSystem.FileSystem;
|
|
161
|
+
const path = yield* Path.Path;
|
|
162
|
+
|
|
163
|
+
if (
|
|
164
|
+
excludedEntry.length === 0 ||
|
|
165
|
+
excludedEntry === "." ||
|
|
166
|
+
excludedEntry === ".." ||
|
|
167
|
+
excludedEntry.includes("/") ||
|
|
168
|
+
excludedEntry.includes("\\")
|
|
169
|
+
) {
|
|
170
|
+
return yield* PathInspectionError.make({
|
|
171
|
+
path: absolutePath,
|
|
172
|
+
operation: "exclude a direct directory entry",
|
|
173
|
+
cause: excludedEntry,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const observed = yield* observeSymbolicLink(absolutePath);
|
|
177
|
+
|
|
178
|
+
if (observed.kind === "missing") return { kind: "missing" } as const;
|
|
179
|
+
if (observed.kind === "symlink") {
|
|
180
|
+
return yield* PathInspectionError.make({
|
|
181
|
+
path: absolutePath,
|
|
182
|
+
operation: "inspect a regular directory",
|
|
183
|
+
cause: "path is a symlink",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const info = yield* fs.stat(absolutePath);
|
|
187
|
+
|
|
188
|
+
if (info.type !== "Directory") {
|
|
189
|
+
return yield* PathInspectionError.make({
|
|
190
|
+
path: absolutePath,
|
|
191
|
+
operation: "inspect a regular directory",
|
|
192
|
+
cause: info.type,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
const entries = (yield* fs.readDirectory(absolutePath))
|
|
196
|
+
.filter((entry) => entry !== excludedEntry)
|
|
197
|
+
.sort(compareUtf8);
|
|
198
|
+
const frames: Array<string | Uint8Array> = ["directory-v1"];
|
|
199
|
+
|
|
200
|
+
for (const entry of entries) {
|
|
201
|
+
const child = yield* digestFileSystemPath(path.join(absolutePath, entry), canonicalFileMode);
|
|
202
|
+
|
|
203
|
+
if (child.kind === "missing") {
|
|
204
|
+
return yield* PathInspectionError.make({
|
|
205
|
+
path: path.join(absolutePath, entry),
|
|
206
|
+
operation: "inspect a stable directory tree",
|
|
207
|
+
cause: "path disappeared during inspection",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
frames.push(entry, child.kind, child.digest);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { kind: "directory", digest: yield* digestFrames(frames) } as const;
|
|
214
|
+
});
|
|
215
|
+
|
|
155
216
|
export const digestText = Effect.fn("digestText")(function* (value: string) {
|
|
156
217
|
return yield* digestFrames(["text-v1", value]);
|
|
157
218
|
});
|
package/src/project-package.ts
CHANGED
|
@@ -47,14 +47,16 @@ export const PACKAGE_MANAGER_COMMANDS = {
|
|
|
47
47
|
yarn: { install: "yarn install", label: "Yarn" },
|
|
48
48
|
} as const;
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
const PackageManagerNameSchema = Schema.Literals(["bun", "npm", "pnpm", "yarn"]);
|
|
51
|
+
|
|
52
|
+
export type PackageManagerName = typeof PackageManagerNameSchema.Type;
|
|
53
|
+
|
|
54
|
+
const decodePackageManagerName = Schema.decodeUnknownOption(PackageManagerNameSchema);
|
|
51
55
|
|
|
52
56
|
const packageManagerName = (declaration: string | undefined): PackageManagerName | undefined => {
|
|
53
57
|
const name = declaration?.split("@", 1)[0];
|
|
54
58
|
|
|
55
|
-
return name
|
|
56
|
-
? (name as PackageManagerName)
|
|
57
|
-
: undefined;
|
|
59
|
+
return name === undefined ? undefined : Option.getOrUndefined(decodePackageManagerName(name));
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
export const detectPackageManager = Effect.fn("detectPackageManager")(function* (
|
|
@@ -129,13 +131,9 @@ const WorkspacePatternsSchema = Schema.Union([
|
|
|
129
131
|
// this is a genuinely untyped boundary.
|
|
130
132
|
const decodeWorkspacePatterns = Schema.decodeUnknownOption(WorkspacePatternsSchema);
|
|
131
133
|
|
|
132
|
-
const workspacePatterns = (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (Option.isNone(decoded)) return [];
|
|
136
|
-
|
|
137
|
-
return "packages" in decoded.value ? decoded.value.packages : decoded.value;
|
|
138
|
-
};
|
|
134
|
+
const workspacePatterns = (
|
|
135
|
+
workspaces: typeof WorkspacePatternsSchema.Type,
|
|
136
|
+
): ReadonlyArray<string> => ("packages" in workspaces ? workspaces.packages : workspaces);
|
|
139
137
|
|
|
140
138
|
/**
|
|
141
139
|
* Direct dependency names of the project package plus every workspace member
|
|
@@ -149,8 +147,12 @@ export const readWorkspaceDependencyNames = Effect.fn("readWorkspaceDependencyNa
|
|
|
149
147
|
const path = yield* Path.Path;
|
|
150
148
|
const manifest = yield* readOptionalProjectPackage(projectDir);
|
|
151
149
|
const names = new Set(manifestDependencyNames(manifest));
|
|
150
|
+
const decodedWorkspaces = decodeWorkspacePatterns(manifest?.workspaces);
|
|
151
|
+
const patterns = Option.isSome(decodedWorkspaces)
|
|
152
|
+
? workspacePatterns(decodedWorkspaces.value)
|
|
153
|
+
: [];
|
|
152
154
|
|
|
153
|
-
for (const pattern of
|
|
155
|
+
for (const pattern of patterns) {
|
|
154
156
|
if (pattern.startsWith("!")) continue;
|
|
155
157
|
const star = pattern.indexOf("*");
|
|
156
158
|
let memberDirs: ReadonlyArray<string> = [];
|