hub

package
v0.2.49 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: GPL-2.0, GPL-3.0 Imports: 38 Imported by: 0

Documentation

Overview

Package hub coordinates the server's per-chat runtime: SSE fan-out, ACP bridge lifecycle, and POST /api/command dispatch — plus the service surfaces that ride the shared utility bridge (knowledge, specs, hooks, governance, account usage, policy), checkpoint HTTP, agent terminals, the browser PTY shell shim, and the MCP runtime registry.

This file defines Hub and its top-level wiring. Command dispatch is hosted via internal/command (adapters in command_deps.go), ACP translation via internal/translate (adapters in translate_deps.go), SSE transport in sse.go, bridge lifecycle in bridge_lifecycle.go and bridge_coord.go, the shell shim in shell.go, agent terminals in agent_terminal.go, utility-bridge services in knowledge.go / spec.go / hooks.go / governance.go / account_usage.go / permissions_policy.go, and checkpoint HTTP in checkpoint_http.go.

Package hub shell subsystem provides a single global PTY session with server-side VT parsing.

The shell runs in a real pseudo-terminal (creack/pty) so interactive programs (vim, htop, less, tab completion) work correctly. I/O flows over a WebSocket at /api/shell/ws using a compact binary wire protocol (see github.com/cplieger/web-terminal-engine/v2/terminal). The server maintains a VT500 screen buffer (github.com/cplieger/web-terminal-engine/v2/vt) and sends only changed rows to the client on each flush tick — dramatically reducing bandwidth vs. raw-byte streaming, and enabling a lightweight DOM-based renderer on the client (no xterm.js dependency).

On reconnect the server replays the full screen snapshot + scrollback history so the client can reconstruct terminal state without needing the raw byte stream.

Wire protocol (binary WebSocket frames):

client → server: raw terminal input bytes
server → client: binary frames (screen/scroll/resumeAck/modes)
client → server: JSON control messages prefixed with 0x00:
  {"type":"resize","cols":N,"rows":N}

The 0x00 prefix byte distinguishes control messages from raw input; no valid terminal input starts with NUL.

Index

Constants

This section is empty.

Variables

View Source
var CheapestModel = cheapestModel

CheapestModel is the exported alias retained for backward compatibility with existing call sites. New code should use cheapestModel directly within the hub package.

Functions

This section is empty.

Types

type BridgeCoordinator

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

BridgeCoordinator encapsulates bridge lifecycle management: creating, loading, priming, forwarding notifications, model switching, and turn finalization. Hub delegates to this coordinator, reducing the hub's role to HTTP/SSE dispatch.

func (*BridgeCoordinator) CloseBridge

func (bc *BridgeCoordinator) CloseBridge(chatID api.ChatID)

CloseBridge stops a bridge and removes it from the map.

func (*BridgeCoordinator) EmitTurnEndedWithStats

func (bc *BridgeCoordinator) EmitTurnEndedWithStats(ctx context.Context, chatID api.ChatID, resp *api.RPCResponse, creditsDelta, elapsedMs float64, closeAndRemovePartial func(context.Context, api.ChatID, *buffer.Buffer))

EmitTurnEndedWithStats finalizes any in-flight assistant message and broadcasts turn_ended with the credit delta and elapsed time.

func (*BridgeCoordinator) FlushInFlightTurnOnSwitch

func (bc *BridgeCoordinator) FlushInFlightTurnOnSwitch(ctx context.Context, chatID api.ChatID, closeAndRemovePartial func(context.Context, api.ChatID, *buffer.Buffer))

FlushInFlightTurnOnSwitch drops the assistant buffer and its .partial sibling for chatID before a bridge restart.

func (*BridgeCoordinator) Forward

func (bc *BridgeCoordinator) Forward(chatID api.ChatID, bridge api.ACPBridge)

Forward is the ACP notification → domain event translator, run as a goroutine per bridge.

func (*BridgeCoordinator) GetBridge

func (bc *BridgeCoordinator) GetBridge(chatID api.ChatID) *sharedBridge

GetBridge returns the bridge for chatID, or nil.

func (*BridgeCoordinator) GetOrCreateBridge

func (bc *BridgeCoordinator) GetOrCreateBridge(ctx context.Context, chatID api.ChatID, modelOverride string) (*sharedBridge, error)

GetOrCreateBridge returns an existing bridge for chatID, or creates one. Concurrent callers for the same chatID coalesce via singleflight.

func (*BridgeCoordinator) NotifyPush

func (bc *BridgeCoordinator) NotifyPush(ctx context.Context, body string, kind api.PushKind)

NotifyPush sends a push notification if the push service is configured.

func (*BridgeCoordinator) PersistModelSwitch

func (bc *BridgeCoordinator) PersistModelSwitch(ctx context.Context, chatID api.ChatID, model string, contextSize int)

PersistModelSwitch records the switch event and updates the chat's model + resets usage counters.

func (*BridgeCoordinator) PrimeIfNeeded

func (bc *BridgeCoordinator) PrimeIfNeeded(ctx context.Context, chatID api.ChatID, sb *sharedBridge)

PrimeIfNeeded sends the chat history as an ephemeral priming prompt on the current bridge.

func (*BridgeCoordinator) TakeBuffer

func (bc *BridgeCoordinator) TakeBuffer(chatID api.ChatID) (*buffer.Buffer, bool)

TakeBuffer returns and removes the chat's assistant buffer.

func (*BridgeCoordinator) TryFastModelSwitch

func (bc *BridgeCoordinator) TryFastModelSwitch(ctx context.Context, chatID api.ChatID, model string) bool

TryFastModelSwitch attempts an in-session model swap via session/set_config_option (configId "model") on the running bridge.

type Hub

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

Hub is the central coordinator.

func New

func New(workDir string, factory api.ACPBridgeFactory, chatStore api.ChatStore, opts ...Option) *Hub

New constructs a Hub. Bridges spawn with a fixed kiro-cli acp arg set (agent engine + model + effort); tool-call authorization is owned by kiro-cli's native Cedar policy on v3, not by CLI trust flags.

func (*Hub) AccountUsage added in v0.1.165

func (h *Hub) AccountUsage(ctx context.Context) (*api.AccountUsage, error)

AccountUsage fetches account/subscription usage via the utility bridge and parses the KAS getUsage result into the domain shape. Lazily constructs the utility bridge (same pattern as UtilityPrompt) so the footer works even when no chat is open. Satisfies api.AccountUsageProvider.

func (*Hub) AdvanceCheckpointTurn

func (h *Hub) AdvanceCheckpointTurn(ctx context.Context, chatID api.ChatID)

AdvanceCheckpointTurn bumps the checkpoint turn counter.

func (*Hub) BridgeNotify

func (h *Hub) BridgeNotify(ctx context.Context, chatID api.ChatID, method string, params map[string]any) error

BridgeNotify sends a notification to the bridge for the given chat.

func (*Hub) BridgeRespond

func (h *Hub) BridgeRespond(ctx context.Context, chatID api.ChatID, requestID int64, result any, err error) error

BridgeRespond sends a response to the bridge for the given chat.

func (*Hub) Broadcast

func (h *Hub) Broadcast(_ context.Context, evt api.ServerEvent)

Broadcast sends a ServerEvent to every connected SSE client. Used by the chat store (chat_created / chat_updated / message_* etc.) and by the hub itself for turn_ended / permission_needed / error.

func (*Hub) BufferStore

func (h *Hub) BufferStore() translate.BufferAccess

BufferStore returns the buffer store for streaming handlers.

func (*Hub) CaptureEditorSave added in v0.2.8

func (h *Hub) CaptureEditorSave(ctx context.Context, absPath string, content []byte)

CaptureEditorSave records a built-in-editor save as a checkpoint snapshot in the owning chat's timeline. Wired into the filehandler's write observer by the composition root; runs synchronously just BEFORE the editor write lands (same ordering as the agent write path) so Snapshot reads the pre-save disk content as beforeSHA — the undo target — and records the incoming content as afterSHA, keeping the cross-chat index's view of disk current so the next agent write in another chat doesn't raise a spurious drift conflict for a save the user made on purpose.

Routing: the owner is the chat whose agent most recently wrote the file (cross-chat index). A file no agent ever wrote has no checkpoint lineage — no restore will ever touch it — so there is nothing to capture. Saves outside the work tree (e.g. the /config mount) are ignored: checkpoints cover the workspace only.

No turn-tag stamping: the save is not part of an agent turn, so it must not claim the turn-canonical Restore anchor on a prompt message (see stampTurnCheckpointTag). Consequence: a save landing mid-turn before the agent's first write consumes the turn-canonical "N" slot and that one turn offers per-file undo but no whole-turn restore anchor — rare, and strictly better than mislabeling.

Failures are logged, never surfaced: the checkpoint exists to serve the user, not to gate their save.

func (*Hub) ChatInSupervisedMode

func (h *Hub) ChatInSupervisedMode(ctx context.Context, chatID api.ChatID) bool

ChatInSupervisedMode reports whether the chat has supervised mode on.

func (*Hub) ChatStore

func (h *Hub) ChatStore() api.ChatStore

ChatStore returns the hub's chat store.

func (*Hub) CheckDedup

func (h *Hub) CheckDedup(reqID string) ([]byte, bool)

CheckDedup returns a cached response for the given request ID. Satisfies command.Dependencies.

func (*Hub) CheckpointOldestTag

func (h *Hub) CheckpointOldestTag(ctx context.Context, chatID api.ChatID) string

CheckpointOldestTag returns the earliest available checkpoint tag for chatID, or "" when none exist. The chat store reads this when building ChatHeader so the client can decide which turns still have working Restore buttons.

func (*Hub) Checkpoints

func (h *Hub) Checkpoints() api.CheckpointService

Checkpoints returns the checkpoint service, or nil if unavailable.

func (*Hub) CleanupChatState

func (h *Hub) CleanupChatState(ctx context.Context, chatID api.ChatID)

CleanupChatState tears down all in-memory state for a chat that is being permanently deleted (the delete / promote / discard paths), reaping the chat's checkpoints too. The archive path uses OnChatArchiving, which runs the same teardown but preserves checkpoints (archive is reversible).

func (*Hub) CleanupCheckpoints

func (h *Hub) CleanupCheckpoints(ctx context.Context, chatID api.ChatID)

CleanupCheckpoints removes a chat's checkpoint event log (the content-addressed blob store is GC'd separately — there is no git repository involved; see internal/checkpoint/events.go "Why JSONL instead of git"). Safe to call even if the checkpoint store is nil (no configDir).

func (*Hub) ClearPendingPermsForChat

func (h *Hub) ClearPendingPermsForChat(chatID api.ChatID)

ClearPendingPermsForChat drops unresolved permission_needed entries.

func (*Hub) CloseBridge

func (h *Hub) CloseBridge(chatID api.ChatID)

CloseBridge tears down the bridge for a chat.

func (*Hub) ConfigDir

func (h *Hub) ConfigDir() string

ConfigDir returns the configuration directory.

func (*Hub) Draining

func (h *Hub) Draining() bool

Draining reports whether the server is shutting down. Satisfies command.Dependencies.

func (*Hub) EmitTurnEndedWithStats

func (h *Hub) EmitTurnEndedWithStats(ctx context.Context, chatID api.ChatID, resp *api.RPCResponse, creditsDelta, elapsedMs float64)

EmitTurnEndedWithStats broadcasts turn_ended with usage stats.

func (*Hub) EnsureCodeIntelligence added in v0.2.32

func (h *Hub) EnsureCodeIntelligence(ctx context.Context)

EnsureCodeIntelligence initializes workspace code intelligence when needed (see the file comment). Safe to call from any goroutine, any number of times; concurrent callers coalesce on an in-flight guard that re-arms on failure so a transient error retries on the next trigger. Never blocks the caller beyond the stat + gate check when nothing is to do.

func (*Hub) FlushPendingForChat

func (h *Hub) FlushPendingForChat(ctx context.Context, chatID api.ChatID, reason api.ClearReason)

FlushPendingForChat rejects all outstanding pending ops for a chat.

func (*Hub) GetBridge

func (h *Hub) GetBridge(chatID api.ChatID) command.Bridge

GetBridge returns the active bridge for a chat, or nil.

func (*Hub) GetOrCreateBridge

func (h *Hub) GetOrCreateBridge(ctx context.Context, chatID api.ChatID, model string) (command.Bridge, error)

GetOrCreateBridge ensures a bridge exists for the chat.

func (*Hub) Governance added in v0.1.165

func (h *Hub) Governance(ctx context.Context) api.GovernanceStatePayload

Governance returns the cached governance state. On a warm cache it returns immediately; on a cold cache it lazily starts the utility bridge (whose session/new pushes the notification) and waits up to governanceWarmTimeout for the first push. A failure to warm returns a Known=false snapshot so the client leaves governed affordances at their permissive default rather than reading the zero value as "everything disabled".

func (*Hub) InflightAdd

func (h *Hub) InflightAdd(delta int)

InflightAdd increments the inflight counter.

func (*Hub) InflightDone

func (h *Hub) InflightDone()

InflightDone decrements the inflight counter.

func (*Hub) InflightGo

func (h *Hub) InflightGo(fn func())

InflightGo runs fn under the inflight WaitGroup.

func (*Hub) IsEmptyTurn

func (h *Hub) IsEmptyTurn(resp *api.RPCResponse, chatID api.ChatID) bool

IsEmptyTurn checks if a prompt response is an empty turn.

func (*Hub) IsHookStatusEnabled

func (h *Hub) IsHookStatusEnabled() bool

IsHookStatusEnabled returns whether hook status display is enabled.

func (*Hub) LineTracker

func (h *Hub) LineTracker() translate.LineRecorder

LineTracker returns the line tracker for file-change recording.

func (*Hub) MCPConfig

func (h *Hub) MCPConfig() api.MCPConfig

MCPConfig returns the MCP configuration store.

func (*Hub) MCPRecorder

func (h *Hub) MCPRecorder() translate.MCPRecorder

MCPRecorder returns the Hub's MCP state recorder.

func (*Hub) MCPRegistry

func (h *Hub) MCPRegistry() api.RouteHandler

MCPRegistry returns the in-memory registry of currently-connected MCP servers as an api.RouteHandler (the only surface main.go needs — the registry registers its own HTTP routes). Exposing the concrete type would leak an unexported name from an exported method.

func (*Hub) MCPSnapshot

func (h *Hub) MCPSnapshot() []api.MCPSnapshotServer

MCPSnapshot returns a stable-ordered snapshot of the runtime registry so callers outside hub (e.g. the steering generator) can read it without taking hub internals as a dependency. Only servers in the connected state are included: the steering file presents the list as "Connected integrations", and a failed or OAuth-pending server has no live tools for the agent to call.

func (*Hub) MCPWaitForReady

func (h *Hub) MCPWaitForReady(ctx context.Context, timeout time.Duration) bool

MCPWaitForReady blocks until MCP servers are ready or timeout.

func (*Hub) Models

func (h *Hub) Models() []api.SessionModel

Models is the Snapshotter contract: the first non-empty model list from a live bridge. No aggregation across bridges — they all see the same kiro-cli catalog.

func (*Hub) NotifyPush

func (h *Hub) NotifyPush(ctx context.Context, body string, kind api.PushKind)

NotifyPush sends a push notification.

func (*Hub) OnChatArchived

func (h *Hub) OnChatArchived(chatID api.ChatID)

OnChatArchived is the post-archive callback wired to chat.WithOnArchive. The in-memory teardown (including the line tracker) already ran in OnChatArchiving before the file moved; checkpoints are deliberately NOT reaped here (archive is reversible — a restored chat keeps its file-restore/undo history; only purge / hard delete reap them). All that remains is kicking off the async summary under the hub's inflight WaitGroup so Shutdown can drain it. Skipped entirely when the hub is already draining: no point spawning new work that's about to race teardown.

func (*Hub) OnChatArchiving added in v0.1.165

func (h *Hub) OnChatArchiving(chatID api.ChatID)

OnChatArchiving is the pre-archive hook wired to chat.WithPreArchive. It runs the SAME in-memory teardown a delete performs — flush the in-flight turn (CloseBridge), kill agent terminals, clear pending perms + supervised trust, close+remove the .partial — EXCEPT it does not remove the chat file (Archive moves it) and does not reap checkpoints (archive is reversible; checkpoints are reaped only at purge / hard delete).

It MUST run before the chat file is moved to the archive dir so that:

  • a live bridge can't outlive its chat record (invariant #3),
  • archiving mid-turn can't strand the in-flight turn (the moved file + tombstone would make Store.Mutate refuse the persist), and
  • no orphan .partial survives for RecoverPartials to resurrect as a ghost active chat after a restart.

func (*Hub) OpenPartialFile

func (h *Hub) OpenPartialFile(ctx context.Context, chatID api.ChatID, buf *buffer.Buffer)

OpenPartialFile opens the partial recovery file for a chat.

func (*Hub) ParentACPSession

func (h *Hub) ParentACPSession(chatID api.ChatID) string

ParentACPSession returns the parent ACP session ID for a chat.

func (*Hub) PendingPermsAdd

func (h *Hub) PendingPermsAdd(requestID int64, evt api.ServerEvent)

PendingPermsAdd tracks a pending permission event for SSE replay.

func (*Hub) PendingPermsRemove

func (h *Hub) PendingPermsRemove(requestID int64)

PendingPermsRemove removes a pending permission by request ID.

func (*Hub) PendingStore

func (h *Hub) PendingStore() *pending.Store

PendingStore returns the pending-changes store.

func (*Hub) PolicyExplain added in v0.1.165

func (h *Hub) PolicyExplain(ctx context.Context, req api.PolicyExplainRequest) (*api.PolicyExplainResult, error)

PolicyExplain simulates the policy decision for a capability/resource WITHOUT executing anything or raising a consent prompt (KAS evaluateSingleResource). Exactly one of Capability / ToolID is required; KAS additionally requires a resource for the shell capability.

func (*Hub) PolicyList added in v0.1.165

func (h *Hub) PolicyList(ctx context.Context, scope string) ([]api.PolicyRule, error)

PolicyList returns the native policy rules, optionally filtered to one scope (empty = all scopes). Backed by _kiro/permissions/list on the utility bridge.

func (*Hub) PrimeIfNeeded

func (h *Hub) PrimeIfNeeded(ctx context.Context, chatID api.ChatID, b command.Bridge)

PrimeIfNeeded primes the bridge with history if needed.

func (*Hub) RecordDedup

func (h *Hub) RecordDedup(reqID string, result []byte)

RecordDedup caches a response for idempotent replay. Satisfies command.Dependencies.

func (*Hub) RecoverPartials

func (h *Hub) RecoverPartials()

RecoverPartials scans the chats directory for orphaned .partial files left by a crash. Each is parsed and merged into its chat as an interrupted assistant message. Called once at startup.

Idempotent against the commit-then-delete window: EmitTurnEndedWithStats persists the finalized turn BEFORE deleting the .partial, so a crash after the commit but before the delete leaves a .partial whose MessageID is already in the chat. When that message already exists, recovery skips the append (and the interrupted event) — the turn completed normally, it wasn't a crash — and only removes the orphan.

func (*Hub) RegisterRoutes

func (h *Hub) RegisterRoutes(mux *http.ServeMux)

RegisterRoutes wires /api/events (SSE), /api/command (POST), and /api/shell/ws (WebSocket PTY).

func (*Hub) RemovePendingPerm

func (h *Hub) RemovePendingPerm(requestID int64)

RemovePendingPerm removes a single pending permission by request ID.

func (*Hub) ResolveInsideWorkDir

func (h *Hub) ResolveInsideWorkDir(rel string) (string, error)

ResolveInsideWorkDir validates a path is inside the workspace.

func (*Hub) SetCodeIntelligence added in v0.2.32

func (h *Hub) SetCodeIntelligence(lspConfigPath string, gate func() bool)

SetCodeIntelligence wires the activation inputs: lspConfigPath is the workspace's .kiro/settings/lsp.json, gate reports whether any lsp-marked tool is enabled and installed. Called once at composition; both empty/nil in tests that don't exercise activation.

func (*Hub) SetGovernance added in v0.1.165

func (h *Hub) SetGovernance(p api.GovernanceStatePayload)

SetGovernance caches the latest governance state. Satisfies translate.Deps (called by translate.HandleGovernanceState on the chat-bridge path).

func (*Hub) SetMCPOnChange

func (h *Hub) SetMCPOnChange(fn func())

SetMCPOnChange wires a callback fired whenever the runtime MCP registry changes (server connected, OAuth needed, bridges closed). Used by main.go to re-run steering.Generate() so environment.md tracks the live integration set.

func (*Hub) SetPreBridgeSpawn

func (h *Hub) SetPreBridgeSpawn(fn func(context.Context))

SetPreBridgeSpawn wires a callback fired right before any kiro-cli bridge starts (both fresh `session/new` and `session/load` paths in getOrCreateBridge). Used to refresh `environment.md` so the latest per-repo steering inventory is on disk by the time kiro-cli reads it during session creation.

The callback receives the per-request context so it can short-circuit on client disconnection. It runs synchronously on the spawn path, so it must be fast (the existing steering.Generate is bounded by the workspace walk + skip-if-unchanged write — typically a few ms).

func (*Hub) Shutdown

func (h *Hub) Shutdown()

Shutdown drains in-flight prompts and closes all bridges.

Order matters: we Stop bridges BEFORE waiting on inflight, because blocking on a stuck prompt is exactly the reason the server is shutting down in the first place. Stop closes the bridge's stdin and kills the kiro-cli subprocess, which unblocks any Call waiter via the readLoop sentinel — allowing the prompt handler goroutine to record its error and decrement inflight normally.

Drain vs abort:

draining=true is set first so new commands get 503. Existing
commands are given a chance to finish cleanly; if they can't
(stuck on an unresponsive kiro-cli), the HTTP server's own
shutdown context kills everything after its grace period.

func (*Hub) ShutdownCtx

func (h *Hub) ShutdownCtx() context.Context

ShutdownCtx returns the context cancelled on shutdown.

func (*Hub) StartCheckpointBackgroundTasks

func (h *Hub) StartCheckpointBackgroundTasks()

StartCheckpointBackgroundTasks kicks off the blob GC ticker and runs the initial sweep. Called from main.go after Hub construction so tests can opt out.

func (*Hub) StopCheckpointBackgroundTasks

func (h *Hub) StopCheckpointBackgroundTasks()

StopCheckpointBackgroundTasks halts the blob GC goroutine. Called from Hub.Shutdown.

func (*Hub) SupervisedClearTrust

func (h *Hub) SupervisedClearTrust(chatID api.ChatID, reason api.ClearReason)

SupervisedClearTrust clears the per-turn trust flag.

func (*Hub) SupervisedSetTrust

func (h *Hub) SupervisedSetTrust(chatID api.ChatID)

SupervisedSetTrust sets the per-turn trust flag for a chat.

func (*Hub) UtilityPrompt

func (h *Hub) UtilityPrompt(ctx context.Context, prompt string, effort api.EffortLevel) (string, error)

UtilityPrompt delegates to the utility text-gen agent, satisfying api.UtilityPrompter. The runtime is lazily constructed on first call.

func (*Hub) WorkDir

func (h *Hub) WorkDir() string

WorkDir returns the workspace root directory.

type Option

type Option func(*Hub)

Option configures optional Hub parameters.

func WithConfigDir

func WithConfigDir(dir string) Option

WithConfigDir sets the configuration directory for permissions, checkpoints, and ignore rules.

func WithMCPConfig

func WithMCPConfig(c api.MCPConfig) Option

WithMCPConfig wires the MCP configuration store. The hub reads ACPServers() on every bridge spawn. Accepts a lazy thunk to resolve circular dependencies (mcpStore→hub broadcast).

func WithPush

func WithPush(p api.PushService) Option

WithPush wires the push notification service at construction time.

func WithSessionReaper added in v0.1.165

func WithSessionReaper(r *kirosession.Reaper, refs func(context.Context) map[string]struct{}) Option

WithSessionReaper wires the KAS session reaper and the referenced-session thunk. The reaper removes on-disk kiro-cli/KAS session state: promptly on chat delete (via cleanupChatState) and via a periodic orphan sweep that spares any session id refs reports as still referenced by a live or archived chat. Unset in tests → session reaping is a no-op.

type ShellManager

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

ShellManager wraps the terminal.Handler to provide the same interface the Hub expects (RegisterRoutes, Shutdown). The terminal package handles all PTY lifecycle, VT parsing, binary wire encoding, client fan-out, and reconnect replay internally.

func NewShellManager

func NewShellManager(_ context.Context, workDir string) *ShellManager

NewShellManager creates a ShellManager backed by the terminal package. The command is always bash --login; workDir is the initial CWD. ctx is accepted for interface compatibility but not used (the terminal package manages its own lifecycle via Shutdown).

Jump to

Keyboard shortcuts

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