chore(ax): gofmt exported declaration comments
Some checks failed
Security Scan / security (push) Failing after 10s
Test / test (push) Successful in 2m4s

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 05:44:09 +00:00
parent 305aa0da6f
commit c42cc4a6ce
65 changed files with 0 additions and 248 deletions

View file

@ -10,7 +10,6 @@ import (
) )
// RunMode determines the execution strategy for a dispatched task. // RunMode determines the execution strategy for a dispatched task.
//
type RunMode string type RunMode string
const ( const (
@ -21,14 +20,12 @@ const (
) )
// Spinner is the Clotho orchestrator that determines the fate of each task. // Spinner is the Clotho orchestrator that determines the fate of each task.
//
type Spinner struct { type Spinner struct {
Config ClothoConfig Config ClothoConfig
Agents map[string]AgentConfig Agents map[string]AgentConfig
} }
// NewSpinner creates a new Clotho orchestrator. // NewSpinner creates a new Clotho orchestrator.
//
func NewSpinner(cfg ClothoConfig, agents map[string]AgentConfig) *Spinner { func NewSpinner(cfg ClothoConfig, agents map[string]AgentConfig) *Spinner {
return &Spinner{ return &Spinner{
Config: cfg, Config: cfg,

View file

@ -11,7 +11,6 @@ import (
) )
// AgentConfig represents a single agent machine in the config file. // AgentConfig represents a single agent machine in the config file.
//
type AgentConfig struct { type AgentConfig struct {
Host string `yaml:"host" mapstructure:"host"` Host string `yaml:"host" mapstructure:"host"`
QueueDir string `yaml:"queue_dir" mapstructure:"queue_dir"` QueueDir string `yaml:"queue_dir" mapstructure:"queue_dir"`
@ -26,7 +25,6 @@ type AgentConfig struct {
} }
// ClothoConfig controls the orchestration strategy. // ClothoConfig controls the orchestration strategy.
//
type ClothoConfig struct { type ClothoConfig struct {
Strategy string `yaml:"strategy" mapstructure:"strategy"` // direct, clotho-verified Strategy string `yaml:"strategy" mapstructure:"strategy"` // direct, clotho-verified
ValidationThreshold float64 `yaml:"validation_threshold" mapstructure:"validation_threshold"` // divergence limit (0.0-1.0) ValidationThreshold float64 `yaml:"validation_threshold" mapstructure:"validation_threshold"` // divergence limit (0.0-1.0)
@ -35,7 +33,6 @@ type ClothoConfig struct {
// LoadAgents reads agent targets from config and returns a map of AgentConfig. // LoadAgents reads agent targets from config and returns a map of AgentConfig.
// Returns an empty map (not an error) if no agents are configured. // Returns an empty map (not an error) if no agents are configured.
//
func LoadAgents(cfg *config.Config) (map[string]AgentConfig, error) { func LoadAgents(cfg *config.Config) (map[string]AgentConfig, error) {
var agents map[string]AgentConfig var agents map[string]AgentConfig
if err := cfg.Get("agentci.agents", &agents); err != nil { if err := cfg.Get("agentci.agents", &agents); err != nil {
@ -66,7 +63,6 @@ func LoadAgents(cfg *config.Config) (map[string]AgentConfig, error) {
} }
// LoadActiveAgents returns only active agents. // LoadActiveAgents returns only active agents.
//
func LoadActiveAgents(cfg *config.Config) (map[string]AgentConfig, error) { func LoadActiveAgents(cfg *config.Config) (map[string]AgentConfig, error) {
all, err := LoadAgents(cfg) all, err := LoadAgents(cfg)
if err != nil { if err != nil {
@ -83,7 +79,6 @@ func LoadActiveAgents(cfg *config.Config) (map[string]AgentConfig, error) {
// LoadClothoConfig loads the Clotho orchestrator settings. // LoadClothoConfig loads the Clotho orchestrator settings.
// Returns sensible defaults if no config is present. // Returns sensible defaults if no config is present.
//
func LoadClothoConfig(cfg *config.Config) (ClothoConfig, error) { func LoadClothoConfig(cfg *config.Config) (ClothoConfig, error) {
var cc ClothoConfig var cc ClothoConfig
if err := cfg.Get("agentci.clotho", &cc); err != nil { if err := cfg.Get("agentci.clotho", &cc); err != nil {
@ -102,7 +97,6 @@ func LoadClothoConfig(cfg *config.Config) (ClothoConfig, error) {
} }
// SaveAgent writes an agent config entry to the config file. // SaveAgent writes an agent config entry to the config file.
//
func SaveAgent(cfg *config.Config, name string, ac AgentConfig) error { func SaveAgent(cfg *config.Config, name string, ac AgentConfig) error {
key := fmt.Sprintf("agentci.agents.%s", name) key := fmt.Sprintf("agentci.agents.%s", name)
data := map[string]any{ data := map[string]any{
@ -131,7 +125,6 @@ func SaveAgent(cfg *config.Config, name string, ac AgentConfig) error {
} }
// RemoveAgent removes an agent from the config file. // RemoveAgent removes an agent from the config file.
//
func RemoveAgent(cfg *config.Config, name string) error { func RemoveAgent(cfg *config.Config, name string) error {
var agents map[string]AgentConfig var agents map[string]AgentConfig
if err := cfg.Get("agentci.agents", &agents); err != nil { if err := cfg.Get("agentci.agents", &agents); err != nil {
@ -145,7 +138,6 @@ func RemoveAgent(cfg *config.Config, name string) error {
} }
// ListAgents returns all configured agents (active and inactive). // ListAgents returns all configured agents (active and inactive).
//
func ListAgents(cfg *config.Config) (map[string]AgentConfig, error) { func ListAgents(cfg *config.Config) (map[string]AgentConfig, error) {
var agents map[string]AgentConfig var agents map[string]AgentConfig
if err := cfg.Get("agentci.agents", &agents); err != nil { if err := cfg.Get("agentci.agents", &agents); err != nil {

View file

@ -16,7 +16,6 @@ var safeNameRegex = regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]+$`)
// SanitizePath ensures a filename or directory name is safe and prevents path traversal. // SanitizePath ensures a filename or directory name is safe and prevents path traversal.
// Returns the validated input unchanged. // Returns the validated input unchanged.
//
func SanitizePath(input string) (string, error) { func SanitizePath(input string) (string, error) {
if input == "" { if input == "" {
return "", coreerr.E("agentci.SanitizePath", "path element is required", nil) return "", coreerr.E("agentci.SanitizePath", "path element is required", nil)
@ -34,13 +33,11 @@ func SanitizePath(input string) (string, error) {
} }
// ValidatePathElement validates a single local path element and returns its safe form. // ValidatePathElement validates a single local path element and returns its safe form.
//
func ValidatePathElement(input string) (string, error) { func ValidatePathElement(input string) (string, error) {
return SanitizePath(input) return SanitizePath(input)
} }
// ResolvePathWithinRoot resolves a validated path element beneath a root directory. // ResolvePathWithinRoot resolves a validated path element beneath a root directory.
//
func ResolvePathWithinRoot(root string, input string) (string, string, error) { func ResolvePathWithinRoot(root string, input string) (string, string, error) {
safeName, err := ValidatePathElement(input) safeName, err := ValidatePathElement(input)
if err != nil { if err != nil {
@ -63,7 +60,6 @@ func ResolvePathWithinRoot(root string, input string) (string, string, error) {
} }
// ValidateRemoteDir validates a remote directory path used over SSH. // ValidateRemoteDir validates a remote directory path used over SSH.
//
func ValidateRemoteDir(dir string) (string, error) { func ValidateRemoteDir(dir string) (string, error) {
if strings.TrimSpace(dir) == "" { if strings.TrimSpace(dir) == "" {
return "", coreerr.E("agentci.ValidateRemoteDir", "directory is required", nil) return "", coreerr.E("agentci.ValidateRemoteDir", "directory is required", nil)
@ -111,7 +107,6 @@ func ValidateRemoteDir(dir string) (string, error) {
} }
// JoinRemotePath joins validated remote path elements using forward slashes. // JoinRemotePath joins validated remote path elements using forward slashes.
//
func JoinRemotePath(base string, parts ...string) (string, error) { func JoinRemotePath(base string, parts ...string) (string, error) {
safeBase, err := ValidateRemoteDir(base) safeBase, err := ValidateRemoteDir(base)
if err != nil { if err != nil {
@ -138,13 +133,11 @@ func JoinRemotePath(base string, parts ...string) (string, error) {
// EscapeShellArg wraps a string in single quotes for safe remote shell insertion. // EscapeShellArg wraps a string in single quotes for safe remote shell insertion.
// Prefer exec.Command arguments over constructing shell strings where possible. // Prefer exec.Command arguments over constructing shell strings where possible.
//
func EscapeShellArg(arg string) string { func EscapeShellArg(arg string) string {
return "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'" return "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'"
} }
// SecureSSHCommand creates an SSH exec.Cmd with strict host key checking and batch mode. // SecureSSHCommand creates an SSH exec.Cmd with strict host key checking and batch mode.
//
func SecureSSHCommand(host string, remoteCmd string) *exec.Cmd { func SecureSSHCommand(host string, remoteCmd string) *exec.Cmd {
return exec.Command("ssh", return exec.Command("ssh",
"-o", "StrictHostKeyChecking=yes", "-o", "StrictHostKeyChecking=yes",
@ -156,7 +149,6 @@ func SecureSSHCommand(host string, remoteCmd string) *exec.Cmd {
} }
// MaskToken returns a masked version of a token for safe logging. // MaskToken returns a masked version of a token for safe logging.
//
func MaskToken(token string) string { func MaskToken(token string) string {
if len(token) < 8 { if len(token) < 8 {
return "*****" return "*****"

View file

@ -30,7 +30,6 @@ var (
) )
// AddCollectCommands registers the 'collect' command and all subcommands. // AddCollectCommands registers the 'collect' command and all subcommands.
//
func AddCollectCommands(root *cli.Command) { func AddCollectCommands(root *cli.Command) {
collectCmd := &cli.Command{ collectCmd := &cli.Command{
Use: "collect", Use: "collect",

View file

@ -35,7 +35,6 @@ var (
) )
// AddForgeCommands registers the 'forge' command and all subcommands. // AddForgeCommands registers the 'forge' command and all subcommands.
//
func AddForgeCommands(root *cli.Command) { func AddForgeCommands(root *cli.Command) {
forgeCmd := &cli.Command{ forgeCmd := &cli.Command{
Use: "forge", Use: "forge",

View file

@ -32,7 +32,6 @@ var (
) )
// AddGiteaCommands registers the 'gitea' command and all subcommands. // AddGiteaCommands registers the 'gitea' command and all subcommands.
//
func AddGiteaCommands(root *cli.Command) { func AddGiteaCommands(root *cli.Command) {
giteaCmd := &cli.Command{ giteaCmd := &cli.Command{
Use: "gitea", Use: "gitea",

View file

@ -27,7 +27,6 @@ var (
) )
// AddScmCommands registers the 'scm' command and all subcommands. // AddScmCommands registers the 'scm' command and all subcommands.
//
func AddScmCommands(root *cli.Command) { func AddScmCommands(root *cli.Command) {
scmCmd := &cli.Command{ scmCmd := &cli.Command{
Use: "scm", Use: "scm",

View file

@ -22,7 +22,6 @@ var httpClient = &http.Client{
} }
// BitcoinTalkCollector collects forum posts from BitcoinTalk. // BitcoinTalkCollector collects forum posts from BitcoinTalk.
//
type BitcoinTalkCollector struct { type BitcoinTalkCollector struct {
// TopicID is the numeric topic identifier. // TopicID is the numeric topic identifier.
TopicID string TopicID string
@ -284,7 +283,6 @@ func formatPostMarkdown(num int, post btPost) string {
// ParsePostsFromHTML parses BitcoinTalk posts from raw HTML content. // ParsePostsFromHTML parses BitcoinTalk posts from raw HTML content.
// This is exported for testing purposes. // This is exported for testing purposes.
//
func ParsePostsFromHTML(htmlContent string) ([]btPost, error) { func ParsePostsFromHTML(htmlContent string) ([]btPost, error) {
doc, err := html.Parse(strings.NewReader(htmlContent)) doc, err := html.Parse(strings.NewReader(htmlContent))
if err != nil { if err != nil {
@ -294,17 +292,14 @@ func ParsePostsFromHTML(htmlContent string) ([]btPost, error) {
} }
// FormatPostMarkdown is exported for testing purposes. // FormatPostMarkdown is exported for testing purposes.
//
func FormatPostMarkdown(num int, author, date, content string) string { func FormatPostMarkdown(num int, author, date, content string) string {
return formatPostMarkdown(num, btPost{Author: author, Date: date, Content: content}) return formatPostMarkdown(num, btPost{Author: author, Date: date, Content: content})
} }
// FetchPageFunc is an injectable function type for fetching pages, used in testing. // FetchPageFunc is an injectable function type for fetching pages, used in testing.
//
type FetchPageFunc func(ctx context.Context, url string) ([]btPost, error) type FetchPageFunc func(ctx context.Context, url string) ([]btPost, error)
// BitcoinTalkCollectorWithFetcher wraps BitcoinTalkCollector with a custom fetcher for testing. // BitcoinTalkCollectorWithFetcher wraps BitcoinTalkCollector with a custom fetcher for testing.
//
type BitcoinTalkCollectorWithFetcher struct { type BitcoinTalkCollectorWithFetcher struct {
BitcoinTalkCollector BitcoinTalkCollector
Fetcher FetchPageFunc Fetcher FetchPageFunc
@ -312,7 +307,6 @@ type BitcoinTalkCollectorWithFetcher struct {
// SetHTTPClient replaces the package-level HTTP client. // SetHTTPClient replaces the package-level HTTP client.
// Use this in tests to inject a custom transport or timeout. // Use this in tests to inject a custom transport or timeout.
//
func SetHTTPClient(c *http.Client) { func SetHTTPClient(c *http.Client) {
httpClient = c httpClient = c
} }

View file

@ -14,7 +14,6 @@ import (
) )
// Collector is the interface all collection sources implement. // Collector is the interface all collection sources implement.
//
type Collector interface { type Collector interface {
// Name returns a human-readable name for this collector. // Name returns a human-readable name for this collector.
Name() string Name() string
@ -24,7 +23,6 @@ type Collector interface {
} }
// Config holds shared configuration for all collectors. // Config holds shared configuration for all collectors.
//
type Config struct { type Config struct {
// Output is the storage medium for writing collected data. // Output is the storage medium for writing collected data.
Output io.Medium Output io.Medium
@ -49,7 +47,6 @@ type Config struct {
} }
// Result holds the output of a collection run. // Result holds the output of a collection run.
//
type Result struct { type Result struct {
// Source identifies which collector produced this result. // Source identifies which collector produced this result.
Source string Source string
@ -70,7 +67,6 @@ type Result struct {
// NewConfig creates a Config with sensible defaults. // NewConfig creates a Config with sensible defaults.
// It initialises a MockMedium for output if none is provided, // It initialises a MockMedium for output if none is provided,
// sets up a rate limiter, state tracker, and event dispatcher. // sets up a rate limiter, state tracker, and event dispatcher.
//
func NewConfig(outputDir string) *Config { func NewConfig(outputDir string) *Config {
m := io.NewMockMedium() m := io.NewMockMedium()
return &Config{ return &Config{
@ -83,7 +79,6 @@ func NewConfig(outputDir string) *Config {
} }
// NewConfigWithMedium creates a Config using the specified storage medium. // NewConfigWithMedium creates a Config using the specified storage medium.
//
func NewConfigWithMedium(m io.Medium, outputDir string) *Config { func NewConfigWithMedium(m io.Medium, outputDir string) *Config {
return &Config{ return &Config{
Output: m, Output: m,
@ -95,7 +90,6 @@ func NewConfigWithMedium(m io.Medium, outputDir string) *Config {
} }
// MergeResults combines multiple results into a single aggregated result. // MergeResults combines multiple results into a single aggregated result.
//
func MergeResults(source string, results ...*Result) *Result { func MergeResults(source string, results ...*Result) *Result {
merged := &Result{Source: source} merged := &Result{Source: source}
for _, r := range results { for _, r := range results {

View file

@ -31,7 +31,6 @@ const (
) )
// Event represents a collection event. // Event represents a collection event.
//
type Event struct { type Event struct {
// Type is one of the Event* constants. // Type is one of the Event* constants.
Type string `json:"type"` Type string `json:"type"`
@ -50,19 +49,16 @@ type Event struct {
} }
// EventHandler handles collection events. // EventHandler handles collection events.
//
type EventHandler func(Event) type EventHandler func(Event)
// Dispatcher manages event dispatch. Handlers are registered per event type // Dispatcher manages event dispatch. Handlers are registered per event type
// and are called synchronously when an event is emitted. // and are called synchronously when an event is emitted.
//
type Dispatcher struct { type Dispatcher struct {
mu sync.RWMutex mu sync.RWMutex
handlers map[string][]EventHandler handlers map[string][]EventHandler
} }
// NewDispatcher creates a new event dispatcher. // NewDispatcher creates a new event dispatcher.
//
func NewDispatcher() *Dispatcher { func NewDispatcher() *Dispatcher {
return &Dispatcher{ return &Dispatcher{
handlers: make(map[string][]EventHandler), handlers: make(map[string][]EventHandler),

View file

@ -13,7 +13,6 @@ import (
// Excavator runs multiple collectors as a coordinated operation. // Excavator runs multiple collectors as a coordinated operation.
// It provides sequential execution with rate limit respect, state tracking // It provides sequential execution with rate limit respect, state tracking
// for resume support, and aggregated results. // for resume support, and aggregated results.
//
type Excavator struct { type Excavator struct {
// Collectors is the list of collectors to run. // Collectors is the list of collectors to run.
Collectors []Collector Collectors []Collector

View file

@ -40,7 +40,6 @@ type ghRepo struct {
} }
// GitHubCollector collects issues and PRs from GitHub repositories. // GitHubCollector collects issues and PRs from GitHub repositories.
//
type GitHubCollector struct { type GitHubCollector struct {
// Org is the GitHub organisation. // Org is the GitHub organisation.
Org string Org string

View file

@ -19,7 +19,6 @@ import (
var coinGeckoBaseURL = "https://api.coingecko.com/api/v3" var coinGeckoBaseURL = "https://api.coingecko.com/api/v3"
// MarketCollector collects market data from CoinGecko. // MarketCollector collects market data from CoinGecko.
//
type MarketCollector struct { type MarketCollector struct {
// CoinID is the CoinGecko coin identifier (e.g. "bitcoin", "ethereum"). // CoinID is the CoinGecko coin identifier (e.g. "bitcoin", "ethereum").
CoinID string CoinID string
@ -275,7 +274,6 @@ func formatMarketSummary(data *coinData) string {
} }
// FormatMarketSummary is exported for testing. // FormatMarketSummary is exported for testing.
//
func FormatMarketSummary(data *coinData) string { func FormatMarketSummary(data *coinData) string {
return formatMarketSummary(data) return formatMarketSummary(data)
} }

View file

@ -27,7 +27,6 @@ const (
) )
// PapersCollector collects papers from IACR and arXiv. // PapersCollector collects papers from IACR and arXiv.
//
type PapersCollector struct { type PapersCollector struct {
// Source is one of PaperSourceIACR, PaperSourceArXiv, or PaperSourceAll. // Source is one of PaperSourceIACR, PaperSourceArXiv, or PaperSourceAll.
Source string Source string
@ -409,7 +408,6 @@ func formatPaperMarkdown(ppr paper) string {
} }
// FormatPaperMarkdown is exported for testing. // FormatPaperMarkdown is exported for testing.
//
func FormatPaperMarkdown(title string, authors []string, date, paperURL, source, abstract string) string { func FormatPaperMarkdown(title string, authors []string, date, paperURL, source, abstract string) string {
return formatPaperMarkdown(paper{ return formatPaperMarkdown(paper{
Title: title, Title: title,

View file

@ -16,7 +16,6 @@ import (
) )
// Processor converts collected data to clean markdown. // Processor converts collected data to clean markdown.
//
type Processor struct { type Processor struct {
// Source identifies the data source directory to process. // Source identifies the data source directory to process.
Source string Source string
@ -334,13 +333,11 @@ func jsonValueToMarkdown(b *strings.Builder, data any, depth int) {
} }
// HTMLToMarkdown is exported for testing. // HTMLToMarkdown is exported for testing.
//
func HTMLToMarkdown(content string) (string, error) { func HTMLToMarkdown(content string) (string, error) {
return htmlToMarkdown(content) return htmlToMarkdown(content)
} }
// JSONToMarkdown is exported for testing. // JSONToMarkdown is exported for testing.
//
func JSONToMarkdown(content string) (string, error) { func JSONToMarkdown(content string) (string, error) {
return jsonToMarkdown(content) return jsonToMarkdown(content)
} }

View file

@ -16,7 +16,6 @@ import (
) )
// RateLimiter tracks per-source rate limiting to avoid overwhelming APIs. // RateLimiter tracks per-source rate limiting to avoid overwhelming APIs.
//
type RateLimiter struct { type RateLimiter struct {
mu sync.Mutex mu sync.Mutex
delays map[string]time.Duration delays map[string]time.Duration
@ -33,7 +32,6 @@ var defaultDelays = map[string]time.Duration{
} }
// NewRateLimiter creates a limiter with default delays. // NewRateLimiter creates a limiter with default delays.
//
func NewRateLimiter() *RateLimiter { func NewRateLimiter() *RateLimiter {
delays := make(map[string]time.Duration, len(defaultDelays)) delays := make(map[string]time.Duration, len(defaultDelays))
maps.Copy(delays, defaultDelays) maps.Copy(delays, defaultDelays)

View file

@ -14,7 +14,6 @@ import (
// State tracks collection progress for incremental runs. // State tracks collection progress for incremental runs.
// It persists entries to disk so that subsequent runs can resume // It persists entries to disk so that subsequent runs can resume
// where they left off. // where they left off.
//
type State struct { type State struct {
mu sync.Mutex mu sync.Mutex
medium io.Medium medium io.Medium
@ -23,7 +22,6 @@ type State struct {
} }
// StateEntry tracks state for one source. // StateEntry tracks state for one source.
//
type StateEntry struct { type StateEntry struct {
// Source identifies the collector. // Source identifies the collector.
Source string `json:"source"` Source string `json:"source"`
@ -43,7 +41,6 @@ type StateEntry struct {
// NewState creates a state tracker that persists to the given path // NewState creates a state tracker that persists to the given path
// using the provided storage medium. // using the provided storage medium.
//
func NewState(m io.Medium, path string) *State { func NewState(m io.Medium, path string) *State {
return &State{ return &State{
medium: m, medium: m,

View file

@ -17,7 +17,6 @@ import (
) )
// Client wraps the Forgejo SDK client with config-based auth. // Client wraps the Forgejo SDK client with config-based auth.
//
type Client struct { type Client struct {
api *forgejo.Client api *forgejo.Client
url string url string
@ -25,7 +24,6 @@ type Client struct {
} }
// New creates a new Forgejo API client for the given URL and token. // New creates a new Forgejo API client for the given URL and token.
//
func New(url, token string) (*Client, error) { func New(url, token string) (*Client, error) {
api, err := forgejo.NewClient(url, forgejo.SetToken(token)) api, err := forgejo.NewClient(url, forgejo.SetToken(token))
if err != nil { if err != nil {

View file

@ -27,8 +27,6 @@ const (
// 1. ~/.core/config.yaml keys: forge.token, forge.url // 1. ~/.core/config.yaml keys: forge.token, forge.url
// 2. FORGE_TOKEN + FORGE_URL environment variables (override config file) // 2. FORGE_TOKEN + FORGE_URL environment variables (override config file)
// 3. Provided flag overrides (highest priority; pass empty to skip) // 3. Provided flag overrides (highest priority; pass empty to skip)
//
//
func NewFromConfig(flagURL, flagToken string) (*Client, error) { func NewFromConfig(flagURL, flagToken string) (*Client, error) {
url, token, err := ResolveConfig(flagURL, flagToken) url, token, err := ResolveConfig(flagURL, flagToken)
if err != nil { if err != nil {
@ -44,7 +42,6 @@ func NewFromConfig(flagURL, flagToken string) (*Client, error) {
// ResolveConfig resolves the Forgejo URL and token from all config sources. // ResolveConfig resolves the Forgejo URL and token from all config sources.
// Flag values take highest priority, then env vars, then config file. // Flag values take highest priority, then env vars, then config file.
//
func ResolveConfig(flagURL, flagToken string) (url, token string, err error) { func ResolveConfig(flagURL, flagToken string) (url, token string, err error) {
// Start with config file values // Start with config file values
cfg, cfgErr := config.New() cfg, cfgErr := config.New()
@ -78,7 +75,6 @@ func ResolveConfig(flagURL, flagToken string) (url, token string, err error) {
} }
// SaveConfig persists the Forgejo URL and/or token to the config file. // SaveConfig persists the Forgejo URL and/or token to the config file.
//
func SaveConfig(url, token string) error { func SaveConfig(url, token string) error {
cfg, err := config.New() cfg, err := config.New()
if err != nil { if err != nil {

View file

@ -11,7 +11,6 @@ import (
) )
// ListIssuesOpts configures issue listing. // ListIssuesOpts configures issue listing.
//
type ListIssuesOpts struct { type ListIssuesOpts struct {
State string // "open", "closed", "all" State string // "open", "closed", "all"
Labels []string // filter by label names Labels []string // filter by label names

View file

@ -12,7 +12,6 @@ import (
// PRMeta holds structural signals from a pull request, // PRMeta holds structural signals from a pull request,
// used by the pipeline MetaReader for AI-driven workflows. // used by the pipeline MetaReader for AI-driven workflows.
//
type PRMeta struct { type PRMeta struct {
Number int64 Number int64
Title string Title string
@ -29,7 +28,6 @@ type PRMeta struct {
} }
// Comment represents a comment with metadata. // Comment represents a comment with metadata.
//
type Comment struct { type Comment struct {
ID int64 ID int64
Author string Author string

View file

@ -17,7 +17,6 @@ import (
) )
// RepoStatus represents the git status of a single repository. // RepoStatus represents the git status of a single repository.
//
type RepoStatus struct { type RepoStatus struct {
Name string Name string
Path string Path string
@ -46,7 +45,6 @@ func (s *RepoStatus) HasUnpulled() bool {
} }
// StatusOptions configures the status check. // StatusOptions configures the status check.
//
type StatusOptions struct { type StatusOptions struct {
// Paths is a list of repo paths to check // Paths is a list of repo paths to check
Paths []string Paths []string
@ -55,7 +53,6 @@ type StatusOptions struct {
} }
// Status checks git status for multiple repositories in parallel. // Status checks git status for multiple repositories in parallel.
//
func Status(ctx context.Context, opts StatusOptions) []RepoStatus { func Status(ctx context.Context, opts StatusOptions) []RepoStatus {
var wg sync.WaitGroup var wg sync.WaitGroup
results := make([]RepoStatus, len(opts.Paths)) results := make([]RepoStatus, len(opts.Paths))
@ -77,7 +74,6 @@ func Status(ctx context.Context, opts StatusOptions) []RepoStatus {
} }
// StatusIter returns an iterator over git status for multiple repositories. // StatusIter returns an iterator over git status for multiple repositories.
//
func StatusIter(ctx context.Context, opts StatusOptions) iter.Seq[RepoStatus] { func StatusIter(ctx context.Context, opts StatusOptions) iter.Seq[RepoStatus] {
return func(yield func(RepoStatus) bool) { return func(yield func(RepoStatus) bool) {
results := Status(ctx, opts) results := Status(ctx, opts)
@ -162,20 +158,17 @@ func getAheadBehind(ctx context.Context, path string) (ahead, behind int) {
// Push pushes commits for a single repository. // Push pushes commits for a single repository.
// Uses interactive mode to support SSH passphrase prompts. // Uses interactive mode to support SSH passphrase prompts.
//
func Push(ctx context.Context, path string) error { func Push(ctx context.Context, path string) error {
return gitInteractive(ctx, path, "push") return gitInteractive(ctx, path, "push")
} }
// Pull pulls changes for a single repository. // Pull pulls changes for a single repository.
// Uses interactive mode to support SSH passphrase prompts. // Uses interactive mode to support SSH passphrase prompts.
//
func Pull(ctx context.Context, path string) error { func Pull(ctx context.Context, path string) error {
return gitInteractive(ctx, path, "pull", "--rebase") return gitInteractive(ctx, path, "pull", "--rebase")
} }
// IsNonFastForward checks if an error is a non-fast-forward rejection. // IsNonFastForward checks if an error is a non-fast-forward rejection.
//
func IsNonFastForward(err error) bool { func IsNonFastForward(err error) bool {
if err == nil { if err == nil {
return false return false
@ -210,7 +203,6 @@ func gitInteractive(ctx context.Context, dir string, args ...string) error {
} }
// PushResult represents the result of a push operation. // PushResult represents the result of a push operation.
//
type PushResult struct { type PushResult struct {
Name string Name string
Path string Path string
@ -220,13 +212,11 @@ type PushResult struct {
// PushMultiple pushes multiple repositories sequentially. // PushMultiple pushes multiple repositories sequentially.
// Sequential because SSH passphrase prompts need user interaction. // Sequential because SSH passphrase prompts need user interaction.
//
func PushMultiple(ctx context.Context, paths []string, names map[string]string) []PushResult { func PushMultiple(ctx context.Context, paths []string, names map[string]string) []PushResult {
return slices.Collect(PushMultipleIter(ctx, paths, names)) return slices.Collect(PushMultipleIter(ctx, paths, names))
} }
// PushMultipleIter returns an iterator that pushes repositories sequentially and yields results. // PushMultipleIter returns an iterator that pushes repositories sequentially and yields results.
//
func PushMultipleIter(ctx context.Context, paths []string, names map[string]string) iter.Seq[PushResult] { func PushMultipleIter(ctx context.Context, paths []string, names map[string]string) iter.Seq[PushResult] {
return func(yield func(PushResult) bool) { return func(yield func(PushResult) bool) {
for _, path := range paths { for _, path := range paths {
@ -275,7 +265,6 @@ func gitCommand(ctx context.Context, dir string, args ...string) (string, error)
} }
// GitError wraps a git command error with stderr output. // GitError wraps a git command error with stderr output.
//
type GitError struct { type GitError struct {
Err error Err error
Stderr string Stderr string

View file

@ -13,58 +13,49 @@ import (
// Queries for git service // Queries for git service
// QueryStatus requests git status for paths. // QueryStatus requests git status for paths.
//
type QueryStatus struct { type QueryStatus struct {
Paths []string Paths []string
Names map[string]string Names map[string]string
} }
// QueryDirtyRepos requests repos with uncommitted changes. // QueryDirtyRepos requests repos with uncommitted changes.
//
type QueryDirtyRepos struct{} type QueryDirtyRepos struct{}
// QueryAheadRepos requests repos with unpushed commits. // QueryAheadRepos requests repos with unpushed commits.
//
type QueryAheadRepos struct{} type QueryAheadRepos struct{}
// Tasks for git service // Tasks for git service
// TaskPush requests git push for a path. // TaskPush requests git push for a path.
//
type TaskPush struct { type TaskPush struct {
Path string Path string
Name string Name string
} }
// TaskPull requests git pull for a path. // TaskPull requests git pull for a path.
//
type TaskPull struct { type TaskPull struct {
Path string Path string
Name string Name string
} }
// TaskPushMultiple requests git push for multiple paths. // TaskPushMultiple requests git push for multiple paths.
//
type TaskPushMultiple struct { type TaskPushMultiple struct {
Paths []string Paths []string
Names map[string]string Names map[string]string
} }
// ServiceOptions for configuring the git service. // ServiceOptions for configuring the git service.
//
type ServiceOptions struct { type ServiceOptions struct {
WorkDir string WorkDir string
} }
// Service provides git operations as a Core service. // Service provides git operations as a Core service.
//
type Service struct { type Service struct {
*core.ServiceRuntime[ServiceOptions] *core.ServiceRuntime[ServiceOptions]
lastStatus []RepoStatus lastStatus []RepoStatus
} }
// NewService creates a git service factory. // NewService creates a git service factory.
//
func NewService(opts ServiceOptions) func(*core.Core) (any, error) { func NewService(opts ServiceOptions) func(*core.Core) (any, error) {
return func(c *core.Core) (any, error) { return func(c *core.Core) (any, error) {
return &Service{ return &Service{

View file

@ -17,14 +17,12 @@ import (
) )
// Client wraps the Gitea SDK client with config-based auth. // Client wraps the Gitea SDK client with config-based auth.
//
type Client struct { type Client struct {
api *gitea.Client api *gitea.Client
url string url string
} }
// New creates a new Gitea API client for the given URL and token. // New creates a new Gitea API client for the given URL and token.
//
func New(url, token string) (*Client, error) { func New(url, token string) (*Client, error) {
api, err := gitea.NewClient(url, gitea.SetToken(token)) api, err := gitea.NewClient(url, gitea.SetToken(token))
if err != nil { if err != nil {

View file

@ -27,8 +27,6 @@ const (
// 1. ~/.core/config.yaml keys: gitea.token, gitea.url // 1. ~/.core/config.yaml keys: gitea.token, gitea.url
// 2. GITEA_TOKEN + GITEA_URL environment variables (override config file) // 2. GITEA_TOKEN + GITEA_URL environment variables (override config file)
// 3. Provided flag overrides (highest priority; pass empty to skip) // 3. Provided flag overrides (highest priority; pass empty to skip)
//
//
func NewFromConfig(flagURL, flagToken string) (*Client, error) { func NewFromConfig(flagURL, flagToken string) (*Client, error) {
url, token, err := ResolveConfig(flagURL, flagToken) url, token, err := ResolveConfig(flagURL, flagToken)
if err != nil { if err != nil {
@ -44,7 +42,6 @@ func NewFromConfig(flagURL, flagToken string) (*Client, error) {
// ResolveConfig resolves the Gitea URL and token from all config sources. // ResolveConfig resolves the Gitea URL and token from all config sources.
// Flag values take highest priority, then env vars, then config file. // Flag values take highest priority, then env vars, then config file.
//
func ResolveConfig(flagURL, flagToken string) (url, token string, err error) { func ResolveConfig(flagURL, flagToken string) (url, token string, err error) {
// Start with config file values // Start with config file values
cfg, cfgErr := config.New() cfg, cfgErr := config.New()
@ -78,7 +75,6 @@ func ResolveConfig(flagURL, flagToken string) (url, token string, err error) {
} }
// SaveConfig persists the Gitea URL and/or token to the config file. // SaveConfig persists the Gitea URL and/or token to the config file.
//
func SaveConfig(url, token string) error { func SaveConfig(url, token string) error {
cfg, err := config.New() cfg, err := config.New()
if err != nil { if err != nil {

View file

@ -11,7 +11,6 @@ import (
) )
// ListIssuesOpts configures issue listing. // ListIssuesOpts configures issue listing.
//
type ListIssuesOpts struct { type ListIssuesOpts struct {
State string // "open", "closed", "all" State string // "open", "closed", "all"
Page int Page int

View file

@ -12,7 +12,6 @@ import (
// PRMeta holds structural signals from a pull request, // PRMeta holds structural signals from a pull request,
// used by the pipeline MetaReader for AI-driven workflows. // used by the pipeline MetaReader for AI-driven workflows.
//
type PRMeta struct { type PRMeta struct {
Number int64 Number int64
Title string Title string
@ -29,7 +28,6 @@ type PRMeta struct {
} }
// Comment represents a comment with metadata. // Comment represents a comment with metadata.
//
type Comment struct { type Comment struct {
ID int64 ID int64
Author string Author string

View file

@ -8,11 +8,9 @@ import (
) )
// Separator mirrors filepath.Separator for Unix-style Core paths. // Separator mirrors filepath.Separator for Unix-style Core paths.
//
const Separator = '/' const Separator = '/'
// Abs mirrors filepath.Abs for the paths used in this repo. // Abs mirrors filepath.Abs for the paths used in this repo.
//
func Abs(p string) (string, error) { func Abs(p string) (string, error) {
if path.IsAbs(p) { if path.IsAbs(p) {
return path.Clean(p), nil return path.Clean(p), nil
@ -25,31 +23,26 @@ func Abs(p string) (string, error) {
} }
// Base mirrors filepath.Base. // Base mirrors filepath.Base.
//
func Base(p string) string { func Base(p string) string {
return path.Base(p) return path.Base(p)
} }
// Clean mirrors filepath.Clean. // Clean mirrors filepath.Clean.
//
func Clean(p string) string { func Clean(p string) string {
return path.Clean(p) return path.Clean(p)
} }
// Dir mirrors filepath.Dir. // Dir mirrors filepath.Dir.
//
func Dir(p string) string { func Dir(p string) string {
return path.Dir(p) return path.Dir(p)
} }
// Ext mirrors filepath.Ext. // Ext mirrors filepath.Ext.
//
func Ext(p string) string { func Ext(p string) string {
return path.Ext(p) return path.Ext(p)
} }
// Join mirrors filepath.Join. // Join mirrors filepath.Join.
//
func Join(elem ...string) string { func Join(elem ...string) string {
return path.Join(elem...) return path.Join(elem...)
} }

View file

@ -10,31 +10,26 @@ import (
) )
// Sprint mirrors fmt.Sprint using Core primitives. // Sprint mirrors fmt.Sprint using Core primitives.
//
func Sprint(args ...any) string { func Sprint(args ...any) string {
return core.Sprint(args...) return core.Sprint(args...)
} }
// Sprintf mirrors fmt.Sprintf using Core primitives. // Sprintf mirrors fmt.Sprintf using Core primitives.
//
func Sprintf(format string, args ...any) string { func Sprintf(format string, args ...any) string {
return core.Sprintf(format, args...) return core.Sprintf(format, args...)
} }
// Fprintf mirrors fmt.Fprintf using Core primitives. // Fprintf mirrors fmt.Fprintf using Core primitives.
//
func Fprintf(w io.Writer, format string, args ...any) (int, error) { func Fprintf(w io.Writer, format string, args ...any) (int, error) {
return io.WriteString(w, Sprintf(format, args...)) return io.WriteString(w, Sprintf(format, args...))
} }
// Printf mirrors fmt.Printf. // Printf mirrors fmt.Printf.
//
func Printf(format string, args ...any) (int, error) { func Printf(format string, args ...any) (int, error) {
return Fprintf(stdio.Stdout, format, args...) return Fprintf(stdio.Stdout, format, args...)
} }
// Println mirrors fmt.Println. // Println mirrors fmt.Println.
//
func Println(args ...any) (int, error) { func Println(args ...any) (int, error) {
return io.WriteString(stdio.Stdout, Sprint(args...)+"\n") return io.WriteString(stdio.Stdout, Sprint(args...)+"\n")
} }

View file

@ -9,31 +9,26 @@ import (
) )
// Marshal mirrors encoding/json.Marshal. // Marshal mirrors encoding/json.Marshal.
//
func Marshal(v any) ([]byte, error) { func Marshal(v any) ([]byte, error) {
return json.Marshal(v) return json.Marshal(v)
} }
// MarshalIndent mirrors encoding/json.MarshalIndent. // MarshalIndent mirrors encoding/json.MarshalIndent.
//
func MarshalIndent(v any, prefix, indent string) ([]byte, error) { func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
return json.MarshalIndent(v, prefix, indent) return json.MarshalIndent(v, prefix, indent)
} }
// NewDecoder mirrors encoding/json.NewDecoder. // NewDecoder mirrors encoding/json.NewDecoder.
//
func NewDecoder(r io.Reader) *json.Decoder { func NewDecoder(r io.Reader) *json.Decoder {
return json.NewDecoder(r) return json.NewDecoder(r)
} }
// NewEncoder mirrors encoding/json.NewEncoder. // NewEncoder mirrors encoding/json.NewEncoder.
//
func NewEncoder(w io.Writer) *json.Encoder { func NewEncoder(w io.Writer) *json.Encoder {
return json.NewEncoder(w) return json.NewEncoder(w)
} }
// Unmarshal mirrors encoding/json.Unmarshal. // Unmarshal mirrors encoding/json.Unmarshal.
//
func Unmarshal(data []byte, v any) error { func Unmarshal(data []byte, v any) error {
return json.Unmarshal(data, v) return json.Unmarshal(data, v)
} }

View file

@ -23,50 +23,41 @@ const (
) )
// Stdin exposes process stdin without importing os. // Stdin exposes process stdin without importing os.
//
var Stdin = stdio.Stdin var Stdin = stdio.Stdin
// Stdout exposes process stdout without importing os. // Stdout exposes process stdout without importing os.
//
var Stdout = stdio.Stdout var Stdout = stdio.Stdout
// Stderr exposes process stderr without importing os. // Stderr exposes process stderr without importing os.
//
var Stderr = stdio.Stderr var Stderr = stdio.Stderr
// Getenv mirrors os.Getenv. // Getenv mirrors os.Getenv.
//
func Getenv(key string) string { func Getenv(key string) string {
value, _ := syscall.Getenv(key) value, _ := syscall.Getenv(key)
return value return value
} }
// Getwd mirrors os.Getwd. // Getwd mirrors os.Getwd.
//
func Getwd() (string, error) { func Getwd() (string, error) {
return syscall.Getwd() return syscall.Getwd()
} }
// IsNotExist mirrors os.IsNotExist. // IsNotExist mirrors os.IsNotExist.
//
func IsNotExist(err error) bool { func IsNotExist(err error) bool {
return core.Is(err, fs.ErrNotExist) return core.Is(err, fs.ErrNotExist)
} }
// MkdirAll mirrors os.MkdirAll. // MkdirAll mirrors os.MkdirAll.
//
func MkdirAll(path string, _ fs.FileMode) error { func MkdirAll(path string, _ fs.FileMode) error {
return coreio.Local.EnsureDir(path) return coreio.Local.EnsureDir(path)
} }
// Open mirrors os.Open. // Open mirrors os.Open.
//
func Open(path string) (fs.File, error) { func Open(path string) (fs.File, error) {
return coreio.Local.Open(path) return coreio.Local.Open(path)
} }
// OpenFile mirrors the append/create/write mode used in this repo. // OpenFile mirrors the append/create/write mode used in this repo.
//
func OpenFile(path string, flag int, _ fs.FileMode) (io.WriteCloser, error) { func OpenFile(path string, flag int, _ fs.FileMode) (io.WriteCloser, error) {
if flag&O_APPEND != 0 { if flag&O_APPEND != 0 {
return coreio.Local.Append(path) return coreio.Local.Append(path)
@ -75,26 +66,22 @@ func OpenFile(path string, flag int, _ fs.FileMode) (io.WriteCloser, error) {
} }
// ReadDir mirrors os.ReadDir. // ReadDir mirrors os.ReadDir.
//
func ReadDir(path string) ([]fs.DirEntry, error) { func ReadDir(path string) ([]fs.DirEntry, error) {
return coreio.Local.List(path) return coreio.Local.List(path)
} }
// ReadFile mirrors os.ReadFile. // ReadFile mirrors os.ReadFile.
//
func ReadFile(path string) ([]byte, error) { func ReadFile(path string) ([]byte, error) {
content, err := coreio.Local.Read(path) content, err := coreio.Local.Read(path)
return []byte(content), err return []byte(content), err
} }
// Stat mirrors os.Stat. // Stat mirrors os.Stat.
//
func Stat(path string) (fs.FileInfo, error) { func Stat(path string) (fs.FileInfo, error) {
return coreio.Local.Stat(path) return coreio.Local.Stat(path)
} }
// UserHomeDir mirrors os.UserHomeDir. // UserHomeDir mirrors os.UserHomeDir.
//
func UserHomeDir() (string, error) { func UserHomeDir() (string, error) {
if home := Getenv("HOME"); home != "" { if home := Getenv("HOME"); home != "" {
return home, nil return home, nil
@ -107,7 +94,6 @@ func UserHomeDir() (string, error) {
} }
// WriteFile mirrors os.WriteFile. // WriteFile mirrors os.WriteFile.
//
func WriteFile(path string, data []byte, perm fs.FileMode) error { func WriteFile(path string, data []byte, perm fs.FileMode) error {
return coreio.Local.WriteMode(path, string(data), perm) return coreio.Local.WriteMode(path, string(data), perm)
} }

View file

@ -28,13 +28,10 @@ func (w fdWriter) Write(p []byte) (int, error) {
} }
// Stdin exposes process stdin without importing os. // Stdin exposes process stdin without importing os.
//
var Stdin io.Reader = fdReader{fd: 0} var Stdin io.Reader = fdReader{fd: 0}
// Stdout exposes process stdout without importing os. // Stdout exposes process stdout without importing os.
//
var Stdout io.Writer = fdWriter{fd: 1} var Stdout io.Writer = fdWriter{fd: 1}
// Stderr exposes process stderr without importing os. // Stderr exposes process stderr without importing os.
//
var Stderr io.Writer = fdWriter{fd: 2} var Stderr io.Writer = fdWriter{fd: 2}

View file

@ -11,29 +11,24 @@ import (
) )
// Builder provides a strings.Builder-like type without importing strings. // Builder provides a strings.Builder-like type without importing strings.
//
type Builder = bytes.Buffer type Builder = bytes.Buffer
// Contains mirrors strings.Contains. // Contains mirrors strings.Contains.
//
func Contains(s, substr string) bool { func Contains(s, substr string) bool {
return core.Contains(s, substr) return core.Contains(s, substr)
} }
// ContainsAny mirrors strings.ContainsAny. // ContainsAny mirrors strings.ContainsAny.
//
func ContainsAny(s, chars string) bool { func ContainsAny(s, chars string) bool {
return bytes.IndexAny([]byte(s), chars) >= 0 return bytes.IndexAny([]byte(s), chars) >= 0
} }
// EqualFold mirrors strings.EqualFold. // EqualFold mirrors strings.EqualFold.
//
func EqualFold(s, t string) bool { func EqualFold(s, t string) bool {
return bytes.EqualFold([]byte(s), []byte(t)) return bytes.EqualFold([]byte(s), []byte(t))
} }
// Fields mirrors strings.Fields. // Fields mirrors strings.Fields.
//
func Fields(s string) []string { func Fields(s string) []string {
scanner := bufio.NewScanner(NewReader(s)) scanner := bufio.NewScanner(NewReader(s))
scanner.Split(bufio.ScanWords) scanner.Split(bufio.ScanWords)
@ -45,37 +40,31 @@ func Fields(s string) []string {
} }
// HasPrefix mirrors strings.HasPrefix. // HasPrefix mirrors strings.HasPrefix.
//
func HasPrefix(s, prefix string) bool { func HasPrefix(s, prefix string) bool {
return core.HasPrefix(s, prefix) return core.HasPrefix(s, prefix)
} }
// HasSuffix mirrors strings.HasSuffix. // HasSuffix mirrors strings.HasSuffix.
//
func HasSuffix(s, suffix string) bool { func HasSuffix(s, suffix string) bool {
return core.HasSuffix(s, suffix) return core.HasSuffix(s, suffix)
} }
// Join mirrors strings.Join. // Join mirrors strings.Join.
//
func Join(elems []string, sep string) string { func Join(elems []string, sep string) string {
return core.Join(sep, elems...) return core.Join(sep, elems...)
} }
// LastIndex mirrors strings.LastIndex. // LastIndex mirrors strings.LastIndex.
//
func LastIndex(s, substr string) int { func LastIndex(s, substr string) int {
return bytes.LastIndex([]byte(s), []byte(substr)) return bytes.LastIndex([]byte(s), []byte(substr))
} }
// NewReader mirrors strings.NewReader. // NewReader mirrors strings.NewReader.
//
func NewReader(s string) *bytes.Reader { func NewReader(s string) *bytes.Reader {
return bytes.NewReader([]byte(s)) return bytes.NewReader([]byte(s))
} }
// Repeat mirrors strings.Repeat. // Repeat mirrors strings.Repeat.
//
func Repeat(s string, count int) string { func Repeat(s string, count int) string {
if count <= 0 { if count <= 0 {
return "" return ""
@ -84,31 +73,26 @@ func Repeat(s string, count int) string {
} }
// ReplaceAll mirrors strings.ReplaceAll. // ReplaceAll mirrors strings.ReplaceAll.
//
func ReplaceAll(s, old, new string) string { func ReplaceAll(s, old, new string) string {
return core.Replace(s, old, new) return core.Replace(s, old, new)
} }
// Replace mirrors strings.Replace for replace-all call sites. // Replace mirrors strings.Replace for replace-all call sites.
//
func Replace(s, old, new string, _ int) string { func Replace(s, old, new string, _ int) string {
return ReplaceAll(s, old, new) return ReplaceAll(s, old, new)
} }
// Split mirrors strings.Split. // Split mirrors strings.Split.
//
func Split(s, sep string) []string { func Split(s, sep string) []string {
return core.Split(s, sep) return core.Split(s, sep)
} }
// SplitN mirrors strings.SplitN. // SplitN mirrors strings.SplitN.
//
func SplitN(s, sep string, n int) []string { func SplitN(s, sep string, n int) []string {
return core.SplitN(s, sep, n) return core.SplitN(s, sep, n)
} }
// SplitSeq mirrors strings.SplitSeq. // SplitSeq mirrors strings.SplitSeq.
//
func SplitSeq(s, sep string) iter.Seq[string] { func SplitSeq(s, sep string) iter.Seq[string] {
parts := Split(s, sep) parts := Split(s, sep)
return func(yield func(string) bool) { return func(yield func(string) bool) {
@ -121,31 +105,26 @@ func SplitSeq(s, sep string) iter.Seq[string] {
} }
// ToLower mirrors strings.ToLower. // ToLower mirrors strings.ToLower.
//
func ToLower(s string) string { func ToLower(s string) string {
return core.Lower(s) return core.Lower(s)
} }
// ToUpper mirrors strings.ToUpper. // ToUpper mirrors strings.ToUpper.
//
func ToUpper(s string) string { func ToUpper(s string) string {
return core.Upper(s) return core.Upper(s)
} }
// TrimPrefix mirrors strings.TrimPrefix. // TrimPrefix mirrors strings.TrimPrefix.
//
func TrimPrefix(s, prefix string) string { func TrimPrefix(s, prefix string) string {
return core.TrimPrefix(s, prefix) return core.TrimPrefix(s, prefix)
} }
// TrimSpace mirrors strings.TrimSpace. // TrimSpace mirrors strings.TrimSpace.
//
func TrimSpace(s string) string { func TrimSpace(s string) string {
return core.Trim(s) return core.Trim(s)
} }
// TrimSuffix mirrors strings.TrimSuffix. // TrimSuffix mirrors strings.TrimSuffix.
//
func TrimSuffix(s, suffix string) string { func TrimSuffix(s, suffix string) string {
return core.TrimSuffix(s, suffix) return core.TrimSuffix(s, suffix)
} }

View file

@ -13,20 +13,17 @@ import (
) )
// Config configures a ForgejoSource. // Config configures a ForgejoSource.
//
type Config struct { type Config struct {
Repos []string // "owner/repo" format Repos []string // "owner/repo" format
} }
// ForgejoSource polls a Forgejo instance for pipeline signals from epic issues. // ForgejoSource polls a Forgejo instance for pipeline signals from epic issues.
//
type ForgejoSource struct { type ForgejoSource struct {
repos []string repos []string
forge *forge.Client forge *forge.Client
} }
// New creates a ForgejoSource using the given forge client. // New creates a ForgejoSource using the given forge client.
//
func New(cfg Config, client *forge.Client) *ForgejoSource { func New(cfg Config, client *forge.Client) *ForgejoSource {
return &ForgejoSource{ return &ForgejoSource{
repos: cfg.Repos, repos: cfg.Repos,

View file

@ -18,13 +18,11 @@ const (
) )
// CompletionHandler manages issue state when an agent finishes work. // CompletionHandler manages issue state when an agent finishes work.
//
type CompletionHandler struct { type CompletionHandler struct {
forge *forge.Client forge *forge.Client
} }
// NewCompletionHandler creates a handler for agent completion events. // NewCompletionHandler creates a handler for agent completion events.
//
func NewCompletionHandler(client *forge.Client) *CompletionHandler { func NewCompletionHandler(client *forge.Client) *CompletionHandler {
return &CompletionHandler{ return &CompletionHandler{
forge: client, forge: client,

View file

@ -35,7 +35,6 @@ const (
// DispatchTicket is the JSON payload written to the agent's queue. // DispatchTicket is the JSON payload written to the agent's queue.
// The ForgeToken is transferred separately via a .env file with 0600 permissions. // The ForgeToken is transferred separately via a .env file with 0600 permissions.
//
type DispatchTicket struct { type DispatchTicket struct {
ID string `json:"id"` ID string `json:"id"`
RepoOwner string `json:"repo_owner"` RepoOwner string `json:"repo_owner"`
@ -55,7 +54,6 @@ type DispatchTicket struct {
} }
// DispatchHandler dispatches coding work to remote agent machines via SSH. // DispatchHandler dispatches coding work to remote agent machines via SSH.
//
type DispatchHandler struct { type DispatchHandler struct {
forge *forge.Client forge *forge.Client
forgeURL string forgeURL string
@ -64,7 +62,6 @@ type DispatchHandler struct {
} }
// NewDispatchHandler creates a handler that dispatches tickets to agent machines. // NewDispatchHandler creates a handler that dispatches tickets to agent machines.
//
func NewDispatchHandler(client *forge.Client, forgeURL, token string, spinner *agentci.Spinner) *DispatchHandler { func NewDispatchHandler(client *forge.Client, forgeURL, token string, spinner *agentci.Spinner) *DispatchHandler {
return &DispatchHandler{ return &DispatchHandler{
forge: client, forge: client,

View file

@ -12,13 +12,11 @@ import (
) )
// EnableAutoMergeHandler merges a PR that is ready using squash strategy. // EnableAutoMergeHandler merges a PR that is ready using squash strategy.
//
type EnableAutoMergeHandler struct { type EnableAutoMergeHandler struct {
forge *forge.Client forge *forge.Client
} }
// NewEnableAutoMergeHandler creates a handler that merges ready PRs. // NewEnableAutoMergeHandler creates a handler that merges ready PRs.
//
func NewEnableAutoMergeHandler(f *forge.Client) *EnableAutoMergeHandler { func NewEnableAutoMergeHandler(f *forge.Client) *EnableAutoMergeHandler {
return &EnableAutoMergeHandler{forge: f} return &EnableAutoMergeHandler{forge: f}
} }

View file

@ -12,13 +12,11 @@ import (
) )
// PublishDraftHandler marks a draft PR as ready for review once its checks pass. // PublishDraftHandler marks a draft PR as ready for review once its checks pass.
//
type PublishDraftHandler struct { type PublishDraftHandler struct {
forge *forge.Client forge *forge.Client
} }
// NewPublishDraftHandler creates a handler that publishes draft PRs. // NewPublishDraftHandler creates a handler that publishes draft PRs.
//
func NewPublishDraftHandler(f *forge.Client) *PublishDraftHandler { func NewPublishDraftHandler(f *forge.Client) *PublishDraftHandler {
return &PublishDraftHandler{forge: f} return &PublishDraftHandler{forge: f}
} }

View file

@ -17,13 +17,11 @@ import (
// DismissReviewsHandler dismisses stale "request changes" reviews on a PR. // DismissReviewsHandler dismisses stale "request changes" reviews on a PR.
// This replaces the GitHub-only ResolveThreadsHandler because Forgejo does // This replaces the GitHub-only ResolveThreadsHandler because Forgejo does
// not have a thread resolution API. // not have a thread resolution API.
//
type DismissReviewsHandler struct { type DismissReviewsHandler struct {
forge *forge.Client forge *forge.Client
} }
// NewDismissReviewsHandler creates a handler that dismisses stale reviews. // NewDismissReviewsHandler creates a handler that dismisses stale reviews.
//
func NewDismissReviewsHandler(f *forge.Client) *DismissReviewsHandler { func NewDismissReviewsHandler(f *forge.Client) *DismissReviewsHandler {
return &DismissReviewsHandler{forge: f} return &DismissReviewsHandler{forge: f}
} }

View file

@ -13,13 +13,11 @@ import (
// SendFixCommandHandler posts a comment on a PR asking for conflict or // SendFixCommandHandler posts a comment on a PR asking for conflict or
// review fixes. // review fixes.
//
type SendFixCommandHandler struct { type SendFixCommandHandler struct {
forge *forge.Client forge *forge.Client
} }
// NewSendFixCommandHandler creates a handler that posts fix commands. // NewSendFixCommandHandler creates a handler that posts fix commands.
//
func NewSendFixCommandHandler(f *forge.Client) *SendFixCommandHandler { func NewSendFixCommandHandler(f *forge.Client) *SendFixCommandHandler {
return &SendFixCommandHandler{forge: f} return &SendFixCommandHandler{forge: f}
} }

View file

@ -17,13 +17,11 @@ import (
// TickParentHandler ticks a child checkbox in the parent epic issue body // TickParentHandler ticks a child checkbox in the parent epic issue body
// after the child's PR has been merged. // after the child's PR has been merged.
//
type TickParentHandler struct { type TickParentHandler struct {
forge *forge.Client forge *forge.Client
} }
// NewTickParentHandler creates a handler that ticks parent epic checkboxes. // NewTickParentHandler creates a handler that ticks parent epic checkboxes.
//
func NewTickParentHandler(f *forge.Client) *TickParentHandler { func NewTickParentHandler(f *forge.Client) *TickParentHandler {
return &TickParentHandler{forge: f} return &TickParentHandler{forge: f}
} }

View file

@ -18,7 +18,6 @@ import (
var validPathComponent = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9._-]*$`) var validPathComponent = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9._-]*$`)
// JournalEntry is a single line in the JSONL audit log. // JournalEntry is a single line in the JSONL audit log.
//
type JournalEntry struct { type JournalEntry struct {
Timestamp string `json:"ts"` Timestamp string `json:"ts"`
Epic int `json:"epic"` Epic int `json:"epic"`
@ -32,7 +31,6 @@ type JournalEntry struct {
} }
// SignalSnapshot captures the structural state of a PR at the time of action. // SignalSnapshot captures the structural state of a PR at the time of action.
//
type SignalSnapshot struct { type SignalSnapshot struct {
PRState string `json:"pr_state"` PRState string `json:"pr_state"`
IsDraft bool `json:"is_draft"` IsDraft bool `json:"is_draft"`
@ -43,7 +41,6 @@ type SignalSnapshot struct {
} }
// ResultSnapshot captures the outcome of an action. // ResultSnapshot captures the outcome of an action.
//
type ResultSnapshot struct { type ResultSnapshot struct {
Success bool `json:"success"` Success bool `json:"success"`
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
@ -51,14 +48,12 @@ type ResultSnapshot struct {
} }
// Journal writes ActionResult entries to date-partitioned JSONL files. // Journal writes ActionResult entries to date-partitioned JSONL files.
//
type Journal struct { type Journal struct {
baseDir string baseDir string
mu sync.Mutex mu sync.Mutex
} }
// NewJournal creates a new Journal rooted at baseDir. // NewJournal creates a new Journal rooted at baseDir.
//
func NewJournal(baseDir string) (*Journal, error) { func NewJournal(baseDir string) (*Journal, error) {
if baseDir == "" { if baseDir == "" {
return nil, coreerr.E("jobrunner.NewJournal", "base directory is required", nil) return nil, coreerr.E("jobrunner.NewJournal", "base directory is required", nil)

View file

@ -11,7 +11,6 @@ import (
) )
// PollerConfig configures a Poller. // PollerConfig configures a Poller.
//
type PollerConfig struct { type PollerConfig struct {
Sources []JobSource Sources []JobSource
Handlers []JobHandler Handlers []JobHandler
@ -21,7 +20,6 @@ type PollerConfig struct {
} }
// Poller discovers signals from sources and dispatches them to handlers. // Poller discovers signals from sources and dispatches them to handlers.
//
type Poller struct { type Poller struct {
mu sync.RWMutex mu sync.RWMutex
sources []JobSource sources []JobSource
@ -33,7 +31,6 @@ type Poller struct {
} }
// NewPoller creates a Poller from the given config. // NewPoller creates a Poller from the given config.
//
func NewPoller(cfg PollerConfig) *Poller { func NewPoller(cfg PollerConfig) *Poller {
interval := cfg.PollInterval interval := cfg.PollInterval
if interval <= 0 { if interval <= 0 {

View file

@ -9,7 +9,6 @@ import (
// PipelineSignal is the structural snapshot of a child issue/PR. // PipelineSignal is the structural snapshot of a child issue/PR.
// Carries structural state plus issue title/body for dispatch prompts. // Carries structural state plus issue title/body for dispatch prompts.
//
type PipelineSignal struct { type PipelineSignal struct {
EpicNumber int EpicNumber int
ChildNumber int ChildNumber int
@ -46,7 +45,6 @@ func (s *PipelineSignal) HasUnresolvedThreads() bool {
} }
// ActionResult carries the outcome of a handler execution. // ActionResult carries the outcome of a handler execution.
//
type ActionResult struct { type ActionResult struct {
Action string `json:"action"` Action string `json:"action"`
RepoOwner string `json:"repo_owner"` RepoOwner string `json:"repo_owner"`
@ -62,7 +60,6 @@ type ActionResult struct {
} }
// JobSource discovers actionable work from an external system. // JobSource discovers actionable work from an external system.
//
type JobSource interface { type JobSource interface {
Name() string Name() string
Poll(ctx context.Context) ([]*PipelineSignal, error) Poll(ctx context.Context) ([]*PipelineSignal, error)
@ -70,7 +67,6 @@ type JobSource interface {
} }
// JobHandler processes a single pipeline signal. // JobHandler processes a single pipeline signal.
//
type JobHandler interface { type JobHandler interface {
Name() string Name() string
Match(signal *PipelineSignal) bool Match(signal *PipelineSignal) bool

View file

@ -5,7 +5,6 @@ package locales
import "embed" import "embed"
//
// //
//go:embed *.json //go:embed *.json
var FS embed.FS var FS embed.FS

View file

@ -15,7 +15,6 @@ import (
// CompiledManifest is the distribution-ready form of a manifest, written as // CompiledManifest is the distribution-ready form of a manifest, written as
// core.json at the repository root (not inside .core/). It embeds the // core.json at the repository root (not inside .core/). It embeds the
// original Manifest and adds build metadata stapled at compile time. // original Manifest and adds build metadata stapled at compile time.
//
type CompiledManifest struct { type CompiledManifest struct {
Manifest `json:",inline" yaml:",inline"` Manifest `json:",inline" yaml:",inline"`
@ -27,7 +26,6 @@ type CompiledManifest struct {
} }
// CompileOptions controls how Compile populates the build metadata. // CompileOptions controls how Compile populates the build metadata.
//
type CompileOptions struct { type CompileOptions struct {
Commit string // Git commit hash Commit string // Git commit hash
Tag string // Git tag (e.g. v1.0.0) Tag string // Git tag (e.g. v1.0.0)
@ -37,7 +35,6 @@ type CompileOptions struct {
// Compile produces a CompiledManifest from a source manifest and build // Compile produces a CompiledManifest from a source manifest and build
// options. If opts.SignKey is provided the manifest is signed first. // options. If opts.SignKey is provided the manifest is signed first.
//
func Compile(m *Manifest, opts CompileOptions) (*CompiledManifest, error) { func Compile(m *Manifest, opts CompileOptions) (*CompiledManifest, error) {
if m == nil { if m == nil {
return nil, coreerr.E("manifest.Compile", "nil manifest", nil) return nil, coreerr.E("manifest.Compile", "nil manifest", nil)
@ -66,13 +63,11 @@ func Compile(m *Manifest, opts CompileOptions) (*CompiledManifest, error) {
} }
// MarshalJSON serialises a CompiledManifest to JSON bytes. // MarshalJSON serialises a CompiledManifest to JSON bytes.
//
func MarshalJSON(cm *CompiledManifest) ([]byte, error) { func MarshalJSON(cm *CompiledManifest) ([]byte, error) {
return json.MarshalIndent(cm, "", " ") return json.MarshalIndent(cm, "", " ")
} }
// ParseCompiled decodes a core.json into a CompiledManifest. // ParseCompiled decodes a core.json into a CompiledManifest.
//
func ParseCompiled(data []byte) (*CompiledManifest, error) { func ParseCompiled(data []byte) (*CompiledManifest, error) {
var cm CompiledManifest var cm CompiledManifest
if err := json.Unmarshal(data, &cm); err != nil { if err := json.Unmarshal(data, &cm); err != nil {
@ -85,7 +80,6 @@ const compiledPath = "core.json"
// WriteCompiled writes a CompiledManifest as core.json to the given root // WriteCompiled writes a CompiledManifest as core.json to the given root
// directory. The file lives at the distribution root, not inside .core/. // directory. The file lives at the distribution root, not inside .core/.
//
func WriteCompiled(medium io.Medium, root string, cm *CompiledManifest) error { func WriteCompiled(medium io.Medium, root string, cm *CompiledManifest) error {
data, err := MarshalJSON(cm) data, err := MarshalJSON(cm)
if err != nil { if err != nil {
@ -96,7 +90,6 @@ func WriteCompiled(medium io.Medium, root string, cm *CompiledManifest) error {
} }
// LoadCompiled reads and parses a core.json from the given root directory. // LoadCompiled reads and parses a core.json from the given root directory.
//
func LoadCompiled(medium io.Medium, root string) (*CompiledManifest, error) { func LoadCompiled(medium io.Medium, root string) (*CompiledManifest, error) {
path := filepath.Join(root, compiledPath) path := filepath.Join(root, compiledPath)
data, err := medium.Read(path) data, err := medium.Read(path)

View file

@ -14,13 +14,11 @@ import (
const manifestPath = ".core/manifest.yaml" const manifestPath = ".core/manifest.yaml"
// MarshalYAML serializes a manifest to YAML bytes. // MarshalYAML serializes a manifest to YAML bytes.
//
func MarshalYAML(m *Manifest) ([]byte, error) { func MarshalYAML(m *Manifest) ([]byte, error) {
return yaml.Marshal(m) return yaml.Marshal(m)
} }
// Load reads and parses a .core/manifest.yaml from the given root directory. // Load reads and parses a .core/manifest.yaml from the given root directory.
//
func Load(medium io.Medium, root string) (*Manifest, error) { func Load(medium io.Medium, root string) (*Manifest, error) {
path := filepath.Join(root, manifestPath) path := filepath.Join(root, manifestPath)
data, err := medium.Read(path) data, err := medium.Read(path)
@ -31,7 +29,6 @@ func Load(medium io.Medium, root string) (*Manifest, error) {
} }
// LoadVerified reads, parses, and verifies the ed25519 signature. // LoadVerified reads, parses, and verifies the ed25519 signature.
//
func LoadVerified(medium io.Medium, root string, pub ed25519.PublicKey) (*Manifest, error) { func LoadVerified(medium io.Medium, root string, pub ed25519.PublicKey) (*Manifest, error) {
m, err := Load(medium, root) m, err := Load(medium, root)
if err != nil { if err != nil {

View file

@ -8,7 +8,6 @@ import (
) )
// Manifest represents a .core/manifest.yaml application manifest. // Manifest represents a .core/manifest.yaml application manifest.
//
type Manifest struct { type Manifest struct {
Code string `yaml:"code" json:"code"` Code string `yaml:"code" json:"code"`
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
@ -34,7 +33,6 @@ type Manifest struct {
} }
// ElementSpec describes a web component for GUI rendering. // ElementSpec describes a web component for GUI rendering.
//
type ElementSpec struct { type ElementSpec struct {
// Tag is the custom element tag name, e.g. "core-cool-widget". // Tag is the custom element tag name, e.g. "core-cool-widget".
Tag string `yaml:"tag" json:"tag"` Tag string `yaml:"tag" json:"tag"`
@ -50,7 +48,6 @@ func (m *Manifest) IsProvider() bool {
} }
// Permissions declares the I/O capabilities a module requires. // Permissions declares the I/O capabilities a module requires.
//
type Permissions struct { type Permissions struct {
Read []string `yaml:"read" json:"read"` Read []string `yaml:"read" json:"read"`
Write []string `yaml:"write" json:"write"` Write []string `yaml:"write" json:"write"`
@ -59,7 +56,6 @@ type Permissions struct {
} }
// DaemonSpec describes a long-running process managed by the runtime. // DaemonSpec describes a long-running process managed by the runtime.
//
type DaemonSpec struct { type DaemonSpec struct {
Binary string `yaml:"binary,omitempty" json:"binary,omitempty"` Binary string `yaml:"binary,omitempty" json:"binary,omitempty"`
Args []string `yaml:"args,omitempty" json:"args,omitempty"` Args []string `yaml:"args,omitempty" json:"args,omitempty"`

View file

@ -18,7 +18,6 @@ func signable(m *Manifest) ([]byte, error) {
} }
// Sign computes the ed25519 signature and stores it in m.Sign (base64). // Sign computes the ed25519 signature and stores it in m.Sign (base64).
//
func Sign(m *Manifest, priv ed25519.PrivateKey) error { func Sign(m *Manifest, priv ed25519.PrivateKey) error {
msg, err := signable(m) msg, err := signable(m)
if err != nil { if err != nil {
@ -30,7 +29,6 @@ func Sign(m *Manifest, priv ed25519.PrivateKey) error {
} }
// Verify checks the ed25519 signature in m.Sign against the public key. // Verify checks the ed25519 signature in m.Sign against the public key.
//
func Verify(m *Manifest, pub ed25519.PublicKey) (bool, error) { func Verify(m *Manifest, pub ed25519.PublicKey) (bool, error) {
if m.Sign == "" { if m.Sign == "" {
return false, coreerr.E("manifest.Verify", "no signature present", nil) return false, coreerr.E("manifest.Verify", "no signature present", nil)

View file

@ -16,12 +16,10 @@ import (
) )
// IndexVersion is the current marketplace index format version. // IndexVersion is the current marketplace index format version.
//
const IndexVersion = 1 const IndexVersion = 1
// Builder constructs a marketplace Index by crawling directories for // Builder constructs a marketplace Index by crawling directories for
// core.json (compiled manifests) or .core/manifest.yaml files. // core.json (compiled manifests) or .core/manifest.yaml files.
//
type Builder struct { type Builder struct {
// BaseURL is the prefix for constructing repository URLs, e.g. // BaseURL is the prefix for constructing repository URLs, e.g.
// "https://forge.lthn.ai". When set, module Repo is derived as // "https://forge.lthn.ai". When set, module Repo is derived as
@ -88,7 +86,6 @@ func (b *Builder) BuildFromDirs(dirs ...string) (*Index, error) {
// BuildFromManifests constructs an Index from pre-loaded manifests. // BuildFromManifests constructs an Index from pre-loaded manifests.
// This is useful when manifests have already been collected (e.g. from // This is useful when manifests have already been collected (e.g. from
// a Forge API crawl). // a Forge API crawl).
//
func BuildFromManifests(manifests []*manifest.Manifest) *Index { func BuildFromManifests(manifests []*manifest.Manifest) *Index {
var modules []Module var modules []Module
seen := make(map[string]bool) seen := make(map[string]bool)
@ -119,7 +116,6 @@ func BuildFromManifests(manifests []*manifest.Manifest) *Index {
} }
// WriteIndex serialises an Index to JSON and writes it to the given path. // WriteIndex serialises an Index to JSON and writes it to the given path.
//
func WriteIndex(path string, idx *Index) error { func WriteIndex(path string, idx *Index) error {
if err := coreio.Local.EnsureDir(filepath.Dir(path)); err != nil { if err := coreio.Local.EnsureDir(filepath.Dir(path)); err != nil {
return coreerr.E("marketplace.WriteIndex", "mkdir failed", err) return coreerr.E("marketplace.WriteIndex", "mkdir failed", err)

View file

@ -14,7 +14,6 @@ import (
) )
// DiscoveredProvider represents a runtime provider found on disk. // DiscoveredProvider represents a runtime provider found on disk.
//
type DiscoveredProvider struct { type DiscoveredProvider struct {
// Dir is the absolute path to the provider directory. // Dir is the absolute path to the provider directory.
Dir string Dir string
@ -27,7 +26,6 @@ type DiscoveredProvider struct {
// Each subdirectory is checked for a .core/manifest.yaml file. Directories // Each subdirectory is checked for a .core/manifest.yaml file. Directories
// without a valid manifest are skipped with a log warning. // without a valid manifest are skipped with a log warning.
// Only manifests with provider fields (namespace + binary) are returned. // Only manifests with provider fields (namespace + binary) are returned.
//
func DiscoverProviders(dir string) ([]DiscoveredProvider, error) { func DiscoverProviders(dir string) ([]DiscoveredProvider, error) {
entries, err := os.ReadDir(dir) entries, err := os.ReadDir(dir)
if err != nil { if err != nil {
@ -73,7 +71,6 @@ func DiscoverProviders(dir string) ([]DiscoveredProvider, error) {
} }
// ProviderRegistryEntry records metadata about an installed provider. // ProviderRegistryEntry records metadata about an installed provider.
//
type ProviderRegistryEntry struct { type ProviderRegistryEntry struct {
Installed string `yaml:"installed" json:"installed"` Installed string `yaml:"installed" json:"installed"`
Version string `yaml:"version" json:"version"` Version string `yaml:"version" json:"version"`
@ -82,7 +79,6 @@ type ProviderRegistryEntry struct {
} }
// ProviderRegistryFile represents the registry.yaml file tracking installed providers. // ProviderRegistryFile represents the registry.yaml file tracking installed providers.
//
type ProviderRegistryFile struct { type ProviderRegistryFile struct {
Version int `yaml:"version" json:"version"` Version int `yaml:"version" json:"version"`
Providers map[string]ProviderRegistryEntry `yaml:"providers" json:"providers"` Providers map[string]ProviderRegistryEntry `yaml:"providers" json:"providers"`
@ -90,7 +86,6 @@ type ProviderRegistryFile struct {
// LoadProviderRegistry reads a registry.yaml file from the given path. // LoadProviderRegistry reads a registry.yaml file from the given path.
// Returns an empty registry if the file does not exist. // Returns an empty registry if the file does not exist.
//
func LoadProviderRegistry(path string) (*ProviderRegistryFile, error) { func LoadProviderRegistry(path string) (*ProviderRegistryFile, error) {
raw, err := coreio.Local.Read(path) raw, err := coreio.Local.Read(path)
if err != nil { if err != nil {
@ -116,7 +111,6 @@ func LoadProviderRegistry(path string) (*ProviderRegistryFile, error) {
} }
// SaveProviderRegistry writes the registry to the given path. // SaveProviderRegistry writes the registry to the given path.
//
func SaveProviderRegistry(path string, reg *ProviderRegistryFile) error { func SaveProviderRegistry(path string, reg *ProviderRegistryFile) error {
if err := coreio.Local.EnsureDir(filepath.Dir(path)); err != nil { if err := coreio.Local.EnsureDir(filepath.Dir(path)); err != nil {
return coreerr.E("marketplace.SaveProviderRegistry", "ensure directory", err) return coreerr.E("marketplace.SaveProviderRegistry", "ensure directory", err)

View file

@ -21,7 +21,6 @@ import (
const storeGroup = "_modules" const storeGroup = "_modules"
// Installer handles module installation from Git repos. // Installer handles module installation from Git repos.
//
type Installer struct { type Installer struct {
medium io.Medium medium io.Medium
modulesDir string modulesDir string
@ -29,7 +28,6 @@ type Installer struct {
} }
// NewInstaller creates a new module installer. // NewInstaller creates a new module installer.
//
func NewInstaller(m io.Medium, modulesDir string, st *store.Store) *Installer { func NewInstaller(m io.Medium, modulesDir string, st *store.Store) *Installer {
return &Installer{ return &Installer{
medium: m, medium: m,
@ -39,7 +37,6 @@ func NewInstaller(m io.Medium, modulesDir string, st *store.Store) *Installer {
} }
// InstalledModule holds stored metadata about an installed module. // InstalledModule holds stored metadata about an installed module.
//
type InstalledModule struct { type InstalledModule struct {
Code string `json:"code"` Code string `json:"code"`
Name string `json:"name"` Name string `json:"name"`

View file

@ -10,7 +10,6 @@ import (
) )
// Module is a marketplace entry pointing to a module's Git repo. // Module is a marketplace entry pointing to a module's Git repo.
//
type Module struct { type Module struct {
Code string `json:"code"` Code string `json:"code"`
Name string `json:"name"` Name string `json:"name"`
@ -20,7 +19,6 @@ type Module struct {
} }
// Index is the root marketplace catalog. // Index is the root marketplace catalog.
//
type Index struct { type Index struct {
Version int `json:"version"` Version int `json:"version"`
Modules []Module `json:"modules"` Modules []Module `json:"modules"`
@ -28,7 +26,6 @@ type Index struct {
} }
// ParseIndex decodes a marketplace index.json. // ParseIndex decodes a marketplace index.json.
//
func ParseIndex(data []byte) (*Index, error) { func ParseIndex(data []byte) (*Index, error) {
var idx Index var idx Index
if err := json.Unmarshal(data, &idx); err != nil { if err := json.Unmarshal(data, &idx); err != nil {

View file

@ -7,7 +7,5 @@ import "embed"
// Assets holds the built UI bundle (core-scm.js and related files). // Assets holds the built UI bundle (core-scm.js and related files).
// The directory is populated by running `npm run build` in the ui/ directory. // The directory is populated by running `npm run build` in the ui/ directory.
// //
//
//
//go:embed all:ui/dist //go:embed all:ui/dist
var Assets embed.FS var Assets embed.FS

View file

@ -26,7 +26,6 @@ import (
// ScmProvider wraps go-scm marketplace, manifest, and registry operations // ScmProvider wraps go-scm marketplace, manifest, and registry operations
// as a service provider. It implements Provider, Streamable, Describable, // as a service provider. It implements Provider, Streamable, Describable,
// and Renderable. // and Renderable.
//
type ScmProvider struct { type ScmProvider struct {
index *marketplace.Index index *marketplace.Index
installer *marketplace.Installer installer *marketplace.Installer
@ -46,7 +45,6 @@ var (
// NewProvider creates an SCM provider backed by the given marketplace index, // NewProvider creates an SCM provider backed by the given marketplace index,
// installer, and registry. The WS hub is used to emit real-time events. // installer, and registry. The WS hub is used to emit real-time events.
// Pass nil for any dependency that is not available. // Pass nil for any dependency that is not available.
//
func NewProvider(idx *marketplace.Index, inst *marketplace.Installer, reg *repos.Registry, hub *ws.Hub) *ScmProvider { func NewProvider(idx *marketplace.Index, inst *marketplace.Installer, reg *repos.Registry, hub *ws.Hub) *ScmProvider {
return &ScmProvider{ return &ScmProvider{
index: idx, index: idx,

View file

@ -3,7 +3,6 @@
package plugin package plugin
// PluginConfig holds configuration for a single installed plugin. // PluginConfig holds configuration for a single installed plugin.
//
type PluginConfig struct { type PluginConfig struct {
Name string `json:"name" yaml:"name"` Name string `json:"name" yaml:"name"`
Version string `json:"version" yaml:"version"` Version string `json:"version" yaml:"version"`

View file

@ -17,14 +17,12 @@ import (
) )
// Installer handles plugin installation from GitHub. // Installer handles plugin installation from GitHub.
//
type Installer struct { type Installer struct {
medium io.Medium medium io.Medium
registry *Registry registry *Registry
} }
// NewInstaller creates a new plugin installer. // NewInstaller creates a new plugin installer.
//
func NewInstaller(m io.Medium, registry *Registry) *Installer { func NewInstaller(m io.Medium, registry *Registry) *Installer {
return &Installer{ return &Installer{
medium: m, medium: m,
@ -182,8 +180,6 @@ func (i *Installer) cloneRepo(ctx context.Context, org, repo, version, dest stri
// Accepted formats: // Accepted formats:
// - "org/repo" -> org="org", repo="repo", version="" // - "org/repo" -> org="org", repo="repo", version=""
// - "org/repo@v1.0" -> org="org", repo="repo", version="v1.0" // - "org/repo@v1.0" -> org="org", repo="repo", version="v1.0"
//
//
func ParseSource(source string) (org, repo, version string, err error) { func ParseSource(source string) (org, repo, version string, err error) {
source, err = url.PathUnescape(source) source, err = url.PathUnescape(source)
if err != nil { if err != nil {

View file

@ -10,14 +10,12 @@ import (
) )
// Loader loads plugins from the filesystem. // Loader loads plugins from the filesystem.
//
type Loader struct { type Loader struct {
medium io.Medium medium io.Medium
baseDir string baseDir string
} }
// NewLoader creates a new plugin loader. // NewLoader creates a new plugin loader.
//
func NewLoader(m io.Medium, baseDir string) *Loader { func NewLoader(m io.Medium, baseDir string) *Loader {
return &Loader{ return &Loader{
medium: m, medium: m,

View file

@ -11,7 +11,6 @@ import (
// Manifest represents a plugin.json manifest file. // Manifest represents a plugin.json manifest file.
// Each plugin repository must contain a plugin.json at its root. // Each plugin repository must contain a plugin.json at its root.
//
type Manifest struct { type Manifest struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
@ -23,7 +22,6 @@ type Manifest struct {
} }
// LoadManifest reads and parses a plugin.json file from the given path. // LoadManifest reads and parses a plugin.json file from the given path.
//
func LoadManifest(m io.Medium, path string) (*Manifest, error) { func LoadManifest(m io.Medium, path string) (*Manifest, error) {
content, err := m.Read(path) content, err := m.Read(path)
if err != nil { if err != nil {

View file

@ -16,7 +16,6 @@ package plugin
import "context" import "context"
// Plugin is the interface that all plugins must implement. // Plugin is the interface that all plugins must implement.
//
type Plugin interface { type Plugin interface {
// Name returns the plugin's unique identifier. // Name returns the plugin's unique identifier.
Name() string Name() string
@ -36,7 +35,6 @@ type Plugin interface {
// BasePlugin provides a default implementation of Plugin. // BasePlugin provides a default implementation of Plugin.
// Embed this in concrete plugin types to inherit default behaviour. // Embed this in concrete plugin types to inherit default behaviour.
//
type BasePlugin struct { type BasePlugin struct {
PluginName string PluginName string
PluginVersion string PluginVersion string

View file

@ -16,7 +16,6 @@ const registryFilename = "registry.json"
// Registry manages installed plugins. // Registry manages installed plugins.
// Plugin metadata is stored in a registry.json file under the base path. // Plugin metadata is stored in a registry.json file under the base path.
//
type Registry struct { type Registry struct {
medium io.Medium medium io.Medium
basePath string // e.g., ~/.core/plugins/ basePath string // e.g., ~/.core/plugins/
@ -24,7 +23,6 @@ type Registry struct {
} }
// NewRegistry creates a new plugin registry. // NewRegistry creates a new plugin registry.
//
func NewRegistry(m io.Medium, basePath string) *Registry { func NewRegistry(m io.Medium, basePath string) *Registry {
return &Registry{ return &Registry{
medium: m, medium: m,

View file

@ -13,7 +13,6 @@ import (
// GitState holds per-machine git sync state for a workspace. // GitState holds per-machine git sync state for a workspace.
// Stored at .core/git.yaml and .gitignored (not shared across machines). // Stored at .core/git.yaml and .gitignored (not shared across machines).
//
type GitState struct { type GitState struct {
Version int `yaml:"version"` Version int `yaml:"version"`
Repos map[string]*RepoGitState `yaml:"repos,omitempty"` Repos map[string]*RepoGitState `yaml:"repos,omitempty"`
@ -21,7 +20,6 @@ type GitState struct {
} }
// RepoGitState tracks the last known git state for a single repo. // RepoGitState tracks the last known git state for a single repo.
//
type RepoGitState struct { type RepoGitState struct {
LastPull time.Time `yaml:"last_pull,omitempty"` LastPull time.Time `yaml:"last_pull,omitempty"`
LastPush time.Time `yaml:"last_push,omitempty"` LastPush time.Time `yaml:"last_push,omitempty"`
@ -32,7 +30,6 @@ type RepoGitState struct {
} }
// AgentState tracks which agent last touched which repos. // AgentState tracks which agent last touched which repos.
//
type AgentState struct { type AgentState struct {
LastSeen time.Time `yaml:"last_seen"` LastSeen time.Time `yaml:"last_seen"`
Active []string `yaml:"active,omitempty"` Active []string `yaml:"active,omitempty"`
@ -40,7 +37,6 @@ type AgentState struct {
// LoadGitState reads .core/git.yaml from the given workspace root directory. // LoadGitState reads .core/git.yaml from the given workspace root directory.
// Returns a new empty GitState if the file does not exist. // Returns a new empty GitState if the file does not exist.
//
func LoadGitState(m io.Medium, root string) (*GitState, error) { func LoadGitState(m io.Medium, root string) (*GitState, error) {
path := filepath.Join(root, ".core", "git.yaml") path := filepath.Join(root, ".core", "git.yaml")
@ -69,7 +65,6 @@ func LoadGitState(m io.Medium, root string) (*GitState, error) {
} }
// SaveGitState writes .core/git.yaml to the given workspace root directory. // SaveGitState writes .core/git.yaml to the given workspace root directory.
//
func SaveGitState(m io.Medium, root string, gs *GitState) error { func SaveGitState(m io.Medium, root string, gs *GitState) error {
coreDir := filepath.Join(root, ".core") coreDir := filepath.Join(root, ".core")
if err := m.EnsureDir(coreDir); err != nil { if err := m.EnsureDir(coreDir); err != nil {
@ -90,7 +85,6 @@ func SaveGitState(m io.Medium, root string, gs *GitState) error {
} }
// NewGitState returns a new empty GitState with version 1. // NewGitState returns a new empty GitState with version 1.
//
func NewGitState() *GitState { func NewGitState() *GitState {
return &GitState{ return &GitState{
Version: 1, Version: 1,

View file

@ -13,7 +13,6 @@ import (
// KBConfig holds knowledge base configuration for a workspace. // KBConfig holds knowledge base configuration for a workspace.
// Stored at .core/kb.yaml and checked into git. // Stored at .core/kb.yaml and checked into git.
//
type KBConfig struct { type KBConfig struct {
Version int `yaml:"version"` Version int `yaml:"version"`
Wiki WikiConfig `yaml:"wiki"` Wiki WikiConfig `yaml:"wiki"`
@ -21,7 +20,6 @@ type KBConfig struct {
} }
// WikiConfig controls local wiki mirror behaviour. // WikiConfig controls local wiki mirror behaviour.
//
type WikiConfig struct { type WikiConfig struct {
// Enabled toggles wiki cloning on sync. // Enabled toggles wiki cloning on sync.
Enabled bool `yaml:"enabled"` Enabled bool `yaml:"enabled"`
@ -33,7 +31,6 @@ type WikiConfig struct {
} }
// KBSearch configures vector search against the OpenBrain Qdrant collection. // KBSearch configures vector search against the OpenBrain Qdrant collection.
//
type KBSearch struct { type KBSearch struct {
// QdrantHost is the Qdrant server (gRPC). // QdrantHost is the Qdrant server (gRPC).
QdrantHost string `yaml:"qdrant_host"` QdrantHost string `yaml:"qdrant_host"`
@ -50,7 +47,6 @@ type KBSearch struct {
} }
// DefaultKBConfig returns sensible defaults for knowledge base config. // DefaultKBConfig returns sensible defaults for knowledge base config.
//
func DefaultKBConfig() *KBConfig { func DefaultKBConfig() *KBConfig {
return &KBConfig{ return &KBConfig{
Version: 1, Version: 1,
@ -72,7 +68,6 @@ func DefaultKBConfig() *KBConfig {
// LoadKBConfig reads .core/kb.yaml from the given workspace root directory. // LoadKBConfig reads .core/kb.yaml from the given workspace root directory.
// Returns defaults if the file does not exist. // Returns defaults if the file does not exist.
//
func LoadKBConfig(m io.Medium, root string) (*KBConfig, error) { func LoadKBConfig(m io.Medium, root string) (*KBConfig, error) {
path := filepath.Join(root, ".core", "kb.yaml") path := filepath.Join(root, ".core", "kb.yaml")
@ -94,7 +89,6 @@ func LoadKBConfig(m io.Medium, root string) (*KBConfig, error) {
} }
// SaveKBConfig writes .core/kb.yaml to the given workspace root directory. // SaveKBConfig writes .core/kb.yaml to the given workspace root directory.
//
func SaveKBConfig(m io.Medium, root string, kb *KBConfig) error { func SaveKBConfig(m io.Medium, root string, kb *KBConfig) error {
coreDir := filepath.Join(root, ".core") coreDir := filepath.Join(root, ".core")
if err := m.EnsureDir(coreDir); err != nil { if err := m.EnsureDir(coreDir); err != nil {

View file

@ -16,7 +16,6 @@ import (
) )
// Registry represents a collection of repositories defined in repos.yaml. // Registry represents a collection of repositories defined in repos.yaml.
//
type Registry struct { type Registry struct {
Version int `yaml:"version"` Version int `yaml:"version"`
Org string `yaml:"org"` Org string `yaml:"org"`
@ -27,7 +26,6 @@ type Registry struct {
} }
// RegistryDefaults contains default values applied to all repos. // RegistryDefaults contains default values applied to all repos.
//
type RegistryDefaults struct { type RegistryDefaults struct {
CI string `yaml:"ci"` CI string `yaml:"ci"`
License string `yaml:"license"` License string `yaml:"license"`
@ -35,7 +33,6 @@ type RegistryDefaults struct {
} }
// RepoType indicates the role of a repository in the ecosystem. // RepoType indicates the role of a repository in the ecosystem.
//
type RepoType string type RepoType string
// Repository type constants for ecosystem classification. // Repository type constants for ecosystem classification.
@ -55,7 +52,6 @@ const (
) )
// Repo represents a single repository in the registry. // Repo represents a single repository in the registry.
//
type Repo struct { type Repo struct {
Name string `yaml:"-"` // Set from map key Name string `yaml:"-"` // Set from map key
Type string `yaml:"type"` Type string `yaml:"type"`

View file

@ -13,7 +13,6 @@ import (
// WorkConfig holds sync policy for a workspace. // WorkConfig holds sync policy for a workspace.
// Stored at .core/work.yaml and checked into git (shared across the team). // Stored at .core/work.yaml and checked into git (shared across the team).
//
type WorkConfig struct { type WorkConfig struct {
Version int `yaml:"version"` Version int `yaml:"version"`
Sync SyncConfig `yaml:"sync"` Sync SyncConfig `yaml:"sync"`
@ -22,7 +21,6 @@ type WorkConfig struct {
} }
// SyncConfig controls how and when repos are synced. // SyncConfig controls how and when repos are synced.
//
type SyncConfig struct { type SyncConfig struct {
Interval time.Duration `yaml:"interval"` Interval time.Duration `yaml:"interval"`
AutoPull bool `yaml:"auto_pull"` AutoPull bool `yaml:"auto_pull"`
@ -31,7 +29,6 @@ type SyncConfig struct {
} }
// AgentPolicy controls multi-agent clash prevention. // AgentPolicy controls multi-agent clash prevention.
//
type AgentPolicy struct { type AgentPolicy struct {
Heartbeat time.Duration `yaml:"heartbeat"` Heartbeat time.Duration `yaml:"heartbeat"`
StaleAfter time.Duration `yaml:"stale_after"` StaleAfter time.Duration `yaml:"stale_after"`
@ -39,7 +36,6 @@ type AgentPolicy struct {
} }
// DefaultWorkConfig returns sensible defaults for workspace sync. // DefaultWorkConfig returns sensible defaults for workspace sync.
//
func DefaultWorkConfig() *WorkConfig { func DefaultWorkConfig() *WorkConfig {
return &WorkConfig{ return &WorkConfig{
Version: 1, Version: 1,
@ -60,7 +56,6 @@ func DefaultWorkConfig() *WorkConfig {
// LoadWorkConfig reads .core/work.yaml from the given workspace root directory. // LoadWorkConfig reads .core/work.yaml from the given workspace root directory.
// Returns defaults if the file does not exist. // Returns defaults if the file does not exist.
//
func LoadWorkConfig(m io.Medium, root string) (*WorkConfig, error) { func LoadWorkConfig(m io.Medium, root string) (*WorkConfig, error) {
path := filepath.Join(root, ".core", "work.yaml") path := filepath.Join(root, ".core", "work.yaml")
@ -82,7 +77,6 @@ func LoadWorkConfig(m io.Medium, root string) (*WorkConfig, error) {
} }
// SaveWorkConfig writes .core/work.yaml to the given workspace root directory. // SaveWorkConfig writes .core/work.yaml to the given workspace root directory.
//
func SaveWorkConfig(m io.Medium, root string, wc *WorkConfig) error { func SaveWorkConfig(m io.Medium, root string, wc *WorkConfig) error {
coreDir := filepath.Join(root, ".core") coreDir := filepath.Join(root, ".core")
if err := m.EnsureDir(coreDir); err != nil { if err := m.EnsureDir(coreDir); err != nil {