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 ¶
- func ChatHandler(registry *repos.Registry, queue ChatQueue) http.Handler
- func DiscoveryHandler(registry *repos.Registry, service DiscoveryCache, changed func()) http.Handler
- func MergeHandler(registry *repos.Registry, merger PullRequestMerger, ...) http.Handler
- func RegisteredRepository(ctx context.Context, registry *repos.Registry, id string) (string, error)
- func ReviewHandler(registry *repos.Registry, reviewer PullRequestReviewer, changed func()) http.Handler
- func UpdateHandler(registry *repos.Registry, updater PullRequestUpdater, ...) http.Handler
- type ChatQueue
- type DecisionModel
- type DiscoveryCache
- type FactsSource
- type GitHubAuthentication
- type GitHubConnection
- type IndexWatch
- type LinkedSessions
- type LocalAPI
- type LocalHandler
- type Options
- type PullRequestMerger
- type PullRequestReviewer
- type PullRequestUpdater
- type Server
- func (s *Server) Handler() http.Handler
- func (s *Server) LaunchURL() string
- func (s *Server) Listen(port int) (string, error)
- func (s *Server) Origin() string
- func (s *Server) Publish(kind string, data any) error
- func (s *Server) Serve(ctx context.Context) error
- func (s *Server) WatchIndex(ctx context.Context, interval time.Duration, w IndexWatch)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ChatHandler ¶
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 ¶
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 ¶
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 (*Server) LaunchURL ¶
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) Publish ¶
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) WatchIndex ¶
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.