rhachet-roles-ehmpathy 1.9.0 β 1.10.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/dist/logic/roles/coach/.briefs/claude.context-caching.md +76 -0
- package/dist/logic/roles/mechanic/.briefs/lessons/code.prod.typescript.types/bivariance_vs_contravariance.[lesson].md +95 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/code.prod.errors.failfast/bad-practices/forbid.failhide.md +19 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/code.prod.errors.failfast/best-practice/prefer.HelpfulError.wrap.md +54 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/code.prod.narrative/bad-practices/forbid.else.md +54 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/code.prod.narrative/best-practice/early-returns.named-checks.[demo].md +181 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/code.prod.repo.structure/bad-practices/forbid.index.ts.md +3 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/code.test.howto/best-practice/howto.diagnose.[lesson].md +14 -0
- package/dist/logic/roles/mechanic/.briefs/patterns/lang.terms/best-practice/require.order.noun_adj.md +39 -0
- package/dist/logic/roles/mechanic/.skills/declapract.upgrade.sh +50 -0
- package/dist/logic/roles/mechanic/.skills/init.bhuild.sh +260 -0
- package/dist/logic/roles/mechanic/.skills/init.claude.hooks.sh +113 -0
- package/dist/logic/roles/mechanic/.skills/init.claude.permissions.sh +109 -0
- package/dist/logic/roles/mechanic/.skills/init.claude.sh +35 -0
- package/dist/logic/roles/mechanic/.skills/link.claude.transcripts.sh +43 -0
- package/dist/logic/roles/mechanic/.skills/run.test.sh +251 -0
- package/dist/logic/roles/mechanic/.skills/test.integration.sh +50 -0
- package/package.json +2 -2
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = initialize a .behavior directory for bhuild thoughtroute
|
|
4
|
+
#
|
|
5
|
+
# .why = standardize the behavior-driven development thoughtroute
|
|
6
|
+
# by scaffolding a structured directory with:
|
|
7
|
+
# - wish definition
|
|
8
|
+
# - vision statement
|
|
9
|
+
# - acceptance criteria
|
|
10
|
+
# - research prompts
|
|
11
|
+
# - distillation prompts
|
|
12
|
+
# - blueprint prompts
|
|
13
|
+
# - roadmap prompts
|
|
14
|
+
# - execution prompts
|
|
15
|
+
# - feedback template
|
|
16
|
+
#
|
|
17
|
+
# .how = creates .behavior/v${isodate}.${behaviorname}/ with
|
|
18
|
+
# all necessary scaffold files for the bhuild thoughtroute
|
|
19
|
+
#
|
|
20
|
+
# usage:
|
|
21
|
+
# init.bhuild.sh --name <behaviorname> [--dir <directory>]
|
|
22
|
+
#
|
|
23
|
+
# guarantee:
|
|
24
|
+
# - creates .behavior/ if missing
|
|
25
|
+
# - creates versioned behavior directory
|
|
26
|
+
# - findserts all thoughtroute files (creates if missing, skips if exists)
|
|
27
|
+
# - idempotent: safe to rerun
|
|
28
|
+
# - fail-fast on errors
|
|
29
|
+
######################################################################
|
|
30
|
+
|
|
31
|
+
set -euo pipefail
|
|
32
|
+
|
|
33
|
+
# parse arguments
|
|
34
|
+
BEHAVIOR_NAME=""
|
|
35
|
+
TARGET_DIR="$PWD"
|
|
36
|
+
while [[ $# -gt 0 ]]; do
|
|
37
|
+
case $1 in
|
|
38
|
+
--name)
|
|
39
|
+
BEHAVIOR_NAME="$2"
|
|
40
|
+
shift 2
|
|
41
|
+
;;
|
|
42
|
+
--dir)
|
|
43
|
+
TARGET_DIR="$2"
|
|
44
|
+
shift 2
|
|
45
|
+
;;
|
|
46
|
+
*)
|
|
47
|
+
echo "error: unknown argument '$1'"
|
|
48
|
+
echo "usage: init.bhuild.sh --name <behaviorname> [--dir <directory>]"
|
|
49
|
+
exit 1
|
|
50
|
+
;;
|
|
51
|
+
esac
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
# validate required arguments
|
|
55
|
+
if [[ -z "$BEHAVIOR_NAME" ]]; then
|
|
56
|
+
echo "error: --name is required"
|
|
57
|
+
echo "usage: init.bhuild.sh --name <behaviorname> [--dir <directory>]"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# generate isodate in format YYYY_MM_DD
|
|
62
|
+
ISO_DATE=$(date +%Y_%m_%d)
|
|
63
|
+
|
|
64
|
+
# trim trailing .behavior from TARGET_DIR if present
|
|
65
|
+
TARGET_DIR="${TARGET_DIR%/.behavior}"
|
|
66
|
+
TARGET_DIR="${TARGET_DIR%.behavior}"
|
|
67
|
+
|
|
68
|
+
# construct behavior directory path (absolute)
|
|
69
|
+
BEHAVIOR_DIR="$TARGET_DIR/.behavior/v${ISO_DATE}.${BEHAVIOR_NAME}"
|
|
70
|
+
|
|
71
|
+
# compute relative path from caller's $PWD for file contents
|
|
72
|
+
BEHAVIOR_DIR_REL="$(realpath --relative-to="$PWD" "$TARGET_DIR")/.behavior/v${ISO_DATE}.${BEHAVIOR_NAME}"
|
|
73
|
+
# normalize: remove leading ./ if present
|
|
74
|
+
BEHAVIOR_DIR_REL="${BEHAVIOR_DIR_REL#./}"
|
|
75
|
+
|
|
76
|
+
# create behavior directory (idempotent)
|
|
77
|
+
mkdir -p "$BEHAVIOR_DIR"
|
|
78
|
+
|
|
79
|
+
# helper: findsert file (create if missing, skip if exists)
|
|
80
|
+
findsert() {
|
|
81
|
+
local filepath="$1"
|
|
82
|
+
if [[ -f "$filepath" ]]; then
|
|
83
|
+
echo " [KEEP] $(basename "$filepath")"
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
cat > "$filepath"
|
|
87
|
+
echo " [CREATE] $(basename "$filepath")"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# findsert 0.wish.md
|
|
91
|
+
findsert "$BEHAVIOR_DIR/0.wish.md" << 'EOF'
|
|
92
|
+
wish =
|
|
93
|
+
|
|
94
|
+
EOF
|
|
95
|
+
|
|
96
|
+
# findsert 1.vision.md
|
|
97
|
+
findsert "$BEHAVIOR_DIR/1.vision.md" << 'EOF'
|
|
98
|
+
|
|
99
|
+
EOF
|
|
100
|
+
|
|
101
|
+
# findsert 2.criteria.md
|
|
102
|
+
findsert "$BEHAVIOR_DIR/2.criteria.md" << 'EOF'
|
|
103
|
+
# usecase.1 = ...
|
|
104
|
+
given()
|
|
105
|
+
when()
|
|
106
|
+
then()
|
|
107
|
+
sothat()
|
|
108
|
+
then()
|
|
109
|
+
then()
|
|
110
|
+
sothat()
|
|
111
|
+
when()
|
|
112
|
+
then()
|
|
113
|
+
|
|
114
|
+
given()
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
# usecase.2 = ...
|
|
118
|
+
...
|
|
119
|
+
EOF
|
|
120
|
+
|
|
121
|
+
# findsert 3.1.research.domain._.v1.src
|
|
122
|
+
findsert "$BEHAVIOR_DIR/3.1.research.domain._.v1.src" << EOF
|
|
123
|
+
research the domain available in order to fulfill the wish declared
|
|
124
|
+
in $BEHAVIOR_DIR_REL/0.wish.md
|
|
125
|
+
|
|
126
|
+
specifically
|
|
127
|
+
- what are the domain objects that are involved with this wish
|
|
128
|
+
- entities
|
|
129
|
+
- events
|
|
130
|
+
- literals
|
|
131
|
+
- what are the domain operations
|
|
132
|
+
- getOne
|
|
133
|
+
- getAll
|
|
134
|
+
- setCreate
|
|
135
|
+
- setUpdate
|
|
136
|
+
- setDelete
|
|
137
|
+
- ...
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
use web search to discover and research
|
|
142
|
+
- cite every claim
|
|
143
|
+
- number each citation
|
|
144
|
+
- clone exact quotes from each citation
|
|
145
|
+
|
|
146
|
+
focus on these sdk's for reference, if provided
|
|
147
|
+
-
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
emit into $BEHAVIOR_DIR_REL/3.1.research.domain._.v1.i1.md
|
|
152
|
+
EOF
|
|
153
|
+
|
|
154
|
+
# findsert 3.2.distill.domain._.v1.src
|
|
155
|
+
findsert "$BEHAVIOR_DIR/3.2.distill.domain._.v1.src" << EOF
|
|
156
|
+
distill the declastruct domain.objects and domain.operations that would
|
|
157
|
+
- enable fulfillment of this wish $BEHAVIOR_DIR_REL/0.wish.md
|
|
158
|
+
- given the research declared here $BEHAVIOR_DIR_REL/3.1.research.domain._.v1.i1.md
|
|
159
|
+
|
|
160
|
+
procedure
|
|
161
|
+
1. declare the usecases and envision the contract that would be used to fulfill the usecases
|
|
162
|
+
2. declare the domain.objects, domain.operations, and access.daos that would fulfill this, via the declastruct pattern in this repo
|
|
163
|
+
|
|
164
|
+
emit into
|
|
165
|
+
- $BEHAVIOR_DIR_REL/3.2.distill.domain._.v1.i1.md
|
|
166
|
+
EOF
|
|
167
|
+
|
|
168
|
+
# findsert 3.3.blueprint.v1.src
|
|
169
|
+
findsert "$BEHAVIOR_DIR/3.3.blueprint.v1.src" << EOF
|
|
170
|
+
propose a blueprint for how we can implement the wish described
|
|
171
|
+
- in $BEHAVIOR_DIR_REL/0.wish.md
|
|
172
|
+
|
|
173
|
+
with the domain distillation declared
|
|
174
|
+
- in $BEHAVIOR_DIR_REL/3.2.distill.domain._.v1.i1.md
|
|
175
|
+
|
|
176
|
+
follow the patterns already present in this repo
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
reference the below for full context
|
|
181
|
+
- $BEHAVIOR_DIR_REL/0.wish.md
|
|
182
|
+
- $BEHAVIOR_DIR_REL/3.1.research.domain._.v1.i1.md
|
|
183
|
+
- $BEHAVIOR_DIR_REL/3.2.distill.domain._.v1.i1.md
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
emit to $BEHAVIOR_DIR_REL/3.3.blueprint.v1.i1.md
|
|
189
|
+
EOF
|
|
190
|
+
|
|
191
|
+
# findsert 4.1.roadmap.v1.src
|
|
192
|
+
findsert "$BEHAVIOR_DIR/4.1.roadmap.v1.src" << EOF
|
|
193
|
+
declare a roadmap,
|
|
194
|
+
|
|
195
|
+
- checklist style
|
|
196
|
+
- with ordered dependencies
|
|
197
|
+
- with behavioral acceptance criteria
|
|
198
|
+
- with behavioral acceptance verification at each step
|
|
199
|
+
|
|
200
|
+
for how to execute the blueprint specified in $BEHAVIOR_DIR_REL/3.3.blueprint.v1.i1.md
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
emit into $BEHAVIOR_DIR_REL/4.1.roadmap.v1.i1.md
|
|
205
|
+
EOF
|
|
206
|
+
|
|
207
|
+
# findsert 5.1.execution.phase0_to_phaseN.v1.src
|
|
208
|
+
findsert "$BEHAVIOR_DIR/5.1.execution.phase0_to_phaseN.v1.src" << EOF
|
|
209
|
+
bootup your mechanic's role via \`npx rhachet roles boot --repo ehmpathy --role mechanic\`
|
|
210
|
+
|
|
211
|
+
then, execute
|
|
212
|
+
- phase0 to phaseN
|
|
213
|
+
of roadmap
|
|
214
|
+
- $BEHAVIOR_DIR_REL/4.1.roadmap.v1.i1.md
|
|
215
|
+
|
|
216
|
+
ref:
|
|
217
|
+
- $BEHAVIOR_DIR_REL/3.3.blueprint.v1.i1.md
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
track your progress
|
|
222
|
+
|
|
223
|
+
emit todos and check them off into
|
|
224
|
+
- $BEHAVIOR_DIR_REL/5.1.execution.phase0_to_phaseN.v1.i1.md
|
|
225
|
+
EOF
|
|
226
|
+
|
|
227
|
+
# findsert .ref.[feedback].v1.[given].by_human.md
|
|
228
|
+
findsert "$BEHAVIOR_DIR/.ref.[feedback].v1.[given].by_human.md" << EOF
|
|
229
|
+
emit your response to the feedback into
|
|
230
|
+
- $BEHAVIOR_DIR_REL/.ref.[feedback].v1.[taken].by_robot.md
|
|
231
|
+
|
|
232
|
+
1. emit your response checklist
|
|
233
|
+
2. exec your response plan
|
|
234
|
+
3. emit your response checkoffs into the checklist
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
first, bootup your mechanics briefs again
|
|
239
|
+
|
|
240
|
+
npx rhachet roles boot --repo ehmpathy --role mechanic
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
---
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# blocker.1
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
# nitpick.2
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
# blocker.3
|
|
256
|
+
EOF
|
|
257
|
+
|
|
258
|
+
echo ""
|
|
259
|
+
echo "behavior thoughtroute initialized!"
|
|
260
|
+
echo " $BEHAVIOR_DIR"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = bind mechanic SessionStart hook to Claude settings
|
|
4
|
+
#
|
|
5
|
+
# .why = the mechanic role needs to boot on every Claude session
|
|
6
|
+
# to ensure project context and briefs are loaded.
|
|
7
|
+
#
|
|
8
|
+
# this script "findserts" (find-or-insert) the SessionStart
|
|
9
|
+
# hook into .claude/settings.local.json, ensuring:
|
|
10
|
+
# β’ the hook is present after running this skill
|
|
11
|
+
# β’ no duplication if already present
|
|
12
|
+
# β’ idempotent: safe to rerun
|
|
13
|
+
#
|
|
14
|
+
# .how = uses jq to merge the SessionStart hook configuration
|
|
15
|
+
# into the existing hooks structure, creating it if absent.
|
|
16
|
+
#
|
|
17
|
+
# guarantee:
|
|
18
|
+
# β creates .claude/settings.local.json if missing
|
|
19
|
+
# β preserves existing settings (permissions, other hooks)
|
|
20
|
+
# β idempotent: no-op if hook already present
|
|
21
|
+
# β fail-fast on errors
|
|
22
|
+
######################################################################
|
|
23
|
+
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
|
|
26
|
+
PROJECT_ROOT="$PWD"
|
|
27
|
+
SETTINGS_FILE="$PROJECT_ROOT/.claude/settings.local.json"
|
|
28
|
+
|
|
29
|
+
# Define the hook configuration to findsert
|
|
30
|
+
HOOK_CONFIG=$(cat <<'EOF'
|
|
31
|
+
{
|
|
32
|
+
"hooks": {
|
|
33
|
+
"SessionStart": [
|
|
34
|
+
{
|
|
35
|
+
"matcher": "*",
|
|
36
|
+
"hooks": [
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "npx rhachet roles boot --repo ehmpathy --role mechanic",
|
|
40
|
+
"timeout": 60
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
EOF
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Ensure .claude directory exists
|
|
51
|
+
mkdir -p "$(dirname "$SETTINGS_FILE")"
|
|
52
|
+
|
|
53
|
+
# Initialize settings file if it doesn't exist
|
|
54
|
+
if [[ ! -f "$SETTINGS_FILE" ]]; then
|
|
55
|
+
echo "{}" > "$SETTINGS_FILE"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Findsert: merge the hook configuration if not already present
|
|
59
|
+
# Strategy: deep merge with existing hooks, creating structure if needed
|
|
60
|
+
jq --argjson hook "$HOOK_CONFIG" '
|
|
61
|
+
# Define the target command for comparison
|
|
62
|
+
def targetCmd: "npx rhachet roles boot --repo ehmpathy --role mechanic";
|
|
63
|
+
|
|
64
|
+
# Check if hook already exists
|
|
65
|
+
def hookExists:
|
|
66
|
+
(.hooks.SessionStart // [])
|
|
67
|
+
| map(select(.matcher == "*") | .hooks // [])
|
|
68
|
+
| flatten
|
|
69
|
+
| map(.command)
|
|
70
|
+
| index(targetCmd) != null;
|
|
71
|
+
|
|
72
|
+
# If hook already exists, return unchanged
|
|
73
|
+
if hookExists then
|
|
74
|
+
.
|
|
75
|
+
else
|
|
76
|
+
# Ensure .hooks exists
|
|
77
|
+
.hooks //= {} |
|
|
78
|
+
|
|
79
|
+
# Ensure .hooks.SessionStart exists
|
|
80
|
+
.hooks.SessionStart //= [] |
|
|
81
|
+
|
|
82
|
+
# Check if our matcher already exists
|
|
83
|
+
if (.hooks.SessionStart | map(.matcher) | index("*")) then
|
|
84
|
+
# Matcher exists, add our hook to its hooks array
|
|
85
|
+
.hooks.SessionStart |= map(
|
|
86
|
+
if .matcher == "*" then
|
|
87
|
+
.hooks += $hook.hooks.SessionStart[0].hooks
|
|
88
|
+
else
|
|
89
|
+
.
|
|
90
|
+
end
|
|
91
|
+
)
|
|
92
|
+
else
|
|
93
|
+
# Matcher does not exist, add the entire entry
|
|
94
|
+
.hooks.SessionStart += $hook.hooks.SessionStart
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
' "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp"
|
|
98
|
+
|
|
99
|
+
# Check if any changes were made
|
|
100
|
+
if diff -q "$SETTINGS_FILE" "$SETTINGS_FILE.tmp" >/dev/null 2>&1; then
|
|
101
|
+
rm "$SETTINGS_FILE.tmp"
|
|
102
|
+
echo "π mechanic SessionStart hook already bound"
|
|
103
|
+
echo " $SETTINGS_FILE"
|
|
104
|
+
exit 0
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# Atomic replace
|
|
108
|
+
mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
|
|
109
|
+
|
|
110
|
+
echo "π mechanic SessionStart hook bound successfully!"
|
|
111
|
+
echo " $SETTINGS_FILE"
|
|
112
|
+
echo ""
|
|
113
|
+
echo "β¨ next time you start a Claude session, the mechanic will boot automatically"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = bind mechanic permissions to Claude settings
|
|
4
|
+
#
|
|
5
|
+
# .why = the mechanic role needs conservative permissions to operate
|
|
6
|
+
# safely while still being productive.
|
|
7
|
+
#
|
|
8
|
+
# this script manages permissions in .claude/settings.local.json:
|
|
9
|
+
# β’ replaces existing allows entirely (conservative)
|
|
10
|
+
# β’ extends denies by appending new entries (conservative)
|
|
11
|
+
# β’ extends asks by appending new entries (conservative)
|
|
12
|
+
# β’ idempotent: safe to rerun
|
|
13
|
+
#
|
|
14
|
+
# .how = uses jq to merge the permissions configuration
|
|
15
|
+
# into the existing settings structure, creating it if absent.
|
|
16
|
+
#
|
|
17
|
+
# guarantee:
|
|
18
|
+
# β creates .claude/settings.local.json if missing
|
|
19
|
+
# β preserves existing settings (hooks, other configs)
|
|
20
|
+
# β replaces allow list entirely
|
|
21
|
+
# β appends to deny list (no duplicates)
|
|
22
|
+
# β appends to ask list (no duplicates)
|
|
23
|
+
# β idempotent: safe to rerun
|
|
24
|
+
# β fail-fast on errors
|
|
25
|
+
######################################################################
|
|
26
|
+
|
|
27
|
+
set -euo pipefail
|
|
28
|
+
|
|
29
|
+
PROJECT_ROOT="$PWD"
|
|
30
|
+
SETTINGS_FILE="$PROJECT_ROOT/.claude/settings.local.json"
|
|
31
|
+
|
|
32
|
+
# define the permissions configuration to apply
|
|
33
|
+
PERMISSIONS_CONFIG=$(cat <<'EOF'
|
|
34
|
+
{
|
|
35
|
+
"permissions": {
|
|
36
|
+
"deny": [
|
|
37
|
+
"Bash(git commit:*)"
|
|
38
|
+
],
|
|
39
|
+
"ask": [
|
|
40
|
+
"Bash(chmod:*)",
|
|
41
|
+
"Bash(pnpm install:*)",
|
|
42
|
+
"Bash(pnpm add:*)"
|
|
43
|
+
],
|
|
44
|
+
"allow": [
|
|
45
|
+
"WebSearch",
|
|
46
|
+
"WebFetch(domain:github.com)",
|
|
47
|
+
"WebFetch(domain:www.npmjs.com)",
|
|
48
|
+
"WebFetch(domain:hub.docker.com)",
|
|
49
|
+
"WebFetch(domain:raw.githubusercontent.com)",
|
|
50
|
+
"Bash(THOROUGH=true npm run test:*)",
|
|
51
|
+
"Bash(AWS_PROFILE=ahbode.dev npm run test:integration:*)",
|
|
52
|
+
"Bash(npm run fix:*)",
|
|
53
|
+
"Bash(AWS_PROFILE=ahbode.dev npx jest:*)",
|
|
54
|
+
"Bash(AWS_PROFILE=ahbode.dev npm run deploy:dev:*)",
|
|
55
|
+
"Bash(AWS_PROFILE=ahbode.dev STAGE=dev npm run test:acceptance:*)",
|
|
56
|
+
"Bash(npm run start:testdb:*)",
|
|
57
|
+
"Bash(cat:*)",
|
|
58
|
+
"Bash(unzip:*)",
|
|
59
|
+
"Bash(npm view:*)"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
EOF
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# ensure .claude directory exists
|
|
67
|
+
mkdir -p "$(dirname "$SETTINGS_FILE")"
|
|
68
|
+
|
|
69
|
+
# initialize settings file if it doesn't exist
|
|
70
|
+
if [[ ! -f "$SETTINGS_FILE" ]]; then
|
|
71
|
+
echo "{}" > "$SETTINGS_FILE"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# apply permissions:
|
|
75
|
+
# - replace allow entirely
|
|
76
|
+
# - append to deny (unique)
|
|
77
|
+
# - append to ask (unique)
|
|
78
|
+
jq --argjson perms "$PERMISSIONS_CONFIG" '
|
|
79
|
+
# ensure .permissions exists
|
|
80
|
+
.permissions //= {} |
|
|
81
|
+
|
|
82
|
+
# replace allow entirely with our config
|
|
83
|
+
.permissions.allow = $perms.permissions.allow |
|
|
84
|
+
|
|
85
|
+
# append to deny (unique entries only)
|
|
86
|
+
.permissions.deny = ((.permissions.deny // []) + $perms.permissions.deny | unique) |
|
|
87
|
+
|
|
88
|
+
# append to ask (unique entries only)
|
|
89
|
+
.permissions.ask = ((.permissions.ask // []) + $perms.permissions.ask | unique)
|
|
90
|
+
' "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp"
|
|
91
|
+
|
|
92
|
+
# check if any changes were made
|
|
93
|
+
if diff -q "$SETTINGS_FILE" "$SETTINGS_FILE.tmp" >/dev/null 2>&1; then
|
|
94
|
+
rm "$SETTINGS_FILE.tmp"
|
|
95
|
+
echo "π mechanic permissions already configured"
|
|
96
|
+
echo " $SETTINGS_FILE"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# atomic replace
|
|
101
|
+
mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
|
|
102
|
+
|
|
103
|
+
echo "π mechanic permissions configured successfully!"
|
|
104
|
+
echo " $SETTINGS_FILE"
|
|
105
|
+
echo ""
|
|
106
|
+
echo "β¨ permissions applied:"
|
|
107
|
+
echo " β’ allow: replaced entirely"
|
|
108
|
+
echo " β’ deny: extended (no duplicates)"
|
|
109
|
+
echo " β’ ask: extended (no duplicates)"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = initialize Claude settings for mechanic role
|
|
4
|
+
#
|
|
5
|
+
# .why = mechanic needs both hooks and permissions configured to
|
|
6
|
+
# operate effectively. this script dispatches to both:
|
|
7
|
+
# β’ init.claude.hooks.sh - binds SessionStart hook
|
|
8
|
+
# β’ init.claude.permissions.sh - configures permissions
|
|
9
|
+
#
|
|
10
|
+
# single entry point for full Claude configuration.
|
|
11
|
+
#
|
|
12
|
+
# .how = runs both init scripts in sequence from the same directory.
|
|
13
|
+
#
|
|
14
|
+
# guarantee:
|
|
15
|
+
# β runs both hooks and permissions initialization
|
|
16
|
+
# β fail-fast on any error
|
|
17
|
+
# β idempotent: safe to rerun
|
|
18
|
+
######################################################################
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
|
|
24
|
+
echo "π§ init claude config for mechanic role..."
|
|
25
|
+
echo ""
|
|
26
|
+
|
|
27
|
+
# initialize hooks
|
|
28
|
+
"$SCRIPT_DIR/init.claude.hooks.sh"
|
|
29
|
+
echo ""
|
|
30
|
+
|
|
31
|
+
# initialize permissions
|
|
32
|
+
"$SCRIPT_DIR/init.claude.permissions.sh"
|
|
33
|
+
echo ""
|
|
34
|
+
|
|
35
|
+
echo "π claude config ready"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = link Claude transcripts into project-local structure
|
|
4
|
+
#
|
|
5
|
+
# .why = Claude stores transcripts in ~/.claude/projects/<encoded-path>
|
|
6
|
+
# which makes them hard to browse, version-control, and sync.
|
|
7
|
+
#
|
|
8
|
+
# this script creates a symlink so transcripts appear under:
|
|
9
|
+
# <project>/.rhachet/claude/transcripts
|
|
10
|
+
#
|
|
11
|
+
# without altering, moving, or creating files in Claude storage.
|
|
12
|
+
#
|
|
13
|
+
# guarantee:
|
|
14
|
+
# β zero mutation to Claude's storage
|
|
15
|
+
# β fail-fast if transcripts don't exist yet
|
|
16
|
+
# β safe to rerun (idempotent)
|
|
17
|
+
######################################################################
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
PROJECT_ROOT="$PWD"
|
|
22
|
+
DEST="$PROJECT_ROOT/.rhachet/claude/transcripts"
|
|
23
|
+
|
|
24
|
+
# Resolve where Claude stores transcripts for this projectβs cwd
|
|
25
|
+
ENCODED_PATH="$(echo "$PROJECT_ROOT" | sed 's#/#-#g')"
|
|
26
|
+
CLAUDE_STORAGE="$HOME/.claude/projects/$ENCODED_PATH"
|
|
27
|
+
|
|
28
|
+
# Fail if Claude hasn't created the storage dir yet
|
|
29
|
+
if [[ ! -d "$CLAUDE_STORAGE" ]]; then
|
|
30
|
+
echo "β no Claude transcripts found for this project:"
|
|
31
|
+
echo " $CLAUDE_STORAGE"
|
|
32
|
+
echo "β‘οΈ first run 'claude' once in this directory to create them"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Ensure our local parent folder exists (not Claudeβs)
|
|
37
|
+
mkdir -p "$(dirname "$DEST")"
|
|
38
|
+
|
|
39
|
+
# Create symlink pointing into Claude-managed storage
|
|
40
|
+
ln -sfn "$CLAUDE_STORAGE" "$DEST"
|
|
41
|
+
|
|
42
|
+
echo "π linked:"
|
|
43
|
+
echo " $DEST β $CLAUDE_STORAGE"
|