rhachet-roles-bhuild 0.1.2 → 0.4.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/domain.operations/behavior/bind/flattenBranchName.cli.d.ts +2 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.cli.js +19 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.cli.js.map +1 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.d.ts +8 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.js +19 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.d.ts +2 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.js +18 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.d.ts +11 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.js +51 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.d.ts +2 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.js +20 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.d.ts +11 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.js +51 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.js.map +1 -0
- package/dist/domain.operations/behavior/bind/index.d.ts +3 -0
- package/dist/domain.operations/behavior/bind/index.js +10 -0
- package/dist/domain.operations/behavior/bind/index.js.map +1 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.criteria-satisfied.md +37 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.determinism-declared.md +44 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.test-coverage-specified.md +42 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.test-patterns-specified.md +43 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.dependency-order.md +43 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.depth-groups.md +44 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.usecase-groups.md +41 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.require.bdd-format.md +25 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.roadmap/rule.prefer.clear-deliverables.md +46 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.roadmap/rule.prefer.dependency-order.md +59 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.wish/rule.prefer.bounded-scope.md +29 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.wish/rule.prefer.clear-desires.md +31 -0
- package/dist/domain.roles/behaver/inits/claude.hooks/sessionstart.boot-behavior.sh +109 -0
- package/dist/domain.roles/behaver/inits/init.claude.hooks.findsert.sh +226 -0
- package/dist/domain.roles/behaver/inits/init.claude.hooks.sh +34 -0
- package/dist/domain.roles/behaver/skills/bind.behavior.sh +236 -0
- package/dist/domain.roles/behaver/skills/init.behavior.sh +55 -0
- package/dist/domain.roles/behaver/skills/review.behavior.sh +396 -0
- package/dist/domain.roles/behaver/skills/review.behavior.test.utils.d.ts +12 -0
- package/dist/domain.roles/behaver/skills/review.behavior.test.utils.js +63 -0
- package/dist/domain.roles/behaver/skills/review.behavior.test.utils.js.map +1 -0
- package/dist/domain.roles/behaver/skills/review.deliverable.sh +344 -0
- package/package.json +10 -8
- package/readme.md +34 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = review behavior artifacts against best practice rules
|
|
4
|
+
#
|
|
5
|
+
# .why = enables automated review of behavior artifacts (wish, criteria,
|
|
6
|
+
# blueprint, roadmap) against established rule briefs, producing
|
|
7
|
+
# structured feedback via bhrain review skill
|
|
8
|
+
#
|
|
9
|
+
# .how = 1. resolve behavior directory from --of argument
|
|
10
|
+
# 2. determine artifacts to review from --against (default: all)
|
|
11
|
+
# 3. invoke bhrain review for each artifact type
|
|
12
|
+
# 4. aggregate feedback into summary output
|
|
13
|
+
#
|
|
14
|
+
# usage:
|
|
15
|
+
# review.behavior.sh --of <behavior-name> [--against <targets>] [--interactive]
|
|
16
|
+
#
|
|
17
|
+
# examples:
|
|
18
|
+
# review.behavior.sh --of say-hello
|
|
19
|
+
# review.behavior.sh --of say-hello --against criteria,blueprint
|
|
20
|
+
# review.behavior.sh --of say-hello --interactive
|
|
21
|
+
#
|
|
22
|
+
# guarantee:
|
|
23
|
+
# - fail-fast if behavior not found or ambiguous
|
|
24
|
+
# - fail-fast if artifact file is absent
|
|
25
|
+
# - idempotent: safe to rerun
|
|
26
|
+
######################################################################
|
|
27
|
+
|
|
28
|
+
set -euo pipefail
|
|
29
|
+
|
|
30
|
+
trap 'echo "review.behavior.sh failed at line $LINENO"' ERR
|
|
31
|
+
|
|
32
|
+
# ────────────────────────────────────────────────────────────────────
|
|
33
|
+
# script location resolution
|
|
34
|
+
# ────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
37
|
+
BRIEFS_DIR="$SCRIPT_DIR/../briefs/practices"
|
|
38
|
+
|
|
39
|
+
# resolve claude binary (prefer global, fallback to local node_modules)
|
|
40
|
+
CLAUDE_BIN=""
|
|
41
|
+
if command -v claude >/dev/null 2>&1; then
|
|
42
|
+
CLAUDE_BIN="claude"
|
|
43
|
+
else
|
|
44
|
+
NPM_BIN_DIR="$(cd "$SCRIPT_DIR" && npm bin 2>/dev/null || echo "")"
|
|
45
|
+
if [[ -n "$NPM_BIN_DIR" && -x "$NPM_BIN_DIR/claude" ]]; then
|
|
46
|
+
CLAUDE_BIN="$NPM_BIN_DIR/claude"
|
|
47
|
+
else
|
|
48
|
+
echo "error: claude binary not found (install @anthropic-ai/claude-code or ensure claude is in PATH)"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# ────────────────────────────────────────────────────────────────────
|
|
54
|
+
# argument parsing
|
|
55
|
+
# ────────────────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
BEHAVIOR_NAME=""
|
|
58
|
+
AGAINST="wish,criteria,blueprint,roadmap"
|
|
59
|
+
INTERACTIVE=false
|
|
60
|
+
TARGET_DIR="$PWD"
|
|
61
|
+
|
|
62
|
+
while [[ $# -gt 0 ]]; do
|
|
63
|
+
case $1 in
|
|
64
|
+
--of)
|
|
65
|
+
BEHAVIOR_NAME="$2"
|
|
66
|
+
shift 2
|
|
67
|
+
;;
|
|
68
|
+
--against)
|
|
69
|
+
AGAINST="$2"
|
|
70
|
+
shift 2
|
|
71
|
+
;;
|
|
72
|
+
--interactive)
|
|
73
|
+
INTERACTIVE=true
|
|
74
|
+
shift
|
|
75
|
+
;;
|
|
76
|
+
--dir)
|
|
77
|
+
TARGET_DIR="$2"
|
|
78
|
+
shift 2
|
|
79
|
+
;;
|
|
80
|
+
--skill|--repo|--role|-s)
|
|
81
|
+
# ignore rhachet passthrough args
|
|
82
|
+
shift 2
|
|
83
|
+
;;
|
|
84
|
+
--help|-h)
|
|
85
|
+
echo "usage: review.behavior.sh --of <behavior-name> [--against <targets>] [--interactive]"
|
|
86
|
+
echo ""
|
|
87
|
+
echo "options:"
|
|
88
|
+
echo " --of <name> behavior name to review (required)"
|
|
89
|
+
echo " --against <list> comma-separated targets: wish,criteria,blueprint,roadmap (default: all)"
|
|
90
|
+
echo " --interactive run in interactive mode"
|
|
91
|
+
echo " --dir <path> target directory (default: current directory)"
|
|
92
|
+
exit 0
|
|
93
|
+
;;
|
|
94
|
+
*)
|
|
95
|
+
echo "error: unknown argument '$1'"
|
|
96
|
+
echo "usage: review.behavior.sh --of <behavior-name> [--against <targets>] [--interactive]"
|
|
97
|
+
exit 1
|
|
98
|
+
;;
|
|
99
|
+
esac
|
|
100
|
+
done
|
|
101
|
+
|
|
102
|
+
# validate required arguments
|
|
103
|
+
if [[ -z "$BEHAVIOR_NAME" ]]; then
|
|
104
|
+
echo "error: --of is required"
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# ────────────────────────────────────────────────────────────────────
|
|
109
|
+
# behavior directory resolution
|
|
110
|
+
# ────────────────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
BEHAVIOR_ROOT="$TARGET_DIR/.behavior"
|
|
113
|
+
if [[ ! -d "$BEHAVIOR_ROOT" ]]; then
|
|
114
|
+
echo "error: .behavior/ directory not found in $TARGET_DIR"
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# find matching behavior directories
|
|
119
|
+
MATCHES=()
|
|
120
|
+
while IFS= read -r -d '' dir; do
|
|
121
|
+
MATCHES+=("$dir")
|
|
122
|
+
done < <(find "$BEHAVIOR_ROOT" -maxdepth 1 -type d -name "*${BEHAVIOR_NAME}*" -print0 2>/dev/null)
|
|
123
|
+
|
|
124
|
+
if [[ ${#MATCHES[@]} -eq 0 ]]; then
|
|
125
|
+
echo "error: no behavior found matching '$BEHAVIOR_NAME'"
|
|
126
|
+
echo "available behaviors:"
|
|
127
|
+
ls -1 "$BEHAVIOR_ROOT" 2>/dev/null | sed 's/^/ /'
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
if [[ ${#MATCHES[@]} -gt 1 ]]; then
|
|
132
|
+
echo "error: multiple behaviors match '$BEHAVIOR_NAME'"
|
|
133
|
+
echo "matches:"
|
|
134
|
+
printf ' %s\n' "${MATCHES[@]}"
|
|
135
|
+
echo "please provide a more specific name"
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
BEHAVIOR_DIR="${MATCHES[0]}"
|
|
140
|
+
BEHAVIOR_DIR_REL=$(realpath --relative-to="$PWD" "$BEHAVIOR_DIR")
|
|
141
|
+
|
|
142
|
+
# ────────────────────────────────────────────────────────────────────
|
|
143
|
+
# artifact file resolution
|
|
144
|
+
# ────────────────────────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
# map target to filename pattern and rules path
|
|
147
|
+
get_artifact_info() {
|
|
148
|
+
local target="$1"
|
|
149
|
+
local behavior_dir="$2"
|
|
150
|
+
local found_file
|
|
151
|
+
local rules_dir
|
|
152
|
+
|
|
153
|
+
case "$target" in
|
|
154
|
+
wish)
|
|
155
|
+
found_file=$(find "$behavior_dir" -maxdepth 1 -name "*.wish.md" -print0 2>/dev/null \
|
|
156
|
+
| head -z -n1 \
|
|
157
|
+
| tr -d '\0')
|
|
158
|
+
rules_dir="$BRIEFS_DIR/behavior.wish"
|
|
159
|
+
;;
|
|
160
|
+
criteria)
|
|
161
|
+
found_file=$(find "$behavior_dir" -maxdepth 1 -name "*.criteria.md" -print0 2>/dev/null \
|
|
162
|
+
| head -z -n1 \
|
|
163
|
+
| tr -d '\0')
|
|
164
|
+
rules_dir="$BRIEFS_DIR/behavior.criteria"
|
|
165
|
+
;;
|
|
166
|
+
blueprint)
|
|
167
|
+
# find latest version: *.blueprint.vN.iM.md
|
|
168
|
+
found_file=$(find "$behavior_dir" -maxdepth 1 -name "*.blueprint.v*.i*.md" -print0 2>/dev/null \
|
|
169
|
+
| sort -zV -t'v' -k2 \
|
|
170
|
+
| tail -z -n1 \
|
|
171
|
+
| tr -d '\0')
|
|
172
|
+
rules_dir="$BRIEFS_DIR/behavior.blueprint"
|
|
173
|
+
;;
|
|
174
|
+
roadmap)
|
|
175
|
+
# find latest version: *.roadmap.vN.iM.md
|
|
176
|
+
found_file=$(find "$behavior_dir" -maxdepth 1 -name "*.roadmap.v*.i*.md" -print0 2>/dev/null \
|
|
177
|
+
| sort -zV -t'v' -k2 \
|
|
178
|
+
| tail -z -n1 \
|
|
179
|
+
| tr -d '\0')
|
|
180
|
+
rules_dir="$BRIEFS_DIR/behavior.roadmap"
|
|
181
|
+
;;
|
|
182
|
+
*)
|
|
183
|
+
echo ""
|
|
184
|
+
return
|
|
185
|
+
;;
|
|
186
|
+
esac
|
|
187
|
+
|
|
188
|
+
echo "${found_file:-}|${rules_dir:-}"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# ────────────────────────────────────────────────────────────────────
|
|
192
|
+
# log setup
|
|
193
|
+
# ────────────────────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
196
|
+
LOG_DIR="$TARGET_DIR/.log/bhuild/review.behavior/$TIMESTAMP"
|
|
197
|
+
mkdir -p "$LOG_DIR"
|
|
198
|
+
LOG_DIR_REL=$(realpath --relative-to="$PWD" "$LOG_DIR")
|
|
199
|
+
|
|
200
|
+
# emit input args
|
|
201
|
+
cat > "$LOG_DIR/input.args.json" <<ARGS_EOF
|
|
202
|
+
{
|
|
203
|
+
"behavior_name": "$BEHAVIOR_NAME",
|
|
204
|
+
"against": "$AGAINST",
|
|
205
|
+
"interactive": $INTERACTIVE,
|
|
206
|
+
"target_dir": "$TARGET_DIR",
|
|
207
|
+
"behavior_dir": "$BEHAVIOR_DIR"
|
|
208
|
+
}
|
|
209
|
+
ARGS_EOF
|
|
210
|
+
|
|
211
|
+
# ────────────────────────────────────────────────────────────────────
|
|
212
|
+
# review invocation
|
|
213
|
+
# ────────────────────────────────────────────────────────────────────
|
|
214
|
+
|
|
215
|
+
# show tree-structured status
|
|
216
|
+
echo ""
|
|
217
|
+
echo "🔭 review.behavior"
|
|
218
|
+
echo "├── behavior: $BEHAVIOR_DIR_REL"
|
|
219
|
+
echo "├── against: $AGAINST"
|
|
220
|
+
echo "└── log: $LOG_DIR_REL"
|
|
221
|
+
echo ""
|
|
222
|
+
|
|
223
|
+
# parse targets
|
|
224
|
+
IFS=',' read -ra TARGETS <<< "$AGAINST"
|
|
225
|
+
BLOCKERS=()
|
|
226
|
+
NITPICKS=()
|
|
227
|
+
REVIEWED_COUNT=0
|
|
228
|
+
SKIPPED_COUNT=0
|
|
229
|
+
|
|
230
|
+
for target in "${TARGETS[@]}"; do
|
|
231
|
+
target=$(echo "$target" | tr -d ' ') # trim whitespace
|
|
232
|
+
|
|
233
|
+
# get artifact info
|
|
234
|
+
artifact_info=$(get_artifact_info "$target" "$BEHAVIOR_DIR")
|
|
235
|
+
artifact_file=$(echo "$artifact_info" | cut -d'|' -f1)
|
|
236
|
+
rules_dir=$(echo "$artifact_info" | cut -d'|' -f2)
|
|
237
|
+
|
|
238
|
+
if [[ -z "$rules_dir" ]]; then
|
|
239
|
+
echo "⚠️ unknown target '$target', skipping"
|
|
240
|
+
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
241
|
+
continue
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
if [[ ! -d "$rules_dir" ]]; then
|
|
245
|
+
echo "⚠️ rules directory not found for '$target': $rules_dir"
|
|
246
|
+
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
247
|
+
continue
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
if [[ -z "$artifact_file" || ! -f "$artifact_file" ]]; then
|
|
251
|
+
echo "error: artifact not found for '$target' in $BEHAVIOR_DIR"
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
artifact_file_rel=$(realpath --relative-to="$TARGET_DIR" "$artifact_file")
|
|
256
|
+
|
|
257
|
+
# output file path
|
|
258
|
+
artifact_basename=$(basename "$artifact_file" .md)
|
|
259
|
+
output_file="$BEHAVIOR_DIR/${artifact_basename}.[feedback].[given].by_robot.v${TIMESTAMP}.md"
|
|
260
|
+
output_file_rel=$(realpath --relative-to="$TARGET_DIR" "$output_file")
|
|
261
|
+
|
|
262
|
+
# get relative path for display
|
|
263
|
+
rules_dir_rel=$(realpath --relative-to="$TARGET_DIR" "$rules_dir")
|
|
264
|
+
|
|
265
|
+
echo "├── reviewing $target..."
|
|
266
|
+
echo "│ ├── artifact: $artifact_file_rel"
|
|
267
|
+
echo "│ ├── rules: $rules_dir_rel/rule.*.md"
|
|
268
|
+
echo "│ └── output: $output_file_rel"
|
|
269
|
+
|
|
270
|
+
# collect rule files and their content
|
|
271
|
+
RULE_FILES=$(find "$rules_dir" -name "rule.*.md" -type f | sort)
|
|
272
|
+
RULES_CONTENT=""
|
|
273
|
+
while IFS= read -r rule_file; do
|
|
274
|
+
rule_name=$(basename "$rule_file")
|
|
275
|
+
rule_content=$(cat "$rule_file")
|
|
276
|
+
RULES_CONTENT="${RULES_CONTENT}### ${rule_name}\n\n${rule_content}\n\n"
|
|
277
|
+
done <<< "$RULE_FILES"
|
|
278
|
+
|
|
279
|
+
# build prompt for bhrain review (with inlined rule content)
|
|
280
|
+
PROMPT=$(cat <<EOF
|
|
281
|
+
# review.behavior: $target
|
|
282
|
+
|
|
283
|
+
you are reviewing a behavior artifact against best practice rules.
|
|
284
|
+
|
|
285
|
+
## artifact to review
|
|
286
|
+
- $artifact_file_rel
|
|
287
|
+
|
|
288
|
+
## rules to apply
|
|
289
|
+
|
|
290
|
+
$(echo -e "$RULES_CONTENT")
|
|
291
|
+
|
|
292
|
+
## instructions
|
|
293
|
+
|
|
294
|
+
1. read the artifact file
|
|
295
|
+
2. evaluate the artifact against each rule shown above
|
|
296
|
+
3. identify BLOCKERs (must fix) and NITPICKs (suggestions)
|
|
297
|
+
|
|
298
|
+
## output format
|
|
299
|
+
|
|
300
|
+
output your review feedback directly to stdout.
|
|
301
|
+
|
|
302
|
+
start with:
|
|
303
|
+
# review: $target
|
|
304
|
+
|
|
305
|
+
then list findings as:
|
|
306
|
+
- # blocker.N = description
|
|
307
|
+
- # nitpick.N = description
|
|
308
|
+
|
|
309
|
+
with clear explanations referencing the specific rules.
|
|
310
|
+
|
|
311
|
+
## begin review
|
|
312
|
+
|
|
313
|
+
read the artifact file now and output review to stdout only.
|
|
314
|
+
EOF
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# save prompt to log
|
|
318
|
+
echo "$PROMPT" > "$LOG_DIR/prompt.$target.md"
|
|
319
|
+
|
|
320
|
+
if [[ "$INTERACTIVE" == "true" ]]; then
|
|
321
|
+
# interactive mode: run claude and show output
|
|
322
|
+
(cd "$TARGET_DIR" && "$CLAUDE_BIN" --print "$PROMPT") | tee "$output_file"
|
|
323
|
+
else
|
|
324
|
+
# non-interactive: run with spinner
|
|
325
|
+
echo -n "│ ⏳ "
|
|
326
|
+
(cd "$TARGET_DIR" && echo "$PROMPT" | "$CLAUDE_BIN" --print 2>&1) > "$LOG_DIR/output.$target.md" &
|
|
327
|
+
CLAUDE_PID=$!
|
|
328
|
+
|
|
329
|
+
# spinner animation
|
|
330
|
+
SPINNER="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
331
|
+
ELAPSED=0
|
|
332
|
+
while kill -0 $CLAUDE_PID 2>/dev/null; do
|
|
333
|
+
for (( i=0; i<${#SPINNER}; i++ )); do
|
|
334
|
+
if ! kill -0 $CLAUDE_PID 2>/dev/null; then break; fi
|
|
335
|
+
echo -ne "\r│ ⏳ ${SPINNER:$i:1} ${ELAPSED}s"
|
|
336
|
+
sleep 0.1
|
|
337
|
+
done
|
|
338
|
+
ELAPSED=$((ELAPSED + 1))
|
|
339
|
+
done
|
|
340
|
+
|
|
341
|
+
wait $CLAUDE_PID
|
|
342
|
+
CLAUDE_EXIT=$?
|
|
343
|
+
|
|
344
|
+
echo -e "\r│ ✓ complete (${ELAPSED}s) "
|
|
345
|
+
|
|
346
|
+
if [[ $CLAUDE_EXIT -eq 0 ]]; then
|
|
347
|
+
# copy output to feedback file
|
|
348
|
+
cp "$LOG_DIR/output.$target.md" "$output_file"
|
|
349
|
+
|
|
350
|
+
# extract blockers and nitpicks
|
|
351
|
+
while IFS= read -r line; do
|
|
352
|
+
BLOCKERS+=("[$target] $line")
|
|
353
|
+
done < <(grep -i "^# blocker" "$output_file" 2>/dev/null || true)
|
|
354
|
+
|
|
355
|
+
while IFS= read -r line; do
|
|
356
|
+
NITPICKS+=("[$target] $line")
|
|
357
|
+
done < <(grep -i "^# nitpick" "$output_file" 2>/dev/null || true)
|
|
358
|
+
else
|
|
359
|
+
echo "│ ⛈️ review failed (exit code: $CLAUDE_EXIT)"
|
|
360
|
+
fi
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
REVIEWED_COUNT=$((REVIEWED_COUNT + 1))
|
|
364
|
+
done
|
|
365
|
+
|
|
366
|
+
# ────────────────────────────────────────────────────────────────────
|
|
367
|
+
# summary output
|
|
368
|
+
# ────────────────────────────────────────────────────────────────────
|
|
369
|
+
|
|
370
|
+
echo ""
|
|
371
|
+
echo "────────────────────────────────────────"
|
|
372
|
+
echo "🌿 summary"
|
|
373
|
+
echo "├── reviewed: $REVIEWED_COUNT"
|
|
374
|
+
echo "├── skipped: $SKIPPED_COUNT"
|
|
375
|
+
echo "├── blockers: ${#BLOCKERS[@]}"
|
|
376
|
+
echo "└── nitpicks: ${#NITPICKS[@]}"
|
|
377
|
+
|
|
378
|
+
if [[ ${#BLOCKERS[@]} -gt 0 ]]; then
|
|
379
|
+
echo ""
|
|
380
|
+
echo "⛈️ blockers:"
|
|
381
|
+
for b in "${BLOCKERS[@]}"; do
|
|
382
|
+
echo " - $b"
|
|
383
|
+
done
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
if [[ ${#NITPICKS[@]} -gt 0 ]]; then
|
|
387
|
+
echo ""
|
|
388
|
+
echo "🌊 nitpicks:"
|
|
389
|
+
for n in "${NITPICKS[@]}"; do
|
|
390
|
+
echo " - $n"
|
|
391
|
+
done
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
echo ""
|
|
395
|
+
echo "✨ review.behavior complete"
|
|
396
|
+
echo "└── log: $LOG_DIR_REL"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const SKILL_PATH: string;
|
|
2
|
+
export declare const FIXTURES_PATH: string;
|
|
3
|
+
/**
|
|
4
|
+
* .what = finds feedback file matching pattern with timestamp
|
|
5
|
+
* .why = feedback files have dynamic timestamps in filename
|
|
6
|
+
*/
|
|
7
|
+
export declare const findFeedbackFile: (dir: string, pattern: string) => string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* .what = creates a temp copy of fixture with real git history
|
|
10
|
+
* .why = avoids git-within-git issues by isolating in /tmp
|
|
11
|
+
*/
|
|
12
|
+
export declare const prepareFixtureWithGit: (fixturePath: string) => string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.prepareFixtureWithGit = exports.findFeedbackFile = exports.FIXTURES_PATH = exports.SKILL_PATH = void 0;
|
|
27
|
+
const child_process_1 = require("child_process");
|
|
28
|
+
const fs = __importStar(require("fs"));
|
|
29
|
+
const os = __importStar(require("os"));
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
|
+
exports.SKILL_PATH = path.join(__dirname, 'review.behavior.sh');
|
|
32
|
+
exports.FIXTURES_PATH = path.join(__dirname, '.test/assets/example.repo');
|
|
33
|
+
/**
|
|
34
|
+
* .what = finds feedback file matching pattern with timestamp
|
|
35
|
+
* .why = feedback files have dynamic timestamps in filename
|
|
36
|
+
*/
|
|
37
|
+
const findFeedbackFile = (dir, pattern) => {
|
|
38
|
+
const files = fs.readdirSync(dir);
|
|
39
|
+
return files.find((f) => f.includes(pattern) && f.includes('[feedback]') && f.endsWith('.md'));
|
|
40
|
+
};
|
|
41
|
+
exports.findFeedbackFile = findFeedbackFile;
|
|
42
|
+
/**
|
|
43
|
+
* .what = creates a temp copy of fixture with real git history
|
|
44
|
+
* .why = avoids git-within-git issues by isolating in /tmp
|
|
45
|
+
*/
|
|
46
|
+
const prepareFixtureWithGit = (fixturePath) => {
|
|
47
|
+
// create temp directory
|
|
48
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'review-behavior-'));
|
|
49
|
+
// copy fixture contents (including hidden directories like .behavior/)
|
|
50
|
+
(0, child_process_1.execSync)(`cp -a ${fixturePath}/. ${tempDir}/`);
|
|
51
|
+
// init git repo
|
|
52
|
+
(0, child_process_1.execSync)('git init', { cwd: tempDir });
|
|
53
|
+
(0, child_process_1.execSync)('git config user.email "test@test.com"', { cwd: tempDir });
|
|
54
|
+
(0, child_process_1.execSync)('git config user.name "Test"', { cwd: tempDir });
|
|
55
|
+
// commit behavior declarations on main
|
|
56
|
+
(0, child_process_1.execSync)('git add .behavior/', { cwd: tempDir });
|
|
57
|
+
(0, child_process_1.execSync)('git commit -m "initial: add behavior declarations"', {
|
|
58
|
+
cwd: tempDir,
|
|
59
|
+
});
|
|
60
|
+
return tempDir;
|
|
61
|
+
};
|
|
62
|
+
exports.prepareFixtureWithGit = prepareFixtureWithGit;
|
|
63
|
+
//# sourceMappingURL=review.behavior.test.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.behavior.test.utils.js","sourceRoot":"","sources":["../../../../src/domain.roles/behaver/skills/review.behavior.test.utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAyC;AACzC,uCAAyB;AACzB,uCAAyB;AACzB,2CAA6B;AAEhB,QAAA,UAAU,GAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AAChE,QAAA,aAAa,GAAW,IAAI,CAAC,IAAI,CAC5C,SAAS,EACT,2BAA2B,CAC5B,CAAC;AAEF;;;GAGG;AACI,MAAM,gBAAgB,GAAG,CAC9B,GAAW,EACX,OAAe,EACK,EAAE;IACtB,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,IAAI,CACf,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC5E,CAAC;AACJ,CAAC,CAAC;AARW,QAAA,gBAAgB,oBAQ3B;AAEF;;;GAGG;AACI,MAAM,qBAAqB,GAAG,CAAC,WAAmB,EAAU,EAAE;IACnE,wBAAwB;IACxB,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAE3E,uEAAuE;IACvE,IAAA,wBAAQ,EAAC,SAAS,WAAW,MAAM,OAAO,GAAG,CAAC,CAAC;IAE/C,gBAAgB;IAChB,IAAA,wBAAQ,EAAC,UAAU,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACvC,IAAA,wBAAQ,EAAC,uCAAuC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACpE,IAAA,wBAAQ,EAAC,6BAA6B,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAE1D,uCAAuC;IACvC,IAAA,wBAAQ,EAAC,oBAAoB,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACjD,IAAA,wBAAQ,EAAC,oDAAoD,EAAE;QAC7D,GAAG,EAAE,OAAO;KACb,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAnBW,QAAA,qBAAqB,yBAmBhC"}
|