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,281 @@
1
+ package herdrcli
2
+
3
+ import "context"
4
+
5
+ type workspaceResponse struct {
6
+ ID string `json:"workspace_id"`
7
+ Label string `json:"label"`
8
+ Worktree *worktreeRefwithID `json:"worktree"`
9
+ }
10
+
11
+ type worktreeRefwithID struct {
12
+ CheckoutPath string `json:"checkout_path"`
13
+ RepoName string `json:"repo_name"`
14
+ RepoRoot string `json:"repo_root"`
15
+ IsLinked bool `json:"is_linked_worktree"`
16
+ }
17
+
18
+ type worktreeResponse struct {
19
+ Path string `json:"path"`
20
+ Branch string `json:"branch"`
21
+ IsLinked bool `json:"is_linked_worktree"`
22
+ OpenWorkspaceID string `json:"open_workspace_id"`
23
+ }
24
+
25
+ type worktreeSourceResponse struct {
26
+ RepoName string `json:"repo_name"`
27
+ RepoRoot string `json:"repo_root"`
28
+ SourceCheckoutPath string `json:"source_checkout_path"`
29
+ }
30
+
31
+ type tabResponse struct {
32
+ ID string `json:"tab_id"`
33
+ WorkspaceID string `json:"workspace_id"`
34
+ Label string `json:"label"`
35
+ }
36
+
37
+ type paneResponse struct {
38
+ ID string `json:"pane_id"`
39
+ TerminalID string `json:"terminal_id"`
40
+ WorkspaceID string `json:"workspace_id"`
41
+ TabID string `json:"tab_id"`
42
+ Label string `json:"label"`
43
+ CWD string `json:"cwd"`
44
+ }
45
+
46
+ type processInfoResponse struct {
47
+ PaneID string `json:"pane_id"`
48
+ ShellPID *uint32 `json:"shell_pid"`
49
+ ForegroundProcesses []foregroundProcessResponse `json:"foreground_processes"`
50
+ }
51
+
52
+ type foregroundProcessResponse struct {
53
+ PID uint32 `json:"pid"`
54
+ Name string `json:"name"`
55
+ }
56
+
57
+ func (c *CLI) Snapshot(ctx context.Context) (Snapshot, error) {
58
+ var response struct {
59
+ Snapshot struct {
60
+ Workspaces []workspaceResponse `json:"workspaces"`
61
+ Tabs []tabResponse `json:"tabs"`
62
+ Panes []paneResponse `json:"panes"`
63
+ } `json:"snapshot"`
64
+ }
65
+ if err := c.runJSON(ctx, "api snapshot", &response, "api", "snapshot"); err != nil {
66
+ return Snapshot{}, err
67
+ }
68
+ return Snapshot{
69
+ Workspaces: convertWorkspaces(response.Snapshot.Workspaces),
70
+ Tabs: convertTabs(response.Snapshot.Tabs),
71
+ Panes: convertPanes(response.Snapshot.Panes),
72
+ }, nil
73
+ }
74
+
75
+ func (c *CLI) WorktreeList(ctx context.Context, repoPath string) (WorktreeListing, error) {
76
+ var response struct {
77
+ Source worktreeSourceResponse `json:"source"`
78
+ Worktrees []worktreeResponse `json:"worktrees"`
79
+ }
80
+ if err := c.runJSON(ctx, "worktree list", &response, "worktree", "list", "--cwd", repoPath); err != nil {
81
+ return WorktreeListing{}, err
82
+ }
83
+ return WorktreeListing{
84
+ Source: WorktreeSource{
85
+ RepoName: response.Source.RepoName,
86
+ RepoRoot: response.Source.RepoRoot,
87
+ SourceCheckoutPath: response.Source.SourceCheckoutPath,
88
+ },
89
+ Worktrees: convertWorktrees(response.Worktrees),
90
+ }, nil
91
+ }
92
+
93
+ // WorktreeCreate creates the ticket branch checkout and opens it as its own
94
+ // workspace. Herdr reuses an existing branch, so base applies only when the
95
+ // branch does not exist yet and prior agent commits are never discarded.
96
+ func (c *CLI) WorktreeCreate(ctx context.Context, repoPath, branch, base, label string) (Workspace, error) {
97
+ args := []string{
98
+ "worktree", "create",
99
+ "--cwd", repoPath,
100
+ "--branch", branch,
101
+ "--base", base,
102
+ "--label", label,
103
+ "--no-focus",
104
+ }
105
+ return c.workspaceFromWorktree(ctx, "worktree create", args)
106
+ }
107
+
108
+ // WorktreeOpen opens the existing ticket checkout, reusing the workspace when
109
+ // it is already open. It returns ErrWorktreeNotFound when no checkout exists
110
+ // for the branch.
111
+ func (c *CLI) WorktreeOpen(ctx context.Context, repoPath, branch, label string) (Workspace, error) {
112
+ args := []string{
113
+ "worktree", "open",
114
+ "--cwd", repoPath,
115
+ "--branch", branch,
116
+ "--label", label,
117
+ "--no-focus",
118
+ }
119
+ return c.workspaceFromWorktree(ctx, "worktree open", args)
120
+ }
121
+
122
+ func (c *CLI) workspaceFromWorktree(ctx context.Context, operation string, args []string) (Workspace, error) {
123
+ var response struct {
124
+ Workspace workspaceResponse `json:"workspace"`
125
+ }
126
+ if err := c.runJSON(ctx, operation, &response, args...); err != nil {
127
+ return Workspace{}, err
128
+ }
129
+ return convertWorkspace(response.Workspace), nil
130
+ }
131
+
132
+ func (c *CLI) CreateTab(ctx context.Context, workspaceID, cwd, label string) (Tab, Pane, error) {
133
+ args := []string{
134
+ "tab", "create",
135
+ "--workspace", workspaceID,
136
+ "--cwd", cwd,
137
+ "--label", label,
138
+ "--no-focus",
139
+ }
140
+ var response struct {
141
+ Tab tabResponse `json:"tab"`
142
+ RootPane paneResponse `json:"root_pane"`
143
+ }
144
+ if err := c.runJSON(ctx, "tab create", &response, args...); err != nil {
145
+ return Tab{}, Pane{}, err
146
+ }
147
+ return convertTab(response.Tab), convertPane(response.RootPane), nil
148
+ }
149
+
150
+ func (c *CLI) ListTabs(ctx context.Context, workspaceID string) ([]Tab, error) {
151
+ var response struct {
152
+ Tabs []tabResponse `json:"tabs"`
153
+ }
154
+ if err := c.runJSON(ctx, "tab list", &response, "tab", "list", "--workspace", workspaceID); err != nil {
155
+ return nil, err
156
+ }
157
+ return convertTabs(response.Tabs), nil
158
+ }
159
+
160
+ func (c *CLI) ListPanes(ctx context.Context, workspaceID string) ([]Pane, error) {
161
+ var response struct {
162
+ Panes []paneResponse `json:"panes"`
163
+ }
164
+ if err := c.runJSON(ctx, "pane list", &response, "pane", "list", "--workspace", workspaceID); err != nil {
165
+ return nil, err
166
+ }
167
+ return convertPanes(response.Panes), nil
168
+ }
169
+
170
+ func (c *CLI) GetPane(ctx context.Context, paneID string) (Pane, error) {
171
+ var response struct {
172
+ Pane paneResponse `json:"pane"`
173
+ }
174
+ if err := c.runJSON(ctx, "pane get", &response, "pane", "get", paneID); err != nil {
175
+ return Pane{}, err
176
+ }
177
+ return convertPane(response.Pane), nil
178
+ }
179
+
180
+ func (c *CLI) ProcessInfo(ctx context.Context, paneID string) (ProcessInfo, error) {
181
+ var response struct {
182
+ ProcessInfo processInfoResponse `json:"process_info"`
183
+ }
184
+ if err := c.runJSON(ctx, "pane process-info", &response, "pane", "process-info", "--pane", paneID); err != nil {
185
+ return ProcessInfo{}, err
186
+ }
187
+ return convertProcessInfo(response.ProcessInfo), nil
188
+ }
189
+
190
+ func (c *CLI) RenamePane(ctx context.Context, paneID, label string) error {
191
+ return c.runCommand(ctx, "pane rename", "pane", "rename", paneID, label)
192
+ }
193
+
194
+ func (c *CLI) RunPane(ctx context.Context, paneID, command string) error {
195
+ return c.runCommand(ctx, "pane run", "pane", "run", paneID, command)
196
+ }
197
+
198
+ func (c *CLI) ClosePane(ctx context.Context, paneID string) error {
199
+ return c.runCommand(ctx, "pane close", "pane", "close", paneID)
200
+ }
201
+
202
+ func (c *CLI) CloseWorkspace(ctx context.Context, workspaceID string) error {
203
+ return c.runCommand(ctx, "workspace close", "workspace", "close", workspaceID)
204
+ }
205
+
206
+ func convertWorkspace(value workspaceResponse) Workspace {
207
+ workspace := Workspace{ID: value.ID, Label: value.Label}
208
+ if value.Worktree != nil {
209
+ workspace.Worktree = WorkspaceWorktree{
210
+ CheckoutPath: value.Worktree.CheckoutPath,
211
+ RepoName: value.Worktree.RepoName,
212
+ RepoRoot: value.Worktree.RepoRoot,
213
+ IsLinked: value.Worktree.IsLinked,
214
+ }
215
+ }
216
+ return workspace
217
+ }
218
+
219
+ func convertWorkspaces(values []workspaceResponse) []Workspace {
220
+ out := make([]Workspace, len(values))
221
+ for i, value := range values {
222
+ out[i] = convertWorkspace(value)
223
+ }
224
+ return out
225
+ }
226
+
227
+ func convertWorktrees(values []worktreeResponse) []Worktree {
228
+ out := make([]Worktree, len(values))
229
+ for i, value := range values {
230
+ out[i] = Worktree{
231
+ Path: value.Path,
232
+ Branch: value.Branch,
233
+ IsLinked: value.IsLinked,
234
+ OpenWorkspaceID: value.OpenWorkspaceID,
235
+ }
236
+ }
237
+ return out
238
+ }
239
+
240
+ func convertTab(value tabResponse) Tab {
241
+ return Tab{ID: value.ID, WorkspaceID: value.WorkspaceID, Label: value.Label}
242
+ }
243
+
244
+ func convertTabs(values []tabResponse) []Tab {
245
+ out := make([]Tab, len(values))
246
+ for i, value := range values {
247
+ out[i] = convertTab(value)
248
+ }
249
+ return out
250
+ }
251
+
252
+ func convertPane(value paneResponse) Pane {
253
+ return Pane{
254
+ ID: value.ID,
255
+ TerminalID: value.TerminalID,
256
+ WorkspaceID: value.WorkspaceID,
257
+ TabID: value.TabID,
258
+ Label: value.Label,
259
+ CWD: value.CWD,
260
+ }
261
+ }
262
+
263
+ func convertPanes(values []paneResponse) []Pane {
264
+ out := make([]Pane, len(values))
265
+ for i, value := range values {
266
+ out[i] = convertPane(value)
267
+ }
268
+ return out
269
+ }
270
+
271
+ func convertProcessInfo(value processInfoResponse) ProcessInfo {
272
+ processes := make([]ForegroundProcess, len(value.ForegroundProcesses))
273
+ for i, process := range value.ForegroundProcesses {
274
+ processes[i] = ForegroundProcess{PID: process.PID, Name: process.Name}
275
+ }
276
+ return ProcessInfo{
277
+ PaneID: value.PaneID,
278
+ ShellPID: value.ShellPID,
279
+ ForegroundProcesses: processes,
280
+ }
281
+ }
@@ -0,0 +1,116 @@
1
+ package herdrcli
2
+
3
+ import (
4
+ "bytes"
5
+ "context"
6
+ "encoding/json"
7
+ "fmt"
8
+ "strings"
9
+ )
10
+
11
+ // Observed Herdr transport contract (herdr 0.8.2, protocol 20):
12
+ //
13
+ // success: JSON envelope {"id":...,"result":{...}} on stdout, exit 0.
14
+ // pane run writes nothing on either stream.
15
+ // failure: JSON envelope {"id":...,"error":{"code","message"}} on stderr,
16
+ // exit 1, empty stdout.
17
+ //
18
+ // There is no "ok" field; presence of result/error is the contract.
19
+ type responseEnvelope struct {
20
+ Result json.RawMessage `json:"result"`
21
+ Error *apiError `json:"error"`
22
+ }
23
+
24
+ type apiError struct {
25
+ Code string `json:"code"`
26
+ Message string `json:"message"`
27
+ }
28
+
29
+ func sentinelFor(code string) error {
30
+ switch code {
31
+ case "pane_not_found":
32
+ return ErrPaneNotFound
33
+ case "workspace_not_found":
34
+ return ErrWorkspaceNotFound
35
+ case "worktree_not_found":
36
+ return ErrWorktreeNotFound
37
+ case "not_git_worktree":
38
+ return ErrNotGitWorktree
39
+ default:
40
+ return nil
41
+ }
42
+ }
43
+
44
+ // runJSON executes an operation that returns a result body and unmarshals it
45
+ // into dest. Command arguments can contain prompts, so failures report only
46
+ // the operation name and Herdr's own message.
47
+ func (c *CLI) runJSON(ctx context.Context, operation string, dest any, args ...string) error {
48
+ stdout, stderr, err := c.execute(ctx, args...)
49
+ if apiErr := decodeError(operation, stderr); apiErr != nil {
50
+ return apiErr
51
+ }
52
+ if err != nil {
53
+ return commandError(operation, stderr, err)
54
+ }
55
+ return decodeResult(operation, stdout, dest)
56
+ }
57
+
58
+ // runCommand executes a mutating operation. Herdr returns either an "ok"
59
+ // result body or no body at all; only the error envelope matters.
60
+ func (c *CLI) runCommand(ctx context.Context, operation string, args ...string) error {
61
+ _, stderr, err := c.execute(ctx, args...)
62
+ if apiErr := decodeError(operation, stderr); apiErr != nil {
63
+ return apiErr
64
+ }
65
+ if err != nil {
66
+ return commandError(operation, stderr, err)
67
+ }
68
+ return nil
69
+ }
70
+
71
+ // decodeError converts a Herdr error envelope on stderr into a typed error.
72
+ // Non-JSON stderr is not an error by itself; Herdr also uses stderr for
73
+ // warnings.
74
+ func decodeError(operation string, stderr []byte) error {
75
+ trimmed := bytes.TrimSpace(stderr)
76
+ if len(trimmed) == 0 || trimmed[0] != '{' {
77
+ return nil
78
+ }
79
+ var envelope responseEnvelope
80
+ if err := json.Unmarshal(trimmed, &envelope); err != nil || envelope.Error == nil {
81
+ return nil
82
+ }
83
+ message := envelope.Error.Message
84
+ if message == "" {
85
+ message = envelope.Error.Code
86
+ }
87
+ if sentinel := sentinelFor(envelope.Error.Code); sentinel != nil {
88
+ return fmt.Errorf("herdr %s: %s: %w", operation, message, sentinel)
89
+ }
90
+ return fmt.Errorf("herdr %s: %s (%s)", operation, message, envelope.Error.Code)
91
+ }
92
+
93
+ func decodeResult(operation string, stdout []byte, dest any) error {
94
+ if dest == nil {
95
+ return nil
96
+ }
97
+ var envelope responseEnvelope
98
+ if err := json.Unmarshal(stdout, &envelope); err != nil {
99
+ return fmt.Errorf("herdr %s: malformed JSON response: %w", operation, err)
100
+ }
101
+ if len(bytes.TrimSpace(envelope.Result)) == 0 {
102
+ return fmt.Errorf("herdr %s: response missing result", operation)
103
+ }
104
+ if err := json.Unmarshal(envelope.Result, dest); err != nil {
105
+ return fmt.Errorf("herdr %s: malformed result: %w", operation, err)
106
+ }
107
+ return nil
108
+ }
109
+
110
+ func commandError(operation string, stderr []byte, commandErr error) error {
111
+ message := strings.TrimSpace(string(stderr))
112
+ if message == "" {
113
+ return fmt.Errorf("herdr %s: command failed: %w", operation, commandErr)
114
+ }
115
+ return fmt.Errorf("herdr %s: command failed: %w: %s", operation, commandErr, message)
116
+ }
@@ -0,0 +1 @@
1
+ {"id":"cli:pane:list","result":{"panes":[],"type":"pane_list"}}
@@ -0,0 +1 @@
1
+ {"id":"cli:tab:list","result":{"tabs":[],"type":"tab_list"}}
@@ -0,0 +1 @@
1
+ {"error":{"code":"not_git_worktree","message":"Herdr worktree actions require a path inside a Git work tree"},"id":"cli:worktree:list"}
@@ -0,0 +1 @@
1
+ {"error":{"code":"pane_not_found","message":"pane w9:p9 not found"},"id":"cli:pane:get"}
@@ -0,0 +1 @@
1
+ {"error":{"code":"workspace_not_found","message":"workspace w9 not found"},"id":"cli:tab:list"}
@@ -0,0 +1 @@
1
+ {"error":{"code":"worktree_not_found","message":"worktree branch not found"},"id":"cli:worktree:open"}
@@ -0,0 +1 @@
1
+ {"id":"cli:pane:get","result":{"pane":
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "cli:pane:close",
3
+ "result": {
4
+ "type": "ok"
5
+ }
6
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "id": "cli:pane:get",
3
+ "result": {
4
+ "pane": {
5
+ "agent_status": "unknown",
6
+ "cwd": "/work/worktrees/payments/pay-101",
7
+ "focused": false,
8
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
9
+ "label": "PAY-101:coding",
10
+ "pane_id": "w2:p2",
11
+ "revision": 2,
12
+ "scroll": {
13
+ "max_offset_from_bottom": 0,
14
+ "offset_from_bottom": 0,
15
+ "viewport_rows": 39
16
+ },
17
+ "tab_id": "w2:t2",
18
+ "terminal_id": "term_65a5cfcc913e03",
19
+ "terminal_title": "sleep 300",
20
+ "terminal_title_stripped": "sleep 300",
21
+ "workspace_id": "w2"
22
+ },
23
+ "type": "pane_info"
24
+ }
25
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "id": "cli:pane:list",
3
+ "result": {
4
+ "panes": [
5
+ {
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": 1,
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
+ "terminal_title": "relay@relay-host:~/.herdr/worktrees/repo/pay-101",
20
+ "terminal_title_stripped": "relay@relay-host:~/.herdr/worktrees/repo/pay-101",
21
+ "workspace_id": "w2"
22
+ },
23
+ {
24
+ "agent_status": "unknown",
25
+ "cwd": "/work/worktrees/payments/pay-101",
26
+ "focused": false,
27
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
28
+ "label": "PAY-101:coding",
29
+ "pane_id": "w2:p2",
30
+ "revision": 2,
31
+ "scroll": {
32
+ "max_offset_from_bottom": 0,
33
+ "offset_from_bottom": 0,
34
+ "viewport_rows": 39
35
+ },
36
+ "tab_id": "w2:t2",
37
+ "terminal_id": "term_65a5cfcc913e03",
38
+ "terminal_title": "sleep 300",
39
+ "terminal_title_stripped": "sleep 300",
40
+ "workspace_id": "w2"
41
+ }
42
+ ],
43
+ "type": "pane_list"
44
+ }
45
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "id": "cli:pane:process_info",
3
+ "result": {
4
+ "process_info": {
5
+ "foreground_process_group_id": 466928,
6
+ "foreground_processes": [
7
+ {
8
+ "argv": [
9
+ "/usr/bin/zsh"
10
+ ],
11
+ "cmdline": "/usr/bin/zsh",
12
+ "cwd": "/work/worktrees/payments/pay-101",
13
+ "name": "zsh",
14
+ "pid": 466928
15
+ }
16
+ ],
17
+ "pane_id": "w2:p3",
18
+ "shell_pid": 466928
19
+ },
20
+ "type": "pane_process_info"
21
+ }
22
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "cli:pane:process_info",
3
+ "result": {
4
+ "process_info": {
5
+ "foreground_process_group_id": 466891,
6
+ "foreground_processes": [
7
+ {
8
+ "argv": [
9
+ "sleep",
10
+ "300"
11
+ ],
12
+ "cmdline": "sleep 300",
13
+ "cwd": "/work/worktrees/payments/pay-101",
14
+ "name": "sleep",
15
+ "pid": 466891
16
+ }
17
+ ],
18
+ "pane_id": "w2:p2",
19
+ "shell_pid": 466344
20
+ },
21
+ "type": "pane_process_info"
22
+ }
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "cli:pane:rename",
3
+ "result": {
4
+ "pane": {
5
+ "agent_status": "unknown",
6
+ "cwd": "/work/worktrees/payments/pay-101",
7
+ "focused": false,
8
+ "foreground_cwd": "/work/worktrees/payments/pay-101",
9
+ "label": "PAY-101:coding",
10
+ "pane_id": "w2:p2",
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:t2",
18
+ "terminal_id": "term_65a5cfcc913e03",
19
+ "workspace_id": "w2"
20
+ },
21
+ "type": "pane_info"
22
+ }
23
+ }