Documentation
¶
Overview ¶
Package daemon provides file watching, reindex coordination, and daemon lifecycle management for the knowing system of record.
Index ¶
- func AcquireLockfile(dbPath string) error
- func GitDiffFiles(repoPath, oldCommit, newCommit string) (changed, added, deleted []string, err error)
- func GitHeadCommit(repoPath string) (string, error)
- func IsDaemonRunning() (int, bool)
- func PIDFilePath() string
- func ReadPIDFile() (int, error)
- func ReleaseLockfile(dbPath string)
- func RemovePIDFile()
- func WritePIDFile() error
- type CommitEvent
- type Daemon
- func (d *Daemon) GarbageCollect(ctx context.Context, gcFunc func(ctx context.Context) error) error
- func (d *Daemon) RLock()
- func (d *Daemon) RUnlock()
- func (d *Daemon) Start(ctx context.Context) error
- func (d *Daemon) Stop() error
- func (d *Daemon) UnwatchRepo(repoPath string) error
- func (d *Daemon) WatchRepo(repoPath string) error
- type DaemonConfig
- type FileWatcher
- type GitWatcher
- type MCPServer
- type TraceIngestConfig
- type WatchEvent
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AcquireLockfile ¶ added in v0.3.0
AcquireLockfile creates a lockfile at dbPath+".lock" containing the current process PID, using O_CREAT|O_EXCL for atomic creation (mirrors git's lockfile.c pattern). If the lockfile already exists and the recorded PID is alive, an error is returned. If the recorded PID is no longer alive, the stale lockfile is removed and creation is retried once.
func GitDiffFiles ¶
func GitDiffFiles(repoPath, oldCommit, newCommit string) (changed, added, deleted []string, err error)
GitDiffFiles resolves changed, added, and deleted files between two commits using git diff --name-status. If oldCommit is empty, all tracked files are returned as added (initial index). Returns paths relative to repoPath.
func GitHeadCommit ¶
GitHeadCommit reads the HEAD commit hash from a git repository without shelling out to git. It resolves symbolic refs and falls back to packed-refs when loose ref files are missing.
Git HEAD resolution works in two stages:
- Read .git/HEAD. If it contains a raw 40-char hex hash, the repo is in "detached HEAD" state and that hash is returned directly.
- If HEAD contains "ref: refs/heads/main" (a symbolic ref), resolve the ref to a commit hash by reading the loose ref file (.git/refs/heads/main). If the loose file is missing (git may pack refs for performance), fall back to scanning .git/packed-refs for the ref.
func IsDaemonRunning ¶ added in v0.7.1
IsDaemonRunning checks whether a daemon process is alive by reading the PID file and sending signal 0 to the recorded process. Returns (pid, true) if the process is running, (0, false) otherwise.
func PIDFilePath ¶ added in v0.7.1
func PIDFilePath() string
PIDFilePath returns the path to the daemon PID file: ~/.knowing/daemon.pid. If the user's home directory cannot be determined, falls back to /tmp.
func ReadPIDFile ¶ added in v0.7.1
ReadPIDFile reads the PID from the PID file. Returns (0, error) if the file does not exist or contains invalid data.
func ReleaseLockfile ¶ added in v0.3.0
func ReleaseLockfile(dbPath string)
ReleaseLockfile removes the lockfile at dbPath+".lock". Safe to call even if the lockfile does not exist.
func RemovePIDFile ¶ added in v0.7.1
func RemovePIDFile()
RemovePIDFile removes the PID file. Safe to call even if the file does not exist.
func WritePIDFile ¶ added in v0.7.1
func WritePIDFile() error
WritePIDFile writes the current process PID to the PID file.
Types ¶
type CommitEvent ¶
type CommitEvent struct {
RepoPath string
OldCommit string
NewCommit string
ChangedFiles []string // modified files (relative paths)
AddedFiles []string // new files (relative paths)
DeletedFiles []string // removed files (relative paths)
}
CommitEvent describes a commit-level change detected in a repository.
type Daemon ¶
type Daemon struct {
// contains filtered or unexported fields
}
Daemon is the long-lived process that watches repositories for changes, triggers reindexing, and serves MCP queries.
func NewDaemon ¶
func NewDaemon(cfg DaemonConfig) *Daemon
NewDaemon creates a Daemon with the given configuration. Call Start to begin watching and serving.
func (*Daemon) GarbageCollect ¶ added in v0.3.0
GarbageCollect runs garbage collection while holding the write lock to prevent concurrent index writes during the reachability sweep. The gcFunc callback performs the actual GC work (e.g., calling SnapshotManager.GarbageCollect or GarbageCollectFull).
func (*Daemon) RLock ¶
func (d *Daemon) RLock()
RLock acquires a read lock, allowing concurrent readers.
func (*Daemon) Start ¶
Start launches the file watcher, MCP server, and index worker. It blocks until the provided context is cancelled or Stop is called.
func (*Daemon) UnwatchRepo ¶
UnwatchRepo removes a repository from the watch list.
type DaemonConfig ¶
type DaemonConfig struct {
Store types.GraphStore
IndexFunc func(ctx context.Context, repoURL, repoPath, commitHash string, changedFiles []string) error
MCPAddr string
MCPServer MCPServer
// EnrichFunc is called in the background after each successful index run.
// It receives the repo hash and workspace root path to run LSP enrichment.
// If nil, enrichment is skipped.
EnrichFunc func(ctx context.Context, repoHash types.Hash, workspaceRoot string, changedFiles []string) error
// TraceConfig holds configuration for the runtime trace ingestion pipeline.
// If nil or Enabled is false, trace ingestion is not started.
TraceConfig *TraceIngestConfig
// DBPath is the path to the SQLite database file, used by the trace
// ingestor for direct DB access. Must be set when TraceConfig is enabled.
DBPath string
// SnapMgr is the SnapshotManager used to obtain the most recently computed
// HierarchicalTree after each index run. Required for cache invalidation.
// If nil, cache invalidation is skipped.
SnapMgr *snapshot.SnapshotManager
// ResultCache is the SubgraphCache to invalidate after each successful index.
// If nil, no cache invalidation occurs.
ResultCache *cache.SubgraphCache
}
DaemonConfig holds all dependencies the daemon needs, injected as interfaces and callbacks to avoid tight coupling to concrete packages.
type FileWatcher ¶
type FileWatcher struct {
// contains filtered or unexported fields
}
FileWatcher monitors repositories for file changes, debouncing rapid successive writes into single events with a configurable quiet threshold.
func NewFileWatcher ¶
func NewFileWatcher(debounce time.Duration) (*FileWatcher, error)
NewFileWatcher creates a watcher with the given debounce duration. Events are emitted on the channel returned by Events().
func (*FileWatcher) Add ¶
func (fw *FileWatcher) Add(repoPath string) error
Add registers a repository directory for watching.
func (*FileWatcher) Close ¶
func (fw *FileWatcher) Close() error
Close shuts down the watcher and closes the events channel.
func (*FileWatcher) Events ¶
func (fw *FileWatcher) Events() <-chan WatchEvent
Events returns a read-only channel of debounced watch events.
func (*FileWatcher) Remove ¶
func (fw *FileWatcher) Remove(repoPath string) error
Remove stops watching a repository directory.
type GitWatcher ¶
type GitWatcher struct {
// contains filtered or unexported fields
}
GitWatcher monitors repositories for git commits by watching .git/HEAD and .git/refs/heads/*. It uses fsnotify on these specific paths (one or two file descriptors per repo) rather than watching all source files, keeping the descriptor count low even for large repositories.
The watch flow: fsnotify fires on .git/HEAD or ref file writes -> debounce coalesces rapid writes (e.g., rebase) -> re-read HEAD -> if commit hash changed, run git diff to determine changed files -> emit CommitEvent.
func NewGitWatcher ¶
func NewGitWatcher(debounce time.Duration) (*GitWatcher, error)
NewGitWatcher creates a GitWatcher with the given debounce duration. Events are emitted on the channel returned by Events().
func (*GitWatcher) Add ¶
func (gw *GitWatcher) Add(repoPath string) error
Add registers a repository for commit watching. It reads the current HEAD commit hash as the baseline and watches .git/HEAD and .git/refs/heads/.
func (*GitWatcher) Close ¶
func (gw *GitWatcher) Close() error
Close shuts down the watcher and waits for the event loop to exit.
func (*GitWatcher) Events ¶
func (gw *GitWatcher) Events() <-chan CommitEvent
Events returns a read-only channel of commit events.
func (*GitWatcher) Remove ¶
func (gw *GitWatcher) Remove(repoPath string) error
Remove stops watching a repository.
type MCPServer ¶
type MCPServer interface {
ServeStdio(ctx context.Context) error
ServeHTTP(ctx context.Context, addr string) error
}
MCPServer abstracts the MCP transport so the daemon does not import the MCP package directly.
type TraceIngestConfig ¶
type TraceIngestConfig struct {
Enabled bool
OTLPEndpoint string
BatchSize int
BatchInterval time.Duration
}
TraceIngestConfig holds configuration for the runtime trace ingestion pipeline.
type WatchEvent ¶
WatchEvent describes a batch of file changes within a repository.