rhachet-roles-ehmpathy 1.17.12 → 1.17.13
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/domain.roles/mechanic/briefs/practices/lang.terms/rule.forbid.term-script.md +81 -0
- package/dist/domain.roles/mechanic/inits/claude.hooks/pretooluse.forbid-terms.blocklist.sh +170 -0
- package/dist/domain.roles/mechanic/inits/claude.hooks/{pretooluse.forbid-gerunds.sh → pretooluse.forbid-terms.gerunds.sh} +32 -23
- package/dist/domain.roles/mechanic/inits/claude.hooks/terms.blocklist.jsonc +11 -0
- package/dist/domain.roles/mechanic/inits/init.claude.hooks.sh +21 -6
- package/dist/domain.roles/mechanic/inits/init.claude.permissions.jsonc +3 -1
- package/package.json +5 -5
- package/dist/domain.roles/mechanic/briefs/practices/lang.terms/rule.forbid.term-script.md.pt1.md +0 -7
- package/dist/domain.roles/mechanic/briefs/practices/lang.terms/rule.forbid.term-script.md.pt2.md +0 -9
- /package/dist/domain.roles/mechanic/inits/claude.hooks/{gerunds.allowlist.jsonc → terms.gerunds.allowlist.jsonc} +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
### .rule = forbid-term-script
|
|
2
|
+
|
|
3
|
+
#### .what
|
|
4
|
+
the term `script` is forbidden — it is overloaded and vague
|
|
5
|
+
|
|
6
|
+
#### .scope
|
|
7
|
+
- code: variable names, function names, comments
|
|
8
|
+
- files: filenames, directory names
|
|
9
|
+
- docs: markdown, briefs, prompts
|
|
10
|
+
- comms: commit messages, pr descriptions
|
|
11
|
+
|
|
12
|
+
#### .why
|
|
13
|
+
- `script` means too many things — it carries no precise signal
|
|
14
|
+
- "all code is scripted" — the term adds no information
|
|
15
|
+
- forces lazy categorization instead of domain clarity
|
|
16
|
+
- hides the actual purpose and lifecycle of the code
|
|
17
|
+
|
|
18
|
+
#### .enforcement
|
|
19
|
+
use of `script` = **BLOCKER**
|
|
20
|
+
|
|
21
|
+
#### .alternatives
|
|
22
|
+
|
|
23
|
+
| 👎 vague | 👍 precise | .when |
|
|
24
|
+
| -------- | ----------- | -------------------------------- |
|
|
25
|
+
| `script` | `command` | shell-invoked, adhoc usage |
|
|
26
|
+
| `script` | `procedure` | reusable sequence of steps |
|
|
27
|
+
| `script` | `operation` | domain logic with business rules |
|
|
28
|
+
| `script` | `task` | background or scheduled work |
|
|
29
|
+
| `script` | `migration` | database schema or data changes |
|
|
30
|
+
| `script` | `hook` | lifecycle callback |
|
|
31
|
+
| `script` | `skill` | agent-invoked capability |
|
|
32
|
+
| `script` | `init` | setup or bootstrap logic |
|
|
33
|
+
| `script` | `transform` | data shape conversion |
|
|
34
|
+
| `script` | `handler` | event or request responder |
|
|
35
|
+
|
|
36
|
+
#### .examples
|
|
37
|
+
|
|
38
|
+
**👎 bad**
|
|
39
|
+
```
|
|
40
|
+
scripts/
|
|
41
|
+
deploy-script.sh
|
|
42
|
+
cleanup-script.js
|
|
43
|
+
data-script.ts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// run the script to fix the data
|
|
48
|
+
const runScript = () => { ... };
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**👍 good**
|
|
52
|
+
```
|
|
53
|
+
commands/
|
|
54
|
+
deploy.sh
|
|
55
|
+
cleanup.command.ts
|
|
56
|
+
migrations/
|
|
57
|
+
2024-01-fix-user-data.ts
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// run the migration to fix the data
|
|
62
|
+
const runMigration = () => { ... };
|
|
63
|
+
|
|
64
|
+
// invoke the command to deploy
|
|
65
|
+
const invokeDeployCommand = () => { ... };
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### .note: filenames
|
|
69
|
+
common renames:
|
|
70
|
+
|
|
71
|
+
| 👎 vague | 👍 precise |
|
|
72
|
+
| ----------------- | --------------------- |
|
|
73
|
+
| `scripts/` | `commands/` or `bin/` |
|
|
74
|
+
| `run-script.sh` | `run.command.sh` |
|
|
75
|
+
| `build-script.js` | `build.command.js` |
|
|
76
|
+
| `test-script.ts` | `test.command.ts` |
|
|
77
|
+
| `setup-script.sh` | `init.sh` |
|
|
78
|
+
|
|
79
|
+
#### .see also
|
|
80
|
+
- `rule.require.ubiqlang` — use precise domain terms
|
|
81
|
+
- `rule.require.treestruct` — name structure guidance
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = PreToolUse hook to forbid terms from a configurable blocklist
|
|
4
|
+
#
|
|
5
|
+
# .why = certain terms are overloaded or vague and degrade precision.
|
|
6
|
+
# this hook blocks Write and Edit operations that contain
|
|
7
|
+
# blocklisted terms, via the HARDNUDGE pattern (block first,
|
|
8
|
+
# allow retry).
|
|
9
|
+
#
|
|
10
|
+
# .how = reads JSON from stdin, extracts content from Write/Edit,
|
|
11
|
+
# loads terms.blocklist.jsonc, scans for matches, blocks
|
|
12
|
+
# on first attempt but allows retry within 5 minutes.
|
|
13
|
+
#
|
|
14
|
+
# usage:
|
|
15
|
+
# configure in .claude/settings.json under hooks.PreToolUse
|
|
16
|
+
#
|
|
17
|
+
# guarantee:
|
|
18
|
+
# - blocks blocklisted terms on first attempt
|
|
19
|
+
# - allows retry within 5 min window (HARDNUDGE)
|
|
20
|
+
# - shows why term is forbidden and alternatives
|
|
21
|
+
######################################################################
|
|
22
|
+
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
# config
|
|
26
|
+
HARDNUDGE_WINDOW_SECONDS=300 # 5 minutes
|
|
27
|
+
STALE_THRESHOLD_SECONDS=3600 # 1 hour
|
|
28
|
+
|
|
29
|
+
# read JSON from stdin
|
|
30
|
+
STDIN_INPUT=$(cat)
|
|
31
|
+
|
|
32
|
+
# failfast: if no input, error
|
|
33
|
+
if [[ -z "$STDIN_INPUT" ]]; then
|
|
34
|
+
echo "ERROR: PreToolUse hook received no input via stdin" >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# extract tool name
|
|
39
|
+
TOOL_NAME=$(echo "$STDIN_INPUT" | jq -r '.tool_name // empty' 2>/dev/null || echo "")
|
|
40
|
+
|
|
41
|
+
# skip if not Write or Edit
|
|
42
|
+
if [[ "$TOOL_NAME" != "Write" && "$TOOL_NAME" != "Edit" ]]; then
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# extract file path
|
|
47
|
+
FILE_PATH=$(echo "$STDIN_INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || echo "")
|
|
48
|
+
|
|
49
|
+
# extract content to scan based on tool type
|
|
50
|
+
if [[ "$TOOL_NAME" == "Write" ]]; then
|
|
51
|
+
CONTENT=$(echo "$STDIN_INPUT" | jq -r '.tool_input.content // empty' 2>/dev/null || echo "")
|
|
52
|
+
else
|
|
53
|
+
# Edit: only scan new_string (additions, not removals)
|
|
54
|
+
CONTENT=$(echo "$STDIN_INPUT" | jq -r '.tool_input.new_string // empty' 2>/dev/null || echo "")
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# skip if no content
|
|
58
|
+
if [[ -z "$CONTENT" ]]; then
|
|
59
|
+
exit 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# find hook directory for blocklist config
|
|
63
|
+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
64
|
+
BLOCKLIST_FILE="$HOOK_DIR/terms.blocklist.jsonc"
|
|
65
|
+
|
|
66
|
+
# skip if no blocklist config
|
|
67
|
+
if [[ ! -f "$BLOCKLIST_FILE" ]]; then
|
|
68
|
+
exit 0
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# load blocklist config (strip comments, parse JSON)
|
|
72
|
+
TERMS_JSON=$(sed 's|//.*||' "$BLOCKLIST_FILE" | jq -c '.terms // []' 2>/dev/null || echo "[]")
|
|
73
|
+
|
|
74
|
+
# skip if no terms
|
|
75
|
+
if [[ "$TERMS_JSON" == "[]" ]]; then
|
|
76
|
+
exit 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# find .claude directory
|
|
80
|
+
find_claude_dir() {
|
|
81
|
+
local dir="$PWD"
|
|
82
|
+
while [[ "$dir" != "/" ]]; do
|
|
83
|
+
if [[ -d "$dir/.claude" ]]; then
|
|
84
|
+
echo "$dir/.claude"
|
|
85
|
+
return 0
|
|
86
|
+
fi
|
|
87
|
+
dir="$(dirname "$dir")"
|
|
88
|
+
done
|
|
89
|
+
return 1
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
CLAUDE_DIR=$(find_claude_dir) || {
|
|
93
|
+
mkdir -p "$PWD/.claude"
|
|
94
|
+
CLAUDE_DIR="$PWD/.claude"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
NUDGE_FILE="$CLAUDE_DIR/terms.blocklist.nudges.local.json"
|
|
98
|
+
|
|
99
|
+
# ensure nudge file exists
|
|
100
|
+
if [[ ! -f "$NUDGE_FILE" ]]; then
|
|
101
|
+
echo '{}' > "$NUDGE_FILE"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# cleanup stale entries (older than 1 hour)
|
|
105
|
+
# nudge format: { hash: { time, path, terms } }
|
|
106
|
+
NOW=$(date +%s)
|
|
107
|
+
TMP_FILE=$(mktemp)
|
|
108
|
+
jq --argjson now "$NOW" --argjson threshold "$STALE_THRESHOLD_SECONDS" \
|
|
109
|
+
'to_entries | map(select(.value.time > ($now - $threshold))) | from_entries' \
|
|
110
|
+
"$NUDGE_FILE" > "$TMP_FILE" 2>/dev/null && mv "$TMP_FILE" "$NUDGE_FILE" || rm -f "$TMP_FILE"
|
|
111
|
+
|
|
112
|
+
# detect matching terms
|
|
113
|
+
DETECTED_TERMS=""
|
|
114
|
+
DETECTED_INFO=""
|
|
115
|
+
term_count=$(echo "$TERMS_JSON" | jq 'length')
|
|
116
|
+
for ((i=0; i<term_count; i++)); do
|
|
117
|
+
TERM=$(echo "$TERMS_JSON" | jq -r ".[$i].term")
|
|
118
|
+
WHY=$(echo "$TERMS_JSON" | jq -r ".[$i].why")
|
|
119
|
+
ALT=$(echo "$TERMS_JSON" | jq -r ".[$i].alt | join(\", \")")
|
|
120
|
+
|
|
121
|
+
# case-insensitive word boundary match
|
|
122
|
+
if echo "$CONTENT" | grep -iqE "\\b${TERM}\\b"; then
|
|
123
|
+
if [[ -n "$DETECTED_TERMS" ]]; then
|
|
124
|
+
DETECTED_TERMS="${DETECTED_TERMS},\"${TERM}\""
|
|
125
|
+
else
|
|
126
|
+
DETECTED_TERMS="\"${TERM}\""
|
|
127
|
+
fi
|
|
128
|
+
DETECTED_INFO="${DETECTED_INFO} ⛔ ${TERM}\n why: ${WHY}\n alt: ${ALT}\n"
|
|
129
|
+
fi
|
|
130
|
+
done
|
|
131
|
+
|
|
132
|
+
# if no terms detected, allow
|
|
133
|
+
if [[ -z "$DETECTED_TERMS" ]]; then
|
|
134
|
+
exit 0
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# build nudge key as hash of file_path
|
|
138
|
+
NUDGE_KEY=$(echo -n "${FILE_PATH}" | sha256sum | cut -d' ' -f1)
|
|
139
|
+
|
|
140
|
+
# check last attempt time (nudge format: { hash: { time, path, terms } })
|
|
141
|
+
LAST_ATTEMPT=$(jq -r --arg key "$NUDGE_KEY" '.[$key].time // 0' "$NUDGE_FILE" 2>/dev/null || echo "0")
|
|
142
|
+
elapsed=$((NOW - LAST_ATTEMPT))
|
|
143
|
+
|
|
144
|
+
if [[ $elapsed -lt $HARDNUDGE_WINDOW_SECONDS ]]; then
|
|
145
|
+
# within retry window, allow
|
|
146
|
+
exit 0
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# first attempt - record and block
|
|
150
|
+
TMP_FILE=$(mktemp)
|
|
151
|
+
jq --arg key "$NUDGE_KEY" --argjson time "$NOW" --arg path "$FILE_PATH" --argjson terms "[${DETECTED_TERMS}]" \
|
|
152
|
+
'. + {($key): {time: $time, path: $path, terms: $terms}}' \
|
|
153
|
+
"$NUDGE_FILE" > "$TMP_FILE" 2>/dev/null && mv "$TMP_FILE" "$NUDGE_FILE" || rm -f "$TMP_FILE"
|
|
154
|
+
|
|
155
|
+
# build block message
|
|
156
|
+
{
|
|
157
|
+
echo ""
|
|
158
|
+
echo "🛑 BLOCKED: forbidden term(s) detected in file write"
|
|
159
|
+
echo ""
|
|
160
|
+
echo "file: $FILE_PATH"
|
|
161
|
+
echo ""
|
|
162
|
+
echo "detected terms:"
|
|
163
|
+
echo -e "$DETECTED_INFO"
|
|
164
|
+
echo "see rule.forbid.term-* briefs for rationale."
|
|
165
|
+
echo ""
|
|
166
|
+
echo "if this is intentional and absolutely unavoidable, retry the same operation."
|
|
167
|
+
echo ""
|
|
168
|
+
} >&2
|
|
169
|
+
|
|
170
|
+
exit 2
|
|
@@ -60,7 +60,7 @@ fi
|
|
|
60
60
|
|
|
61
61
|
# find script directory for allowlist
|
|
62
62
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
63
|
-
ALLOWLIST_FILE="$SCRIPT_DIR/gerunds.allowlist.jsonc"
|
|
63
|
+
ALLOWLIST_FILE="$SCRIPT_DIR/terms.gerunds.allowlist.jsonc"
|
|
64
64
|
|
|
65
65
|
# load allowlist (strip comments, extract all words)
|
|
66
66
|
ALLOWLIST=()
|
|
@@ -123,7 +123,7 @@ CLAUDE_DIR=$(find_claude_dir) || {
|
|
|
123
123
|
CLAUDE_DIR="$PWD/.claude"
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
NUDGE_FILE="$CLAUDE_DIR/
|
|
126
|
+
NUDGE_FILE="$CLAUDE_DIR/terms.gerunds.nudges.local.json"
|
|
127
127
|
|
|
128
128
|
# ensure nudge file exists
|
|
129
129
|
if [[ ! -f "$NUDGE_FILE" ]]; then
|
|
@@ -131,37 +131,46 @@ if [[ ! -f "$NUDGE_FILE" ]]; then
|
|
|
131
131
|
fi
|
|
132
132
|
|
|
133
133
|
# cleanup stale entries (older than 1 hour)
|
|
134
|
+
# nudge format: { hash: { time, path, terms } }
|
|
134
135
|
NOW=$(date +%s)
|
|
135
136
|
TMP_FILE=$(mktemp)
|
|
136
137
|
jq --argjson now "$NOW" --argjson threshold "$STALE_THRESHOLD_SECONDS" \
|
|
137
|
-
'to_entries | map(select(.value > ($now - $threshold))) | from_entries' \
|
|
138
|
+
'to_entries | map(select(.value.time > ($now - $threshold))) | from_entries' \
|
|
138
139
|
"$NUDGE_FILE" > "$TMP_FILE" 2>/dev/null && mv "$TMP_FILE" "$NUDGE_FILE" || rm -f "$TMP_FILE"
|
|
139
140
|
|
|
140
|
-
#
|
|
141
|
-
|
|
142
|
-
for gerund in "${GERUNDS[@]}"; do
|
|
143
|
-
# build nudge key as hash of file_path + gerund
|
|
144
|
-
NUDGE_KEY=$(echo -n "${FILE_PATH}:${gerund}" | sha256sum | cut -d' ' -f1)
|
|
141
|
+
# build nudge key as hash of file_path
|
|
142
|
+
NUDGE_KEY=$(echo -n "${FILE_PATH}" | sha256sum | cut -d' ' -f1)
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
144
|
+
# check last attempt time (nudge format: { hash: { time, path, terms } })
|
|
145
|
+
LAST_ATTEMPT=$(jq -r --arg key "$NUDGE_KEY" '.[$key].time // 0' "$NUDGE_FILE" 2>/dev/null || echo "0")
|
|
146
|
+
ELAPSED=$((NOW - LAST_ATTEMPT))
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
if [[ $ELAPSED -lt $HARDNUDGE_WINDOW_SECONDS ]]; then
|
|
149
|
+
# within retry window, allow
|
|
150
|
+
exit 0
|
|
151
|
+
fi
|
|
154
152
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
153
|
+
# outside window - all detected gerunds are blocked
|
|
154
|
+
BLOCKED_GERUNDS=("${GERUNDS[@]}")
|
|
155
|
+
|
|
156
|
+
# build terms array for nudge record
|
|
157
|
+
TERMS_JSON="["
|
|
158
|
+
first=true
|
|
159
|
+
for gerund in "${BLOCKED_GERUNDS[@]}"; do
|
|
160
|
+
if [[ "$first" == "true" ]]; then
|
|
161
|
+
TERMS_JSON="${TERMS_JSON}\"${gerund}\""
|
|
162
|
+
first=false
|
|
163
|
+
else
|
|
164
|
+
TERMS_JSON="${TERMS_JSON},\"${gerund}\""
|
|
165
|
+
fi
|
|
159
166
|
done
|
|
167
|
+
TERMS_JSON="${TERMS_JSON}]"
|
|
160
168
|
|
|
161
|
-
#
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
# record attempt with new format: { hash: { time, path, terms } }
|
|
170
|
+
TMP_FILE=$(mktemp)
|
|
171
|
+
jq --arg key "$NUDGE_KEY" --argjson time "$NOW" --arg path "$FILE_PATH" --argjson terms "$TERMS_JSON" \
|
|
172
|
+
'. + {($key): {time: $time, path: $path, terms: $terms}}' \
|
|
173
|
+
"$NUDGE_FILE" > "$TMP_FILE" 2>/dev/null && mv "$TMP_FILE" "$NUDGE_FILE" || rm -f "$TMP_FILE"
|
|
165
174
|
|
|
166
175
|
# build block message
|
|
167
176
|
{
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
// forbidden terms blocklist
|
|
3
|
+
// each entry specifies a term to forbid with rationale and alternatives
|
|
4
|
+
"terms": [
|
|
5
|
+
{
|
|
6
|
+
"term": "script",
|
|
7
|
+
"why": "overloaded and vague - conflates command, procedure, operation, and mechanism",
|
|
8
|
+
"alt": ["command", "executable", "procedure", "operation", "mechanism"]
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
# • SessionStart: notify Claude of allowed permissions upfront
|
|
8
8
|
# • PreToolUse: forbid stderr redirects (2>&1)
|
|
9
9
|
# • PreToolUse: forbid gerunds in file writes (HARDNUDGE)
|
|
10
|
+
# • PreToolUse: forbid blocklisted terms in file writes (HARDNUDGE)
|
|
10
11
|
# • PreToolUse: check permissions before new requests
|
|
11
12
|
#
|
|
12
13
|
# this script manages hook registration via findsert utility.
|
|
@@ -85,18 +86,32 @@ run_findsert "pretooluse.forbid-stderr-redirect" \
|
|
|
85
86
|
--timeout 5 \
|
|
86
87
|
--position prepend
|
|
87
88
|
|
|
88
|
-
run_findsert "pretooluse.forbid-gerunds.write" \
|
|
89
|
+
run_findsert "pretooluse.forbid-terms.gerunds.write" \
|
|
89
90
|
--hook-type PreToolUse \
|
|
90
91
|
--matcher "Write" \
|
|
91
|
-
--command "$RHACHET_INIT claude.hooks/pretooluse.forbid-gerunds" \
|
|
92
|
-
--name "pretooluse.forbid-gerunds.write" \
|
|
92
|
+
--command "$RHACHET_INIT claude.hooks/pretooluse.forbid-terms.gerunds" \
|
|
93
|
+
--name "pretooluse.forbid-terms.gerunds.write" \
|
|
93
94
|
--timeout 5
|
|
94
95
|
|
|
95
|
-
run_findsert "pretooluse.forbid-gerunds.edit" \
|
|
96
|
+
run_findsert "pretooluse.forbid-terms.gerunds.edit" \
|
|
96
97
|
--hook-type PreToolUse \
|
|
97
98
|
--matcher "Edit" \
|
|
98
|
-
--command "$RHACHET_INIT claude.hooks/pretooluse.forbid-gerunds" \
|
|
99
|
-
--name "pretooluse.forbid-gerunds.edit" \
|
|
99
|
+
--command "$RHACHET_INIT claude.hooks/pretooluse.forbid-terms.gerunds" \
|
|
100
|
+
--name "pretooluse.forbid-terms.gerunds.edit" \
|
|
101
|
+
--timeout 5
|
|
102
|
+
|
|
103
|
+
run_findsert "pretooluse.forbid-terms.blocklist.write" \
|
|
104
|
+
--hook-type PreToolUse \
|
|
105
|
+
--matcher "Write" \
|
|
106
|
+
--command "$RHACHET_INIT claude.hooks/pretooluse.forbid-terms.blocklist" \
|
|
107
|
+
--name "pretooluse.forbid-terms.blocklist.write" \
|
|
108
|
+
--timeout 5
|
|
109
|
+
|
|
110
|
+
run_findsert "pretooluse.forbid-terms.blocklist.edit" \
|
|
111
|
+
--hook-type PreToolUse \
|
|
112
|
+
--matcher "Edit" \
|
|
113
|
+
--command "$RHACHET_INIT claude.hooks/pretooluse.forbid-terms.blocklist" \
|
|
114
|
+
--name "pretooluse.forbid-terms.blocklist.edit" \
|
|
100
115
|
--timeout 5
|
|
101
116
|
|
|
102
117
|
run_findsert "pretooluse.check-permissions" \
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
"permissions": {
|
|
10
10
|
// commands that should never be auto-approved
|
|
11
11
|
"deny": [
|
|
12
|
+
// whatever it uses via bash is typically executable via its own name -> own permissions
|
|
13
|
+
"Bash(bash:*)",
|
|
14
|
+
|
|
12
15
|
// git write operations - require explicit user request for audit trail
|
|
13
16
|
"Bash(git commit:*)",
|
|
14
17
|
"Bash(git add .)",
|
|
@@ -107,7 +110,6 @@
|
|
|
107
110
|
|
|
108
111
|
// commands that require explicit user approval each time
|
|
109
112
|
"ask": [
|
|
110
|
-
"Bash(bash:*)",
|
|
111
113
|
"Bash(chmod:*)",
|
|
112
114
|
"Bash(npm install:*)",
|
|
113
115
|
"Bash(pnpm install:*)",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "rhachet-roles-ehmpathy",
|
|
3
3
|
"author": "ehmpathy",
|
|
4
4
|
"description": "empathetic software construction roles and skills, via rhachet",
|
|
5
|
-
"version": "1.17.
|
|
5
|
+
"version": "1.17.13",
|
|
6
6
|
"repository": "ehmpathy/rhachet-roles-ehmpathy",
|
|
7
7
|
"homepage": "https://github.com/ehmpathy/rhachet-roles-ehmpathy",
|
|
8
8
|
"keywords": [
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"prepare:husky": "husky install && chmod ug+x .husky/*",
|
|
50
50
|
"prepare": "if [ -e .git ] && [ -z $CI ]; then npm run prepare:husky && npm run prepare:rhachet; fi",
|
|
51
51
|
"test:format:biome": "biome format",
|
|
52
|
-
"prepare:rhachet": "rhachet init && rhachet roles link --role mechanic && rhachet roles init --role mechanic"
|
|
52
|
+
"prepare:rhachet": "rhachet init && rhachet roles link --role mechanic && rhachet roles init --role mechanic && rhachet roles link --role behaver && rhachet roles init --role behaver"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@ehmpathy/as-command": "1.0.3",
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"esbuild-register": "3.6.0",
|
|
90
90
|
"husky": "8.0.3",
|
|
91
91
|
"jest": "30.2.0",
|
|
92
|
-
"rhachet": "1.20.
|
|
93
|
-
"rhachet-roles-bhrain": "0.5.
|
|
94
|
-
"rhachet-roles-bhuild": "0.5.
|
|
92
|
+
"rhachet": "1.20.7",
|
|
93
|
+
"rhachet-roles-bhrain": "0.5.9",
|
|
94
|
+
"rhachet-roles-bhuild": "0.5.6",
|
|
95
95
|
"rhachet-roles-ehmpathy": "link:.",
|
|
96
96
|
"test-fns": "1.6.0",
|
|
97
97
|
"tsc-alias": "1.8.10",
|
|
File without changes
|