Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/skills-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@bomb.sh/tools': patch
---

Updates the `lint`, `build`, and `lifecycle` skills to match current `bsh` behavior

The lint skill no longer claims publint runs in `pnpm run lint` (it gates `pnpm run build`), documents `--strict`, `--warnings`, and `--format json`, and adds a remedies table mapping common violations to their sanctioned fixes. The lifecycle skill moves the knip dead-code gate (`lint --strict`) to the PR handoff step.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ If you'd like to use this package for your own projects, please consider forking
- `bsh test` command, using [`vitest`](https://vitest.dev/)
- `bsh format` command, using [`oxfmt`](https://oxc.rs/docs/guide/usage/formatter)
- `bsh lint` command, using [`oxlint`](https://oxc.rs/docs/guide/usage/linter), [`knip`](https://knip.dev), [`tsgo`](https://npmx.dev/@typescript/native-preview)
- `bsh publint` command, using [`publint`](https://publint.dev/)
- `bsh publint` command, using [`publint`](https://publint.dev/) (also runs automatically as a publish gate in `bsh build`)
- `bsh sync` command, which links our shared [agent skills](#agent-skills) into your project
- shared `tsconfig.json` file

Expand Down
27 changes: 21 additions & 6 deletions skills/build/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
name: build
description: >
TypeScript to ESM compilation via tsdown with opinionated defaults. Sourcemaps,
clean dist/, unbundled output. Flags: --dts, --bundle, --minify. Default entry
src/**/*.ts. Use when building a package for publish or generating declarations.
clean dist/, unbundled output, .d.mts types by default, publint publish gate.
Flags: --no-dts, --bundle, --minify. Default entry src/**/*.ts. Use when
building a package for publish or generating declarations.
metadata:
type: core
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
requires:
- lifecycle
sources:
Expand All @@ -31,28 +32,42 @@ pnpm run build
- **Sourcemaps:** enabled
- **Clean:** removes dist/ before building
- **Unbundled** by default (each source file produces one output file)
- **Types:** `.d.mts` declarations generated by default (via tsgo)
- **Entry:** defaults to `src/**/*.ts`
- **Config:** explicitly disabled (`config: false`) — tsdown.config.ts is ignored

## Publish gate

After a successful build, `bsh build` runs **publint** (strict mode) against
the emitted `dist/` and fails the build on errors — broken `exports` targets,
missing declaration files, and invalid `package.json` fields are caught here,
not at publish time. Warnings and suggestions are advisory.

A failed gate after `--no-dts` almost always means `package.json` declares
types that weren't emitted — either rebuild with types (the default) or fix
the `exports` map.

## Flags

Pass flags after `--` in pnpm:

| Flag | Effect |
|------|--------|
| `--dts` | Generate `.d.mts` declaration files |
| `--no-dts` | Skip `.d.mts` declaration generation (on by default) |
| `--bundle` | Bundle into single output (disables unbundled mode) |
| `--minify` | Minify output |
| positional args | Custom entry points (replaces default `src/**/*.ts`) |

```sh
pnpm run build -- --dts
pnpm run build -- --no-dts
pnpm run build -- --bundle
pnpm run build -- --minify
pnpm run build -- src/index.ts
pnpm run build -- --dts --minify
```

If no entry files match, the build fails with `No entry files matched: …` —
pass explicit entries or check that `src/` exists.

## Common Mistakes

### MEDIUM: Passing unnecessary flags
Expand Down
2 changes: 1 addition & 1 deletion skills/dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: >
metadata:
type: core
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
requires:
- lifecycle
sources:
Expand Down
2 changes: 1 addition & 1 deletion skills/format/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: >
metadata:
type: core
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
requires:
- lifecycle
sources:
Expand Down
2 changes: 1 addition & 1 deletion skills/init/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: >
metadata:
type: core
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
sources:
- 'bombshell-dev/tools:src/commands/init.ts'
---
Expand Down
17 changes: 14 additions & 3 deletions skills/lifecycle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: >
metadata:
type: lifecycle
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
sources:
- 'bombshell-dev/tools:skills/lifecycle/SKILL.md'
- 'bombshell-dev/tools:src/bin.ts'
Expand All @@ -27,7 +27,7 @@ All scripts proxy to `bsh <command>` via `package.json`. Never bypass them.
| `pnpm run build` | `bsh build` | Build with tsdown (ESM, sourcemaps, clean) |
| `pnpm run dev` | `bsh dev` | Watch mode with native Node TS transforms |
| `pnpm run format` | `bsh format` | Format with oxfmt |
| `pnpm run lint` | `bsh lint` | Parallel: oxlint + publint + knip + tsgo |
| `pnpm run lint` | `bsh lint` | Parallel: oxlint + knip + tsgo |
| `pnpm run test` | `bsh test` | Run tests with vitest (single run) |
| `pnpm run init` | `bsh init` | Scaffold new project from template |

Expand Down Expand Up @@ -101,6 +101,9 @@ pnpm run lint
pnpm run lint -- --fix
```

- [ ] Warnings are collapsed by default (they never fail the run). Expand them
with `--warnings` when triaging.

### 4. Format

- [ ] Normalize code style:
Expand All @@ -111,7 +114,8 @@ pnpm run format

### 5. Build

- [ ] Verify the package compiles:
- [ ] Verify the package compiles (types are generated by default) and passes
the publint publish gate:

```sh
pnpm run build
Expand All @@ -127,6 +131,13 @@ pnpm run test

### 7. PR Handoff

- [ ] Run the strict lint pass — this is the dead-code gate (knip unused
exports/types/files) that doesn't run during the TDD loop:

```sh
pnpm run lint -- --strict
```

- [ ] Present a summary of changes to the human
- [ ] **Human creates the PR** — agents do not create or merge PRs autonomously

Expand Down
81 changes: 61 additions & 20 deletions skills/lint/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
---
name: lint
description: >
Multi-tool linting pipeline: oxlint, publint, knip, tsgo run in parallel via
pnpm run lint. Covers Bombshell conventions: URL over node:path, max 2 params
with options bag, named exports only, import type, prefer node builtins, no
console.log, no generic Error. Use when checking code quality or understanding
lint violations.
Multi-tool linting pipeline: oxlint, knip, and tsgo run in parallel via
pnpm run lint (publint gates pnpm run build instead). Covers Bombshell
conventions: URL over node:path, max 2 params with options bag, named
exports only, import type, prefer node builtins, no console.log, no
generic Error. Use when checking code quality or understanding lint
violations.
metadata:
type: core
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
requires:
- lifecycle
sources:
Expand All @@ -20,32 +21,63 @@ metadata:

# Lint

Multi-tool linting pipeline. All four tools run in parallel with unified output.
Multi-tool linting pipeline. oxlint, knip, and tsgo run in parallel with unified output.

## Setup

```sh
pnpm run lint # Report violations
pnpm run lint -- --fix # Auto-fix (oxlint only), then report remaining
pnpm run lint -- src/foo.ts # Target specific files (default: ./src)
pnpm run lint # Report errors (warnings collapsed to counts)
pnpm run lint -- --warnings # Show warnings in full
pnpm run lint -- --strict # Include knip dead-code checks (pre-commit gate)
pnpm run lint -- --fix # Auto-fix (oxlint only), then report remaining
pnpm run lint -- src/foo.ts # Target specific files (default: whole project)
pnpm -s run lint -- --format json # Machine-readable report for agents/CI
```

Do not run oxlint, publint, knip, or tsgo directly. Always use `pnpm run lint`.
Do not run oxlint, knip, or tsgo directly. Always use `pnpm run lint`.
(`--format json` needs `pnpm -s` to keep pnpm's banner out of stdout.)

See [lifecycle/SKILL.md](../lifecycle/SKILL.md) for where lint fits in the development workflow (step 5: after tests pass, before format).
See [lifecycle/SKILL.md](../lifecycle/SKILL.md) for where lint fits in the development workflow (step 3: after tests pass, before format). Run `--strict` at PR handoff, not during the TDD loop.

## How It Works

`pnpm run lint` runs `bsh lint`, which executes four tools via `Promise.allSettled`:
`pnpm run lint` runs `bsh lint`, which executes three tools via `Promise.allSettled`:

| Tool | What It Checks | Fix Support |
|------|---------------|-------------|
| **oxlint** | JS/TS linting via Rust-based engine with Bombshell config | Yes (`--fix`) |
| **publint** | `package.json` exports, types, and field correctness (strict mode) | No |
| **knip** | Unused dependencies, devDependencies, exports, types, files | No |
| **tsgo** | TypeScript type errors (`--noEmit`, native Go compiler) | No |
| **knip** | Unused dependencies/devDependencies (always); unused exports, types, files (`--strict` only) | No |
| **tsgo** | TypeScript type errors (`--noEmit`, project mode) | No |

Results merge into a single report grouped by file. Exit code 1 if any errors exist.
Results merge into a single report grouped by file. **Errors print in full;
warnings collapse to a per-rule count** (they never affect the exit code —
pass `--warnings` to expand them). Exit code 1 if any errors exist.

publint is deliberately not part of lint: its file-existence checks need
`dist/`, so it runs as a publish gate in `pnpm run build` (see
[build/SKILL.md](../build/SKILL.md)) and standalone via `pnpm run publint`.

## Remedies

The sanctioned fix for the most common violations. Do not improvise
alternatives (e.g. sprinkling disable comments).

| Violation | Fix |
|-----------|-----|
| `tsc/TS2688` — Cannot find type definition file for 'node' | `pnpm add -D @types/node` |
| `tsc/TS2591` — Cannot find name 'process'/'Buffer' | `pnpm add -D @types/node` |
| `oxlint/eslint(no-restricted-imports)` | Use the `URL` API; `fileURLToPath()` only at third-party boundaries |
| `oxlint/eslint(max-params)` / `bombshell-dev(max-params)` | Options bag with a typed interface. If conforming to a platform interface, say so with `override`/`implements` — the rule exempts those |
| `oxlint/import(no-default-export)` | Use a named export |
| `oxlint/bombshell-dev(no-generic-error)` | Define a project error class with a `code`; throw that |
| `oxlint/bombshell-dev(exported-function-async)` | Only fires on public entry files: make it `async`, or move the export out of the public surface |
| `oxlint/bombshell-dev(require-export-jsdoc)` | Only fires on public entry files: add a one-line `/** ... */` |
| `knip/unused-dependency` | Remove it from `package.json` |
| `knip/unused-export` (`--strict`) | Un-export it, or delete it if nothing consumes it |

Inline `// oxlint-disable` comments are a last resort for genuinely
exceptional cases, never a workflow. If a rule is wrong for your project
shape, raise it — the fix belongs upstream in `oxlintrc.json`.

## Core Patterns

Expand All @@ -68,7 +100,12 @@ await thirdPartyLib(configPath);

### Options bag for >2 parameters

Functions must have at most 2 parameters. Use an options object for anything beyond that.
Functions we author must have at most 2 parameters. Use an options object for anything beyond that.

Signatures conforming to an API you don't control are exempt — `override`
methods, members of classes that `extends` or `implements`, and inline
callbacks. If a platform interface forces more parameters on you, express the
conformance (`override`, `implements`) and the rule stays silent.

```ts
// Correct
Expand Down Expand Up @@ -144,7 +181,11 @@ Use `const` by default. Use `let` only when reassignment is necessary. `var` is

### Exported functions: `async`, explicit return types, JSDoc

All three are enforced (as warnings) on exported functions:
All three are enforced (as warnings) on exported functions — but `async` and
JSDoc only apply to the **public API surface**: files consumers can import,
derived from `package.json` `exports`/`bin` (mapping `dist/` paths back to
`src/`). Internal modules are exempt. Packages with no publish surface (apps,
examples) are exempt entirely.

```ts
// Correct
Expand Down Expand Up @@ -274,7 +315,7 @@ Builtin error constructors (`Error`, `TypeError`, `RangeError`, `ReferenceError`

## Tensions

- **Prototyping speed vs lint strictness**: During early prototyping (see [lifecycle](../lifecycle/SKILL.md)), you may want to move fast. The lint rules still apply -- write correct code from the start rather than fixing lint after the fact.
- **Prototyping speed vs lint strictness**: During early prototyping (see [lifecycle](../lifecycle/SKILL.md)), you may want to move fast. The lint rules still apply -- write correct code from the start rather than fixing lint after the fact. Dead-code checks (knip unused exports/types/files) are deferred to `--strict` at PR handoff precisely so they don't fire mid-implementation.
- **Opinionated defaults vs explicit config**: The lint config is intentionally strict and not configurable per-project. If a rule is wrong, change it in `oxlintrc.json` upstream.

## Reference
Expand Down
34 changes: 24 additions & 10 deletions skills/lint/references/lint-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,32 @@ Complete rule table for `oxlintrc.json` and custom Bombshell plugin rules.
| `no-console` | warn | oxlint | Bans `console.log`; allows `console.info`, `warn`, `error`, `debug` |
| `prefer-const` | error | oxlint | Use `const` when variable is never reassigned |
| `no-var` | error | oxlint | No `var` declarations |
| `max-params` | error | oxlint | Max 2 parameters per function |
| `typescript/explicit-function-return-type` | warn | oxlint/typescript | Function declarations need return types (expressions exempt) |
| `node/no-path-concat` | error | oxlint/node | No string concatenation with `__dirname`/`__filename` |

Deliberately disabled category defaults: `unicorn/consistent-function-scoping`, `no-underscore-dangle`.

## Bombshell Custom Plugin Rules

Defined in `rules/plugin.js`, registered as the `bombshell-dev` plugin.

| Rule | Severity | Description |
|------|----------|-------------|
| `bombshell-dev/no-generic-error` | error | No `throw new Error(...)` or other builtin error constructors. Use project-specific error classes. |
| `bombshell-dev/require-export-jsdoc` | warn | Exported functions and classes must have a `/** ... */` JSDoc comment. |
| `bombshell-dev/exported-function-async` | warn | Exported functions must use `async`. Adding async later is a breaking change. |
| `bombshell-dev/max-params` | error | Max 2 parameters in authored signatures — use an options bag. Exempt: `override` methods, members of classes that `extends`/`implements`, inline callbacks. |
| `bombshell-dev/require-export-jsdoc` | warn | Exported functions and classes must have a `/** ... */` JSDoc comment. **Public API surface only** (see below). |
| `bombshell-dev/exported-function-async` | warn | Exported functions must use `async`. Adding async later is a breaking change. **Public API surface only** (see below). |

## Public API Surface Scoping

`require-export-jsdoc` and `exported-function-async` encode conventions that
exist to prevent breaking changes for consumers — so they only apply to files
consumers can import. `bsh lint` derives the public surface from
`package.json` (`exports`, `bin`, `main`/`module`, mapping `dist/` paths back
to `src/`), including conventional `packages/*/` workspace members, and scopes
these rules to those files via oxlint `overrides`. Internal modules, packages
without a publish surface (apps, examples), and wildcard passthrough exports
(`"./*": "./dist/*"`) are exempt.

## oxlint Categories

Expand All @@ -41,12 +54,13 @@ These apply in addition to individual rules:

`unicorn`, `typescript`, `oxc`, `import`, `node`, plus the custom `bombshell-dev` JS plugin.

## Other Tools in the Pipeline
## Other Tools

| Tool | What It Catches |
|------|----------------|
| **publint** | Incorrect `package.json` exports, missing types, invalid fields |
| **knip** | Unused dependencies, devDependencies, exports, types, files |
| **tsgo** | TypeScript type errors (`--noEmit`) |
| Tool | Where it runs | What It Catches |
|------|---------------|-----------------|
| **knip** | `bsh lint` | Unused dependencies/devDependencies (always); unused exports/types/files (`--strict` only) |
| **tsgo** | `bsh lint` | TypeScript type errors (`--noEmit`, project mode) |
| **publint** | `bsh build` (publish gate) and `bsh publint` | Incorrect `package.json` exports, missing types, invalid fields (strict mode) |

These tools have no configurable rules in this project. They run with defaults (publint in strict mode, knip configured in `package.json`).
publint does not run in `bsh lint` — its file-existence checks need `dist/`,
so it gates the build instead.
2 changes: 1 addition & 1 deletion skills/migrate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: >
metadata:
type: lifecycle
library: "@bomb.sh/tools"
library_version: "0.3.1"
library_version: "0.6.0"
requires:
- lifecycle
sources:
Expand Down
2 changes: 1 addition & 1 deletion skills/test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description: >
metadata:
type: core
library: '@bomb.sh/tools'
library_version: '0.3.1'
library_version: '0.6.0'
requires:
- lifecycle
sources:
Expand Down
Loading