daemon

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: May 26, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package daemon provides file watching, reindex coordination, and daemon lifecycle management for the knowing system of record.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcquireLockfile added in v0.3.0

func AcquireLockfile(dbPath string) error

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

func GitHeadCommit(repoPath string) (string, error)

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:

  1. 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.
  2. 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

func IsDaemonRunning() (int, bool)

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

func ReadPIDFile() (int, error)

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

func (d *Daemon) GarbageCollect(ctx context.Context, gcFunc func(ctx context.Context) error) error

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) RUnlock

func (d *Daemon) RUnlock()

RUnlock releases the read lock.

func (*Daemon) Start

func (d *Daemon) Start(ctx context.Context) error

Start launches the file watcher, MCP server, and index worker. It blocks until the provided context is cancelled or Stop is called.

func (*Daemon) Stop

func (d *Daemon) Stop() error

Stop triggers graceful shutdown of the daemon.

func (*Daemon) UnwatchRepo

func (d *Daemon) UnwatchRepo(repoPath string) error

UnwatchRepo removes a repository from the watch list.

func (*Daemon) WatchRepo

func (d *Daemon) WatchRepo(repoPath string) error

WatchRepo registers a repository directory for file watching and future reindexing. If the daemon is already running the directory is added to the live watcher immediately.

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

type WatchEvent struct {
	RepoPath string
	Files    []string
}

WatchEvent describes a batch of file changes within a repository.

Jump to

Keyboard shortcuts

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