uiserver

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 37 Imported by: 0

Documentation

Overview

Package uiserver hosts the authenticated local application. Providers own their routes; every provider runs inside the same Host, auth and CSRF checks.

Browsers reach the application only under a secret path namespace, /s/<namespace>/, and the session cookie is scoped to that path. Cookies are shared by every port on 127.0.0.1, so a host-wide cookie would also reach other loopback services; a path they cannot guess keeps it from them.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChatHandler

func ChatHandler(registry *repos.Registry, queue ChatQueue) http.Handler

ChatHandler serves GET and POST /api/prs/chat: a pull request's conversations with the agent that wrote its review, and asking a question. The repository is a registered clone ID, as for /api/versions.

func DiscoveryHandler

func DiscoveryHandler(registry *repos.Registry, service DiscoveryCache, changed func()) http.Handler

func MergeHandler

func MergeHandler(registry *repos.Registry, merger PullRequestMerger, merged func(ctx context.Context, repository github.Repository, number int, head string), changed func()) http.Handler

MergeHandler serves /api/prs/merge-options and /api/prs/merge for picked repositories only. merged records a merge GitHub accepted, so the inbox shows it merged at once; its failure never turns a merge into an error.

func RegisteredRepository

func RegisteredRepository(ctx context.Context, registry *repos.Registry, id string) (string, error)

RegisteredRepository resolves a registered clone ID, without allowing a request to use arbitrary repository names or local paths.

func ReviewHandler

func ReviewHandler(registry *repos.Registry, reviewer PullRequestReviewer, changed func()) http.Handler

ReviewHandler serves POST /api/prs/review for picked repositories only.

func UpdateHandler

func UpdateHandler(registry *repos.Registry, updater PullRequestUpdater, refresh func(context.Context, github.Repository), changed func()) http.Handler

UpdateHandler serves /api/prs/update-branch(-options), /api/prs/rerun-checks(-options), /api/prs/review-threads, /api/prs/resolve-thread, /api/prs/failing-checks, /api/prs/checks, /api/prs/conflicts, /api/prs/description and /api/prs/rerun-job for picked repositories only. refresh re-reads the repository's pull requests after a write so the inbox shows the new state; its failure never turns a write into an error.

Types

type ChatQueue

type ChatQueue interface {
	Ask(ctx context.Context, ask chat.Ask) (jobs.ChatQueued, error)
	Conversations(ctx context.Context, clone string, pr int) ([]store.Conversation, error)
}

ChatQueue queues questions to a review's agent and lists the conversations; *jobs.Queue implements it.

type DecisionModel

type DecisionModel struct {
	Backend string `json:"effective_backend"`
	// Undetermined is a backend whose checks did not answer in time.
	Undetermined bool   `json:"backend_undetermined"`
	Model        string `json:"effective_model"`
	Ignored      bool   `json:"model_ignored"`
}

DecisionModel is the backend and decision model capture uses (decisionlog.EffectiveModel), and whether the chosen model is ignored.

type DiscoveryCache

type DiscoveryCache interface {
	Cached(context.Context, github.Repository) (discovery.Snapshot, error)
	PollNow(context.Context, github.Repository) (discovery.Snapshot, error)
}

DiscoveryCache is shared with the review index. Cached must never contact GitHub; polling runs in the background or an authenticated same-origin mutation. A refresh the person asks for polls now, without waiting for the backoff.

type FactsSource

type FactsSource interface {
	// Facts answers the pull request's facts at head, the head the page
	// shows, building them when they are due.
	Facts(ctx context.Context, clone repos.Clone, number int, head string) ([]byte, error)
	// Cached is the facts last built for the pull request and the head they
	// describe, nil when none; it never reads GitHub.
	Cached(clone repos.Clone, number int) ([]byte, string)
}

FactsSource builds and keeps pull requests' facts (review.Facts); *facts.Service implements it.

type GitHubAuthentication

type GitHubAuthentication struct {
	// contains filtered or unexported fields
}

GitHubAuthentication owns the lifetime of polling independently of browser requests. Its handler must be mounted inside the local session/CSRF boundary.

func NewGitHubAuthentication

func NewGitHubAuthentication(ctx context.Context, manager *githubauth.Manager, cfg config.Config, changed func(), transitions ...func() func(bool)) *GitHubAuthentication

func (*GitHubAuthentication) Handler

func (a *GitHubAuthentication) Handler() http.Handler

func (*GitHubAuthentication) Login

func (a *GitHubAuthentication) Login() string

Login is the connected GitHub account's login, "" without one.

type GitHubConnection

type GitHubConnection struct {
	State    string             `json:"state"`
	Host     string             `json:"host"`
	Login    string             `json:"login,omitempty"`
	Source   string             `json:"source,omitempty"`
	Override bool               `json:"override"`
	Saved    bool               `json:"saved"`
	Pending  *githubauth.Device `json:"pending,omitempty"`
	Error    string             `json:"error,omitempty"`
	Message  string             `json:"message,omitempty"`
}

GitHubConnection is the public view of the daemon's own connection. Override identifies an explicit credential that remains effective after disconnect.

type IndexWatch

type IndexWatch struct {
	// Fingerprint digests what the index is built from that other processes
	// change. It must be cheap: it runs every tick.
	Fingerprint func(context.Context) string
	// Invalidate drops the cached index; it is called when Fingerprint moves.
	Invalidate func()
	// Fresh reports the version of the cached index while it is still valid.
	Fresh func() (uint64, bool)
	// Snapshot returns the index and its version, building it if needed. It
	// must read local state only and honor cancellation.
	Snapshot func(context.Context) (any, uint64, error)
}

IndexWatch is what WatchIndex reads: a cached index and a cheap check for changes made outside this process. Only Snapshot is required; without the others every tick reads a snapshot.

type LinkedSessions

type LinkedSessions = func(ctx context.Context, repository string, number int) ([]locallink.Session, time.Time, error)

LinkedSessions lists the sessions a pull request's latest saved review links on this machine, and when that review was generated (zero without one). It is an alias, so decisionlog.API takes it as it is.

type LocalAPI

type LocalAPI struct {
	Registry         *repos.Registry
	Config           config.Config
	PRs, Index, Jobs http.Handler
	Background       http.Handler
	GitHubAuth       http.Handler
	// Automatic serves /api/automatic: the automatic generation preferences
	// and per-repository status.
	Automatic http.Handler
	// Live serves /api/live-sessions: the agent sessions in progress, and
	// /api/live-sessions/{agent}/{id}/transcript: one of their transcripts.
	Live http.Handler
	// AgentRequests serves /api/agent-requests and /api/agent-messages: the
	// permission requests and questions agents wait on the app to answer, and
	// the messages queued for running sessions (internal/agentrequests).
	AgentRequests http.Handler
	// Clones serves /api/clones/found: the local clones found without asking.
	Clones http.Handler
	// Merge serves /api/prs/merge-options and /api/prs/merge: merging a pull
	// request from the app.
	Merge http.Handler
	// Review serves /api/prs/review: submitting a pull request review with
	// inline comments from the app.
	Review http.Handler
	// Chat serves /api/prs/chat: asking the agent that wrote a review about
	// the pull request, and the conversations so far (ChatHandler).
	Chat http.Handler
	// Update serves /api/prs/update-branch and /api/prs/rerun-checks, with
	// their -options reads: updating a pull request's branch and re-running its
	// failed workflow runs. With merging, submitting a review and a
	// fix's push, they are the GitHub writes the app makes.
	Update http.Handler
	// Groups serves /api/groups: review groups and their combined reviews
	// (internal/reviewgroups).
	Groups http.Handler
	// Inboxes serves /api/inboxes: the saved filters listed under Inbox in
	// the app. Without it the route reports the capability unavailable.
	Inboxes http.Handler
	// UIState keeps inbox bookkeeping and review drafts across browser origins.
	UIState http.Handler
	// GitHubRepositories serves the account's repositories for picking
	// (/api/github/repositories) and cloning one
	// (/api/repositories/{owner}/{name}/clone and clone-target).
	GitHubRepositories http.Handler
	// PlanUsage serves /api/plan-usage: what remains of the Claude and Codex
	// plans.
	PlanUsage http.Handler
	// Analytics serves /api/analytics: what the agents did, cost and
	// delivered (internal/analytics).
	Analytics http.Handler
	// CurrentName lets POST /api/repos register a folder whose remote uses
	// an earlier name of the repository (repos.Registry.HandlerWith).
	CurrentName repos.CurrentName
	Changed     func()
	// Timeline serves /api/timeline/: the features and decisions of the
	// local decision log (internal/decisionlog).
	Timeline http.Handler
	// Sessions are the session stores a pull request page's linked sessions
	// are read from; the zero value reads this computer's default stores.
	Sessions sessions.Options
	// Facts builds what GET /api/facts answers: a pull request's facts for
	// its page while it has no saved review (internal/facts). Without it the
	// route reports the capability unavailable.
	Facts FactsSource
	// Decisions builds the handler of /api/decisions, the decisions captured
	// from agent sessions (internal/decisionlog), given the sessions a pull
	// request's saved review links, as its PR page lists them.
	Decisions func(LinkedSessions) http.Handler
	// DecisionModel resolves the decision model capture uses with the given
	// preferences, for GET and PUT /api/settings/decisions; nil reports none.
	DecisionModel func(context.Context, repos.Preferences) DecisionModel
	// DecisionsChanged, when set, is called after a change to what decision
	// capture does: its settings or a repository's. The daemon publishes the
	// app's decisions event with it.
	DecisionsChanged func()
	// ConcurrencyChanged, when set, applies a new job concurrency
	// (repos.Preferences.JobConcurrency) to the running queue.
	ConcurrencyChanged func(int)
	// Log receives what the API logs; nil is slog.Default.
	Log *slog.Logger
	// Diagnostics builds the report served at /api/diagnostics; nil serves the
	// capability fields with a null report. It must honour its context.
	Diagnostics func(context.Context) doctor.Report
	// HookTrust checks Codex session reporting without running a conversation.
	HookTrust func(context.Context) agentplugins.HookTrust
	// DiagnosticsTimeout bounds one shared run; zero means
	// defaultDiagnosticsTimeout.
	DiagnosticsTimeout time.Duration
	// Version is this baum's version, named in the "Report a problem" link
	// that /api/diagnostics returns.
	Version string
	// contains filtered or unexported fields
}

LocalAPI composes the existing local services. It never selects a filesystem path supplied by HTTP: document selectors must name a registered clone ID. Providers for later capabilities may be installed without changing the authentication or instance boundary.

func (LocalAPI) Handler

func (a LocalAPI) Handler() *LocalHandler

type LocalHandler

type LocalHandler struct {
	http.Handler
	// contains filtered or unexported fields
}

LocalHandler owns bounded per-document viewer resources.

func (*LocalHandler) Close

func (h *LocalHandler) Close()

func (*LocalHandler) InvalidateSessions

func (h *LocalHandler) InvalidateSessions()

type Options

type Options struct {
	// API serves application routes after authentication and CSRF validation.
	API http.Handler
	// App serves the browser application's files (GET and HEAD outside /api/)
	// under the session namespace, after authentication, with the namespace
	// prefix stripped. Nil serves a minimal status page.
	App http.Handler
	// Sample serves the API under /s/<namespace>/sample/, the sample project
	// the tour shows when there is no local data yet; the app's files are the
	// same. Nil leaves those paths unserved.
	Sample http.Handler
}

type PullRequestMerger

type PullRequestMerger interface {
	MergeOptions(ctx context.Context, repository github.Repository, number int) (github.MergeOptions, error)
	MergePullRequest(ctx context.Context, repository github.Repository, number int, method, expectedHead string) error
}

PullRequestMerger is the GitHub write of merging a pull request the user confirmed. *github.Client implements it.

type PullRequestReviewer

type PullRequestReviewer interface {
	SubmitReview(ctx context.Context, repository github.Repository, number int, review github.ReviewSubmission) (github.ReviewResult, error)
}

PullRequestReviewer is the GitHub write of submitting a pull request review the user wrote. *github.Client implements it.

type PullRequestUpdater

type PullRequestUpdater interface {
	UpdateOptions(ctx context.Context, repository github.Repository, number int) (prupdate.UpdateOptions, error)
	UpdateBranch(ctx context.Context, repository github.Repository, number int, expectedHead string) error
	RerunOptions(ctx context.Context, repository github.Repository, number int) (prupdate.RerunOptions, error)
	RerunFailedChecks(ctx context.Context, repository github.Repository, number int, expectedHead string) (prupdate.RerunResult, error)
	ReviewThreads(ctx context.Context, repository github.Repository, number, unresolved int) (prupdate.Threads, error)
	ResolveThread(ctx context.Context, repository github.Repository, number int, id string) error
	FailingChecks(ctx context.Context, repository github.Repository, number int, head string) (prupdate.Checks, error)
	RerunJob(ctx context.Context, repository github.Repository, number int, expectedHead string, job int64) error
	AllChecks(ctx context.Context, repository github.Repository, number int, head string) (prupdate.CheckList, error)
	Conflicts(ctx context.Context, repository github.Repository, number int) (prupdate.ConflictFiles, error)
	Description(ctx context.Context, repository github.Repository, number int) (prupdate.Description, error)
}

PullRequestUpdater is the other GitHub writes the local app makes: updating a pull request's branch and re-running its failed workflow runs, each one the user confirmed, and resolving a review thread the user chose. prupdate.Service implements it.

type Server

type Server struct {
	// contains filtered or unexported fields
}

func New

func New(opts Options) (*Server, error)

func (*Server) Handler

func (s *Server) Handler() http.Handler

func (*Server) LaunchURL

func (s *Server) LaunchURL() string

LaunchURL is a private capability, suitable for the browser fragment or a mode-0600 instance file. It must never be logged in diagnostics.

func (*Server) Listen

func (s *Server) Listen(port int) (string, error)

func (*Server) Origin

func (s *Server) Origin() string

func (*Server) Publish

func (s *Server) Publish(kind string, data any) error

Publish records a small notification, not sensitive documents. Clients that miss the bounded replay window receive a reset event and rebuild their index.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context) error

func (*Server) WatchIndex

func (s *Server) WatchIndex(ctx context.Context, interval time.Duration, w IndexWatch)

WatchIndex publishes an index event for changes nothing in this process announced: terminal generation, other processes' store and database writes, and changes that come with time. Each tick reads the index again only when the fingerprint moved, the cached index expired or was replaced, and publishes only when its JSON differs from the last one published.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL