@spardutti/claude-skills 2.19.1 → 2.19.3

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.
Files changed (2) hide show
  1. package/lib/local.mjs +31 -1
  2. package/package.json +1 -1
package/lib/local.mjs CHANGED
@@ -3,6 +3,10 @@
3
3
  // publishing it first.
4
4
  import { readdir, readFile } from "node:fs/promises";
5
5
  import { join } from "node:path";
6
+ import { execFile } from "node:child_process";
7
+ import { promisify } from "node:util";
8
+
9
+ const exec = promisify(execFile);
6
10
 
7
11
  function parseFrontmatter(content, fallbackName) {
8
12
  const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
@@ -25,6 +29,28 @@ async function listDir(dir) {
25
29
  try { return await readdir(dir, { withFileTypes: true }); } catch { return []; }
26
30
  }
27
31
 
32
+ // Build output is not a project. Next.js writes a package.json into .next/,
33
+ // .next/dev/ and .next/standalone/, so a scan that skipped only a hardcoded
34
+ // list reported three phantom projects on a plain Next app — and then filtered
35
+ // the real repo root out as "a root that delegates to a workspace". A second
36
+ // list of build dirs drifts from .gitignore the moment a framework adds one, so
37
+ // ask git the way ship-gate.sh already does. --directory collapses a fully
38
+ // ignored tree to its own name, which is what keeps this output small.
39
+ async function gitIgnoredDirs(projectDir) {
40
+ try {
41
+ const { stdout } = await exec(
42
+ "git",
43
+ ["-C", projectDir, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"],
44
+ { maxBuffer: 10 * 1024 * 1024 },
45
+ );
46
+ return new Set(
47
+ stdout.split("\n").filter((l) => l.endsWith("/")).map((l) => l.slice(0, -1)),
48
+ );
49
+ } catch {
50
+ return new Set();
51
+ }
52
+ }
53
+
28
54
  export function makeLocalSource(root) {
29
55
  return {
30
56
  async fetchSkills() {
@@ -113,6 +139,8 @@ export async function reportToolNeeds(projectDir) {
113
139
  // needs a tool. A root that delegates is not the place to install, even once
114
140
  // the workspace it delegates to is already set up.
115
141
  const nested = { Stryker: false, mutmut: false };
142
+ // Empty outside a git repo, so the hardcoded list below still carries those.
143
+ const ignored = await gitIgnoredDirs(projectDir);
116
144
 
117
145
  async function scan(rel, depth) {
118
146
  if (depth > 2) return;
@@ -159,7 +187,9 @@ export async function reportToolNeeds(projectDir) {
159
187
  for (const e of entries) {
160
188
  if (!e.isDirectory()) continue;
161
189
  if (["node_modules", ".git", "dist", "build", ".venv", "venv", ".claude"].includes(e.name)) continue;
162
- await scan(rel ? `${rel}/${e.name}` : e.name, depth + 1);
190
+ const child = rel ? `${rel}/${e.name}` : e.name;
191
+ if (ignored.has(child)) continue;
192
+ await scan(child, depth + 1);
163
193
  }
164
194
  }
165
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spardutti/claude-skills",
3
- "version": "2.19.1",
3
+ "version": "2.19.3",
4
4
  "description": "CLI to install Claude Code skills from the claude-skills collection",
5
5
  "type": "module",
6
6
  "repository": {