broker_offline_client_test_helpers_test.go RawHistoryFolder

1package app
2
3import (
4	"context"
5	"errors"
6	"io"
7	"log/slog"
8
9	"github.com/bnema/vev/internal/adapters/brokeripc"
10	"github.com/bnema/vev/internal/adapters/clock"
11	"github.com/bnema/vev/internal/adapters/uiterm"
12	"github.com/bnema/vev/internal/ports"
13	"github.com/bnema/vev/internal/usecase/client"
14)
15
16// runOfflineClient is the sandbox terminal harness over the shared broker
17// client composition. It supplies the real broker IPC connector for one
18// offline root and the no-argument ephemeral local creation, then delegates the
19// whole run to runBrokerClient: the sandbox adds no picker, supervisor, dialer,
20// or stream of its own.
21func runOfflineClient(ctx context.Context, socket string, terminal ports.Terminal, ui *client.UI, log *slog.Logger, onState func(client.State), onFailure func(error)) error {
22	if terminal == nil {
23		return errors.New("offline client requires a terminal")
24	}
25	if log != nil {
26		log.Debug("broker_offline_client", "socket", socket)
27	}
28	return runBrokerClient(ctx, brokerClientConfig{
29		Connector: brokeripc.NewConnector(socket, brokeripc.Config{}).Navigator(),
30		Terminal:  terminal,
31		UI:        ui,
32		// No-argument composition creates one ephemeral local session through
33		// the closed initial-navigation union; there is no special attach path.
34		InitialNavigation:     localEphemeralNavigation(),
35		AttachmentEnvironment: terminalAttachmentEnvironment(),
36		SessionEnvironment:    client.SessionEnvironment{Provenance: client.SessionEnvironmentLocalCLI},
37		OnState:               onState,
38		OnFailure:             onFailure,
39	})
40}
41
42// offlineUIDriverHarness is the sandbox harness input: one explicitly supplied
43// offline broker socket, the virtual terminal and UI service built over it, the
44// one-shot navigation the harness was asked to perform, and the stream the JSONL
45// protocol is served on. The CLI's `--picker` selects the zero picker intent; the
46// default is the same no-argument local ephemeral creation every frontend uses.
47type offlineUIDriverHarness struct {
48	socket     string
49	terminal   *uiterm.Terminal
50	ui         *client.UI
51	log        *slog.Logger
52	navigation client.InitialNavigation
53	resolver   client.InitialNavigationResolver
54	stream     io.ReadWriteCloser
55}
56
57// runOfflineUIDriverClient composes the sandbox UI-driver harness over the same
58// runUIDriverClient path production uses. Its connector is the real broker IPC
59// connector of one explicitly supplied offline root: the sandbox adds no
60// production fallback, starts no broker of its own, and never reaches the
61// production XDG runtime or state. No session, endpoint, or process is
62// provisioned here: the harness reaches sessions only through the broker of its
63// own root, exactly like the production driver.
64func runOfflineUIDriverClient(ctx context.Context, harness offlineUIDriverHarness) error {
65	if harness.log != nil {
66		harness.log.Debug("broker_offline_ui_driver", "socket", harness.socket)
67	}
68	return runUIDriverClient(ctx, brokerClientConfig{
69		Connector:                brokeripc.NewConnector(harness.socket, brokeripc.Config{}).Navigator(),
70		Terminal:                 harness.terminal,
71		Clock:                    clock.New(),
72		UI:                       harness.ui,
73		InitialNavigation:        harness.navigation,
74		ResolveInitialNavigation: harness.resolver,
75		AttachmentEnvironment:    terminalAttachmentEnvironment(),
76		SessionEnvironment:       client.SessionEnvironment{Provenance: client.SessionEnvironmentLocalCLI},
77	}, harness.stream)
78}

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 12

Tags 11

↑↓ moveenter openesc close