acstack 0.0.0-stage → 0.47.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.
- package/.claude-plugin/plugin.json +19 -0
- package/LICENSE +21 -0
- package/README.md +389 -2
- package/THIRD_PARTY_NOTICES +14 -0
- package/TROUBLESHOOTING.md +225 -0
- package/agents/codex/frontend-verifier.toml +352 -0
- package/agents/codex/task-checker.toml +345 -0
- package/agents/codex/task-executor.toml +157 -0
- package/agents/codex/test-writer.toml +149 -0
- package/agents/frontend-verifier.md +351 -0
- package/agents/task-checker.md +344 -0
- package/agents/task-executor.md +156 -0
- package/agents/test-writer.md +148 -0
- package/assets/playwriter-bridge/build-launcher.ps1 +32 -0
- package/assets/playwriter-bridge/doctor.ps1 +450 -0
- package/assets/playwriter-bridge/launcher-src.cs +131 -0
- package/assets/playwriter-bridge/opener.js +330 -0
- package/assets/playwriter-bridge/opener.ps1 +63 -0
- package/assets/playwriter-bridge/register-tasks.ps1 +328 -0
- package/assets/playwriter-bridge/relay.ps1 +50 -0
- package/assets/playwriter-bridge/stop.ps1 +125 -0
- package/assets/playwriter-bridge/sync.ps1 +271 -0
- package/assets/playwriter-bridge/tunnel.ps1 +325 -0
- package/assets/playwriter-bridge/vm-free-port.sh +166 -0
- package/assets/terminal-workspace/client-keybindings.md +87 -0
- package/assets/terminal-workspace/config.example.yaml +334 -0
- package/assets/terminal-workspace/setup.sh +4404 -0
- package/cli/README.md +47 -0
- package/cli/bin/acstack.js +3 -0
- package/cli/dist/index.js +25984 -0
- package/cli/dist/index.js.map +7 -0
- package/cli/package.json +59 -0
- package/docs/adr/0001-ste-writing-standard.md +16 -0
- package/docs/adr/0002-version-gate-not-auto-bump.md +35 -0
- package/docs/adr/0003-handoff-ack-command.md +19 -0
- package/docs/adr/0004-dev-setup-per-host.md +13 -0
- package/docs/adr/0005-two-orchestrators-per-host.md +25 -0
- package/docs/adr/0006-document-opener-service.md +89 -0
- package/docs/adr/0007-lead-check-reads-the-transcript.md +87 -0
- package/docs/adr/0008-cli-audits-skill-interviews.md +37 -0
- package/docs/adr/0009-verify-the-write-not-the-writer.md +51 -0
- package/docs/adr/0010-promote-dev-to-main-by-fast-forward.md +115 -0
- package/docs/adr/0011-node-header-is-the-edge-encoding.md +20 -0
- package/docs/adr/0012-node-kind-is-a-closed-set-of-five.md +31 -0
- package/docs/adr/0013-the-diagram-renderer-is-pure.md +23 -0
- package/docs/adr/0014-reading-a-node-hides-its-generated-diagram.md +29 -0
- package/docs/adr/0015-a-node-id-links-to-its-issue-through-an-anchor.md +37 -0
- package/docs/adr/0016-the-map-root-carries-no-status-of-its-own.md +21 -0
- package/docs/adr/0017-call-impeccable-copy-only-its-questions.md +13 -0
- package/docs/adr/index.md +17 -0
- package/docs/config-reference.md +572 -0
- package/docs/dev-setups.md +164 -0
- package/docs/migrate-0.8.md +28 -0
- package/docs/playwriter-bridge-windows.md +15 -0
- package/docs/terminal-workspace-keys.md +137 -0
- package/docs/terminal-workspace.md +1780 -0
- package/docs/workflows.md +309 -0
- package/hooks/ac-writing-style-reminder.sh +86 -0
- package/hooks/context-pressure.sh +583 -0
- package/hooks/hooks.json +50 -0
- package/hooks/session-start-handoff.sh +165 -0
- package/hooks/session-start.sh +214 -0
- package/orchestrator/AGENTS.md +532 -0
- package/output-styles/ac-writing-style.md +286 -0
- package/package.json +50 -4
- package/pi/agents/frontend-verifier.md +357 -0
- package/pi/agents/task-checker.md +348 -0
- package/pi/agents/task-executor.md +160 -0
- package/pi/agents/test-writer.md +154 -0
- package/pi/extension.ts +723 -0
- package/profiles/fullstack-python.yaml +29 -0
- package/profiles/node-typescript.yaml +23 -0
- package/profiles/python.yaml +24 -0
- package/skills/archive/SKILL.md +160 -0
- package/skills/bootstrap/SKILL.md +109 -0
- package/skills/bridge/HANDOFF.md +93 -0
- package/skills/bridge/SKILL-VM.md +292 -0
- package/skills/bridge/SKILL-WINDOWS.md +526 -0
- package/skills/bridge/SKILL.md +121 -0
- package/skills/browser-verify/SKILL.md +229 -0
- package/skills/code-review/SKILL.md +44 -0
- package/skills/commit/SKILL.md +106 -0
- package/skills/compact-and-continue/SKILL.md +241 -0
- package/skills/explore/SKILL.md +149 -0
- package/skills/grilling/SKILL.md +134 -0
- package/skills/handoff/SKILL.md +250 -0
- package/skills/handoff/launch-herdr.md +197 -0
- package/skills/handoff/launch-without-herdr.md +30 -0
- package/skills/handoff/lead-check.md +59 -0
- package/skills/handoff/outcomes.md +162 -0
- package/skills/handoff/running-agent.md +50 -0
- package/skills/handoff/watch.md +115 -0
- package/skills/host/SKILL.md +247 -0
- package/skills/host/detect-host.sh +297 -0
- package/skills/host/herdr.md +79 -0
- package/skills/host/install-herdr-block.sh +467 -0
- package/skills/host/install-orca.sh +512 -0
- package/skills/host/notes.md +97 -0
- package/skills/host/orca.md +160 -0
- package/skills/host/questions.md +163 -0
- package/skills/host/report.md +42 -0
- package/skills/implement/SKILL.md +230 -0
- package/skills/implement/decision-log.md +62 -0
- package/skills/implement/design-pass.md +32 -0
- package/skills/implement/relaxed-tdd.md +28 -0
- package/skills/map/SKILL.md +250 -0
- package/skills/map/frontend.md +227 -0
- package/skills/map/trackers/files.md +74 -0
- package/skills/map/trackers/github.md +180 -0
- package/skills/map/visuals.md +387 -0
- package/skills/new-worktree/SKILL.md +155 -0
- package/skills/new-worktree/detect-orchestrator.sh +328 -0
- package/skills/new-worktree/detect-orchestrator.test.sh +894 -0
- package/skills/new-worktree/herdr.md +84 -0
- package/skills/new-worktree/orca.md +101 -0
- package/skills/pre-commit-review/SKILL.md +242 -0
- package/skills/pre-commit-review/auto-fix.md +19 -0
- package/skills/pre-commit-review/interactive.md +35 -0
- package/skills/quick-fix/SKILL.md +125 -0
- package/skills/record-context/SKILL.md +106 -0
- package/skills/setup/SKILL.md +250 -0
- package/skills/setup/browser.md +123 -0
- package/skills/setup/design-review.md +97 -0
- package/skills/setup/first-run.md +114 -0
- package/skills/setup/report.md +68 -0
- package/skills/setup/row-fixes.md +196 -0
- package/skills/setup/terminal-workspace.md +153 -0
- package/skills/sync/SKILL.md +171 -0
- package/skills/teardown-worktree/SKILL.md +245 -0
- package/skills/teardown-worktree/detector.md +39 -0
- package/skills/teardown-worktree/herdr.md +113 -0
- package/skills/teardown-worktree/orca.md +61 -0
- package/skills/terminal-workspace/SKILL.md +249 -0
- package/skills/terminal-workspace/components.md +36 -0
- package/skills/terminal-workspace/config-choices.md +69 -0
- package/skills/terminal-workspace/emulator-keys.md +48 -0
- package/skills/terminal-workspace/headless-clipboard.md +175 -0
- package/skills/terminal-workspace/turn-off-and-update.md +104 -0
- package/skills/test-conventions/SKILL.md +59 -0
- package/skills/visual-docs/SKILL.md +246 -0
- package/skills/writing/SKILL.md +231 -0
- package/skills/writing/examples.md +153 -0
- package/skills/writing/vocabulary.md +96 -0
|
@@ -0,0 +1,894 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test harness for detect-orchestrator.sh.
|
|
3
|
+
#
|
|
4
|
+
# detect-orchestrator.sh is a read-only report. It prints which orchestrators
|
|
5
|
+
# this host DECLARES it has, one boolean per orchestrator (via the ACStack
|
|
6
|
+
# CLI's `config get host.orchestrators.herdr` and
|
|
7
|
+
# `config get host.orchestrators.orca`), and which one is actually DETECTED as
|
|
8
|
+
# hosting the current session (via environment markers), then reconciles the
|
|
9
|
+
# two into an ACTIVE orchestrator plus an optional WARNING line.
|
|
10
|
+
#
|
|
11
|
+
# The two declarations are independent: a host can have both orchestrators
|
|
12
|
+
# installed, or neither, so there is no single "the declared orchestrator"
|
|
13
|
+
# any more.
|
|
14
|
+
#
|
|
15
|
+
# Each case runs the script in a subshell with HOME pointed at a scratch
|
|
16
|
+
# directory (containing a fake ACStack CLI, when the case needs one) and
|
|
17
|
+
# with HERDR_ENV / HERDR_PANE_ID / ORCA_PANE_KEY explicitly unset and then
|
|
18
|
+
# re-set as the case requires, so nothing leaks in from the real session
|
|
19
|
+
# this suite happens to be running inside.
|
|
20
|
+
#
|
|
21
|
+
# The report also names the OWNER of the checkout it is looking at. A checkout
|
|
22
|
+
# is one git worktree directory, and its path root names the owner: a path
|
|
23
|
+
# under $HOME/orca/workspaces/ belongs to orca, a path under herdr's worktree
|
|
24
|
+
# root belongs to herdr, and anything else belongs to plain git. Cases that
|
|
25
|
+
# care about the owner therefore run the script from a scratch directory built
|
|
26
|
+
# under the case's fake HOME, or pass that directory as the script's first
|
|
27
|
+
# argument.
|
|
28
|
+
#
|
|
29
|
+
# Run it: bash skills/new-worktree/detect-orchestrator.test.sh
|
|
30
|
+
# Exit code is 0 when every check passes, 1 otherwise.
|
|
31
|
+
|
|
32
|
+
set -u
|
|
33
|
+
|
|
34
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
35
|
+
SUT="${SCRIPT_DIR}/detect-orchestrator.sh"
|
|
36
|
+
|
|
37
|
+
WORK="$(mktemp -d)"
|
|
38
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
39
|
+
cd "$WORK" || exit 1
|
|
40
|
+
|
|
41
|
+
pass=0
|
|
42
|
+
fail=0
|
|
43
|
+
ok() { printf ' \033[32mPASS\033[0m %s\n' "$1"; pass=$((pass + 1)); }
|
|
44
|
+
no() { printf ' \033[31mFAIL\033[0m %s\n' "$1"; fail=$((fail + 1)); }
|
|
45
|
+
check() { if eval "$2"; then ok "$1"; else no "$1"; fi; }
|
|
46
|
+
|
|
47
|
+
# --- helpers ------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
# Write a fake ACStack CLI at $1/.claude/acstack/bin/acstack that answers
|
|
50
|
+
# EVERY invocation the same way: printing $2 (verbatim, plus a trailing
|
|
51
|
+
# newline) and exiting with code $3 (default 0). For the cases where the tool
|
|
52
|
+
# itself is the subject, so what it was asked does not matter.
|
|
53
|
+
mk_cli() {
|
|
54
|
+
local home_dir="$1" output="$2" code="${3:-0}"
|
|
55
|
+
local bin_dir="$home_dir/.claude/acstack/bin"
|
|
56
|
+
mkdir -p "$bin_dir"
|
|
57
|
+
printf '%s' "$output" > "$bin_dir/.output"
|
|
58
|
+
printf '%s' "$code" > "$bin_dir/.exitcode"
|
|
59
|
+
cat > "$bin_dir/acstack" <<'CLIEOF'
|
|
60
|
+
#!/usr/bin/env bash
|
|
61
|
+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
62
|
+
cat "$DIR/.output"
|
|
63
|
+
exit "$(cat "$DIR/.exitcode")"
|
|
64
|
+
CLIEOF
|
|
65
|
+
chmod +x "$bin_dir/acstack"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Write a fake ACStack CLI that answers the two orchestrator axes separately:
|
|
69
|
+
# `config get host.orchestrators.herdr` prints $2 and exits $3, and
|
|
70
|
+
# `config get host.orchestrators.orca` prints $4 and exits $5.
|
|
71
|
+
#
|
|
72
|
+
# Any other key exits 1 without printing, so a script that still asks the
|
|
73
|
+
# retired `host.orchestrator` key reads as a tool failure rather than
|
|
74
|
+
# silently passing these cases.
|
|
75
|
+
mk_cli_axes() {
|
|
76
|
+
local home_dir="$1"
|
|
77
|
+
local bin_dir="$home_dir/.claude/acstack/bin"
|
|
78
|
+
mkdir -p "$bin_dir"
|
|
79
|
+
printf '%s' "$2" > "$bin_dir/.herdr.output"
|
|
80
|
+
printf '%s' "$3" > "$bin_dir/.herdr.exitcode"
|
|
81
|
+
printf '%s' "$4" > "$bin_dir/.orca.output"
|
|
82
|
+
printf '%s' "$5" > "$bin_dir/.orca.exitcode"
|
|
83
|
+
cat > "$bin_dir/acstack" <<'CLIEOF'
|
|
84
|
+
#!/usr/bin/env bash
|
|
85
|
+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
86
|
+
case "${3:-}" in
|
|
87
|
+
host.orchestrators.herdr) axis=herdr ;;
|
|
88
|
+
host.orchestrators.orca) axis=orca ;;
|
|
89
|
+
*) exit 1 ;;
|
|
90
|
+
esac
|
|
91
|
+
cat "$DIR/.$axis.output"
|
|
92
|
+
exit "$(cat "$DIR/.$axis.exitcode")"
|
|
93
|
+
CLIEOF
|
|
94
|
+
chmod +x "$bin_dir/acstack"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# The readable form of mk_cli_axes: each of $2 (herdr) and $3 (orca) is one
|
|
98
|
+
# of true, false or unset, and is turned into the answer a real CLI would
|
|
99
|
+
# give – the JSON boolean on exit 0, or exit 2 with no output for a key that
|
|
100
|
+
# was never set.
|
|
101
|
+
mk_cli_declared() {
|
|
102
|
+
local home_dir="$1" herdr="$2" orca="$3"
|
|
103
|
+
local h_out h_code o_out o_code
|
|
104
|
+
case "$herdr" in
|
|
105
|
+
true) h_out="true"; h_code=0 ;;
|
|
106
|
+
false) h_out="false"; h_code=0 ;;
|
|
107
|
+
unset) h_out=""; h_code=2 ;;
|
|
108
|
+
*) echo "mk_cli_declared: bad herdr spec: $herdr" >&2; exit 1 ;;
|
|
109
|
+
esac
|
|
110
|
+
case "$orca" in
|
|
111
|
+
true) o_out="true"; o_code=0 ;;
|
|
112
|
+
false) o_out="false"; o_code=0 ;;
|
|
113
|
+
unset) o_out=""; o_code=2 ;;
|
|
114
|
+
*) echo "mk_cli_declared: bad orca spec: $orca" >&2; exit 1 ;;
|
|
115
|
+
esac
|
|
116
|
+
mk_cli_axes "$home_dir" "$h_out" "$h_code" "$o_out" "$o_code"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Run the SUT with HOME=$1 and the given env-setup snippet ($2, eval'd in a
|
|
120
|
+
# subshell before invoking the script) applied on top of a clean slate
|
|
121
|
+
# where HERDR_ENV, HERDR_PANE_ID and ORCA_PANE_KEY start unset. Echoes
|
|
122
|
+
# stdout only (stderr discarded); caller reads $? for the exit code.
|
|
123
|
+
run_case() {
|
|
124
|
+
local home_dir="$1" env_setup="$2"
|
|
125
|
+
(
|
|
126
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
127
|
+
export HOME="$home_dir"
|
|
128
|
+
eval "$env_setup"
|
|
129
|
+
bash "$SUT" 2>/dev/null
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Extract the value for key $2 out of full output $1.
|
|
134
|
+
get_val() {
|
|
135
|
+
printf '%s\n' "$1" | grep "^${2}=" | head -n1 | sed "s/^${2}=//"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
new_home() { mktemp -d -p "$WORK"; }
|
|
139
|
+
|
|
140
|
+
# run_case, but from a given working directory ($2), so the case controls which
|
|
141
|
+
# checkout the script is looking at. cd is left logical on purpose: a case that
|
|
142
|
+
# hands over a symlinked path is testing that the script resolves it itself.
|
|
143
|
+
run_case_in() {
|
|
144
|
+
local home_dir="$1" cwd_dir="$2" env_setup="$3"
|
|
145
|
+
(
|
|
146
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
147
|
+
export HOME="$home_dir"
|
|
148
|
+
cd "$cwd_dir" || exit 1
|
|
149
|
+
eval "$env_setup"
|
|
150
|
+
bash "$SUT" 2>/dev/null
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
# run_case, but passing $2 as the script's first argument, so the case names the
|
|
155
|
+
# checkout to examine rather than standing in it.
|
|
156
|
+
run_case_arg() {
|
|
157
|
+
local home_dir="$1" path_arg="$2" env_setup="$3"
|
|
158
|
+
(
|
|
159
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
160
|
+
export HOME="$home_dir"
|
|
161
|
+
eval "$env_setup"
|
|
162
|
+
bash "$SUT" "$path_arg" 2>/dev/null
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# Create the checkout $2/$3 under home $1's default herdr worktree root and echo
|
|
167
|
+
# its path.
|
|
168
|
+
mk_herdr_checkout() {
|
|
169
|
+
local path="$1/.herdr/worktrees/$2/$3"
|
|
170
|
+
mkdir -p "$path"
|
|
171
|
+
printf '%s\n' "$path"
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Create the orca workspace $2 under home $1 and echo its path.
|
|
175
|
+
mk_orca_checkout() {
|
|
176
|
+
local path="$1/orca/workspaces/$2"
|
|
177
|
+
mkdir -p "$path"
|
|
178
|
+
printf '%s\n' "$path"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# Write herdr's config file under home $1 with a [worktrees] section naming $2
|
|
182
|
+
# as the worktree root. $2 is written verbatim, so a case can pass either a
|
|
183
|
+
# "~/..." path or an absolute one.
|
|
184
|
+
mk_herdr_config() {
|
|
185
|
+
local home_dir="$1" dir="$2"
|
|
186
|
+
mkdir -p "$home_dir/.config/herdr"
|
|
187
|
+
cat > "$home_dir/.config/herdr/config.toml" <<EOF
|
|
188
|
+
[worktrees]
|
|
189
|
+
directory = "$dir"
|
|
190
|
+
EOF
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Write a herdr config file under home $1 that exists but says nothing about
|
|
194
|
+
# worktrees, so the default root still applies.
|
|
195
|
+
mk_herdr_config_without_worktrees() {
|
|
196
|
+
local home_dir="$1"
|
|
197
|
+
mkdir -p "$home_dir/.config/herdr"
|
|
198
|
+
cat > "$home_dir/.config/herdr/config.toml" <<'EOF'
|
|
199
|
+
[general]
|
|
200
|
+
theme = "dark"
|
|
201
|
+
EOF
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
echo "Testing: $SUT"
|
|
205
|
+
echo "Workdir: $WORK"
|
|
206
|
+
echo ""
|
|
207
|
+
|
|
208
|
+
# =========================================================================
|
|
209
|
+
# R1 – output shape: one line per declared orchestrator, then the rest
|
|
210
|
+
# =========================================================================
|
|
211
|
+
echo "Case 1: basic run – output shape (R1)"
|
|
212
|
+
H1="$(new_home)"
|
|
213
|
+
mk_cli_declared "$H1" false false
|
|
214
|
+
OUT="$(run_case "$H1" '')"
|
|
215
|
+
CODE=$?
|
|
216
|
+
LINES="$(printf '%s\n' "$OUT" | wc -l | tr -d ' ')"
|
|
217
|
+
check "exit code is 0" '[ "$CODE" -eq 0 ]'
|
|
218
|
+
check "prints exactly 6 lines" '[ "$LINES" -eq 6 ]'
|
|
219
|
+
check "line 1 is declared_herdr=" 'printf "%s\n" "$OUT" | sed -n "1p" | grep -q "^declared_herdr="'
|
|
220
|
+
check "line 2 is declared_orca=" 'printf "%s\n" "$OUT" | sed -n "2p" | grep -q "^declared_orca="'
|
|
221
|
+
check "line 3 is detected=" 'printf "%s\n" "$OUT" | sed -n "3p" | grep -q "^detected="'
|
|
222
|
+
check "line 4 is active=" 'printf "%s\n" "$OUT" | sed -n "4p" | grep -q "^active="'
|
|
223
|
+
check "line 5 is owner=" 'printf "%s\n" "$OUT" | sed -n "5p" | grep -q "^owner="'
|
|
224
|
+
check "line 6 is warning=" 'printf "%s\n" "$OUT" | sed -n "6p" | grep -q "^warning="'
|
|
225
|
+
check "no bare declared= line remains" '! printf "%s\n" "$OUT" | grep -q "^declared="'
|
|
226
|
+
check "declared_herdr=false" '[ "$(get_val "$OUT" declared_herdr)" = "false" ]'
|
|
227
|
+
check "declared_orca=false" '[ "$(get_val "$OUT" declared_orca)" = "false" ]'
|
|
228
|
+
check "detected=none" '[ "$(get_val "$OUT" detected)" = "none" ]'
|
|
229
|
+
check "active=none" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
230
|
+
check "owner=none (a plain git checkout)" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
231
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
232
|
+
|
|
233
|
+
# =========================================================================
|
|
234
|
+
# R2 – declared: two independent booleans
|
|
235
|
+
# =========================================================================
|
|
236
|
+
echo "Case 2: CLI prints true with surrounding whitespace -> trimmed (R2)"
|
|
237
|
+
H2="$(new_home)"
|
|
238
|
+
mk_cli_axes "$H2" " true " 0 " false " 0
|
|
239
|
+
OUT="$(run_case "$H2" '')"
|
|
240
|
+
check "declared_herdr=true (trimmed)" '[ "$(get_val "$OUT" declared_herdr)" = "true" ]'
|
|
241
|
+
check "declared_orca=false (trimmed)" '[ "$(get_val "$OUT" declared_orca)" = "false" ]'
|
|
242
|
+
|
|
243
|
+
echo "Case 3: the two booleans are read independently (R2)"
|
|
244
|
+
H3="$(new_home)"
|
|
245
|
+
mk_cli_declared "$H3" false true
|
|
246
|
+
OUT="$(run_case "$H3" '')"
|
|
247
|
+
check "declared_herdr=false" '[ "$(get_val "$OUT" declared_herdr)" = "false" ]'
|
|
248
|
+
check "declared_orca=true" '[ "$(get_val "$OUT" declared_orca)" = "true" ]'
|
|
249
|
+
|
|
250
|
+
echo "Case 4: both are declared true (R2)"
|
|
251
|
+
H4="$(new_home)"
|
|
252
|
+
mk_cli_declared "$H4" true true
|
|
253
|
+
OUT="$(run_case "$H4" '')"
|
|
254
|
+
check "declared_herdr=true" '[ "$(get_val "$OUT" declared_herdr)" = "true" ]'
|
|
255
|
+
check "declared_orca=true" '[ "$(get_val "$OUT" declared_orca)" = "true" ]'
|
|
256
|
+
|
|
257
|
+
echo "Case 5: CLI exits 2 for both keys (never declared) -> unset, no warning (R2)"
|
|
258
|
+
H5="$(new_home)"
|
|
259
|
+
mk_cli_declared "$H5" unset unset
|
|
260
|
+
OUT="$(run_case "$H5" '')"
|
|
261
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
262
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
263
|
+
check "no warning (nothing is hosting either)" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
264
|
+
|
|
265
|
+
echo "Case 6: one key unset, the other declared -> only that one is unset (R2)"
|
|
266
|
+
H6="$(new_home)"
|
|
267
|
+
mk_cli_axes "$H6" "true" 0 "" 2
|
|
268
|
+
OUT="$(run_case "$H6" '')"
|
|
269
|
+
check "declared_herdr=true" '[ "$(get_val "$OUT" declared_herdr)" = "true" ]'
|
|
270
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
271
|
+
|
|
272
|
+
echo "Case 7: CLI exits 0 with an unrecognised value -> that key is unset, the other still read (R2)"
|
|
273
|
+
H7="$(new_home)"
|
|
274
|
+
mk_cli_axes "$H7" "tmux" 0 "true" 0
|
|
275
|
+
OUT="$(run_case "$H7" '')"
|
|
276
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
277
|
+
check "declared_orca=true (unaffected)" '[ "$(get_val "$OUT" declared_orca)" = "true" ]'
|
|
278
|
+
check "warning mentions the unrecognised value" 'printf "%s" "$(get_val "$OUT" warning)" | grep -q "tmux"'
|
|
279
|
+
|
|
280
|
+
echo "Case 8: CLI path does not exist -> both declarations unreadable (R2)"
|
|
281
|
+
H8="$(new_home)"
|
|
282
|
+
mkdir -p "$H8"
|
|
283
|
+
OUT="$(run_case "$H8" '')"
|
|
284
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
285
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
286
|
+
WARN8="$(get_val "$OUT" warning)"
|
|
287
|
+
check "warning says CLI could not be run" 'printf "%s" "$WARN8" | grep -qi "acstack"'
|
|
288
|
+
check "warning mentions restarting Claude Code" 'printf "%s" "$WARN8" | grep -qi "restart"'
|
|
289
|
+
|
|
290
|
+
echo "Case 9: CLI exists but is not executable (R2)"
|
|
291
|
+
H9="$(new_home)"
|
|
292
|
+
mk_cli_declared "$H9" true false
|
|
293
|
+
chmod -x "$H9/.claude/acstack/bin/acstack"
|
|
294
|
+
OUT="$(run_case "$H9" '')"
|
|
295
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
296
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
297
|
+
WARN9="$(get_val "$OUT" warning)"
|
|
298
|
+
check "warning says CLI could not be run" 'printf "%s" "$WARN9" | grep -qi "acstack"'
|
|
299
|
+
check "warning mentions restarting Claude Code" 'printf "%s" "$WARN9" | grep -qi "restart"'
|
|
300
|
+
|
|
301
|
+
echo "Case 10: CLI exits with an unrelated non-zero code (R2)"
|
|
302
|
+
H10="$(new_home)"
|
|
303
|
+
mk_cli "$H10" "boom" 1
|
|
304
|
+
OUT="$(run_case "$H10" '')"
|
|
305
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
306
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
307
|
+
check "warning mentions the CLI failed" 'printf "%s" "$(get_val "$OUT" warning)" | grep -qi "fail"'
|
|
308
|
+
|
|
309
|
+
# =========================================================================
|
|
310
|
+
# R3 – detected: environment markers, read without help from the CLI
|
|
311
|
+
# =========================================================================
|
|
312
|
+
echo "Case 11: HERDR_ENV set, herdr declared true -> detected=herdr, no warning (R3)"
|
|
313
|
+
H11="$(new_home)"
|
|
314
|
+
mk_cli_declared "$H11" true false
|
|
315
|
+
OUT="$(run_case "$H11" 'export HERDR_ENV=1')"
|
|
316
|
+
check "detected=herdr" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
317
|
+
check "active=herdr" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
318
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
319
|
+
|
|
320
|
+
echo "Case 12: HERDR_PANE_ID set, herdr declared true -> detected=herdr (R3)"
|
|
321
|
+
H12="$(new_home)"
|
|
322
|
+
mk_cli_declared "$H12" true false
|
|
323
|
+
OUT="$(run_case "$H12" 'export HERDR_PANE_ID=pane-1')"
|
|
324
|
+
check "detected=herdr" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
325
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
326
|
+
|
|
327
|
+
echo "Case 13: ORCA_PANE_KEY set, orca declared true -> detected=orca, no warning (R3)"
|
|
328
|
+
H13="$(new_home)"
|
|
329
|
+
mk_cli_declared "$H13" false true
|
|
330
|
+
OUT="$(run_case "$H13" 'export ORCA_PANE_KEY=key-1')"
|
|
331
|
+
check "detected=orca" '[ "$(get_val "$OUT" detected)" = "orca" ]'
|
|
332
|
+
check "active=orca" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
333
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
334
|
+
|
|
335
|
+
echo "Case 14: HERDR_ENV set but empty -> detected=none (R3)"
|
|
336
|
+
H14="$(new_home)"
|
|
337
|
+
mk_cli_declared "$H14" true false
|
|
338
|
+
OUT="$(run_case "$H14" 'export HERDR_ENV=""')"
|
|
339
|
+
check "detected=none" '[ "$(get_val "$OUT" detected)" = "none" ]'
|
|
340
|
+
|
|
341
|
+
echo "Case 15: all markers set but empty -> detected=none (R3)"
|
|
342
|
+
H15="$(new_home)"
|
|
343
|
+
mk_cli_declared "$H15" true true
|
|
344
|
+
OUT="$(run_case "$H15" 'export HERDR_ENV="" HERDR_PANE_ID="" ORCA_PANE_KEY=""')"
|
|
345
|
+
check "detected=none" '[ "$(get_val "$OUT" detected)" = "none" ]'
|
|
346
|
+
|
|
347
|
+
echo "Case 16: markers are read even when the CLI cannot be run (R3)"
|
|
348
|
+
H16="$(new_home)"
|
|
349
|
+
mkdir -p "$H16"
|
|
350
|
+
OUT="$(run_case "$H16" 'export HERDR_ENV=1')"
|
|
351
|
+
check "detected=herdr despite no readable CLI" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
352
|
+
check "active=herdr" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
353
|
+
WARN16="$(get_val "$OUT" warning)"
|
|
354
|
+
check "warning is the actionable CLI one (restart)" 'printf "%s" "$WARN16" | grep -qi "restart"'
|
|
355
|
+
|
|
356
|
+
# =========================================================================
|
|
357
|
+
# R4 – hosting without a declaration is a warning, not an error
|
|
358
|
+
# =========================================================================
|
|
359
|
+
echo "Case 17: herdr markers, herdr declared false -> active=herdr, warned (R4)"
|
|
360
|
+
H17="$(new_home)"
|
|
361
|
+
mk_cli_declared "$H17" false false
|
|
362
|
+
OUT="$(run_case "$H17" 'export HERDR_ENV=1')"
|
|
363
|
+
check "detected=herdr" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
364
|
+
check "active=herdr (hosting beats declaring)" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
365
|
+
WARN17="$(get_val "$OUT" warning)"
|
|
366
|
+
check "warning is non-empty" '[ -n "$WARN17" ]'
|
|
367
|
+
check "warning names herdr" 'printf "%s" "$WARN17" | grep -qi "herdr"'
|
|
368
|
+
check "warning mentions declaring" 'printf "%s" "$WARN17" | grep -qi "declare"'
|
|
369
|
+
|
|
370
|
+
echo "Case 18: herdr markers, herdr declaration unset -> active=herdr, warned (R4)"
|
|
371
|
+
H18="$(new_home)"
|
|
372
|
+
mk_cli_declared "$H18" unset unset
|
|
373
|
+
OUT="$(run_case "$H18" 'export HERDR_ENV=1')"
|
|
374
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
375
|
+
check "active=herdr" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
376
|
+
WARN18="$(get_val "$OUT" warning)"
|
|
377
|
+
check "warning names herdr" 'printf "%s" "$WARN18" | grep -qi "herdr"'
|
|
378
|
+
check "warning mentions declaring" 'printf "%s" "$WARN18" | grep -qi "declare"'
|
|
379
|
+
|
|
380
|
+
echo "Case 19: orca markers, orca declared false -> active=orca, warned (R4)"
|
|
381
|
+
H19="$(new_home)"
|
|
382
|
+
mk_cli_declared "$H19" true false
|
|
383
|
+
OUT="$(run_case "$H19" 'export ORCA_PANE_KEY=key-1')"
|
|
384
|
+
check "detected=orca" '[ "$(get_val "$OUT" detected)" = "orca" ]'
|
|
385
|
+
check "active=orca" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
386
|
+
WARN19="$(get_val "$OUT" warning)"
|
|
387
|
+
check "warning names orca" 'printf "%s" "$WARN19" | grep -qi "orca"'
|
|
388
|
+
check "warning mentions declaring" 'printf "%s" "$WARN19" | grep -qi "declare"'
|
|
389
|
+
|
|
390
|
+
# =========================================================================
|
|
391
|
+
# R5 – no markers: nothing is hosting, and that is not worth a warning
|
|
392
|
+
# =========================================================================
|
|
393
|
+
echo "Case 20: no markers, herdr declared true -> active=none, no warning (R5)"
|
|
394
|
+
H20="$(new_home)"
|
|
395
|
+
mk_cli_declared "$H20" true false
|
|
396
|
+
OUT="$(run_case "$H20" '')"
|
|
397
|
+
check "detected=none" '[ "$(get_val "$OUT" detected)" = "none" ]'
|
|
398
|
+
check "active=none (not herdr)" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
399
|
+
check "warning is empty (installed is not hosting)" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
400
|
+
|
|
401
|
+
echo "Case 21: no markers, both declared true -> active=none, no warning (R5)"
|
|
402
|
+
H21="$(new_home)"
|
|
403
|
+
mk_cli_declared "$H21" true true
|
|
404
|
+
OUT="$(run_case "$H21" '')"
|
|
405
|
+
check "active=none" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
406
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
407
|
+
|
|
408
|
+
echo "Case 22: no markers, both declared false -> active=none, no warning (R5)"
|
|
409
|
+
H22="$(new_home)"
|
|
410
|
+
mk_cli_declared "$H22" false false
|
|
411
|
+
OUT="$(run_case "$H22" '')"
|
|
412
|
+
check "active=none" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
413
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
414
|
+
|
|
415
|
+
# =========================================================================
|
|
416
|
+
# R6 – both marker families at once, in a checkout nobody owns
|
|
417
|
+
#
|
|
418
|
+
# The checkout's owner settles this first: when the checkout belongs to herdr
|
|
419
|
+
# or to orca, that owner is the one hosting the session and there is nothing
|
|
420
|
+
# ambiguous to say. Those cases live under R16.
|
|
421
|
+
#
|
|
422
|
+
# Every case below runs from a plain git checkout, so the owner is none and the
|
|
423
|
+
# older reconciliation still applies: the declared booleans break the tie when
|
|
424
|
+
# exactly one orchestrator is declared true, and when both or neither are,
|
|
425
|
+
# herdr is picked and the reader is told why.
|
|
426
|
+
# =========================================================================
|
|
427
|
+
echo "Case 23: both markers, only herdr declared true -> active=herdr (R6)"
|
|
428
|
+
H23="$(new_home)"
|
|
429
|
+
mk_cli_declared "$H23" true false
|
|
430
|
+
OUT="$(run_case "$H23" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
431
|
+
check "detected=herdr" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
432
|
+
check "active=herdr" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
433
|
+
|
|
434
|
+
echo "Case 24: both markers, only orca declared true -> active=orca (R6)"
|
|
435
|
+
H24="$(new_home)"
|
|
436
|
+
mk_cli_declared "$H24" false true
|
|
437
|
+
OUT="$(run_case "$H24" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
438
|
+
check "detected=orca" '[ "$(get_val "$OUT" detected)" = "orca" ]'
|
|
439
|
+
check "active=orca" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
440
|
+
|
|
441
|
+
echo "Case 25: both markers, both declared true -> active=herdr, warning names both (R6)"
|
|
442
|
+
H25="$(new_home)"
|
|
443
|
+
mk_cli_declared "$H25" true true
|
|
444
|
+
OUT="$(run_case "$H25" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
445
|
+
check "active=herdr (the tie-break default)" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
446
|
+
check "owner=none (a plain git checkout)" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
447
|
+
WARN25="$(get_val "$OUT" warning)"
|
|
448
|
+
check "warning is non-empty" '[ -n "$WARN25" ]'
|
|
449
|
+
check "warning names herdr" 'printf "%s" "$WARN25" | grep -qi "herdr"'
|
|
450
|
+
check "warning names orca" 'printf "%s" "$WARN25" | grep -qi "orca"'
|
|
451
|
+
|
|
452
|
+
echo "Case 26: both markers, neither declared true -> active=herdr, warning names both (R6)"
|
|
453
|
+
H26="$(new_home)"
|
|
454
|
+
mk_cli_declared "$H26" false false
|
|
455
|
+
OUT="$(run_case "$H26" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
456
|
+
check "active=herdr (the tie-break default)" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
457
|
+
check "owner=none (a plain git checkout)" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
458
|
+
WARN26="$(get_val "$OUT" warning)"
|
|
459
|
+
check "warning names herdr" 'printf "%s" "$WARN26" | grep -qi "herdr"'
|
|
460
|
+
check "warning names orca" 'printf "%s" "$WARN26" | grep -qi "orca"'
|
|
461
|
+
|
|
462
|
+
echo "Case 27: both markers, both declarations unset -> active=herdr, warning names both (R6)"
|
|
463
|
+
H27="$(new_home)"
|
|
464
|
+
mk_cli_declared "$H27" unset unset
|
|
465
|
+
OUT="$(run_case "$H27" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
466
|
+
check "active=herdr (the tie-break default)" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
467
|
+
WARN27="$(get_val "$OUT" warning)"
|
|
468
|
+
check "warning names herdr" 'printf "%s" "$WARN27" | grep -qi "herdr"'
|
|
469
|
+
check "warning names orca" 'printf "%s" "$WARN27" | grep -qi "orca"'
|
|
470
|
+
|
|
471
|
+
# =========================================================================
|
|
472
|
+
# R7 – purity: no filesystem writes, anywhere
|
|
473
|
+
# =========================================================================
|
|
474
|
+
echo "Case 28: purity – a run leaves the scratch dir untouched (R7)"
|
|
475
|
+
H28="$(new_home)"
|
|
476
|
+
mk_cli_declared "$H28" true false
|
|
477
|
+
SCRATCH="$WORK/scratch28"
|
|
478
|
+
mkdir -p "$SCRATCH"
|
|
479
|
+
cd "$SCRATCH" || exit 1
|
|
480
|
+
BEFORE="$(find . | sort)"
|
|
481
|
+
(
|
|
482
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
483
|
+
export HOME="$H28"
|
|
484
|
+
export HERDR_ENV=1
|
|
485
|
+
bash "$SUT" >/dev/null 2>/dev/null
|
|
486
|
+
)
|
|
487
|
+
AFTER="$(find . | sort)"
|
|
488
|
+
cd "$WORK" || exit 1
|
|
489
|
+
check "scratch dir listing unchanged by the run" '[ "$BEFORE" = "$AFTER" ]'
|
|
490
|
+
|
|
491
|
+
echo "Case 29: purity – a run touches nothing under HOME and adds no global git config (R7)"
|
|
492
|
+
H29="$(new_home)"
|
|
493
|
+
mk_cli_declared "$H29" true false
|
|
494
|
+
BEFORE_TREE29="$(find "$H29" | sort)"
|
|
495
|
+
BEFORE_GITCFG29="$(HOME="$H29" git config --global --list 2>/dev/null || true)"
|
|
496
|
+
(
|
|
497
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
498
|
+
export HOME="$H29"
|
|
499
|
+
export HERDR_ENV=1
|
|
500
|
+
bash "$SUT" >/dev/null 2>/dev/null
|
|
501
|
+
)
|
|
502
|
+
AFTER_TREE29="$(find "$H29" | sort)"
|
|
503
|
+
AFTER_GITCFG29="$(HOME="$H29" git config --global --list 2>/dev/null || true)"
|
|
504
|
+
check "whole HOME tree unchanged by the run" '[ "$BEFORE_TREE29" = "$AFTER_TREE29" ]'
|
|
505
|
+
check "no global git config added" '[ "$BEFORE_GITCFG29" = "$AFTER_GITCFG29" ]'
|
|
506
|
+
|
|
507
|
+
# =========================================================================
|
|
508
|
+
# R8 – a malformed CLI answer must not break the six-line contract
|
|
509
|
+
# =========================================================================
|
|
510
|
+
echo "Case 30: CLI exits 0 and prints two lines -> six-line contract still holds (R8)"
|
|
511
|
+
H30="$(new_home)"
|
|
512
|
+
mk_cli "$H30" $'true\nfalse' 0
|
|
513
|
+
OUT="$(run_case "$H30" '')"
|
|
514
|
+
CODE=$?
|
|
515
|
+
LINES="$(printf '%s\n' "$OUT" | wc -l | tr -d ' ')"
|
|
516
|
+
check "exit code is 0" '[ "$CODE" -eq 0 ]'
|
|
517
|
+
check "prints exactly 6 lines" '[ "$LINES" -eq 6 ]'
|
|
518
|
+
check "line 1 is declared_herdr=" 'printf "%s\n" "$OUT" | sed -n "1p" | grep -q "^declared_herdr="'
|
|
519
|
+
check "line 2 is declared_orca=" 'printf "%s\n" "$OUT" | sed -n "2p" | grep -q "^declared_orca="'
|
|
520
|
+
check "line 3 is detected=" 'printf "%s\n" "$OUT" | sed -n "3p" | grep -q "^detected="'
|
|
521
|
+
check "line 4 is active=" 'printf "%s\n" "$OUT" | sed -n "4p" | grep -q "^active="'
|
|
522
|
+
check "line 5 is owner=" 'printf "%s\n" "$OUT" | sed -n "5p" | grep -q "^owner="'
|
|
523
|
+
check "line 6 is warning=" 'printf "%s\n" "$OUT" | sed -n "6p" | grep -q "^warning="'
|
|
524
|
+
check "declared_herdr=unset (a two-line answer is not a boolean)" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
525
|
+
check "warning is non-empty" '[ -n "$(get_val "$OUT" warning)" ]'
|
|
526
|
+
|
|
527
|
+
# =========================================================================
|
|
528
|
+
# R9 – a directory at the CLI path is not runnable
|
|
529
|
+
# =========================================================================
|
|
530
|
+
echo "Case 31: a directory sits at the CLI path -> warning names the fix (restart) (R9)"
|
|
531
|
+
H31="$(new_home)"
|
|
532
|
+
mkdir -p "$H31/.claude/acstack/bin/acstack"
|
|
533
|
+
OUT="$(run_case "$H31" '')"
|
|
534
|
+
CODE=$?
|
|
535
|
+
check "exit code is 0" '[ "$CODE" -eq 0 ]'
|
|
536
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
537
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
538
|
+
WARN31="$(get_val "$OUT" warning)"
|
|
539
|
+
check "warning mentions restarting Claude Code (the fix), not the generic CLI-failed message" 'printf "%s" "$WARN31" | grep -qi "restart"'
|
|
540
|
+
|
|
541
|
+
# =========================================================================
|
|
542
|
+
# R10 – an empty answer with exit 0 is not the same as an unset key
|
|
543
|
+
# =========================================================================
|
|
544
|
+
echo "Case 32: CLI exits 0 and prints nothing -> not an unset key, and not silent (R10)"
|
|
545
|
+
H32="$(new_home)"
|
|
546
|
+
mk_cli "$H32" "" 0
|
|
547
|
+
OUT="$(run_case "$H32" '')"
|
|
548
|
+
CODE=$?
|
|
549
|
+
check "exit code is 0" '[ "$CODE" -eq 0 ]'
|
|
550
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
551
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
552
|
+
WARN32="$(get_val "$OUT" warning)"
|
|
553
|
+
check "warning is non-empty (not silent)" '[ -n "$WARN32" ]'
|
|
554
|
+
check "warning says the tool gave an empty answer" 'printf "%s" "$WARN32" | grep -qi "empty"'
|
|
555
|
+
DQ32='""'
|
|
556
|
+
check "warning does not quote an empty value back at the user" '! printf "%s" "$WARN32" | grep -qF "$DQ32"'
|
|
557
|
+
|
|
558
|
+
# =========================================================================
|
|
559
|
+
# R11 – HOME is not set at all
|
|
560
|
+
# =========================================================================
|
|
561
|
+
echo "Case 33: HOME is not set at all -> same contract, same fix as the missing-tool case (R11)"
|
|
562
|
+
OUT="$(
|
|
563
|
+
env -u HOME -u HERDR_ENV -u HERDR_PANE_ID -u ORCA_PANE_KEY \
|
|
564
|
+
bash "$SUT" 2>/dev/null
|
|
565
|
+
)"
|
|
566
|
+
CODE=$?
|
|
567
|
+
LINES="$(printf '%s\n' "$OUT" | wc -l | tr -d ' ')"
|
|
568
|
+
check "exit code is 0" '[ "$CODE" -eq 0 ]'
|
|
569
|
+
check "prints exactly 6 lines" '[ "$LINES" -eq 6 ]'
|
|
570
|
+
check "line 1 is declared_herdr=" 'printf "%s\n" "$OUT" | sed -n "1p" | grep -q "^declared_herdr="'
|
|
571
|
+
check "line 2 is declared_orca=" 'printf "%s\n" "$OUT" | sed -n "2p" | grep -q "^declared_orca="'
|
|
572
|
+
check "line 3 is detected=" 'printf "%s\n" "$OUT" | sed -n "3p" | grep -q "^detected="'
|
|
573
|
+
check "line 4 is active=" 'printf "%s\n" "$OUT" | sed -n "4p" | grep -q "^active="'
|
|
574
|
+
check "line 5 is owner=" 'printf "%s\n" "$OUT" | sed -n "5p" | grep -q "^owner="'
|
|
575
|
+
check "line 6 is warning=" 'printf "%s\n" "$OUT" | sed -n "6p" | grep -q "^warning="'
|
|
576
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
577
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
578
|
+
check "owner=none (no HOME, so neither root resolves)" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
579
|
+
WARN33="$(get_val "$OUT" warning)"
|
|
580
|
+
check "warning is non-empty" '[ -n "$WARN33" ]'
|
|
581
|
+
check "warning mentions restarting Claude Code (the same fix as the missing-tool case)" 'printf "%s" "$WARN33" | grep -qi "restart"'
|
|
582
|
+
|
|
583
|
+
# =========================================================================
|
|
584
|
+
# R12 – owner: which orchestrator owns the checkout being looked at
|
|
585
|
+
#
|
|
586
|
+
# A checkout is one git worktree directory, and its path root names the
|
|
587
|
+
# owner: a path under $HOME/orca/workspaces/ belongs to orca, a path under
|
|
588
|
+
# herdr's worktree root belongs to herdr, and anything else belongs to plain
|
|
589
|
+
# git and has no owner. The owner comes from the path alone – no markers, no
|
|
590
|
+
# declarations.
|
|
591
|
+
# =========================================================================
|
|
592
|
+
echo "Case 34: inside a herdr checkout, no markers -> owner=herdr (R12)"
|
|
593
|
+
H34="$(new_home)"
|
|
594
|
+
mk_cli_declared "$H34" false false
|
|
595
|
+
WT34="$(mk_herdr_checkout "$H34" repo-a branch-a)"
|
|
596
|
+
OUT="$(run_case_in "$H34" "$WT34" '')"
|
|
597
|
+
CODE=$?
|
|
598
|
+
LINES="$(printf '%s\n' "$OUT" | wc -l | tr -d ' ')"
|
|
599
|
+
check "exit code is 0" '[ "$CODE" -eq 0 ]'
|
|
600
|
+
check "prints exactly 6 lines" '[ "$LINES" -eq 6 ]'
|
|
601
|
+
check "line 5 is owner=" 'printf "%s\n" "$OUT" | sed -n "5p" | grep -q "^owner="'
|
|
602
|
+
check "line 6 is warning=" 'printf "%s\n" "$OUT" | sed -n "6p" | grep -q "^warning="'
|
|
603
|
+
check "owner=herdr" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
604
|
+
check "detected=none (owning is not hosting)" '[ "$(get_val "$OUT" detected)" = "none" ]'
|
|
605
|
+
check "active=none" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
606
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
607
|
+
|
|
608
|
+
echo "Case 35: inside an orca workspace, no markers -> owner=orca (R12)"
|
|
609
|
+
H35="$(new_home)"
|
|
610
|
+
mk_cli_declared "$H35" false false
|
|
611
|
+
WS35="$(mk_orca_checkout "$H35" project-a)"
|
|
612
|
+
OUT="$(run_case_in "$H35" "$WS35" '')"
|
|
613
|
+
check "owner=orca" '[ "$(get_val "$OUT" owner)" = "orca" ]'
|
|
614
|
+
check "active=none" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
615
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
616
|
+
|
|
617
|
+
echo "Case 36: inside a checkout under neither root -> owner=none (R12)"
|
|
618
|
+
H36="$(new_home)"
|
|
619
|
+
mk_cli_declared "$H36" true true
|
|
620
|
+
PLAIN36="$WORK/plain36/repo"
|
|
621
|
+
mkdir -p "$PLAIN36"
|
|
622
|
+
OUT="$(run_case_in "$H36" "$PLAIN36" '')"
|
|
623
|
+
check "owner=none" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
624
|
+
|
|
625
|
+
echo "Case 37: the owner is reported even when the CLI cannot be run (R12)"
|
|
626
|
+
H37="$(new_home)"
|
|
627
|
+
mkdir -p "$H37"
|
|
628
|
+
WT37="$(mk_herdr_checkout "$H37" repo-b branch-b)"
|
|
629
|
+
OUT="$(run_case_in "$H37" "$WT37" '')"
|
|
630
|
+
check "owner=herdr despite no readable CLI" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
631
|
+
check "declared_herdr=unset" '[ "$(get_val "$OUT" declared_herdr)" = "unset" ]'
|
|
632
|
+
check "declared_orca=unset" '[ "$(get_val "$OUT" declared_orca)" = "unset" ]'
|
|
633
|
+
check "warning is still the actionable CLI one" 'printf "%s" "$(get_val "$OUT" warning)" | grep -qi "restart"'
|
|
634
|
+
|
|
635
|
+
echo "Case 38: the declared booleans do not move the owner (R12)"
|
|
636
|
+
H38A="$(new_home)"
|
|
637
|
+
mk_cli_declared "$H38A" true true
|
|
638
|
+
WS38="$(mk_orca_checkout "$H38A" project-b)"
|
|
639
|
+
OUT="$(run_case_in "$H38A" "$WS38" '')"
|
|
640
|
+
check "owner=orca with both declared true" '[ "$(get_val "$OUT" owner)" = "orca" ]'
|
|
641
|
+
H38B="$(new_home)"
|
|
642
|
+
mk_cli_declared "$H38B" false false
|
|
643
|
+
WT38="$(mk_herdr_checkout "$H38B" repo-c branch-c)"
|
|
644
|
+
OUT="$(run_case_in "$H38B" "$WT38" '')"
|
|
645
|
+
check "owner=herdr with both declared false" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
646
|
+
|
|
647
|
+
# =========================================================================
|
|
648
|
+
# R13 – the optional path argument names the checkout to examine
|
|
649
|
+
# =========================================================================
|
|
650
|
+
echo "Case 39: a path argument replaces the working directory (R13)"
|
|
651
|
+
H39="$(new_home)"
|
|
652
|
+
mk_cli_declared "$H39" false false
|
|
653
|
+
WS39="$(mk_orca_checkout "$H39" project-c)"
|
|
654
|
+
WT39="$(mk_herdr_checkout "$H39" repo-d branch-d)"
|
|
655
|
+
PLAIN39="$WORK/plain39/repo"
|
|
656
|
+
mkdir -p "$PLAIN39"
|
|
657
|
+
OUT="$(run_case_arg "$H39" "$WS39" '')"
|
|
658
|
+
CODE=$?
|
|
659
|
+
LINES="$(printf '%s\n' "$OUT" | wc -l | tr -d ' ')"
|
|
660
|
+
check "exit code is 0 with an argument" '[ "$CODE" -eq 0 ]'
|
|
661
|
+
check "still prints exactly 6 lines" '[ "$LINES" -eq 6 ]'
|
|
662
|
+
check "owner=orca from the named path" '[ "$(get_val "$OUT" owner)" = "orca" ]'
|
|
663
|
+
OUT="$(
|
|
664
|
+
(
|
|
665
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
666
|
+
export HOME="$H39"
|
|
667
|
+
cd "$WT39" || exit 1
|
|
668
|
+
bash "$SUT" "$PLAIN39" 2>/dev/null
|
|
669
|
+
)
|
|
670
|
+
)"
|
|
671
|
+
check "the argument wins over a herdr-owned cwd" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
672
|
+
|
|
673
|
+
# =========================================================================
|
|
674
|
+
# R14 – the path is resolved before it is judged
|
|
675
|
+
#
|
|
676
|
+
# Symlinks and .. segments are resolved first, and the root directory itself
|
|
677
|
+
# is not a checkout: only what sits underneath it counts.
|
|
678
|
+
# =========================================================================
|
|
679
|
+
echo "Case 40: symlinks are resolved before the path is judged (R14)"
|
|
680
|
+
H40="$(new_home)"
|
|
681
|
+
mk_cli_declared "$H40" false false
|
|
682
|
+
WT40="$(mk_herdr_checkout "$H40" repo-e branch-e)"
|
|
683
|
+
SYM40="$WORK/sym40"
|
|
684
|
+
ln -s "$WT40" "$SYM40"
|
|
685
|
+
OUT="$(run_case_in "$H40" "$SYM40" '')"
|
|
686
|
+
check "a symlink into the herdr root -> owner=herdr" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
687
|
+
OUTSIDE40="$WORK/outside40"
|
|
688
|
+
mkdir -p "$OUTSIDE40"
|
|
689
|
+
mkdir -p "$H40/.herdr/worktrees/repo-f"
|
|
690
|
+
ln -s "$OUTSIDE40" "$H40/.herdr/worktrees/repo-f/branch-f"
|
|
691
|
+
OUT="$(run_case_in "$H40" "$H40/.herdr/worktrees/repo-f/branch-f" '')"
|
|
692
|
+
check "a symlink out of the herdr root -> owner=none" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
693
|
+
|
|
694
|
+
echo "Case 41: .. segments are resolved before the path is judged (R14)"
|
|
695
|
+
H41="$(new_home)"
|
|
696
|
+
mk_cli_declared "$H41" false false
|
|
697
|
+
WT41="$(mk_herdr_checkout "$H41" repo-g branch-g)"
|
|
698
|
+
mkdir -p "$H41/elsewhere"
|
|
699
|
+
OUT="$(run_case_arg "$H41" "$H41/.herdr/worktrees/repo-g/branch-g/../branch-g" '')"
|
|
700
|
+
check ".. that lands back inside -> owner=herdr" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
701
|
+
OUT="$(run_case_arg "$H41" "$H41/.herdr/worktrees/../elsewhere" '')"
|
|
702
|
+
check ".. that climbs out -> owner=none" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
703
|
+
|
|
704
|
+
echo "Case 42: the root itself is not a checkout (R14)"
|
|
705
|
+
H42="$(new_home)"
|
|
706
|
+
mk_cli_declared "$H42" false false
|
|
707
|
+
mkdir -p "$H42/.herdr/worktrees" "$H42/orca/workspaces"
|
|
708
|
+
OUT="$(run_case_arg "$H42" "$H42/.herdr/worktrees" '')"
|
|
709
|
+
check "the herdr worktree root itself -> owner=none" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
710
|
+
OUT="$(run_case_arg "$H42" "$H42/orca/workspaces" '')"
|
|
711
|
+
check "the orca workspaces root itself -> owner=none" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
712
|
+
|
|
713
|
+
echo "Case 43: a sibling whose name merely starts with a root's name is not owned (R14)"
|
|
714
|
+
H43="$(new_home)"
|
|
715
|
+
mk_cli_declared "$H43" false false
|
|
716
|
+
mkdir -p "$H43/.herdr/worktrees-old/repo-h/branch-h"
|
|
717
|
+
mkdir -p "$H43/orca/workspaces-archive/project-d"
|
|
718
|
+
OUT="$(run_case_arg "$H43" "$H43/.herdr/worktrees-old/repo-h/branch-h" '')"
|
|
719
|
+
check ".herdr/worktrees-old is not the herdr root" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
720
|
+
OUT="$(run_case_arg "$H43" "$H43/orca/workspaces-archive/project-d" '')"
|
|
721
|
+
check "orca/workspaces-archive is not the orca root" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
722
|
+
|
|
723
|
+
# =========================================================================
|
|
724
|
+
# R15 – herdr's config names its own worktree root
|
|
725
|
+
#
|
|
726
|
+
# $HOME/.config/herdr/config.toml may set [worktrees] directory. When it
|
|
727
|
+
# does, that is the herdr root and the default one is not. A leading ~/ is
|
|
728
|
+
# the home directory.
|
|
729
|
+
# =========================================================================
|
|
730
|
+
echo "Case 44: config.toml moves the herdr root, and the default stops counting (R15)"
|
|
731
|
+
H44="$(new_home)"
|
|
732
|
+
mk_cli_declared "$H44" false false
|
|
733
|
+
mk_herdr_config "$H44" '~/custom/wt'
|
|
734
|
+
mkdir -p "$H44/custom/wt/repo-i/branch-i"
|
|
735
|
+
mkdir -p "$H44/.herdr/worktrees/repo-i/branch-i"
|
|
736
|
+
OUT="$(run_case_arg "$H44" "$H44/custom/wt/repo-i/branch-i" '')"
|
|
737
|
+
check "the configured root owns its checkouts" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
738
|
+
OUT="$(run_case_arg "$H44" "$H44/.herdr/worktrees/repo-i/branch-i" '')"
|
|
739
|
+
check "the default root no longer owns anything" '[ "$(get_val "$OUT" owner)" = "none" ]'
|
|
740
|
+
|
|
741
|
+
echo "Case 45: config.toml may name the root as an absolute path (R15)"
|
|
742
|
+
H45="$(new_home)"
|
|
743
|
+
mk_cli_declared "$H45" false false
|
|
744
|
+
mk_herdr_config "$H45" "$H45/abs/wt"
|
|
745
|
+
mkdir -p "$H45/abs/wt/repo-j/branch-j"
|
|
746
|
+
OUT="$(run_case_arg "$H45" "$H45/abs/wt/repo-j/branch-j" '')"
|
|
747
|
+
check "an absolute configured root owns its checkouts" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
748
|
+
|
|
749
|
+
echo "Case 46: a config.toml without a [worktrees] section falls back to the default (R15)"
|
|
750
|
+
H46="$(new_home)"
|
|
751
|
+
mk_cli_declared "$H46" false false
|
|
752
|
+
mk_herdr_config_without_worktrees "$H46"
|
|
753
|
+
WT46="$(mk_herdr_checkout "$H46" repo-k branch-k)"
|
|
754
|
+
OUT="$(run_case_arg "$H46" "$WT46" '')"
|
|
755
|
+
check "the default root still owns its checkouts" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
756
|
+
|
|
757
|
+
# =========================================================================
|
|
758
|
+
# R16 – both marker families at once, in a checkout somebody owns
|
|
759
|
+
#
|
|
760
|
+
# When both families are present the owner settles it outright, ahead of the
|
|
761
|
+
# declared booleans, and there is nothing ambiguous left to warn about.
|
|
762
|
+
# =========================================================================
|
|
763
|
+
echo "Case 47: both markers, orca owns the checkout, both declared true -> active=orca (R16)"
|
|
764
|
+
H47="$(new_home)"
|
|
765
|
+
mk_cli_declared "$H47" true true
|
|
766
|
+
WS47="$(mk_orca_checkout "$H47" project-e)"
|
|
767
|
+
OUT="$(run_case_in "$H47" "$WS47" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
768
|
+
check "owner=orca" '[ "$(get_val "$OUT" owner)" = "orca" ]'
|
|
769
|
+
check "detected=orca" '[ "$(get_val "$OUT" detected)" = "orca" ]'
|
|
770
|
+
check "active=orca" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
771
|
+
check "warning is empty (nothing ambiguous)" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
772
|
+
|
|
773
|
+
echo "Case 48: both markers, herdr owns the checkout, both declared true -> active=herdr (R16)"
|
|
774
|
+
H48="$(new_home)"
|
|
775
|
+
mk_cli_declared "$H48" true true
|
|
776
|
+
WT48="$(mk_herdr_checkout "$H48" repo-l branch-l)"
|
|
777
|
+
OUT="$(run_case_in "$H48" "$WT48" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
778
|
+
check "owner=herdr" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
779
|
+
check "detected=herdr" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
780
|
+
check "active=herdr" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
781
|
+
check "warning is empty (nothing ambiguous)" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
782
|
+
|
|
783
|
+
echo "Case 49: both markers, orca owns the checkout, only herdr declared true -> active=orca (R16)"
|
|
784
|
+
H49="$(new_home)"
|
|
785
|
+
mk_cli_declared "$H49" true false
|
|
786
|
+
WS49="$(mk_orca_checkout "$H49" project-f)"
|
|
787
|
+
OUT="$(run_case_in "$H49" "$WS49" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
788
|
+
check "active=orca (the owner outranks the declarations)" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
789
|
+
WARN49="$(get_val "$OUT" warning)"
|
|
790
|
+
check "no ambiguity warning (it does not name both)" '! { printf "%s" "$WARN49" | grep -qi "herdr" && printf "%s" "$WARN49" | grep -qi "orca"; }'
|
|
791
|
+
|
|
792
|
+
echo "Case 50: both markers, herdr owns the checkout, only orca declared true -> active=herdr (R16)"
|
|
793
|
+
H50="$(new_home)"
|
|
794
|
+
mk_cli_declared "$H50" false true
|
|
795
|
+
WT50="$(mk_herdr_checkout "$H50" repo-m branch-m)"
|
|
796
|
+
OUT="$(run_case_in "$H50" "$WT50" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
797
|
+
check "active=herdr (the owner outranks the declarations)" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
798
|
+
WARN50="$(get_val "$OUT" warning)"
|
|
799
|
+
check "no ambiguity warning (it does not name both)" '! { printf "%s" "$WARN50" | grep -qi "herdr" && printf "%s" "$WARN50" | grep -qi "orca"; }'
|
|
800
|
+
|
|
801
|
+
echo "Case 51: both markers, orca owns the checkout, neither declared true -> active=orca (R16)"
|
|
802
|
+
H51="$(new_home)"
|
|
803
|
+
mk_cli_declared "$H51" false false
|
|
804
|
+
WS51="$(mk_orca_checkout "$H51" project-g)"
|
|
805
|
+
OUT="$(run_case_in "$H51" "$WS51" 'export HERDR_ENV=1 ORCA_PANE_KEY=key-1')"
|
|
806
|
+
check "active=orca" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
807
|
+
WARN51="$(get_val "$OUT" warning)"
|
|
808
|
+
check "no ambiguity warning (it does not name both)" '! { printf "%s" "$WARN51" | grep -qi "herdr" && printf "%s" "$WARN51" | grep -qi "orca"; }'
|
|
809
|
+
|
|
810
|
+
# =========================================================================
|
|
811
|
+
# R17 – one marker family, or none, is unaffected by the owner
|
|
812
|
+
#
|
|
813
|
+
# The owner only ever settles a tie. A single family of markers is already
|
|
814
|
+
# unambiguous, and no markers at all means nothing is hosting this session,
|
|
815
|
+
# however the checkout is owned.
|
|
816
|
+
# =========================================================================
|
|
817
|
+
echo "Case 52: herdr markers only, inside an orca workspace -> active=herdr (R17)"
|
|
818
|
+
H52="$(new_home)"
|
|
819
|
+
mk_cli_declared "$H52" true false
|
|
820
|
+
WS52="$(mk_orca_checkout "$H52" project-h)"
|
|
821
|
+
OUT="$(run_case_in "$H52" "$WS52" 'export HERDR_ENV=1')"
|
|
822
|
+
check "owner=orca" '[ "$(get_val "$OUT" owner)" = "orca" ]'
|
|
823
|
+
check "detected=herdr" '[ "$(get_val "$OUT" detected)" = "herdr" ]'
|
|
824
|
+
check "active=herdr (markers beat the owner)" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
825
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
826
|
+
|
|
827
|
+
echo "Case 53: orca markers only, inside a herdr checkout -> active=orca (R17)"
|
|
828
|
+
H53="$(new_home)"
|
|
829
|
+
mk_cli_declared "$H53" false true
|
|
830
|
+
WT53="$(mk_herdr_checkout "$H53" repo-n branch-n)"
|
|
831
|
+
OUT="$(run_case_in "$H53" "$WT53" 'export ORCA_PANE_KEY=key-1')"
|
|
832
|
+
check "owner=herdr" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
833
|
+
check "detected=orca" '[ "$(get_val "$OUT" detected)" = "orca" ]'
|
|
834
|
+
check "active=orca (markers beat the owner)" '[ "$(get_val "$OUT" active)" = "orca" ]'
|
|
835
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
836
|
+
|
|
837
|
+
echo "Case 54: one family undeclared is still warned about, whoever owns the checkout (R17)"
|
|
838
|
+
H54="$(new_home)"
|
|
839
|
+
mk_cli_declared "$H54" false false
|
|
840
|
+
WS54="$(mk_orca_checkout "$H54" project-i)"
|
|
841
|
+
OUT="$(run_case_in "$H54" "$WS54" 'export HERDR_ENV=1')"
|
|
842
|
+
check "active=herdr" '[ "$(get_val "$OUT" active)" = "herdr" ]'
|
|
843
|
+
WARN54="$(get_val "$OUT" warning)"
|
|
844
|
+
check "warning names herdr" 'printf "%s" "$WARN54" | grep -qi "herdr"'
|
|
845
|
+
check "warning mentions declaring" 'printf "%s" "$WARN54" | grep -qi "declare"'
|
|
846
|
+
|
|
847
|
+
echo "Case 55: no markers at all, inside a herdr checkout -> active=none (R17)"
|
|
848
|
+
H55="$(new_home)"
|
|
849
|
+
mk_cli_declared "$H55" true true
|
|
850
|
+
WT55="$(mk_herdr_checkout "$H55" repo-o branch-o)"
|
|
851
|
+
OUT="$(run_case_in "$H55" "$WT55" '')"
|
|
852
|
+
check "owner=herdr" '[ "$(get_val "$OUT" owner)" = "herdr" ]'
|
|
853
|
+
check "detected=none" '[ "$(get_val "$OUT" detected)" = "none" ]'
|
|
854
|
+
check "active=none (owning is not hosting)" '[ "$(get_val "$OUT" active)" = "none" ]'
|
|
855
|
+
check "warning is empty" '[ -z "$(get_val "$OUT" warning)" ]'
|
|
856
|
+
|
|
857
|
+
# =========================================================================
|
|
858
|
+
# R18 – purity: working out the owner changes nothing on disk
|
|
859
|
+
# =========================================================================
|
|
860
|
+
echo "Case 56: a run from inside an owned git checkout writes nothing (R18)"
|
|
861
|
+
H56="$(new_home)"
|
|
862
|
+
mk_cli_declared "$H56" true true
|
|
863
|
+
WT56="$(mk_herdr_checkout "$H56" repo-p branch-p)"
|
|
864
|
+
git init -q "$WT56" 2>/dev/null
|
|
865
|
+
BEFORE_TREE56="$(find "$H56" | sort)"
|
|
866
|
+
BEFORE_GITCFG56="$(HOME="$H56" git config --global --list 2>/dev/null || true)"
|
|
867
|
+
(
|
|
868
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
869
|
+
export HOME="$H56"
|
|
870
|
+
cd "$WT56" || exit 1
|
|
871
|
+
export HERDR_ENV=1 ORCA_PANE_KEY=key-1
|
|
872
|
+
bash "$SUT" >/dev/null 2>/dev/null
|
|
873
|
+
)
|
|
874
|
+
AFTER_TREE56="$(find "$H56" | sort)"
|
|
875
|
+
AFTER_GITCFG56="$(HOME="$H56" git config --global --list 2>/dev/null || true)"
|
|
876
|
+
check "the whole HOME tree is unchanged" '[ "$BEFORE_TREE56" = "$AFTER_TREE56" ]'
|
|
877
|
+
check "no global git config added" '[ "$BEFORE_GITCFG56" = "$AFTER_GITCFG56" ]'
|
|
878
|
+
|
|
879
|
+
echo "Case 57: a run in a directory that is not a git repo creates no repository (R18)"
|
|
880
|
+
H57="$(new_home)"
|
|
881
|
+
mk_cli_declared "$H57" true false
|
|
882
|
+
WT57="$(mk_herdr_checkout "$H57" repo-q branch-q)"
|
|
883
|
+
(
|
|
884
|
+
unset HERDR_ENV HERDR_PANE_ID ORCA_PANE_KEY
|
|
885
|
+
export HOME="$H57"
|
|
886
|
+
cd "$WT57" || exit 1
|
|
887
|
+
bash "$SUT" >/dev/null 2>/dev/null
|
|
888
|
+
)
|
|
889
|
+
check "no .git directory was created" '[ ! -e "$WT57/.git" ]'
|
|
890
|
+
|
|
891
|
+
echo ""
|
|
892
|
+
echo "----------------------------------------"
|
|
893
|
+
printf 'Result: %d passed, %d failed\n' "$pass" "$fail"
|
|
894
|
+
[ "$fail" -eq 0 ] || exit 1
|