@outfitter/tooling 0.3.3 → 0.3.4

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 (67) hide show
  1. package/.markdownlint-cli2.jsonc +55 -55
  2. package/README.md +21 -21
  3. package/dist/bun-version-compat.d.ts +2 -0
  4. package/dist/bun-version-compat.js +10 -0
  5. package/dist/cli/check-boundary-invocations.d.ts +34 -0
  6. package/dist/cli/check-boundary-invocations.js +14 -0
  7. package/dist/cli/check-bunup-registry.d.ts +36 -0
  8. package/dist/cli/check-bunup-registry.js +12 -0
  9. package/dist/cli/check-changeset.d.ts +66 -0
  10. package/dist/cli/check-changeset.js +20 -0
  11. package/dist/cli/check-clean-tree.d.ts +36 -0
  12. package/dist/cli/check-clean-tree.js +14 -0
  13. package/dist/cli/check-exports.d.ts +2 -0
  14. package/dist/cli/check-exports.js +14 -0
  15. package/dist/cli/check-markdown-links.d.ts +42 -0
  16. package/dist/cli/check-markdown-links.js +13 -0
  17. package/dist/cli/check-readme-imports.d.ts +60 -0
  18. package/dist/{shared/chunk-7tdgbqb0.js → cli/check-readme-imports.js} +7 -6
  19. package/dist/cli/check-tsdoc.d.ts +2 -0
  20. package/dist/cli/check-tsdoc.js +36 -0
  21. package/dist/cli/check.d.ts +19 -0
  22. package/dist/cli/check.js +10 -0
  23. package/dist/cli/fix.d.ts +19 -0
  24. package/dist/cli/fix.js +10 -0
  25. package/dist/cli/index.js +49 -1218
  26. package/dist/cli/init.d.ts +31 -0
  27. package/dist/cli/init.js +12 -0
  28. package/dist/cli/pre-push.d.ts +60 -0
  29. package/dist/cli/pre-push.js +27 -0
  30. package/dist/cli/upgrade-bun.d.ts +8 -0
  31. package/dist/cli/upgrade-bun.js +9 -0
  32. package/dist/index.d.ts +6 -186
  33. package/dist/index.js +4 -42
  34. package/dist/registry/build.d.ts +4 -0
  35. package/dist/registry/build.js +279 -0
  36. package/dist/registry/index.d.ts +3 -0
  37. package/dist/registry/index.js +1 -0
  38. package/dist/registry/schema.d.ts +2 -0
  39. package/dist/registry/schema.js +28 -0
  40. package/dist/shared/@outfitter/tooling-1hez6j9d.js +21 -0
  41. package/dist/shared/@outfitter/tooling-6cxfdx0q.js +187 -0
  42. package/dist/shared/{chunk-cmde0fwx.js → @outfitter/tooling-875svjnz.js} +16 -31
  43. package/dist/shared/@outfitter/tooling-9ram55dd.js +69 -0
  44. package/dist/shared/@outfitter/tooling-9vs606gq.d.ts +3 -0
  45. package/dist/shared/@outfitter/tooling-a4bfx4be.js +21 -0
  46. package/dist/shared/@outfitter/tooling-amrbp7cm.js +102 -0
  47. package/dist/shared/@outfitter/tooling-ctmgnap5.js +19 -0
  48. package/dist/shared/@outfitter/tooling-d363b88r.js +349 -0
  49. package/dist/shared/@outfitter/tooling-gcdvsqqp.js +73 -0
  50. package/dist/shared/@outfitter/tooling-h04te11c.js +231 -0
  51. package/dist/shared/@outfitter/tooling-ja1zg5yc.js +214 -0
  52. package/dist/shared/@outfitter/tooling-jnrs9rqd.js +4 -0
  53. package/dist/shared/@outfitter/tooling-mkynjra9.js +23 -0
  54. package/dist/shared/@outfitter/tooling-njw4z34x.d.ts +140 -0
  55. package/dist/shared/@outfitter/tooling-pq47jv6t.js +213 -0
  56. package/dist/shared/@outfitter/tooling-sjm8nebx.d.ts +109 -0
  57. package/dist/shared/@outfitter/tooling-vjmhvpjq.d.ts +29 -0
  58. package/dist/shared/@outfitter/tooling-wesswf21.d.ts +59 -0
  59. package/dist/shared/@outfitter/tooling-wwm97f47.js +81 -0
  60. package/dist/version.d.ts +2 -0
  61. package/dist/version.js +8 -0
  62. package/package.json +134 -131
  63. package/registry/registry.json +17 -10
  64. package/tsconfig.preset.bun.json +5 -5
  65. package/tsconfig.preset.json +33 -33
  66. package/biome.json +0 -81
  67. package/dist/shared/chunk-3s189drz.js +0 -4
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shared Bun version compatibility helpers.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ /**
7
+ * Parsed semantic version components.
8
+ */
9
+ interface ParsedSemver {
10
+ readonly major: number;
11
+ readonly minor: number;
12
+ readonly patch: number;
13
+ }
14
+ /**
15
+ * Parse a semver-like value into numeric components.
16
+ *
17
+ * Accepts standard versions like `1.3.10` and prerelease variants like
18
+ * `1.3.10-canary.1` by reading only the numeric major/minor/patch prefix.
19
+ */
20
+ declare function parseSemver(version: string): ParsedSemver | undefined;
21
+ /**
22
+ * Whether a candidate `@types/bun` version is compatible with a target Bun version.
23
+ *
24
+ * Compatibility rule:
25
+ * - same major/minor
26
+ * - candidate patch <= Bun patch
27
+ */
28
+ declare function isTypesBunVersionCompatible(bunVersion: string, bunTypesVersion: string): boolean;
29
+ export { ParsedSemver, parseSemver, isTypesBunVersionCompatible };
@@ -0,0 +1,59 @@
1
+ /** A package.json map: keys are subpaths, values are conditions or strings */
2
+ type ExportMap = Record<string, unknown>;
3
+ /** Describes drift between expected and actual exports for a single package */
4
+ interface ExportDrift {
5
+ readonly package: string;
6
+ readonly path: string;
7
+ readonly added: string[];
8
+ readonly removed: string[];
9
+ readonly changed: Array<{
10
+ readonly key: string;
11
+ readonly expected: unknown;
12
+ readonly actual: unknown;
13
+ }>;
14
+ }
15
+ /** Per-package comparison result */
16
+ interface PackageResult {
17
+ readonly name: string;
18
+ readonly status: "ok" | "drift";
19
+ readonly drift?: ExportDrift;
20
+ }
21
+ /** Aggregated result across all checked packages */
22
+ interface CheckResult {
23
+ readonly ok: boolean;
24
+ readonly packages: PackageResult[];
25
+ }
26
+ /** Input for comparing a single package's exports */
27
+ interface CompareInput {
28
+ readonly name: string;
29
+ readonly actual: ExportMap;
30
+ readonly expected: ExportMap;
31
+ readonly path?: string;
32
+ }
33
+ /**
34
+ * Convert a source entry file path to its subpath.
35
+ *
36
+ * @example
37
+ * entryToSubpath("src/index.ts") // "."
38
+ * entryToSubpath("src/branded.ts") // "./branded"
39
+ * entryToSubpath("src/cli/index.ts") // "./cli"
40
+ * entryToSubpath("src/cli/check.ts") // "./cli/check"
41
+ */
42
+ declare function entryToSubpath(entry: string): string;
43
+ /**
44
+ * Compare actual vs expected exports for a single package.
45
+ *
46
+ * Returns a PackageResult with status "ok" or "drift" and detailed diff.
47
+ */
48
+ declare function compareExports(input: CompareInput): PackageResult;
49
+ interface CheckExportsOptions {
50
+ readonly json?: boolean;
51
+ }
52
+ declare function resolveJsonMode(options?: CheckExportsOptions): boolean;
53
+ /**
54
+ * Run check-exports across all workspace packages.
55
+ *
56
+ * Reads the bunup workspace config to discover packages and their * settings, then compares expected vs actual exports in each package.json.
57
+ */
58
+ declare function runCheckExports(options?: CheckExportsOptions): Promise<void>;
59
+ export { ExportMap, ExportDrift, PackageResult, CheckResult, CompareInput, entryToSubpath, compareExports, CheckExportsOptions, resolveJsonMode, runCheckExports };
@@ -0,0 +1,81 @@
1
+ // @bun
2
+ // packages/tooling/src/cli/check-bunup-registry.ts
3
+ import { resolve } from "path";
4
+ function extractBunupFilterName(script) {
5
+ const match = script.match(/bunup\s+--filter\s+(\S+)/);
6
+ return match?.[1] ?? null;
7
+ }
8
+ function findUnregisteredPackages(packagesWithFilter, registeredNames) {
9
+ const registered = new Set(registeredNames);
10
+ const missing = packagesWithFilter.filter((name) => !registered.has(name)).toSorted();
11
+ return {
12
+ ok: missing.length === 0,
13
+ missing
14
+ };
15
+ }
16
+ var COLORS = {
17
+ reset: "\x1B[0m",
18
+ red: "\x1B[31m",
19
+ green: "\x1B[32m",
20
+ yellow: "\x1B[33m",
21
+ blue: "\x1B[34m",
22
+ dim: "\x1B[2m"
23
+ };
24
+ async function runCheckBunupRegistry() {
25
+ const cwd = process.cwd();
26
+ const configPath = resolve(cwd, "bunup.config.ts");
27
+ let registeredNames;
28
+ try {
29
+ const configModule = await import(configPath);
30
+ const rawConfig = configModule.default;
31
+ if (!Array.isArray(rawConfig)) {
32
+ process.stderr.write(`bunup.config.ts must export a workspace array
33
+ `);
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+ registeredNames = rawConfig.map((entry) => entry.name);
38
+ } catch {
39
+ process.stderr.write(`Could not load bunup.config.ts from ${cwd}
40
+ `);
41
+ process.exitCode = 1;
42
+ return;
43
+ }
44
+ const packagesWithFilter = [];
45
+ const glob = new Bun.Glob("{packages,apps}/*/package.json");
46
+ for (const match of glob.scanSync({ cwd })) {
47
+ const pkgPath = resolve(cwd, match);
48
+ try {
49
+ const pkg = await Bun.file(pkgPath).json();
50
+ const buildScript = pkg.scripts?.["build"];
51
+ if (!buildScript)
52
+ continue;
53
+ const filterName = extractBunupFilterName(buildScript);
54
+ if (filterName) {
55
+ packagesWithFilter.push(filterName);
56
+ }
57
+ } catch {}
58
+ }
59
+ const result = findUnregisteredPackages(packagesWithFilter, registeredNames);
60
+ if (result.ok) {
61
+ process.stdout.write(`${COLORS.green}All ${packagesWithFilter.length} packages with bunup --filter are registered in bunup.config.ts.${COLORS.reset}
62
+ `);
63
+ process.exitCode = 0;
64
+ return;
65
+ }
66
+ process.stderr.write(`${COLORS.red}${result.missing.length} package(s) have bunup --filter build scripts but are not registered in bunup.config.ts:${COLORS.reset}
67
+
68
+ `);
69
+ for (const name of result.missing) {
70
+ process.stderr.write(` ${COLORS.yellow}${name}${COLORS.reset} ${COLORS.dim}(missing from workspace array)${COLORS.reset}
71
+ `);
72
+ }
73
+ process.stderr.write(`
74
+ Add the missing entries to ${COLORS.blue}bunup.config.ts${COLORS.reset} defineWorkspace array.
75
+ `);
76
+ process.stderr.write(`Without registration, ${COLORS.dim}bunup --filter <name>${COLORS.reset} silently exits with no output.
77
+ `);
78
+ process.exitCode = 1;
79
+ }
80
+
81
+ export { extractBunupFilterName, findUnregisteredPackages, runCheckBunupRegistry };
@@ -0,0 +1,2 @@
1
+ import { VERSION } from "./shared/@outfitter/tooling-9vs606gq.js";
2
+ export { VERSION };
@@ -0,0 +1,8 @@
1
+ // @bun
2
+ import {
3
+ VERSION
4
+ } from "./shared/@outfitter/tooling-ctmgnap5.js";
5
+ import"./shared/@outfitter/tooling-jnrs9rqd.js";
6
+ export {
7
+ VERSION
8
+ };
package/package.json CHANGED
@@ -1,133 +1,136 @@
1
1
  {
2
- "name": "@outfitter/tooling",
3
- "description": "Dev tooling configuration presets for Outfitter projects (biome, typescript, lefthook, markdownlint)",
4
- "version": "0.3.3",
5
- "type": "module",
6
- "files": [
7
- "dist",
8
- "registry",
9
- "biome.json",
10
- "tsconfig.preset.json",
11
- "tsconfig.preset.bun.json",
12
- "lefthook.yml",
13
- ".markdownlint-cli2.jsonc"
14
- ],
15
- "module": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
17
- "exports": {
18
- ".": {
19
- "import": {
20
- "types": "./dist/index.d.ts",
21
- "default": "./dist/index.js"
22
- }
23
- },
24
- "./.markdownlint-cli2": "./.markdownlint-cli2.jsonc",
25
- "./.markdownlint-cli2.jsonc": "./.markdownlint-cli2.jsonc",
26
- "./biome": "./biome.json",
27
- "./biome.json": "./biome.json",
28
- "./cli/check": {
29
- "import": {
30
- "types": "./dist/cli/check.d.ts",
31
- "default": "./dist/cli/check.js"
32
- }
33
- },
34
- "./cli/check-tsdoc": {
35
- "import": {
36
- "types": "./dist/cli/check-tsdoc.d.ts",
37
- "default": "./dist/cli/check-tsdoc.js"
38
- }
39
- },
40
- "./cli/fix": {
41
- "import": {
42
- "types": "./dist/cli/fix.d.ts",
43
- "default": "./dist/cli/fix.js"
44
- }
45
- },
46
- "./cli/init": {
47
- "import": {
48
- "types": "./dist/cli/init.d.ts",
49
- "default": "./dist/cli/init.js"
50
- }
51
- },
52
- "./lefthook": "./lefthook.yml",
53
- "./lefthook.yml": "./lefthook.yml",
54
- "./package.json": "./package.json",
55
- "./registry": {
56
- "import": {
57
- "types": "./dist/registry/index.d.ts",
58
- "default": "./dist/registry/index.js"
59
- }
60
- },
61
- "./tsconfig": "./tsconfig.preset.json",
62
- "./tsconfig-bun": "./tsconfig.preset.bun.json",
63
- "./tsconfig.preset.bun.json": "./tsconfig.preset.bun.json",
64
- "./tsconfig.preset.json": "./tsconfig.preset.json"
65
- },
66
- "bin": {
67
- "tooling": "./dist/cli/index.js"
68
- },
69
- "sideEffects": false,
70
- "scripts": {
71
- "build:registry": "bun run src/registry/build.ts",
72
- "sync:exports": "bun run scripts/sync-exports.ts",
73
- "sync:exports:check": "bun run scripts/sync-exports.ts --check",
74
- "prebuild": "bun run build:registry && bun run sync:exports:check",
75
- "build": "bunup --filter @outfitter/tooling",
76
- "prepack": "bun run sync:exports",
77
- "lint": "biome lint ./src",
78
- "lint:fix": "biome lint --write ./src",
79
- "test": "bun run build:registry && bun test",
80
- "typecheck": "tsc --noEmit",
81
- "clean": "rm -rf dist registry",
82
- "prepublishOnly": "bun ../../scripts/check-publish-manifest.ts"
83
- },
84
- "dependencies": {
85
- "@outfitter/cli": "0.5.2",
86
- "commander": "^14.0.2",
87
- "typescript": "^5.9.3",
88
- "zod": "^4.3.5"
89
- },
90
- "devDependencies": {
91
- "@outfitter/presets": "0.2.0",
92
- "@types/bun": "^1.3.9",
93
- "yaml": "^2.8.2"
94
- },
95
- "peerDependencies": {
96
- "ultracite": "^7.0.0",
97
- "lefthook": "^2.0.0",
98
- "markdownlint-cli2": ">=0.17.0"
99
- },
100
- "peerDependenciesMeta": {
101
- "ultracite": {
102
- "optional": true
103
- },
104
- "lefthook": {
105
- "optional": true
106
- },
107
- "markdownlint-cli2": {
108
- "optional": true
109
- }
110
- },
111
- "engines": {
112
- "bun": ">=1.3.9"
113
- },
114
- "keywords": [
115
- "outfitter",
116
- "tooling",
117
- "biome",
118
- "typescript",
119
- "lefthook",
120
- "markdownlint",
121
- "config",
122
- "presets"
123
- ],
124
- "license": "MIT",
125
- "repository": {
126
- "type": "git",
127
- "url": "https://github.com/outfitter-dev/outfitter.git",
128
- "directory": "packages/tooling"
129
- },
130
- "publishConfig": {
131
- "access": "public"
132
- }
2
+ "name": "@outfitter/tooling",
3
+ "description": "Dev tooling configuration presets for Outfitter projects (oxlint/oxfmt, typescript, lefthook, markdownlint)",
4
+ "version": "0.3.4",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "registry",
9
+ "tsconfig.preset.json",
10
+ "tsconfig.preset.bun.json",
11
+ "lefthook.yml",
12
+ ".markdownlint-cli2.jsonc"
13
+ ],
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ }
22
+ },
23
+ "./.markdownlint-cli2": "./.markdownlint-cli2.jsonc",
24
+ "./.markdownlint-cli2.jsonc": "./.markdownlint-cli2.jsonc",
25
+ "./cli/check": {
26
+ "import": {
27
+ "types": "./dist/cli/check.d.ts",
28
+ "default": "./dist/cli/check.js"
29
+ }
30
+ },
31
+ "./cli/check-markdown-links": {
32
+ "import": {
33
+ "types": "./dist/cli/check-markdown-links.d.ts",
34
+ "default": "./dist/cli/check-markdown-links.js"
35
+ }
36
+ },
37
+ "./cli/check-tsdoc": {
38
+ "import": {
39
+ "types": "./dist/cli/check-tsdoc.d.ts",
40
+ "default": "./dist/cli/check-tsdoc.js"
41
+ }
42
+ },
43
+ "./cli/fix": {
44
+ "import": {
45
+ "types": "./dist/cli/fix.d.ts",
46
+ "default": "./dist/cli/fix.js"
47
+ }
48
+ },
49
+ "./cli/init": {
50
+ "import": {
51
+ "types": "./dist/cli/init.d.ts",
52
+ "default": "./dist/cli/init.js"
53
+ }
54
+ },
55
+ "./lefthook": "./lefthook.yml",
56
+ "./lefthook.yml": "./lefthook.yml",
57
+ "./package.json": "./package.json",
58
+ "./registry": {
59
+ "import": {
60
+ "types": "./dist/registry/index.d.ts",
61
+ "default": "./dist/registry/index.js"
62
+ }
63
+ },
64
+ "./tsconfig": "./tsconfig.preset.json",
65
+ "./tsconfig-bun": "./tsconfig.preset.bun.json",
66
+ "./tsconfig.preset.bun.json": "./tsconfig.preset.bun.json",
67
+ "./tsconfig.preset.json": "./tsconfig.preset.json"
68
+ },
69
+ "bin": {
70
+ "tooling": "./dist/cli/index.js"
71
+ },
72
+ "sideEffects": false,
73
+ "scripts": {
74
+ "build:registry": "bun run src/registry/build.ts",
75
+ "sync:exports": "bun run scripts/sync-exports.ts",
76
+ "sync:exports:check": "bun run scripts/sync-exports.ts --check",
77
+ "build": "bun run build:registry && bun run sync:exports:check && cd ../.. && bunup --filter @outfitter/tooling",
78
+ "prepack": "bun run sync:exports",
79
+ "lint": "oxlint ./src",
80
+ "lint:fix": "oxlint --fix ./src",
81
+ "test": "bun run build:registry && bun test",
82
+ "typecheck": "tsc --noEmit",
83
+ "clean": "rm -rf dist registry",
84
+ "prepublishOnly": "bun ../../scripts/check-publish-manifest.ts"
85
+ },
86
+ "dependencies": {
87
+ "@outfitter/cli": "0.5.3",
88
+ "commander": "^14.0.2",
89
+ "typescript": "^5.9.3",
90
+ "zod": "^4.3.5"
91
+ },
92
+ "devDependencies": {
93
+ "@outfitter/presets": "0.2.1",
94
+ "@types/bun": "^1.3.9",
95
+ "yaml": "^2.8.2"
96
+ },
97
+ "peerDependencies": {
98
+ "ultracite": "^7.0.0",
99
+ "lefthook": "^2.0.0",
100
+ "markdownlint-cli2": ">=0.17.0"
101
+ },
102
+ "peerDependenciesMeta": {
103
+ "ultracite": {
104
+ "optional": true
105
+ },
106
+ "lefthook": {
107
+ "optional": true
108
+ },
109
+ "markdownlint-cli2": {
110
+ "optional": true
111
+ }
112
+ },
113
+ "engines": {
114
+ "bun": ">=1.3.10"
115
+ },
116
+ "keywords": [
117
+ "outfitter",
118
+ "tooling",
119
+ "oxlint",
120
+ "oxfmt",
121
+ "typescript",
122
+ "lefthook",
123
+ "markdownlint",
124
+ "config",
125
+ "presets"
126
+ ],
127
+ "license": "MIT",
128
+ "repository": {
129
+ "type": "git",
130
+ "url": "https://github.com/outfitter-dev/outfitter.git",
131
+ "directory": "packages/tooling"
132
+ },
133
+ "publishConfig": {
134
+ "access": "public"
135
+ }
133
136
  }
@@ -16,17 +16,24 @@
16
16
  }
17
17
  ]
18
18
  },
19
- "biome": {
20
- "name": "biome",
21
- "description": "Biome linter/formatter configuration via Ultracite",
19
+ "linter": {
20
+ "name": "linter",
21
+ "description": "Linter and formatter configuration (oxlint/oxfmt) via Ultracite",
22
22
  "files": [
23
23
  {
24
- "path": "biome.json",
25
- "content": "{\n\t\"$schema\": \"https://biomejs.dev/schemas/2.4.4/schema.json\",\n\t\"root\": false,\n\t\"javascript\": {\n\t\t\"globals\": [\"Bun\"]\n\t},\n\t\"linter\": {\n\t\t\"rules\": {\n\t\t\t\"complexity\": {\n\t\t\t\t\"useLiteralKeys\": \"off\",\n\t\t\t\t\"noVoid\": \"off\",\n\t\t\t\t\"noExcessiveCognitiveComplexity\": \"off\"\n\t\t\t},\n\t\t\t\"performance\": {\n\t\t\t\t\"useTopLevelRegex\": \"off\"\n\t\t\t},\n\t\t\t\"style\": {\n\t\t\t\t\"useBlockStatements\": \"off\"\n\t\t\t},\n\t\t\t\"suspicious\": {\n\t\t\t\t\"noConsole\": \"error\"\n\t\t\t}\n\t\t}\n\t},\n\t\"vcs\": {\n\t\t\"enabled\": true,\n\t\t\"clientKind\": \"git\",\n\t\t\"useIgnoreFile\": true\n\t},\n\t\"files\": {\n\t\t\"ignoreUnknown\": true,\n\t\t\"includes\": [\n\t\t\t\"**\",\n\t\t\t\"!**/node_modules\",\n\t\t\t\"!**/dist\",\n\t\t\t\"!**/.turbo\",\n\t\t\t\"!**/*.gen.ts\",\n\t\t\t\"!registry/registry.json\"\n\t\t]\n\t},\n\t\"overrides\": [\n\t\t{\n\t\t\t\"includes\": [\n\t\t\t\t\"packages/*/src/index.ts\",\n\t\t\t\t\"apps/*/src/index.ts\",\n\t\t\t\t\"**/index.ts\"\n\t\t\t],\n\t\t\t\"linter\": {\n\t\t\t\t\"rules\": {\n\t\t\t\t\t\"performance\": {\n\t\t\t\t\t\t\"noBarrelFile\": \"off\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"includes\": [\"**/*.test.ts\", \"**/__tests__/**/*\"],\n\t\t\t\"linter\": {\n\t\t\t\t\"rules\": {\n\t\t\t\t\t\"suspicious\": {\n\t\t\t\t\t\t\"useAwait\": \"off\",\n\t\t\t\t\t\t\"noConsole\": \"off\"\n\t\t\t\t\t},\n\t\t\t\t\t\"performance\": {\n\t\t\t\t\t\t\"noDelete\": \"off\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"includes\": [\"apps/**/*.ts\", \"scripts/**/*.ts\", \"**/scripts/**/*.ts\"],\n\t\t\t\"linter\": {\n\t\t\t\t\"rules\": {\n\t\t\t\t\t\"suspicious\": {\n\t\t\t\t\t\t\"noConsole\": \"off\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t]\n}\n"
24
+ "path": ".oxlintrc.json",
25
+ "content": "{\n \"$schema\": \"./node_modules/oxlint/configuration_schema.json\",\n \"plugins\": [\"eslint\"],\n \"jsPlugins\": [\n {\n \"name\": \"outfitter\",\n \"specifier\": \"@outfitter/oxlint-plugin\"\n }\n ],\n \"globals\": { \"Bun\": \"readonly\" },\n \"categories\": {\n \"correctness\": \"error\",\n \"suspicious\": \"error\",\n \"pedantic\": \"off\",\n \"perf\": \"off\",\n \"style\": \"off\",\n \"restriction\": \"off\"\n },\n \"ignorePatterns\": [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/.turbo/**\",\n \"**/*.gen.ts\"\n ],\n \"rules\": {\n \"no-void\": \"off\",\n \"outfitter/action-must-register\": \"warn\",\n \"outfitter/handler-must-return-result\": \"error\",\n \"outfitter/max-file-lines\": [\"error\", { \"warn\": 200, \"error\": 400 }],\n \"outfitter/no-console-in-packages\": \"error\",\n \"outfitter/no-cross-tier-import\": \"error\",\n \"outfitter/no-deep-relative-import\": \"warn\",\n \"outfitter/no-nested-barrel\": \"warn\",\n \"outfitter/no-process-env-in-packages\": \"warn\",\n \"outfitter/no-process-exit-in-packages\": \"error\",\n \"outfitter/no-throw-in-handler\": \"error\",\n \"outfitter/prefer-bun-api\": \"warn\",\n \"outfitter/snapshot-location\": \"warn\",\n \"outfitter/test-file-naming\": \"warn\",\n \"outfitter/use-error-taxonomy\": \"warn\"\n }\n}\n"
26
+ },
27
+ {
28
+ "path": ".oxfmtrc.jsonc",
29
+ "content": "{\n \"$schema\": \"./node_modules/oxfmt/configuration_schema.json\",\n \"printWidth\": 80,\n \"tabWidth\": 2,\n \"useTabs\": false,\n \"semi\": true,\n \"singleQuote\": false,\n \"quoteProps\": \"as-needed\",\n \"jsxSingleQuote\": false,\n \"trailingComma\": \"es5\",\n \"bracketSpacing\": true,\n \"bracketSameLine\": false,\n \"arrowParens\": \"always\",\n \"endOfLine\": \"lf\",\n \"experimentalSortImports\": {\n \"ignoreCase\": true,\n \"newlinesBetween\": true,\n \"order\": \"asc\",\n },\n}\n"
26
30
  }
27
31
  ],
28
32
  "devDependencies": {
29
- "ultracite": "7.2.3"
33
+ "@outfitter/oxlint-plugin": "^0.1.0",
34
+ "ultracite": "7.2.3",
35
+ "oxlint": "1.50.0",
36
+ "oxfmt": "0.35.0"
30
37
  }
31
38
  },
32
39
  "lefthook": {
@@ -39,7 +46,7 @@
39
46
  }
40
47
  ],
41
48
  "devDependencies": {
42
- "@outfitter/tooling": "^0.3.3",
49
+ "@outfitter/tooling": "^0.3.4",
43
50
  "lefthook": "^2.1.1",
44
51
  "ultracite": "7.2.3"
45
52
  }
@@ -50,7 +57,7 @@
50
57
  "files": [
51
58
  {
52
59
  "path": ".markdownlint-cli2.jsonc",
53
- "content": "{\n\t// Outfitter markdownlint preset\n\t// https://github.com/DavidAnson/markdownlint\n\n\t\"config\": {\n\t\t// Headings\n\t\t\"MD003\": { \"style\": \"atx\" }, // ATX-style headings (# Heading)\n\t\t\"MD022\": { \"lines_above\": 1, \"lines_below\": 1 }, // Blank lines around headings\n\t\t\"MD024\": { \"siblings_only\": true }, // Allow duplicate headings in different sections\n\t\t\"MD041\": false, // First line doesn't need to be h1 (frontmatter, etc.)\n\n\t\t// Line length - disabled for prose flexibility\n\t\t\"MD013\": false,\n\n\t\t// Lists\n\t\t\"MD004\": { \"style\": \"dash\" }, // Unordered list style: dash (-)\n\t\t\"MD007\": { \"indent\": 2 }, // List indentation: 2 spaces\n\t\t\"MD032\": true, // Blank lines around lists\n\n\t\t// Code blocks\n\t\t\"MD040\": true, // Fenced code blocks should have a language\n\t\t\"MD046\": { \"style\": \"fenced\" }, // Code block style: fenced (```)\n\t\t\"MD048\": { \"style\": \"backtick\" }, // Code fence style: backticks\n\n\t\t// Links\n\t\t\"MD034\": true, // No bare URLs (use <url> or [text](url))\n\n\t\t// Whitespace\n\t\t\"MD009\": { \"br_spaces\": 2 }, // Allow 2 trailing spaces for <br>\n\t\t\"MD010\": { \"spaces_per_tab\": 2 }, // Tabs to spaces\n\t\t\"MD012\": { \"maximum\": 1 }, // Max 1 consecutive blank line\n\t\t\"MD047\": true, // Files should end with newline\n\n\t\t// HTML - allow for GitHub-specific elements\n\t\t\"MD033\": {\n\t\t\t\"allowed_elements\": [\n\t\t\t\t\"details\",\n\t\t\t\t\"summary\",\n\t\t\t\t\"kbd\",\n\t\t\t\t\"br\",\n\t\t\t\t\"sup\",\n\t\t\t\t\"sub\",\n\t\t\t\t\"img\",\n\t\t\t\t\"picture\",\n\t\t\t\t\"source\",\n\t\t\t\t\"a\"\n\t\t\t]\n\t\t},\n\n\t\t// Emphasis\n\t\t\"MD049\": { \"style\": \"asterisk\" }, // Emphasis style: *italic*\n\t\t\"MD050\": { \"style\": \"asterisk\" } // Strong style: **bold**\n\t},\n\n\t// Ignore patterns\n\t\"ignores\": [\n\t\t\"node_modules/**\",\n\t\t\"**/node_modules/**\",\n\t\t\"dist/**\",\n\t\t\"**/dist/**\",\n\t\t\".turbo/**\",\n\t\t\"**/.turbo/**\",\n\t\t\"CHANGELOG.md\",\n\t\t\"**/CHANGELOG.md\"\n\t]\n}\n"
60
+ "content": "{\n // Outfitter markdownlint preset\n // https://github.com/DavidAnson/markdownlint\n\n \"config\": {\n // Headings\n \"MD003\": { \"style\": \"atx\" }, // ATX-style headings (# Heading)\n \"MD022\": { \"lines_above\": 1, \"lines_below\": 1 }, // Blank lines around headings\n \"MD024\": { \"siblings_only\": true }, // Allow duplicate headings in different sections\n \"MD041\": false, // First line doesn't need to be h1 (frontmatter, etc.)\n\n // Line length - disabled for prose flexibility\n \"MD013\": false,\n\n // Lists\n \"MD004\": { \"style\": \"dash\" }, // Unordered list style: dash (-)\n \"MD007\": { \"indent\": 2 }, // List indentation: 2 spaces\n \"MD032\": true, // Blank lines around lists\n\n // Code blocks\n \"MD040\": true, // Fenced code blocks should have a language\n \"MD046\": { \"style\": \"fenced\" }, // Code block style: fenced (```)\n \"MD048\": { \"style\": \"backtick\" }, // Code fence style: backticks\n\n // Links\n \"MD034\": true, // No bare URLs (use <url> or [text](url))\n\n // Whitespace\n \"MD009\": { \"br_spaces\": 2 }, // Allow 2 trailing spaces for <br>\n \"MD010\": { \"spaces_per_tab\": 2 }, // Tabs to spaces\n \"MD012\": { \"maximum\": 1 }, // Max 1 consecutive blank line\n \"MD047\": true, // Files should end with newline\n\n // HTML - allow for GitHub-specific elements\n \"MD033\": {\n \"allowed_elements\": [\n \"details\",\n \"summary\",\n \"kbd\",\n \"br\",\n \"sup\",\n \"sub\",\n \"img\",\n \"picture\",\n \"source\",\n \"a\",\n ],\n },\n\n // Emphasis\n \"MD049\": { \"style\": \"asterisk\" }, // Emphasis style: *italic*\n \"MD050\": { \"style\": \"asterisk\" }, // Strong style: **bold**\n },\n\n // Ignore patterns\n \"ignores\": [\n \"node_modules/**\",\n \"**/node_modules/**\",\n \"dist/**\",\n \"**/dist/**\",\n \".turbo/**\",\n \"**/.turbo/**\",\n \"CHANGELOG.md\",\n \"**/CHANGELOG.md\",\n ],\n}\n"
54
61
  }
55
62
  ]
56
63
  },
@@ -67,10 +74,10 @@
67
74
  },
68
75
  "scaffolding": {
69
76
  "name": "scaffolding",
70
- "description": "Full starter kit: Claude settings, Biome, Lefthook, markdownlint, and bootstrap script",
77
+ "description": "Full starter kit: Claude settings, oxlint/oxfmt, Lefthook, markdownlint, and bootstrap script",
71
78
  "extends": [
72
79
  "claude",
73
- "biome",
80
+ "linter",
74
81
  "lefthook",
75
82
  "markdownlint",
76
83
  "bootstrap"
@@ -1,7 +1,7 @@
1
1
  {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "extends": "./tsconfig.preset.json",
4
- "compilerOptions": {
5
- "types": ["@types/bun"]
6
- }
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "./tsconfig.preset.json",
4
+ "compilerOptions": {
5
+ "types": ["@types/bun"]
6
+ }
7
7
  }
@@ -1,40 +1,40 @@
1
1
  {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "compilerOptions": {
4
- "target": "ESNext",
5
- "module": "ESNext",
6
- "moduleResolution": "bundler",
7
- "lib": ["ESNext"],
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "lib": ["ESNext"],
8
8
 
9
- "strict": true,
10
- "noImplicitAny": true,
11
- "strictNullChecks": true,
12
- "strictFunctionTypes": true,
13
- "strictBindCallApply": true,
14
- "strictPropertyInitialization": true,
15
- "noImplicitThis": true,
16
- "useUnknownInCatchVariables": true,
17
- "alwaysStrict": true,
9
+ "strict": true,
10
+ "noImplicitAny": true,
11
+ "strictNullChecks": true,
12
+ "strictFunctionTypes": true,
13
+ "strictBindCallApply": true,
14
+ "strictPropertyInitialization": true,
15
+ "noImplicitThis": true,
16
+ "useUnknownInCatchVariables": true,
17
+ "alwaysStrict": true,
18
18
 
19
- "noUncheckedIndexedAccess": true,
20
- "noImplicitReturns": true,
21
- "noFallthroughCasesInSwitch": true,
22
- "noUnusedLocals": true,
23
- "noUnusedParameters": true,
24
- "exactOptionalPropertyTypes": true,
25
- "noPropertyAccessFromIndexSignature": true,
19
+ "noUncheckedIndexedAccess": true,
20
+ "noImplicitReturns": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+ "noUnusedLocals": true,
23
+ "noUnusedParameters": true,
24
+ "exactOptionalPropertyTypes": true,
25
+ "noPropertyAccessFromIndexSignature": true,
26
26
 
27
- "declaration": true,
28
- "declarationMap": true,
29
- "sourceMap": true,
27
+ "declaration": true,
28
+ "declarationMap": true,
29
+ "sourceMap": true,
30
30
 
31
- "esModuleInterop": true,
32
- "forceConsistentCasingInFileNames": true,
33
- "isolatedModules": true,
34
- "verbatimModuleSyntax": true,
35
- "skipLibCheck": true,
31
+ "esModuleInterop": true,
32
+ "forceConsistentCasingInFileNames": true,
33
+ "isolatedModules": true,
34
+ "verbatimModuleSyntax": true,
35
+ "skipLibCheck": true,
36
36
 
37
- "resolveJsonModule": true,
38
- "allowSyntheticDefaultImports": true
39
- }
37
+ "resolveJsonModule": true,
38
+ "allowSyntheticDefaultImports": true
39
+ }
40
40
  }