@rtorcato/repo-tooling 4.8.0 → 5.0.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/AGENTS.md CHANGED
@@ -84,7 +84,6 @@ npx @rtorcato/repo-tooling doctor --json -d ./existing-repo
84
84
  # Apply one fixer from the list (run `list --json` for every target)
85
85
  npx @rtorcato/repo-tooling fix dependabot --yes --json
86
86
  npx @rtorcato/repo-tooling fix engines --yes --json
87
- npx @rtorcato/repo-tooling fix docs-site --yes --json # scaffold a Docusaurus docs site under apps/docs
88
87
  npx @rtorcato/repo-tooling fix bun --yes --json # Bun runtime/test config
89
88
  ```
90
89
 
@@ -100,81 +100,6 @@ export async function checkCommunityHealth(dir) {
100
100
  hint: 'Run `npx @rtorcato/repo-tooling fix community-health` to scaffold them',
101
101
  };
102
102
  }
103
- const BRAND_HINT = 'Run `npx @rtorcato/repo-tooling fix brand` to scaffold brand/ (SVG sources + render.sh) and render the PNGs (needs librsvg)';
104
- /** The two banners the README consumes — the pair `brand/` exists to keep regenerable. */
105
- const BANNERS = ['banner', 'banner-mobile'];
106
- /**
107
- * Brand assets (#395). A committed PNG with no SVG beside it can't be
108
- * recoloured, retitled or resized — which was the state of every repo in the
109
- * family but one. Three signals, all language-agnostic:
110
- *
111
- * 1. a rendered banner with no `brand/<name>.svg` source
112
- * 2. a `brand/` folder with no `render.sh` — sources nobody can render
113
- * 3. a README still pointing at the pre-amendment root-level `./banner.png`
114
- *
115
- * A repo with no brand images at all is `optional-missing`, not a finding:
116
- * there's nothing broken to fix, and banners are opt-in.
117
- */
118
- export async function checkBrand(dir) {
119
- const check = 'Brand assets';
120
- const has = (rel) => fs.pathExists(path.join(dir, rel));
121
- const problems = [];
122
- const orphans = [];
123
- for (const name of BANNERS) {
124
- const rendered = (await has(`${name}.png`)) || (await has(`brand/${name}.png`));
125
- if (rendered && !(await has(`brand/${name}.svg`)))
126
- orphans.push(`${name}.png`);
127
- }
128
- if (orphans.length > 0) {
129
- problems.push(`${orphans.join(' + ')} committed with no brand/*.svg source`);
130
- }
131
- const brandDir = await has('brand');
132
- if (brandDir && !(await has('brand/render.sh'))) {
133
- problems.push('brand/ has no render.sh — the PNGs cannot be regenerated');
134
- }
135
- const readmePath = path.join(dir, 'README.md');
136
- if (await fs.pathExists(readmePath)) {
137
- const readme = await fs.readFile(readmePath, 'utf-8');
138
- if (/(?<!brand\/)banner(?:-mobile)?\.png/.test(readme)) {
139
- problems.push('README points at root-level banner PNGs (the spec moved them to brand/)');
140
- }
141
- }
142
- if (problems.length > 0) {
143
- return { check, status: 'drift', detail: problems.join('; '), hint: BRAND_HINT };
144
- }
145
- // Name the pieces still missing (#679). Severity is unchanged: brand is optional.
146
- const missing = [];
147
- if (!(await has('brand/favicon.svg')))
148
- missing.push('favicon (brand/favicon.svg)');
149
- const unrendered = [];
150
- for (const n of ['banner', 'banner-mobile', 'social-card', 'favicon-512']) {
151
- if (!(await has(`brand/${n}.png`)))
152
- unrendered.push(`${n}.png`);
153
- }
154
- if (unrendered.length > 0)
155
- missing.push(`rendered PNGs (brand/${unrendered.join(', ')})`);
156
- const readmeFile = path.join(dir, 'README.md');
157
- const readmeText = (await fs.pathExists(readmeFile)) ? await fs.readFile(readmeFile, 'utf-8') : '';
158
- if (!/brand\/banner(?:-mobile)?\.png/.test(readmeText))
159
- missing.push('README banner');
160
- if (!brandDir) {
161
- return {
162
- check,
163
- status: 'optional-missing',
164
- detail: `no brand/ folder — missing: ${missing.join('; ')}`,
165
- hint: BRAND_HINT,
166
- };
167
- }
168
- if (missing.length > 0) {
169
- return {
170
- check,
171
- status: 'ok',
172
- detail: `brand/ holds the SVG sources and render.sh; missing: ${missing.join('; ')}`,
173
- hint: BRAND_HINT,
174
- };
175
- }
176
- return { check, status: 'ok', detail: 'brand/ holds the SVG sources and render.sh' };
177
- }
178
103
  /**
179
104
  * `org/action@vN`, the only form the generators emit. Same shape as the scan in
180
105
  * tests/cli/generators/action-pins.test.ts — major-only, because that's the
@@ -15,7 +15,6 @@ import path from 'node:path';
15
15
  import chalk from 'chalk';
16
16
  import fs from 'fs-extra';
17
17
  import { installAgentRules, installAiSetup } from '../cli/generators/agent-rules.js';
18
- import { addReadmeBanner, generateBrand, renderBrand, resolveBrandMeta, syncBrandToDocs, } from '../cli/generators/brand.js';
19
18
  import { generateCommunityHealth } from '../cli/generators/community-health.js';
20
19
  import { generateCommitlintConfig } from '../cli/generators/git.js';
21
20
  import { generateCodeowners, generateEditorConfig } from '../cli/generators/misc.js';
@@ -247,41 +246,6 @@ export const BASE_FIXERS = [
247
246
  return { filesWritten };
248
247
  },
249
248
  },
250
- {
251
- target: 'brand',
252
- selfSafe: true,
253
- description: 'Scaffold brand/ — favicon, banner, mobile-banner and social-card SVG sources + render.sh — render the PNGs and favicon.ico when rsvg-convert is on PATH, and add the README banner',
254
- appliesTo: ['Brand assets'],
255
- outputs: [
256
- 'brand/favicon.svg',
257
- 'brand/banner.svg',
258
- 'brand/banner-mobile.svg',
259
- 'brand/social-card.svg',
260
- 'brand/render.sh',
261
- 'brand/banner.png',
262
- 'brand/banner-mobile.png',
263
- 'brand/social-card.png',
264
- 'brand/favicon-512.png',
265
- 'brand/favicon.ico',
266
- 'README.md',
267
- ],
268
- // Every SVG is written only when absent, PNGs are re-rendered only when
269
- // older than their source, and the README edit is a delimited block (or
270
- // two image paths) — hand-edited art is never clobbered.
271
- riskLevel: 'safe-merge',
272
- canFixDrift: true,
273
- async run({ targetDir, pkg, lock }) {
274
- const tagline = lock?.rules?.brand?.tagline;
275
- const filesWritten = await generateBrand(pkg, targetDir, tagline);
276
- filesWritten.push(...((await renderBrand(targetDir)) ?? []));
277
- filesWritten.push(...(await syncBrandToDocs(targetDir)));
278
- const { name } = await resolveBrandMeta(pkg, targetDir, tagline);
279
- const readme = await addReadmeBanner(targetDir, name);
280
- if (readme && !filesWritten.includes(readme))
281
- filesWritten.push(readme);
282
- return { filesWritten };
283
- },
284
- },
285
249
  {
286
250
  target: 'ai',
287
251
  description: 'Install all AI agent files at once (AGENTS.md, CLAUDE.md, Cursor, Copilot, Claude skill, MCP example)',
@@ -21,8 +21,8 @@ import { checkCopiedAssets } from '../utils/copied-assets.js';
21
21
  import { LOCKFILE_VERSION, readLockfile } from '../utils/lockfile.js';
22
22
  import { compareRulesWithReference } from '../utils/reference-rules.js';
23
23
  import { declinedInLock, getFixTargetForCheck } from './fix-targets.js';
24
- import { checkAiSetup, checkBrand, checkCodeowners, checkCodeQL, checkCommunityHealth, checkCoverageUpload, checkDependabot, checkEditorConfig, checkFile, checkGitHooks, checkGitHubActions, checkGitLabCI, checkNestedLanguages, checkPrePushHook, checkReadmeBadges, checkRecommendedMcp, COMMITLINT_FILE_CHECK, } from '../../base/checks.js';
25
- import { allDeps, checkAreTheTypesWrong, checkBiome, checkClaudeWorktreeSettings, checkConfigSchemaVersions, checkDocsSite, checkEnginesNode, checkExportsBuildable, checkGitDependencies, checkKnip, checkLintStaged, checkNodeVersionConsistency, checkNodeVersionPin, checkPackageJson, checkPackageManager, checkPeerVersions, checkPublint, checkSemanticRelease, checkSizeLimit, checkTailwind, checkBuildApprovals, checkPnpmWorkspace, checkTreeshakeSetup, checkTurborepo, checkTypedoc, checkVerifyScript, checkVscodeExtensions, evaluateNodeVersion, FILE_CHECKS, findDocsAppDir, jsBadgeAudience, jsGitHooksProfile, readPackageJson, } from '../../languages/js/checks.js';
24
+ import { checkAiSetup, checkCodeowners, checkCodeQL, checkCommunityHealth, checkCoverageUpload, checkDependabot, checkEditorConfig, checkFile, checkGitHooks, checkGitHubActions, checkGitLabCI, checkNestedLanguages, checkPrePushHook, checkReadmeBadges, checkRecommendedMcp, COMMITLINT_FILE_CHECK, } from '../../base/checks.js';
25
+ import { allDeps, checkAreTheTypesWrong, checkBiome, checkClaudeWorktreeSettings, checkConfigSchemaVersions, checkEnginesNode, checkExportsBuildable, checkGitDependencies, checkKnip, checkLintStaged, checkNodeVersionConsistency, checkNodeVersionPin, checkPackageJson, checkPackageManager, checkPeerVersions, checkPublint, checkSemanticRelease, checkSizeLimit, checkTailwind, checkBuildApprovals, checkPnpmWorkspace, checkTreeshakeSetup, checkTurborepo, checkTypedoc, checkVerifyScript, checkVscodeExtensions, evaluateNodeVersion, FILE_CHECKS, jsBadgeAudience, jsGitHooksProfile, readPackageJson, } from '../../languages/js/checks.js';
26
26
  export { evaluateNodeVersion };
27
27
  const PACKAGE = '@rtorcato/repo-tooling';
28
28
  // Detects the broken-release-on-protected-main footgun: a workflow that runs
@@ -218,7 +218,6 @@ async function runBaseChecks(dir, lock, opts) {
218
218
  results.push(await checkGitLabCI(dir));
219
219
  results.push(await checkCodeowners(dir));
220
220
  results.push(await checkCommunityHealth(dir));
221
- results.push(await checkBrand(dir));
222
221
  results.push(await checkAiSetup(dir));
223
222
  // #534: advisory. Absent `mcp.recommended` means the repo has nothing to say
224
223
  // about MCP, which is not a finding.
@@ -375,11 +374,6 @@ export async function runDoctor(dir) {
375
374
  if (await fs.pathExists(path.join(targetDir, 'pnpm-workspace.yaml'))) {
376
375
  results.push(await checkTurborepo(targetDir));
377
376
  }
378
- // Docs site is opt-in — only surface the check when a Docusaurus site exists.
379
- const docsAppDir = await findDocsAppDir(targetDir);
380
- if (docsAppDir) {
381
- results.push(await checkDocsSite(targetDir, docsAppDir));
382
- }
383
377
  // Tailwind is opt-in — only surface the check when the repo actually depends on it.
384
378
  if ('tailwindcss' in allDeps(pkg)) {
385
379
  results.push(await checkTailwind(targetDir, pkg));
@@ -45,7 +45,6 @@ export const FIX_TARGETS = {
45
45
  'are-the-types-wrong': 'attw',
46
46
  publint: 'publint',
47
47
  'README badges': 'badges',
48
- 'Brand assets': 'brand',
49
48
  TypeDoc: 'typedoc',
50
49
  'AI setup': 'ai',
51
50
  'Claude worktree settings': 'ai',
@@ -177,8 +176,6 @@ export function declinedInLock(lock, checkName) {
177
176
  return c.turborepo === false;
178
177
  case 'Tailwind':
179
178
  return c.tailwind === false;
180
- case 'Brand assets':
181
- return c.brand === false;
182
179
  default:
183
180
  return false;
184
181
  }
@@ -248,12 +245,8 @@ export function lockfilePatchForTarget(target, lock) {
248
245
  return c.nx ? null : { nx: true };
249
246
  case 'tailwind':
250
247
  return c.tailwind ? null : { tailwind: true };
251
- case 'docs-site':
252
- return c.docsSite ? null : { docsSite: true };
253
248
  case 'bun':
254
249
  return c.bun ? null : { bun: true };
255
- case 'brand':
256
- return c.brand ? null : { brand: true };
257
250
  default:
258
251
  return null;
259
252
  }
@@ -59,7 +59,6 @@ export function buildPresetConfig(name, projectName) {
59
59
  semanticRelease: true,
60
60
  bundler: 'tsup',
61
61
  publint: true,
62
- brand: true,
63
62
  };
64
63
  case 'web-app':
65
64
  return {
@@ -210,8 +209,9 @@ export const CONFIG_SCHEMA = {
210
209
  turborepo: { type: 'boolean' },
211
210
  nx: { type: 'boolean' },
212
211
  tailwind: { type: 'boolean' },
213
- docsSite: { type: 'boolean' },
214
- brand: { type: 'boolean' },
212
+ // Deprecated (#718): both scaffolds moved to @rtorcato/shared-docs. Accepted, inert.
213
+ docsSite: { type: 'boolean', deprecated: true },
214
+ brand: { type: 'boolean', deprecated: true },
215
215
  bun: { type: 'boolean' },
216
216
  },
217
217
  };
@@ -317,8 +317,6 @@ export function computeFileList(config) {
317
317
  files.push('postcss.config.mjs', 'src/styles/globals.css');
318
318
  if (config.bun)
319
319
  files.push('bunfig.toml');
320
- if (config.brand)
321
- files.push('brand/banner.svg', 'brand/banner-mobile.svg', 'brand/social-card.svg', 'brand/render.sh');
322
320
  files.push('README.md');
323
321
  return files;
324
322
  }
@@ -24,7 +24,6 @@ const REVIEWABLE_FEATURES = [
24
24
  { key: 'securityAutomation', label: 'Security automation (Dependabot + CodeQL)' },
25
25
  { key: 'badges', label: 'README status badges' },
26
26
  { key: 'aiSetup', label: 'AI agent rules (AGENTS.md, CLAUDE.md, Cursor, Copilot)' },
27
- { key: 'brand', label: 'Brand assets (brand/ banner + social-card SVGs, render.sh)' },
28
27
  ];
29
28
  /**
30
29
  * A preset run may only ask questions when a human is on both ends of the pipe.
@@ -461,13 +460,6 @@ async function promptForConfig(targetDir, seed) {
461
460
  message: '🤖 Add AI agent rules (AGENTS.md, CLAUDE.md, Cursor, Copilot, Claude skill)?',
462
461
  default: seed?.aiSetup ?? true,
463
462
  },
464
- {
465
- type: 'confirm',
466
- name: 'brand',
467
- message: '🎨 Add brand assets (brand/ banner + social-card SVG sources, render.sh)?',
468
- // On by default for libraries — the ones that publish a README to npm.
469
- default: (answers) => seed?.brand ?? answers.projectType === 'library',
470
- },
471
463
  {
472
464
  type: 'select',
473
465
  name: 'orchestrator',
@@ -557,7 +549,6 @@ async function promptForConfig(targetDir, seed) {
557
549
  publint: answers.publint ?? false,
558
550
  badges: answers.badges ?? false,
559
551
  aiSetup: answers.aiSetup ?? false,
560
- brand: answers.brand ?? false,
561
552
  turborepo: answers.orchestrator === 'turbo',
562
553
  nx: answers.orchestrator === 'nx',
563
554
  tailwind: answers.tailwind ?? false,
@@ -19,7 +19,6 @@ import { generateTailwind } from './tailwind.js';
19
19
  import { generateTurborepo } from './turborepo.js';
20
20
  import { generateNx } from './nx.js';
21
21
  import { generateBun } from './bun.js';
22
- import { generateBrand } from './brand.js';
23
22
  const __filename = fileURLToPath(import.meta.url);
24
23
  const __dirname = path.dirname(__filename);
25
24
  export async function generateConfigs(config, targetDir) {
@@ -123,11 +122,6 @@ export async function generateConfigs(config, targetDir) {
123
122
  }
124
123
  // Generate README
125
124
  await generateReadme(config, targetDir);
126
- // brand/ (#677) — the same generator as `fix brand`. After the README so the
127
- // banner-path repoint sees it; no tagline yet, as the lockfile isn't written.
128
- if (config.brand) {
129
- await generateBrand(await fs.readJson(path.join(targetDir, 'package.json')), targetDir);
130
- }
131
125
  // Copy ts-reset if TypeScript is enabled
132
126
  if (config.typescript.enabled) {
133
127
  await copyTSReset(targetDir);
package/dist/cli/index.js CHANGED
@@ -178,12 +178,6 @@ const TOOL_CATALOG = [
178
178
  exports: ['@rtorcato/repo-tooling/typedoc'],
179
179
  fixTarget: 'typedoc',
180
180
  },
181
- {
182
- name: 'Docs site',
183
- description: 'Docusaurus docs site (apps/docs) with shared tokens + GitHub Pages deploy',
184
- exports: [],
185
- fixTarget: 'docs-site',
186
- },
187
181
  {
188
182
  name: 'esbuild',
189
183
  description: 'Fast JavaScript bundler configuration',
@@ -340,7 +334,16 @@ program
340
334
  '\n `npx @rtorcato/repo-ai fix claude-skills --force-skills`.');
341
335
  process.exitCode = 1;
342
336
  });
337
+ // The docs-site and brand scaffolds moved to @rtorcato/shared-docs (#718). The
338
+ // fix targets stay as hidden pointers so old instructions fail with the fix.
339
+ const MOVED_TARGETS = { 'docs-site': 'init', brand: 'brand' };
343
340
  program.hook('preAction', async (_, actionCommand) => {
341
+ const target = actionCommand.args[0];
342
+ if (actionCommand.name() === 'fix' && target && Object.hasOwn(MOVED_TARGETS, target)) {
343
+ console.error(chalk.red(`\`repo-tooling fix ${target}\` moved to @rtorcato/shared-docs.`) +
344
+ `\n Run \`npx @rtorcato/shared-docs ${MOVED_TARGETS[target]}\` instead.`);
345
+ process.exit(1);
346
+ }
344
347
  const refusal = await selfRepoRefusal(actionCommand.name(), actionCommand.args[0], actionCommand.opts());
345
348
  if (refusal) {
346
349
  console.log(chalk.yellow('\n⚠️ This command cannot be run inside the @rtorcato/repo-tooling repo itself.\n'));
@@ -96,26 +96,6 @@ export const PRESETS = {
96
96
  target: '.mcp.json.example',
97
97
  desc: 'Commented MCP server template (copy to .mcp.json to activate)',
98
98
  },
99
- 'docusaurus-sync-changelog': {
100
- source: 'tooling/docusaurus/sync-changelog.mjs',
101
- target: 'scripts/sync-changelog.mjs',
102
- desc: 'Canonical CHANGELOG → docs sync script for Docusaurus sites',
103
- },
104
- 'docusaurus-docs-helpers': {
105
- source: 'tooling/docusaurus/docs-helpers.mjs',
106
- target: 'scripts/docs-helpers.mjs',
107
- desc: 'Docs-generator helpers (markdown-table escaping, export parser, generated-block splice)',
108
- },
109
- 'docusaurus-theme-tokens': {
110
- source: 'tooling/docusaurus/theme-tokens.css',
111
- target: 'apps/docs/src/css/_jt-tokens.css',
112
- desc: 'Shared Docusaurus design tokens (Geist + navy surfaces; accent per-project)',
113
- },
114
- 'docusaurus-theme': {
115
- source: 'tooling/docusaurus/theme.css',
116
- target: 'apps/docs/src/css/theme.css',
117
- desc: 'Shared Docusaurus component theme (navbar, cards, sidebar, footer, tables; accent-agnostic — @import after docusaurus-theme-tokens)',
118
- },
119
99
  };
120
100
  export function getPackageRoot() {
121
101
  const cliFile = new URL(import.meta.url).pathname;
@@ -163,18 +163,20 @@ export function lockfileSchema() {
163
163
  brand: {
164
164
  type: 'object',
165
165
  additionalProperties: false,
166
- description: 'Inputs to `fix brand`, which scaffolds the banner and social-card SVGs.',
166
+ deprecated: true,
167
+ description: 'Deprecated: the brand scaffold moved to @rtorcato/shared-docs. Still accepted so existing files validate; removed in the next major.',
167
168
  properties: {
168
169
  tagline: {
169
170
  type: 'string',
170
- description: 'Short line for the banners and social card, used in place of the package.json description. Keep it to two lines of about 42 characters; `fix brand` warns when it is longer.',
171
+ description: 'Short line for the banners and social card, used in place of the package.json description. Keep it to two lines of about 42 characters.',
171
172
  },
172
173
  },
173
174
  },
174
175
  docs: {
175
176
  type: 'object',
176
177
  additionalProperties: false,
177
- description: 'Inputs to `fix docs-site`.',
178
+ deprecated: true,
179
+ description: 'Deprecated: the docs-site scaffold moved to @rtorcato/shared-docs, which has the sibling list natively. Still accepted so existing files validate; removed in the next major.',
178
180
  properties: {
179
181
  siblings: {
180
182
  type: 'array',
@@ -1425,68 +1425,6 @@ export async function checkBuildApprovals(dir, pkg) {
1425
1425
  hint: `Record a decision per package under \`allowBuilds:\` in ${WORKSPACE_FILE} (\`name: true\` to run it, \`false\` to skip). pnpm 11 fails \`pnpm install --frozen-lockfile\` outright while any is undecided, so CI cannot pass until each is answered.`,
1426
1426
  };
1427
1427
  }
1428
- /** The docs app dir (apps/docs or apps/doc) if a Docusaurus config lives there. */
1429
- export async function findDocsAppDir(dir) {
1430
- for (const app of ['apps/docs', 'apps/doc']) {
1431
- if (await fs.pathExists(path.join(dir, app, 'docusaurus.config.ts')))
1432
- return app;
1433
- }
1434
- return null;
1435
- }
1436
- // Only surfaced when a Docusaurus site exists (see runDoctor). Verifies the
1437
- // shared-asset wiring #54 standardizes: sync-changelog present + chained into
1438
- // the docs app's build/start, and the deploy artifact path is `build` (not
1439
- // `dist`). Opt-in, so a repo without a docs site never sees this.
1440
- export async function checkDocsSite(dir, docsAppDir) {
1441
- const check = 'Docs site';
1442
- const deltas = [];
1443
- // sync-changelog pumps a root CHANGELOG.md into the site — a semantic-release
1444
- // shape. Changesets writes per-package changelogs and leaves the (private)
1445
- // root package without one, so don't require the script there (#425). If a
1446
- // Changesets repo keeps the script anyway, it still has to be wired.
1447
- const syncPath = path.join(dir, 'scripts', 'sync-changelog.mjs');
1448
- if (!(await fs.pathExists(syncPath))) {
1449
- if (!(await usesChangesets(dir)))
1450
- deltas.push('scripts/sync-changelog.mjs missing');
1451
- }
1452
- else {
1453
- const pkgPath = path.join(dir, docsAppDir, 'package.json');
1454
- if (await fs.pathExists(pkgPath)) {
1455
- try {
1456
- const docsPkg = (await fs.readJson(pkgPath));
1457
- const scripts = docsPkg.scripts ?? {};
1458
- const chained = ['build', 'start'].some((s) => typeof scripts[s] === 'string' && /sync-changelog/.test(scripts[s]));
1459
- // pnpm 8 doesn't run pre* hooks reliably, so build/start must chain it explicitly.
1460
- if (!chained)
1461
- deltas.push(`${docsAppDir} build/start does not chain sync-changelog`);
1462
- }
1463
- catch {
1464
- // Unparseable package.json — a separate check owns that; skip here.
1465
- }
1466
- }
1467
- }
1468
- // The GitHub Pages deploy must upload `apps/doc*/build` (Docusaurus emits
1469
- // `build/`, not `dist/`).
1470
- const workflowsDir = path.join(dir, '.github', 'workflows');
1471
- if (await fs.pathExists(workflowsDir)) {
1472
- for (const file of await fs.readdir(workflowsDir)) {
1473
- if (!/\.ya?ml$/.test(file))
1474
- continue;
1475
- const body = await fs.readFile(path.join(workflowsDir, file), 'utf-8').catch(() => '');
1476
- if (new RegExp(`${docsAppDir}/dist`).test(body)) {
1477
- deltas.push(`${file} deploys ${docsAppDir}/dist (should be ${docsAppDir}/build)`);
1478
- }
1479
- }
1480
- }
1481
- if (deltas.length)
1482
- return {
1483
- check,
1484
- status: 'drift',
1485
- detail: deltas.join('; '),
1486
- hint: 'Align the docs site with the shared standard (sync-changelog wiring, build/ artifact path)',
1487
- };
1488
- return { check, status: 'ok', detail: `${docsAppDir} wired per standard` };
1489
- }
1490
1428
  // Only called when `tailwindcss` is a dependency (see runDoctor) — Tailwind is
1491
1429
  // opt-in per project, so nudging repos that don't use it would be noise. v4 is
1492
1430
  // CSS-first: the wiring is a PostCSS plugin (or the Vite plugin), not a config
@@ -72,11 +72,10 @@ import { generateTailwind } from '../../cli/generators/tailwind.js';
72
72
  import { generateTurborepo } from '../../cli/generators/turborepo.js';
73
73
  import { generateNx } from '../../cli/generators/nx.js';
74
74
  import { generateBun } from '../../cli/generators/bun.js';
75
- import { generateDocsSite } from '../../cli/generators/docs-site.js';
76
75
  import { generateTypedocConfig, generateTypedocWorkflow } from '../../cli/generators/typedoc.js';
77
76
  import { copyPreset } from '../../cli/utils/copy-preset.js';
78
77
  import { identifiablePresetHashes } from '../../cli/utils/copied-assets.js';
79
- import { LOCKFILE_NAME, readLockfile, writeLockfile } from '../../cli/utils/lockfile.js';
78
+ import { LOCKFILE_NAME, writeLockfile } from '../../cli/utils/lockfile.js';
80
79
  // The fixer contract moved to src/base/fixers.ts when Swift became the second
81
80
  // module (#286) — import it from there.
82
81
  import { FixerAbort } from '../../base/fixers.js';
@@ -739,48 +738,6 @@ export const FIXERS = [
739
738
  return { filesWritten };
740
739
  },
741
740
  },
742
- {
743
- target: 'docs-site',
744
- description: 'Scaffold a Docusaurus docs site under apps/docs (config/sidebars/tokens + reusable Pages deploy), inferring name/org/repo from package.json',
745
- // Manual/opt-in target — the "Docs site" doctor check is opt-in (only
746
- // surfaces once a site exists), so this never nags a repo without one.
747
- appliesTo: [],
748
- outputs: [
749
- 'apps/docs/**',
750
- 'scripts/sync-changelog.mjs',
751
- 'pnpm-workspace.yaml',
752
- '.github/workflows/docs.yml',
753
- ],
754
- riskLevel: 'safe-add',
755
- async run({ targetDir, pkg }) {
756
- // Wire the TypeDoc API section (#229) when the repo already uses TypeDoc —
757
- // a typedoc config on disk or the dep installed. No new CLI flag needed.
758
- const deps = {
759
- ...(pkg?.dependencies ?? {}),
760
- ...(pkg?.devDependencies ?? {}),
761
- };
762
- const typedocConfigs = [
763
- 'typedoc.json',
764
- 'typedoc.config.js',
765
- 'typedoc.config.mjs',
766
- 'typedoc.config.cjs',
767
- 'typedoc.config.ts',
768
- ];
769
- let hasTypedocConfig = false;
770
- for (const c of typedocConfigs) {
771
- if (await fs.pathExists(path.join(targetDir, c))) {
772
- hasTypedocConfig = true;
773
- break;
774
- }
775
- }
776
- const typedoc = hasTypedocConfig || 'typedoc' in deps;
777
- const filesWritten = await generateDocsSite(pkg, targetDir, {
778
- typedoc,
779
- siblings: (await readLockfile(targetDir))?.rules?.docs?.siblings,
780
- });
781
- return { filesWritten };
782
- },
783
- },
784
741
  {
785
742
  target: 'attw',
786
743
  description: 'Install @arethetypeswrong/cli + add an `attw` script (esm-only profile when applicable) and wire it into verify',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "4.8.0",
3
+ "version": "5.0.1",
4
4
  "description": "One CLI to scaffold, audit and fix your repo's whole toolchain — linting, tests, commits, releases & CI.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -85,12 +85,6 @@
85
85
  "tooling/rollup/rollup.config.d.mts",
86
86
  "tooling/rolldown/rolldown.config.mjs",
87
87
  "tooling/rolldown/rolldown.config.d.mts",
88
- "tooling/docusaurus/index.mjs",
89
- "tooling/docusaurus/index.d.mts",
90
- "tooling/docusaurus/sync-changelog.mjs",
91
- "tooling/docusaurus/docs-helpers.mjs",
92
- "tooling/docusaurus/theme-tokens.css",
93
- "tooling/docusaurus/theme.css",
94
88
  "tooling/biome/preset.json",
95
89
  "tooling/bun/bunfig.toml",
96
90
  "tooling/nx/nx.json",
@@ -199,10 +193,6 @@
199
193
  "types": "./tooling/rolldown/rolldown.config.d.mts",
200
194
  "import": "./tooling/rolldown/rolldown.config.mjs"
201
195
  },
202
- "./docusaurus": {
203
- "types": "./tooling/docusaurus/index.d.mts",
204
- "import": "./tooling/docusaurus/index.mjs"
205
- },
206
196
  "./biome": "./tooling/biome/preset.json",
207
197
  "./nx": "./tooling/nx/nx.json",
208
198
  "./changesets": "./tooling/changesets/config.json",
@@ -84,7 +84,7 @@ export default {
84
84
  // and the `version` field in package.json stop moving on the default branch.**
85
85
  // The git tag, the npm publish and the GitHub Release are unaffected and are
86
86
  // the source of truth for what shipped. Build any user-facing changelog from
87
- // GitHub Releases — `repo-tooling copy docusaurus-sync-changelog` does exactly
87
+ // GitHub Releases — `@rtorcato/shared-docs`'s sync-changelog script does exactly
88
88
  // that — never from the frozen file.
89
89
  //
90
90
  // Adding a bypass actor to the ruleset would also make the push succeed. It is