Documentation
¶
Overview ¶
Package cli provides a unified interactive TUI for config editing, CLI, and SSH sessions.
Design: docs/architecture/config/yang-config-design.md — config editor Detail: editor_draft.go — write-through draft protocol (sub-hub for commit/walk) Detail: editor_session.go — session identity for concurrent editing Detail: editor_annotated.go — annotated view and show column preferences
Package editor provides an interactive configuration editor.
Design: docs/architecture/config/yang-config-design.md — config editor write operations Overview: editor.go — editor state and lifecycle
Index ¶
- Constants
- Variables
- func ApplyPipeFilter(content string, filter PipeFilter) (string, error)
- func ChangePath(configPath, user string) string
- func ChangePrefix(configPath string) string
- func ChangeUser(configPath, changeFilePath string) string
- func DraftPath(configPath string) string
- func FindPipeIndex(tokens []string) int
- func LockPath(configPath string) string
- func NormalizeCompareTarget(target string) string
- func TranscriptEnabled() bool
- func ValidateUser(user string) error
- func WrapExecutorWithTranscript(fn func(string) (string, error), tw *TranscriptWriter) func(string) (string, error)
- type BackupInfo
- type CommandCompleter
- type CommandModeCompleter
- type CommandNode
- type CommitResult
- type Completer
- func (c *Completer) Backends() map[string]string
- func (c *Completer) Complete(input string, contextPath []string) []Completion
- func (c *Completer) GetListKeyEntry(listPath []string) *gyang.Entry
- func (c *Completer) GhostText(input string, contextPath []string) string
- func (c *Completer) SetTree(tree any)
- func (c *Completer) TypeHint(t *gyang.YangType) string
- func (c *Completer) ValidateValueAtPath(path []string, value string) error
- type Completion
- type ConfigValidationError
- type ConfigValidationResult
- type ConfigValidator
- func (v *ConfigValidator) Validate(content string) ConfigValidationResult
- func (v *ConfigValidator) ValidateSemantic(tree *config.Tree) ([]ConfigValidationError, []ConfigValidationError)
- func (v *ConfigValidator) ValidateSyntax(content string) []ConfigValidationError
- func (v *ConfigValidator) ValidateTransition(previous, candidate string) ConfigValidationResult
- func (v *ConfigValidator) ValidateWithYANG(tree *config.Tree) ([]ConfigValidationError, []ConfigValidationError)
- type Conflict
- type ConflictType
- type DashboardFactory
- type EditSession
- type Editor
- func (e *Editor) ActivateLeaf(parentPath []string, leafName string) error
- func (e *Editor) ActivateLeafListValue(path []string, leafListName, value string) error
- func (e *Editor) ActivatePath(path []string) error
- func (e *Editor) ActiveContentAtPath(path []string) string
- func (e *Editor) ActiveSessions() []string
- func (e *Editor) AdoptSession(oldSessionID string) error
- func (e *Editor) AnnotatedView(path []string, columns config.ShowColumns, setFormat bool) string
- func (e *Editor) AutoSelectListEntry(path []string) []string
- func (e *Editor) BlameView() string
- func (e *Editor) CheckDraftChanged() (changed bool, notification string)
- func (e *Editor) Close() error
- func (e *Editor) CommitSession() (*CommitResult, error)
- func (e *Editor) CommitSessionCandidate(stamp time.Time) (*CommitResult, string, error)
- func (e *Editor) ContentAtPath(path []string) string
- func (e *Editor) ContentWithoutUser(username string) string
- func (e *Editor) CopyListEntry(parentPath []string, listName, srcKey, dstKey string) error
- func (e *Editor) CreateEntry(path []string) error
- func (e *Editor) DeactivateLeaf(parentPath []string, leafName string) error
- func (e *Editor) DeactivateLeafListValue(path []string, leafListName, value string) error
- func (e *Editor) DeactivatePath(path []string) error
- func (e *Editor) DeleteByPath(fullPath []string) error
- func (e *Editor) DeleteContainer(path []string, name string) error
- func (e *Editor) DeleteLeafListValue(path []string, leafListName, value string) error
- func (e *Editor) DeleteList(path []string, name string) error
- func (e *Editor) DeleteListEntry(path []string, listName, key string) error
- func (e *Editor) DeleteLive()
- func (e *Editor) DeleteValue(path []string, key string) error
- func (e *Editor) DetectConflicts() []Conflict
- func (e *Editor) Diff() string
- func (e *Editor) DiffGutterEnabled() bool
- func (e *Editor) Dirty() bool
- func (e *Editor) Discard() error
- func (e *Editor) DiscardSessionPath(path []string) error
- func (e *Editor) DisconnectSession(sessionID string) error
- func (e *Editor) EnsureListEntry(parentPath []string, listName, key string) error
- func (e *Editor) HasArchiveNotifier() bool
- func (e *Editor) HasDraft() bool
- func (e *Editor) HasPendingEdit() bool
- func (e *Editor) HasPendingLive() bool
- func (e *Editor) HasPendingSessionChanges() bool
- func (e *Editor) HasReloadNotifier() bool
- func (e *Editor) HasSession() bool
- func (e *Editor) InactiveContentAtPath(path []string) string
- func (e *Editor) InsertLeafListValue(path []string, leafListName, value, position, ref string) error
- func (e *Editor) IsListKeyLeafPath(path []string) bool
- func (e *Editor) ListBackups() ([]BackupInfo, error)
- func (e *Editor) ListKeys(listName string) []string
- func (e *Editor) LivePath() string
- func (e *Editor) LoadDraft() bool
- func (e *Editor) LoadPendingEdit() error
- func (e *Editor) LookupSchemaNode(path []string) config.Node
- func (e *Editor) MarkCommittedContent(content string)
- func (e *Editor) MarkDirty()
- func (e *Editor) NotifyArchive(content []byte) []error
- func (e *Editor) NotifyReload() error
- func (e *Editor) OriginalContent() string
- func (e *Editor) OriginalContentAtPath(path []string) string
- func (e *Editor) OriginalPath() string
- func (e *Editor) PendingChanges(sessionID string) []config.PendingChange
- func (e *Editor) PendingEditDiff() string
- func (e *Editor) PendingEditTime() time.Time
- func (e *Editor) PromptPendingEdit() PendingEditAction
- func (e *Editor) ReadBackupContent(path string) ([]byte, error)
- func (e *Editor) RenameListEntry(parentPath []string, listName, oldKey, newKey string) error
- func (e *Editor) ResolveLeafListValue(fullPath []string) (parentPath []string, leafListName string, ok bool)
- func (e *Editor) RestoreOriginalContent(content string) error
- func (e *Editor) Rollback(backupPath string) error
- func (e *Editor) Save() error
- func (e *Editor) SaveDraft() error
- func (e *Editor) SaveEditState() error
- func (e *Editor) SaveLive() error
- func (e *Editor) SavedDraftContent() string
- func (e *Editor) SensitiveKeys() map[string]bool
- func (e *Editor) SessionChanges(sessionID string) []config.SessionEntry
- func (e *Editor) SessionID() string
- func (e *Editor) SetArchiveNotifier(fn archive.Notifier)
- func (e *Editor) SetDiffGutter(enabled bool)
- func (e *Editor) SetPreCommitValidate(fn func(candidate string) error)
- func (e *Editor) SetReloadNotifier(fn ReloadNotifier)
- func (e *Editor) SetSession(session *EditSession)
- func (e *Editor) SetShowColumn(column string, enabled bool)
- func (e *Editor) SetValue(path []string, key, value string) error
- func (e *Editor) SetView() string
- func (e *Editor) SetWorkingContent(content string)
- func (e *Editor) ShowColumnEnabled(column string) bool
- func (e *Editor) StageCandidate(stamp time.Time) (string, string, error)
- func (e *Editor) Tree() *config.Tree
- func (e *Editor) WalkPath(path []string) *config.Tree
- func (e *Editor) WalkPathWithSchema(path []string) (*config.Tree, config.Node)
- func (e *Editor) WorkingContent() string
- type EditorMode
- type History
- func (h *History) Append(cmd string) bool
- func (h *History) Down() (string, bool)
- func (h *History) Entries() []string
- func (h *History) Load(mode string) []string
- func (h *History) Max() int
- func (h *History) ResetBrowsing()
- func (h *History) Save(mode string)
- func (h *History) Up(currentInput string) (string, bool)
- type LoginWarning
- type Model
- func (m *Model) ApplyResult(r commandResult)
- func (m Model) Completions() []Completion
- func (m Model) ConfirmTimerActive() bool
- func (m Model) ContextPath() []string
- func (m Model) Dirty() bool
- func (m Model) Error() error
- func (m Model) GhostText() string
- func (m Model) Init() tea.Cmd
- func (m Model) InputValue() string
- func (m Model) IsDashboard() bool
- func (m Model) IsMonitoring() bool
- func (m Model) IsPingMonitor() bool
- func (m Model) IsPingMonitorPiped() bool
- func (m Model) IsTemplate() bool
- func (m Model) IsTraceroute() bool
- func (m Model) IsTraceroutePiped() bool
- func (m Model) Mode() EditorMode
- func (m Model) SelectedIndex() int
- func (m *Model) SetAuditRecorder(recorder audit.Recorder, surface, username, remoteAddr string)
- func (m *Model) SetCommandCompleter(cc CommandModeCompleter)
- func (m *Model) SetCommandExecutor(fn func(string) (string, error))
- func (m *Model) SetDashboardFactory(f DashboardFactory)
- func (m *Model) SetHistory(h *History)
- func (m *Model) SetInput(value string)
- func (m *Model) SetLoginWarnings(warnings []LoginWarning)
- func (m *Model) SetMonitorFactory(f MonitorFactory)
- func (m *Model) SetPingFactory(f PingFactory)
- func (m *Model) SetRestartFunc(fn func())
- func (m *Model) SetShutdownFunc(fn func())
- func (m *Model) SetTracerouteFactory(f TracerouteFactory)
- func (m Model) ShowDropdown() bool
- func (m Model) StatusMessage() string
- func (m *Model) SwitchMode(target EditorMode)
- func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *Model) UpdateCompletions()
- func (m Model) ValidationErrors() []ConfigValidationError
- func (m Model) ValidationWarnings() []ConfigValidationError
- func (m Model) View() tea.View
- func (m Model) ViewportContent() string
- type MonitorFactory
- type MonitorSession
- type PendingEditAction
- type PingFactory
- type PipeFilter
- type PluginCompleter
- type ReloadNotifier
- type ShowPipeOpts
- type TracerouteFactory
- type TranscriptWriter
Constants ¶
const ( FmtTree = fmtTree FmtConfig = fmtConfig SrcSaved = srcSaved SrcConfirmed = srcConfirmed CmpRollback = cmdRollback )
Show format and source names for pipes and version display.
Variables ¶
var ( ErrLeafAlreadyInactive = errors.New("leaf already inactive") ErrLeafNotInactive = errors.New("leaf is not inactive") ErrPathAlreadyInactive = errors.New("path already inactive") ErrPathNotInactive = errors.New("path is not inactive") ErrPathNotFound = errors.New("path not found") )
Sentinel errors returned by the leaf and path deactivation helpers. Callers (the CLI verb, the TUI command) use errors.Is to distinguish "no change" from real failures so they can decide whether to surface or swallow the result.
var ( ConflictLive = contract.ConflictLive ConflictStale = contract.ConflictStale )
Re-export contract conflict constants for backward compatibility.
Functions ¶
func ApplyPipeFilter ¶
func ApplyPipeFilter(content string, filter PipeFilter) (string, error)
ApplyPipeFilter applies a single pipe filter to content. Returns error for unknown filter types.
func ChangePath ¶
ChangePath returns the per-user change file path for a given config path and user. Uses filepath.Base on the user to strip directory traversal.
func ChangePrefix ¶
ChangePrefix returns the filename prefix for scanning all change files. Used with store.List(dir) to filter change files from other files.
func ChangeUser ¶
ChangeUser extracts the username from a change file path. Returns empty string if the path is not a valid change file.
func FindPipeIndex ¶
findPipeIndex returns the index of "|" in tokens, or -1 if not found.
func NormalizeCompareTarget ¶
NormalizeCompareTarget maps compare aliases to the shared target names used by SSH and web CLI compare handling.
func TranscriptEnabled ¶
func TranscriptEnabled() bool
TranscriptEnabled returns true if the ze.cli.transcript env var is set to a truthy value.
func ValidateUser ¶
ValidateUser checks whether a user string is safe for use as a change file identifier. Only alphanumeric characters, hyphens, underscores, and dots are allowed. Returns an error for empty strings, "..", or any character outside the whitelist.
func WrapExecutorWithTranscript ¶
func WrapExecutorWithTranscript(fn func(string) (string, error), tw *TranscriptWriter) func(string) (string, error)
WrapExecutorWithTranscript wraps a command executor function so that every command and its response are recorded in the transcript. The original response is returned unchanged.
Types ¶
type BackupInfo ¶
BackupInfo describes a backup file.
type CommandCompleter ¶
type CommandCompleter struct {
// contains filtered or unexported fields
}
CommandCompleter delegates to command.TreeCompleter and converts command.Suggestion to the editor's Completion type at the boundary.
func NewCommandCompleter ¶
func NewCommandCompleter(root *command.Node) *CommandCompleter
NewCommandCompleter creates a completer from a command tree root.
func (*CommandCompleter) Complete ¶
func (c *CommandCompleter) Complete(input string) []Completion
Complete returns completions for the given input.
func (*CommandCompleter) GhostText ¶
func (c *CommandCompleter) GhostText(input string) string
GhostText returns the best single completion for inline display.
func (*CommandCompleter) SetActiveBackends ¶
func (c *CommandCompleter) SetActiveBackends(backends map[string]string)
SetActiveBackends propagates per-component backend names to the tree completer.
type CommandModeCompleter ¶
type CommandModeCompleter interface {
Complete(input string) []Completion
GhostText(input string) string
}
CommandModeCompleter provides completions for command mode. Implemented by CommandCompleter (operational commands) and PluginCompleter (plugin SDK methods).
type CommandNode ¶
CommandNode is an alias for command.Node. Use command.Node directly in new code.
type CommitResult ¶
type CommitResult = contract.CommitResult
CommitResult holds the outcome of a CommitSession attempt. CommitResult is a type alias of contract.CommitResult.
type Completer ¶
type Completer struct {
// contains filtered or unexported fields
}
Completer provides YANG-driven completions.
func NewCompleter ¶
func NewCompleter() *Completer
NewCompleter creates a completer using YANG schema.
func (*Completer) Complete ¶
func (c *Completer) Complete(input string, contextPath []string) []Completion
Complete returns completions for the given input at cursor position. contextPath is the current edit context (e.g., ["bgp", "peer", "192.168.1.1"]).
func (*Completer) GetListKeyEntry ¶
GetListKeyEntry returns the YANG entry for a list's key leaf. For example, peer list with key "address" returns the address leaf entry.
func (*Completer) ValidateValueAtPath ¶
ValidateValueAtPath validates a value against the YANG type at the given path. Returns nil if valid, an error describing why the value is invalid. Path should include the leaf name (e.g., ["bgp", "peer", "1.1.1.1", "receive-hold-time"]).
type Completion ¶
type Completion = contract.Completion
Completion represents a single completion suggestion. Completion is a type alias of contract.Completion.
type ConfigValidationError ¶
type ConfigValidationError struct {
Line int // 1-based line number (0 if unknown)
Column int // 1-based column (0 if unknown)
Message string // Human-readable message
Severity string // severityError or severityWarning
}
ConfigValidationError represents a single validation error or warning.
type ConfigValidationResult ¶
type ConfigValidationResult struct {
Errors []ConfigValidationError
Warnings []ConfigValidationError
}
ConfigValidationResult contains all validation errors and warnings.
func (*ConfigValidationResult) HasErrors ¶
func (r *ConfigValidationResult) HasErrors() bool
HasErrors returns true if there are any errors.
func (*ConfigValidationResult) HasWarnings ¶
func (r *ConfigValidationResult) HasWarnings() bool
HasWarnings returns true if there are any warnings.
type ConfigValidator ¶
type ConfigValidator struct {
// contains filtered or unexported fields
}
ConfigValidator provides configuration text validation. Uses YANG-derived schema for parsing and validation.
func NewConfigValidator ¶
func NewConfigValidator() (*ConfigValidator, error)
NewConfigValidator creates a new config validator. Returns error if YANG schema cannot be loaded.
func (*ConfigValidator) Validate ¶
func (v *ConfigValidator) Validate(content string) ConfigValidationResult
Validate runs all validation levels and returns the result. Detects the config format (hierarchical vs set/set-meta) and uses the appropriate parser. This is necessary because WorkingContent() returns set+meta format when a session is active.
func (*ConfigValidator) ValidateSemantic ¶
func (v *ConfigValidator) ValidateSemantic(tree *config.Tree) ([]ConfigValidationError, []ConfigValidationError)
ValidateSemantic validates semantic constraints on parsed tree. Delegates to ValidateWithYANG for YANG-based validation.
func (*ConfigValidator) ValidateSyntax ¶
func (v *ConfigValidator) ValidateSyntax(content string) []ConfigValidationError
ValidateSyntax validates only syntax using YANG-derived schema.
func (*ConfigValidator) ValidateTransition ¶
func (v *ConfigValidator) ValidateTransition(previous, candidate string) ConfigValidationResult
ValidateTransition validates a candidate config with access to the previous config, so plugin verifiers see deleted roots as runtime reload would. Uses the transition-aware path instead of Validate to avoid running plugin verifiers twice for roots present in both configs.
func (*ConfigValidator) ValidateWithYANG ¶
func (v *ConfigValidator) ValidateWithYANG(tree *config.Tree) ([]ConfigValidationError, []ConfigValidationError)
ValidateWithYANG validates the parsed tree using YANG constraints. Uses recursive ValidateTree for systematic validation of all leaves. Group peers inherit group-level fields merged with peer-level fields. Returns (errors, warnings). Mandatory-missing fields are warnings, value errors are errors.
type Conflict ¶
Conflict describes a single conflict detected during commit. Conflict is a type alias of contract.Conflict.
type ConflictType ¶
type ConflictType = contract.ConflictType
ConflictType is a type alias of contract.ConflictType.
type DashboardFactory ¶
type DashboardFactory = contract.DashboardFactory
DashboardFactory creates a dashboard polling function. The returned function calls commandExecutor("bgp summary") and returns the JSON. DashboardFactory creates a dashboard poller. Type alias of contract.DashboardFactory so ssh, web, and hub use the same type.
type EditSession ¶
type EditSession struct {
User string // User identifier (e.g., "thomas")
Origin string // Origin: "local" for terminal, "ssh" for SSH sessions
ID string // Full session ID matching MetaEntry.SessionKey(): "user@origin%RFC3339time"
StartTime time.Time // When the session was created
}
EditSession represents an editing session identity for concurrent config editing. Each editor instance gets a unique session, used to track authorship in the draft file.
func NewEditSession ¶
func NewEditSession(user, origin string) *EditSession
NewEditSession creates a new editing session with the given user and origin. The session ID matches MetaEntry.SessionKey() format: "user@origin%RFC3339time". The user is sanitized via filepath.Base to prevent path traversal. Callers should validate user with ValidateUser at input boundaries.
func (*EditSession) OrphanedSessions ¶
func (s *EditSession) OrphanedSessions(allSessions []string) []string
OrphanedSessions filters a list of session IDs to those belonging to the same user and origin as this session but with a different timestamp (i.e., from a previous session). Uses "user@origin%" prefix matching -- the % delimiter ensures "thomas@local" does not match "thomasmore@local".
func (*EditSession) UserAtOrigin ¶
func (s *EditSession) UserAtOrigin() string
UserAtOrigin returns "user@origin" for metadata prefixes.
type Editor ¶
type Editor struct {
// contains filtered or unexported fields
}
Editor manages an editing session for a configuration file. The tree is the canonical in-memory representation when treeValid is true. WorkingContent() returns Serialize(tree) when tree is valid, otherwise falls back to stored raw text for configs that can't be parsed.
func NewEditor ¶
NewEditor creates a new editor for the given configuration file. Uses filesystem storage by default. For blob storage, use NewEditorWithStorage.
func NewEditorWithStorage ¶
NewEditorWithStorage creates a new editor backed by the given storage. All file I/O (config, draft, backup, lock) goes through the storage interface.
func (*Editor) ActivateLeaf ¶
ActivateLeaf clears the inactive marker on a leaf at parentPath. Returns ErrLeafNotInactive (wrapped) when the leaf is already active.
func (*Editor) ActivateLeafListValue ¶
ActivateLeafListValue removes "inactive:" prefix from a value in a leaf-list.
func (*Editor) ActivatePath ¶
ActivatePath clears the inactive flag on the container or list entry at path. Strict on path resolution.
Returns ErrPathNotFound or ErrPathNotInactive (wrapped) for the idempotent / mistyped-path cases.
func (*Editor) ActiveContentAtPath ¶
ActiveContentAtPath returns config text showing only active nodes (inactive pruned).
func (*Editor) ActiveSessions ¶
ActiveSessions returns all session IDs with pending changes. Scans change files to include other users' sessions.
func (*Editor) AdoptSession ¶
AdoptSession rewrites all entries belonging to oldSessionID to the current session. Used when a user reconnects and wants to take over an orphaned session's changes.
func (*Editor) AnnotatedView ¶
AnnotatedView returns config content annotated with the enabled metadata columns. When setFormat is true, produces flat set commands; otherwise hierarchical tree. At a sub-path, the metadata tree is walked to match the context path.
func (*Editor) AutoSelectListEntry ¶
AutoSelectListEntry checks if the path ends at a list node with exactly one entry. If so, it returns the expanded path with the single entry's key appended. Otherwise returns the original path unchanged.
func (*Editor) BlameView ¶
BlameView returns a blame-annotated view of the configuration. When no metadata exists, uses an empty MetaTree to produce a consistent hierarchical tree format with empty blame gutters.
func (*Editor) CheckDraftChanged ¶
CheckDraftChanged checks if the draft file has been modified by another session. Uses Storage.Stat for both filesystem (OS mtime) and blob (tracked mtime). Returns true if the draft mtime is newer than the last known mtime. Also re-reads and re-parses the draft on change to update in-memory state.
func (*Editor) CommitSession ¶
func (e *Editor) CommitSession() (*CommitResult, error)
CommitSession commits the current session's changes to config.conf. First saves (change file → draft), then applies draft to config.conf. Returns a CommitResult with conflicts (if any) or the number of applied changes.
func (*Editor) CommitSessionCandidate ¶
CommitSessionCandidate merges the current session's changes into a staged candidate version instead of overwriting the active config file. Session draft/change files are left intact until MarkCommittedContent confirms the daemon promoted the candidate.
func (*Editor) ContentAtPath ¶
ContentAtPath returns the serialized content at the given context path in tree format. Always returns tree (junos-style) format for display, regardless of session state. If the path doesn't resolve, falls back to full tree content.
func (*Editor) ContentWithoutUser ¶
ContentWithoutUser returns the config as it would be without the specified user's changes. Clones the working tree, then reverts each leaf that the user changed to its Previous value. Leaves with no Previous value (new additions by the user) are deleted. Returns serialized tree content, or empty string if no metadata or no changes by that user.
func (*Editor) CopyListEntry ¶
CopyListEntry clones a list entry under a new key at the given path. The parentPath navigates to the tree containing the list. MetaTree is not updated because copy is blocked in session mode (meta is session-only).
func (*Editor) CreateEntry ¶
CreateEntry creates an empty list entry at the given path. The path must end at a list entry (e.g., ["bgp", "peer", "london"]). If the entry already exists, this is a no-op.
func (*Editor) DeactivateLeaf ¶
DeactivateLeaf marks a leaf inactive on the tree at parentPath. The leaf value (if any) is preserved verbatim; PruneInactive removes the entry at apply time so consumers see it as absent. Permissive on absent leaves -- pre-marking before set is allowed, matching the Tree.SetLeafInactive contract; this is what lets a leaf with a YANG default be deactivated without a prior explicit set.
Returns ErrLeafAlreadyInactive (wrapped) when the leaf is already marked, so callers can use errors.Is for idempotent flows.
func (*Editor) DeactivateLeafListValue ¶
DeactivateLeafListValue adds "inactive:" prefix to a value in a leaf-list.
func (*Editor) DeactivatePath ¶
DeactivatePath sets the inactive flag on the container or list entry at path. Strict on path resolution: it rejects non-existent paths rather than silently materializing them (which is what plain SetValue + walkOrCreate would do).
Returns ErrPathNotFound when the path does not resolve in the tree, and ErrPathAlreadyInactive (wrapped) when the inactive flag is already set, so callers can use errors.Is for idempotent flows.
func (*Editor) DeleteByPath ¶
DeleteByPath deletes the element at the given absolute path using schema awareness. It determines whether the target is a leaf, container, or list entry and calls the appropriate delete method.
func (*Editor) DeleteContainer ¶
DeleteContainer removes a container at the given path in the tree.
func (*Editor) DeleteLeafListValue ¶
DeleteLeafListValue removes one member from a leaf-list (the inverse of add-member set). Returns an error if the member is not present.
func (*Editor) DeleteList ¶
DeleteList removes an entire list (all entries) at the given path.
func (*Editor) DeleteListEntry ¶
DeleteListEntry removes a list entry at the given path in the tree.
func (*Editor) DeleteLive ¶
func (e *Editor) DeleteLive()
DeleteLive removes the .live.conf file if it exists. Errors are ignored because the file may not exist.
func (*Editor) DeleteValue ¶
DeleteValue removes a leaf value at the given path in the tree.
func (*Editor) DetectConflicts ¶
DetectConflicts scans pending changes from other sessions and reports live overlaps.
func (*Editor) DiffGutterEnabled ¶
DiffGutterEnabled returns whether the diff gutter (+/-) markers are shown.
func (*Editor) DiscardSessionPath ¶
DiscardSessionPath discards this session's changes at the given path. If path is nil, discards all changes (deletes change file, reloads from base).
func (*Editor) DisconnectSession ¶
DisconnectSession removes another user's change file. In the per-user change file model, each user has their own file, so disconnect simply deletes the other user's change file.
func (*Editor) EnsureListEntry ¶
EnsureListEntry creates a list entry if it does not already exist. Validates the key value against the list's YANG key type.
func (*Editor) HasArchiveNotifier ¶
HasArchiveNotifier returns true if an archive notifier is configured.
func (*Editor) HasPendingEdit ¶
HasPendingEdit returns true if an edit file exists from a previous session.
func (*Editor) HasPendingLive ¶
HasPendingLive returns true if a .live.conf file exists. This indicates an unconfirmed "commit confirmed" from a previous session.
func (*Editor) HasPendingSessionChanges ¶
HasPendingSessionChanges returns true if this session has pending changes in the draft.
func (*Editor) HasReloadNotifier ¶
HasReloadNotifier returns true if a reload notifier is configured. Use this to distinguish "no daemon" from "reload succeeded".
func (*Editor) HasSession ¶
HasSession returns true if a concurrent editing session is active.
func (*Editor) InactiveContentAtPath ¶
InactiveContentAtPath returns config text showing only inactive nodes. Active nodes are pruned; inactive nodes are shown with their full subtree.
func (*Editor) InsertLeafListValue ¶
func (e *Editor) InsertLeafListValue(path []string, leafListName, value, position, ref string) error
InsertLeafListValue inserts a value into a leaf-list at the specified position. path navigates to the container holding the leaf-list. leafListName is the leaf-list field name. position is first/last/before/after, ref is the reference value for before/after.
func (*Editor) IsListKeyLeafPath ¶
IsListKeyLeafPath checks if the last two path elements are a list name and its key leaf keyword. Uses the config schema which flattens choice/case.
func (*Editor) ListBackups ¶
func (e *Editor) ListBackups() ([]BackupInfo, error)
ListBackups returns available backup files, sorted by timestamp descending.
func (*Editor) ListKeys ¶
ListKeys returns the keys for a list at the given path (e.g., "neighbor").
func (*Editor) LivePath ¶
LivePath returns the path to the .live.conf file. This file holds the trial config during a "commit confirmed" window.
func (*Editor) LoadDraft ¶
LoadDraft reads the draft file and loads its content into the editor's in-memory tree. Called on startup to restore previously saved work. Returns false if no draft exists.
func (*Editor) LoadPendingEdit ¶
LoadPendingEdit loads the content from the .edit file.
func (*Editor) LookupSchemaNode ¶
LookupSchemaNode returns the schema node at the terminus of path. Unlike WalkPathWithSchema, this walks the schema only (no tree walk), so it resolves leaves as well as containers and list entries. Used by one-shot CLI verbs that need to dispatch deactivate/activate based on the node kind regardless of whether the value is currently set.
List keys interleaved in the path are skipped (a list child consumes two tokens: its name and its key value).
func (*Editor) MarkCommittedContent ¶
MarkCommittedContent updates editor state after the daemon has promoted a candidate.
func (*Editor) MarkDirty ¶
func (e *Editor) MarkDirty()
MarkDirty marks the editor as having unsaved changes.
func (*Editor) NotifyArchive ¶
NotifyArchive calls the archive notifier if one is configured. Returns nil if no notifier is set or if archival succeeds.
func (*Editor) NotifyReload ¶
NotifyReload calls the reload notifier if one is configured. Returns nil if no notifier is set or if notification succeeds.
func (*Editor) OriginalContent ¶
OriginalContent returns the original file content.
func (*Editor) OriginalContentAtPath ¶
OriginalContentAtPath returns the serialized content from the original (on-disk) config at the given context path in tree format. Re-parses originalContent on each call (config files are small, and this is only called on user interaction, not hot path). Always returns tree format to match ContentAtPath, regardless of the stored format. Returns empty string if path doesn't resolve in the original config.
func (*Editor) OriginalPath ¶
OriginalPath returns the path to the original configuration file.
func (*Editor) PendingChanges ¶
func (e *Editor) PendingChanges(sessionID string) []config.PendingChange
PendingChanges returns the unified pending-change view for a specific session, or all sessions when sessionID is empty.
func (*Editor) PendingEditDiff ¶
PendingEditDiff returns the diff between original and pending edit content. Returns empty string if no edit file exists.
func (*Editor) PendingEditTime ¶
PendingEditTime returns the modification time of the .edit file. Returns zero time if no edit file exists. For blob storage, mod time is unavailable so this returns zero time even when the edit exists; callers handle zero time gracefully in the prompt.
func (*Editor) PromptPendingEdit ¶
func (e *Editor) PromptPendingEdit() PendingEditAction
PromptPendingEdit prompts user about existing uncommitted changes. Reads from stdin, writes to stdout.
func (*Editor) ReadBackupContent ¶
ReadBackupContent reads the content of a backup by its path.
func (*Editor) RenameListEntry ¶
RenameListEntry renames a list entry key at the given path. The parentPath navigates to the tree containing the list. In session mode, the rename is recorded as a structural op in the per-user change file and the in-memory tree/meta are updated immediately.
func (*Editor) ResolveLeafListValue ¶
func (e *Editor) ResolveLeafListValue(fullPath []string) (parentPath []string, leafListName string, ok bool)
ResolveLeafListValue checks whether fullPath terminates inside a leaf-list value (e.g. `bgp filter import no-self-as`). Returns the tree-level parent path (to the container holding the leaf-list), the leaf-list field name, and true if so. Handles list keys interleaved in the path (e.g. `bgp peer peer1 filter import value`).
The Model's TUI dispatch and the one-shot CLI verbs both call this to route deactivate/activate to DeactivateLeafListValue.
func (*Editor) RestoreOriginalContent ¶
RestoreOriginalContent writes the previous committed content back to disk after a failed runtime reload while keeping the current candidate in memory.
func (*Editor) Rollback ¶
Rollback restores the configuration from a backup file. Creates a backup of the current config first, so the rollback itself can be undone.
func (*Editor) Save ¶
Save commits changes: creates backup of original, writes serialized tree. Returns an error when a session is active -- use CommitSession() instead.
func (*Editor) SaveDraft ¶
SaveDraft applies changes from the per-user change file to config.conf.draft. Creates a new draft (base + own changes), then deletes the change file.
func (*Editor) SaveEditState ¶
SaveEditState saves the current working content to the .edit file.
func (*Editor) SaveLive ¶
SaveLive writes the current working content to the .live.conf file. Used by "commit confirmed" to create the trial config.
func (*Editor) SavedDraftContent ¶
SavedDraftContent returns the content of the saved draft file on disk. Returns empty string if no draft exists.
func (*Editor) SensitiveKeys ¶
SensitiveKeys returns the set of leaf names marked ze:sensitive in the schema.
func (*Editor) SessionChanges ¶
func (e *Editor) SessionChanges(sessionID string) []config.SessionEntry
SessionChanges returns the changes for a specific session, or all sessions. If sessionID is empty, returns changes for all sessions (scanning change files).
func (*Editor) SessionID ¶
SessionID returns the current session's ID, or empty string if no session.
func (*Editor) SetArchiveNotifier ¶
SetArchiveNotifier sets an optional function to archive config after save. When set, commit will call this after writing config to disk. When nil (no archive locations configured), no archival is attempted.
func (*Editor) SetDiffGutter ¶
SetDiffGutter enables or disables the diff gutter (+/-) markers.
func (*Editor) SetPreCommitValidate ¶
SetPreCommitValidate sets a function called during SaveDraft to validate the candidate config before writing. If the function returns an error, the save is rejected and the draft is not written.
func (*Editor) SetReloadNotifier ¶
func (e *Editor) SetReloadNotifier(fn ReloadNotifier)
SetReloadNotifier sets an optional function to notify the daemon after save. When set, commit will call this after writing config to disk. When nil (standalone mode), no notification is attempted.
func (*Editor) SetSession ¶
func (e *Editor) SetSession(session *EditSession)
SetSession sets the concurrent editing session identity. When set, SetValue and DeleteValue use write-through to the draft file.
func (*Editor) SetShowColumn ¶
SetShowColumn enables or disables a show column preference. Only valid column names (author, date, source, changes) are accepted.
func (*Editor) SetValue ¶
SetValue sets a leaf value at the given path in the tree. Plain leaf-lists (ValueOrArrayNode) get JunOS add-member semantics: each set appends one member (idempotently); it never replaces the list. The member lands in the multi-value store — the store every serializer reads — not the scalar map, where it would be silently dropped.
func (*Editor) SetView ¶
SetView returns the flat set-format view of the configuration. Always emits bare set commands without metadata (AC-15: exportable format).
func (*Editor) SetWorkingContent ¶
SetWorkingContent sets the working content and parses it into the tree. If parsing fails, falls back to raw text mode (treeValid = false).
func (*Editor) ShowColumnEnabled ¶
ShowColumnEnabled returns whether a show column is enabled.
func (*Editor) StageCandidate ¶
StageCandidate writes the current working config as a timestamped candidate. It does not update the editor's committed state; callers do that only after the daemon promotes the candidate.
func (*Editor) WalkPath ¶
WalkPath navigates the tree using the schema to distinguish containers from list keys. Returns the subtree at the given path, or nil if the path doesn't resolve.
func (*Editor) WalkPathWithSchema ¶
WalkPathWithSchema is the exported form of walkPathWithSchema. Returns the (sub-tree, schema node) pair at the given path. Halts at structural nodes (containers, lists) -- for terminal-leaf lookups use LookupSchemaNode instead.
func (*Editor) WorkingContent ¶
WorkingContent returns the current working content. When a session is active with metadata, returns set+meta format (matching what CommitSession writes). Otherwise returns hierarchical format. Falls back to raw text if tree is not valid.
type EditorMode ¶
type EditorMode int
EditorMode represents the current editor mode.
const ( // ModeConfig is the config editing mode (default when editor loaded). ModeConfig EditorMode = iota // ModeOperational is the operational command mode. ModeOperational )
type History ¶
type History struct {
// contains filtered or unexported fields
}
History manages command history entries with browsing and optional persistence. It owns the entries list, the Up/Down browsing state, and the save/load logic. A nil rw means no persistence (in-memory only, graceful degradation).
func NewHistory ¶
NewHistory creates a History backed by the given reader/writer. Pass nil for no persistence (in-memory only). The username scopes history storage per user (meta/history/<user>/<mode>). The max entry count is read from meta/history/max (default 100).
func (*History) Append ¶
Append adds a command to history with consecutive dedup. Empty commands and commands containing newlines are rejected. Returns true if the entry was added (not a duplicate or invalid).
func (*History) Down ¶
Down recalls the next command from history, or restores the saved input. Returns the value and true if there is something to show, or empty and false if not currently browsing.
func (*History) Load ¶
Load reads the history for the given mode from the store. Returns nil if no history exists or the store is nil. Results are trimmed to the configured max.
func (*History) ResetBrowsing ¶
func (h *History) ResetBrowsing()
ResetBrowsing clears the browsing state without changing entries. Called when the user types a character, so the next Up starts fresh.
type LoginWarning ¶
type LoginWarning = contract.LoginWarning
LoginWarning is a single warning shown at CLI login. Type alias of contract.LoginWarning so ssh, web, and hub use the same type.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the Bubble Tea model for the editor.
func NewCommandModel ¶
func NewCommandModel() Model
NewCommandModel creates a command-only model with no editor. Used by ze cli and plugin CLI where no config file is loaded. The model starts in ModeOperational with config commands unavailable.
func (*Model) ApplyResult ¶
func (m *Model) ApplyResult(r commandResult)
ApplyResult applies a commandResult to the model. Useful for testing to simulate what the Update handler does.
func (Model) Completions ¶
func (m Model) Completions() []Completion
Completions returns the current completion list.
func (Model) ConfirmTimerActive ¶
ConfirmTimerActive returns true if a commit confirm timer is active.
func (Model) ContextPath ¶
ContextPath returns the current context path.
func (Model) InputValue ¶
InputValue returns the current text input value.
func (Model) IsDashboard ¶
IsDashboard returns true if the dashboard is active.
func (Model) IsMonitoring ¶
IsMonitoring returns true if a monitor session is active.
func (Model) IsPingMonitor ¶
IsPingMonitor returns true if the ping monitor is active.
func (Model) IsPingMonitorPiped ¶
IsPingMonitorPiped returns true if a piped ping session is active.
func (Model) IsTemplate ¶
IsTemplate returns true if in template editing mode.
func (Model) IsTraceroute ¶
IsTraceroute returns true if the traceroute monitor is active.
func (Model) IsTraceroutePiped ¶
IsTraceroutePiped returns true if a piped traceroute session is active.
func (Model) SelectedIndex ¶
SelectedIndex returns the currently selected dropdown index.
func (*Model) SetAuditRecorder ¶
SetAuditRecorder sets the audit sink and caller metadata for config mutations.
func (*Model) SetCommandCompleter ¶
func (m *Model) SetCommandCompleter(cc CommandModeCompleter)
SetCommandCompleter sets the command mode completer. When set, command mode provides operational command completions. When nil, command mode has no completions (editor-only / standalone mode). Accepts any CommandModeCompleter (e.g., *CommandCompleter or *PluginCompleter).
func (*Model) SetCommandExecutor ¶
SetCommandExecutor sets the function used to execute operational commands in command mode. The function receives a command string and returns the output or an error. When nil, command mode shows an error on Enter.
func (*Model) SetDashboardFactory ¶
func (m *Model) SetDashboardFactory(f DashboardFactory)
SetDashboardFactory sets the factory used to create dashboard sessions.
func (*Model) SetHistory ¶
SetHistory replaces the model's history with a persistent History. Loads saved entries for the current mode and pre-loads the other mode into modeStates so history is available on mode switch.
func (*Model) SetInput ¶
SetInput sets the text input value. Used by external packages (e.g. SSH) that cannot access the unexported textInput field directly.
func (*Model) SetLoginWarnings ¶
func (m *Model) SetLoginWarnings(warnings []LoginWarning)
SetLoginWarnings sets the login warnings to display in the welcome area. Called by the SSH session after collecting warnings from the daemon.
func (*Model) SetMonitorFactory ¶
func (m *Model) SetMonitorFactory(f MonitorFactory)
SetMonitorFactory sets the factory used to create monitor sessions. When set, streaming commands (e.g., "monitor event") in the interactive TUI enter streaming mode. When nil, streaming commands fall through to the regular executor (non-streaming).
func (*Model) SetPingFactory ¶
func (m *Model) SetPingFactory(f PingFactory)
SetPingFactory sets the factory used to run continuous ping sessions.
func (*Model) SetRestartFunc ¶
func (m *Model) SetRestartFunc(fn func())
SetRestartFunc sets the callback for the "restart" interactive CLI command. When set, typing "restart" prompts for confirmation, then calls fn and quits.
func (*Model) SetShutdownFunc ¶
func (m *Model) SetShutdownFunc(fn func())
SetShutdownFunc sets the callback for the "stop" interactive CLI command. When set, typing "stop" prompts for confirmation, then calls fn and quits.
func (*Model) SetTracerouteFactory ¶
func (m *Model) SetTracerouteFactory(f TracerouteFactory)
SetTracerouteFactory sets the factory used to run traceroute probes.
func (Model) ShowDropdown ¶
ShowDropdown returns true if the completion dropdown is visible.
func (Model) StatusMessage ¶
StatusMessage returns the current status message.
func (*Model) SwitchMode ¶
func (m *Model) SwitchMode(target EditorMode)
SwitchMode switches the editor to the given mode, saving and restoring screen state.
func (*Model) UpdateCompletions ¶
func (m *Model) UpdateCompletions()
UpdateCompletions refreshes the completion list based on current input. Useful for testing to ensure completions are populated.
func (Model) ValidationErrors ¶
func (m Model) ValidationErrors() []ConfigValidationError
ValidationErrors returns the current validation errors.
func (Model) ValidationWarnings ¶
func (m Model) ValidationWarnings() []ConfigValidationError
ValidationWarnings returns the current validation warnings.
func (Model) ViewportContent ¶
ViewportContent returns the content currently displayed in the viewport.
type MonitorFactory ¶
type MonitorFactory = contract.MonitorFactory
MonitorFactory creates a monitor session for the given arguments. The context controls the session lifetime; cancel stops delivery. args are the parsed monitor keywords (e.g., ["peer", "10.0.0.1"]). MonitorFactory creates a monitor session. Type alias of contract.MonitorFactory so ssh, web, and hub use the same type.
type MonitorSession ¶
type MonitorSession = contract.MonitorSession
MonitorSession represents an active monitor streaming session inside the TUI. The model holds at most one active session. Events arrive on EventChan; the model polls with a ticker and appends them to the viewport. MonitorSession represents an active monitor streaming session inside the TUI. Type alias of contract.MonitorSession so ssh, web, and hub use the same type.
type PendingEditAction ¶
type PendingEditAction int
PendingEditAction represents user's choice for pending edit file.
const ( // PendingEditContinue - continue editing from pending file. PendingEditContinue PendingEditAction = iota // PendingEditDiscard - discard pending file, start fresh. PendingEditDiscard // PendingEditQuit - quit without editing. PendingEditQuit )
type PingFactory ¶
type PingFactory func(ctx context.Context, target string, interval, timeout time.Duration) (<-chan map[string]any, context.CancelFunc, error)
PingFactory starts a continuous ping session. The returned channel receives per-reply results until the context is canceled.
type PipeFilter ¶
type PipeFilter struct {
Type string // "grep", "head", "tail", "format", "compare"
Arg string // Pattern or count
}
PipeFilter represents a filter in a pipe chain.
func ParsePipeFilters ¶
func ParsePipeFilters(tokens []string) []PipeFilter
ParsePipeFilters parses pipe filter tokens into PipeFilter structs.
type PluginCompleter ¶
type PluginCompleter struct {
// contains filtered or unexported fields
}
PluginCompleter provides tab completion for plugin SDK methods. Used by `ze bgp plugin cli` interactive mode after 5-stage negotiation.
func NewPluginCompleter ¶
func NewPluginCompleter() *PluginCompleter
NewPluginCompleter creates a completer for plugin SDK methods.
func (*PluginCompleter) Complete ¶
func (c *PluginCompleter) Complete(input string) []Completion
Complete returns completions for the given input.
func (*PluginCompleter) GhostText ¶
func (c *PluginCompleter) GhostText(input string) string
GhostText returns the best single completion for inline display.
type ReloadNotifier ¶
type ReloadNotifier func() error
ReloadNotifier is called after a successful save to notify the running daemon. Returns nil on success, or an error if the daemon could not be reached.
func NewSocketReloadNotifier ¶
func NewSocketReloadNotifier(socketPath string) ReloadNotifier
NewSocketReloadNotifier creates a ReloadNotifier that triggers config reload via the daemon's API socket. It sends the "ze-system:daemon-reload" RPC using NUL-framed JSON, the same protocol the CLI uses.
If the socket does not exist or the daemon is not running, the returned function returns an error (which cmdCommit handles gracefully).
type ShowPipeOpts ¶
type ShowPipeOpts struct {
Format string // "tree" (default) or "config"
CompareTarget string // "", "confirmed", "saved", "rollback N"
TreeFilter string // "", "active", "inactive"
Blame bool // show | blame
Changes bool // show | changes
ChangesAll bool // show | changes all
Errors bool // show | errors
History bool // show | history
TextFilters []PipeFilter // remaining text filters (match, head, tail)
}
ShowPipeOpts holds the classified result of show-specific pipe filters.
func ClassifyShowPipes ¶
func ClassifyShowPipes(filters []PipeFilter) (ShowPipeOpts, error)
ClassifyShowPipes separates show-specific pipes (format, compare, active/inactive) from text filters (match, head, tail). Both the SSH and web CLI call this so the classification logic lives in one place.
type TracerouteFactory ¶
type TracerouteFactory func(ctx context.Context, target string, maxHops int) (<-chan map[string]any, context.CancelFunc, error)
TracerouteFactory starts a streaming probe round. The returned channel receives individual hop results as ICMP responses arrive. It is closed when the round completes (after ~1s). Cancel stops the round early.
type TranscriptWriter ¶
type TranscriptWriter struct {
// contains filtered or unexported fields
}
TranscriptWriter records CLI commands and their output to a local file. A nil *TranscriptWriter is a valid no-op receiver.
func NewTranscriptWriter ¶
func NewTranscriptWriter(f *os.File, username, remoteHost string) *TranscriptWriter
NewTranscriptWriter creates a TranscriptWriter that writes to the given file. Writes a header with session metadata. The caller is responsible for creating the file and directory. Returns nil if f is nil.
func (*TranscriptWriter) Close ¶
func (w *TranscriptWriter) Close() error
Close closes the transcript file.
func (*TranscriptWriter) Record ¶
func (w *TranscriptWriter) Record(command, output string)
Record appends a command and its output to the transcript file. Errors are silently ignored (best-effort).
Source Files
¶
- completer.go
- completer_command.go
- completer_plugin.go
- completer_validate.go
- diff.go
- diff_tree.go
- doc.go
- editor.go
- editor_annotated.go
- editor_commands.go
- editor_commit.go
- editor_draft.go
- editor_leaflist.go
- editor_session.go
- editor_walk.go
- history.go
- init.go
- model.go
- model_commands.go
- model_commands_commit.go
- model_commands_edit.go
- model_commands_option.go
- model_commands_session.go
- model_commands_show.go
- model_dashboard.go
- model_dashboard_render.go
- model_dashboard_sort.go
- model_enrich.go
- model_keys.go
- model_load.go
- model_mode.go
- model_monitor.go
- model_ping.go
- model_render.go
- model_search.go
- model_traceroute.go
- reload.go
- transcript.go
- validator.go
- warnings.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Design: docs/architecture/core-design.md — interactive CLI Related: ../../../../cmd/ze/internal/cmdutil/cmdutil.go — shared command utilities (uses BuildCommandTree)
|
Design: docs/architecture/core-design.md — interactive CLI Related: ../../../../cmd/ze/internal/cmdutil/cmdutil.go — shared command utilities (uses BuildCommandTree) |
|
Design: docs/architecture/core-design.md -- component boundaries (cli/contract)
|
Design: docs/architecture/core-design.md -- component boundaries (cli/contract) |
|
Design: docs/architecture/config/yang-config-design.md — editor test infrastructure
|
Design: docs/architecture/config/yang-config-design.md — editor test infrastructure |