@outfitter/tooling 0.3.0 → 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 (53) 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.js +2 -2
  6. package/dist/cli/check-bunup-registry.js +2 -2
  7. package/dist/cli/check-changeset.js +2 -2
  8. package/dist/cli/check-clean-tree.js +2 -2
  9. package/dist/cli/check-exports.js +2 -2
  10. package/dist/cli/check-markdown-links.d.ts +42 -0
  11. package/dist/cli/check-markdown-links.js +13 -0
  12. package/dist/cli/check-readme-imports.d.ts +2 -3
  13. package/dist/cli/check-readme-imports.js +4 -4
  14. package/dist/cli/check-tsdoc.js +2 -2
  15. package/dist/cli/check.js +2 -2
  16. package/dist/cli/fix.js +2 -2
  17. package/dist/cli/index.js +49 -1221
  18. package/dist/cli/init.js +2 -2
  19. package/dist/cli/pre-push.d.ts +13 -1
  20. package/dist/cli/pre-push.js +5 -3
  21. package/dist/cli/upgrade-bun.js +3 -2
  22. package/dist/index.d.ts +6 -186
  23. package/dist/index.js +4 -42
  24. package/dist/registry/build.d.ts +1 -3
  25. package/dist/registry/build.js +187 -58
  26. package/dist/registry/index.js +1 -13
  27. package/dist/registry/schema.js +22 -6
  28. package/dist/shared/@outfitter/{tooling-9errkcvk.js → tooling-1hez6j9d.js} +1 -1
  29. package/dist/shared/@outfitter/{tooling-cj5vsa9k.js → tooling-6cxfdx0q.js} +21 -18
  30. package/dist/shared/@outfitter/{tooling-qk5xgmxr.js → tooling-875svjnz.js} +5 -4
  31. package/dist/shared/@outfitter/{tooling-mxwc1n8w.js → tooling-9ram55dd.js} +4 -3
  32. package/dist/shared/@outfitter/{tooling-0x5q15ec.js → tooling-a4bfx4be.js} +1 -1
  33. package/dist/shared/@outfitter/{tooling-r9976n43.js → tooling-amrbp7cm.js} +6 -4
  34. package/dist/shared/@outfitter/{tooling-2n2dpsaa.js → tooling-d363b88r.js} +38 -12
  35. package/dist/shared/@outfitter/{tooling-1y8w5ahg.js → tooling-gcdvsqqp.js} +7 -4
  36. package/dist/shared/@outfitter/{tooling-enjcenja.js → tooling-h04te11c.js} +6 -4
  37. package/dist/shared/@outfitter/tooling-ja1zg5yc.js +214 -0
  38. package/dist/shared/@outfitter/tooling-mkynjra9.js +23 -0
  39. package/dist/shared/@outfitter/{tooling-9yzd08v1.js → tooling-pq47jv6t.js} +72 -5
  40. package/dist/shared/@outfitter/tooling-vjmhvpjq.d.ts +29 -0
  41. package/dist/shared/@outfitter/{tooling-t17gnh9b.js → tooling-wwm97f47.js} +8 -5
  42. package/dist/version.js +1 -1
  43. package/package.json +134 -130
  44. package/registry/registry.json +18 -11
  45. package/tsconfig.preset.bun.json +5 -5
  46. package/tsconfig.preset.json +33 -33
  47. package/biome.json +0 -81
  48. package/dist/shared/@outfitter/tooling-kcvs6mys.js +0 -1
  49. package/dist/shared/@outfitter/tooling-wv09k6hr.js +0 -23
  50. package/dist/shared/chunk-3s189drz.js +0 -4
  51. package/dist/shared/chunk-7tdgbqb0.js +0 -197
  52. package/dist/shared/chunk-cmde0fwx.js +0 -421
  53. /package/dist/shared/@outfitter/{tooling-dvwh9qve.js → tooling-jnrs9rqd.js} +0 -0
@@ -1,4 +1,9 @@
1
1
  // @bun
2
+ import {
3
+ isTypesBunVersionCompatible,
4
+ parseSemver
5
+ } from "./tooling-mkynjra9.js";
6
+
2
7
  // packages/tooling/src/cli/upgrade-bun.ts
3
8
  import { existsSync, readFileSync, writeFileSync } from "fs";
4
9
  import { join } from "path";
@@ -34,15 +39,61 @@ async function fetchLatestVersion() {
34
39
  }
35
40
  return match[1];
36
41
  }
42
+ async function resolveTypesBunVersion(targetVersion) {
43
+ const response = await fetch("https://registry.npmjs.org/@types%2fbun");
44
+ if (!response.ok) {
45
+ throw new Error(`Failed to fetch @types/bun metadata: ${response.status}`);
46
+ }
47
+ const data = await response.json();
48
+ if (data.versions && Object.hasOwn(data.versions, targetVersion)) {
49
+ return targetVersion;
50
+ }
51
+ if (data.versions) {
52
+ const compatible = Object.keys(data.versions).filter((candidate) => isTypesBunVersionCompatible(targetVersion, candidate)).map((candidate) => ({
53
+ version: candidate,
54
+ parsed: parseSemver(candidate)
55
+ })).filter((candidate) => !!candidate.parsed).toSorted((left, right) => right.parsed.patch - left.parsed.patch);
56
+ const preferred = compatible[0];
57
+ if (preferred) {
58
+ return preferred.version;
59
+ }
60
+ }
61
+ const latest = data["dist-tags"]?.latest;
62
+ if (latest && isTypesBunVersionCompatible(targetVersion, latest)) {
63
+ return latest;
64
+ }
65
+ return targetVersion;
66
+ }
37
67
  function findPackageJsonFiles(dir) {
38
- const results = [];
68
+ const files = new Set;
39
69
  const glob = new Bun.Glob("**/package.json");
40
70
  for (const path of glob.scanSync({ cwd: dir })) {
41
71
  if (!path.includes("node_modules")) {
42
- results.push(join(dir, path));
72
+ files.add(join(dir, path));
73
+ }
74
+ }
75
+ const gitList = Bun.spawnSync(["git", "ls-files", "--cached", "--others", "--exclude-standard"], { cwd: dir });
76
+ if (gitList.exitCode === 0) {
77
+ const trackedAndUntrackedFiles = new TextDecoder().decode(gitList.stdout).split(`
78
+ `).filter((path) => path.endsWith("package.json")).filter((path) => !path.includes("node_modules")).map((path) => join(dir, path)).filter((path) => existsSync(path));
79
+ for (const filePath of trackedAndUntrackedFiles) {
80
+ files.add(filePath);
43
81
  }
44
82
  }
45
- return results;
83
+ return [...files].toSorted();
84
+ }
85
+ function updatePackageManager(filePath, version) {
86
+ const content = readFileSync(filePath, "utf-8");
87
+ const pattern = /"packageManager":\s*"bun@[\d.]+"/;
88
+ if (!pattern.test(content)) {
89
+ return false;
90
+ }
91
+ const updated = content.replace(pattern, `"packageManager": "bun@${version}"`);
92
+ if (updated !== content) {
93
+ writeFileSync(filePath, updated);
94
+ return true;
95
+ }
96
+ return false;
46
97
  }
47
98
  function updateEnginesBun(filePath, version) {
48
99
  const content = readFileSync(filePath, "utf-8");
@@ -88,10 +139,26 @@ async function runUpgradeBun(targetVersion, options = {}) {
88
139
  log("");
89
140
  info(`Upgrading Bun: ${currentVersion} \u2192 ${version}`);
90
141
  log("");
142
+ let typesVersion = version;
143
+ try {
144
+ info("Resolving @types/bun version...");
145
+ typesVersion = await resolveTypesBunVersion(version);
146
+ if (typesVersion !== version) {
147
+ warn(`@types/bun ${version} is not published yet; using @types/bun ${typesVersion}`);
148
+ }
149
+ } catch (error) {
150
+ warn(`Could not resolve @types/bun metadata (${error instanceof Error ? error.message : "unknown error"}), defaulting to ${version}`);
151
+ }
91
152
  writeFileSync(bunVersionFile, `${version}
92
153
  `);
93
154
  success("Updated .bun-version");
94
155
  const packageFiles = findPackageJsonFiles(cwd);
156
+ info("Updating packageManager...");
157
+ for (const file of packageFiles) {
158
+ if (updatePackageManager(file, version)) {
159
+ log(` ${file.replace(`${cwd}/`, "")}`);
160
+ }
161
+ }
95
162
  info("Updating engines.bun...");
96
163
  for (const file of packageFiles) {
97
164
  if (updateEnginesBun(file, version)) {
@@ -100,7 +167,7 @@ async function runUpgradeBun(targetVersion, options = {}) {
100
167
  }
101
168
  info("Updating @types/bun...");
102
169
  for (const file of packageFiles) {
103
- if (updateTypesBun(file, version)) {
170
+ if (updateTypesBun(file, typesVersion)) {
104
171
  log(` ${file.replace(`${cwd}/`, "")}`);
105
172
  }
106
173
  }
@@ -137,7 +204,7 @@ async function runUpgradeBun(targetVersion, options = {}) {
137
204
  log("");
138
205
  success("Done! Changes ready to commit:");
139
206
  log(" - .bun-version");
140
- log(" - package.json files (engines.bun, @types/bun)");
207
+ log(" - package.json files (packageManager, engines.bun, @types/bun)");
141
208
  log(" - bun.lock");
142
209
  log("");
143
210
  log(`Commit with: git add -A && git commit -m 'chore: upgrade Bun to ${version}'`);
@@ -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 };
@@ -7,7 +7,7 @@ function extractBunupFilterName(script) {
7
7
  }
8
8
  function findUnregisteredPackages(packagesWithFilter, registeredNames) {
9
9
  const registered = new Set(registeredNames);
10
- const missing = packagesWithFilter.filter((name) => !registered.has(name)).sort();
10
+ const missing = packagesWithFilter.filter((name) => !registered.has(name)).toSorted();
11
11
  return {
12
12
  ok: missing.length === 0,
13
13
  missing
@@ -31,13 +31,15 @@ async function runCheckBunupRegistry() {
31
31
  if (!Array.isArray(rawConfig)) {
32
32
  process.stderr.write(`bunup.config.ts must export a workspace array
33
33
  `);
34
- process.exit(1);
34
+ process.exitCode = 1;
35
+ return;
35
36
  }
36
37
  registeredNames = rawConfig.map((entry) => entry.name);
37
38
  } catch {
38
39
  process.stderr.write(`Could not load bunup.config.ts from ${cwd}
39
40
  `);
40
- process.exit(1);
41
+ process.exitCode = 1;
42
+ return;
41
43
  }
42
44
  const packagesWithFilter = [];
43
45
  const glob = new Bun.Glob("{packages,apps}/*/package.json");
@@ -58,7 +60,8 @@ async function runCheckBunupRegistry() {
58
60
  if (result.ok) {
59
61
  process.stdout.write(`${COLORS.green}All ${packagesWithFilter.length} packages with bunup --filter are registered in bunup.config.ts.${COLORS.reset}
60
62
  `);
61
- process.exit(0);
63
+ process.exitCode = 0;
64
+ return;
62
65
  }
63
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}
64
67
 
@@ -72,7 +75,7 @@ Add the missing entries to ${COLORS.blue}bunup.config.ts${COLORS.reset} defineWo
72
75
  `);
73
76
  process.stderr.write(`Without registration, ${COLORS.dim}bunup --filter <name>${COLORS.reset} silently exits with no output.
74
77
  `);
75
- process.exit(1);
78
+ process.exitCode = 1;
76
79
  }
77
80
 
78
81
  export { extractBunupFilterName, findUnregisteredPackages, runCheckBunupRegistry };
package/dist/version.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  VERSION
4
4
  } from "./shared/@outfitter/tooling-ctmgnap5.js";
5
- import"./shared/@outfitter/tooling-dvwh9qve.js";
5
+ import"./shared/@outfitter/tooling-jnrs9rqd.js";
6
6
  export {
7
7
  VERSION
8
8
  };
package/package.json CHANGED
@@ -1,132 +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.0",
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 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
- "@types/bun": "^1.3.9",
92
- "yaml": "^2.8.2"
93
- },
94
- "peerDependencies": {
95
- "ultracite": "^7.0.0",
96
- "lefthook": "^2.0.0",
97
- "markdownlint-cli2": ">=0.17.0"
98
- },
99
- "peerDependenciesMeta": {
100
- "ultracite": {
101
- "optional": true
102
- },
103
- "lefthook": {
104
- "optional": true
105
- },
106
- "markdownlint-cli2": {
107
- "optional": true
108
- }
109
- },
110
- "engines": {
111
- "bun": ">=1.3.9"
112
- },
113
- "keywords": [
114
- "outfitter",
115
- "tooling",
116
- "biome",
117
- "typescript",
118
- "lefthook",
119
- "markdownlint",
120
- "config",
121
- "presets"
122
- ],
123
- "license": "MIT",
124
- "repository": {
125
- "type": "git",
126
- "url": "https://github.com/outfitter-dev/outfitter.git",
127
- "directory": "packages/tooling"
128
- },
129
- "publishConfig": {
130
- "access": "public"
131
- }
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
+ }
132
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,9 +46,9 @@
39
46
  }
40
47
  ],
41
48
  "devDependencies": {
42
- "@outfitter/tooling": "^0.2.4",
49
+ "@outfitter/tooling": "^0.3.4",
43
50
  "lefthook": "^2.1.1",
44
- "ultracite": "^7.2.3"
51
+ "ultracite": "7.2.3"
45
52
  }
46
53
  },
47
54
  "markdownlint": {
@@ -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
  }