@spardutti/claude-skills 2.11.0 → 2.11.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/bin/cli.mjs CHANGED
@@ -158,10 +158,12 @@ async function main() {
158
158
  await setupClaudeMd();
159
159
 
160
160
  // Report what the gauntlet will actually run, so a silent no-op is visible.
161
- const { test, typecheck } = await detectStack(CWD);
162
- if (test) {
163
- const found = [typecheck, test].filter(Boolean).join(" + ");
164
- console.log(` ${chalk.dim(`Gauntlet detected ${found} — it will run those on changed files.`)}`);
161
+ // This asks the installed hook itself — never a second copy of its logic.
162
+ const gates = await detectStack(CWD);
163
+ if (gates) {
164
+ for (const gate of gates.split(";").map((g) => g.trim()).filter(Boolean)) {
165
+ console.log(` ${chalk.dim(`Gauntlet gate: ${gate}`)}`);
166
+ }
165
167
  } else {
166
168
  console.log(` ${chalk.yellow("!")} ${chalk.dim("Gauntlet found no test runner here — it will stay asleep.")}`);
167
169
  console.log();
@@ -1,5 +1,6 @@
1
1
  import { mkdir, writeFile, readFile, chmod, unlink } from "node:fs/promises";
2
2
  import { join, resolve, dirname } from "node:path";
3
+ import { spawn } from "node:child_process";
3
4
 
4
5
  // PreToolUse gate on Write|Edit|MultiEdit. Blocks the tool call unless
5
6
  // a per-session marker file exists at /tmp/claude-skill-gate-<SESSION_ID>.
@@ -469,37 +470,28 @@ const GAUNTLET_FILENAME = "gauntlet.sh";
469
470
  const LEGACY_EVAL_FILENAME = "skill-forced-eval-hook.sh";
470
471
  const LEGACY_AUDIT_RUNNER_FILENAME = "skill-audit-runner.sh";
471
472
 
472
- // Mirrors the detect() in scripts/gauntlet.sh. Kept in sync by hand: this one
473
- // only reports what the hook will find, it never decides anything.
473
+ // Asks the installed hook what it would run, rather than reimplementing its
474
+ // detection here. A second copy drifts: the JS one reported "no test runner"
475
+ // for repos the shell script had already learned to handle.
474
476
  export async function detectStack(targetDir = process.cwd()) {
475
477
  const dir = resolve(targetDir);
476
- const has = async (f) => {
477
- try { await readFile(join(dir, f), "utf-8"); return true; } catch { return false; }
478
- };
479
- const read = async (f) => {
480
- try { return await readFile(join(dir, f), "utf-8"); } catch { return ""; }
481
- };
482
-
483
- let test = null;
484
- let typecheck = null;
485
-
486
- const pkg = await read("package.json");
487
- if (pkg) {
488
- if (pkg.includes('"vitest"')) test = "vitest";
489
- else if (pkg.includes('"jest"')) test = "jest";
490
- // A delegating monorepo root has no runner as a direct dependency, but its
491
- // own `test` script still runs the right thing.
492
- else if (/"test"\s*:/.test(pkg)) test = "npm test";
493
- if (/"typecheck"\s*:/.test(pkg)) typecheck = "npm run typecheck";
494
- else if (await has("tsconfig.json")) typecheck = "tsc";
495
- }
496
- if (!test && (await has("pyproject.toml") || await has("pytest.ini") || await has("setup.cfg"))) {
497
- test = "pytest";
498
- if (await has("mypy.ini") || (await read("pyproject.toml")).includes("tool.mypy")) {
499
- typecheck = "mypy";
500
- }
501
- }
502
- return { test, typecheck };
478
+ const hook = join(dir, ".claude", "hooks", GAUNTLET_FILENAME);
479
+ return new Promise((done) => {
480
+ const child = spawn("bash", [hook], {
481
+ cwd: dir,
482
+ env: { ...process.env, CLAUDE_PROJECT_DIR: dir, GAUNTLET_DEBUG: "1", GAUNTLET_DRYRUN: "1" },
483
+ });
484
+ let err = "";
485
+ child.stderr.on("data", (c) => { err += c; });
486
+ child.on("error", () => done(null));
487
+ child.on("close", () => {
488
+ const line = err.split("\n").find((l) => l.startsWith("gauntlet: would run:"));
489
+ if (!line) return done(null);
490
+ const gates = line.slice("gauntlet: would run:".length).trim();
491
+ done(gates && !gates.startsWith("nothing") ? gates : null);
492
+ });
493
+ child.stdin.end('{"session_id":"install"}');
494
+ });
503
495
  }
504
496
 
505
497
  // Written only when detection finds nothing — otherwise the hook auto-detects and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spardutti/claude-skills",
3
- "version": "2.11.0",
3
+ "version": "2.11.1",
4
4
  "description": "CLI to install Claude Code skills from the claude-skills collection",
5
5
  "type": "module",
6
6
  "bin": {