@rtorcato/repo-tooling 3.19.0 → 3.19.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.
@@ -2,7 +2,7 @@ import path from 'node:path';
2
2
  import fs from 'fs-extra';
3
3
  import { BLOCK_START, hasStaleAgentBlock } from '../cli/generators/agent-rules.js';
4
4
  import { BADGE_START, hasPublicOnlyBadges } from '../cli/generators/badges.js';
5
- import { claudeSkillStatus, SHIPPED_SKILL } from '../cli/generators/claude-skills.js';
5
+ import { claudeSkillStatus, SHIPPED_SKILL, skillDiffCommand, } from '../cli/generators/claude-skills.js';
6
6
  import { DEPENDABOT_CONFIG_PATHS, dependabotIgnoreRules } from '../cli/generators/security.js';
7
7
  import { detectNestedLanguages } from '../cli/utils/detect-language.js';
8
8
  /**
@@ -500,7 +500,9 @@ export async function checkClaudeSkills(skillsDir) {
500
500
  // A local fork is `ok` for the same reason a modified copied asset is (#448):
501
501
  // it is somebody's deliberate work, so it is named once and never nagged as
502
502
  // fixable — pointing at a `fix` that would refuse is worse than saying nothing.
503
- if (status.contentState && status.contentState !== 'pristine') {
503
+ // `realFile` is set whenever `contentState` is — both mean something is
504
+ // installed. The extra test is TypeScript's, not a real condition.
505
+ if (status.realFile && status.contentState && status.contentState !== 'pristine') {
504
506
  const why = status.contentState === 'modified'
505
507
  ? `has local changes since ${status.installedVersion}`
506
508
  : 'carries no content record, so a fork cannot be told from a stale copy';
@@ -508,7 +510,9 @@ export async function checkClaudeSkills(skillsDir) {
508
510
  check,
509
511
  status: 'ok',
510
512
  detail: `${SHIPPED_SKILL} skill at ${status.file} ${why}; this package ships ${status.shippedVersion} and will not overwrite it`,
511
- hint: `Diff it against the shipped copy, then run \`npx @rtorcato/repo-tooling fix claude-skills --force-skills\` to take the shipped version`,
513
+ // Name both paths: "diff it against the shipped copy" left the reader
514
+ // with nothing to diff, in the one case they most want to look (#484).
515
+ hint: `Diff it against the shipped copy — \`${skillDiffCommand({ realFile: status.realFile, shippedFile: status.shippedFile })}\` — then run \`npx @rtorcato/repo-tooling fix claude-skills --force-skills\` to take the shipped version`,
512
516
  };
513
517
  }
514
518
  return {
@@ -16,7 +16,7 @@ import path from 'node:path';
16
16
  import chalk from 'chalk';
17
17
  import inquirer from 'inquirer';
18
18
  import { installAgentRules, installAiSetup } from '../cli/generators/agent-rules.js';
19
- import { installClaudeSkill, resolveSkillsDir, SHIPPED_SKILL, } from '../cli/generators/claude-skills.js';
19
+ import { installClaudeSkill, resolveSkillsDir, SHIPPED_SKILL, skillDiffCommand, } from '../cli/generators/claude-skills.js';
20
20
  import { generateBrand } from '../cli/generators/brand.js';
21
21
  import { generateCommunityHealth } from '../cli/generators/community-health.js';
22
22
  import { generateCommitlintConfig } from '../cli/generators/git.js';
@@ -89,7 +89,7 @@ function describeSkillFork(result) {
89
89
  return [
90
90
  `skipped — ${SHIPPED_SKILL} was not overwritten with ${result.shippedVersion}: ${why}`,
91
91
  ` ${target}`,
92
- ` compare: diff "${result.realFile}" "${result.shippedFile}"`,
92
+ ` compare: ${skillDiffCommand(result)}`,
93
93
  ' overwrite anyway: fix claude-skills --force-skills',
94
94
  ];
95
95
  }
@@ -129,6 +129,16 @@ export async function readShippedSkill(name = SHIPPED_SKILL) {
129
129
  const pkg = await fs.readJson(path.join(root, 'package.json'));
130
130
  return { content, version: String(pkg.version), file };
131
131
  }
132
+ /**
133
+ * The command a human runs to see what their fork changed, before deciding
134
+ * whether to take the shipped copy. One builder, because `doctor` and `fix`
135
+ * both print it and two independently-built strings drift (#484). Always
136
+ * `realFile`: through a stow symlink the nominal path is the link, and the
137
+ * bytes worth reading are in the dotfiles checkout it points at.
138
+ */
139
+ export function skillDiffCommand(paths) {
140
+ return `diff "${paths.realFile}" "${paths.shippedFile}"`;
141
+ }
132
142
  /** Whether `file` is itself a symlink, as opposed to merely resolving through one. */
133
143
  async function isSymlink(file) {
134
144
  return await fs
@@ -185,6 +195,8 @@ export async function claudeSkillStatus(name = SHIPPED_SKILL, explicit) {
185
195
  const shipped = await readShippedSkill(name);
186
196
  const { dir } = await resolveSkillsDir(explicit);
187
197
  const absent = {
198
+ realFile: null,
199
+ shippedFile: shipped.file,
188
200
  installed: false,
189
201
  installedVersion: null,
190
202
  shippedVersion: shipped.version,
@@ -202,6 +214,8 @@ export async function claudeSkillStatus(name = SHIPPED_SKILL, explicit) {
202
214
  const behind = installedVersion === null || isNewerVersion(shipped.version, installedVersion);
203
215
  return {
204
216
  file,
217
+ realFile: (await isSymlink(file)) ? await fs.realpath(file) : file,
218
+ shippedFile: shipped.file,
205
219
  installed: true,
206
220
  installedVersion,
207
221
  shippedVersion: shipped.version,
@@ -4,7 +4,9 @@ import fs from 'fs-extra';
4
4
  import { recordAssetHash } from './lockfile.js';
5
5
  export const PRESETS = {
6
6
  biome: {
7
- source: 'tooling/biome/biome.json',
7
+ // Not named `biome.json`: Biome auto-discovers any file by that name, so
8
+ // shipping one inside this package made it a second root config here (#486).
9
+ source: 'tooling/biome/preset.json',
8
10
  target: 'biome.json',
9
11
  desc: 'Biome formatter and linter configuration',
10
12
  },
@@ -84,7 +84,7 @@ function matchesBiomeConfig(contents) {
84
84
  if (BIOME_PRESET_REF.test(JSON.stringify(config.extends ?? '')))
85
85
  return true;
86
86
  // The inlined preset: biome's own `$schema` plus the `linter.rules.preset`
87
- // key the shipped `tooling/biome/biome.json` sets.
87
+ // key the shipped `tooling/biome/preset.json` sets.
88
88
  const schema = config.$schema;
89
89
  return (typeof schema === 'string' &&
90
90
  schema.includes('biomejs.dev/schemas/') &&
@@ -1373,7 +1373,7 @@ function readSchemaUrl(contents) {
1373
1373
  * of which version the config targets, so comparing it against the declared
1374
1374
  * dependency floor is exact — no heuristics, no false positives.
1375
1375
  *
1376
- * This is the #330 defect precisely: `tooling/biome/biome.json` carries
1376
+ * This is the #330 defect precisely: `tooling/biome/preset.json` carries
1377
1377
  * `$schema` 2.5.0 and uses `linter.rules.preset`, a 2.5 key, while
1378
1378
  * `peerDependencies` advertised `@biomejs/biome: ^2.0.0`. Consumers on 2.0–2.4
1379
1379
  * got `Found an unknown key \`preset\`` with nothing pointing at the range.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "3.19.0",
3
+ "version": "3.19.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": [
@@ -90,7 +90,7 @@
90
90
  "tooling/docusaurus/docs-helpers.mjs",
91
91
  "tooling/docusaurus/theme-tokens.css",
92
92
  "tooling/docusaurus/theme.css",
93
- "tooling/biome/biome.json",
93
+ "tooling/biome/preset.json",
94
94
  "tooling/bun/bunfig.toml",
95
95
  "tooling/nx/nx.json",
96
96
  "tooling/changesets/config.json",
@@ -201,7 +201,7 @@
201
201
  "types": "./tooling/docusaurus/index.d.mts",
202
202
  "import": "./tooling/docusaurus/index.mjs"
203
203
  },
204
- "./biome": "./tooling/biome/biome.json",
204
+ "./biome": "./tooling/biome/preset.json",
205
205
  "./nx": "./tooling/nx/nx.json",
206
206
  "./changesets": "./tooling/changesets/config.json",
207
207
  "./release-please": "./tooling/release-please/release-please-config.json",
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "$schema": "https://biomejs.dev/schemas/latest/schema.json",
3
- "root": false,
4
3
  "vcs": {
5
4
  "enabled": true,
6
5
  "clientKind": "git",