project

package
v0.601.2 Latest Latest
Warning

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

Go to latest
Published: Jun 22, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StatusStopped      = "stopped"
	StatusRunning      = "running"
	StatusError        = "error"
	StatusInitializing = "initializing"
	StatusMissing      = "missing" // path no longer exists on disk
)

Status constants for project lifecycle states.

Variables

View Source
var ErrExternalInstance = errors.New("project instance was launched externally and cannot be stopped from here")

ErrExternalInstance is returned by Stop when the project is running but its ACP instance was launched by another application (e.g. an editor's ACP integration) rather than by this manager. Such an instance cannot be stopped from here; the user must close it from the application that started it.

View Source
var ErrInstanceNotRunning = errors.New("no running manager-owned instance for project")

ErrInstanceNotRunning is returned by Delegate when no manager-owned child ACP instance is currently running for the requested project. Routing the work to a warm instance is only possible while one is live; callers that want auto-start must spawn the instance first (see the warm-target routing phase).

View Source
var ErrProjectNeedsInit = errors.New("project needs initialization: no .pando.toml found at path")

ErrProjectNeedsInit is returned when Activate is called on a project path that has no .pando.toml (or .pando.json) configuration file. The caller should guide the user through the init flow before retrying.

View Source
var ErrProjectNotRegistered = errors.New("project is not registered")

ErrProjectNotRegistered is returned by WarmDelegate when neither a project id nor a resolvable project path maps to a registered project, so no warm target can be selected. The caller should take the cold path.

View Source
var ErrWarmCapReached = errors.New("warm instance concurrency cap reached")

ErrWarmCapReached is returned by WarmDelegate when the per-instance concurrency cap (Delegation.MaxConcurrent) is already reached. The caller should fall back to the cold path rather than overloading a single warm instance.

Functions

This section is empty.

Types

type CreatedEvent

type CreatedEvent struct {
	Project Project
}

CreatedEvent is published when a new project is registered.

type DelegateResult added in v0.601.2

type DelegateResult struct {
	// ChildSessionID is the ACP session id created in the child for this run.
	// It is stored on the task (ACPSessionID) for correlation/recovery.
	ChildSessionID string
	// Output is the agent's full streamed message text for the turn.
	Output string
	// StopReason is the ACP stop reason reported by the child (e.g. end_turn).
	StopReason string
}

DelegateResult is the raw outcome of running a delegated prompt inside a warm per-project instance. The orchestrator (warm-target routing) wraps it into a terminal models.Task — populating Output so the existing conclusion pipeline (conclusion.Enrich → supervisor) extracts the <pando:conclusion> block — and fills software-owned launch metadata (model, parent session, correlation, depth) which this transport layer does not know about.

type DeletedEvent

type DeletedEvent struct {
	ProjectID string
}

DeletedEvent is published when a project is removed from the registry.

type InitRequiredEvent

type InitRequiredEvent struct {
	ProjectID string
	Path      string
}

InitRequiredEvent is published when activation is attempted on an uninitialized path.

type Instance

type Instance struct {
	Project Project
	// contains filtered or unexported fields
}

Instance represents a running (or stopped) child Pando ACP process for a registered project directory.

func (*Instance) InflightDelegations added in v0.601.2

func (i *Instance) InflightDelegations() int

InflightDelegations reports how many delegated sessions are currently running inside this instance. Used by the Projects panel to show "N delegated loops".

type Manager

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

Manager tracks child Pando ACP processes for registered project directories and routes lifecycle events to subscribers via a generic pubsub broker.

func NewManager

func NewManager(ctx context.Context, service Service) (*Manager, error)

NewManager creates a new Manager. Call Shutdown() when done to stop all child processes and release resources.

func (*Manager) Activate

func (m *Manager) Activate(ctx context.Context, projectID string) error

Activate starts (if needed) the child ACP process for projectID and makes it the active project. Returns ErrProjectNeedsInit if the path has no .pando.toml or .pando.json configuration file.

func (*Manager) ActiveID

func (m *Manager) ActiveID() string

ActiveID returns the currently active project ID. An empty string means the main (non-project) pando instance is active.

func (*Manager) ActiveProject

func (m *Manager) ActiveProject(ctx context.Context) (*Project, error)

ActiveProject returns the currently active Project, or nil when the main instance is active.

func (*Manager) CompleteInit

func (m *Manager) CompleteInit(ctx context.Context, projectID string) error

CompleteInit initializes the Pando configuration at the project's directory and then activates the project. It is called after the user confirms the initialization prompt shown when Activate returns ErrProjectNeedsInit.

It creates .pando.toml, .pando/ directory structure, and the init flag, then retries Activate. On success the project becomes the active project.

func (*Manager) Deactivate

func (m *Manager) Deactivate(_ context.Context) error

Deactivate clears the active project (the main pando instance becomes active again).

func (*Manager) Delegate added in v0.601.2

func (m *Manager) Delegate(ctx context.Context, projectID, promptText string) (*DelegateResult, error)

Delegate runs promptText inside the already-running ("warm") child ACP instance for projectID and captures the agent's streamed output over the wire. It opens a fresh ephemeral session in the child (the child keeps its own session history; the orchestrator's FileStore remains the single source of truth) and closes it on completion.

It returns ErrInstanceNotRunning when no manager-owned instance is live for the project — auto-start is the responsibility of the warm-target routing layer. If ctx is cancelled while the turn is in flight, the child session is cancelled and the context error is returned so the caller can fall back to the cold path.

func (*Manager) DelegationInfo added in v0.601.2

func (m *Manager) DelegationInfo(projectID string) (inflight int, spawned, running bool)

DelegationInfo reports the warm-delegation state of a manager-owned instance: the count of in-flight delegated sessions, whether the instance was auto-started by the delegation router (vs user-activated), and whether an instance is running at all. All zero/false when the project has no manager-owned instance (e.g. stopped or external).

func (*Manager) EnsureInstance added in v0.601.2

func (m *Manager) EnsureInstance(ctx context.Context, projectID string, autoStart bool) (*Instance, error)

EnsureInstance returns a running manager-owned instance for projectID, reusing an existing one or auto-starting a new child WITHOUT changing the active project (delegation must never switch the user's focused project).

When the project is served by an external (editor-launched) instance it returns ErrExternalInstance — such instances are never warm targets. When no instance is running and autoStart is false it returns ErrInstanceNotRunning; when autoStart is true but the path has no Pando config it returns ErrProjectNeedsInit.

func (*Manager) List

func (m *Manager) List(ctx context.Context) ([]Project, error)

List returns all registered projects from the underlying service.

func (*Manager) ListSessions

func (m *Manager) ListSessions(_ context.Context, projectID string) ([]sessionEntry, error)

ListSessions returns the cached session list for the given project instance. Returns nil when the project is not currently running.

NOTE: Actual session fetching will be implemented in Phase 5 via the REST API. For now this returns the in-memory cache which starts empty and is refreshed by future implementations.

func (*Manager) Register

func (m *Manager) Register(ctx context.Context, name, path string) (*Project, error)

Register adds a new project path to the registry. If name is empty, filepath.Base(path) is used. The path is expanded (~ resolved) and symlinks are evaluated before storing.

func (*Manager) Rename added in v0.290.1

func (m *Manager) Rename(ctx context.Context, projectID, newName string) error

Rename changes the display name of a registered project and propagates the change to the global projects registry so other instances can see it.

func (*Manager) Runtime added in v0.504.1

func (m *Manager) Runtime(projectID, path string) (running, external bool, pid int)

Runtime reports the live execution state of a project.

running is true when a Pando ACP instance is currently serving the project's directory. external is true when that instance was launched by another application (e.g. an editor's ACP integration) rather than by this manager, and therefore cannot be stopped from here. pid is the OS process id of the serving instance when known.

Ownership is determined by the in-memory instance map: an instance this manager spawned is tracked there. Anything else that holds the project's IPC lock on disk with a live PID is considered an external instance.

func (*Manager) SeedFromGlobal added in v0.290.1

func (m *Manager) SeedFromGlobal(ctx context.Context)

SeedFromGlobal upserts every entry from the global projects registry into the local DB so that any Pando instance can see all known projects. Entries whose path is already registered are skipped. This is called once during startup.

func (*Manager) Shutdown

func (m *Manager) Shutdown()

Shutdown stops all running child processes and cleans up resources. It is safe to call Shutdown more than once.

func (*Manager) Stop added in v0.504.1

func (m *Manager) Stop(ctx context.Context, projectID string) error

Stop terminates the child ACP instance this manager launched for projectID.

It returns ErrExternalInstance when the project is running but its instance was launched by another application, which this manager has no authority to terminate. When nothing is running, Stop is a no-op that ensures the registry reflects a stopped state.

func (*Manager) StopReport added in v0.601.2

func (m *Manager) StopReport(ctx context.Context, projectID string) (cancelled int, err error)

StopReport is Stop with bookkeeping: it returns the number of in-flight delegated sessions that were running inside the instance at stop time. Those sessions are cancelled by the process teardown; the orchestrator observes the failed turn and synthesizes a terminal conclusion (cold-path fallback), so the parent loop never hangs. The count lets the UI warn the user how many delegated loops were interrupted.

func (*Manager) Subscribe

func (m *Manager) Subscribe(ctx context.Context) <-chan pubsub.Event[ManagerEvent]

Subscribe returns a channel of ManagerEvents for real-time notifications.

func (*Manager) Unregister

func (m *Manager) Unregister(ctx context.Context, projectID string) error

Unregister removes a project from the registry and stops its running instance (if any).

func (*Manager) WarmDelegate added in v0.601.2

func (m *Manager) WarmDelegate(ctx context.Context, projectID, projectPath, promptText string, autoStart bool, maxConcurrent int) (*DelegateResult, error)

WarmDelegate is the high-level warm-routing entry point used by the orchestrator adapter. It ensures a warm instance for the project (reuse-then-autostart, excluding external instances), enforces the per-instance concurrency cap, and runs promptText in the instance, capturing the conclusion over the wire.

projectID may be empty, in which case projectPath is resolved to a registered project. autoStart selects reuse-then-autostart (true) vs reuse-only (false). maxConcurrent (>0) bounds concurrent delegated sessions per instance.

It returns a sentinel error the caller should treat as "use the cold path": ErrInstanceNotRunning (reuse-only, nothing running), ErrExternalInstance (the project is served by an editor-launched instance), ErrProjectNeedsInit (no config to start a child), ErrProjectNotRegistered (unknown project), or ErrWarmCapReached (cap reached). Any other error is a genuine warm-run failure.

type ManagerEvent

type ManagerEvent struct {
	Type      ManagerEventType
	ProjectID string
	Status    string
	Error     string
	// Count carries the current in-flight delegated-session count for
	// EvDelegationChanged events; zero for other event types.
	Count int
}

ManagerEvent is the union event type published by Manager.

type ManagerEventType

type ManagerEventType string

ManagerEventType identifies the kind of ManagerEvent.

const (
	// EvProjectSwitched is published when the active project changes.
	EvProjectSwitched ManagerEventType = "switched"
	// EvStatusChanged is published when a project's running status changes.
	EvStatusChanged ManagerEventType = "status_changed"
	// EvInitRequired is published when activation fails because the project
	// path has no Pando configuration file.
	EvInitRequired ManagerEventType = "init_required"
	// EvDelegationChanged is published when the count of in-flight delegated
	// sessions running inside a warm instance changes (start/end). The current
	// count is carried in ManagerEvent.Count.
	EvDelegationChanged ManagerEventType = "delegation_changed"
)

type Project

type Project struct {
	ID          string
	Name        string
	Path        string
	Status      string
	Initialized bool
	// External is a computed (non-persisted) flag: true when the project is
	// running but its ACP instance was launched by another application (e.g. an
	// editor in ACP mode) rather than by this manager, so it cannot be stopped
	// from here. It is populated on demand via Manager.Runtime and is zero in
	// values returned directly from the database.
	External bool
	// Delegations is a computed (non-persisted) count of delegated agent loops
	// currently running inside this project's warm instance. Populated on demand
	// via Manager.DelegationInfo; zero for stopped or DB-only values.
	Delegations int
	// DelegationSpawned is a computed (non-persisted) flag: true when the running
	// instance was auto-started by the delegation router (warm reuse) rather than
	// activated by the user. Populated on demand via Manager.DelegationInfo.
	DelegationSpawned bool
	ACPPID            int
	ACPPort           int
	LastOpened        *time.Time
	CreatedAt         time.Time
	UpdatedAt         time.Time
}

Project represents a registered project directory managed by Pando.

type Service

type Service interface {
	// Create registers a new project directory.
	// name defaults to filepath.Base(path) if empty.
	Create(ctx context.Context, name, path string) (*Project, error)

	// Get retrieves a project by ID.
	Get(ctx context.Context, id string) (*Project, error)

	// GetByPath retrieves a project by its directory path.
	GetByPath(ctx context.Context, path string) (*Project, error)

	// List returns all registered projects, newest first.
	List(ctx context.Context) ([]Project, error)

	// UpdateStatus updates the running state and optional process info.
	// pid and port should be 0 when not applicable.
	UpdateStatus(ctx context.Context, id, status string, pid, port int) error

	// MarkInitialized marks the project's config as having been initialized.
	MarkInitialized(ctx context.Context, id string) error

	// TouchLastOpened records the current time as last_opened for the project.
	TouchLastOpened(ctx context.Context, id string) error

	// Rename updates the display name of a project.
	Rename(ctx context.Context, id, name string) error

	// Delete removes a project from the registry (does NOT delete files).
	Delete(ctx context.Context, id string) error
}

Service defines operations for managing registered projects.

func NewService

func NewService(q *db.Queries) Service

NewService creates a new project service backed by the given DB queries.

type StatusChangedEvent

type StatusChangedEvent struct {
	ProjectID string
	OldStatus string
	NewStatus string
}

StatusChangedEvent is published when a project's status changes.

type SwitchedEvent

type SwitchedEvent struct {
	ProjectID string // empty string means "back to main instance"
}

SwitchedEvent is published when the active project changes.

Jump to

Keyboard shortcuts

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