mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 22:37:28 +00:00
The 80s arcade classics (Space Invaders/nInvaders, Pac-Man/pacman4console, Tetris/tint, Moon Patrol/moon-buggy) are ncurses programs: initscr() fails with "Error opening terminal" when TERM is unset. Game subprocesses were built with exec.Command and no Env, so they inherited the agentbbs systemd daemon's environment — which has no TERM — and every game exited before drawing a frame. DOOM was unaffected because doom-ascii writes ANSI directly and never touches terminfo. Thread the client PTY's TERM through plugin.Context and hand each sandboxed game a curated environment (TERM, PATH, HOME, LANG=C.UTF-8) instead of the daemon's. Curating the env also stops leaking operator secrets (e.g. COINPAY_API_KEY) into third-party game binaries. Verified live on bbs.profullstack.com: Space Invaders and Pac-Man now render; previously all four died instantly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
1.9 KiB
Go
53 lines
1.9 KiB
Go
// Package plugin defines the AgentBBS plugin contract (PRD §4.3).
|
|
//
|
|
// A plugin is one interface implementation plus one registration in the hub.
|
|
// Plugins return control to the hub by emitting ExitMsg, never by quitting
|
|
// the session.
|
|
package plugin
|
|
|
|
import (
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"github.com/profullstack/agentbbs/internal/auth"
|
|
"github.com/profullstack/agentbbs/internal/sandbox"
|
|
"github.com/profullstack/agentbbs/internal/store"
|
|
)
|
|
|
|
// Context carries the shared services a plugin may use.
|
|
type Context struct {
|
|
Store store.Store
|
|
Sandbox *sandbox.Runner
|
|
// DataDir is the per-user persistent directory (members/agents only;
|
|
// empty for guests).
|
|
DataDir string
|
|
// AssetsDir is the read-only platform assets tree (wads, binaries).
|
|
AssetsDir string
|
|
// Host is the BBS hostname (e.g. bbs.profullstack.com), for building
|
|
// member homepage URLs (https://Host/~name) and similar links.
|
|
Host string
|
|
// Term is the client PTY's terminal type (e.g. xterm-256color). Needed by
|
|
// sandboxed ncurses games (Space Invaders, Pac-Man, Tetris, Moon Patrol),
|
|
// which call initscr() and fail with "Error opening terminal" if TERM is
|
|
// unset — the systemd daemon environment has no TERM to inherit.
|
|
Term string
|
|
}
|
|
|
|
// Plugin is the only integration point between a feature and the hub.
|
|
type Plugin interface {
|
|
// ID is a stable unique identifier, e.g. "arcade".
|
|
ID() string
|
|
// Title is the hub menu label.
|
|
Title() string
|
|
// Description is a one-line summary shown in the menu.
|
|
Description() string
|
|
// RequiresAuth reports whether guests are admitted.
|
|
RequiresAuth() bool
|
|
// New returns a fresh Bubble Tea model for one session.
|
|
New(user auth.User, ctx Context) tea.Model
|
|
}
|
|
|
|
// ExitMsg is emitted by a plugin model to hand the session back to the hub.
|
|
type ExitMsg struct{}
|
|
|
|
// Exit is a convenience command for plugins.
|
|
func Exit() tea.Msg { return ExitMsg{} }
|