@rtorcato/repo-tooling 3.18.0 → 3.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.
@@ -469,11 +469,16 @@ export async function checkAiSetup(dir) {
469
469
  * is not a defect in this repo, and either of those statuses would fail its CI
470
470
  * over a file CI has never seen. `optional-missing` is the honest verdict — an
471
471
  * opt-in workflow tool that isn't configured — and it leaves the exit code alone.
472
+ *
473
+ * `skillsDir` is doctor's `--skills-dir`. Without it this reported against
474
+ * `~/.claude/skills` whatever directory the repo actually installs into, so a
475
+ * consumer who passes the flag to `fix` saw a permanent false `optional-missing`
476
+ * for a skill they have (#485).
472
477
  */
473
- export async function checkClaudeSkills() {
478
+ export async function checkClaudeSkills(skillsDir) {
474
479
  const check = 'Claude skills';
475
480
  const hint = `Run \`npx @rtorcato/repo-tooling fix claude-skills\` to install the ${SHIPPED_SKILL} skill (writes outside the repo; opt-in, so \`fix\` alone skips it)`;
476
- const status = await claudeSkillStatus();
481
+ const status = await claudeSkillStatus(SHIPPED_SKILL, skillsDir);
477
482
  if (!status.installed) {
478
483
  return {
479
484
  check,
@@ -179,12 +179,12 @@ async function runBaseChecks(dir, lock, opts) {
179
179
  results.push(await checkBrand(dir));
180
180
  results.push(await checkAiSetup(dir));
181
181
  // User-global, not repo state — see checkClaudeSkills on why it never returns drift.
182
- results.push(await checkClaudeSkills());
182
+ results.push(await checkClaudeSkills(opts.skillsDir));
183
183
  results.push(await checkReadmeBadges(dir, opts.badges.audience, opts.badges.fixTarget));
184
184
  results.push(await checkCoverageUpload(dir));
185
185
  return results;
186
186
  }
187
- export async function runDoctor(dir) {
187
+ export async function runDoctor(dir, skillsDir) {
188
188
  const targetDir = path.resolve(dir);
189
189
  const lock = await readLockfile(targetDir);
190
190
  // Per-module dispatch (#285): the base checks (repo hygiene, CI, security,
@@ -212,6 +212,7 @@ export async function runDoctor(dir) {
212
212
  presetWorkflow: null,
213
213
  language,
214
214
  codeqlLanguages: languageModule.codeqlLanguages,
215
+ skillsDir,
215
216
  })),
216
217
  ];
217
218
  return demoteDeclined(results, lock);
@@ -234,6 +235,7 @@ export async function runDoctor(dir) {
234
235
  presetWorkflow: renderSwiftWorkflow(await readSwiftPackage(targetDir)),
235
236
  language,
236
237
  codeqlLanguages: languageModule.codeqlLanguages,
238
+ skillsDir,
237
239
  })),
238
240
  ...(await runSwiftChecks(targetDir)),
239
241
  ];
@@ -257,6 +259,7 @@ export async function runDoctor(dir) {
257
259
  presetWorkflow: renderPythonWorkflow(await readPyproject(targetDir)),
258
260
  language,
259
261
  codeqlLanguages: languageModule.codeqlLanguages,
262
+ skillsDir,
260
263
  })),
261
264
  ...(await runPythonChecks(targetDir)),
262
265
  ];
@@ -282,6 +285,7 @@ export async function runDoctor(dir) {
282
285
  presetWorkflow: renderPerlWorkflow(await readPerlProject(targetDir)),
283
286
  language,
284
287
  codeqlLanguages: languageModule.codeqlLanguages,
288
+ skillsDir,
285
289
  })),
286
290
  ...(await runPerlChecks(targetDir)),
287
291
  ];
@@ -342,6 +346,7 @@ export async function runDoctor(dir) {
342
346
  presetWorkflow: renderGitHubWorkflow(githubJobs(inferProjectConfig(pkg), { scripts: scriptsOf(pkg) })),
343
347
  language,
344
348
  codeqlLanguages: languageModule.codeqlLanguages,
349
+ skillsDir,
345
350
  })));
346
351
  return demoteDeclined(results, lock);
347
352
  }
@@ -397,7 +402,7 @@ export function summarize(results) {
397
402
  }
398
403
  export async function doctorCommand(options = {}) {
399
404
  const dir = options.directory ?? process.cwd();
400
- const results = await runDoctor(dir);
405
+ const results = await runDoctor(dir, options.skillsDir);
401
406
  if (options.json) {
402
407
  console.log(JSON.stringify({ directory: path.resolve(dir), results }, null, 2));
403
408
  }
@@ -333,7 +333,9 @@ export async function fixCommand(target, options = {}) {
333
333
  const pkg = await readPackageJson(targetDir);
334
334
  const lock = await readLockfile(targetDir);
335
335
  const fixers = fixersForLanguage(await detectLanguage(targetDir));
336
- const results = await runDoctor(targetDir);
336
+ // Same --skills-dir the claude-skills fixer writes to, so the diagnosis fix
337
+ // acts on and the install it performs agree on one directory (#485).
338
+ const results = await runDoctor(targetDir, options.skillsDir);
337
339
  const actions = [];
338
340
  const noteLockConflict = (check) => {
339
341
  if (!lock)
package/dist/cli/index.js CHANGED
@@ -317,6 +317,9 @@ program
317
317
  .description('🩺 Diagnose project alignment with @rtorcato/repo-tooling presets')
318
318
  .option('-d, --directory <path>', 'Target directory to diagnose', process.cwd())
319
319
  .option('--json', 'Emit machine-readable JSON output')
320
+ // The read side of `fix --skills-dir` (#485). No --yes/--json requirement
321
+ // here: doctor never writes, so an unresolved directory is just reported.
322
+ .option('--skills-dir <path>', 'Where `fix claude-skills` installs user-global agent skills (default: ~/.claude/skills). Pass the same path `fix` was given, or the skill reports as not installed')
320
323
  .action(doctorCommand);
321
324
  program
322
325
  .command('fix [target]')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "3.18.0",
3
+ "version": "3.19.0",
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": [