@rtorcato/js-tooling 2.18.0 → 2.19.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.
package/README.md
CHANGED
|
@@ -17,12 +17,65 @@ Most tooling libraries give you one piece — just TypeScript configs, or just a
|
|
|
17
17
|
|
|
18
18
|
**[Full documentation →](https://rtorcato.github.io/js-tooling/)**
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Start a new project
|
|
21
|
+
|
|
22
|
+
Interactive wizard — answers every prompt, scaffolds the whole project:
|
|
21
23
|
|
|
22
24
|
```bash
|
|
23
25
|
npx @rtorcato/js-tooling setup
|
|
24
26
|
```
|
|
25
27
|
|
|
28
|
+
Non-interactive — scaffold from a named preset in one shot (CI-friendly):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx @rtorcato/js-tooling setup --preset library -d ./my-lib --skip-install
|
|
32
|
+
# presets: library | web-app | node-api | nextjs-app | react-app
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Just one config file? Use `copy`:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @rtorcato/js-tooling copy biome # → biome.json
|
|
39
|
+
npx @rtorcato/js-tooling copy tsconfig # → tsconfig.json
|
|
40
|
+
npx @rtorcato/js-tooling copy changesets # → .changeset/config.json
|
|
41
|
+
npx @rtorcato/js-tooling copy oxlint # → .oxlintrc.json
|
|
42
|
+
npx @rtorcato/js-tooling copy claude-skill # → .claude/skills/js-tooling.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Already have a project?** Don't rerun `setup` — use `doctor` + `fix`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx @rtorcato/js-tooling doctor # find what's missing or drifted
|
|
49
|
+
npx @rtorcato/js-tooling fix # apply scaffolders, prompting per item
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
See the [Getting Started guide](https://rtorcato.github.io/js-tooling/guides/getting-started/) for the full walkthrough.
|
|
53
|
+
|
|
54
|
+
## AI agent rules
|
|
55
|
+
|
|
56
|
+
The package ships rules that teach AI coding agents to drive the CLI
|
|
57
|
+
(`doctor` / `fix` / `setup`) non-interactively. Install for your agent — all
|
|
58
|
+
generated from one source, so guidance never drifts between them:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx @rtorcato/js-tooling fix claude-skill --yes # → .claude/skills/js-tooling.md
|
|
62
|
+
npx @rtorcato/js-tooling fix cursor-rules --yes # → .cursor/rules/js-tooling.mdc
|
|
63
|
+
npx @rtorcato/js-tooling fix copilot-instructions --yes # → .github/copilot-instructions.md
|
|
64
|
+
npx @rtorcato/js-tooling fix agents-md --yes # → AGENTS.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`copilot-instructions` and `agents-md` upsert a delimited block, so your own
|
|
68
|
+
content in those shared files is never clobbered. Re-running updates the block
|
|
69
|
+
in place on upgrade.
|
|
70
|
+
|
|
71
|
+
Prefer a symlink that auto-syncs the Claude skill on every upgrade?
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
mkdir -p .claude/skills
|
|
75
|
+
ln -sf ../../node_modules/@rtorcato/js-tooling/tooling/claude/js-tooling.md \
|
|
76
|
+
.claude/skills/js-tooling.md
|
|
77
|
+
```
|
|
78
|
+
|
|
26
79
|
## What's new
|
|
27
80
|
|
|
28
81
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
@@ -716,28 +716,28 @@ async function checkAreTheTypesWrong(_dir, pkg) {
|
|
|
716
716
|
...(pkg?.devDependencies ?? {}),
|
|
717
717
|
};
|
|
718
718
|
const scripts = pkg?.scripts ?? {};
|
|
719
|
-
const hasDep = !!deps['
|
|
720
|
-
const hasScript = Object.values(scripts).some((s) => /\battw\b
|
|
719
|
+
const hasDep = !!deps['@arethetypeswrong/cli'];
|
|
720
|
+
const hasScript = Object.values(scripts).some((s) => /\battw\b/.test(s));
|
|
721
721
|
if (hasDep && hasScript) {
|
|
722
722
|
return {
|
|
723
723
|
check: 'are-the-types-wrong',
|
|
724
724
|
status: 'ok',
|
|
725
|
-
detail: '
|
|
725
|
+
detail: '@arethetypeswrong/cli installed and wired into a script',
|
|
726
726
|
};
|
|
727
727
|
}
|
|
728
728
|
if (hasDep) {
|
|
729
729
|
return {
|
|
730
730
|
check: 'are-the-types-wrong',
|
|
731
731
|
status: 'drift',
|
|
732
|
-
detail: '
|
|
733
|
-
hint: '
|
|
732
|
+
detail: '@arethetypeswrong/cli installed but no script runs it',
|
|
733
|
+
hint: 'Run `npx @rtorcato/js-tooling fix attw` to add an `attw` script and wire it into verify',
|
|
734
734
|
};
|
|
735
735
|
}
|
|
736
736
|
return {
|
|
737
737
|
check: 'are-the-types-wrong',
|
|
738
738
|
status: 'optional-missing',
|
|
739
|
-
detail: '
|
|
740
|
-
hint: 'Run `
|
|
739
|
+
detail: '@arethetypeswrong/cli not configured',
|
|
740
|
+
hint: 'Run `npx @rtorcato/js-tooling fix attw` to validate TypeScript exports before publishing',
|
|
741
741
|
};
|
|
742
742
|
}
|
|
743
743
|
async function checkTreeshakeSetup(dir, pkg) {
|
package/dist/cli/commands/fix.js
CHANGED
|
@@ -4,6 +4,7 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { createPatch } from 'diff';
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
6
|
import inquirer from 'inquirer';
|
|
7
|
+
import { installAgentRules } from '../generators/agent-rules.js';
|
|
7
8
|
import { generateSemanticReleaseConfig } from '../generators/build.js';
|
|
8
9
|
import { generateCommitlintConfig, generateHuskyConfig, generatePrePushHook, } from '../generators/git.js';
|
|
9
10
|
import { generateGitHubActions } from '../generators/github-actions.js';
|
|
@@ -59,6 +60,24 @@ async function readPackageJson(dir) {
|
|
|
59
60
|
return null;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
63
|
+
/** True when any (possibly nested) exports condition declares a `require`/CJS entry. */
|
|
64
|
+
function hasRequireCondition(exports) {
|
|
65
|
+
if (!exports || typeof exports !== 'object')
|
|
66
|
+
return false;
|
|
67
|
+
for (const value of Object.values(exports)) {
|
|
68
|
+
if (value && typeof value === 'object') {
|
|
69
|
+
if ('require' in value)
|
|
70
|
+
return true;
|
|
71
|
+
if (hasRequireCondition(value))
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/** ESM-only = `"type": "module"` and no CJS/`require` resolution in exports. */
|
|
78
|
+
function isEsmOnly(pkg) {
|
|
79
|
+
return pkg.type === 'module' && !hasRequireCondition(pkg.exports);
|
|
80
|
+
}
|
|
62
81
|
const FIXERS = [
|
|
63
82
|
{
|
|
64
83
|
target: 'biome',
|
|
@@ -408,6 +427,86 @@ const FIXERS = [
|
|
|
408
427
|
return { filesWritten };
|
|
409
428
|
},
|
|
410
429
|
},
|
|
430
|
+
{
|
|
431
|
+
target: 'attw',
|
|
432
|
+
description: 'Install @arethetypeswrong/cli + add an `attw` script (esm-only profile when applicable) and wire it into verify',
|
|
433
|
+
appliesTo: ['are-the-types-wrong'],
|
|
434
|
+
outputs: ['package.json (devDependencies + scripts.attw)'],
|
|
435
|
+
riskLevel: 'safe-merge',
|
|
436
|
+
canFixDrift: true,
|
|
437
|
+
async run({ targetDir, pkg }) {
|
|
438
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
439
|
+
if (!pkg) {
|
|
440
|
+
console.log(chalk.yellow(' no package.json found — skipping'));
|
|
441
|
+
return { filesWritten: [] };
|
|
442
|
+
}
|
|
443
|
+
const updated = { ...pkg };
|
|
444
|
+
const devDeps = {
|
|
445
|
+
...(updated.devDependencies ?? {}),
|
|
446
|
+
};
|
|
447
|
+
if (!devDeps['@arethetypeswrong/cli'])
|
|
448
|
+
devDeps['@arethetypeswrong/cli'] = '^0.18.2';
|
|
449
|
+
updated.devDependencies = devDeps;
|
|
450
|
+
const scripts = { ...(updated.scripts ?? {}) };
|
|
451
|
+
scripts.attw = isEsmOnly(pkg) ? 'attw --pack --profile esm-only' : 'attw --pack';
|
|
452
|
+
if (scripts.verify && !/\battw\b/.test(scripts.verify)) {
|
|
453
|
+
scripts.verify = `${scripts.verify} && pnpm attw`;
|
|
454
|
+
}
|
|
455
|
+
updated.scripts = scripts;
|
|
456
|
+
await fs.writeJson(pkgPath, updated, { spaces: 2 });
|
|
457
|
+
return { filesWritten: ['package.json'] };
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
target: 'claude-skill',
|
|
462
|
+
description: 'Install the js-tooling Claude Code skill into .claude/skills/',
|
|
463
|
+
appliesTo: ['Claude skill'],
|
|
464
|
+
outputs: ['.claude/skills/js-tooling.md'],
|
|
465
|
+
riskLevel: 'safe-add',
|
|
466
|
+
canFixDrift: true,
|
|
467
|
+
async run({ targetDir }) {
|
|
468
|
+
const result = await copyPreset('claude-skill', targetDir);
|
|
469
|
+
return { filesWritten: [result.target] };
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
target: 'cursor-rules',
|
|
474
|
+
description: 'Install the js-tooling rules for Cursor (.cursor/rules/js-tooling.mdc)',
|
|
475
|
+
appliesTo: ['Cursor rules'],
|
|
476
|
+
outputs: ['.cursor/rules/js-tooling.mdc'],
|
|
477
|
+
riskLevel: 'safe-add',
|
|
478
|
+
canFixDrift: true,
|
|
479
|
+
async run({ targetDir }) {
|
|
480
|
+
const written = await installAgentRules(targetDir, 'cursor');
|
|
481
|
+
return { filesWritten: [written] };
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
target: 'copilot-instructions',
|
|
486
|
+
description: 'Install the js-tooling rules for GitHub Copilot (.github/copilot-instructions.md)',
|
|
487
|
+
appliesTo: ['Copilot instructions'],
|
|
488
|
+
outputs: ['.github/copilot-instructions.md'],
|
|
489
|
+
// Upserts a delimited block — never clobbers the consumer's own instructions.
|
|
490
|
+
riskLevel: 'safe-merge',
|
|
491
|
+
canFixDrift: true,
|
|
492
|
+
async run({ targetDir }) {
|
|
493
|
+
const written = await installAgentRules(targetDir, 'copilot');
|
|
494
|
+
return { filesWritten: [written] };
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
target: 'agents-md',
|
|
499
|
+
description: 'Install the js-tooling rules into AGENTS.md (universal agent instructions)',
|
|
500
|
+
appliesTo: ['AGENTS.md rules'],
|
|
501
|
+
outputs: ['AGENTS.md'],
|
|
502
|
+
// Upserts a delimited block — never clobbers existing AGENTS.md content.
|
|
503
|
+
riskLevel: 'safe-merge',
|
|
504
|
+
canFixDrift: true,
|
|
505
|
+
async run({ targetDir }) {
|
|
506
|
+
const written = await installAgentRules(targetDir, 'agents-md');
|
|
507
|
+
return { filesWritten: [written] };
|
|
508
|
+
},
|
|
509
|
+
},
|
|
411
510
|
{
|
|
412
511
|
target: 'package-json',
|
|
413
512
|
description: 'Add @rtorcato/js-tooling to devDependencies',
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import { getPackageRoot } from '../utils/copy-preset.js';
|
|
4
|
+
/**
|
|
5
|
+
* All agent rule files are generated from one source of truth — the shipped
|
|
6
|
+
* Claude skill — so the guidance never drifts between agents. Only the
|
|
7
|
+
* location and the frontmatter differ per agent.
|
|
8
|
+
*/
|
|
9
|
+
const SOURCE = 'tooling/claude/js-tooling.md';
|
|
10
|
+
const BLOCK_START = '<!-- js-tooling:start -->';
|
|
11
|
+
const BLOCK_END = '<!-- js-tooling:end -->';
|
|
12
|
+
/** Read the shipped skill and split its frontmatter from the markdown body. */
|
|
13
|
+
async function readSkill() {
|
|
14
|
+
const raw = await fs.readFile(path.join(getPackageRoot(), SOURCE), 'utf8');
|
|
15
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
16
|
+
if (!match)
|
|
17
|
+
return { description: '', body: raw.trim() };
|
|
18
|
+
const description = (match[1].match(/^description:\s*(.+)$/m)?.[1] ?? '').trim();
|
|
19
|
+
return { description, body: match[2].trim() };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Upsert a delimited js-tooling block into a file that may already hold the
|
|
23
|
+
* consumer's own content (AGENTS.md, copilot-instructions). Replaces an
|
|
24
|
+
* existing block, appends if the file exists without one, creates otherwise.
|
|
25
|
+
* Never clobbers surrounding content.
|
|
26
|
+
*/
|
|
27
|
+
async function upsertBlock(filePath, body) {
|
|
28
|
+
const block = `${BLOCK_START}\n${body}\n${BLOCK_END}`;
|
|
29
|
+
if (await fs.pathExists(filePath)) {
|
|
30
|
+
const existing = await fs.readFile(filePath, 'utf8');
|
|
31
|
+
const start = existing.indexOf(BLOCK_START);
|
|
32
|
+
const end = existing.indexOf(BLOCK_END);
|
|
33
|
+
if (start !== -1 && end !== -1) {
|
|
34
|
+
const next = existing.slice(0, start) + block + existing.slice(end + BLOCK_END.length);
|
|
35
|
+
await fs.writeFile(filePath, next);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await fs.writeFile(filePath, `${existing.trimEnd()}\n\n${block}\n`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
42
|
+
await fs.writeFile(filePath, `${block}\n`);
|
|
43
|
+
}
|
|
44
|
+
/** Install the js-tooling rules for one agent. Returns the written path (relative). */
|
|
45
|
+
export async function installAgentRules(targetDir, agent) {
|
|
46
|
+
const { description, body } = await readSkill();
|
|
47
|
+
switch (agent) {
|
|
48
|
+
case 'cursor': {
|
|
49
|
+
const rel = path.join('.cursor', 'rules', 'js-tooling.mdc');
|
|
50
|
+
const file = path.join(targetDir, rel);
|
|
51
|
+
const frontmatter = `---\ndescription: ${description}\nglobs:\nalwaysApply: false\n---\n\n`;
|
|
52
|
+
await fs.ensureDir(path.dirname(file));
|
|
53
|
+
await fs.writeFile(file, `${frontmatter}${body}\n`);
|
|
54
|
+
return rel;
|
|
55
|
+
}
|
|
56
|
+
case 'copilot': {
|
|
57
|
+
const rel = path.join('.github', 'copilot-instructions.md');
|
|
58
|
+
await upsertBlock(path.join(targetDir, rel), body);
|
|
59
|
+
return rel;
|
|
60
|
+
}
|
|
61
|
+
case 'agents-md': {
|
|
62
|
+
const rel = 'AGENTS.md';
|
|
63
|
+
await upsertBlock(path.join(targetDir, rel), body);
|
|
64
|
+
return rel;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -21,6 +21,11 @@ export const PRESETS = {
|
|
|
21
21
|
target: 'tsconfig.json',
|
|
22
22
|
desc: 'TypeScript base configuration',
|
|
23
23
|
},
|
|
24
|
+
'claude-skill': {
|
|
25
|
+
source: 'tooling/claude/js-tooling.md',
|
|
26
|
+
target: '.claude/skills/js-tooling.md',
|
|
27
|
+
desc: 'Claude Code skill for driving the js-tooling CLI',
|
|
28
|
+
},
|
|
24
29
|
};
|
|
25
30
|
export function getPackageRoot() {
|
|
26
31
|
const cliFile = new URL(import.meta.url).pathname;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rtorcato/js-tooling",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"description": "JavaScript and TypeScript tooling for Node.js, React, Next.js, and Vitest.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"tooling/typedoc/typedoc.json",
|
|
79
79
|
"tooling/semantic-release/*.mjs",
|
|
80
80
|
"tooling/semantic-release/*.d.mts",
|
|
81
|
+
"tooling/claude/*.md",
|
|
81
82
|
"README.md"
|
|
82
83
|
],
|
|
83
84
|
"exports": {
|
|
@@ -199,8 +200,8 @@
|
|
|
199
200
|
"@total-typescript/ts-reset": "0.6.1",
|
|
200
201
|
"@types/fs-extra": "^11.0.4",
|
|
201
202
|
"@types/node": "^25.9.2",
|
|
202
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
203
|
-
"@typescript-eslint/parser": "^8.
|
|
203
|
+
"@typescript-eslint/eslint-plugin": "^8.61.1",
|
|
204
|
+
"@typescript-eslint/parser": "^8.61.1",
|
|
204
205
|
"@vitejs/plugin-react": "^5.1.0",
|
|
205
206
|
"@vitest/coverage-v8": "^4.0.3",
|
|
206
207
|
"commitizen": "^4.3.1",
|
|
@@ -208,9 +209,9 @@
|
|
|
208
209
|
"cz-conventional-changelog": "^3.3.0",
|
|
209
210
|
"esbuild": "^0.28.0",
|
|
210
211
|
"esbuild-node-externals": "^1.22.0",
|
|
211
|
-
"eslint": "
|
|
212
|
+
"eslint": "10.5.0",
|
|
212
213
|
"eslint-plugin-import": "^2.32.0",
|
|
213
|
-
"eslint-plugin-jest": "29.
|
|
214
|
+
"eslint-plugin-jest": "29.15.2",
|
|
214
215
|
"husky": "^9.1.7",
|
|
215
216
|
"is-ci": "^4.1.0",
|
|
216
217
|
"jest": "^29.7.0",
|
|
@@ -223,7 +224,7 @@
|
|
|
223
224
|
"ts-jest": "^29.4.11",
|
|
224
225
|
"tsup": "8.5.1",
|
|
225
226
|
"typescript": "^5.9.3",
|
|
226
|
-
"typescript-eslint": "^8.
|
|
227
|
+
"typescript-eslint": "^8.61.1",
|
|
227
228
|
"vitest": "^4.1.8"
|
|
228
229
|
},
|
|
229
230
|
"peerDependencies": {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: js-tooling
|
|
3
|
+
description: Use when auditing or fixing TypeScript/JavaScript project tooling in a repo that depends on @rtorcato/js-tooling, or scaffolding a new project with it. Triggers on "audit my tooling", "fix tooling drift", "is my tsconfig/biome/vitest config right", "set up CI/semantic-release/dependabot", "scaffold a TS library/web-app/node-api", "run doctor", "run fix", or "/js-tooling". Drives the `@rtorcato/js-tooling` CLI non-interactively (--json --yes). NOT for hand-editing configs the CLI owns — let the CLI scaffold them so they stay in sync with the presets.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# js-tooling
|
|
7
|
+
|
|
8
|
+
`@rtorcato/js-tooling` is a single-package TS/JS tooling distribution: every preset
|
|
9
|
+
(TypeScript, Biome, ESLint, Prettier, Vitest/Jest, Commitlint, semantic-release,
|
|
10
|
+
tsup/esbuild/Vite/Playwright) plus a CLI to scaffold and audit. Prefer the CLI over
|
|
11
|
+
hand-editing the configs it owns — a manual edit drifts from the preset and `doctor`
|
|
12
|
+
will flag it.
|
|
13
|
+
|
|
14
|
+
Every command takes `--json` and a non-interactive mode; pair with `--yes` for
|
|
15
|
+
autonomous use. `--json` implies `--yes` (a prompt would corrupt the JSON).
|
|
16
|
+
|
|
17
|
+
Run via `npx @rtorcato/js-tooling <cmd>` (or the local `js-tooling` bin if installed).
|
|
18
|
+
`-d <dir>` targets a directory other than cwd.
|
|
19
|
+
|
|
20
|
+
## The two workflows you'll use most
|
|
21
|
+
|
|
22
|
+
### Audit → fix → confirm (existing repo)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @rtorcato/js-tooling doctor --json # findings
|
|
26
|
+
npx @rtorcato/js-tooling fix --yes --json # apply every fixable finding
|
|
27
|
+
npx @rtorcato/js-tooling doctor --json # confirm clean
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`doctor` returns `{ directory, results: [{ check, status, detail, hint? }] }`.
|
|
31
|
+
Status is one of:
|
|
32
|
+
- `ok` — configured correctly, nothing to do.
|
|
33
|
+
- `drift` — file exists but doesn't extend our preset. `fix` defaults the overwrite
|
|
34
|
+
prompt to **No**; `--yes` is required to overwrite.
|
|
35
|
+
- `missing` — required and absent → fix it.
|
|
36
|
+
- `optional-missing` — opt-in tool not configured. Only fix if the user wants that tool.
|
|
37
|
+
|
|
38
|
+
`fix` returns `FixActionRecord[]` with `status: applied | dry-run | skipped | already-ok | unsupported`.
|
|
39
|
+
|
|
40
|
+
### Targeted fix (one concern)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx @rtorcato/js-tooling list --json # enumerate targets
|
|
44
|
+
npx @rtorcato/js-tooling fix <target> --yes --json # e.g. biome, vitest, dependabot, attw
|
|
45
|
+
npx @rtorcato/js-tooling fix <target> --dry-run --json # preview writes
|
|
46
|
+
npx @rtorcato/js-tooling fix <target> --diff # unified diff before confirming
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`list --json` is the source of truth for valid targets — read it, don't guess.
|
|
50
|
+
|
|
51
|
+
## Scaffolding a new project
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Quick: from a named preset (library | web-app | node-api | nextjs-app | react-app)
|
|
55
|
+
npx @rtorcato/js-tooling setup --preset library -d ./my-lib --skip-install
|
|
56
|
+
|
|
57
|
+
# Full control: validate a config against the schema, preview, then write
|
|
58
|
+
npx @rtorcato/js-tooling setup --config-schema > project-config.schema.json
|
|
59
|
+
npx @rtorcato/js-tooling setup --config project.json --dry-run # preview file list
|
|
60
|
+
npx @rtorcato/js-tooling setup --config project.json -d ./my-lib --skip-install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Drift policy (don't surprise the user)
|
|
64
|
+
|
|
65
|
+
- Safe-merge fixers (`engines`, `husky`, `package-json`) never overwrite — they add/merge.
|
|
66
|
+
- Drift on a config file (`biome`, `tsconfig`, …) is only overwritten with `--yes`.
|
|
67
|
+
Before overwriting drift the user wrote by hand, show `fix <target> --diff` first.
|
|
68
|
+
- `optional-missing` ≠ broken. Don't install opt-in tools (typedoc, size-limit,
|
|
69
|
+
treeshake-check, attw, codeql) unless the user asked for that capability.
|
|
70
|
+
|
|
71
|
+
## Rules
|
|
72
|
+
|
|
73
|
+
- Let the CLI own its configs. If `doctor` says `drift`, fix via the CLI, don't hand-patch.
|
|
74
|
+
- Use `--json` whenever you'll parse the result; use `--dry-run`/`--diff` before any
|
|
75
|
+
destructive overwrite.
|
|
76
|
+
- After a `fix`, re-run `doctor` to confirm the finding cleared.
|
|
77
|
+
|
|
78
|
+
Full docs: https://rtorcato.github.io/js-tooling/guides/cli/
|