1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#!/usr/bin/env bats
# Tests for agent-roster: report other live Claude agents in a project.
#
# pgrep and /proc are the system boundary, so the test injects both and runs
# the real include/exclude logic against fixtures — no Claude processes are
# spawned. Injection points:
# ROSTER_PGREP command standing in for pgrep (a stub printing $FAKE_PIDS)
# ROSTER_PROC proc dir (a fixture of <pid>/cwd symlinks + <pid>/status)
# ROSTER_SELF_PID the scanner's own pid, so the ancestry walk is testable
#
# Fixture process tree: pid 1000 (the scanner) is a child of 999 (the current
# session's claude), which is a child of init (1). So 999 must always be
# excluded as scanner ancestry; other claude pids are judged by cwd.
setup() {
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
ROSTER="$SCRIPT_DIR/agent-roster"
PROC="$BATS_TEST_TMPDIR/proc"
ROOT="$BATS_TEST_TMPDIR/project"
mkdir -p "$PROC" "$ROOT/sub" "$BATS_TEST_TMPDIR/elsewhere"
PGREP_STUB="$BATS_TEST_TMPDIR/pgrep"
cat >"$PGREP_STUB" <<'EOF'
#!/usr/bin/env bash
printf '%s\n' $FAKE_PIDS
EOF
chmod +x "$PGREP_STUB"
SELF=1000
# scanner (1000) <- session claude (999) <- init (1)
mkproc 1000 "$ROOT" 999
mkproc 999 "$ROOT" 1
}
# mkproc PID CWD PPID — register a fake process in the fixture proc dir.
mkproc() {
mkdir -p "$PROC/$1"
ln -sf "$2" "$PROC/$1/cwd"
printf 'PPid:\t%s\n' "$3" >"$PROC/$1/status"
}
run_roster() {
ROSTER_PGREP="$PGREP_STUB" ROSTER_PROC="$PROC" ROSTER_SELF_PID="$SELF" \
FAKE_PIDS="$FAKE_PIDS" run "$ROSTER" "$ROOT"
}
@test "agent-roster: alone (only the session's own claude) exits 0, no output" {
FAKE_PIDS="999"
run_roster
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "agent-roster: one other agent in-project is printed, exit 1" {
mkproc 2000 "$ROOT" 1
FAKE_PIDS="999 2000"
run_roster
[ "$status" -eq 1 ]
[[ "$output" == *"2000"* ]]
[[ "$output" == *"$ROOT"* ]]
}
@test "agent-roster: two other agents both printed, exit 1" {
mkproc 2000 "$ROOT" 1
mkproc 2001 "$ROOT/sub" 1
FAKE_PIDS="999 2000 2001"
run_roster
[ "$status" -eq 1 ]
[[ "$output" == *"2000"* ]]
[[ "$output" == *"2001"* ]]
[ "${#lines[@]}" -eq 2 ]
}
@test "agent-roster: the scanner's session-claude ancestor is excluded even with matching cwd" {
# 999 has cwd == ROOT but is scanner ancestry; must not appear.
FAKE_PIDS="999"
run_roster
[ "$status" -eq 0 ]
[[ "$output" != *"999"* ]]
}
@test "agent-roster: cwd outside the project root is excluded" {
mkproc 3000 "$BATS_TEST_TMPDIR/elsewhere" 1
FAKE_PIDS="999 3000"
run_roster
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "agent-roster: cwd in a subdirectory of root is included" {
mkproc 2002 "$ROOT/sub" 1
FAKE_PIDS="999 2002"
run_roster
[ "$status" -eq 1 ]
[[ "$output" == *"2002"* ]]
}
@test "agent-roster: a sibling path sharing a prefix is not a false match" {
# ROOT is .../project; .../project-other must not count as inside it.
mkdir -p "$BATS_TEST_TMPDIR/project-other"
mkproc 3100 "$BATS_TEST_TMPDIR/project-other" 1
FAKE_PIDS="999 3100"
run_roster
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "agent-roster: a pid that vanished between pgrep and the proc read is skipped" {
# 4000 has no fixture dir, simulating a process gone by readlink time.
FAKE_PIDS="999 4000"
run_roster
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "agent-roster: missing proc reports unavailable on stderr, exit 2, never silent-alone" {
ROSTER_PGREP="$PGREP_STUB" ROSTER_PROC="$BATS_TEST_TMPDIR/nonexistent" \
ROSTER_SELF_PID="$SELF" FAKE_PIDS="999 2000" run "$ROSTER" "$ROOT"
[ "$status" -eq 2 ]
[[ "$output" == *"roster unavailable"* ]]
}
@test "agent-roster: a missing pgrep reports unavailable, exit 2, never silent-alone" {
# If pgrep itself is absent, the scan can't run; reporting "alone" would be a
# false negative the "never silent-alone" invariant forbids.
mkproc 2000 "$ROOT" 1
ROSTER_PGREP="$BATS_TEST_TMPDIR/no-such-pgrep" ROSTER_PROC="$PROC" \
ROSTER_SELF_PID="$SELF" FAKE_PIDS="999 2000" run "$ROSTER" "$ROOT"
[ "$status" -eq 2 ]
[[ "$output" == *"roster unavailable"* ]]
}
@test "agent-roster: defaults project root to PWD when no argument is given" {
mkproc 2000 "$ROOT" 1
FAKE_PIDS="999 2000"
ROSTER_PGREP="$PGREP_STUB" ROSTER_PROC="$PROC" ROSTER_SELF_PID="$SELF" \
FAKE_PIDS="$FAKE_PIDS" run env -C "$ROOT" "$ROSTER"
[ "$status" -eq 1 ]
[[ "$output" == *"2000"* ]]
}
|