picoclaw/pkg/miniapp/types.go
dj-oyu 34a8f13f78 refactor: split pkg/miniapp/miniapp.go into focused files
1279-line monolith → 7 files by responsibility:

  miniapp.go  ( 89L) — Handler struct, NewHandler, RegisterRoutes, serveIndex
  types.go    (180L) — exported types, interfaces, StateNotifier
  auth.go     (131L) — requireAuth, isAllowed, ValidateInitData
  dev.go      (477L) — dev proxy management + apiDev/serveDevProxy/apiDevConsole
  ws.go       (224L) — wsLogs, wsOrchestration, wsUpgrader/wsClient
  api.go      (168L) — JSON API handlers, writeJSON, sendSSEIfChanged
  logs.go     (143L) — apiLogsSnapshot, download, cleanOldSnapshots

go build ./pkg/miniapp/... and go test ./pkg/miniapp/... pass unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 03:25:18 +09:00

180 lines
4.9 KiB
Go

package miniapp
import (
"sync"
"github.com/sipeed/picoclaw/pkg/skills"
"github.com/sipeed/picoclaw/pkg/stats"
)
// PlanPhase mirrors agent.PlanPhase for JSON serialization.
type PlanPhase struct {
Number int `json:"number"`
Title string `json:"title"`
Steps []PlanStep `json:"steps"`
}
// PlanStep mirrors agent.PlanStep for JSON serialization.
type PlanStep struct {
Index int `json:"index"`
Description string `json:"description"`
Done bool `json:"done"`
}
// PlanInfo represents the plan state exposed via the API.
type PlanInfo struct {
HasPlan bool `json:"has_plan"`
Status string `json:"status"`
CurrentPhase int `json:"current_phase"`
TotalPhases int `json:"total_phases"`
Display string `json:"display"`
Phases []PlanPhase `json:"phases"`
Memory string `json:"memory"`
}
// SessionInfo represents an active session entry for the API response.
type SessionInfo struct {
SessionKey string `json:"session_key"`
Channel string `json:"channel"`
ChatID string `json:"chat_id"`
TouchDir string `json:"touch_dir"`
ProjectPath string `json:"project_path,omitempty"`
Purpose string `json:"purpose,omitempty"`
Branch string `json:"branch,omitempty"`
LastSeenAt string `json:"last_seen_at"`
AgeSec int `json:"age_sec"`
}
// GitRepoSummary represents a lightweight repo entry for the list view.
type GitRepoSummary struct {
Name string `json:"name"`
Branch string `json:"branch"`
}
// GitInfo represents the git repository state exposed via the API.
type GitInfo struct {
Name string `json:"name"`
Branch string `json:"branch"`
Commits []GitCommit `json:"commits"`
Modified []GitChange `json:"modified"`
}
// GitCommit represents a single commit entry.
type GitCommit struct {
Hash string `json:"hash"`
Subject string `json:"subject"`
Author string `json:"author"`
Date string `json:"date"`
}
// GitChange represents a modified/untracked file entry.
type GitChange struct {
Status string `json:"status"`
Path string `json:"path"`
}
// BootstrapFileInfo describes a resolved bootstrap file for the context API.
type BootstrapFileInfo struct {
Name string `json:"name"`
Path string `json:"path"`
Scope string `json:"scope"`
}
// ContextInfo describes the agent's directory context and bootstrap file resolution.
type ContextInfo struct {
WorkDir string `json:"work_dir"`
PlanWorkDir string `json:"plan_work_dir"`
Workspace string `json:"workspace"`
Bootstrap []BootstrapFileInfo `json:"bootstrap"`
}
// DataProvider is the read-only interface to agent state for the Mini App API.
type DataProvider interface {
ListSkills() []skills.SkillInfo
GetPlanInfo() PlanInfo
GetSessionStats() *stats.Stats
GetActiveSessions() []SessionInfo
GetGitRepos() []GitRepoSummary
GetGitRepoDetail(name string) GitInfo
GetContextInfo() ContextInfo
GetSystemPrompt() string
}
// CommandSender injects a command into the message bus on behalf of a user.
type CommandSender interface {
SendCommand(senderID, chatID, command string)
}
// DevTarget represents a registered dev server target.
type DevTarget struct {
ID string `json:"id"`
Name string `json:"name"` // display name (e.g. "frontend")
Target string `json:"target"` // URL (e.g. "http://localhost:3000")
}
// DevTargetManager allows tools to register, activate, and deactivate dev proxy targets.
type DevTargetManager interface {
RegisterDevTarget(name, target string) (id string, err error)
UnregisterDevTarget(id string) error
ActivateDevTarget(id string) error
DeactivateDevTarget() error
GetDevTarget() string
ListDevTargets() []DevTarget
}
// StateNotifier broadcasts state-change signals to SSE subscribers.
type StateNotifier struct {
mu sync.Mutex
subs map[chan struct{}]struct{}
done chan struct{}
}
// NewStateNotifier creates a new StateNotifier.
func NewStateNotifier() *StateNotifier {
return &StateNotifier{
subs: make(map[chan struct{}]struct{}),
done: make(chan struct{}),
}
}
// Subscribe returns a channel that receives a signal on each state change.
func (n *StateNotifier) Subscribe() chan struct{} {
ch := make(chan struct{}, 1)
n.mu.Lock()
n.subs[ch] = struct{}{}
n.mu.Unlock()
return ch
}
// Unsubscribe removes a subscriber channel.
func (n *StateNotifier) Unsubscribe(ch chan struct{}) {
n.mu.Lock()
delete(n.subs, ch)
n.mu.Unlock()
}
// Close signals all SSE handlers to exit.
func (n *StateNotifier) Close() {
select {
case <-n.done:
default:
close(n.done)
}
}
// Done returns a channel that is closed when the notifier is shut down.
func (n *StateNotifier) Done() <-chan struct{} {
return n.done
}
// Notify sends a signal to all subscribers, coalescing rapid notifications.
func (n *StateNotifier) Notify() {
n.mu.Lock()
defer n.mu.Unlock()
for ch := range n.subs {
select {
case ch <- struct{}{}:
default:
}
}
}