rhachet-roles-bhuild 0.1.3 → 0.4.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.
Files changed (47) hide show
  1. package/dist/domain.operations/behavior/bind/flattenBranchName.cli.d.ts +2 -0
  2. package/dist/domain.operations/behavior/bind/flattenBranchName.cli.js +19 -0
  3. package/dist/domain.operations/behavior/bind/flattenBranchName.cli.js.map +1 -0
  4. package/dist/domain.operations/behavior/bind/flattenBranchName.d.ts +8 -0
  5. package/dist/domain.operations/behavior/bind/flattenBranchName.js +19 -0
  6. package/dist/domain.operations/behavior/bind/flattenBranchName.js.map +1 -0
  7. package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.d.ts +2 -0
  8. package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.js +18 -0
  9. package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.js.map +1 -0
  10. package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.d.ts +11 -0
  11. package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.js +51 -0
  12. package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.js.map +1 -0
  13. package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.d.ts +2 -0
  14. package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.js +20 -0
  15. package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.js.map +1 -0
  16. package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.d.ts +11 -0
  17. package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.js +51 -0
  18. package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.js.map +1 -0
  19. package/dist/domain.operations/behavior/bind/index.d.ts +3 -0
  20. package/dist/domain.operations/behavior/bind/index.js +10 -0
  21. package/dist/domain.operations/behavior/bind/index.js.map +1 -0
  22. package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.criteria-satisfied.md +37 -0
  23. package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.determinism-declared.md +44 -0
  24. package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.test-coverage-specified.md +42 -0
  25. package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.test-patterns-specified.md +43 -0
  26. package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.dependency-order.md +43 -0
  27. package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.depth-groups.md +44 -0
  28. package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.usecase-groups.md +41 -0
  29. package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.require.bdd-format.md +25 -0
  30. package/dist/domain.roles/behaver/briefs/practices/behavior.roadmap/rule.prefer.clear-deliverables.md +46 -0
  31. package/dist/domain.roles/behaver/briefs/practices/behavior.roadmap/rule.prefer.dependency-order.md +59 -0
  32. package/dist/domain.roles/behaver/briefs/practices/behavior.wish/rule.prefer.bounded-scope.md +29 -0
  33. package/dist/domain.roles/behaver/briefs/practices/behavior.wish/rule.prefer.clear-desires.md +31 -0
  34. package/dist/domain.roles/behaver/getBehaverRole.js +4 -0
  35. package/dist/domain.roles/behaver/getBehaverRole.js.map +1 -1
  36. package/dist/domain.roles/behaver/inits/claude.hooks/sessionstart.boot-behavior.sh +109 -0
  37. package/dist/domain.roles/behaver/inits/init.claude.hooks.findsert.sh +226 -0
  38. package/dist/domain.roles/behaver/inits/init.claude.hooks.sh +34 -0
  39. package/dist/domain.roles/behaver/skills/bind.behavior.sh +236 -0
  40. package/dist/domain.roles/behaver/skills/init.behavior.sh +51 -0
  41. package/dist/domain.roles/behaver/skills/review.behavior.sh +396 -0
  42. package/dist/domain.roles/behaver/skills/review.behavior.test.utils.d.ts +12 -0
  43. package/dist/domain.roles/behaver/skills/review.behavior.test.utils.js +63 -0
  44. package/dist/domain.roles/behaver/skills/review.behavior.test.utils.js.map +1 -0
  45. package/dist/domain.roles/behaver/skills/review.deliverable.sh +344 -0
  46. package/package.json +10 -8
  47. package/readme.md +34 -0
@@ -0,0 +1,59 @@
1
+ .rule = prefer.dependency-order
2
+
3
+ .what = roadmap phases should be ordered by dependency
4
+
5
+ .why = dependency order enables correct execution sequence and parallel work identification; prerequisites must be built before dependents
6
+
7
+ .how = verify that phase prerequisites are listed before dependents; check for circular dependencies which are blockers
8
+
9
+ .examples:
10
+ .positive:
11
+ - |
12
+ ## dependencies
13
+
14
+ ```
15
+ phase.0 (scaffolding)
16
+
17
+ phase.1 (rule briefs)
18
+
19
+ phase.2 (composite skill)
20
+
21
+ phase.3 (symlinks)
22
+
23
+ phase.4 (validation)
24
+ ```
25
+
26
+ ## phase.0 = scaffolding
27
+
28
+ ### dependencies
29
+ - none
30
+
31
+ ## phase.1 = rule briefs
32
+
33
+ ### dependencies
34
+ - [x] phase.0 complete (scaffolding exists)
35
+ .negative:
36
+ - |
37
+ ## phase.1 = validation
38
+
39
+ run validation to check everything works.
40
+
41
+ ## phase.2 = implementation
42
+
43
+ implement the features to validate.
44
+
45
+ (validation before implementation - wrong order)
46
+ - |
47
+ ## phase.1 = skill
48
+
49
+ ### dependencies
50
+ - phase.2 complete
51
+
52
+ ## phase.2 = tests
53
+
54
+ ### dependencies
55
+ - phase.1 complete
56
+
57
+ (circular dependency)
58
+
59
+ .severity = BLOCKER
@@ -0,0 +1,29 @@
1
+ .rule = prefer.bounded-scope
2
+
3
+ .what = wishes should define boundaries of what is in scope and out of scope
4
+
5
+ .why = unbounded scope leads to scope creep and unclear completion criteria; explicit boundaries enable focused implementation
6
+
7
+ .how = check for explicit scope boundaries or constraints; verify the wish does not imply unlimited or vague scope
8
+
9
+ .examples:
10
+ .positive:
11
+ - |
12
+ # wish
13
+
14
+ wish = create rule briefs for behavior artifact review
15
+
16
+ ## scope
17
+ - in: wish, criteria, blueprint, roadmap artifacts
18
+ - out: code review, test review, documentation review
19
+ .negative:
20
+ - |
21
+ # wish
22
+
23
+ wish = review all project artifacts comprehensively
24
+ - |
25
+ # wish
26
+
27
+ wish = make everything better
28
+
29
+ .severity = NITPICK
@@ -0,0 +1,31 @@
1
+ .rule = prefer.clear-desires
2
+
3
+ .what = wishes must clearly state what is desired
4
+
5
+ .why = ambiguous wishes lead to misaligned implementations; clear desires enable accurate criteria, blueprints, and roadmaps
6
+
7
+ .how = check for explicit "wish =" statement with concrete, actionable desires; verify desires are specific enough to derive testable criteria
8
+
9
+ .examples:
10
+ .positive:
11
+ - |
12
+ # wish
13
+
14
+ wish = create a skill that reviews behavior artifacts against best practice rules
15
+
16
+ ## desires
17
+ - review wish documents for clarity and scope
18
+ - review criteria documents for bdd format compliance
19
+ - review blueprints for test coverage specification
20
+ - review roadmaps for dependency order
21
+ .negative:
22
+ - |
23
+ # wish
24
+
25
+ make the system better at reviewing things
26
+ - |
27
+ # wish
28
+
29
+ wish = improve quality
30
+
31
+ .severity = BLOCKER
@@ -19,5 +19,9 @@ Used to declare clear and testable behaviors that can be reliably built and veri
19
19
  briefs: {
20
20
  dirs: [{ uri: __dirname + '/briefs' }],
21
21
  },
22
+ inits: {
23
+ dirs: { uri: __dirname + '/inits' },
24
+ exec: [{ cmd: __dirname + '/inits/init.claude.hooks.sh' }],
25
+ },
22
26
  });
23
27
  //# sourceMappingURL=getBehaverRole.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getBehaverRole.js","sourceRoot":"","sources":["../../../src/domain.roles/behaver/getBehaverRole.ts"],"names":[],"mappings":";;;AAAA,qCAA+B;AAElB,QAAA,YAAY,GAAS,cAAI,CAAC,KAAK,CAAC;IAC3C,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,kDAAkD;IAC3D,MAAM,EAAE;;;;GAIP,CAAC,IAAI,EAAE;IACR,MAAM,EAAE,EAAE;IACV,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;QACtC,IAAI,EAAE,EAAE;KACT;IACD,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;KACvC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"getBehaverRole.js","sourceRoot":"","sources":["../../../src/domain.roles/behaver/getBehaverRole.ts"],"names":[],"mappings":";;;AAAA,qCAA+B;AAElB,QAAA,YAAY,GAAS,cAAI,CAAC,KAAK,CAAC;IAC3C,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,kDAAkD;IAC3D,MAAM,EAAE;;;;GAIP,CAAC,IAAI,EAAE;IACR,MAAM,EAAE,EAAE;IACV,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;QACtC,IAAI,EAAE,EAAE;KACT;IACD,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;KACvC;IACD,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,GAAG,QAAQ,EAAE;QACnC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,GAAG,6BAA6B,EAAE,CAAC;KAC3D;CACF,CAAC,CAAC"}
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env bash
2
+ ######################################################################
3
+ # .what = inject bound behavior context on session start
4
+ #
5
+ # .why = agent starts with full awareness of current behavior
6
+ #
7
+ # .note = SessionStart hooks run on both session start AND compaction
8
+ # this means behavior context is re-injected after context
9
+ # is summarized, keeping the agent aligned.
10
+ #
11
+ # guarantee:
12
+ # ✔ exits 0 silently if branch not bound (unbound = normal work)
13
+ # ✔ exits 0 with warning if multiple bindings (don't block session)
14
+ # ✔ never blocks session start (exit 0 always)
15
+ ######################################################################
16
+
17
+ # note: no set -e because we must exit 0 always
18
+ set -uo pipefail
19
+
20
+ # resolve script location and repo root
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
23
+
24
+ # ────────────────────────────────────────────────────────────────────
25
+ # helpers
26
+ # ────────────────────────────────────────────────────────────────────
27
+
28
+ get_bound_behavior() {
29
+ npx tsx "$REPO_ROOT/src/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.ts" "$1" 2>/dev/null || echo '{"behaviorDir":null,"bindings":[]}'
30
+ }
31
+
32
+ get_latest_blueprint() {
33
+ npx tsx "$REPO_ROOT/src/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.ts" "$1" 2>/dev/null || echo ""
34
+ }
35
+
36
+ # ────────────────────────────────────────────────────────────────────
37
+ # main
38
+ # ────────────────────────────────────────────────────────────────────
39
+
40
+ # get current branch
41
+ CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
42
+ if [[ -z "$CURRENT_BRANCH" ]]; then
43
+ exit 0 # not in a git repo, silently exit
44
+ fi
45
+
46
+ # check if bound
47
+ BINDING_RESULT=$(get_bound_behavior "$CURRENT_BRANCH")
48
+ BEHAVIOR_DIR=$(echo "$BINDING_RESULT" | jq -r '.behaviorDir // empty')
49
+ BINDINGS_COUNT=$(echo "$BINDING_RESULT" | jq -r '.bindings | length')
50
+
51
+ # if not bound, exit silently
52
+ if [[ -z "$BEHAVIOR_DIR" || "$BEHAVIOR_DIR" == "null" ]]; then
53
+ # check for multiple bindings (conflict)
54
+ if [[ "$BINDINGS_COUNT" -gt 1 ]]; then
55
+ echo "⚠️ warning: branch '$CURRENT_BRANCH' has conflicting bindings:" >&2
56
+ echo "$BINDING_RESULT" | jq -r '.bindings[]' | while read -r binding; do
57
+ echo " - $(basename "$binding")" >&2
58
+ done
59
+ echo "use 'bind.behavior.sh --del' to unbind and 'bind.behavior.sh --set' to rebind" >&2
60
+ fi
61
+ exit 0
62
+ fi
63
+
64
+ # extract behavior name from path
65
+ BEHAVIOR_NAME=$(basename "$BEHAVIOR_DIR")
66
+
67
+ # ────────────────────────────────────────────────────────────────────
68
+ # output behavior context
69
+ # ────────────────────────────────────────────────────────────────────
70
+
71
+ echo "=================================================="
72
+ echo "BOUND BEHAVIOR: $BEHAVIOR_NAME"
73
+ echo "=================================================="
74
+ echo ""
75
+
76
+ # helper to output a behavior file
77
+ output_behavior_file() {
78
+ local tag="$1"
79
+ local filepath="$2"
80
+ local is_required="$3"
81
+
82
+ if [[ -f "$filepath" ]]; then
83
+ local relpath
84
+ relpath=$(realpath --relative-to="$PWD" "$filepath" 2>/dev/null || echo "$filepath")
85
+ echo "<behavior-$tag path=\"$relpath\">"
86
+ cat "$filepath"
87
+ echo "</behavior-$tag>"
88
+ echo ""
89
+ elif [[ "$is_required" == "true" ]]; then
90
+ echo "⚠️ missing required file: $filepath" >&2
91
+ fi
92
+ }
93
+
94
+ # output wish (required)
95
+ output_behavior_file "wish" "$BEHAVIOR_DIR/0.wish.md" "true"
96
+
97
+ # output vision (optional)
98
+ output_behavior_file "vision" "$BEHAVIOR_DIR/1.vision.md" "false"
99
+
100
+ # output criteria (optional)
101
+ output_behavior_file "criteria" "$BEHAVIOR_DIR/2.criteria.md" "false"
102
+
103
+ # output latest blueprint (optional)
104
+ LATEST_BLUEPRINT=$(get_latest_blueprint "$BEHAVIOR_DIR")
105
+ if [[ -n "$LATEST_BLUEPRINT" && -f "$LATEST_BLUEPRINT" ]]; then
106
+ output_behavior_file "blueprint" "$LATEST_BLUEPRINT" "false"
107
+ fi
108
+
109
+ echo "=================================================="
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env bash
2
+ ######################################################################
3
+ # .what = generic findsert utility for Claude hooks
4
+ #
5
+ # .why = centralizes the "find-or-insert" logic for binding hooks
6
+ # to .claude/settings.local.json, avoiding duplication across
7
+ # individual hook initializers.
8
+ #
9
+ # .how = takes hook configuration as arguments and uses jq to merge
10
+ # the hook into the settings file, creating structure if absent.
11
+ #
12
+ # usage:
13
+ # init.claude.hooks.findsert.sh \
14
+ # --hook-type SessionStart|PreToolUse \
15
+ # --matcher "*"|"Bash"|... \
16
+ # --command "command to run" \
17
+ # --name "hookname" \
18
+ # [--timeout 5] \
19
+ # [--position append|prepend]
20
+ #
21
+ # guarantee:
22
+ # ✔ creates .claude/settings.local.json if missing
23
+ # ✔ preserves existing settings (permissions, other hooks)
24
+ # ✔ idempotent: no-op if hook already present (at correct position)
25
+ # ✔ fail-fast on errors
26
+ ######################################################################
27
+
28
+ set -euo pipefail
29
+
30
+ # fail loud: print what failed
31
+ trap 'echo "❌ init.claude.hooks.findsert.sh failed at line $LINENO" >&2' ERR
32
+
33
+ # Defaults
34
+ HOOK_TYPE=""
35
+ MATCHER=""
36
+ HOOK_COMMAND=""
37
+ HOOK_NAME=""
38
+ TIMEOUT=5
39
+ POSITION="append"
40
+ AUTHOR="repo=bhuild/role=behaver"
41
+
42
+ # Parse arguments
43
+ while [[ $# -gt 0 ]]; do
44
+ case "$1" in
45
+ --hook-type)
46
+ HOOK_TYPE="$2"
47
+ shift 2
48
+ ;;
49
+ --matcher)
50
+ MATCHER="$2"
51
+ shift 2
52
+ ;;
53
+ --command)
54
+ HOOK_COMMAND="$2"
55
+ shift 2
56
+ ;;
57
+ --name)
58
+ HOOK_NAME="$2"
59
+ shift 2
60
+ ;;
61
+ --timeout)
62
+ TIMEOUT="$2"
63
+ shift 2
64
+ ;;
65
+ --position)
66
+ POSITION="$2"
67
+ shift 2
68
+ ;;
69
+ --author)
70
+ AUTHOR="$2"
71
+ shift 2
72
+ ;;
73
+ *)
74
+ echo "Unknown argument: $1" >&2
75
+ exit 1
76
+ ;;
77
+ esac
78
+ done
79
+
80
+ # Validate required arguments
81
+ if [[ -z "$HOOK_TYPE" || -z "$MATCHER" || -z "$HOOK_COMMAND" || -z "$HOOK_NAME" ]]; then
82
+ echo "Usage: $0 --hook-type TYPE --matcher MATCHER --command CMD --name NAME [--timeout SECS] [--position append|prepend] [--author AUTHOR]" >&2
83
+ exit 1
84
+ fi
85
+
86
+ PROJECT_ROOT="$PWD"
87
+ SETTINGS_FILE="$PROJECT_ROOT/.claude/settings.local.json"
88
+
89
+ # Ensure .claude directory exists
90
+ mkdir -p "$(dirname "$SETTINGS_FILE")"
91
+
92
+ # Initialize settings file if it doesn't exist
93
+ if [[ ! -f "$SETTINGS_FILE" ]]; then
94
+ echo "{}" > "$SETTINGS_FILE"
95
+ fi
96
+
97
+ # Build the hook configuration JSON
98
+ HOOK_CONFIG=$(jq -n \
99
+ --arg hookType "$HOOK_TYPE" \
100
+ --arg matcher "$MATCHER" \
101
+ --arg command "$HOOK_COMMAND" \
102
+ --argjson timeout "$TIMEOUT" \
103
+ --arg author "$AUTHOR" \
104
+ '{
105
+ hooks: {
106
+ ($hookType): [
107
+ {
108
+ matcher: $matcher,
109
+ hooks: [
110
+ {
111
+ type: "command",
112
+ command: $command,
113
+ timeout: $timeout,
114
+ author: $author
115
+ }
116
+ ]
117
+ }
118
+ ]
119
+ }
120
+ }'
121
+ )
122
+
123
+ # Generate jq script based on position (append vs prepend)
124
+ if [[ "$POSITION" == "prepend" ]]; then
125
+ # Prepend: ensure hook is first in the array
126
+ JQ_SCRIPT=$(cat <<'JQEOF'
127
+ def hookType: $hookType;
128
+ def matcher: $matcher;
129
+ def targetCmd: $hook.hooks[hookType][0].hooks[0].command;
130
+
131
+ # Check if hook is already first in the matcher
132
+ def hookIsFirst:
133
+ (.hooks[hookType] // [])
134
+ | map(select(.matcher == matcher) | .hooks // [])
135
+ | flatten
136
+ | first
137
+ | .command == targetCmd;
138
+
139
+ # If hook is already first, return unchanged
140
+ if hookIsFirst then
141
+ .
142
+ else
143
+ # Ensure .hooks exists
144
+ .hooks //= {} |
145
+
146
+ # Ensure .hooks[hookType] exists
147
+ .hooks[hookType] //= [] |
148
+
149
+ # Check if our matcher already exists
150
+ if (.hooks[hookType] | map(.matcher) | index(matcher)) then
151
+ # Matcher exists - remove our hook if present, then prepend it
152
+ .hooks[hookType] |= map(
153
+ if .matcher == matcher then
154
+ .hooks = $hook.hooks[hookType][0].hooks + (.hooks | map(select(.command != targetCmd)))
155
+ else
156
+ .
157
+ end
158
+ )
159
+ else
160
+ # Matcher does not exist, add the entire entry
161
+ .hooks[hookType] += $hook.hooks[hookType]
162
+ end
163
+ end
164
+ JQEOF
165
+ )
166
+ else
167
+ # Append: add hook to end of array (default)
168
+ JQ_SCRIPT=$(cat <<'JQEOF'
169
+ def hookType: $hookType;
170
+ def matcher: $matcher;
171
+ def targetCmd: $hook.hooks[hookType][0].hooks[0].command;
172
+
173
+ # Check if hook already exists anywhere
174
+ def hookExists:
175
+ (.hooks[hookType] // [])
176
+ | map(select(.matcher == matcher) | .hooks // [])
177
+ | flatten
178
+ | map(.command)
179
+ | any(. == targetCmd);
180
+
181
+ # If hook already exists, return unchanged
182
+ if hookExists then
183
+ .
184
+ else
185
+ # Ensure .hooks exists
186
+ .hooks //= {} |
187
+
188
+ # Ensure .hooks[hookType] exists
189
+ .hooks[hookType] //= [] |
190
+
191
+ # Check if our matcher already exists
192
+ if (.hooks[hookType] | map(.matcher) | index(matcher)) then
193
+ # Matcher exists, add our hook to its hooks array
194
+ .hooks[hookType] |= map(
195
+ if .matcher == matcher then
196
+ .hooks += $hook.hooks[hookType][0].hooks
197
+ else
198
+ .
199
+ end
200
+ )
201
+ else
202
+ # Matcher does not exist, add the entire entry
203
+ .hooks[hookType] += $hook.hooks[hookType]
204
+ end
205
+ end
206
+ JQEOF
207
+ )
208
+ fi
209
+
210
+ # Run jq with the appropriate script
211
+ jq --argjson hook "$HOOK_CONFIG" \
212
+ --arg hookType "$HOOK_TYPE" \
213
+ --arg matcher "$MATCHER" \
214
+ "$JQ_SCRIPT" "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp"
215
+
216
+ # Check if any changes were made
217
+ if diff -q "$SETTINGS_FILE" "$SETTINGS_FILE.tmp" >/dev/null 2>&1; then
218
+ rm "$SETTINGS_FILE.tmp"
219
+ echo "👌 $HOOK_NAME hook already bound"
220
+ exit 0
221
+ fi
222
+
223
+ # Atomic replace
224
+ mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
225
+
226
+ echo "🔗 $HOOK_NAME hook bound successfully!"
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ ######################################################################
3
+ # .what = bind behaver hooks to Claude settings
4
+ #
5
+ # .why = the behaver role uses a SessionStart hook to inject
6
+ # bound behavior context into agent sessions on start
7
+ # and compaction events.
8
+ #
9
+ # .how = calls findsert for the boot-behavior hook
10
+ #
11
+ # guarantee:
12
+ # ✔ idempotent: safe to rerun
13
+ # ✔ fail-fast on errors
14
+ ######################################################################
15
+
16
+ set -euo pipefail
17
+
18
+ # fail loud: print what failed
19
+ trap 'echo "❌ init.claude.hooks.sh failed at line $LINENO" >&2' ERR
20
+
21
+ INITS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ FINDSERT="$INITS_DIR/init.claude.hooks.findsert.sh"
23
+
24
+ # path to hook scripts (relative to this script)
25
+ HOOKS_DIR="$INITS_DIR/claude.hooks"
26
+
27
+ # SessionStart hook: boot behavior context
28
+ # note: SessionStart hooks run on both session start AND compaction
29
+ "$FINDSERT" \
30
+ --hook-type SessionStart \
31
+ --matcher "*" \
32
+ --command "$HOOKS_DIR/sessionstart.boot-behavior.sh" \
33
+ --name "sessionstart.boot-behavior" \
34
+ --timeout 10