rulereceipt 0.1.88 → 0.1.89
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/dist/guard.js +27 -2
- package/package.json +1 -1
package/dist/guard.js
CHANGED
|
@@ -8,6 +8,7 @@ import { loadOverrides, ruleFingerprint, ratifiedForbids } from "./overrides.js"
|
|
|
8
8
|
import { commandRunsLiteral } from "./checks/proposedAction.js";
|
|
9
9
|
import { approvalOccurrences, allowListed, approvalCommandShort, approvalScopedBranch } from "./checks/approvalGate.js";
|
|
10
10
|
import { readTranscriptFromFile } from "./parsers/transcriptParser.js";
|
|
11
|
+
import { touchedPaths, ruleWasLoaded } from "./checks/pathScope.js";
|
|
11
12
|
import { execFileSync } from "node:child_process";
|
|
12
13
|
/**
|
|
13
14
|
* The current git branch in `cwd`, or undefined if it can't be determined —
|
|
@@ -92,8 +93,28 @@ function forbidRules(cwd) {
|
|
|
92
93
|
* is why the guard cannot drift from the report: same checkers, same
|
|
93
94
|
* verdicts, different tense.
|
|
94
95
|
*/
|
|
96
|
+
/**
|
|
97
|
+
* A path-scoped rule (a subfolder CLAUDE.md, or `paths:`/`globs:` frontmatter)
|
|
98
|
+
* only governs its own subtree. The guard must honour that: enforcing it on an
|
|
99
|
+
* action OUTSIDE the subtree is a false-block — the live-blocking equivalent of
|
|
100
|
+
* a false accusation. Found 2026-10-03: subfolder-rule discovery (0.1.88) made
|
|
101
|
+
* loadRules return those scoped rules, and the guard applied every forbid
|
|
102
|
+
* globally, so a demo rule scoped to one subtree blocked an edit elsewhere.
|
|
103
|
+
*
|
|
104
|
+
* Direction of error, deliberately toward NOT blocking: an unscoped rule always
|
|
105
|
+
* applies; a scoped rule applies only when the proposed action's touched path is
|
|
106
|
+
* inside the scope. A Bash command exposes no file path to match, so a scoped
|
|
107
|
+
* rule never fires on one here — under-enforcing a subtree is safe, a false-block
|
|
108
|
+
* is not. (`check` already path-scopes via this same machinery.)
|
|
109
|
+
*/
|
|
110
|
+
function inScope(rule, touched) {
|
|
111
|
+
if (!rule.paths || rule.paths.length === 0)
|
|
112
|
+
return true;
|
|
113
|
+
return ruleWasLoaded(rule.paths, touched);
|
|
114
|
+
}
|
|
95
115
|
function structuredBlocks(cwd, event) {
|
|
96
|
-
const
|
|
116
|
+
const touched = touchedPaths([event]);
|
|
117
|
+
const cls = forbidRules(cwd).filter((c) => inScope(c.rule, touched));
|
|
97
118
|
const of = (k) => cls.filter((c) => c.kind === k);
|
|
98
119
|
const results = [
|
|
99
120
|
...runCodeContentChecks(of("codeContent"), [event]),
|
|
@@ -218,7 +239,11 @@ function reason(blocks) {
|
|
|
218
239
|
* decide — by the current permission mode — whether to ask or to deny.
|
|
219
240
|
*/
|
|
220
241
|
function unapprovedGate(cwd, command, events) {
|
|
221
|
-
|
|
242
|
+
// A Bash command exposes no file path, so a path-scoped gate (a subfolder rule)
|
|
243
|
+
// can't be confirmed in-scope and is not enforced here — same no-false-block
|
|
244
|
+
// reasoning as structuredBlocks' inScope.
|
|
245
|
+
const gates = classifyRules(loadRules(cwd)).filter((c) => c.kind === "approvalGate")
|
|
246
|
+
.filter((c) => inScope(c.rule, touchedPaths([{ role: "assistant", kind: "tool_use", toolName: "Bash", input: { command }, timestamp: "" }])));
|
|
222
247
|
for (const { rule, actions } of gates) {
|
|
223
248
|
const proposed = { role: "assistant", kind: "tool_use", toolName: "Bash", input: { command }, timestamp: "", permissionMode: "dontAsk" };
|
|
224
249
|
const occ = approvalOccurrences([...events, proposed], actions, { scopedBranch: approvalScopedBranch(rule), currentBranch: gitCurrentBranch(cwd) });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rulereceipt",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.89",
|
|
4
4
|
"description": "Checks whether your AI coding agent followed your rules, with evidence. Works with Claude Code (Codex in testing); reads CLAUDE.md, AGENTS.md, Cursor, Copilot and Windsurf rules.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|