ports

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package ports — LLMSource port definition.

LLMSource is the unified abstraction for any AI CLI's session data. The current implementation only supports Claude Code (via the jsonl adapter), but the interface is designed to accept Gemini CLI, Codex CLI, Kimi CLI etc. in future versions.

Adapter locations:

  • claude-code → internal/adapters/jsonl (existing)
  • gemini-cli → internal/adapters/gemini (V21+, not yet implemented)
  • codex → internal/adapters/codex (V21+, not yet implemented)
  • kimi → internal/adapters/kimi (V21+, not yet implemented)

Package ports — LSPSource port definition.

LSPSource discovers language servers available on the developer's machine. V1 detects by scanning $PATH for known LSP binary names; V2+ may extend to inspect editor configurations or project-local toolchains.

Package ports — PlanUsageSource port definition.

PlanUsageSource is the abstraction for retrieving the user's subscription plan-quota usage from a backend. The numbers it returns are the SAME ones shown on https://claude.ai/settings/usage — i.e. plan-quota percentages, NOT token counts derivable from local JSONL session files.

Adapter locations:

  • anthropic-api → internal/adapters/anthropicapi (calls /api/oauth/usage with the OAuth token Claude Code stores locally)

Package ports defines the port interfaces for the hexagonal architecture.

Ports are the "driven" side of the hexagon — they describe what the application layer needs from the outside world (data sources, clocks, etc.) without naming any specific technology. Concrete implementations live in internal/adapters/*.

Index

Constants

This section is empty.

Variables

View Source
var ErrPlanUsageAuth = errors.New("plan usage auth failed")

ErrPlanUsageAuth is returned when credentials exist but cannot be used — the OAuth refresh token has been revoked or has hit a terminal invalid_grant. Callers SHOULD prompt the user to re-authenticate.

View Source
var ErrPlanUsageUnavailable = errors.New("plan usage unavailable")

ErrPlanUsageUnavailable is returned when no credentials are present or the user is on a plan that does not expose plan-quota data. Callers SHOULD hide the plan-quota UI rather than treat this as an error worth surfacing.

Functions

This section is empty.

Types

type Clock

type Clock interface {
	// Now returns the current time in UTC.
	Now() time.Time
}

Clock is the port that provides the current time to the application layer.

The domain and application layers MUST NOT call time.Now() directly — all current-time access goes through Clock. This keeps time deterministic in tests and decouples the application from the system clock.

Contract:

  • Clock MUST return the current time as a UTC timestamp.
  • Successive calls MUST NOT return a time earlier than a preceding call (monotonic requirement for display purposes).

type GlobalSessionRef

type GlobalSessionRef struct {
	// ProjectEncodedDir is the encoded project directory name under ~/.claude/projects/,
	// e.g. "-Users-alice-work-clyde".
	ProjectEncodedDir string

	// SessionID is the session identifier (the JSONL filename without extension).
	SessionID session.ID

	// LastActivity is the file mtime — a cheap proxy for the session's last event.
	LastActivity time.Time

	// Path is the absolute path to the JSONL file.
	Path string
}

GlobalSessionRef is a reference to a session in any project directory. It carries enough metadata to filter by time window without reading the full JSONL file, plus the absolute path for on-demand event loading.

type GlobalSessionSource

type GlobalSessionSource interface {
	// AllProjectSessions returns refs to all sessions across all projects,
	// ordered by LastActivity descending. At most maxResults refs are returned.
	// Pass maxResults=0 for no cap (not recommended in production).
	AllProjectSessions(ctx context.Context, maxResults int) ([]GlobalSessionRef, error)
}

GlobalSessionSource is an optional extension port that enumerates sessions across ALL project directories under ~/.claude/projects/.

Implementations MUST:

  • Walk every subdirectory of the projects root, list *.jsonl files.
  • Return refs ordered by LastActivity descending (most recent first).
  • Return empty slice (no error) when the projects root is missing.
  • Cap results at a reasonable N to bound snapshot latency.

type LLMSource

type LLMSource interface {
	// Name returns the CLI source name, e.g. "claude-code", "gemini-cli".
	// Used for display in the title bar and for --source flag matching.
	Name() string

	// Sessions returns sessions for the given project working directory.
	Sessions(ctx context.Context, projectCWD string) ([]session.Summary, error)

	// Events returns events for the given session in ascending chronological order.
	Events(ctx context.Context, id session.ID) ([]event.Event, error)

	// AllProjectSessions returns references to sessions across all project
	// directories, ordered by LastActivity descending.
	// maxResults caps the result count (0 = no cap, not recommended in production).
	AllProjectSessions(ctx context.Context, maxResults int) ([]GlobalSessionRef, error)

	// PlanLimits returns the user's subscription plan limits, if detectable.
	// Returns nil when unknown (the caller falls back to hiding limit indicators).
	PlanLimits(ctx context.Context) *PlanLimits
}

LLMSource is the unified interface for reading session data from any AI CLI.

Adapters MUST satisfy this interface; the composition root selects the adapter at startup based on the --source flag.

Contract:

  • Sessions and Events follow the same semantics as SessionSource.
  • AllProjectSessions follows the same semantics as GlobalSessionSource.
  • PlanLimits returns nil when the plan/limits are unknown.
  • Name returns a short slug, e.g. "claude-code".

type LSPInfo

type LSPInfo struct {
	// Name is the human-readable display label, e.g. "gopls", "rust-analyzer".
	Name string

	// Binary is the executable name as resolved on PATH, e.g. "/usr/local/bin/gopls".
	// Empty when the source did not preserve the resolved path.
	Binary string

	// Active is true when the binary is available (resolved on PATH).
	// Note: this is "installed and runnable", NOT "claude code is using it".
	// See ClaudeEnabled for that distinction.
	Active bool

	// ClaudeEnabled is true when Claude Code's settings.json enabledPlugins
	// map contains the plugin entry for this LSP (e.g.
	// "gopls-lsp@claude-plugins-official"). When false, the binary may be
	// installed locally but Claude Code is not actually using it — the TUI
	// flags this state with an amber dot so the user notices the gap.
	ClaudeEnabled bool
}

LSPInfo describes a single language server detected on the host.

type LSPSource

type LSPSource interface {
	LSPs() ([]LSPInfo, error)
}

LSPSource is the port through which the application layer retrieves the list of detected language servers.

Implementations MUST:

  • Return an empty slice (not an error) when none are found.
  • Return entries sorted in a stable order (alphabetical by Name).
  • Complete in well under a second on a normal machine.

type MCPEntry

type MCPEntry struct {
	// Name is the plugin identifier as it appears in the settings file,
	// e.g. "engram@engram" or "claude-code-setup@claude-plugins-official".
	Name string

	// Enabled is true when the plugin is explicitly enabled.
	Enabled bool

	// ToolCount is the number of tools provided by this server.
	// 0 when live inspection is unavailable (V1).
	ToolCount int
}

MCPEntry is the raw MCP plugin entry read from the settings source. It carries just enough information for the livesession view to build a displayable MCP list without knowing about the settings file format.

type MCPSource

type MCPSource interface {
	// MCPs returns all configured MCP entries from the underlying settings source.
	MCPs() ([]MCPEntry, error)
}

MCPSource is the port through which the application layer retrieves the list of configured MCP servers. Implementations MUST:

  • Return entries sorted in a stable order (e.g. alphabetical by Name).
  • Return an empty slice (not an error) when the source is unavailable.
  • Never block for more than a few milliseconds (no live socket ping in V1).

type PlanLimits

type PlanLimits struct {
	// Name is the human-readable plan name, e.g. "Max ×5", "Pro", "Free".
	Name string

	// SessionLimit is the maximum tokens per 5-hour rolling window.
	// 0 means no limit is known or the plan has no token-based session cap.
	SessionLimit int64

	// WeeklyLimit is the maximum tokens per 7-day rolling window.
	// 0 means no limit is known or the plan has no weekly token cap.
	WeeklyLimit int64
}

PlanLimits describes the rate limits associated with a subscription plan.

type PlanUsage

type PlanUsage struct {
	// FiveHour is the rolling 5-hour session window.
	FiveHour PlanWindow

	// SevenDay is the rolling 7-day weekly window across all models.
	SevenDay PlanWindow

	// Tier is the human-readable plan tier name, derived from the
	// credentials file's rateLimitTier (e.g. "max_5x" → "Max 5x").
	// Empty when unknown.
	Tier string

	// FetchedAt is the time the PlanUsage was retrieved.
	FetchedAt time.Time
}

PlanUsage is the snapshot of the user's plan-quota state at FetchedAt.

type PlanUsageSource

type PlanUsageSource interface {
	Fetch(ctx context.Context) (PlanUsage, error)
}

PlanUsageSource fetches plan-quota usage from the active LLM provider.

Contract:

  • Fetch returns a fully-populated PlanUsage on success.
  • Fetch returns ErrPlanUsageUnavailable when credentials are missing or the user is not on a metered plan; callers SHOULD degrade gracefully (e.g. hide the plan-quota bars).
  • Fetch returns ErrPlanUsageAuth when credentials exist but are invalid / expired beyond refresh; callers SHOULD prompt the user to re-auth (e.g. run `claude` again).
  • Network errors are returned wrapped — callers MAY display a stale last-good value if they cache.
  • Implementations MUST be safe for concurrent calls.

type PlanWindow

type PlanWindow struct {
	// Utilization is the 0–100 percentage of plan quota consumed in this window.
	// Values may exceed 100 when the user is over-limit and on extra-usage credits.
	Utilization float64

	// ResetsAt is the wall-clock time when the window resets.
	// Zero when unknown — callers SHOULD treat it as "no countdown".
	ResetsAt time.Time

	// Present is false when the backend response did not include this window
	// (e.g. an A/B-test variant renamed the key). Callers SHOULD hide the
	// bar entirely rather than drawing a 0% value.
	Present bool
}

PlanWindow describes one rolling-window quota.

type ProcessSource

type ProcessSource interface {
	RunningClaudeSessionIDs(ctx context.Context) ([]session.ID, error)
}

ProcessSource is an optional port for detecting running `claude` CLI processes by their `--session-id` flag. Used by the livesession layer to mark sessions as live even when their JSONL is mtime-stale — `/resume`-d sessions sit idle waiting for the next user prompt and would otherwise drop out of the title-bar tab strip after the 90-second activeSessionWindow even though the process is still running and the user clearly wants to come back to it.

Implementations MUST:

  • Return ALL session IDs that appear in a live `claude` argv on the host, regardless of the cwd that process was launched in. The livesession layer filters down to the current project by intersecting with the per-cwd session list (set membership) — ProcessSource itself is cwd-agnostic so it stays trivial to implement and test.
  • Return an empty slice + nil error when no `claude` processes are running. Errors are reserved for genuine failures (cannot read /proc, `ps` invocation fails, etc.).
  • Be cheap enough to call on every TUI poll (~1s cadence). A single `ps` shell-out fits.

type SessionSource

type SessionSource interface {
	// Sessions returns all Sessions belonging to the given Project working
	// directory, ordered by latest activity descending. May be empty.
	Sessions(ctx context.Context, projectCWD string) ([]session.Summary, error)

	// Events returns all Events for the given Session in strictly ascending
	// chronological order. May be empty.
	Events(ctx context.Context, id session.ID) ([]event.Event, error)
}

SessionSource is the port through which the application layer discovers and reads Sessions for a Project. Implementations MUST:

  • Surface all Sessions for the given project CWD, ordered by latest activity descending. Empty directory → empty slice, no error.
  • Return Events for a Session in strictly ascending chronological order.
  • Preserve Events with unknown kinds as opaque Events — never drop them.
  • NOT modify any underlying storage (reads are observational only).

type SubagentInfo

type SubagentInfo struct {
	// AgentID is the identifier parsed from the JSONL filename, e.g.
	// "agent-a09b7f25bb46ce5bc" from "agent-a09b7f25bb46ce5bc.jsonl".
	AgentID string

	// Description is the human-readable description from the agent's meta.json file.
	// Empty if no meta.json exists.
	Description string

	// AgentType is the type of the agent (e.g. "general-purpose").
	// Empty if no meta.json exists.
	AgentType string
}

SubagentInfo describes a single subagent that ran under a parent session.

type SubagentSource

type SubagentSource interface {
	// Subagents lists all subagent infos for the given parent session.
	// projectCWD is needed to locate the encoded project directory.
	// Returns an empty slice (no error) when no subagents exist.
	Subagents(ctx context.Context, projectCWD string, parentSessionID string) ([]SubagentInfo, error)

	// SubagentEvents returns all events from the given subagent's JSONL file
	// in file order (ascending chronological). projectCWD and parentSessionID
	// are needed to locate the file.
	SubagentEvents(ctx context.Context, projectCWD string, parentSessionID string, agentID string) ([]event.Event, error)
}

SubagentSource is the port through which the application layer discovers and reads subagent JSONL files associated with a parent session.

Subagent files live at:

~/.claude/projects/<encoded-cwd>/<sessionID>/subagents/agent-<id>.jsonl

Implementations MUST:

  • Return an empty slice with no error when the subagents directory is absent (most sessions have no subagents).
  • Preserve subagent events with unknown kinds as KindOpaque — never drop them.

Jump to

Keyboard shortcuts

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