v0.42.0 82578de

resident_subagent_tools_test.go RawHistoryFolder

1package modes
2
3import (
4	"context"
5	"testing"
6
7	"github.com/bnema/zut/packages/agent/subagents"
8	"github.com/bnema/zut/packages/agent/tools"
9	"github.com/bnema/zut/packages/core"
10)
11
12// TestApplyAutoSubagentsToolReplacesOneFacadeEntry covers the interactive
13// refresh path: the previously installed facade is replaced by exactly one
14// entry whose non-nil fields are the currently granted actions, and unrelated
15// tools survive.
16func TestApplyAutoSubagentsToolReplacesOneFacadeEntry(t *testing.T) {
17	manager := subagents.NewResidentManager(t.TempDir(), nil)
18	t.Cleanup(func() { _ = manager.Close(context.Background()) })
19	preSeeded := &tools.SubagentTool{}
20	agent := core.NewAgent(nil, "model", "", core.Registry{
21		"read": &tools.GrepTool{},
22		// A previously installed facade, as a prior refresh would have left it.
23		"subagent": preSeeded,
24	})
25	allowed, resumeAllowed := true, true
26	interactive := NewInteractive(InteractiveConfig{
27		Agent:                          agent,
28		ResidentManager:                manager,
29		AutoSubagentsToolAllowed:       &allowed,
30		AutoSubagentsStatusToolAllowed: &allowed,
31		AutoSubagentsStopToolAllowed:   &allowed,
32		AutoSubagentsResumeToolAllowed: &resumeAllowed,
33	})
34
35	interactive.applyAutoSubagentsTool()
36
37	assertFacade := func(wantResume bool) {
38		t.Helper()
39		snapshot := agent.ToolsSnapshot()
40		if _, ok := snapshot["read"]; !ok {
41			t.Fatal("interactive refresh dropped an unrelated tool")
42		}
43		found := 0
44		for name := range snapshot {
45			switch name {
46			case tools.SubagentToolName:
47				found++
48			case "subagent_spawn", "subagent_status", "subagent_stop", "subagent_resume":
49				t.Fatalf("legacy tool key %q is present", name)
50			}
51		}
52		if found != 1 {
53			t.Fatalf("registry has %d %q entries, want 1", found, tools.SubagentToolName)
54		}
55		facade, ok := snapshot[tools.SubagentToolName].(*tools.SubagentTool)
56		if !ok {
57			t.Fatalf("registry entry %q = %T, want *tools.SubagentTool", tools.SubagentToolName, snapshot[tools.SubagentToolName])
58		}
59		if facade == preSeeded {
60			t.Fatal("interactive refresh reused the pre-seeded facade instead of replacing it")
61		}
62		if facade.Spawn == nil || facade.Status == nil || facade.Stop == nil {
63			t.Fatalf("facade actions = spawn:%v status:%v stop:%v", facade.Spawn != nil, facade.Status != nil, facade.Stop != nil)
64		}
65		if (facade.Resume != nil) != wantResume {
66			t.Fatalf("facade resume = %v, want %v", facade.Resume != nil, wantResume)
67		}
68	}
69
70	assertFacade(true)
71
72	// A later policy change must replace the installed facade, not merge or
73	// duplicate it.
74	resumeAllowed = false
75	interactive.applyAutoSubagentsTool()
76	assertFacade(false)
77}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 477

↑↓ moveenter openesc close