@spardutti/claude-skills 2.64.0 → 2.65.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.
- package/hooks/registry-lib.mjs +4 -3
- package/hooks/registry.mjs +22 -8
- package/package.json +1 -1
package/hooks/registry-lib.mjs
CHANGED
|
@@ -77,10 +77,11 @@ export function triggerHits(entry, text) {
|
|
|
77
77
|
return entry.triggers.filter((t) => new RegExp(`\\b${escape(t)}\\b`, "i").test(text));
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
export const locationsOf = (entry) => [].concat(entry.location ?? []).map((l) => l.replace(/^\.\//, "")).filter(Boolean);
|
|
81
|
+
|
|
82
|
+
// A location is a folder or files, like sim/aim.gd beside unrelated systems in sim/.
|
|
81
83
|
export function insideLocation(entry, file) {
|
|
82
|
-
|
|
83
|
-
return loc !== "" && (file === loc || file.startsWith(loc.replace(/\/?$/, "/")));
|
|
84
|
+
return locationsOf(entry).some((loc) => file === loc || file.startsWith(loc.replace(/\/?$/, "/")));
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
export const isAllowed = (entry, file) => entry.allowed.some((a) => (a.endsWith("/") ? file.startsWith(a) : file === a));
|
package/hooks/registry.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import {
|
|
5
|
-
REGISTRY_SUFFIX, addedText, escape, insideLocation, isAllowed, loadRegistry, planMarks, projectFiles, projectRoot, symbolsOf, triggerHits,
|
|
5
|
+
REGISTRY_SUFFIX, addedText, escape, insideLocation, isAllowed, loadRegistry, locationsOf, planMarks, projectFiles, projectRoot, symbolsOf, triggerHits,
|
|
6
6
|
} from "./registry-lib.mjs";
|
|
7
7
|
import { loadEditRules } from "./text-rules.mjs";
|
|
8
8
|
|
|
@@ -61,7 +61,7 @@ function evaluate() {
|
|
|
61
61
|
const outside = files.filter((f) => !insideLocation(e, f) && !isAllowed(e, f) && !f.endsWith(REGISTRY_SUFFIX));
|
|
62
62
|
const hits = outside.flatMap((f) => readFileSync(join(root, f), "utf8").split("\n").flatMap((line, i) =>
|
|
63
63
|
e.does.filter((code) => calls(line, code)).map((code) => `registry SUSPECT ${e.name} ${f}:${i + 1} ${code}`)));
|
|
64
|
-
console.log(hits.length ? hits.join("\n") : `registry eval ${e.name}: nothing outside ${e.
|
|
64
|
+
console.log(hits.length ? hits.join("\n") : `registry eval ${e.name}: nothing outside ${locationsOf(e).join(", ")} does its job`);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -82,16 +82,30 @@ function stale() {
|
|
|
82
82
|
if (/^\s+-\s/m.test(e.text)) say("write lists on one line, like triggers: [aim, target]");
|
|
83
83
|
if (seen.has(e.name)) say(`name ${e.name} is used twice`);
|
|
84
84
|
seen.add(e.name);
|
|
85
|
+
staleLocation(e, say);
|
|
85
86
|
staleCode(e, say);
|
|
86
87
|
}
|
|
87
88
|
if (problems.length) fail(problems);
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
// A folder wide enough to hold another system hides that folder from eval.
|
|
92
|
+
function staleLocation(e, say) {
|
|
93
|
+
const bare = (l) => l.replace(/\/$/, "");
|
|
94
|
+
const own = locationsOf(e).map(bare);
|
|
95
|
+
for (const other of entries) {
|
|
96
|
+
if (other === e) continue;
|
|
97
|
+
const held = locationsOf(other).map(bare).filter((l) => !own.includes(l) && insideLocation(e, l));
|
|
98
|
+
if (held.length) say(`location holds ${other.name}'s ${held.join(", ")} — list this system's own files`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
90
102
|
function staleCode(e, say) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
103
|
+
const locs = locationsOf(e);
|
|
104
|
+
const where = locs.join(", ");
|
|
105
|
+
const gone = locs.filter((l) => !existsSync(join(root, l)));
|
|
106
|
+
if (!locs.length || gone.length) return say(`location ${gone.join(", ") || e.location} not found`);
|
|
107
|
+
const near = locs.map((l) => (statSync(join(root, l)).isDirectory() ? join(root, l) : dirname(join(root, l))));
|
|
108
|
+
if (e.example && !near.some((n) => existsSync(join(n, e.example))) && !existsSync(join(root, e.example))) say(`example ${e.example} not found`);
|
|
95
109
|
const syms = symbolsOf(e.extend_by);
|
|
96
110
|
if (!syms.length) say("extend_by names no symbol — write names like `AimStrategy`");
|
|
97
111
|
const code = files.filter((f) => insideLocation(e, f) && !f.endsWith(REGISTRY_SUFFIX))
|
|
@@ -99,9 +113,9 @@ function staleCode(e, say) {
|
|
|
99
113
|
for (const s of syms) {
|
|
100
114
|
// A plain word like `first` matches `var first = enemies[0]`; `Aim.first` only matches real use.
|
|
101
115
|
if (/^[a-z][a-z0-9]*$/.test(s)) say(`\`${s}\` is too common a word to prove use — name its owner, like \`Owner.${s}\``);
|
|
102
|
-
else if (!s.split(".").every((part) => uses(code, part))) say(`${s} from extend_by is not found in ${
|
|
116
|
+
else if (!s.split(".").every((part) => uses(code, part))) say(`${s} from extend_by is not found in ${where}`);
|
|
103
117
|
}
|
|
104
|
-
for (const c of e.does) if (!calls(code, c)) say(`does ${c} is not found in ${
|
|
118
|
+
for (const c of e.does) if (!calls(code, c)) say(`does ${c} is not found in ${where}`);
|
|
105
119
|
}
|
|
106
120
|
|
|
107
121
|
function fail(lines) {
|