relay-flow 0.3.0-alpha → 0.3.2-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.
package/README.md CHANGED
@@ -24,13 +24,13 @@ same `relay-flow-plugin` package with host-specific entrypoints.
24
24
  **OpenCode**
25
25
 
26
26
  ```sh
27
- opencode plugin relay-flow-plugin@0.3.0-alpha
27
+ opencode plugin relay-flow-plugin@0.3.2-alpha
28
28
  ```
29
29
 
30
30
  **Pi**
31
31
 
32
32
  ```sh
33
- pi install npm:relay-flow-plugin@0.3.0-alpha
33
+ pi install npm:relay-flow-plugin@0.3.2-alpha
34
34
  ```
35
35
 
36
36
  Pi loads the package's `pi.ts` extension from its manifest. Do not add
@@ -160,7 +160,7 @@ OpenCode plugin configuration uses both entrypoints. The server entrypoint is li
160
160
  ```json
161
161
  {
162
162
  "$schema": "https://opencode.ai/config.json",
163
- "plugin": ["relay-flow-plugin@0.3.0-alpha"]
163
+ "plugin": ["relay-flow-plugin@0.3.2-alpha"]
164
164
  }
165
165
  ```
166
166
 
@@ -169,7 +169,7 @@ The native HITL approval entrypoint is listed in `.opencode/tui.json`:
169
169
  ```json
170
170
  {
171
171
  "$schema": "https://opencode.ai/tui.json",
172
- "plugin": ["relay-flow-plugin@0.3.0-alpha"]
172
+ "plugin": ["relay-flow-plugin@0.3.2-alpha"]
173
173
  }
174
174
  ```
175
175
 
@@ -185,7 +185,7 @@ Pi plugin: install the same published package manually in Pi's global package
185
185
  settings before starting a Pi harness session:
186
186
 
187
187
  ```sh
188
- pi install npm:relay-flow-plugin@0.3.0-alpha
188
+ pi install npm:relay-flow-plugin@0.3.2-alpha
189
189
  ```
190
190
 
191
191
  Relay-flow does not install or configure the package automatically. Pi resolves
@@ -853,8 +853,8 @@ func cmdServe(p paths.Paths, args []string) int {
853
853
  }
854
854
 
855
855
  var (
856
- backgroundServeStartupTimeout = 10 * time.Second
857
- backgroundServePollInterval = 50 * time.Millisecond
856
+ backgroundServeStartupTimeout = 5 * time.Minute
857
+ backgroundServePollInterval = 250 * time.Millisecond
858
858
  )
859
859
 
860
860
  func startBackgroundServe(p paths.Paths, recover, debug bool) error {
@@ -88,7 +88,7 @@ func init() {
88
88
  type Harness struct {
89
89
  templates Config
90
90
  // listAgents is the test seam; nil → real `opencode agent list`.
91
- listAgents func(ctx context.Context) ([]string, error)
91
+ listAgents func(ctx context.Context, repoPath string) ([]string, error)
92
92
  }
93
93
 
94
94
  // New returns the production Harness.
@@ -110,7 +110,7 @@ func (h *Harness) SetupRepo(_ context.Context, repoPath string) error {
110
110
  // ValidateAgent reports whether name is a known OpenCode agent for the
111
111
  // repo, per `opencode agent list` (agent names are the unindented first
112
112
  // tokens).
113
- func (h *Harness) ValidateAgent(ctx context.Context, _ string, agent string) error {
113
+ func (h *Harness) ValidateAgent(ctx context.Context, repoPath, agent string) error {
114
114
  if agent == "" {
115
115
  return fmt.Errorf("opencode: agent name is empty")
116
116
  }
@@ -118,7 +118,7 @@ func (h *Harness) ValidateAgent(ctx context.Context, _ string, agent string) err
118
118
  if list == nil {
119
119
  list = listAgents
120
120
  }
121
- names, err := list(ctx)
121
+ names, err := list(ctx, repoPath)
122
122
  if err != nil {
123
123
  return err
124
124
  }
@@ -236,8 +236,10 @@ func relayFlowHome() (string, error) {
236
236
 
237
237
  // listAgents runs `opencode agent list` and returns the agent names
238
238
  // (the unindented lines' first tokens).
239
- func listAgents(ctx context.Context) ([]string, error) {
240
- out, err := exec.CommandContext(ctx, "opencode", "agent", "list").Output()
239
+ func listAgents(ctx context.Context, repoPath string) ([]string, error) {
240
+ cmd := exec.CommandContext(ctx, "opencode", "agent", "list")
241
+ cmd.Dir = repoPath
242
+ out, err := cmd.Output()
241
243
  if err != nil {
242
244
  return nil, fmt.Errorf("opencode agent list: %w", err)
243
245
  }
@@ -14,7 +14,7 @@ import (
14
14
  "github.com/rajpopat27/relay-flow/internal/workflow"
15
15
  )
16
16
 
17
- const configuredPlugin = "relay-flow-plugin@0.3.0-alpha"
17
+ const configuredPlugin = "relay-flow-plugin@0.3.2-alpha"
18
18
 
19
19
  func TestBuildCommandArgv(t *testing.T) {
20
20
  t.Setenv("RELAY_FLOW_HOME", "/var/lib/relay-flow-test")
@@ -10,7 +10,7 @@ import (
10
10
  "github.com/rajpopat27/relay-flow/internal/config"
11
11
  )
12
12
 
13
- const relayFlowPlugin = "relay-flow-plugin@0.3.0-alpha"
13
+ const relayFlowPlugin = "relay-flow-plugin@0.3.2-alpha"
14
14
 
15
15
  type jsoncToken struct {
16
16
  kind byte
@@ -0,0 +1,106 @@
1
+ package opencode
2
+
3
+ import (
4
+ "context"
5
+ "os"
6
+ "path/filepath"
7
+ "runtime"
8
+ "strings"
9
+ "testing"
10
+ )
11
+
12
+ func TestValidateAgentPassesRepositoryToListAgentsSeam(t *testing.T) {
13
+ repoPath := t.TempDir()
14
+ var gotRepoPath string
15
+ h := New()
16
+ h.listAgents = func(_ context.Context, path string) ([]string, error) {
17
+ gotRepoPath = path
18
+ return []string{"build"}, nil
19
+ }
20
+
21
+ if err := h.ValidateAgent(context.Background(), repoPath, "build"); err != nil {
22
+ t.Fatalf("ValidateAgent: %v", err)
23
+ }
24
+ if gotRepoPath != repoPath {
25
+ t.Fatalf("listAgents repoPath = %q, want %q", gotRepoPath, repoPath)
26
+ }
27
+ }
28
+
29
+ func TestValidateAgentUsesRepositoryWorkingDirectory(t *testing.T) {
30
+ if runtime.GOOS == "windows" {
31
+ t.Skip("fake opencode uses a POSIX shell")
32
+ }
33
+
34
+ repoA := t.TempDir()
35
+ repoB := t.TempDir()
36
+ fakeDir := t.TempDir()
37
+ fake := filepath.Join(fakeDir, "opencode")
38
+ script := `#!/bin/sh
39
+ set -eu
40
+ [ "$#" -eq 2 ] && [ "$1" = "agent" ] && [ "$2" = "list" ] || exit 2
41
+ actual=$(pwd)
42
+ case "$actual" in
43
+ "$OPENCODE_REPO_A")
44
+ printf 'repo-a-agent details\n'
45
+ ;;
46
+ "$OPENCODE_REPO_B")
47
+ printf 'repo-b-agent details\n'
48
+ ;;
49
+ *)
50
+ printf 'unexpected working directory: %s\n' "$actual" >&2
51
+ exit 3
52
+ ;;
53
+ esac
54
+ printf ' ignored-indented\n'
55
+ printf '[ignored-json]\n'
56
+ printf '{"ignored":true}\n'
57
+ `
58
+ if err := os.WriteFile(fake, []byte(script), 0o700); err != nil {
59
+ t.Fatal(err)
60
+ }
61
+ t.Setenv("PATH", fakeDir)
62
+ t.Setenv("OPENCODE_REPO_A", repoA)
63
+ t.Setenv("OPENCODE_REPO_B", repoB)
64
+
65
+ h := New()
66
+ if err := h.ValidateAgent(context.Background(), repoA, "repo-a-agent"); err != nil {
67
+ t.Fatalf("agent from repository A rejected: %v", err)
68
+ }
69
+ if err := h.ValidateAgent(context.Background(), repoB, "repo-b-agent"); err != nil {
70
+ t.Fatalf("agent from repository B rejected: %v", err)
71
+ }
72
+ if err := h.ValidateAgent(context.Background(), repoA, "repo-b-agent"); err == nil {
73
+ t.Fatal("repository B agent accepted while validating repository A")
74
+ }
75
+ if err := h.ValidateAgent(context.Background(), repoB, "repo-a-agent"); err == nil {
76
+ t.Fatal("repository A agent accepted while validating repository B")
77
+ }
78
+ }
79
+
80
+ func TestValidateAgentPropagatesListCommandFailure(t *testing.T) {
81
+ if runtime.GOOS == "windows" {
82
+ t.Skip("fake opencode uses a POSIX shell")
83
+ }
84
+
85
+ fakeDir := t.TempDir()
86
+ fake := filepath.Join(fakeDir, "opencode")
87
+ script := `#!/bin/sh
88
+ set -eu
89
+ [ "$#" -eq 2 ] && [ "$1" = "agent" ] && [ "$2" = "list" ] || exit 2
90
+ printf 'agent list failed\n' >&2
91
+ exit 17
92
+ `
93
+ if err := os.WriteFile(fake, []byte(script), 0o700); err != nil {
94
+ t.Fatal(err)
95
+ }
96
+ t.Setenv("PATH", fakeDir)
97
+
98
+ h := New()
99
+ err := h.ValidateAgent(context.Background(), t.TempDir(), "build")
100
+ if err == nil {
101
+ t.Fatal("ValidateAgent succeeded after opencode agent list failed")
102
+ }
103
+ if !strings.Contains(err.Error(), "opencode agent list") {
104
+ t.Fatalf("error = %q, want opencode agent list context", err)
105
+ }
106
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relay-flow",
3
- "version": "0.3.0-alpha",
3
+ "version": "0.3.2-alpha",
4
4
  "description": "Graph-based agent workflow engine — tracker-agnostic, pluggable runners",
5
5
  "bin": {
6
6
  "relay-flow": "./bin/relay-flow.js",