Documentation
¶
Overview ¶
Package app is the core of the native desktop UI: the app-wide Context handed to every view, the registry of areas (chat, settings, files, ...), the router and the window layout (sidebar, header, content). Each area lives in its own package under internal/nativeui/app/<area> and registers itself from init(); see internal/nativeui/README.md for the conventions.
Index ¶
- Constants
- Variables
- func OnStart(fn func(a *Context))
- func ParseThemeID(id string) (kit.Family, kit.Mode, bool)
- func Register(ar Area)
- func RegisterBanner(order int, f func(a *Context) Banner)
- func RegisterCommand(cmd Command)
- func RegisterHeaderSlot(s HeaderSlot)
- func RegisterOverlay(f func(a *Context) Overlay)
- func RegisterShellExt(f func(a *Context) ShellExt)
- func RegisterStatusItem(it StatusItem)
- func ShortenPath(p string) string
- type Area
- type Banner
- type Batch
- type Closer
- type Command
- type Context
- func (a *Context) ActiveSessionID() string
- func (a *Context) ApplyPrefs(p client.UIPrefs)
- func (a *Context) CycleThemeMode()
- func (a *Context) FocusProjectWorkspace(id string)
- func (a *Context) ForClient(c *client.Client, cwd string) *Context
- func (a *Context) Go(fn func(ctx context.Context))
- func (a *Context) InsertIntoChatDraft(text string)
- func (a *Context) Invalidate()
- func (a *Context) IsChild() bool
- func (a *Context) Navigate(path string)
- func (a *Context) OpenModelSwitcher()
- func (a *Context) OpenQuickMenu()
- func (a *Context) PeekChatDraft() string
- func (a *Context) ReportError(title string, err error)
- func (a *Context) SavePrefs(patch client.UIPrefs)
- func (a *Context) SetDispatcher(d Dispatcher)
- func (a *Context) SetLanguage(lang string)
- func (a *Context) SetSidebarCollapsed(v bool)
- func (a *Context) SetTheme(s kit.Settings)
- func (a *Context) Shell() *Shell
- func (a *Context) StartServices(h Host)
- func (a *Context) T(key string, args ...any) string
- func (a *Context) TakeChatDraft() string
- func (a *Context) ToggleSimpleChat()
- func (a *Context) TrayLabels() shell.TrayLabels
- func (a *Context) Update(fn func())
- func (a *Context) WebViewHost() kit.WebViewHost
- type Dispatcher
- type ExternalAccess
- type HeaderActions
- type HeaderSlot
- type Host
- type LeaveGuard
- type Overlay
- type QueueDispatcher
- type Root
- type Section
- type Shell
- type ShellExt
- type ShellTab
- type StatusItem
- type Titled
- type View
- type WindowHost
Constants ¶
const DefaultPath = "/chat"
DefaultPath is the route shown at start-up.
const DocsURL = "https://madeindigio.github.io/pando-docs/"
DocsURL is the documentation site the header links to.
Variables ¶
var CustomFrame = shell.CustomFrame
CustomFrame reports whether the UI draws its own title bar and window buttons (no native ones): Linux and Windows, never macOS. A variable so tests can switch the platform.
var OpenExternal = func(url string) { _ = mygo.Shell.OpenExternal(url) }
OpenExternal opens a URL in the default browser (a variable for tests).
Functions ¶
func OnStart ¶
func OnStart(fn func(a *Context))
OnStart registers fn to run once, on the UI thread, in the first frame of the root view (after the dispatcher is connected). Areas use it to react to the server state at start-up, e.g. the setup area opens its assistant when the server says the first-run setup is needed. fn must not block: start goroutines with a.Go and come back through a.Update.
func ParseThemeID ¶
ParseThemeID parses a backend theme id ("family-mode", the config field shared with the TUI). ok is false for ids the desktop does not know (TUI-only themes such as "pando-nobg").
func Register ¶
func Register(ar Area)
Register adds an area, replacing one with the same ID (so a real area replaces its placeholder regardless of init order: a non-placeholder registration always wins over a placeholder).
func RegisterBanner ¶
RegisterBanner registers a banner factory; banners stack by order.
func RegisterCommand ¶
func RegisterCommand(cmd Command)
RegisterCommand adds a quick menu command, replacing one with the same ID.
func RegisterHeaderSlot ¶
func RegisterHeaderSlot(s HeaderSlot)
RegisterHeaderSlot adds a header control, replacing one with the same ID.
func RegisterOverlay ¶
RegisterOverlay registers a factory called once per window root.
func RegisterShellExt ¶
RegisterShellExt registers a factory called by NewRoot.
func RegisterStatusItem ¶
func RegisterStatusItem(it StatusItem)
RegisterStatusItem adds a status strip item (call from init). The extensions package registers the "status-bar" slot here.
func ShortenPath ¶
ShortenPath replaces the home directory with ~ (the Web UI's shortenPath), also for paths under another home (remote instances).
Types ¶
type Area ¶
type Area struct {
// ID is unique and stable ("chat", "settings").
ID string
// Path is where the sidebar entry navigates ("/chat").
Path string
// Patterns are the router patterns the area builds; Path when empty.
// Use "/settings/{section...}" style patterns for sub-pages.
Patterns []string
// TitleKey is the i18n key of the label and header title ("nav.chat").
TitleKey string
// Icon is a kit icon name.
Icon string
Section Section
// Order sorts entries within a section (ascending).
Order int
// New builds the area's view once, the first time it is shown; the view
// then keeps its state across navigation.
New func(a *Context) View
// Placeholder marks areas not built yet.
Placeholder bool
// Visible, when set, decides on each frame whether the sidebar shows
// the entry (the extensions area hides itself on builds without panels).
// The area stays routable either way.
Visible func(a *Context) bool
}
Area is a top-level destination of the app (a sidebar entry and its routes).
type Banner ¶
type Banner = Overlay
Banner is a strip drawn above the header of the main tab (config init, update notice). Build runs every frame and draws nothing when not needed.
type Batch ¶
type Batch[T any] struct { // contains filtered or unexported fields }
Batch coalesces items pushed from goroutines into one UI update per frame: Push queues an item and schedules a single Update that hands every item queued meanwhile to apply. It is how streams feed the UI without one frame per token.
type Closer ¶
type Closer interface {
Close()
}
Closer is implemented by views that own goroutines or streams to stop when the app shuts down.
type Command ¶
type Command struct {
ID string
Title string
// TitleKey, when set, is the i18n key of the title (Title is then the
// fallback when the key is missing).
TitleKey string
Description string
// Group is "command" (default) or "account".
Group string
Icon string
Keywords []string
Run func(a *Context)
}
Command is an entry of the quick menu (command palette).
type Context ¶
type Context struct {
// Ctx is canceled when the app shuts down: derive goroutine contexts
// from it.
Ctx context.Context
// Client talks to the Pando server.
Client *client.Client
// Server describes the server (version, startup mode).
Server client.ServerInfo
// CWD is the working directory of the server, when known.
CWD string
// Router navigates between areas (paths of the registered areas).
Router *ui.Router
// Toasts queues toasts from any goroutine.
Toasts *kit.Toaster
// Theme selects family, mode and accent; read every frame.
Theme kit.Settings
// Log is the UI logger.
Log *slog.Logger
// contains filtered or unexported fields
}
Context is the app-wide context every view receives. Its fields are set once at start-up; mutate view state only on the UI thread (in the view, or through Update from goroutines).
func NewContext ¶
NewContext returns a context with defaults for what opts leaves empty.
func (*Context) ActiveSessionID ¶
ActiveSessionID returns the chat session the route shows ("" outside a session), from /chat/s/{id} or /chat/simple/s/{id}.
func (*Context) ApplyPrefs ¶
ApplyPrefs applies persisted UI preferences (theme, language, sidebar) to the live state. UI thread.
func (*Context) CycleThemeMode ¶
func (a *Context) CycleThemeMode()
CycleThemeMode cycles system -> light -> dark and persists it.
func (*Context) FocusProjectWorkspace ¶
FocusProjectWorkspace focuses a project workspace tab (tray menu).
func (*Context) ForClient ¶
ForClient returns a context that talks to another server (a project's child instance through the parent proxy, see client.Client.Derive) while sharing everything else: the window dispatcher, toasts, ctx and logger. Areas are instantiated against it with Area.New(child), which is how a project workspace hosts chat, files, ... for another project. The child has its own Router (the routes of the embedded areas must not move the main window) and its own Server info and CWD. Its Theme is not used: the root view applies the theme once per frame and kit.Current() is global.
func (*Context) Go ¶
Go runs fn on a goroutine with the app context, logging a panic instead of crashing the UI.
func (*Context) InsertIntoChatDraft ¶
InsertIntoChatDraft appends text to the pending chat draft.
func (*Context) IsChild ¶
IsChild reports whether the context is a project workspace's (made by ForClient): its areas are embedded in a tab, without the window header.
func (*Context) OpenModelSwitcher ¶
func (a *Context) OpenModelSwitcher()
OpenModelSwitcher opens the model switcher overlay.
func (*Context) OpenQuickMenu ¶
func (a *Context) OpenQuickMenu()
OpenQuickMenu opens the command palette.
func (*Context) PeekChatDraft ¶
PeekChatDraft returns the pending chat draft without clearing it.
func (*Context) ReportError ¶
ReportError tells the user a background call failed. Authorization failures get a clear message of their own, shown at most once a minute.
func (*Context) SavePrefs ¶
SavePrefs persists a preferences patch in the background (the server merges it). A failure is logged, and a 401 is surfaced.
func (*Context) SetDispatcher ¶
func (a *Context) SetDispatcher(d Dispatcher)
SetDispatcher connects the context to its window. Until then Update runs nothing (there is no UI to update) and Invalidate is a no-op.
func (*Context) SetLanguage ¶
SetLanguage selects and persists the UI language. UI thread.
func (*Context) SetSidebarCollapsed ¶
SetSidebarCollapsed collapses or expands the sidebar and persists it.
func (*Context) Shell ¶
Shell returns the shared window state of the root context (a context made by ForClient shares its parent's).
func (*Context) StartServices ¶
StartServices connects the context to the window shell and starts the background services of the window: persisted UI preferences, the minimise/close-to-tray setting (followed live through /config/events) and OS notifications for runs finishing while the window is unfocused. Call it on the UI thread once the window exists. h may be nil (headless).
func (*Context) TakeChatDraft ¶
TakeChatDraft returns and clears the pending chat draft.
func (*Context) ToggleSimpleChat ¶
func (a *Context) ToggleSimpleChat()
ToggleSimpleChat switches between the full and the simple chat and remembers the choice (chatMode).
func (*Context) TrayLabels ¶
func (a *Context) TrayLabels() shell.TrayLabels
TrayLabels returns the tray menu labels in the UI language (Web UI keys where they exist; English defaults otherwise).
func (*Context) Update ¶
func (a *Context) Update(fn func())
Update runs fn on the UI thread and redraws. Background goroutines must change view state only through it.
func (*Context) WebViewHost ¶
func (a *Context) WebViewHost() kit.WebViewHost
WebViewHost returns the window that hosts embedded web views (the main window), or nil before it exists and in headless tests. Use it as kit.WebPane.Host:
pane := &kit.WebPane{Host: a.WebViewHost}
type Dispatcher ¶
type Dispatcher interface {
Update(fn func())
Invalidate()
}
Dispatcher posts work to the UI thread. *mygo.Window implements it: Update runs fn on the main thread then redraws, Invalidate only redraws. Both are safe from any goroutine and return without waiting.
type ExternalAccess ¶
type ExternalAccess struct {
Enabled bool `json:"enabled"`
BindHost string `json:"bindHost"`
Port int `json:"port"`
CanToggle bool `json:"canToggle"`
BasicAuthReady bool `json:"basicAuthReady"`
URLs []string `json:"urls"`
}
ExternalAccess mirrors GET/PUT /api/v1/config/api-server/external-access: whether the running server listens on 0.0.0.0 (the Web UI's footer toggle).
type HeaderActions ¶
HeaderActions is implemented by views that add controls to the header bar, on its right.
type HeaderSlot ¶
type HeaderSlot struct {
ID string
// Order sorts slots ascending; built-ins use 100+ (simple chat 100,
// docs 110, theme 120, settings 130).
Order int
Build func(c *ui.Context, a *Context)
}
HeaderSlot is a control of the header bar, on the right of the view's own actions. The persona selector registers one with ID "persona".
type Host ¶
type Host interface {
// Focused reports whether the window has the keyboard focus.
Focused() bool
// Show brings the window back (tray, minimised, behind others).
Show()
// Quit quits the app, whatever the tray setting.
Quit()
// SetTitle sets the window title.
SetTitle(title string)
// SetTrayOnClose mirrors Desktop.TrayOnMinimizeClose.
SetTrayOnClose(on bool)
// SetTrayProjects lists the open project workspaces in the tray menu.
SetTrayProjects(p []shell.TrayProject)
// Notify shows an OS notification.
Notify(id, title, body string)
}
Host is what the window shell (internal/nativeui/shell) offers the app: *shell.Controller implements it. It is nil in headless tests, so callers go through the Shell helpers, which tolerate that.
type LeaveGuard ¶
type LeaveGuard interface {
ConfirmLeave(proceed func()) bool
}
LeaveGuard is implemented by views that hold unsaved edits (settings). The layout asks it before navigating to another area: ConfirmLeave returns true when leaving is fine right now; otherwise it shows its own prompt and calls proceed later if the user decides to leave.
type Overlay ¶
Overlay is a layer drawn above the whole window (dialogs, palettes). Build runs every frame on the main tab; it draws nothing while closed.
type QueueDispatcher ¶
type QueueDispatcher struct {
// contains filtered or unexported fields
}
QueueDispatcher is a Dispatcher for tests and headless use: Update queues fn until Drain runs the queue on the caller's goroutine.
func (*QueueDispatcher) Drain ¶
func (q *QueueDispatcher) Drain() int
Drain runs the queued functions (and those they queue) and reports how many ran.
func (*QueueDispatcher) Invalidate ¶
func (q *QueueDispatcher) Invalidate()
Invalidate counts a redraw request.
type Root ¶
type Root struct {
App *Context
// contains filtered or unexported fields
}
Root is the window's view: sidebar, header and the routed area.
func NewEmbeddedRoot ¶
NewEmbeddedRoot returns a root that lives inside another root (a project workspace tab): it uses the theme of the host frame, shows no toasts, tab bar or theme toggle, and titles its sidebar brand. a is usually made with Context.ForClient.
type Section ¶
type Section string
Section groups sidebar entries.
const ( SectionMain Section = "main" // chat, projects SectionTools Section = "tools" // editor, terminal, orchestrator, ... SectionServices Section = "services" // instances, extensions SectionBottom Section = "bottom" // settings, pinned to the bottom SectionHidden Section = "hidden" // routable, not in the sidebar (setup) )
Sidebar sections, top to bottom.
type Shell ¶
type Shell struct {
// Host is the window shell (nil headless).
Host Host
// QuickMenuOpen and ModelSwitcherOpen are the overlays (Ctrl/Cmd+K or
// Ctrl/Cmd+P, and Ctrl/Cmd+O).
QuickMenuOpen bool
ModelSwitcherOpen bool
// SidebarCollapsed is the icon-rail sidebar (persisted in the UI
// preferences).
SidebarCollapsed bool
// StartExplicit is set when the first route was chosen (--simple, a
// path option); otherwise the persisted chat mode may pick it.
StartExplicit bool
// NextModel is a model picked in the switcher while no chat session was
// open: the chat sends it with the first prompt (the web's
// sessionModelStore). Empty when none.
NextModel string
// ModelChanged, when set (the chat sets it), is told after the model
// switcher changed the model of a session ("" = none open).
ModelChanged func(model, sessionID string)
// FocusProject focuses a project workspace tab by project ID (tray
// menu). The projects area sets it; the default only opens /projects.
FocusProject func(id string)
// contains filtered or unexported fields
}
Shell is the window-level state shared by the chrome and the overlays: which overlay is open, the sidebar, the host. UI thread only.
type ShellExt ¶
type ShellExt interface {
// Tabs lists the open tabs, in order.
Tabs() []ShellTab
// Active returns the focused tab ID, "" for the main tab.
Active() string
// Select focuses a tab ("" is the main tab).
Select(id string)
// Close asks to close a tab (the extension may prompt first).
Close(id string)
// Build draws the content of the active tab.
Build(c *ui.Context, id string)
// Dialogs draws the extension's modal dialogs; it runs every frame, on
// whichever tab is focused.
Dialogs(c *ui.Context)
}
ShellExt adds tabs to the shell. The main tab ("") always exists and shows the routed areas; the extension's tabs replace the whole main panel, sidebar included, with their own content, the way the Web UI shows a project workspace iframe. An extension is created once per root window (never for an embedded root) by the factory given to RegisterShellExt.
type ShellTab ¶
type ShellTab struct {
ID string
Title string
// Detail is the tooltip (path, state).
Detail string
// State is starting, running, stopped or error; it picks the tab icon.
State string
// Busy marks a tab whose workspace has an agent run in flight.
Busy bool
}
ShellTab is a tab of the shell tab bar (a project workspace).
type StatusItem ¶
type StatusItem struct {
Order int
// Visible reports whether the item has something to show this frame.
Visible func(a *Context) bool
Build func(c *ui.Context, a *Context)
}
StatusItem is a part of the window's status strip, under the routed area of the main tab (the Web UI's StatusBar slot). Build draws nothing when it has nothing to show; the strip itself only appears when an item drew.
type Titled ¶
type Titled interface {
Title() string
}
Titled is implemented by views whose header title depends on state (the chat shows the session title). The area's TitleKey is used otherwise.
type View ¶
View is what an area shows. Build runs on the UI thread every frame the area is visible; r is the matched route (r.Param for {id} patterns).
type WindowHost ¶
type WindowHost interface {
// Minimize hides into the tray or minimises, following the tray setting.
Minimize()
// ToggleMaximize maximises or restores.
ToggleMaximize()
// IsMaximized reports the maximised state.
IsMaximized() bool
// CloseWindow hides into the tray or closes (quitting), following the
// tray setting.
CloseWindow()
// ToggleFullScreen toggles full screen.
ToggleFullScreen()
}
WindowHost is the part of the host that drives the window for the custom title bar (Linux, Windows); *shell.Controller implements it.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package agentvcs is the Agent VCS area (route /snapshots, as in the Web UI): the sessions that have agent commits, their commit log, the files each commit changed with a side-by-side diff viewer (MyGo ui/editor DiffView), revert of a commit or of single files, and the named project snapshots.
|
Package agentvcs is the Agent VCS area (route /snapshots, as in the Web UI): the sessions that have agent commits, their commit log, the files each commit changed with a side-by-side diff viewer (MyGo ui/editor DiffView), revert of a commit or of single files, and the named project snapshots. |
|
Package chat is the chat area of the native desktop: the sessions list, session history and streaming runs (P0 MVP; P1 brings parity with the Web UI: tool cards, diffs, questions, plan/goal, model picker, slash and @).
|
Package chat is the chat area of the native desktop: the sessions list, session history and streaming runs (P0 MVP; P1 brings parity with the Web UI: tool cards, diffs, questions, plan/goal, model picker, slash and @). |
|
Package design is the Design Studio area of the native desktop: the artifact and template galleries at /design and one artifact's Studio at /design/{id} (web-ui components/design + designStore).
|
Package design is the Design Studio area of the native desktop: the artifact and template galleries at /design and one artifact's Studio at /design/{id} (web-ui components/design + designStore). |
|
Package editor is the code editor area of the native desktop: a file explorer, open-file tabs, a code editor (MyGo ui/editor, with find bar, folding, multi-cursor and syntax highlighting), image/PDF viewers and a status bar.
|
Package editor is the code editor area of the native desktop: a file explorer, open-file tabs, a code editor (MyGo ui/editor, with find bar, folding, multi-cursor and syntax highlighting), image/PDF viewers and a status bar. |
|
Package evaluator is the self-improvement area: metrics cards, the daily evaluations chart, the UCB ranking of prompt variants, learned skills with approve/reject, the evaluated sessions with their score explanation and the doctor banner.
|
Package evaluator is the self-improvement area: metrics cards, the daily evaluations chart, the UCB ranking of prompt variants, learned skills with approve/reject, the evaluated sessions with their score explanation and the doctor banner. |
|
Package extensions is the extension UI of the native desktop: the sidebar page at /ext/{panelId} and the slots (sidebar, settings, chat-side, status-bar) other areas embed.
|
Package extensions is the extension UI of the native desktop: the sidebar page at /ext/{panelId} and the slots (sidebar, settings, chat-side, status-bar) other areas embed. |
|
Package instances is the instances area: the Pando instances running on this machine grouped by project path, and for the selected one its sessions with the conversation history, the live event stream (/instances/{id}/sessions/{sid}/stream), a message box and cancel.
|
Package instances is the instances area: the Pando instances running on this machine grouped by project path, and for the selected one its sessions with the conversation history, the live event stream (/instances/{id}/sessions/{sid}/stream), a message box and cancel. |
|
Package logs is the native Logs area: the server log buffer as a table with level and text filters, auto-scroll and a detail panel.
|
Package logs is the native Logs area: the server log buffer as a table with level and text filters, auto-scroll and a detail panel. |
|
Package orchestrator is the native Orchestrator area: Mesnada tasks (list, detail, create, cancel, delete), delegation metrics and the CronJobs panel.
|
Package orchestrator is the native Orchestrator area: Mesnada tasks (list, detail, create, cancel, delete), delegation metrics and the CronJobs panel. |
|
Package overlays holds the window-level layers of the native desktop that the Web UI draws over its layout: the quick menu (command palette), the model switcher, the config-init banner and the update notice.
|
Package overlays holds the window-level layers of the native desktop that the Web UI draws over its layout: the quick menu (command palette), the model switcher, the config-init banner and the update notice. |
|
Package projects is the native Projects area and the project workspaces: the registry of projects (add, rename, stop, delete, init) and the tabs that open a project's child instance inside the shell.
|
Package projects is the native Projects area and the project workspaces: the registry of projects (add, rename, stop, delete, init) and the tabs that open a project's child instance inside the shell. |
|
Package settings is the settings area of the native desktop: the 23 categories of the Web UI settings (web-ui/src/components/settings), their unsaved-changes guard and the "?section=" deep link.
|
Package settings is the settings area of the native desktop: the 23 categories of the Web UI settings (web-ui/src/components/settings), their unsaved-changes guard and the "?section=" deep link. |
|
Package setup is the first-run setup assistant of the native desktop (the Web UI's SetupWizard): scope, provider, models, Remembrances and a summary.
|
Package setup is the first-run setup assistant of the native desktop (the Web UI's SetupWizard): scope, provider, models, Remembrances and a summary. |
|
Package terminal is the Terminal area of the native desktop: tabs of interactive shells running in real PTYs on the server, shown by MyGo's terminal plugin (libghostty-vt, loaded at run time without cgo) and fed by the WebSocket PTY endpoint /api/v1/terminal/pty, the same one the Web UI's xterm.js pane uses (binary frames carry I/O, JSON text frames carry ready/exit/resize/close).
|
Package terminal is the Terminal area of the native desktop: tabs of interactive shells running in real PTYs on the server, shown by MyGo's terminal plugin (libghostty-vt, loaded at run time without cgo) and fed by the WebSocket PTY endpoint /api/v1/terminal/pty, the same one the Web UI's xterm.js pane uses (binary frames carry I/O, JSON text frames carry ready/exit/resize/close). |