relay-flow 0.2.3-alpha → 0.2.4-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +116 -10
  2. package/cmd/relay-flow/main.go +2 -0
  3. package/cmd/relay-flow/pi_wiring_test.go +64 -0
  4. package/cmd/relay-flow/serve.go +2 -0
  5. package/examples/beads-workflow.yaml +3 -3
  6. package/examples/config-reference.yaml +144 -0
  7. package/examples/minimal-beads-task-workflow.yaml +34 -0
  8. package/examples/minimal-jira-task-workflow.yaml +68 -0
  9. package/examples/workflow-reference.yaml +111 -0
  10. package/internal/harness/opencode/opencode_test.go +1 -1
  11. package/internal/harness/opencode/repo_setup.go +1 -1
  12. package/internal/harness/pi/config_test.go +46 -0
  13. package/internal/harness/pi/lifecycle_test.go +69 -0
  14. package/internal/harness/pi/pi.go +261 -0
  15. package/internal/harness/pi/pi_test.go +322 -0
  16. package/internal/harness/pi/prompt_test.go +121 -0
  17. package/internal/harness/pi/testdata/pi-0.84.1/capture.json +126 -0
  18. package/internal/harness/pi/testdata/pi-0.84.1/noninteractive-output.txt +11 -0
  19. package/internal/harness/pi/testdata/pi-0.84.1/tui-output-sanitized.txt +17 -0
  20. package/internal/harness/pi/validation_test.go +168 -0
  21. package/internal/runner/herdr/baseref.go +60 -0
  22. package/internal/runner/herdr/herdr.go +578 -0
  23. package/internal/runner/herdr/herdr_test.go +688 -0
  24. package/internal/runner/herdr/herdrcli/contract.go +128 -0
  25. package/internal/runner/herdr/herdrcli/exec.go +68 -0
  26. package/internal/runner/herdr/herdrcli/herdrcli_test.go +274 -0
  27. package/internal/runner/herdr/herdrcli/live_test.go +132 -0
  28. package/internal/runner/herdr/herdrcli/operations.go +281 -0
  29. package/internal/runner/herdr/herdrcli/response.go +116 -0
  30. package/internal/runner/herdr/herdrcli/testdata/empty-panes.json +1 -0
  31. package/internal/runner/herdr/herdrcli/testdata/empty-tabs.json +1 -0
  32. package/internal/runner/herdr/herdrcli/testdata/error-not-git-worktree.json +1 -0
  33. package/internal/runner/herdr/herdrcli/testdata/error-pane-not-found.json +1 -0
  34. package/internal/runner/herdr/herdrcli/testdata/error-workspace-not-found.json +1 -0
  35. package/internal/runner/herdr/herdrcli/testdata/error-worktree-not-found.json +1 -0
  36. package/internal/runner/herdr/herdrcli/testdata/malformed.json +1 -0
  37. package/internal/runner/herdr/herdrcli/testdata/pane-close.json +6 -0
  38. package/internal/runner/herdr/herdrcli/testdata/pane-get.json +25 -0
  39. package/internal/runner/herdr/herdrcli/testdata/pane-list.json +45 -0
  40. package/internal/runner/herdr/herdrcli/testdata/pane-process-info-shell.json +22 -0
  41. package/internal/runner/herdr/herdrcli/testdata/pane-process-info.json +23 -0
  42. package/internal/runner/herdr/herdrcli/testdata/pane-rename.json +23 -0
  43. package/internal/runner/herdr/herdrcli/testdata/snapshot.json +213 -0
  44. package/internal/runner/herdr/herdrcli/testdata/strict-herdr.sh +175 -0
  45. package/internal/runner/herdr/herdrcli/testdata/tab-create.json +31 -0
  46. package/internal/runner/herdr/herdrcli/testdata/tab-list.json +26 -0
  47. package/internal/runner/herdr/herdrcli/testdata/workspace-close.json +6 -0
  48. package/internal/runner/herdr/herdrcli/testdata/worktree-create.json +58 -0
  49. package/internal/runner/herdr/herdrcli/testdata/worktree-list.json +35 -0
  50. package/internal/runner/herdr/herdrcli/testdata/worktree-open.json +59 -0
  51. package/internal/task/beads/beads.go +0 -16
  52. package/internal/task/beads/config_compatibility_test.go +7 -8
  53. package/internal/task/jira/filters_test.go +32 -6
  54. package/internal/task/jira/jira.go +27 -17
  55. package/package.json +1 -1
@@ -0,0 +1,213 @@
1
+ {
2
+ "id": "cli:api:snapshot",
3
+ "result": {
4
+ "snapshot": {
5
+ "agents": [],
6
+ "focused_pane_id": "w1:p1",
7
+ "focused_tab_id": "w1:t1",
8
+ "focused_workspace_id": "w1",
9
+ "layouts": [
10
+ {
11
+ "area": {
12
+ "height": 39,
13
+ "width": 94,
14
+ "x": 26,
15
+ "y": 1
16
+ },
17
+ "focused_pane_id": "w1:p1",
18
+ "panes": [
19
+ {
20
+ "focused": true,
21
+ "pane_id": "w1:p1",
22
+ "rect": {
23
+ "height": 39,
24
+ "width": 94,
25
+ "x": 26,
26
+ "y": 1
27
+ }
28
+ }
29
+ ],
30
+ "splits": [],
31
+ "tab_id": "w1:t1",
32
+ "workspace_id": "w1",
33
+ "zoomed": false
34
+ },
35
+ {
36
+ "area": {
37
+ "height": 39,
38
+ "width": 94,
39
+ "x": 26,
40
+ "y": 1
41
+ },
42
+ "focused_pane_id": "w2:p1",
43
+ "panes": [
44
+ {
45
+ "focused": true,
46
+ "pane_id": "w2:p1",
47
+ "rect": {
48
+ "height": 39,
49
+ "width": 94,
50
+ "x": 26,
51
+ "y": 1
52
+ }
53
+ }
54
+ ],
55
+ "splits": [],
56
+ "tab_id": "w2:t1",
57
+ "workspace_id": "w2",
58
+ "zoomed": false
59
+ },
60
+ {
61
+ "area": {
62
+ "height": 39,
63
+ "width": 94,
64
+ "x": 26,
65
+ "y": 1
66
+ },
67
+ "focused_pane_id": "w2:p2",
68
+ "panes": [
69
+ {
70
+ "focused": true,
71
+ "pane_id": "w2:p2",
72
+ "rect": {
73
+ "height": 39,
74
+ "width": 94,
75
+ "x": 26,
76
+ "y": 1
77
+ }
78
+ }
79
+ ],
80
+ "splits": [],
81
+ "tab_id": "w2:t2",
82
+ "workspace_id": "w2",
83
+ "zoomed": false
84
+ }
85
+ ],
86
+ "panes": [
87
+ {
88
+ "agent_status": "unknown",
89
+ "cwd": "/work/payments",
90
+ "focused": true,
91
+ "foreground_cwd": "/work/payments",
92
+ "pane_id": "w1:p1",
93
+ "revision": 1,
94
+ "scroll": {
95
+ "max_offset_from_bottom": 0,
96
+ "offset_from_bottom": 0,
97
+ "viewport_rows": 39
98
+ },
99
+ "tab_id": "w1:t1",
100
+ "terminal_id": "term_65a5cfcc8c6361",
101
+ "terminal_title": "relay@relay-host:/work/payments",
102
+ "terminal_title_stripped": "relay@relay-host:/work/payments",
103
+ "workspace_id": "w1"
104
+ },
105
+ {
106
+ "agent_status": "unknown",
107
+ "cwd": "/work/worktrees/payments/pay-101",
108
+ "focused": false,
109
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
110
+ "pane_id": "w2:p1",
111
+ "revision": 1,
112
+ "scroll": {
113
+ "max_offset_from_bottom": 0,
114
+ "offset_from_bottom": 0,
115
+ "viewport_rows": 39
116
+ },
117
+ "tab_id": "w2:t1",
118
+ "terminal_id": "term_65a5cfcc8cd9e2",
119
+ "terminal_title": "relay@relay-host:~/.herdr/worktrees/repo/pay-101",
120
+ "terminal_title_stripped": "relay@relay-host:~/.herdr/worktrees/repo/pay-101",
121
+ "workspace_id": "w2"
122
+ },
123
+ {
124
+ "agent_status": "unknown",
125
+ "cwd": "/work/worktrees/payments/pay-101",
126
+ "focused": false,
127
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
128
+ "label": "PAY-101:coding",
129
+ "pane_id": "w2:p2",
130
+ "revision": 2,
131
+ "scroll": {
132
+ "max_offset_from_bottom": 0,
133
+ "offset_from_bottom": 0,
134
+ "viewport_rows": 39
135
+ },
136
+ "tab_id": "w2:t2",
137
+ "terminal_id": "term_65a5cfcc913e03",
138
+ "terminal_title": "sleep 300",
139
+ "terminal_title_stripped": "sleep 300",
140
+ "workspace_id": "w2"
141
+ }
142
+ ],
143
+ "protocol": 20,
144
+ "tabs": [
145
+ {
146
+ "agent_status": "unknown",
147
+ "focused": true,
148
+ "label": "1",
149
+ "number": 1,
150
+ "pane_count": 1,
151
+ "tab_id": "w1:t1",
152
+ "workspace_id": "w1"
153
+ },
154
+ {
155
+ "agent_status": "unknown",
156
+ "focused": false,
157
+ "label": "1",
158
+ "number": 1,
159
+ "pane_count": 1,
160
+ "tab_id": "w2:t1",
161
+ "workspace_id": "w2"
162
+ },
163
+ {
164
+ "agent_status": "unknown",
165
+ "focused": false,
166
+ "label": "PAY-101:coding",
167
+ "number": 2,
168
+ "pane_count": 1,
169
+ "tab_id": "w2:t2",
170
+ "workspace_id": "w2"
171
+ }
172
+ ],
173
+ "version": "0.8.2",
174
+ "workspaces": [
175
+ {
176
+ "active_tab_id": "w1:t1",
177
+ "agent_status": "unknown",
178
+ "focused": true,
179
+ "label": "repo",
180
+ "number": 1,
181
+ "pane_count": 1,
182
+ "tab_count": 1,
183
+ "workspace_id": "w1",
184
+ "worktree": {
185
+ "checkout_path": "/work/payments",
186
+ "is_linked_worktree": false,
187
+ "repo_key": "/work/payments/.git",
188
+ "repo_name": "repo",
189
+ "repo_root": "/work/payments"
190
+ }
191
+ },
192
+ {
193
+ "active_tab_id": "w2:t1",
194
+ "agent_status": "unknown",
195
+ "focused": false,
196
+ "label": "PAY-101",
197
+ "number": 2,
198
+ "pane_count": 2,
199
+ "tab_count": 2,
200
+ "workspace_id": "w2",
201
+ "worktree": {
202
+ "checkout_path": "/work/worktrees/payments/pay-101",
203
+ "is_linked_worktree": true,
204
+ "repo_key": "/work/payments/.git",
205
+ "repo_name": "repo",
206
+ "repo_root": "/work/payments"
207
+ }
208
+ }
209
+ ]
210
+ },
211
+ "type": "session_snapshot"
212
+ }
213
+ }
@@ -0,0 +1,175 @@
1
+ #!/bin/sh
2
+ # Strict fake `herdr`. It accepts only the exact production command shapes and
3
+ # reproduces the observed transport contract of herdr 0.8.2:
4
+ # success -> result envelope on stdout, exit 0 (pane run prints nothing)
5
+ # failure -> error envelope on stderr, exit 1, empty stdout
6
+ set -eu
7
+
8
+ fail() {
9
+ printf 'unsupported or malformed herdr invocation:' >&2
10
+ for arg in "$@"; do
11
+ printf ' <%s>' "$arg" >&2
12
+ done
13
+ printf '\n' >&2
14
+ exit 64
15
+ }
16
+
17
+ # The wrapper supplies selector configuration through the environment rather
18
+ # than adding session/socket flags to every Herdr command.
19
+ check_selector() {
20
+ actual_name=$1
21
+ expected_name=$2
22
+ eval "expected_set=\${${expected_name}+x}"
23
+ if [ "$expected_set" = x ]; then
24
+ eval "expected=\${${expected_name}-}"
25
+ eval "actual=\${${actual_name}-}"
26
+ [ "$actual" = "$expected" ] || fail "wrong $actual_name: $actual"
27
+ else
28
+ eval "actual_set=\${${actual_name}+x}"
29
+ [ "$actual_set" != x ] || fail "ambient $actual_name leaked"
30
+ fi
31
+ }
32
+
33
+ check_selector HERDR_SESSION HERDR_EXPECT_SESSION
34
+ check_selector HERDR_SOCKET_PATH HERDR_EXPECT_SOCKET_PATH
35
+
36
+ fixture_path() {
37
+ fixture_dir=${HERDR_FIXTURE_DIR-}
38
+ [ -n "$fixture_dir" ] || fail "HERDR_FIXTURE_DIR is unset"
39
+ [ -f "$fixture_dir/$1" ] || fail "missing fixture: $1"
40
+ printf '%s' "$fixture_dir/$1"
41
+ }
42
+
43
+ emit_result() { cat "$(fixture_path "$1")"; exit 0; }
44
+
45
+ # Herdr writes error envelopes to stderr and exits 1.
46
+ emit_error() { cat "$(fixture_path "$1")" >&2; exit 1; }
47
+
48
+ check_absolute_cwd() {
49
+ case "$1" in
50
+ /*) ;;
51
+ *) fail "--cwd must be absolute: $1" ;;
52
+ esac
53
+ }
54
+
55
+ check_value() {
56
+ [ -n "$1" ] || fail "empty positional value"
57
+ case "$1" in
58
+ -*) fail "unexpected flag in positional value: $1" ;;
59
+ esac
60
+ }
61
+
62
+ case "$#:${1-}:${2-}" in
63
+ 2:api:snapshot)
64
+ emit_result snapshot.json
65
+ ;;
66
+ 4:worktree:list)
67
+ [ "$3" = --cwd ] || fail "$@"
68
+ check_absolute_cwd "$4"
69
+ case "$4" in
70
+ *not-a-repo) emit_error error-not-git-worktree.json ;;
71
+ *) emit_result worktree-list.json ;;
72
+ esac
73
+ ;;
74
+ 11:worktree:create)
75
+ [ "$3" = --cwd ] || fail "$@"
76
+ check_absolute_cwd "$4"
77
+ [ "$5" = --branch ] || fail "$@"
78
+ check_value "$6"
79
+ [ "$7" = --base ] || fail "$@"
80
+ check_value "$8"
81
+ [ "$9" = --label ] || fail "$@"
82
+ check_value "${10}"
83
+ [ "${11}" = --no-focus ] || fail "$@"
84
+ emit_result worktree-create.json
85
+ ;;
86
+ 9:worktree:open)
87
+ [ "$3" = --cwd ] || fail "$@"
88
+ check_absolute_cwd "$4"
89
+ [ "$5" = --branch ] || fail "$@"
90
+ check_value "$6"
91
+ [ "$7" = --label ] || fail "$@"
92
+ check_value "$8"
93
+ [ "$9" = --no-focus ] || fail "$@"
94
+ case "$6" in
95
+ MISSING-*) emit_error error-worktree-not-found.json ;;
96
+ esac
97
+ emit_result worktree-open.json
98
+ ;;
99
+ 9:tab:create)
100
+ [ "$3" = --workspace ] || fail "$@"
101
+ check_value "$4"
102
+ [ "$5" = --cwd ] || fail "$@"
103
+ check_absolute_cwd "$6"
104
+ [ "$7" = --label ] || fail "$@"
105
+ check_value "$8"
106
+ [ "$9" = --no-focus ] || fail "$@"
107
+ emit_result tab-create.json
108
+ ;;
109
+ 4:tab:list)
110
+ [ "$3" = --workspace ] || fail "$@"
111
+ check_value "$4"
112
+ case "$4" in
113
+ empty) emit_result empty-tabs.json ;;
114
+ missing) emit_error error-workspace-not-found.json ;;
115
+ *) emit_result tab-list.json ;;
116
+ esac
117
+ ;;
118
+ 4:pane:list)
119
+ [ "$3" = --workspace ] || fail "$@"
120
+ check_value "$4"
121
+ case "$4" in
122
+ empty) emit_result empty-panes.json ;;
123
+ missing) emit_error error-workspace-not-found.json ;;
124
+ *) emit_result pane-list.json ;;
125
+ esac
126
+ ;;
127
+ 3:pane:get)
128
+ check_value "$3"
129
+ case "$3" in
130
+ malformed) emit_result malformed.json ;;
131
+ warning) printf 'captured warning\n' >&2; emit_result pane-get.json ;;
132
+ missing) emit_error error-pane-not-found.json ;;
133
+ *) emit_result pane-get.json ;;
134
+ esac
135
+ ;;
136
+ 4:pane:process-info)
137
+ [ "$3" = --pane ] || fail "$@"
138
+ check_value "$4"
139
+ case "$4" in
140
+ shell) emit_result pane-process-info-shell.json ;;
141
+ missing) emit_error error-pane-not-found.json ;;
142
+ *) emit_result pane-process-info.json ;;
143
+ esac
144
+ ;;
145
+ 4:pane:rename)
146
+ check_value "$3"
147
+ check_value "$4"
148
+ emit_result pane-rename.json
149
+ ;;
150
+ 4:pane:run)
151
+ # COMMAND is deliberately one logical argument: a command containing
152
+ # spaces or newlines must arrive as the same argument the wrapper passed
153
+ # to exec.CommandContext. Herdr prints nothing on success.
154
+ check_value "$3"
155
+ [ -n "$4" ] || fail "empty command"
156
+ exit 0
157
+ ;;
158
+ 3:pane:close)
159
+ check_value "$3"
160
+ case "$3" in
161
+ missing) emit_error error-pane-not-found.json ;;
162
+ *) emit_result pane-close.json ;;
163
+ esac
164
+ ;;
165
+ 3:workspace:close)
166
+ check_value "$3"
167
+ case "$3" in
168
+ missing) emit_error error-workspace-not-found.json ;;
169
+ *) emit_result workspace-close.json ;;
170
+ esac
171
+ ;;
172
+ *)
173
+ fail "$@"
174
+ ;;
175
+ esac
@@ -0,0 +1,31 @@
1
+ {
2
+ "id": "cli:tab:create",
3
+ "result": {
4
+ "root_pane": {
5
+ "agent_status": "unknown",
6
+ "cwd": "/work/worktrees/payments/pay-101",
7
+ "focused": false,
8
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
9
+ "pane_id": "w2:p2",
10
+ "revision": 0,
11
+ "scroll": {
12
+ "max_offset_from_bottom": 0,
13
+ "offset_from_bottom": 0,
14
+ "viewport_rows": 39
15
+ },
16
+ "tab_id": "w2:t2",
17
+ "terminal_id": "term_65a5cfcc913e03",
18
+ "workspace_id": "w2"
19
+ },
20
+ "tab": {
21
+ "agent_status": "unknown",
22
+ "focused": false,
23
+ "label": "PAY-101:coding",
24
+ "number": 2,
25
+ "pane_count": 1,
26
+ "tab_id": "w2:t2",
27
+ "workspace_id": "w2"
28
+ },
29
+ "type": "tab_created"
30
+ }
31
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "id": "cli:tab:list",
3
+ "result": {
4
+ "tabs": [
5
+ {
6
+ "agent_status": "unknown",
7
+ "focused": false,
8
+ "label": "1",
9
+ "number": 1,
10
+ "pane_count": 1,
11
+ "tab_id": "w2:t1",
12
+ "workspace_id": "w2"
13
+ },
14
+ {
15
+ "agent_status": "unknown",
16
+ "focused": false,
17
+ "label": "PAY-101:coding",
18
+ "number": 2,
19
+ "pane_count": 1,
20
+ "tab_id": "w2:t2",
21
+ "workspace_id": "w2"
22
+ }
23
+ ],
24
+ "type": "tab_list"
25
+ }
26
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "cli:workspace:close",
3
+ "result": {
4
+ "type": "ok"
5
+ }
6
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "id": "cli:worktree:create",
3
+ "result": {
4
+ "root_pane": {
5
+ "agent_status": "unknown",
6
+ "cwd": "/work/worktrees/payments/pay-101",
7
+ "focused": false,
8
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
9
+ "pane_id": "w2:p1",
10
+ "revision": 0,
11
+ "scroll": {
12
+ "max_offset_from_bottom": 0,
13
+ "offset_from_bottom": 0,
14
+ "viewport_rows": 40
15
+ },
16
+ "tab_id": "w2:t1",
17
+ "terminal_id": "term_65a5cfcc8cd9e2",
18
+ "workspace_id": "w2"
19
+ },
20
+ "tab": {
21
+ "agent_status": "unknown",
22
+ "focused": false,
23
+ "label": "1",
24
+ "number": 1,
25
+ "pane_count": 1,
26
+ "tab_id": "w2:t1",
27
+ "workspace_id": "w2"
28
+ },
29
+ "type": "worktree_created",
30
+ "workspace": {
31
+ "active_tab_id": "w2:t1",
32
+ "agent_status": "unknown",
33
+ "focused": false,
34
+ "label": "PAY-101",
35
+ "number": 2,
36
+ "pane_count": 1,
37
+ "tab_count": 1,
38
+ "workspace_id": "w2",
39
+ "worktree": {
40
+ "checkout_path": "/work/worktrees/payments/pay-101",
41
+ "is_linked_worktree": true,
42
+ "repo_key": "/work/payments/.git",
43
+ "repo_name": "repo",
44
+ "repo_root": "/work/payments"
45
+ }
46
+ },
47
+ "worktree": {
48
+ "branch": "PAY-101",
49
+ "is_bare": false,
50
+ "is_detached": false,
51
+ "is_linked_worktree": true,
52
+ "is_prunable": false,
53
+ "label": "repo",
54
+ "open_workspace_id": "w2",
55
+ "path": "/work/worktrees/payments/pay-101"
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "cli:worktree:list",
3
+ "result": {
4
+ "source": {
5
+ "repo_key": "/work/payments/.git",
6
+ "repo_name": "repo",
7
+ "repo_root": "/work/payments",
8
+ "source_checkout_path": "/work/payments",
9
+ "source_workspace_id": "w1"
10
+ },
11
+ "type": "worktree_list",
12
+ "worktrees": [
13
+ {
14
+ "branch": "main",
15
+ "is_bare": false,
16
+ "is_detached": false,
17
+ "is_linked_worktree": false,
18
+ "is_prunable": false,
19
+ "label": "repo",
20
+ "open_workspace_id": "w1",
21
+ "path": "/work/payments"
22
+ },
23
+ {
24
+ "branch": "PAY-101",
25
+ "is_bare": false,
26
+ "is_detached": false,
27
+ "is_linked_worktree": true,
28
+ "is_prunable": false,
29
+ "label": "repo",
30
+ "open_workspace_id": "w2",
31
+ "path": "/work/worktrees/payments/pay-101"
32
+ }
33
+ ]
34
+ }
35
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "id": "cli:worktree:open",
3
+ "result": {
4
+ "already_open": true,
5
+ "root_pane": {
6
+ "agent_status": "unknown",
7
+ "cwd": "/work/worktrees/payments/pay-101",
8
+ "focused": false,
9
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
10
+ "pane_id": "w2:p1",
11
+ "revision": 0,
12
+ "scroll": {
13
+ "max_offset_from_bottom": 0,
14
+ "offset_from_bottom": 0,
15
+ "viewport_rows": 39
16
+ },
17
+ "tab_id": "w2:t1",
18
+ "terminal_id": "term_65a5cfcc8cd9e2",
19
+ "workspace_id": "w2"
20
+ },
21
+ "tab": {
22
+ "agent_status": "unknown",
23
+ "focused": false,
24
+ "label": "1",
25
+ "number": 1,
26
+ "pane_count": 1,
27
+ "tab_id": "w2:t1",
28
+ "workspace_id": "w2"
29
+ },
30
+ "type": "worktree_opened",
31
+ "workspace": {
32
+ "active_tab_id": "w2:t1",
33
+ "agent_status": "unknown",
34
+ "focused": false,
35
+ "label": "PAY-101",
36
+ "number": 2,
37
+ "pane_count": 1,
38
+ "tab_count": 1,
39
+ "workspace_id": "w2",
40
+ "worktree": {
41
+ "checkout_path": "/work/worktrees/payments/pay-101",
42
+ "is_linked_worktree": true,
43
+ "repo_key": "/work/payments/.git",
44
+ "repo_name": "repo",
45
+ "repo_root": "/work/payments"
46
+ }
47
+ },
48
+ "worktree": {
49
+ "branch": "PAY-101",
50
+ "is_bare": false,
51
+ "is_detached": false,
52
+ "is_linked_worktree": true,
53
+ "is_prunable": false,
54
+ "label": "repo",
55
+ "open_workspace_id": "w2",
56
+ "path": "/work/worktrees/payments/pay-101"
57
+ }
58
+ }
59
+ }
@@ -328,9 +328,6 @@ func (s *system) CompileFilter(workflowTaskConfig config.RawValues) (func(task.T
328
328
  return nil, err
329
329
  }
330
330
  f := cfg.Filters
331
- if !hasAssigneeFilter(merged) && cfg.Assignee != "" {
332
- f.Assignees = []string{cfg.Assignee}
333
- }
334
331
  return func(ticket task.Ticket) bool {
335
332
  if len(f.ParentStatuses) > 0 && !containsExact(f.ParentStatuses, stringField(ticket.Fields, "status")) {
336
333
  return false
@@ -353,19 +350,6 @@ func (s *system) CompileFilter(workflowTaskConfig config.RawValues) (func(task.T
353
350
  }, nil
354
351
  }
355
352
 
356
- func hasAssigneeFilter(raw config.RawValues) bool {
357
- switch filters := raw["filters"].(type) {
358
- case map[string]any:
359
- _, ok := filters["assignees"]
360
- return ok
361
- case config.RawValues:
362
- _, ok := filters["assignees"]
363
- return ok
364
- default:
365
- return false
366
- }
367
- }
368
-
369
353
  func containsExact(values []string, want string) bool {
370
354
  for _, value := range values {
371
355
  if value == want {
@@ -50,7 +50,7 @@ func TestBeadsConfigRejectsJiraOnlyFields(t *testing.T) {
50
50
  }
51
51
  }
52
52
 
53
- func TestBeadsCompileFilterUsesInheritedTopLevelAssignee(t *testing.T) {
53
+ func TestBeadsCompileFilterDoesNotUseTopLevelAssignee(t *testing.T) {
54
54
  sys := &system{base: config.Merge(DefaultConfig(), config.RawValues{
55
55
  "assignee": "Repo.Bot@Example.com",
56
56
  })}
@@ -58,15 +58,14 @@ func TestBeadsCompileFilterUsesInheritedTopLevelAssignee(t *testing.T) {
58
58
  if err != nil {
59
59
  t.Fatalf("CompileFilter failed: %v", err)
60
60
  }
61
- if !match(task.Ticket{Fields: map[string]any{"assignee": "repo.bot@example.COM"}}) {
62
- t.Fatal("top-level assignee did not become the default filter")
63
- }
64
- if match(task.Ticket{Fields: map[string]any{"assignee": "other@example.com"}}) {
65
- t.Fatal("ticket assigned to another user matched the default assignee filter")
61
+ for _, assignee := range []string{"repo.bot@example.COM", "other@example.com"} {
62
+ if !match(task.Ticket{Fields: map[string]any{"assignee": assignee}}) {
63
+ t.Fatalf("assignee %q was filtered without filters.assignees", assignee)
64
+ }
66
65
  }
67
66
  }
68
67
 
69
- func TestBeadsExplicitAssigneeFilterOverridesInheritedDefault(t *testing.T) {
68
+ func TestBeadsExplicitAssigneeFilterIsUsed(t *testing.T) {
70
69
  sys := &system{base: config.Merge(DefaultConfig(), config.RawValues{
71
70
  "assignee": "repo@example.com",
72
71
  })}
@@ -84,7 +83,7 @@ func TestBeadsExplicitAssigneeFilterOverridesInheritedDefault(t *testing.T) {
84
83
  }
85
84
  for _, assignee := range []string{"repo@example.com", "workflow@example.com"} {
86
85
  if match(task.Ticket{Fields: map[string]any{"assignee": assignee}}) {
87
- t.Fatalf("inherited assignee %q overrode explicit assignee filter", assignee)
86
+ t.Fatalf("explicit assignee filter accepted %q", assignee)
88
87
  }
89
88
  }
90
89
  }