@davesheffer/hunch 0.35.0 → 0.35.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/README.md +6 -0
- package/dist/cli/index.js +6 -0
- package/dist/core/constraintmatch.js +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -172,6 +172,12 @@ Plus the **Regression Guard** (re-adding deliberately-retired code) and the
|
|
|
172
172
|
**[CI Constraint Guard](https://hunch-pi.vercel.app/docs#ci)** (`hunch ci` — a PR gate that
|
|
173
173
|
comments the affected `con_`/`dec_` ids and fails on a blocking one).
|
|
174
174
|
|
|
175
|
+
Give a blocking rule a content matcher — `record-constraint "…" --scope "src/**" --severity
|
|
176
|
+
blocking --match "lodash"` — and it blocks the *actual* violation across the file's whole life
|
|
177
|
+
(matched against added code; comments ignored) instead of relaxing to advisory after the file
|
|
178
|
+
is edited again. It's a deterministic guard for the obvious/accidental violation, not a
|
|
179
|
+
bypass-proof boundary.
|
|
180
|
+
|
|
175
181
|
## Working as a team
|
|
176
182
|
|
|
177
183
|
The `.hunch/` JSON is the **source of truth** — diffable, reviewable in PRs, synced for free
|
package/dist/cli/index.js
CHANGED
|
@@ -955,6 +955,12 @@ program
|
|
|
955
955
|
store.reindex();
|
|
956
956
|
updateClaudeMd(root, store);
|
|
957
957
|
console.log(`✓ recorded ${c.severity} constraint ${c.id}: "${c.statement}" (scope: ${scope.join(", ") || "repo"})`);
|
|
958
|
+
if (c.severity === "blocking" && !c.match) {
|
|
959
|
+
// The default path's sharp edge: a scope-only blocking rule fails OPEN once any
|
|
960
|
+
// file in scope is committed after today (staleness). Point the user at the fix.
|
|
961
|
+
console.log(` ⚠ scope-only — this will downgrade to advisory once a file in scope is changed after today.`);
|
|
962
|
+
console.log(` To block the actual violation across the file's life, add a content matcher, e.g. --match "lodash"`);
|
|
963
|
+
}
|
|
958
964
|
store.close();
|
|
959
965
|
});
|
|
960
966
|
// ---- test (failure-learning loop) -----------------------------------------
|
|
@@ -19,10 +19,20 @@ export function constraintMatcher(pattern) {
|
|
|
19
19
|
return null; // malformed pattern → inert, never throws
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
22
|
+
/** The enforceable CODE of an added line: a comment carries no invariant, so a rule
|
|
23
|
+
* must not fire on it (a `// we avoid lodash` note is not a violation). We strip
|
|
24
|
+
* comments but NOT string literals — the thing a matcher most often targets, an
|
|
25
|
+
* import specifier (`from "lodash"`), IS a string, so stripping strings would blind
|
|
26
|
+
* the matcher to the real violation. A comment-only line → "". */
|
|
27
|
+
export function matchableCode(line) {
|
|
28
|
+
if (/^\s*(\/\/|\/\*|\*)/.test(line))
|
|
29
|
+
return ""; // // line, /* block, or * JSDoc-continuation
|
|
30
|
+
return line.replace(/\s+\/\/.*$/, ""); // drop a trailing inline // comment (keeps "://" in URLs/strings)
|
|
31
|
+
}
|
|
32
|
+
/** True iff any ADDED line's CODE trips the constraint's content matcher. */
|
|
23
33
|
export function contentViolates(re, addedLines) {
|
|
24
34
|
if (!re)
|
|
25
35
|
return false;
|
|
26
|
-
return addedLines.some((l) => re.test(l));
|
|
36
|
+
return addedLines.some((l) => re.test(matchableCode(l)));
|
|
27
37
|
}
|
|
28
38
|
//# sourceMappingURL=constraintmatch.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davesheffer/hunch",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Dave Sheffer <dave.sheffer1@gmail.com>",
|
|
6
6
|
"description": "Hunch — an Engineering Memory OS: a persistent, git-native graph of the decisions, bugs, and rules behind your code, served to any MCP coding assistant (Claude Code, Cursor, Copilot, Windsurf, Codex).",
|