@outfitter/presets 0.2.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.
Files changed (71) hide show
  1. package/dist/index.d.ts +43 -0
  2. package/dist/index.js +118 -0
  3. package/package.json +63 -0
  4. package/presets/.gitkeep +0 -0
  5. package/presets/basic/.gitignore.template +30 -0
  6. package/presets/basic/.lefthook.yml.template +26 -0
  7. package/presets/basic/package.json.template +39 -0
  8. package/presets/basic/src/index.ts.template +26 -0
  9. package/presets/basic/tsconfig.json.template +34 -0
  10. package/presets/cli/.gitignore.template +4 -0
  11. package/presets/cli/.lefthook.yml.template +26 -0
  12. package/presets/cli/README.md.template +35 -0
  13. package/presets/cli/biome.json.template +4 -0
  14. package/presets/cli/package.json.template +46 -0
  15. package/presets/cli/src/cli.ts.template +8 -0
  16. package/presets/cli/src/index.ts.template +7 -0
  17. package/presets/cli/src/program.ts.template +31 -0
  18. package/presets/cli/tsconfig.json.template +34 -0
  19. package/presets/daemon/.gitignore.template +4 -0
  20. package/presets/daemon/.lefthook.yml.template +26 -0
  21. package/presets/daemon/README.md.template +67 -0
  22. package/presets/daemon/biome.json.template +4 -0
  23. package/presets/daemon/package.json.template +49 -0
  24. package/presets/daemon/src/cli.ts.template +96 -0
  25. package/presets/daemon/src/daemon-main.ts.template +79 -0
  26. package/presets/daemon/src/daemon.ts.template +11 -0
  27. package/presets/daemon/src/index.ts.template +7 -0
  28. package/presets/daemon/tsconfig.json.template +23 -0
  29. package/presets/full-stack/.gitignore.template +30 -0
  30. package/presets/full-stack/README.md.template +30 -0
  31. package/presets/full-stack/apps/cli/package.json.template +35 -0
  32. package/presets/full-stack/apps/cli/src/cli.ts.template +24 -0
  33. package/presets/full-stack/apps/cli/src/index.test.ts.template +18 -0
  34. package/presets/full-stack/apps/cli/src/index.ts.template +5 -0
  35. package/presets/full-stack/apps/cli/tsconfig.json.template +37 -0
  36. package/presets/full-stack/apps/mcp/package.json.template +36 -0
  37. package/presets/full-stack/apps/mcp/src/index.test.ts.template +18 -0
  38. package/presets/full-stack/apps/mcp/src/index.ts.template +6 -0
  39. package/presets/full-stack/apps/mcp/src/mcp.ts.template +22 -0
  40. package/presets/full-stack/apps/mcp/src/server.ts.template +10 -0
  41. package/presets/full-stack/apps/mcp/tsconfig.json.template +37 -0
  42. package/presets/full-stack/package.json.template +16 -0
  43. package/presets/full-stack/packages/core/package.json.template +32 -0
  44. package/presets/full-stack/packages/core/src/handlers.ts.template +31 -0
  45. package/presets/full-stack/packages/core/src/index.test.ts.template +30 -0
  46. package/presets/full-stack/packages/core/src/index.ts.template +8 -0
  47. package/presets/full-stack/packages/core/src/types.ts.template +13 -0
  48. package/presets/full-stack/packages/core/tsconfig.json.template +34 -0
  49. package/presets/library/.gitignore.template +30 -0
  50. package/presets/library/README.md.template +29 -0
  51. package/presets/library/bunup.config.ts.template +20 -0
  52. package/presets/library/package.json.template +52 -0
  53. package/presets/library/src/handlers.ts.template +31 -0
  54. package/presets/library/src/index.test.ts.template +35 -0
  55. package/presets/library/src/index.ts.template +8 -0
  56. package/presets/library/src/types.ts.template +13 -0
  57. package/presets/library/tsconfig.json.template +34 -0
  58. package/presets/mcp/.gitignore.template +4 -0
  59. package/presets/mcp/.lefthook.yml.template +26 -0
  60. package/presets/mcp/README.md.template +54 -0
  61. package/presets/mcp/biome.json.template +4 -0
  62. package/presets/mcp/package.json.template +46 -0
  63. package/presets/mcp/src/index.ts.template +7 -0
  64. package/presets/mcp/src/mcp.ts.template +33 -0
  65. package/presets/mcp/src/server.ts.template +8 -0
  66. package/presets/mcp/tsconfig.json.template +23 -0
  67. package/presets/minimal/.gitignore.template +30 -0
  68. package/presets/minimal/.lefthook.yml.template +26 -0
  69. package/presets/minimal/package.json.template +46 -0
  70. package/presets/minimal/src/index.ts.template +26 -0
  71. package/presets/minimal/tsconfig.json.template +34 -0
@@ -0,0 +1,43 @@
1
+ interface ResolvedVersions {
2
+ /** All dependency versions from the presets package (catalog-resolved at publish time). */
3
+ readonly all: Readonly<Record<string, string>>;
4
+ }
5
+ interface PresetInfo {
6
+ /** The preset name (directory name). */
7
+ readonly name: string;
8
+ /** Absolute path to the preset directory. */
9
+ readonly path: string;
10
+ }
11
+ /**
12
+ * Get the absolute path to the presets directory.
13
+ * Works both in the monorepo (source) and when published to npm (dist/).
14
+ */
15
+ declare function getPresetsDir(): string;
16
+ /**
17
+ * List all available presets.
18
+ */
19
+ declare function listPresets(): readonly PresetInfo[];
20
+ /**
21
+ * Get the absolute path to a specific preset directory.
22
+ * Returns undefined if the preset does not exist.
23
+ */
24
+ declare function getPresetPath(presetName: string): string | undefined;
25
+ /**
26
+ * Read resolved dependency versions from the presets package's own package.json.
27
+ *
28
+ * When published to npm, `catalog:` is replaced with concrete semver ranges,
29
+ * so versions are read directly. In the monorepo, `catalog:` references are
30
+ * resolved by reading the workspace root's catalog field.
31
+ *
32
+ * @returns Resolved versions for all declared dependencies.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * import { getResolvedVersions } from "@outfitter/presets";
37
+ *
38
+ * const { all } = getResolvedVersions();
39
+ * console.log(all["zod"]); // "^4.3.5"
40
+ * ```
41
+ */
42
+ declare function getResolvedVersions(): ResolvedVersions;
43
+ export { listPresets, getResolvedVersions, getPresetsDir, getPresetPath, ResolvedVersions, PresetInfo };
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ // @bun
2
+ // packages/presets/src/index.ts
3
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
4
+ import { dirname, isAbsolute, join, relative, resolve } from "path";
5
+ import { fileURLToPath } from "url";
6
+ var DEPENDENCY_SECTIONS = [
7
+ "dependencies",
8
+ "devDependencies",
9
+ "peerDependencies",
10
+ "optionalDependencies"
11
+ ];
12
+ function getPresetsDir() {
13
+ const thisFile = dirname(fileURLToPath(import.meta.url));
14
+ const presetsDir = join(thisFile, "..", "presets");
15
+ if (existsSync(presetsDir)) {
16
+ return presetsDir;
17
+ }
18
+ throw new Error(`Presets directory not found at ${presetsDir}. Ensure @outfitter/presets is properly installed.`);
19
+ }
20
+ function listPresets() {
21
+ const presetsDir = getPresetsDir();
22
+ return readdirSync(presetsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => ({
23
+ name: entry.name,
24
+ path: join(presetsDir, entry.name)
25
+ })).sort((a, b) => a.name.localeCompare(b.name));
26
+ }
27
+ function getPresetPath(presetName) {
28
+ const presetsDir = getPresetsDir();
29
+ const presetDir = resolve(presetsDir, presetName);
30
+ const relativePath = relative(presetsDir, presetDir);
31
+ if (relativePath.length === 0 || relativePath.startsWith("..") || isAbsolute(relativePath)) {
32
+ return;
33
+ }
34
+ if (!existsSync(presetDir)) {
35
+ return;
36
+ }
37
+ return statSync(presetDir).isDirectory() ? presetDir : undefined;
38
+ }
39
+ function isRecord(value) {
40
+ return typeof value === "object" && value !== null && !Array.isArray(value);
41
+ }
42
+ function loadWorkspaceCatalog(packageDir) {
43
+ let dir = packageDir;
44
+ for (let i = 0;i < 10; i++) {
45
+ const rootPkgPath = join(dir, "package.json");
46
+ if (existsSync(rootPkgPath)) {
47
+ try {
48
+ const raw = JSON.parse(readFileSync(rootPkgPath, "utf-8"));
49
+ if (isRecord(raw) && isRecord(raw["catalog"])) {
50
+ const catalog = {};
51
+ for (const [name, version] of Object.entries(raw["catalog"])) {
52
+ if (typeof version === "string") {
53
+ catalog[name] = version;
54
+ }
55
+ }
56
+ return catalog;
57
+ }
58
+ } catch {}
59
+ }
60
+ const parent = dirname(dir);
61
+ if (parent === dir)
62
+ break;
63
+ dir = parent;
64
+ }
65
+ return {};
66
+ }
67
+ function getResolvedVersions() {
68
+ const packageDir = join(dirname(fileURLToPath(import.meta.url)), "..");
69
+ const packageJsonPath = join(packageDir, "package.json");
70
+ const raw = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
71
+ if (!isRecord(raw)) {
72
+ throw new Error("@outfitter/presets package.json must be a JSON object");
73
+ }
74
+ const all = {};
75
+ let hasCatalogRefs = false;
76
+ for (const section of DEPENDENCY_SECTIONS) {
77
+ const deps = raw[section];
78
+ if (!isRecord(deps))
79
+ continue;
80
+ for (const [name, version] of Object.entries(deps)) {
81
+ if (typeof version === "string") {
82
+ if (version === "catalog:") {
83
+ hasCatalogRefs = true;
84
+ } else {
85
+ all[name] = version;
86
+ }
87
+ }
88
+ }
89
+ }
90
+ if (hasCatalogRefs) {
91
+ const catalog = loadWorkspaceCatalog(packageDir);
92
+ const unresolved = [];
93
+ for (const section of DEPENDENCY_SECTIONS) {
94
+ const deps = raw[section];
95
+ if (!isRecord(deps))
96
+ continue;
97
+ for (const [name, version] of Object.entries(deps)) {
98
+ if (version === "catalog:") {
99
+ if (catalog[name]) {
100
+ all[name] = catalog[name];
101
+ } else {
102
+ unresolved.push(name);
103
+ }
104
+ }
105
+ }
106
+ }
107
+ if (unresolved.length > 0) {
108
+ throw new Error(`Unresolvable catalog: references (no catalog entry found): ${unresolved.join(", ")}`);
109
+ }
110
+ }
111
+ return { all };
112
+ }
113
+ export {
114
+ listPresets,
115
+ getResolvedVersions,
116
+ getPresetsDir,
117
+ getPresetPath
118
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@outfitter/presets",
3
+ "description": "Scaffold presets and shared dependency versions for Outfitter projects",
4
+ "version": "0.2.0",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "presets"
9
+ ],
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "dependencies": {
22
+ "@biomejs/biome": "2.4.4",
23
+ "@clack/prompts": "^1.0.1",
24
+ "@logtape/logtape": "^2.0.0",
25
+ "@modelcontextprotocol/sdk": "^1.12.1",
26
+ "@types/node": "^25.3.0",
27
+ "better-result": "^2.5.1",
28
+ "bunup": "^0.16.29",
29
+ "commander": "^14.0.2",
30
+ "lefthook": "^2.1.1",
31
+ "smol-toml": "^1.6.0",
32
+ "ultracite": "7.2.3",
33
+ "yaml": "^2.8.2",
34
+ "zod": "^4.3.5"
35
+ },
36
+ "devDependencies": {
37
+ "@types/bun": "^1.3.9",
38
+ "typescript": "^5.9.3"
39
+ },
40
+ "engines": {
41
+ "bun": ">=1.3.9"
42
+ },
43
+ "keywords": [
44
+ "outfitter",
45
+ "presets",
46
+ "scaffolding",
47
+ "templates",
48
+ "versions"
49
+ ],
50
+ "license": "MIT",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/outfitter-dev/stack.git",
54
+ "directory": "packages/presets"
55
+ },
56
+ "scripts": {
57
+ "build": "cd ../.. && bunup --filter @outfitter/presets",
58
+ "clean": "rm -rf dist .turbo",
59
+ "test": "bun test",
60
+ "typecheck": "tsc --noEmit",
61
+ "prepublishOnly": "bun ../../scripts/check-publish-manifest.ts"
62
+ }
63
+ }
File without changes
@@ -0,0 +1,30 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # IDE
8
+ .idea/
9
+ .vscode/
10
+ *.swp
11
+ *.swo
12
+
13
+ # OS
14
+ .DS_Store
15
+ Thumbs.db
16
+
17
+ # Logs
18
+ *.log
19
+ npm-debug.log*
20
+
21
+ # Environment
22
+ .env
23
+ .env.local
24
+ .env.*.local
25
+
26
+ # Test coverage
27
+ coverage/
28
+
29
+ # Bun
30
+ bun.lockb
@@ -0,0 +1,26 @@
1
+ # Lefthook configuration
2
+ # https://github.com/evilmartians/lefthook
3
+
4
+ pre-commit:
5
+ parallel: true
6
+ commands:
7
+ format:
8
+ glob: "*.{js,ts,tsx,json,md}"
9
+ run: bunx biome format --no-errors-on-unmatched {staged_files}
10
+ stage_fixed: true
11
+
12
+ lint:
13
+ glob: "*.{js,ts,tsx}"
14
+ run: bunx biome lint --no-errors-on-unmatched {staged_files}
15
+
16
+ typecheck:
17
+ glob: "*.{ts,tsx}"
18
+ run: bun run typecheck
19
+
20
+ pre-push:
21
+ parallel: false
22
+ commands:
23
+ verify:
24
+ # TDD-aware strict verification with RED-phase branch carveout
25
+ # (*-tests, */tests, *_tests).
26
+ run: bunx @outfitter/tooling pre-push
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "version": "{{version}}",
4
+ "description": "{{description}}",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "bun build ./src/index.ts --outdir=dist --format=esm",
21
+ "dev": "bun run --watch src/index.ts",
22
+ "test": "bun test",
23
+ "test:watch": "bun test --watch",
24
+ "typecheck": "tsc --noEmit",
25
+ "check": "ultracite check",
26
+ "verify:ci": "bun run typecheck && bun run check && bun run build && bun run test",
27
+ "lint": "biome check .",
28
+ "lint:fix": "biome check . --write",
29
+ "format": "biome format --write .",
30
+ "clean:artifacts": "rm -rf dist .turbo",
31
+ "clean": "rm -rf dist"
32
+ },
33
+ "devDependencies": {},
34
+ "engines": {
35
+ "bun": ">=1.3.9"
36
+ },
37
+ "keywords": [],
38
+ "license": "MIT"
39
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * {{projectName}}
3
+ *
4
+ * {{description}}
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ /**
10
+ * Main entry point for {{projectName}}.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { main } from "{{packageName}}";
15
+ *
16
+ * main();
17
+ * ```
18
+ */
19
+ export function main(): void {
20
+ console.log("Hello from {{projectName}}!");
21
+ }
22
+
23
+ // Run if executed directly
24
+ if (import.meta.main) {
25
+ main();
26
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "lib": ["ESNext"],
8
+ "types": ["@types/bun"],
9
+
10
+ "strict": true,
11
+ "noImplicitAny": true,
12
+ "strictNullChecks": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "exactOptionalPropertyTypes": true,
15
+ "noPropertyAccessFromIndexSignature": true,
16
+ "noImplicitReturns": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+
19
+ "declaration": true,
20
+ "declarationMap": true,
21
+ "sourceMap": true,
22
+ "outDir": "./dist",
23
+ "rootDir": "./src",
24
+
25
+ "esModuleInterop": true,
26
+ "forceConsistentCasingInFileNames": true,
27
+ "isolatedModules": true,
28
+ "verbatimModuleSyntax": true,
29
+ "skipLibCheck": true,
30
+ "resolveJsonModule": true
31
+ },
32
+ "include": ["src/**/*"],
33
+ "exclude": ["node_modules", "dist"]
34
+ }
@@ -0,0 +1,4 @@
1
+ node_modules/
2
+ dist/
3
+ *.log
4
+ .DS_Store
@@ -0,0 +1,26 @@
1
+ # Lefthook configuration
2
+ # https://github.com/evilmartians/lefthook
3
+
4
+ pre-commit:
5
+ parallel: true
6
+ commands:
7
+ format:
8
+ glob: "*.{js,ts,tsx,json,md}"
9
+ run: bunx biome format --no-errors-on-unmatched {staged_files}
10
+ stage_fixed: true
11
+
12
+ lint:
13
+ glob: "*.{js,ts,tsx}"
14
+ run: bunx biome lint --no-errors-on-unmatched {staged_files}
15
+
16
+ typecheck:
17
+ glob: "*.{ts,tsx}"
18
+ run: bun run typecheck
19
+
20
+ pre-push:
21
+ parallel: false
22
+ commands:
23
+ verify:
24
+ # TDD-aware strict verification with RED-phase branch carveout
25
+ # (*-tests, */tests, *_tests).
26
+ run: bunx @outfitter/tooling pre-push
@@ -0,0 +1,35 @@
1
+ # {{projectName}}
2
+
3
+ {{description}}
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add {{packageName}}
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ {{binName}} hello [name]
15
+ ```
16
+
17
+ ## Development
18
+
19
+ ```bash
20
+ # Install dependencies
21
+ bun install
22
+
23
+ # Run in development
24
+ bun run dev
25
+
26
+ # Build
27
+ bun run build
28
+
29
+ # Run tests
30
+ bun run test
31
+ ```
32
+
33
+ ## License
34
+
35
+ MIT
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.4/schema.json",
3
+ "extends": ["ultracite/config/biome/core/biome.jsonc"]
4
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "version": "{{version}}",
4
+ "description": "{{description}}",
5
+ "type": "module",
6
+ "bin": {
7
+ "{{binName}}": "./dist/cli.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "bun build src/cli.ts --outdir dist --target bun && bun build src/index.ts --outdir dist --target bun --sourcemap",
19
+ "dev": "bun --watch src/cli.ts",
20
+ "typecheck": "tsc --noEmit",
21
+ "check": "ultracite check",
22
+ "verify:ci": "bun run typecheck && bun run check && bun run build && bun run test",
23
+ "test": "bun test",
24
+ "test:watch": "bun test --watch",
25
+ "lint": "biome check .",
26
+ "lint:fix": "biome check . --write",
27
+ "format": "biome format --write .",
28
+ "clean:artifacts": "rm -rf dist .turbo"
29
+ },
30
+ "dependencies": {
31
+ "@outfitter/contracts": "workspace:*",
32
+ "@outfitter/types": "workspace:*",
33
+ "@outfitter/cli": "workspace:*",
34
+ "@outfitter/logging": "workspace:*",
35
+ "commander": "^14.0.2"
36
+ },
37
+ "devDependencies": {},
38
+ "outfitter": {
39
+ "template": {
40
+ "kind": "runnable",
41
+ "placement": "apps",
42
+ "surfaces": ["cli"]
43
+ }
44
+ },
45
+ "license": "MIT"
46
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * {{projectName}} CLI entry point
4
+ */
5
+
6
+ import { program } from "./program.js";
7
+
8
+ program.parse(process.argv);
@@ -0,0 +1,7 @@
1
+ /**
2
+ * {{projectName}} - Public API exports
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+
7
+ export { program } from "./program.js";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * {{projectName}} - CLI program definition
3
+ */
4
+
5
+ import { command, createCLI } from "@outfitter/cli/command";
6
+ import { verbosePreset } from "@outfitter/cli/flags";
7
+ import { createLogger } from "@outfitter/logging";
8
+
9
+ const logger = createLogger({ name: "{{binName}}" });
10
+
11
+ export const program = createCLI({
12
+ name: "{{binName}}",
13
+ version: "{{version}}",
14
+ description: "{{description}}",
15
+ });
16
+
17
+ const verbose = verbosePreset();
18
+
19
+ program.register(
20
+ command("hello [name]")
21
+ .description("Say hello")
22
+ .preset(verbose)
23
+ .action<{ verbose: boolean }>(async ({ args, flags }) => {
24
+ const { verbose: isVerbose } = verbose.resolve(flags);
25
+ const name = args[0] ?? "World";
26
+ logger.info(`Hello, ${name}!`);
27
+ if (isVerbose) {
28
+ logger.debug("Running in verbose mode");
29
+ }
30
+ }),
31
+ );
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "lib": ["ESNext"],
8
+ "types": ["@types/bun"],
9
+
10
+ "strict": true,
11
+ "noImplicitAny": true,
12
+ "strictNullChecks": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "exactOptionalPropertyTypes": true,
15
+ "noPropertyAccessFromIndexSignature": true,
16
+ "noImplicitReturns": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+
19
+ "declaration": true,
20
+ "declarationMap": true,
21
+ "sourceMap": true,
22
+ "outDir": "./dist",
23
+ "rootDir": "./src",
24
+
25
+ "esModuleInterop": true,
26
+ "forceConsistentCasingInFileNames": true,
27
+ "isolatedModules": true,
28
+ "verbatimModuleSyntax": true,
29
+ "skipLibCheck": true,
30
+ "resolveJsonModule": true
31
+ },
32
+ "include": ["src/**/*"],
33
+ "exclude": ["node_modules", "dist"]
34
+ }
@@ -0,0 +1,4 @@
1
+ node_modules/
2
+ dist/
3
+ *.log
4
+ .DS_Store
@@ -0,0 +1,26 @@
1
+ # Lefthook configuration
2
+ # https://github.com/evilmartians/lefthook
3
+
4
+ pre-commit:
5
+ parallel: true
6
+ commands:
7
+ format:
8
+ glob: "*.{js,ts,tsx,json,md}"
9
+ run: bunx biome format --no-errors-on-unmatched {staged_files}
10
+ stage_fixed: true
11
+
12
+ lint:
13
+ glob: "*.{js,ts,tsx}"
14
+ run: bunx biome lint --no-errors-on-unmatched {staged_files}
15
+
16
+ typecheck:
17
+ glob: "*.{ts,tsx}"
18
+ run: bun run typecheck
19
+
20
+ pre-push:
21
+ parallel: false
22
+ commands:
23
+ verify:
24
+ # TDD-aware strict verification with RED-phase branch carveout
25
+ # (*-tests, */tests, *_tests).
26
+ run: bunx @outfitter/tooling pre-push