rhachet-roles-ehmpathy 1.9.1 → 1.11.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/git.worktree.common.sh +58 -0
- package/dist/logic/roles/mechanic/.skills/git.worktree.del.sh +51 -0
- package/dist/logic/roles/mechanic/.skills/git.worktree.get.sh +51 -0
- package/dist/logic/roles/mechanic/.skills/git.worktree.set.sh +108 -0
- package/dist/logic/roles/mechanic/.skills/git.worktree.sh +46 -0
- package/dist/logic/roles/mechanic/.skills/git.worktree.test.sh +229 -0
- package/dist/logic/roles/mechanic/.skills/init.bhuild.sh +260 -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/run.test.sh +8 -2
- package/package.json +2 -2
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = list git worktrees for this repo
|
|
4
|
+
#
|
|
5
|
+
# .why = discover existing worktrees managed by git.worktree.sh
|
|
6
|
+
#
|
|
7
|
+
# .how = lists worktrees at @gitroot/../_worktrees/$reponame/
|
|
8
|
+
#
|
|
9
|
+
# usage:
|
|
10
|
+
# git.worktree.get.sh
|
|
11
|
+
#
|
|
12
|
+
# guarantee:
|
|
13
|
+
# - works from root repo or from within a worktree
|
|
14
|
+
# - shows "(no worktrees)" if none exist
|
|
15
|
+
######################################################################
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
+
|
|
21
|
+
# source shared helpers
|
|
22
|
+
source "$SCRIPT_DIR/git.worktree.common.sh"
|
|
23
|
+
|
|
24
|
+
# resolve worktrees directory
|
|
25
|
+
REPO_WORKTREES_DIR="$(resolve_worktrees_dir)"
|
|
26
|
+
REPO_NAME="$(get_repo_name)"
|
|
27
|
+
|
|
28
|
+
# check if worktrees directory exists
|
|
29
|
+
if [[ ! -d "$REPO_WORKTREES_DIR" ]]; then
|
|
30
|
+
echo "(no worktrees)"
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# list worktrees
|
|
35
|
+
WORKTREES=()
|
|
36
|
+
for dir in "$REPO_WORKTREES_DIR"/*/; do
|
|
37
|
+
[[ -d "$dir" ]] && WORKTREES+=("$dir")
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
# handle empty
|
|
41
|
+
if [[ ${#WORKTREES[@]} -eq 0 ]]; then
|
|
42
|
+
echo "(no worktrees)"
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# output worktree list
|
|
47
|
+
echo "worktrees for $REPO_NAME:"
|
|
48
|
+
for dir in "${WORKTREES[@]}"; do
|
|
49
|
+
name="$(basename "$dir")"
|
|
50
|
+
echo " $name => $dir"
|
|
51
|
+
done
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = findsert a git worktree for a branch
|
|
4
|
+
#
|
|
5
|
+
# .why = enable parallel work on same repo without nested worktrees
|
|
6
|
+
# worktrees are placed outside repo so git diff stays clean
|
|
7
|
+
#
|
|
8
|
+
# .how = creates worktree at @gitroot/../_worktrees/$reponame/$branch
|
|
9
|
+
#
|
|
10
|
+
# usage:
|
|
11
|
+
# git.worktree.set.sh <branch> # findsert worktree
|
|
12
|
+
# git.worktree.set.sh <branch> --open # findsert + open in codium
|
|
13
|
+
# git.worktree.set.sh <branch> --main # create from origin/main
|
|
14
|
+
#
|
|
15
|
+
# guarantee:
|
|
16
|
+
# - idempotent: [KEEP] if exists, [CREATE] if not
|
|
17
|
+
# - works from root repo or from within a worktree
|
|
18
|
+
# - worktree placed outside repo (not nested)
|
|
19
|
+
######################################################################
|
|
20
|
+
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
|
|
25
|
+
# source shared helpers
|
|
26
|
+
source "$SCRIPT_DIR/git.worktree.common.sh"
|
|
27
|
+
|
|
28
|
+
# parse arguments
|
|
29
|
+
BRANCH=""
|
|
30
|
+
FLAG_OPEN=false
|
|
31
|
+
FLAG_MAIN=false
|
|
32
|
+
|
|
33
|
+
while [[ $# -gt 0 ]]; do
|
|
34
|
+
case $1 in
|
|
35
|
+
--open)
|
|
36
|
+
FLAG_OPEN=true
|
|
37
|
+
shift
|
|
38
|
+
;;
|
|
39
|
+
--main)
|
|
40
|
+
FLAG_MAIN=true
|
|
41
|
+
shift
|
|
42
|
+
;;
|
|
43
|
+
-*)
|
|
44
|
+
echo "error: unknown flag '$1'"
|
|
45
|
+
echo "usage: git.worktree.set.sh <branch> [--open] [--main]"
|
|
46
|
+
exit 1
|
|
47
|
+
;;
|
|
48
|
+
*)
|
|
49
|
+
if [[ -z "$BRANCH" ]]; then
|
|
50
|
+
BRANCH="$1"
|
|
51
|
+
else
|
|
52
|
+
echo "error: unexpected argument '$1'"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
shift
|
|
56
|
+
;;
|
|
57
|
+
esac
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
# validate branch argument
|
|
61
|
+
if [[ -z "$BRANCH" ]]; then
|
|
62
|
+
echo "error: branch name required"
|
|
63
|
+
echo "usage: git.worktree.set.sh <branch> [--open] [--main]"
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# resolve paths
|
|
68
|
+
REPO_WORKTREES_DIR="$(resolve_worktrees_dir)"
|
|
69
|
+
WORKTREE_NAME="$(sanitize_branch_name "$BRANCH")"
|
|
70
|
+
WORKTREE_PATH="$REPO_WORKTREES_DIR/$WORKTREE_NAME"
|
|
71
|
+
|
|
72
|
+
# ensure parent directory exists
|
|
73
|
+
mkdir -p "$REPO_WORKTREES_DIR"
|
|
74
|
+
|
|
75
|
+
# findsert logic
|
|
76
|
+
if [[ -d "$WORKTREE_PATH" ]]; then
|
|
77
|
+
echo "[KEEP] $WORKTREE_NAME => $WORKTREE_PATH"
|
|
78
|
+
else
|
|
79
|
+
# create worktree
|
|
80
|
+
if [[ "$FLAG_MAIN" == true ]]; then
|
|
81
|
+
# fetch latest main first
|
|
82
|
+
git fetch origin main 2>/dev/null || git fetch origin master 2>/dev/null || true
|
|
83
|
+
|
|
84
|
+
# create new branch from origin/main
|
|
85
|
+
git worktree add -b "$BRANCH" "$WORKTREE_PATH" origin/main 2>/dev/null || \
|
|
86
|
+
git worktree add -b "$BRANCH" "$WORKTREE_PATH" origin/master
|
|
87
|
+
else
|
|
88
|
+
# check if branch exists
|
|
89
|
+
if git show-ref --verify --quiet "refs/heads/$BRANCH" 2>/dev/null; then
|
|
90
|
+
# branch exists locally, checkout existing
|
|
91
|
+
git worktree add "$WORKTREE_PATH" "$BRANCH"
|
|
92
|
+
elif git show-ref --verify --quiet "refs/remotes/origin/$BRANCH" 2>/dev/null; then
|
|
93
|
+
# branch exists on remote, track it
|
|
94
|
+
git worktree add --track -b "$BRANCH" "$WORKTREE_PATH" "origin/$BRANCH"
|
|
95
|
+
else
|
|
96
|
+
# create new branch from current HEAD
|
|
97
|
+
git worktree add -b "$BRANCH" "$WORKTREE_PATH"
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
echo "[CREATE] $WORKTREE_NAME => $WORKTREE_PATH"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# open in codium if requested
|
|
105
|
+
if [[ "$FLAG_OPEN" == true ]]; then
|
|
106
|
+
echo "opening in codium..."
|
|
107
|
+
codium "$WORKTREE_PATH"
|
|
108
|
+
fi
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = dispatcher for git worktree management
|
|
4
|
+
#
|
|
5
|
+
# .why = single entry point for get|set|del subcommands
|
|
6
|
+
# enables convenient `git.worktree.sh get|set|del` interface
|
|
7
|
+
#
|
|
8
|
+
# .how = routes to git.worktree.{get,set,del}.sh based on subcommand
|
|
9
|
+
#
|
|
10
|
+
# usage:
|
|
11
|
+
# git.worktree.sh get # list worktrees
|
|
12
|
+
# git.worktree.sh set <branch> # findsert worktree
|
|
13
|
+
# git.worktree.sh set <branch> --open # findsert + open in codium
|
|
14
|
+
# git.worktree.sh set <branch> --main # create from origin/main
|
|
15
|
+
# git.worktree.sh del <branch> # remove worktree
|
|
16
|
+
#
|
|
17
|
+
# guarantee:
|
|
18
|
+
# - dispatches to correct subcommand script
|
|
19
|
+
# - shows usage on invalid/missing subcommand
|
|
20
|
+
# - fail-fast on errors
|
|
21
|
+
######################################################################
|
|
22
|
+
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
SUBCOMMAND="${1:-}"
|
|
27
|
+
|
|
28
|
+
case "$SUBCOMMAND" in
|
|
29
|
+
get|set|del)
|
|
30
|
+
shift
|
|
31
|
+
exec "$SCRIPT_DIR/git.worktree.$SUBCOMMAND.sh" "$@"
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
echo "usage: git.worktree.sh <command> [args]"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "commands:"
|
|
37
|
+
echo " get list worktrees for this repo"
|
|
38
|
+
echo " set <branch> findsert worktree for branch"
|
|
39
|
+
echo " del <branch> remove worktree for branch"
|
|
40
|
+
echo ""
|
|
41
|
+
echo "options (for set):"
|
|
42
|
+
echo " --open open worktree in codium after creation"
|
|
43
|
+
echo " --main create branch from origin/main"
|
|
44
|
+
exit 1
|
|
45
|
+
;;
|
|
46
|
+
esac
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
######################################################################
|
|
3
|
+
# .what = test suite for git worktree management scripts
|
|
4
|
+
#
|
|
5
|
+
# .why = verify all worktree operations work correctly
|
|
6
|
+
#
|
|
7
|
+
# .how = sets up temp git repo, exercises all commands, cleans up
|
|
8
|
+
#
|
|
9
|
+
# usage:
|
|
10
|
+
# ./git.worktree.test.sh
|
|
11
|
+
#
|
|
12
|
+
# guarantee:
|
|
13
|
+
# - creates isolated temp environment
|
|
14
|
+
# - cleans up after itself
|
|
15
|
+
# - exits 0 on success, 1 on failure
|
|
16
|
+
######################################################################
|
|
17
|
+
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
|
|
20
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
TEST_DIR=""
|
|
22
|
+
TESTS_PASSED=0
|
|
23
|
+
TESTS_FAILED=0
|
|
24
|
+
|
|
25
|
+
# colors for output
|
|
26
|
+
RED='\033[0;31m'
|
|
27
|
+
GREEN='\033[0;32m'
|
|
28
|
+
NC='\033[0m' # No Color
|
|
29
|
+
|
|
30
|
+
# test helper: assert condition
|
|
31
|
+
assert() {
|
|
32
|
+
local description="$1"
|
|
33
|
+
local condition="$2"
|
|
34
|
+
|
|
35
|
+
if eval "$condition"; then
|
|
36
|
+
echo -e " ${GREEN}✓${NC} $description"
|
|
37
|
+
((TESTS_PASSED++))
|
|
38
|
+
else
|
|
39
|
+
echo -e " ${RED}✗${NC} $description"
|
|
40
|
+
((TESTS_FAILED++))
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# test helper: assert output contains
|
|
45
|
+
assert_output_contains() {
|
|
46
|
+
local description="$1"
|
|
47
|
+
local output="$2"
|
|
48
|
+
local expected="$3"
|
|
49
|
+
|
|
50
|
+
if [[ "$output" == *"$expected"* ]]; then
|
|
51
|
+
echo -e " ${GREEN}✓${NC} $description"
|
|
52
|
+
((TESTS_PASSED++))
|
|
53
|
+
else
|
|
54
|
+
echo -e " ${RED}✗${NC} $description"
|
|
55
|
+
echo " expected: $expected"
|
|
56
|
+
echo " got: $output"
|
|
57
|
+
((TESTS_FAILED++))
|
|
58
|
+
fi
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# setup: create temp git repo with remote
|
|
62
|
+
setup() {
|
|
63
|
+
echo "setting up test environment..."
|
|
64
|
+
|
|
65
|
+
# create temp directory
|
|
66
|
+
TEST_DIR="$(mktemp -d)"
|
|
67
|
+
|
|
68
|
+
# create "remote" bare repo
|
|
69
|
+
mkdir -p "$TEST_DIR/remote.git"
|
|
70
|
+
git -C "$TEST_DIR/remote.git" init --bare -q
|
|
71
|
+
|
|
72
|
+
# create "local" repo
|
|
73
|
+
mkdir -p "$TEST_DIR/local"
|
|
74
|
+
git -C "$TEST_DIR/local" init -q
|
|
75
|
+
git -C "$TEST_DIR/local" config user.email "test@test.com"
|
|
76
|
+
git -C "$TEST_DIR/local" config user.name "Test"
|
|
77
|
+
git -C "$TEST_DIR/local" remote add origin "$TEST_DIR/remote.git"
|
|
78
|
+
|
|
79
|
+
# initial commit
|
|
80
|
+
echo "test" > "$TEST_DIR/local/README.md"
|
|
81
|
+
git -C "$TEST_DIR/local" add .
|
|
82
|
+
git -C "$TEST_DIR/local" commit -m "initial commit" -q
|
|
83
|
+
|
|
84
|
+
# push to remote (handle both main and master default branch names)
|
|
85
|
+
git -C "$TEST_DIR/local" push -u origin HEAD:main -q 2>/dev/null || true
|
|
86
|
+
|
|
87
|
+
echo " test dir: $TEST_DIR"
|
|
88
|
+
echo ""
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# teardown: clean up temp directory
|
|
92
|
+
teardown() {
|
|
93
|
+
echo ""
|
|
94
|
+
echo "cleaning up..."
|
|
95
|
+
|
|
96
|
+
if [[ -n "$TEST_DIR" ]] && [[ -d "$TEST_DIR" ]]; then
|
|
97
|
+
rm -rf "$TEST_DIR"
|
|
98
|
+
echo " removed: $TEST_DIR"
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# run tests
|
|
103
|
+
run_tests() {
|
|
104
|
+
local worktree_sh="$SCRIPT_DIR/git.worktree.sh"
|
|
105
|
+
|
|
106
|
+
echo "=== test: dispatcher ==="
|
|
107
|
+
|
|
108
|
+
# test: dispatcher shows usage
|
|
109
|
+
local usage_output
|
|
110
|
+
usage_output=$("$worktree_sh" 2>&1 || true)
|
|
111
|
+
assert_output_contains "shows usage on no args" "$usage_output" "usage: git.worktree.sh"
|
|
112
|
+
|
|
113
|
+
echo ""
|
|
114
|
+
echo "=== test: get (empty) ==="
|
|
115
|
+
|
|
116
|
+
# test: get with no worktrees
|
|
117
|
+
local get_empty
|
|
118
|
+
get_empty=$(cd "$TEST_DIR/local" && "$worktree_sh" get)
|
|
119
|
+
assert_output_contains "shows no worktrees" "$get_empty" "(no worktrees)"
|
|
120
|
+
|
|
121
|
+
echo ""
|
|
122
|
+
echo "=== test: set (create) ==="
|
|
123
|
+
|
|
124
|
+
# test: set creates worktree
|
|
125
|
+
local set_output
|
|
126
|
+
set_output=$(cd "$TEST_DIR/local" && "$worktree_sh" set test/branch1)
|
|
127
|
+
assert_output_contains "creates worktree" "$set_output" "[CREATE]"
|
|
128
|
+
assert_output_contains "correct path" "$set_output" "_worktrees/local/test.branch1"
|
|
129
|
+
assert "worktree directory exists" "[[ -d '$TEST_DIR/_worktrees/local/test.branch1' ]]"
|
|
130
|
+
|
|
131
|
+
echo ""
|
|
132
|
+
echo "=== test: set (idempotent) ==="
|
|
133
|
+
|
|
134
|
+
# test: set is idempotent
|
|
135
|
+
local set_keep
|
|
136
|
+
set_keep=$(cd "$TEST_DIR/local" && "$worktree_sh" set test/branch1)
|
|
137
|
+
assert_output_contains "keeps existing worktree" "$set_keep" "[KEEP]"
|
|
138
|
+
|
|
139
|
+
echo ""
|
|
140
|
+
echo "=== test: get (with worktrees) ==="
|
|
141
|
+
|
|
142
|
+
# test: get lists worktrees
|
|
143
|
+
local get_list
|
|
144
|
+
get_list=$(cd "$TEST_DIR/local" && "$worktree_sh" get)
|
|
145
|
+
assert_output_contains "lists worktrees header" "$get_list" "worktrees for local:"
|
|
146
|
+
assert_output_contains "lists worktree entry" "$get_list" "test.branch1"
|
|
147
|
+
|
|
148
|
+
echo ""
|
|
149
|
+
echo "=== test: set (second worktree) ==="
|
|
150
|
+
|
|
151
|
+
# test: create second worktree
|
|
152
|
+
local set_second
|
|
153
|
+
set_second=$(cd "$TEST_DIR/local" && "$worktree_sh" set feature/auth)
|
|
154
|
+
assert_output_contains "creates second worktree" "$set_second" "[CREATE]"
|
|
155
|
+
assert "second worktree exists" "[[ -d '$TEST_DIR/_worktrees/local/feature.auth' ]]"
|
|
156
|
+
|
|
157
|
+
echo ""
|
|
158
|
+
echo "=== test: get from worktree ==="
|
|
159
|
+
|
|
160
|
+
# test: get from within worktree resolves same dir
|
|
161
|
+
local get_from_wt
|
|
162
|
+
get_from_wt=$(cd "$TEST_DIR/_worktrees/local/test.branch1" && "$worktree_sh" get)
|
|
163
|
+
assert_output_contains "lists from worktree" "$get_from_wt" "worktrees for local:"
|
|
164
|
+
assert_output_contains "sees both worktrees" "$get_from_wt" "feature.auth"
|
|
165
|
+
|
|
166
|
+
echo ""
|
|
167
|
+
echo "=== test: set from worktree ==="
|
|
168
|
+
|
|
169
|
+
# test: set from within worktree creates in same _worktrees dir
|
|
170
|
+
local set_from_wt
|
|
171
|
+
set_from_wt=$(cd "$TEST_DIR/_worktrees/local/test.branch1" && "$worktree_sh" set test/from-wt)
|
|
172
|
+
assert_output_contains "creates from worktree" "$set_from_wt" "[CREATE]"
|
|
173
|
+
assert "created in same _worktrees dir" "[[ -d '$TEST_DIR/_worktrees/local/test.from-wt' ]]"
|
|
174
|
+
|
|
175
|
+
echo ""
|
|
176
|
+
echo "=== test: del ==="
|
|
177
|
+
|
|
178
|
+
# test: del removes worktree
|
|
179
|
+
local del_output
|
|
180
|
+
del_output=$(cd "$TEST_DIR/local" && "$worktree_sh" del test/from-wt)
|
|
181
|
+
assert_output_contains "deletes worktree" "$del_output" "[DELETE]"
|
|
182
|
+
assert "worktree removed" "[[ ! -d '$TEST_DIR/_worktrees/local/test.from-wt' ]]"
|
|
183
|
+
|
|
184
|
+
echo ""
|
|
185
|
+
echo "=== test: del (skip nonexistent) ==="
|
|
186
|
+
|
|
187
|
+
# test: del skips nonexistent
|
|
188
|
+
local del_skip
|
|
189
|
+
del_skip=$(cd "$TEST_DIR/local" && "$worktree_sh" del nonexistent/branch)
|
|
190
|
+
assert_output_contains "skips nonexistent" "$del_skip" "[SKIP]"
|
|
191
|
+
assert_output_contains "shows not found" "$del_skip" "(not found)"
|
|
192
|
+
|
|
193
|
+
echo ""
|
|
194
|
+
echo "=== test: cleanup remaining ==="
|
|
195
|
+
|
|
196
|
+
# cleanup remaining test worktrees
|
|
197
|
+
cd "$TEST_DIR/local" && "$worktree_sh" del test/branch1 >/dev/null
|
|
198
|
+
cd "$TEST_DIR/local" && "$worktree_sh" del feature/auth >/dev/null
|
|
199
|
+
|
|
200
|
+
local final_get
|
|
201
|
+
final_get=$(cd "$TEST_DIR/local" && "$worktree_sh" get)
|
|
202
|
+
assert_output_contains "all cleaned up" "$final_get" "(no worktrees)"
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# main
|
|
206
|
+
main() {
|
|
207
|
+
echo "git.worktree.sh test suite"
|
|
208
|
+
echo "=========================="
|
|
209
|
+
echo ""
|
|
210
|
+
|
|
211
|
+
setup
|
|
212
|
+
|
|
213
|
+
# run tests (trap ensures cleanup on failure)
|
|
214
|
+
trap teardown EXIT
|
|
215
|
+
run_tests
|
|
216
|
+
|
|
217
|
+
echo ""
|
|
218
|
+
echo "=========================="
|
|
219
|
+
echo -e "passed: ${GREEN}$TESTS_PASSED${NC}"
|
|
220
|
+
echo -e "failed: ${RED}$TESTS_FAILED${NC}"
|
|
221
|
+
|
|
222
|
+
if [[ $TESTS_FAILED -gt 0 ]]; then
|
|
223
|
+
exit 1
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
exit 0
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
main "$@"
|
|
@@ -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"
|