@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
@@ -1,66 +1,66 @@
1
1
  {
2
- // Outfitter markdownlint preset
3
- // https://github.com/DavidAnson/markdownlint
2
+ // Outfitter markdownlint preset
3
+ // https://github.com/DavidAnson/markdownlint
4
4
 
5
- "config": {
6
- // Headings
7
- "MD003": { "style": "atx" }, // ATX-style headings (# Heading)
8
- "MD022": { "lines_above": 1, "lines_below": 1 }, // Blank lines around headings
9
- "MD024": { "siblings_only": true }, // Allow duplicate headings in different sections
10
- "MD041": false, // First line doesn't need to be h1 (frontmatter, etc.)
5
+ "config": {
6
+ // Headings
7
+ "MD003": { "style": "atx" }, // ATX-style headings (# Heading)
8
+ "MD022": { "lines_above": 1, "lines_below": 1 }, // Blank lines around headings
9
+ "MD024": { "siblings_only": true }, // Allow duplicate headings in different sections
10
+ "MD041": false, // First line doesn't need to be h1 (frontmatter, etc.)
11
11
 
12
- // Line length - disabled for prose flexibility
13
- "MD013": false,
12
+ // Line length - disabled for prose flexibility
13
+ "MD013": false,
14
14
 
15
- // Lists
16
- "MD004": { "style": "dash" }, // Unordered list style: dash (-)
17
- "MD007": { "indent": 2 }, // List indentation: 2 spaces
18
- "MD032": true, // Blank lines around lists
15
+ // Lists
16
+ "MD004": { "style": "dash" }, // Unordered list style: dash (-)
17
+ "MD007": { "indent": 2 }, // List indentation: 2 spaces
18
+ "MD032": true, // Blank lines around lists
19
19
 
20
- // Code blocks
21
- "MD040": true, // Fenced code blocks should have a language
22
- "MD046": { "style": "fenced" }, // Code block style: fenced (```)
23
- "MD048": { "style": "backtick" }, // Code fence style: backticks
20
+ // Code blocks
21
+ "MD040": true, // Fenced code blocks should have a language
22
+ "MD046": { "style": "fenced" }, // Code block style: fenced (```)
23
+ "MD048": { "style": "backtick" }, // Code fence style: backticks
24
24
 
25
- // Links
26
- "MD034": true, // No bare URLs (use <url> or [text](url))
25
+ // Links
26
+ "MD034": true, // No bare URLs (use <url> or [text](url))
27
27
 
28
- // Whitespace
29
- "MD009": { "br_spaces": 2 }, // Allow 2 trailing spaces for <br>
30
- "MD010": { "spaces_per_tab": 2 }, // Tabs to spaces
31
- "MD012": { "maximum": 1 }, // Max 1 consecutive blank line
32
- "MD047": true, // Files should end with newline
28
+ // Whitespace
29
+ "MD009": { "br_spaces": 2 }, // Allow 2 trailing spaces for <br>
30
+ "MD010": { "spaces_per_tab": 2 }, // Tabs to spaces
31
+ "MD012": { "maximum": 1 }, // Max 1 consecutive blank line
32
+ "MD047": true, // Files should end with newline
33
33
 
34
- // HTML - allow for GitHub-specific elements
35
- "MD033": {
36
- "allowed_elements": [
37
- "details",
38
- "summary",
39
- "kbd",
40
- "br",
41
- "sup",
42
- "sub",
43
- "img",
44
- "picture",
45
- "source",
46
- "a"
47
- ]
48
- },
34
+ // HTML - allow for GitHub-specific elements
35
+ "MD033": {
36
+ "allowed_elements": [
37
+ "details",
38
+ "summary",
39
+ "kbd",
40
+ "br",
41
+ "sup",
42
+ "sub",
43
+ "img",
44
+ "picture",
45
+ "source",
46
+ "a",
47
+ ],
48
+ },
49
49
 
50
- // Emphasis
51
- "MD049": { "style": "asterisk" }, // Emphasis style: *italic*
52
- "MD050": { "style": "asterisk" } // Strong style: **bold**
53
- },
50
+ // Emphasis
51
+ "MD049": { "style": "asterisk" }, // Emphasis style: *italic*
52
+ "MD050": { "style": "asterisk" }, // Strong style: **bold**
53
+ },
54
54
 
55
- // Ignore patterns
56
- "ignores": [
57
- "node_modules/**",
58
- "**/node_modules/**",
59
- "dist/**",
60
- "**/dist/**",
61
- ".turbo/**",
62
- "**/.turbo/**",
63
- "CHANGELOG.md",
64
- "**/CHANGELOG.md"
65
- ]
55
+ // Ignore patterns
56
+ "ignores": [
57
+ "node_modules/**",
58
+ "**/node_modules/**",
59
+ "dist/**",
60
+ "**/dist/**",
61
+ ".turbo/**",
62
+ "**/.turbo/**",
63
+ "CHANGELOG.md",
64
+ "**/CHANGELOG.md",
65
+ ],
66
66
  }
package/README.md CHANGED
@@ -4,7 +4,7 @@ Dev tooling configuration presets and CLI for Outfitter projects.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Configuration Presets**: Biome, TypeScript, Lefthook, and markdownlint configs
7
+ - **Configuration Presets**: oxlint, TypeScript, Lefthook, and markdownlint configs
8
8
  - **CLI Commands**: Initialize configs, upgrade Bun, TDD-aware pre-push hooks
9
9
  - **Registry System**: Composable config blocks for scaffolding
10
10
 
@@ -15,7 +15,8 @@ bun add -D @outfitter/tooling
15
15
  ```
16
16
 
17
17
  Peer dependencies (optional):
18
- - `ultracite` — Biome wrapper for formatting/linting
18
+
19
+ - `ultracite` — oxlint/oxfmt wrapper for formatting/linting
19
20
  - `lefthook` — Git hooks
20
21
  - `markdownlint-cli2` — Markdown linting
21
22
 
@@ -23,7 +24,7 @@ Peer dependencies (optional):
23
24
 
24
25
  ### `tooling init`
25
26
 
26
- Initialize tooling configuration in the current project. Copies preset configs for Biome, TypeScript, Lefthook, and markdownlint.
27
+ Initialize tooling configuration in the current project. Copies preset configs for oxlint, TypeScript, Lefthook, and markdownlint.
27
28
 
28
29
  ```bash
29
30
  bunx @outfitter/tooling init
@@ -50,6 +51,7 @@ bunx @outfitter/tooling fix src/
50
51
  ### `tooling upgrade-bun [version]`
51
52
 
52
53
  Upgrade Bun version across the project. Updates:
54
+
53
55
  - `.bun-version`
54
56
  - `engines.bun` in all package.json files
55
57
  - `@types/bun` dependency versions (leaves "latest" alone)
@@ -71,11 +73,13 @@ bunx @outfitter/tooling upgrade-bun 1.4.0 --no-install
71
73
  TDD-aware pre-push strict verification hook. Detects RED phase branches and skips verification by design.
72
74
 
73
75
  RED phase branches follow these patterns:
76
+
74
77
  - `*-tests` (e.g., `feature/auth-tests`)
75
78
  - `*/tests` (e.g., `feature/auth/tests`)
76
79
  - `*_tests` (e.g., `feature/auth_tests`)
77
80
 
78
81
  Verification order:
82
+
79
83
  1. Run `verify:ci` if present.
80
84
  2. Otherwise run strict fallback: `typecheck`, `check|lint`, `build`, `test`.
81
85
 
@@ -169,16 +173,6 @@ bunx @outfitter/tooling check-readme-imports --json
169
173
 
170
174
  ## Configuration Presets
171
175
 
172
- ### Biome
173
-
174
- Extends our Biome config in your `biome.json`:
175
-
176
- ```json
177
- {
178
- "extends": ["@outfitter/tooling/biome.json"]
179
- }
180
- ```
181
-
182
176
  ### TypeScript
183
177
 
184
178
  Extends our TypeScript config in your `tsconfig.json`:
@@ -207,6 +201,7 @@ extends:
207
201
  ```
208
202
 
209
203
  Default hooks:
204
+
210
205
  - **pre-commit**: Runs ultracite on staged files, typechecks
211
206
  - **pre-push**: Runs TDD-aware strict verification via `tooling pre-push`
212
207
 
@@ -224,8 +219,9 @@ cp node_modules/@outfitter/tooling/.markdownlint-cli2.jsonc .
224
219
  The tooling package includes a registry of composable config blocks for the `outfitter` CLI scaffolding system.
225
220
 
226
221
  Available blocks:
222
+
227
223
  - `claude` — Claude Code settings and hooks
228
- - `biome` — Biome/Ultracite configuration
224
+ - `linter` — oxlint/Ultracite configuration
229
225
  - `lefthook` — Git hooks configuration
230
226
  - `markdownlint` — Markdown linting configuration
231
227
  - `bootstrap` — Project bootstrap script
@@ -245,13 +241,17 @@ bun run apps/outfitter/src/cli.ts repo check boundary-invocations --cwd .
245
241
 
246
242
  ## Exports
247
243
 
248
- | Export | Description |
249
- |--------|-------------|
250
- | `./biome.json` | Biome configuration preset |
251
- | `./tsconfig.preset.json` | TypeScript preset (general) |
252
- | `./tsconfig.preset.bun.json` | TypeScript preset (Bun) |
253
- | `./lefthook.yml` | Lefthook hooks configuration |
254
- | `./.markdownlint-cli2.jsonc` | markdownlint configuration |
244
+ | Export | Description |
245
+ | ---------------------------- | -------------------------------------- |
246
+ | `./registry` | Tooling block registry API |
247
+ | `./tsconfig` | Alias for `./tsconfig.preset.json` |
248
+ | `./tsconfig-bun` | Alias for `./tsconfig.preset.bun.json` |
249
+ | `./tsconfig.preset.json` | TypeScript preset (general) |
250
+ | `./tsconfig.preset.bun.json` | TypeScript preset (Bun) |
251
+ | `./lefthook` | Alias for `./lefthook.yml` |
252
+ | `./lefthook.yml` | Lefthook hooks configuration |
253
+ | `./.markdownlint-cli2` | Alias for `./.markdownlint-cli2.jsonc` |
254
+ | `./.markdownlint-cli2.jsonc` | markdownlint configuration |
255
255
 
256
256
  ## Related
257
257
 
@@ -0,0 +1,2 @@
1
+ import { ParsedSemver, isTypesBunVersionCompatible, parseSemver } from "./shared/@outfitter/tooling-vjmhvpjq.js";
2
+ export { parseSemver, isTypesBunVersionCompatible, ParsedSemver };
@@ -0,0 +1,10 @@
1
+ // @bun
2
+ import {
3
+ isTypesBunVersionCompatible,
4
+ parseSemver
5
+ } from "./shared/@outfitter/tooling-mkynjra9.js";
6
+ import"./shared/@outfitter/tooling-jnrs9rqd.js";
7
+ export {
8
+ parseSemver,
9
+ isTypesBunVersionCompatible
10
+ };
@@ -0,0 +1,34 @@
1
+ interface ScriptLocation {
2
+ readonly file: string;
3
+ readonly scriptName: string;
4
+ readonly command: string;
5
+ }
6
+ interface BoundaryViolation extends ScriptLocation {
7
+ readonly rule: "root-runs-package-src" | "cd-package-then-runs-src";
8
+ }
9
+ interface ReadScriptEntriesOptions {
10
+ readonly appManifestRelativePaths?: readonly string[];
11
+ readonly readPackageJson?: (filePath: string) => Promise<{
12
+ scripts?: Record<string, string>;
13
+ }>;
14
+ }
15
+ /**
16
+ * Detect whether a single script command violates boundary invocation rules.
17
+ */
18
+ declare function detectBoundaryViolation(location: ScriptLocation): BoundaryViolation | null;
19
+ /**
20
+ * Find all boundary violations across package/app script maps.
21
+ */
22
+ declare function findBoundaryViolations(entries: readonly {
23
+ file: string;
24
+ scripts: Readonly<Record<string, string>>;
25
+ }[]): BoundaryViolation[];
26
+ declare function readScriptEntries(cwd: string, options?: ReadScriptEntriesOptions): Promise<{
27
+ file: string;
28
+ scripts: Record<string, string>;
29
+ }[]>;
30
+ /**
31
+ * Run boundary invocation checks against root/apps package scripts.
32
+ */
33
+ declare function runCheckBoundaryInvocations(): Promise<void>;
34
+ export { runCheckBoundaryInvocations, readScriptEntries, findBoundaryViolations, detectBoundaryViolation, ScriptLocation, BoundaryViolation };
@@ -0,0 +1,14 @@
1
+ // @bun
2
+ import {
3
+ detectBoundaryViolation,
4
+ findBoundaryViolations,
5
+ readScriptEntries,
6
+ runCheckBoundaryInvocations
7
+ } from "../shared/@outfitter/tooling-amrbp7cm.js";
8
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
9
+ export {
10
+ runCheckBoundaryInvocations,
11
+ readScriptEntries,
12
+ findBoundaryViolations,
13
+ detectBoundaryViolation
14
+ };
@@ -0,0 +1,36 @@
1
+ /** Result of checking bunup workspace registration */
2
+ interface RegistryCheckResult {
3
+ readonly ok: boolean;
4
+ readonly missing: string[];
5
+ }
6
+ /**
7
+ * Extract the package name from a build script containing `bunup --filter`.
8
+ *
9
+ * @example
10
+ * extractBunupFilterName("bunup --filter @outfitter/logging")
11
+ * // => "@outfitter/logging"
12
+ *
13
+ * extractBunupFilterName("cd ../.. && bunup --filter @outfitter/types")
14
+ * // => "@outfitter/types"
15
+ *
16
+ * extractBunupFilterName("tsc --noEmit")
17
+ * // => null
18
+ */
19
+ declare function extractBunupFilterName(script: string): string | null;
20
+ /**
21
+ * Find packages that have `bunup --filter` build scripts but are not
22
+ * registered in the bunup workspace config.
23
+ *
24
+ * @param packagesWithFilter - Package names that have `bunup --filter` in their build script
25
+ * @param registeredNames - Package names registered in bunup.config.ts
26
+ * @returns Result with sorted list of missing packages
27
+ */
28
+ declare function findUnregisteredPackages(packagesWithFilter: string[], registeredNames: string[]): RegistryCheckResult;
29
+ /**
30
+ * Run bunup registry check across all workspace packages.
31
+ *
32
+ * Scans packages/&#42;/package.json for build scripts containing `bunup --filter`,
33
+ * then verifies each is registered in bunup.config.ts.
34
+ */
35
+ declare function runCheckBunupRegistry(): Promise<void>;
36
+ export { runCheckBunupRegistry, findUnregisteredPackages, extractBunupFilterName, RegistryCheckResult };
@@ -0,0 +1,12 @@
1
+ // @bun
2
+ import {
3
+ extractBunupFilterName,
4
+ findUnregisteredPackages,
5
+ runCheckBunupRegistry
6
+ } from "../shared/@outfitter/tooling-wwm97f47.js";
7
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
8
+ export {
9
+ runCheckBunupRegistry,
10
+ findUnregisteredPackages,
11
+ extractBunupFilterName
12
+ };
@@ -0,0 +1,66 @@
1
+ /** Result of checking whether changesets are required */
2
+ interface ChangesetCheckResult {
3
+ readonly ok: boolean;
4
+ readonly missingFor: string[];
5
+ }
6
+ interface ChangesetIgnoredReference {
7
+ readonly file: string;
8
+ readonly packages: string[];
9
+ }
10
+ /**
11
+ * Extract unique package names from changed file paths.
12
+ *
13
+ * Only considers files matching the pattern "packages/NAME/src/..." and
14
+ * ignores apps/, root files, and package-level config.
15
+ *
16
+ * @param files - List of changed file paths relative to repo root
17
+ * @returns Sorted array of unique package names
18
+ */
19
+ declare function getChangedPackagePaths(files: string[]): string[];
20
+ /**
21
+ * Extract changeset filenames from changed file paths.
22
+ *
23
+ * Only considers files matching `.changeset/*.md`, excluding README.md.
24
+ * This checks the git diff rather than disk, ensuring only changesets added
25
+ * in the current PR are counted.
26
+ *
27
+ * @param files - List of changed file paths relative to repo root
28
+ * @returns Array of changeset filenames (e.g. `["happy-turtle.md"]`)
29
+ */
30
+ declare function getChangedChangesetFiles(files: string[]): string[];
31
+ /**
32
+ * Determine whether a changeset is required and present.
33
+ *
34
+ * Returns `ok: true` when either no packages were changed or at least one
35
+ * changeset file exists. Returns `ok: false` with the list of changed
36
+ * packages when changesets are missing.
37
+ *
38
+ * @param changedPackages - Package names with source changes
39
+ * @param changesetFiles - Changeset filenames found in `.changeset/`
40
+ */
41
+ declare function checkChangesetRequired(changedPackages: string[], changesetFiles: string[]): ChangesetCheckResult;
42
+ declare function parseIgnoredPackagesFromChangesetConfig(jsonContent: string): string[];
43
+ declare function parseChangesetFrontmatterPackageNames(markdownContent: string): string[];
44
+ declare function findIgnoredPackageReferences(input: {
45
+ readonly changesetFiles: readonly string[];
46
+ readonly ignoredPackages: readonly string[];
47
+ readonly readChangesetFile: (filename: string) => string;
48
+ }): ChangesetIgnoredReference[];
49
+ interface CheckChangesetOptions {
50
+ readonly skip?: boolean;
51
+ }
52
+ /**
53
+ * Run check-changeset to verify PRs include changeset files.
54
+ *
55
+ * Uses `git diff --name-only origin/main...HEAD` to detect changed files,
56
+ * then checks for changeset presence when package source files are modified.
57
+ *
58
+ * Skips silently when:
59
+ * - `NO_CHANGESET=1` env var is set
60
+ * - `--skip` flag is passed
61
+ * - `GITHUB_EVENT_NAME=push` (post-merge on main)
62
+ * - No packages have source changes
63
+ * - Git diff fails (local dev without origin)
64
+ */
65
+ declare function runCheckChangeset(options?: CheckChangesetOptions): Promise<void>;
66
+ export { runCheckChangeset, parseIgnoredPackagesFromChangesetConfig, parseChangesetFrontmatterPackageNames, getChangedPackagePaths, getChangedChangesetFiles, findIgnoredPackageReferences, checkChangesetRequired, CheckChangesetOptions, ChangesetIgnoredReference, ChangesetCheckResult };
@@ -0,0 +1,20 @@
1
+ // @bun
2
+ import {
3
+ checkChangesetRequired,
4
+ findIgnoredPackageReferences,
5
+ getChangedChangesetFiles,
6
+ getChangedPackagePaths,
7
+ parseChangesetFrontmatterPackageNames,
8
+ parseIgnoredPackagesFromChangesetConfig,
9
+ runCheckChangeset
10
+ } from "../shared/@outfitter/tooling-6cxfdx0q.js";
11
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
12
+ export {
13
+ runCheckChangeset,
14
+ parseIgnoredPackagesFromChangesetConfig,
15
+ parseChangesetFrontmatterPackageNames,
16
+ getChangedPackagePaths,
17
+ getChangedChangesetFiles,
18
+ findIgnoredPackageReferences,
19
+ checkChangesetRequired
20
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Check-clean-tree command — asserts the working tree has no modified or untracked files.
3
+ *
4
+ * Pure core functions for parsing git output and determining tree cleanliness.
5
+ * The CLI runner in {@link runCheckCleanTree} handles git invocation and output.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ /** Status of the working tree after verification steps */
10
+ interface TreeStatus {
11
+ readonly clean: boolean;
12
+ readonly modified: string[];
13
+ readonly untracked: string[];
14
+ }
15
+ /**
16
+ * Parse `git diff --name-only` output into a list of modified file paths.
17
+ */
18
+ declare function parseGitDiff(diffOutput: string): string[];
19
+ /**
20
+ * Parse `git ls-files --others --exclude-standard` output into a list of untracked file paths.
21
+ */
22
+ declare function parseUntrackedFiles(lsOutput: string): string[];
23
+ /**
24
+ * Determine if the tree status represents a clean working tree.
25
+ */
26
+ declare function isCleanTree(status: TreeStatus): boolean;
27
+ interface CheckCleanTreeOptions {
28
+ readonly paths?: string[];
29
+ }
30
+ /**
31
+ * Run clean-tree check against the current working directory.
32
+ *
33
+ * Exits 0 if clean, 1 if dirty files are found.
34
+ */
35
+ declare function runCheckCleanTree(options?: CheckCleanTreeOptions): Promise<void>;
36
+ export { runCheckCleanTree, parseUntrackedFiles, parseGitDiff, isCleanTree, TreeStatus, CheckCleanTreeOptions };
@@ -0,0 +1,14 @@
1
+ // @bun
2
+ import {
3
+ isCleanTree,
4
+ parseGitDiff,
5
+ parseUntrackedFiles,
6
+ runCheckCleanTree
7
+ } from "../shared/@outfitter/tooling-gcdvsqqp.js";
8
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
9
+ export {
10
+ runCheckCleanTree,
11
+ parseUntrackedFiles,
12
+ parseGitDiff,
13
+ isCleanTree
14
+ };
@@ -0,0 +1,2 @@
1
+ import { CheckExportsOptions, CheckResult, CompareInput, ExportDrift, ExportMap, PackageResult, compareExports, entryToSubpath, resolveJsonMode, runCheckExports } from "../shared/@outfitter/tooling-wesswf21.js";
2
+ export { runCheckExports, resolveJsonMode, entryToSubpath, compareExports, PackageResult, ExportMap, ExportDrift, CompareInput, CheckResult, CheckExportsOptions };
@@ -0,0 +1,14 @@
1
+ // @bun
2
+ import {
3
+ compareExports,
4
+ entryToSubpath,
5
+ resolveJsonMode,
6
+ runCheckExports
7
+ } from "../shared/@outfitter/tooling-h04te11c.js";
8
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
9
+ export {
10
+ runCheckExports,
11
+ resolveJsonMode,
12
+ entryToSubpath,
13
+ compareExports
14
+ };
@@ -0,0 +1,42 @@
1
+ /** A relative link extracted from a markdown file. */
2
+ interface MarkdownLink {
3
+ /** The link target path (anchors stripped). */
4
+ readonly target: string;
5
+ /** 1-based line number where the link appears. */
6
+ readonly line: number;
7
+ }
8
+ /** A broken link with its source file context. */
9
+ interface BrokenLink {
10
+ /** Relative path of the source markdown file. */
11
+ readonly source: string;
12
+ /** The link target that could not be resolved. */
13
+ readonly target: string;
14
+ /** 1-based line number in the source file. */
15
+ readonly line: number;
16
+ }
17
+ /**
18
+ * Extract relative markdown links from content, skipping external URLs,
19
+ * bare anchors, code fences, and inline code.
20
+ *
21
+ * @param content - Raw markdown content
22
+ * @returns Array of extracted links with line numbers
23
+ */
24
+ declare function extractMarkdownLinks(content: string): MarkdownLink[];
25
+ /**
26
+ * Validate that relative links in the given markdown files resolve to
27
+ * existing files on disk.
28
+ *
29
+ * @param rootDir - Absolute path to the project root
30
+ * @param files - Relative file paths (from rootDir) to check
31
+ * @returns Array of broken links
32
+ */
33
+ declare function validateLinks(rootDir: string, files: readonly string[]): Promise<BrokenLink[]>;
34
+ /**
35
+ * Run check-markdown-links across the project.
36
+ *
37
+ * @param rootDir - Project root directory
38
+ * @param patterns - Glob patterns for file discovery (defaults to standard set)
39
+ * @returns Exit code (0 = all valid, 1 = broken links found)
40
+ */
41
+ declare function runCheckMarkdownLinks(rootDir: string, patterns?: readonly string[]): Promise<number>;
42
+ export { validateLinks, runCheckMarkdownLinks, extractMarkdownLinks, MarkdownLink, BrokenLink };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ import {
4
+ extractMarkdownLinks,
5
+ runCheckMarkdownLinks,
6
+ validateLinks
7
+ } from "../shared/@outfitter/tooling-ja1zg5yc.js";
8
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
9
+ export {
10
+ validateLinks,
11
+ runCheckMarkdownLinks,
12
+ extractMarkdownLinks
13
+ };
@@ -0,0 +1,60 @@
1
+ import { ExportMap } from "../shared/@outfitter/tooling-wesswf21.js";
2
+ /** An import example extracted from a markdown code block */
3
+ interface ImportExample {
4
+ /** Package name, e.g. "@outfitter/cli" */
5
+ readonly packageName: string;
6
+ /** Export subpath, e.g. "./output" or "." */
7
+ readonly subpath: string;
8
+ /** Full import specifier, e.g. "@outfitter/cli/output" */
9
+ readonly fullSpecifier: string;
10
+ /** File where the import was found */
11
+ readonly file: string;
12
+ /** 1-based line number */
13
+ readonly line: number;
14
+ }
15
+ /** Result of checking imports in a single file */
16
+ interface ImportCheckResult {
17
+ readonly file: string;
18
+ readonly valid: ImportExample[];
19
+ readonly invalid: ImportExample[];
20
+ }
21
+ /**
22
+ * Parse a full import specifier into package name and subpath.
23
+ *
24
+ * Only recognizes `@outfitter/*` scoped packages.
25
+ *
26
+ * @example
27
+ * parseSpecifier("@outfitter/cli/output")
28
+ * // { packageName: "@outfitter/cli", subpath: "./output" }
29
+ *
30
+ * parseSpecifier("@outfitter/contracts")
31
+ * // { packageName: "@outfitter/contracts", subpath: "." }
32
+ */
33
+ declare function parseSpecifier(specifier: string): {
34
+ packageName: string;
35
+ subpath: string;
36
+ } | null;
37
+ /**
38
+ * Extract import specifiers from markdown content.
39
+ *
40
+ * Only extracts imports from fenced code blocks (typescript, ts,
41
+ * javascript, js). Skips blocks preceded by a non-contractual HTML comment.
42
+ * Deduplicates by full specifier within a single file.
43
+ */
44
+ declare function extractImports(content: string, file: string): ImportExample[];
45
+ /**
46
+ * Check whether a subpath exists in a package.json map.
47
+ */
48
+ declare function isExportedSubpath(subpath: string, exports: ExportMap): boolean;
49
+ interface CheckReadmeImportsOptions {
50
+ readonly json?: boolean;
51
+ }
52
+ declare function resolveJsonMode(options?: CheckReadmeImportsOptions): boolean;
53
+ /**
54
+ * Run check-readme-imports across all workspace packages.
55
+ *
56
+ * Finds README.md files in `packages/`, extracts import examples, and
57
+ * validates each subpath against the corresponding package.json exports.
58
+ */
59
+ declare function runCheckReadmeImports(options?: CheckReadmeImportsOptions): Promise<void>;
60
+ export { runCheckReadmeImports, resolveJsonMode, parseSpecifier, isExportedSubpath, extractImports, ImportExample, ImportCheckResult, ExportMap, CheckReadmeImportsOptions };
@@ -1,7 +1,8 @@
1
- import"./chunk-3s189drz.js";
1
+ // @bun
2
+ import"../shared/@outfitter/tooling-jnrs9rqd.js";
2
3
 
3
- // src/cli/check-readme-imports.ts
4
- import { resolve } from "node:path";
4
+ // packages/tooling/src/cli/check-readme-imports.ts
5
+ import { resolve } from "path";
5
6
  function parseSpecifier(specifier) {
6
7
  if (!specifier.startsWith("@outfitter/")) {
7
8
  return null;
@@ -90,7 +91,7 @@ function resolveJsonMode(options = {}) {
90
91
  async function runCheckReadmeImports(options = {}) {
91
92
  const cwd = process.cwd();
92
93
  const readmeGlob = new Bun.Glob("**/README.md");
93
- const readmeDirs = ["packages", "docs/packages"];
94
+ const readmeDirs = ["packages"];
94
95
  const readmePaths = [];
95
96
  for (const dir of readmeDirs) {
96
97
  const fullDir = resolve(cwd, dir);
@@ -126,7 +127,7 @@ async function runCheckReadmeImports(options = {}) {
126
127
  }
127
128
  const results = [];
128
129
  let hasInvalid = false;
129
- for (const readmePath of readmePaths.sort()) {
130
+ for (const readmePath of readmePaths.toSorted()) {
130
131
  const content = await Bun.file(readmePath).text();
131
132
  const relativePath = readmePath.replace(`${cwd}/`, "");
132
133
  const imports = extractImports(content, relativePath);
@@ -186,7 +187,7 @@ async function runCheckReadmeImports(options = {}) {
186
187
  `);
187
188
  }
188
189
  }
189
- process.exit(hasInvalid ? 1 : 0);
190
+ process.exitCode = hasInvalid ? 1 : 0;
190
191
  }
191
192
  export {
192
193
  runCheckReadmeImports,