discovery

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jan 21, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package discovery provides unified resource discovery from tool-native configurations. This allows agentctl to detect and load resources (rules, skills, hooks, etc.) from tool-specific directories like .claude/, .gemini/, .cursor/ even without agentctl.json.

Index

Constants

View Source
const MaxFileSize = 1 << 20 // 1MB

MaxFileSize is the default maximum file size to read (1MB)

Variables

View Source
var DefaultReader = NewSafeReader()

DefaultReader is a package-level SafeReader for convenience

Functions

func DiscoverAgents

func DiscoverAgents(dir string) []*agent.Agent

DiscoverAgents scans all detected tools for agents in the given directory

func DiscoverGlobalAgents

func DiscoverGlobalAgents() []*agent.Agent

DiscoverGlobalAgents scans all tools for global agents

func DiscoverHooks

func DiscoverHooks(dir string) []*hook.Hook

DiscoverHooks scans all detected tools for hooks

func DiscoverRules

func DiscoverRules(dir string) []*rule.Rule

DiscoverRules scans all detected tools for rules

func DiscoverSkills

func DiscoverSkills(dir string) []*skill.Skill

DiscoverSkills scans all detected tools for skills

func HasToolConfig

func HasToolConfig(dir string) bool

HasToolConfig checks if any tool has a config in the given directory

func Register

func Register(s Scanner)

Register adds a scanner to the registry

func SafeReadFile

func SafeReadFile(path string) ([]byte, error)

SafeReadFile reads a file using the default SafeReader

func ToolConfigPaths

func ToolConfigPaths(dir string) map[string]string

ToolConfigPaths returns paths to all detected tool configs

Types

type AgentScanner

type AgentScanner interface {
	Scanner
	// ScanAgents discovers agents from the tool's local config directory
	ScanAgents(dir string) ([]*agent.Agent, error)
	// ScanGlobalAgents discovers agents from the tool's global config directory
	ScanGlobalAgents() ([]*agent.Agent, error)
}

AgentScanner defines the interface for discovering agents/subagents

type ClaudeScanner

type ClaudeScanner struct{}

ClaudeScanner discovers resources from Claude Code's .claude/ directory

func (*ClaudeScanner) Detect

func (s *ClaudeScanner) Detect(dir string) bool

func (*ClaudeScanner) Name

func (s *ClaudeScanner) Name() string

func (*ClaudeScanner) ScanAgents

func (s *ClaudeScanner) ScanAgents(dir string) ([]*agent.Agent, error)

ScanAgents discovers agents from the project's local .claude/agents/ directory

func (*ClaudeScanner) ScanCommands

func (s *ClaudeScanner) ScanCommands(dir string) ([]*command.Command, error)

func (*ClaudeScanner) ScanGlobalAgents

func (s *ClaudeScanner) ScanGlobalAgents() ([]*agent.Agent, error)

ScanGlobalAgents discovers agents from Claude's global ~/.claude/agents/ directory

func (*ClaudeScanner) ScanGlobalCommands

func (s *ClaudeScanner) ScanGlobalCommands() ([]*command.Command, error)

ScanGlobalCommands discovers commands from Claude's global config directory

func (*ClaudeScanner) ScanGlobalHooks

func (s *ClaudeScanner) ScanGlobalHooks() ([]*hook.Hook, error)

ScanGlobalHooks discovers hooks from Claude's global settings

func (*ClaudeScanner) ScanGlobalPlugins

func (s *ClaudeScanner) ScanGlobalPlugins() ([]*Plugin, error)

ScanGlobalPlugins discovers plugins from Claude's global plugin config

func (*ClaudeScanner) ScanGlobalRules

func (s *ClaudeScanner) ScanGlobalRules() ([]*rule.Rule, error)

ScanGlobalRules discovers rules from Claude's global config directory

func (*ClaudeScanner) ScanGlobalSkills

func (s *ClaudeScanner) ScanGlobalSkills() ([]*skill.Skill, error)

ScanGlobalSkills discovers skills from Claude's global config directory

func (*ClaudeScanner) ScanHooks

func (s *ClaudeScanner) ScanHooks(dir string) ([]*hook.Hook, error)

func (*ClaudeScanner) ScanPlugins

func (s *ClaudeScanner) ScanPlugins(dir string) ([]*Plugin, error)

ScanPlugins discovers plugins from the project's local plugin config

func (*ClaudeScanner) ScanRules

func (s *ClaudeScanner) ScanRules(dir string) ([]*rule.Rule, error)

func (*ClaudeScanner) ScanServers

func (s *ClaudeScanner) ScanServers(dir string) ([]*mcp.Server, error)

func (*ClaudeScanner) ScanSkills

func (s *ClaudeScanner) ScanSkills(dir string) ([]*skill.Skill, error)

type DirectoryScanner

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

DirectoryScanner is a config-driven scanner for discovering resources from tool-native directories.

func NewDirectoryScanner

func NewDirectoryScanner(cfg ScannerConfig) *DirectoryScanner

NewDirectoryScanner creates a new DirectoryScanner with the given config.

func (*DirectoryScanner) Detect

func (s *DirectoryScanner) Detect(dir string) bool

func (*DirectoryScanner) Name

func (s *DirectoryScanner) Name() string

func (*DirectoryScanner) ScanAgents

func (s *DirectoryScanner) ScanAgents(dir string) ([]*agent.Agent, error)

ScanAgents discovers agents from the tool's local agents directory

func (*DirectoryScanner) ScanCommands

func (s *DirectoryScanner) ScanCommands(dir string) ([]*command.Command, error)

func (*DirectoryScanner) ScanGlobalAgents

func (s *DirectoryScanner) ScanGlobalAgents() ([]*agent.Agent, error)

ScanGlobalAgents discovers agents from the tool's global agents directory

func (*DirectoryScanner) ScanHooks

func (s *DirectoryScanner) ScanHooks(dir string) ([]*hook.Hook, error)

func (*DirectoryScanner) ScanRules

func (s *DirectoryScanner) ScanRules(dir string) ([]*rule.Rule, error)

func (*DirectoryScanner) ScanServers

func (s *DirectoryScanner) ScanServers(dir string) ([]*mcp.Server, error)

func (*DirectoryScanner) ScanSkills

func (s *DirectoryScanner) ScanSkills(dir string) ([]*skill.Skill, error)

type GeminiScanner

type GeminiScanner struct{}

GeminiScanner discovers resources from Gemini CLI's .gemini/ directory

func (*GeminiScanner) Detect

func (s *GeminiScanner) Detect(dir string) bool

func (*GeminiScanner) Name

func (s *GeminiScanner) Name() string

func (*GeminiScanner) ScanCommands

func (s *GeminiScanner) ScanCommands(dir string) ([]*command.Command, error)

func (*GeminiScanner) ScanGlobalCommands

func (s *GeminiScanner) ScanGlobalCommands() ([]*command.Command, error)

ScanGlobalCommands discovers commands from Gemini's global config directory

func (*GeminiScanner) ScanGlobalHooks

func (s *GeminiScanner) ScanGlobalHooks() ([]*hook.Hook, error)

ScanGlobalHooks discovers hooks from Gemini's global settings

func (*GeminiScanner) ScanGlobalRules

func (s *GeminiScanner) ScanGlobalRules() ([]*rule.Rule, error)

ScanGlobalRules discovers rules from Gemini's global config directory

func (*GeminiScanner) ScanGlobalSkills

func (s *GeminiScanner) ScanGlobalSkills() ([]*skill.Skill, error)

ScanGlobalSkills discovers skills from Gemini's global config directory

func (*GeminiScanner) ScanHooks

func (s *GeminiScanner) ScanHooks(dir string) ([]*hook.Hook, error)

func (*GeminiScanner) ScanRules

func (s *GeminiScanner) ScanRules(dir string) ([]*rule.Rule, error)

func (*GeminiScanner) ScanServers

func (s *GeminiScanner) ScanServers(dir string) ([]*mcp.Server, error)

func (*GeminiScanner) ScanSkills

func (s *GeminiScanner) ScanSkills(dir string) ([]*skill.Skill, error)

type GlobalScanner

type GlobalScanner interface {
	Scanner
	// ScanGlobalRules discovers rules from the tool's global config directory
	ScanGlobalRules() ([]*rule.Rule, error)
	// ScanGlobalSkills discovers skills from the tool's global config directory
	ScanGlobalSkills() ([]*skill.Skill, error)
	// ScanGlobalCommands discovers commands from the tool's global config directory
	ScanGlobalCommands() ([]*command.Command, error)
	// ScanGlobalHooks discovers hooks from the tool's global settings
	ScanGlobalHooks() ([]*hook.Hook, error)
}

GlobalScanner defines the interface for discovering global resources

type NativeResource

type NativeResource struct {
	Type     string // "rule", "skill", "command", "hook", "server", "plugin", "agent"
	Name     string
	Path     string // Path to the file or directory
	Tool     string // Which tool owns this (e.g., "claude", "gemini")
	Scope    string // "local" or "global"
	Resource any    // The actual resource (*rule.Rule, *skill.Skill, *agent.Agent, etc.)
}

NativeResource represents a resource discovered from a tool's native config

func DiscoverAll

func DiscoverAll(dir string) []*NativeResource

DiscoverAll runs all scanners against the given directory and returns discovered resources

func DiscoverBoth

func DiscoverBoth(dir string) []*NativeResource

DiscoverBoth discovers resources from both local and global configurations

func DiscoverGlobal

func DiscoverGlobal() []*NativeResource

DiscoverGlobal discovers resources from global tool configurations

func DiscoverWorkingDir

func DiscoverWorkingDir() []*NativeResource

DiscoverWorkingDir discovers resources from the current working directory

type Plugin

type Plugin struct {
	Name         string `json:"name"`
	Path         string `json:"path"`
	Version      string `json:"version"`
	Enabled      bool   `json:"enabled"`
	Scope        string `json:"-"` // "local" or "global"
	Tool         string `json:"-"` // Always "claude" for now
	InstalledAt  string `json:"installed_at,omitempty"`
	LastUpdated  string `json:"last_updated,omitempty"`
	GitCommitSha string `json:"git_commit_sha,omitempty"`
}

Plugin represents a Claude Code plugin

func LoadClaudePlugins

func LoadClaudePlugins() ([]*Plugin, error)

LoadClaudePlugins loads plugins from Claude's installed_plugins.json

func LoadClaudeProjectPlugins

func LoadClaudeProjectPlugins(projectDir string) ([]*Plugin, error)

LoadClaudeProjectPlugins loads plugins from a project's local plugin config

func (*Plugin) InspectContent

func (p *Plugin) InspectContent() string

InspectContent returns the formatted content for the inspector viewport

func (*Plugin) InspectTitle

func (p *Plugin) InspectTitle() string

InspectTitle returns the display name for the inspector modal header

type PluginScanner

type PluginScanner interface {
	Scanner
	// ScanPlugins discovers plugins from the tool's local config
	ScanPlugins(dir string) ([]*Plugin, error)
	// ScanGlobalPlugins discovers plugins from the tool's global config
	ScanGlobalPlugins() ([]*Plugin, error)
}

PluginScanner defines the interface for discovering plugins

type SafeReader

type SafeReader struct {
	MaxSize int64
}

SafeReader provides safe file reading with size limits to prevent memory exhaustion

func NewSafeReader

func NewSafeReader() *SafeReader

NewSafeReader creates a new SafeReader with the default max size

func (*SafeReader) ReadFile

func (r *SafeReader) ReadFile(path string) ([]byte, error)

ReadFile reads a file with size checking to prevent memory exhaustion

type Scanner

type Scanner interface {
	// Name returns the scanner/tool name (e.g., "claude", "gemini")
	Name() string

	// Detect checks if the tool's configuration exists in the given directory
	Detect(dir string) bool

	// ScanRules discovers rules from the tool's config directory
	ScanRules(dir string) ([]*rule.Rule, error)

	// ScanSkills discovers skills from the tool's config directory
	ScanSkills(dir string) ([]*skill.Skill, error)

	// ScanHooks discovers hooks from the tool's settings
	ScanHooks(dir string) ([]*hook.Hook, error)

	// ScanCommands discovers commands (slash commands) from the tool's config
	ScanCommands(dir string) ([]*command.Command, error)

	// ScanServers discovers MCP servers from the tool's config
	ScanServers(dir string) ([]*mcp.Server, error)
}

Scanner defines the interface for discovering resources from tool configurations

func All

func All() []Scanner

All returns all registered scanners

func Detected

func Detected(dir string) []Scanner

Detected returns scanners that detect configs in the given directory

func Get

func Get(name string) (Scanner, bool)

Get returns a scanner by name

type ScannerConfig

type ScannerConfig struct {
	Name         string   // Scanner/tool name (e.g., "cursor")
	LocalDirs    []string // Tool directories relative to project (e.g., [".cursor"])
	GlobalDirs   []string // Global config directories (e.g., ["~/.cursor"])
	DetectFiles  []string // Files that indicate tool presence (e.g., [".cursorrules"])
	RulesDirs    []string // Subdirs containing rules (e.g., ["rules"])
	SkillsDirs   []string // Subdirs containing skills
	CommandsDirs []string // Subdirs containing commands
	AgentsDirs   []string // Subdirs containing agents (e.g., ["agents"])
	FileExts     []string // Allowed file extensions (default: [".md", ".mdc"])
}

ScannerConfig defines the configuration for a DirectoryScanner. WARNING: Keep this struct frozen. The moment you add ValidationFunc, CustomDetectors, or IgnorePatterns, consider whether 5 simple files would be clearer. Config-driven is good; a DSL is not.

Jump to

Keyboard shortcuts

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