@bensandee/tooling 0.70.0 → 0.72.1

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.
package/README.md CHANGED
@@ -28,17 +28,18 @@ The tool auto-detects project structure, CI platform, project type, and Docker p
28
28
 
29
29
  ### Project management
30
30
 
31
- | Command | Description |
32
- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
33
- | `tooling repo:sync [dir]` | Detect, generate, and sync project tooling (idempotent). First run prompts for release strategy, CI platform (if not detected), and formatter (if Prettier found). Subsequent runs are non-interactive. |
34
- | `tooling repo:sync --check [dir]` | Dry-run drift detection. Exits 1 if files would change. CI-friendly. |
35
- | `tooling checks:run` | Run project checks (build, docker:build, typecheck, lint, test, format, knip, tooling:check, docker:check). Flags: `--skip`, `--add`, `--fail-fast`, `--verbose`, `--with-coverage`, `--coverage`, `--no-coverage`. |
31
+ | Command | Description |
32
+ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
33
+ | `tooling repo:sync [dir]` | Detect, generate, and sync project tooling (idempotent). First run prompts for release strategy, CI platform (if not detected), and formatter (if Prettier found). Subsequent runs are non-interactive. |
34
+ | `tooling repo:sync --check [dir]` | Dry-run drift detection. Exits 1 if files would change. CI-friendly. |
35
+ | `tooling checks:run` | Run project checks -- `bst checks:run --help` lists the ordered steps. Flags: `--skip`, `--add`, `--fail-fast`, `--verbose`, `--with-coverage`, `--coverage`, `--no-coverage`. |
36
+ | `tooling lint:types` | Type-aware linting (`oxlint --type-aware`, backed by `oxlint-tsgolint`). Flags: `--json`. See [Type-aware linting](#type-aware-linting) below. |
36
37
 
37
38
  **Flags:** `--yes` (accept all defaults), `--no-ci` (negates `--ci`), `--no-prompt` (negates `--prompt`), `--eslint-plugin`
38
39
 
39
40
  #### `checks:run`
40
41
 
41
- Runs checks in order: build, docker:build, typecheck, lint, test, format (--check), knip, tooling:check, docker:check. Checks without a matching script in `package.json` are silently skipped.
42
+ Runs checks in order: build, typecheck, lint, ascii:check (opt-in), lint:types, test, format (--check), knip, tooling:check, health:check (opt-in), docs:check, docker:build, docker:check. Checks without a matching script in `package.json` are silently skipped.
42
43
 
43
44
  The `--skip` flag supports glob patterns via picomatch:
44
45
 
@@ -82,6 +83,16 @@ Because the decision is branch-aware, the generated CI workflow runs plain `pnpm
82
83
 
83
84
  The generated `ci:check` script defaults to `pnpm check --skip 'docker:*'` since CI environments typically lack Docker support.
84
85
 
86
+ ### Type-aware linting
87
+
88
+ For `stack: "typescript"` repos, `repo:sync` generates a `lint:types` script (`bst lint:types`, backed by a managed `oxlint-tsgolint` devDependency) and inserts a `lint:types` step into `checks:run` right after `lint`. It runs `oxlint --type-aware` and selects its findings by subtracting a plain `oxlint` run from it -- there is no maintained list of type-aware rule names, so a rule oxlint adds lands the day it ships.
89
+
90
+ **Two phases, and the tooling's own version carries them.** The **report** phase prints every finding, states plainly that they will block once a later tooling release flips to **enforce**, and exits 0. The flip is one constant in the tooling's source, so it reaches every consumer as an ordinary `@bensandee/tooling` version bump -- no coordinated migration, nothing to remember. `.tooling.json#lint.strictTypeAware` (default `false`) lets a repo opt into blocking during the report phase, ahead of the fleet-wide flip.
91
+
92
+ **The whole default rule set ships, and the tooling excludes nothing.** A repo's own `oxlint.config.ts` is the per-rule control -- turning a rule off there (`"typescript/<rule>": "off"`) is honored by the type-aware run, and since plain `oxlint` ignores type-aware rules entirely, such an entry never weakens `pnpm lint`. In increasing order of bluntness: turn off one rule in `oxlint.config.ts`, or skip the whole step with `.tooling.json#checks.skip: ["lint:types"]`.
93
+
94
+ A missing `oxlint-tsgolint` binary degrades to a notice at exit 0 in the report phase, and fails only when `lint.strictTypeAware` is set -- a repo that has not armed enforcement should not have CI broken by a platform gap, and a repo that has asked for the gate should not silently lose it.
95
+
85
96
  ### Custom blocks in workflows
86
97
 
87
98
  Generated workflow files are regenerated on each `repo:sync` run. To preserve custom additions (extra steps, environment variables, etc.), wrap them in custom block markers:
@@ -268,7 +279,7 @@ pnpm test:coverage -> coverage:summary -> coverage:record -> coverage:stat
268
279
 
269
280
  so every CI log ends with the trend table for the last 10 records.
270
281
 
271
- The history file (`coverage-history.jsonl`) lives on a dedicated `bst/coverage-metrics` orphan branch -- never on `main`. This sidesteps branch protection (no privileged token needed beyond `contents: write`) and keeps `git log main` clean. `coverage:record` uses pure git plumbing (`hash-object` -> `mktree` -> `commit-tree` -> `push --force-with-lease`) so the working tree is never touched, and concurrent CI runs are handled safely via compare-and-swap with retry.
282
+ The history file (`coverage-history.jsonl`) lives on a dedicated `bst/coverage-metrics` orphan branch -- never on `main`. This sidesteps branch protection (no privileged token needed beyond `contents: write`) and keeps `git log main` clean. The `contents: write` workflow permission is a GitHub concern: on Forgejo the generated workflow declares no `permissions` block at all, and the push is authorized by the runner token's default access (or an Authorized Integration, where an instance restricts it). `coverage:record` uses pure git plumbing (`hash-object` -> `mktree` -> `commit-tree` -> `push --force-with-lease`) so the working tree is never touched, and concurrent CI runs are handled safely via compare-and-swap with retry.
272
283
 
273
284
  #### The local ratchet
274
285
 
@@ -420,7 +431,7 @@ Each package is tagged independently using its own version, so packages in a mon
420
431
 
421
432
  | Host | Username secret | Password secret |
422
433
  | ------------------------- | --------------------------------- | --------------------------------- |
423
- | `code.orangebikelabs.com` | `FORGEJO_REGISTRY_USERNAME` | `FORGEJO_REGISTRY_PASSWORD` |
434
+ | `code.orangebikelabs.com` | `OBL_REGISTRY_USERNAME` | `OBL_REGISTRY_PASSWORD` |
424
435
  | `docker.io` | `DOCKERHUB_USERNAME` | `DOCKERHUB_PASSWORD` |
425
436
  | `quay.io` | `QUAY_USERNAME` | `QUAY_PASSWORD` |
426
437
  | `ghcr.io` | `GHCR_USERNAME` | `GHCR_PASSWORD` |
@@ -428,7 +439,9 @@ Each package is tagged independently using its own version, so packages in a mon
428
439
 
429
440
  When `package.json#repository` and `.tooling.json#registryHost` are both absent the generator falls back to neutral `REGISTRY_USERNAME` / `REGISTRY_PASSWORD`.
430
441
 
431
- This rename exists because Forgejo's [act fork auto-injects](https://code.forgejo.org/forgejo/runner/src/branch/main/act/runner/run_context.go#L1437) `secrets.DOCKER_USERNAME` / `secrets.DOCKER_PASSWORD` into every `container:` image pull regardless of the target registry, so reusing those generic names across multiple registries causes confusing "denied" / "incorrect username or password" errors. The registry-specific names defeat the auto-injection trigger.
442
+ Registry-specific names keep one credential per registry, so a repo publishing to more than one never has to decide which registry the generic pair belongs to.
443
+
444
+ **Names a forge will not accept.** A secret name must match `[A-Za-z_][A-Za-z0-9_]*` and must not start with `FORGEJO_`, `GITEA_`, `GITHUB_`, or a digit -- Forgejo answers `invalid secret name` and refuses to create it. The generator sanitizes every derived name against those rules, which is why `code.orangebikelabs.com` is `OBL_REGISTRY_*` rather than the `FORGEJO_*` the hostname would suggest, and why a host like `10.0.0.5:5000` or `forgejo.example.com` derives a `REGISTRY_`-prefixed name. `bst forgejo:secrets set` refuses an invalid name up front rather than passing it to the API.
432
445
 
433
446
  **Forgejo setup:** On Forgejo, the username secret is your Forgejo account username, and the password secret can reuse the same token as `RELEASE_TOKEN`. The token needs write permissions on the org, package, and repository scopes. These permissions should be set for the **user** if the package is under a user namespace (e.g. `bensandee`), or the **organization** if it's under an org namespace (e.g. `orangebikelabs`). After migrating, the old `DOCKER_USERNAME` / `DOCKER_PASSWORD` user/org-level secrets can be deleted once every consumer has been regenerated.
434
447