chore(ax): gofmt exported declaration comments
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
305aa0da6f
commit
c42cc4a6ce
65 changed files with 0 additions and 248 deletions
|
|
@ -10,7 +10,6 @@ import (
|
|||
)
|
||||
|
||||
// RunMode determines the execution strategy for a dispatched task.
|
||||
//
|
||||
type RunMode string
|
||||
|
||||
const (
|
||||
|
|
@ -21,14 +20,12 @@ const (
|
|||
)
|
||||
|
||||
// Spinner is the Clotho orchestrator that determines the fate of each task.
|
||||
//
|
||||
type Spinner struct {
|
||||
Config ClothoConfig
|
||||
Agents map[string]AgentConfig
|
||||
}
|
||||
|
||||
// NewSpinner creates a new Clotho orchestrator.
|
||||
//
|
||||
func NewSpinner(cfg ClothoConfig, agents map[string]AgentConfig) *Spinner {
|
||||
return &Spinner{
|
||||
Config: cfg,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
)
|
||||
|
||||
// AgentConfig represents a single agent machine in the config file.
|
||||
//
|
||||
type AgentConfig struct {
|
||||
Host string `yaml:"host" mapstructure:"host"`
|
||||
QueueDir string `yaml:"queue_dir" mapstructure:"queue_dir"`
|
||||
|
|
@ -26,7 +25,6 @@ type AgentConfig struct {
|
|||
}
|
||||
|
||||
// ClothoConfig controls the orchestration strategy.
|
||||
//
|
||||
type ClothoConfig struct {
|
||||
Strategy string `yaml:"strategy" mapstructure:"strategy"` // direct, clotho-verified
|
||||
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.
|
||||
// Returns an empty map (not an error) if no agents are configured.
|
||||
//
|
||||
func LoadAgents(cfg *config.Config) (map[string]AgentConfig, error) {
|
||||
var agents map[string]AgentConfig
|
||||
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.
|
||||
//
|
||||
func LoadActiveAgents(cfg *config.Config) (map[string]AgentConfig, error) {
|
||||
all, err := LoadAgents(cfg)
|
||||
if err != nil {
|
||||
|
|
@ -83,7 +79,6 @@ func LoadActiveAgents(cfg *config.Config) (map[string]AgentConfig, error) {
|
|||
|
||||
// LoadClothoConfig loads the Clotho orchestrator settings.
|
||||
// Returns sensible defaults if no config is present.
|
||||
//
|
||||
func LoadClothoConfig(cfg *config.Config) (ClothoConfig, error) {
|
||||
var cc ClothoConfig
|
||||
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.
|
||||
//
|
||||
func SaveAgent(cfg *config.Config, name string, ac AgentConfig) error {
|
||||
key := fmt.Sprintf("agentci.agents.%s", name)
|
||||
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.
|
||||
//
|
||||
func RemoveAgent(cfg *config.Config, name string) error {
|
||||
var agents map[string]AgentConfig
|
||||
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).
|
||||
//
|
||||
func ListAgents(cfg *config.Config) (map[string]AgentConfig, error) {
|
||||
var agents map[string]AgentConfig
|
||||
if err := cfg.Get("agentci.agents", &agents); err != nil {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
// Returns the validated input unchanged.
|
||||
//
|
||||
func SanitizePath(input string) (string, error) {
|
||||
if input == "" {
|
||||
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.
|
||||
//
|
||||
func ValidatePathElement(input string) (string, error) {
|
||||
return SanitizePath(input)
|
||||
}
|
||||
|
||||
// ResolvePathWithinRoot resolves a validated path element beneath a root directory.
|
||||
//
|
||||
func ResolvePathWithinRoot(root string, input string) (string, string, error) {
|
||||
safeName, err := ValidatePathElement(input)
|
||||
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.
|
||||
//
|
||||
func ValidateRemoteDir(dir string) (string, error) {
|
||||
if strings.TrimSpace(dir) == "" {
|
||||
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.
|
||||
//
|
||||
func JoinRemotePath(base string, parts ...string) (string, error) {
|
||||
safeBase, err := ValidateRemoteDir(base)
|
||||
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.
|
||||
// Prefer exec.Command arguments over constructing shell strings where possible.
|
||||
//
|
||||
func EscapeShellArg(arg string) string {
|
||||
return "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'"
|
||||
}
|
||||
|
||||
// SecureSSHCommand creates an SSH exec.Cmd with strict host key checking and batch mode.
|
||||
//
|
||||
func SecureSSHCommand(host string, remoteCmd string) *exec.Cmd {
|
||||
return exec.Command("ssh",
|
||||
"-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.
|
||||
//
|
||||
func MaskToken(token string) string {
|
||||
if len(token) < 8 {
|
||||
return "*****"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ var (
|
|||
)
|
||||
|
||||
// AddCollectCommands registers the 'collect' command and all subcommands.
|
||||
//
|
||||
func AddCollectCommands(root *cli.Command) {
|
||||
collectCmd := &cli.Command{
|
||||
Use: "collect",
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ var (
|
|||
)
|
||||
|
||||
// AddForgeCommands registers the 'forge' command and all subcommands.
|
||||
//
|
||||
func AddForgeCommands(root *cli.Command) {
|
||||
forgeCmd := &cli.Command{
|
||||
Use: "forge",
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ var (
|
|||
)
|
||||
|
||||
// AddGiteaCommands registers the 'gitea' command and all subcommands.
|
||||
//
|
||||
func AddGiteaCommands(root *cli.Command) {
|
||||
giteaCmd := &cli.Command{
|
||||
Use: "gitea",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ var (
|
|||
)
|
||||
|
||||
// AddScmCommands registers the 'scm' command and all subcommands.
|
||||
//
|
||||
func AddScmCommands(root *cli.Command) {
|
||||
scmCmd := &cli.Command{
|
||||
Use: "scm",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ var httpClient = &http.Client{
|
|||
}
|
||||
|
||||
// BitcoinTalkCollector collects forum posts from BitcoinTalk.
|
||||
//
|
||||
type BitcoinTalkCollector struct {
|
||||
// TopicID is the numeric topic identifier.
|
||||
TopicID string
|
||||
|
|
@ -284,7 +283,6 @@ func formatPostMarkdown(num int, post btPost) string {
|
|||
|
||||
// ParsePostsFromHTML parses BitcoinTalk posts from raw HTML content.
|
||||
// This is exported for testing purposes.
|
||||
//
|
||||
func ParsePostsFromHTML(htmlContent string) ([]btPost, error) {
|
||||
doc, err := html.Parse(strings.NewReader(htmlContent))
|
||||
if err != nil {
|
||||
|
|
@ -294,17 +292,14 @@ func ParsePostsFromHTML(htmlContent string) ([]btPost, error) {
|
|||
}
|
||||
|
||||
// FormatPostMarkdown is exported for testing purposes.
|
||||
//
|
||||
func FormatPostMarkdown(num int, author, date, content string) string {
|
||||
return formatPostMarkdown(num, btPost{Author: author, Date: date, Content: content})
|
||||
}
|
||||
|
||||
// FetchPageFunc is an injectable function type for fetching pages, used in testing.
|
||||
//
|
||||
type FetchPageFunc func(ctx context.Context, url string) ([]btPost, error)
|
||||
|
||||
// BitcoinTalkCollectorWithFetcher wraps BitcoinTalkCollector with a custom fetcher for testing.
|
||||
//
|
||||
type BitcoinTalkCollectorWithFetcher struct {
|
||||
BitcoinTalkCollector
|
||||
Fetcher FetchPageFunc
|
||||
|
|
@ -312,7 +307,6 @@ type BitcoinTalkCollectorWithFetcher struct {
|
|||
|
||||
// SetHTTPClient replaces the package-level HTTP client.
|
||||
// Use this in tests to inject a custom transport or timeout.
|
||||
//
|
||||
func SetHTTPClient(c *http.Client) {
|
||||
httpClient = c
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
)
|
||||
|
||||
// Collector is the interface all collection sources implement.
|
||||
//
|
||||
type Collector interface {
|
||||
// Name returns a human-readable name for this collector.
|
||||
Name() string
|
||||
|
|
@ -24,7 +23,6 @@ type Collector interface {
|
|||
}
|
||||
|
||||
// Config holds shared configuration for all collectors.
|
||||
//
|
||||
type Config struct {
|
||||
// Output is the storage medium for writing collected data.
|
||||
Output io.Medium
|
||||
|
|
@ -49,7 +47,6 @@ type Config struct {
|
|||
}
|
||||
|
||||
// Result holds the output of a collection run.
|
||||
//
|
||||
type Result struct {
|
||||
// Source identifies which collector produced this result.
|
||||
Source string
|
||||
|
|
@ -70,7 +67,6 @@ type Result struct {
|
|||
// NewConfig creates a Config with sensible defaults.
|
||||
// It initialises a MockMedium for output if none is provided,
|
||||
// sets up a rate limiter, state tracker, and event dispatcher.
|
||||
//
|
||||
func NewConfig(outputDir string) *Config {
|
||||
m := io.NewMockMedium()
|
||||
return &Config{
|
||||
|
|
@ -83,7 +79,6 @@ func NewConfig(outputDir string) *Config {
|
|||
}
|
||||
|
||||
// NewConfigWithMedium creates a Config using the specified storage medium.
|
||||
//
|
||||
func NewConfigWithMedium(m io.Medium, outputDir string) *Config {
|
||||
return &Config{
|
||||
Output: m,
|
||||
|
|
@ -95,7 +90,6 @@ func NewConfigWithMedium(m io.Medium, outputDir string) *Config {
|
|||
}
|
||||
|
||||
// MergeResults combines multiple results into a single aggregated result.
|
||||
//
|
||||
func MergeResults(source string, results ...*Result) *Result {
|
||||
merged := &Result{Source: source}
|
||||
for _, r := range results {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ const (
|
|||
)
|
||||
|
||||
// Event represents a collection event.
|
||||
//
|
||||
type Event struct {
|
||||
// Type is one of the Event* constants.
|
||||
Type string `json:"type"`
|
||||
|
|
@ -50,19 +49,16 @@ type Event struct {
|
|||
}
|
||||
|
||||
// EventHandler handles collection events.
|
||||
//
|
||||
type EventHandler func(Event)
|
||||
|
||||
// Dispatcher manages event dispatch. Handlers are registered per event type
|
||||
// and are called synchronously when an event is emitted.
|
||||
//
|
||||
type Dispatcher struct {
|
||||
mu sync.RWMutex
|
||||
handlers map[string][]EventHandler
|
||||
}
|
||||
|
||||
// NewDispatcher creates a new event dispatcher.
|
||||
//
|
||||
func NewDispatcher() *Dispatcher {
|
||||
return &Dispatcher{
|
||||
handlers: make(map[string][]EventHandler),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
// Excavator runs multiple collectors as a coordinated operation.
|
||||
// It provides sequential execution with rate limit respect, state tracking
|
||||
// for resume support, and aggregated results.
|
||||
//
|
||||
type Excavator struct {
|
||||
// Collectors is the list of collectors to run.
|
||||
Collectors []Collector
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ type ghRepo struct {
|
|||
}
|
||||
|
||||
// GitHubCollector collects issues and PRs from GitHub repositories.
|
||||
//
|
||||
type GitHubCollector struct {
|
||||
// Org is the GitHub organisation.
|
||||
Org string
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import (
|
|||
var coinGeckoBaseURL = "https://api.coingecko.com/api/v3"
|
||||
|
||||
// MarketCollector collects market data from CoinGecko.
|
||||
//
|
||||
type MarketCollector struct {
|
||||
// CoinID is the CoinGecko coin identifier (e.g. "bitcoin", "ethereum").
|
||||
CoinID string
|
||||
|
|
@ -275,7 +274,6 @@ func formatMarketSummary(data *coinData) string {
|
|||
}
|
||||
|
||||
// FormatMarketSummary is exported for testing.
|
||||
//
|
||||
func FormatMarketSummary(data *coinData) string {
|
||||
return formatMarketSummary(data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ const (
|
|||
)
|
||||
|
||||
// PapersCollector collects papers from IACR and arXiv.
|
||||
//
|
||||
type PapersCollector struct {
|
||||
// Source is one of PaperSourceIACR, PaperSourceArXiv, or PaperSourceAll.
|
||||
Source string
|
||||
|
|
@ -409,7 +408,6 @@ func formatPaperMarkdown(ppr paper) string {
|
|||
}
|
||||
|
||||
// FormatPaperMarkdown is exported for testing.
|
||||
//
|
||||
func FormatPaperMarkdown(title string, authors []string, date, paperURL, source, abstract string) string {
|
||||
return formatPaperMarkdown(paper{
|
||||
Title: title,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
)
|
||||
|
||||
// Processor converts collected data to clean markdown.
|
||||
//
|
||||
type Processor struct {
|
||||
// Source identifies the data source directory to process.
|
||||
Source string
|
||||
|
|
@ -334,13 +333,11 @@ func jsonValueToMarkdown(b *strings.Builder, data any, depth int) {
|
|||
}
|
||||
|
||||
// HTMLToMarkdown is exported for testing.
|
||||
//
|
||||
func HTMLToMarkdown(content string) (string, error) {
|
||||
return htmlToMarkdown(content)
|
||||
}
|
||||
|
||||
// JSONToMarkdown is exported for testing.
|
||||
//
|
||||
func JSONToMarkdown(content string) (string, error) {
|
||||
return jsonToMarkdown(content)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
)
|
||||
|
||||
// RateLimiter tracks per-source rate limiting to avoid overwhelming APIs.
|
||||
//
|
||||
type RateLimiter struct {
|
||||
mu sync.Mutex
|
||||
delays map[string]time.Duration
|
||||
|
|
@ -33,7 +32,6 @@ var defaultDelays = map[string]time.Duration{
|
|||
}
|
||||
|
||||
// NewRateLimiter creates a limiter with default delays.
|
||||
//
|
||||
func NewRateLimiter() *RateLimiter {
|
||||
delays := make(map[string]time.Duration, len(defaultDelays))
|
||||
maps.Copy(delays, defaultDelays)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
// State tracks collection progress for incremental runs.
|
||||
// It persists entries to disk so that subsequent runs can resume
|
||||
// where they left off.
|
||||
//
|
||||
type State struct {
|
||||
mu sync.Mutex
|
||||
medium io.Medium
|
||||
|
|
@ -23,7 +22,6 @@ type State struct {
|
|||
}
|
||||
|
||||
// StateEntry tracks state for one source.
|
||||
//
|
||||
type StateEntry struct {
|
||||
// Source identifies the collector.
|
||||
Source string `json:"source"`
|
||||
|
|
@ -43,7 +41,6 @@ type StateEntry struct {
|
|||
|
||||
// NewState creates a state tracker that persists to the given path
|
||||
// using the provided storage medium.
|
||||
//
|
||||
func NewState(m io.Medium, path string) *State {
|
||||
return &State{
|
||||
medium: m,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import (
|
|||
)
|
||||
|
||||
// Client wraps the Forgejo SDK client with config-based auth.
|
||||
//
|
||||
type Client struct {
|
||||
api *forgejo.Client
|
||||
url string
|
||||
|
|
@ -25,7 +24,6 @@ type Client struct {
|
|||
}
|
||||
|
||||
// New creates a new Forgejo API client for the given URL and token.
|
||||
//
|
||||
func New(url, token string) (*Client, error) {
|
||||
api, err := forgejo.NewClient(url, forgejo.SetToken(token))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ const (
|
|||
// 1. ~/.core/config.yaml keys: forge.token, forge.url
|
||||
// 2. FORGE_TOKEN + FORGE_URL environment variables (override config file)
|
||||
// 3. Provided flag overrides (highest priority; pass empty to skip)
|
||||
//
|
||||
//
|
||||
func NewFromConfig(flagURL, flagToken string) (*Client, error) {
|
||||
url, token, err := ResolveConfig(flagURL, flagToken)
|
||||
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.
|
||||
// Flag values take highest priority, then env vars, then config file.
|
||||
//
|
||||
func ResolveConfig(flagURL, flagToken string) (url, token string, err error) {
|
||||
// Start with config file values
|
||||
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.
|
||||
//
|
||||
func SaveConfig(url, token string) error {
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
)
|
||||
|
||||
// ListIssuesOpts configures issue listing.
|
||||
//
|
||||
type ListIssuesOpts struct {
|
||||
State string // "open", "closed", "all"
|
||||
Labels []string // filter by label names
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
// PRMeta holds structural signals from a pull request,
|
||||
// used by the pipeline MetaReader for AI-driven workflows.
|
||||
//
|
||||
type PRMeta struct {
|
||||
Number int64
|
||||
Title string
|
||||
|
|
@ -29,7 +28,6 @@ type PRMeta struct {
|
|||
}
|
||||
|
||||
// Comment represents a comment with metadata.
|
||||
//
|
||||
type Comment struct {
|
||||
ID int64
|
||||
Author string
|
||||
|
|
|
|||
11
git/git.go
11
git/git.go
|
|
@ -17,7 +17,6 @@ import (
|
|||
)
|
||||
|
||||
// RepoStatus represents the git status of a single repository.
|
||||
//
|
||||
type RepoStatus struct {
|
||||
Name string
|
||||
Path string
|
||||
|
|
@ -46,7 +45,6 @@ func (s *RepoStatus) HasUnpulled() bool {
|
|||
}
|
||||
|
||||
// StatusOptions configures the status check.
|
||||
//
|
||||
type StatusOptions struct {
|
||||
// Paths is a list of repo paths to check
|
||||
Paths []string
|
||||
|
|
@ -55,7 +53,6 @@ type StatusOptions struct {
|
|||
}
|
||||
|
||||
// Status checks git status for multiple repositories in parallel.
|
||||
//
|
||||
func Status(ctx context.Context, opts StatusOptions) []RepoStatus {
|
||||
var wg sync.WaitGroup
|
||||
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.
|
||||
//
|
||||
func StatusIter(ctx context.Context, opts StatusOptions) iter.Seq[RepoStatus] {
|
||||
return func(yield func(RepoStatus) bool) {
|
||||
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.
|
||||
// Uses interactive mode to support SSH passphrase prompts.
|
||||
//
|
||||
func Push(ctx context.Context, path string) error {
|
||||
return gitInteractive(ctx, path, "push")
|
||||
}
|
||||
|
||||
// Pull pulls changes for a single repository.
|
||||
// Uses interactive mode to support SSH passphrase prompts.
|
||||
//
|
||||
func Pull(ctx context.Context, path string) error {
|
||||
return gitInteractive(ctx, path, "pull", "--rebase")
|
||||
}
|
||||
|
||||
// IsNonFastForward checks if an error is a non-fast-forward rejection.
|
||||
//
|
||||
func IsNonFastForward(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
|
|
@ -210,7 +203,6 @@ func gitInteractive(ctx context.Context, dir string, args ...string) error {
|
|||
}
|
||||
|
||||
// PushResult represents the result of a push operation.
|
||||
//
|
||||
type PushResult struct {
|
||||
Name string
|
||||
Path string
|
||||
|
|
@ -220,13 +212,11 @@ type PushResult struct {
|
|||
|
||||
// PushMultiple pushes multiple repositories sequentially.
|
||||
// Sequential because SSH passphrase prompts need user interaction.
|
||||
//
|
||||
func PushMultiple(ctx context.Context, paths []string, names map[string]string) []PushResult {
|
||||
return slices.Collect(PushMultipleIter(ctx, paths, names))
|
||||
}
|
||||
|
||||
// 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] {
|
||||
return func(yield func(PushResult) bool) {
|
||||
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.
|
||||
//
|
||||
type GitError struct {
|
||||
Err error
|
||||
Stderr string
|
||||
|
|
|
|||
|
|
@ -13,58 +13,49 @@ import (
|
|||
// Queries for git service
|
||||
|
||||
// QueryStatus requests git status for paths.
|
||||
//
|
||||
type QueryStatus struct {
|
||||
Paths []string
|
||||
Names map[string]string
|
||||
}
|
||||
|
||||
// QueryDirtyRepos requests repos with uncommitted changes.
|
||||
//
|
||||
type QueryDirtyRepos struct{}
|
||||
|
||||
// QueryAheadRepos requests repos with unpushed commits.
|
||||
//
|
||||
type QueryAheadRepos struct{}
|
||||
|
||||
// Tasks for git service
|
||||
|
||||
// TaskPush requests git push for a path.
|
||||
//
|
||||
type TaskPush struct {
|
||||
Path string
|
||||
Name string
|
||||
}
|
||||
|
||||
// TaskPull requests git pull for a path.
|
||||
//
|
||||
type TaskPull struct {
|
||||
Path string
|
||||
Name string
|
||||
}
|
||||
|
||||
// TaskPushMultiple requests git push for multiple paths.
|
||||
//
|
||||
type TaskPushMultiple struct {
|
||||
Paths []string
|
||||
Names map[string]string
|
||||
}
|
||||
|
||||
// ServiceOptions for configuring the git service.
|
||||
//
|
||||
type ServiceOptions struct {
|
||||
WorkDir string
|
||||
}
|
||||
|
||||
// Service provides git operations as a Core service.
|
||||
//
|
||||
type Service struct {
|
||||
*core.ServiceRuntime[ServiceOptions]
|
||||
lastStatus []RepoStatus
|
||||
}
|
||||
|
||||
// NewService creates a git service factory.
|
||||
//
|
||||
func NewService(opts ServiceOptions) func(*core.Core) (any, error) {
|
||||
return func(c *core.Core) (any, error) {
|
||||
return &Service{
|
||||
|
|
|
|||
|
|
@ -17,14 +17,12 @@ import (
|
|||
)
|
||||
|
||||
// Client wraps the Gitea SDK client with config-based auth.
|
||||
//
|
||||
type Client struct {
|
||||
api *gitea.Client
|
||||
url string
|
||||
}
|
||||
|
||||
// New creates a new Gitea API client for the given URL and token.
|
||||
//
|
||||
func New(url, token string) (*Client, error) {
|
||||
api, err := gitea.NewClient(url, gitea.SetToken(token))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ const (
|
|||
// 1. ~/.core/config.yaml keys: gitea.token, gitea.url
|
||||
// 2. GITEA_TOKEN + GITEA_URL environment variables (override config file)
|
||||
// 3. Provided flag overrides (highest priority; pass empty to skip)
|
||||
//
|
||||
//
|
||||
func NewFromConfig(flagURL, flagToken string) (*Client, error) {
|
||||
url, token, err := ResolveConfig(flagURL, flagToken)
|
||||
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.
|
||||
// Flag values take highest priority, then env vars, then config file.
|
||||
//
|
||||
func ResolveConfig(flagURL, flagToken string) (url, token string, err error) {
|
||||
// Start with config file values
|
||||
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.
|
||||
//
|
||||
func SaveConfig(url, token string) error {
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
)
|
||||
|
||||
// ListIssuesOpts configures issue listing.
|
||||
//
|
||||
type ListIssuesOpts struct {
|
||||
State string // "open", "closed", "all"
|
||||
Page int
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
// PRMeta holds structural signals from a pull request,
|
||||
// used by the pipeline MetaReader for AI-driven workflows.
|
||||
//
|
||||
type PRMeta struct {
|
||||
Number int64
|
||||
Title string
|
||||
|
|
@ -29,7 +28,6 @@ type PRMeta struct {
|
|||
}
|
||||
|
||||
// Comment represents a comment with metadata.
|
||||
//
|
||||
type Comment struct {
|
||||
ID int64
|
||||
Author string
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ import (
|
|||
)
|
||||
|
||||
// Separator mirrors filepath.Separator for Unix-style Core paths.
|
||||
//
|
||||
const Separator = '/'
|
||||
|
||||
// Abs mirrors filepath.Abs for the paths used in this repo.
|
||||
//
|
||||
func Abs(p string) (string, error) {
|
||||
if path.IsAbs(p) {
|
||||
return path.Clean(p), nil
|
||||
|
|
@ -25,31 +23,26 @@ func Abs(p string) (string, error) {
|
|||
}
|
||||
|
||||
// Base mirrors filepath.Base.
|
||||
//
|
||||
func Base(p string) string {
|
||||
return path.Base(p)
|
||||
}
|
||||
|
||||
// Clean mirrors filepath.Clean.
|
||||
//
|
||||
func Clean(p string) string {
|
||||
return path.Clean(p)
|
||||
}
|
||||
|
||||
// Dir mirrors filepath.Dir.
|
||||
//
|
||||
func Dir(p string) string {
|
||||
return path.Dir(p)
|
||||
}
|
||||
|
||||
// Ext mirrors filepath.Ext.
|
||||
//
|
||||
func Ext(p string) string {
|
||||
return path.Ext(p)
|
||||
}
|
||||
|
||||
// Join mirrors filepath.Join.
|
||||
//
|
||||
func Join(elem ...string) string {
|
||||
return path.Join(elem...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,31 +10,26 @@ import (
|
|||
)
|
||||
|
||||
// Sprint mirrors fmt.Sprint using Core primitives.
|
||||
//
|
||||
func Sprint(args ...any) string {
|
||||
return core.Sprint(args...)
|
||||
}
|
||||
|
||||
// Sprintf mirrors fmt.Sprintf using Core primitives.
|
||||
//
|
||||
func Sprintf(format string, args ...any) string {
|
||||
return core.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
// Fprintf mirrors fmt.Fprintf using Core primitives.
|
||||
//
|
||||
func Fprintf(w io.Writer, format string, args ...any) (int, error) {
|
||||
return io.WriteString(w, Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Printf mirrors fmt.Printf.
|
||||
//
|
||||
func Printf(format string, args ...any) (int, error) {
|
||||
return Fprintf(stdio.Stdout, format, args...)
|
||||
}
|
||||
|
||||
// Println mirrors fmt.Println.
|
||||
//
|
||||
func Println(args ...any) (int, error) {
|
||||
return io.WriteString(stdio.Stdout, Sprint(args...)+"\n")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,31 +9,26 @@ import (
|
|||
)
|
||||
|
||||
// Marshal mirrors encoding/json.Marshal.
|
||||
//
|
||||
func Marshal(v any) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// MarshalIndent mirrors encoding/json.MarshalIndent.
|
||||
//
|
||||
func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
|
||||
return json.MarshalIndent(v, prefix, indent)
|
||||
}
|
||||
|
||||
// NewDecoder mirrors encoding/json.NewDecoder.
|
||||
//
|
||||
func NewDecoder(r io.Reader) *json.Decoder {
|
||||
return json.NewDecoder(r)
|
||||
}
|
||||
|
||||
// NewEncoder mirrors encoding/json.NewEncoder.
|
||||
//
|
||||
func NewEncoder(w io.Writer) *json.Encoder {
|
||||
return json.NewEncoder(w)
|
||||
}
|
||||
|
||||
// Unmarshal mirrors encoding/json.Unmarshal.
|
||||
//
|
||||
func Unmarshal(data []byte, v any) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,50 +23,41 @@ const (
|
|||
)
|
||||
|
||||
// Stdin exposes process stdin without importing os.
|
||||
//
|
||||
var Stdin = stdio.Stdin
|
||||
|
||||
// Stdout exposes process stdout without importing os.
|
||||
//
|
||||
var Stdout = stdio.Stdout
|
||||
|
||||
// Stderr exposes process stderr without importing os.
|
||||
//
|
||||
var Stderr = stdio.Stderr
|
||||
|
||||
// Getenv mirrors os.Getenv.
|
||||
//
|
||||
func Getenv(key string) string {
|
||||
value, _ := syscall.Getenv(key)
|
||||
return value
|
||||
}
|
||||
|
||||
// Getwd mirrors os.Getwd.
|
||||
//
|
||||
func Getwd() (string, error) {
|
||||
return syscall.Getwd()
|
||||
}
|
||||
|
||||
// IsNotExist mirrors os.IsNotExist.
|
||||
//
|
||||
func IsNotExist(err error) bool {
|
||||
return core.Is(err, fs.ErrNotExist)
|
||||
}
|
||||
|
||||
// MkdirAll mirrors os.MkdirAll.
|
||||
//
|
||||
func MkdirAll(path string, _ fs.FileMode) error {
|
||||
return coreio.Local.EnsureDir(path)
|
||||
}
|
||||
|
||||
// Open mirrors os.Open.
|
||||
//
|
||||
func Open(path string) (fs.File, error) {
|
||||
return coreio.Local.Open(path)
|
||||
}
|
||||
|
||||
// OpenFile mirrors the append/create/write mode used in this repo.
|
||||
//
|
||||
func OpenFile(path string, flag int, _ fs.FileMode) (io.WriteCloser, error) {
|
||||
if flag&O_APPEND != 0 {
|
||||
return coreio.Local.Append(path)
|
||||
|
|
@ -75,26 +66,22 @@ func OpenFile(path string, flag int, _ fs.FileMode) (io.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// ReadDir mirrors os.ReadDir.
|
||||
//
|
||||
func ReadDir(path string) ([]fs.DirEntry, error) {
|
||||
return coreio.Local.List(path)
|
||||
}
|
||||
|
||||
// ReadFile mirrors os.ReadFile.
|
||||
//
|
||||
func ReadFile(path string) ([]byte, error) {
|
||||
content, err := coreio.Local.Read(path)
|
||||
return []byte(content), err
|
||||
}
|
||||
|
||||
// Stat mirrors os.Stat.
|
||||
//
|
||||
func Stat(path string) (fs.FileInfo, error) {
|
||||
return coreio.Local.Stat(path)
|
||||
}
|
||||
|
||||
// UserHomeDir mirrors os.UserHomeDir.
|
||||
//
|
||||
func UserHomeDir() (string, error) {
|
||||
if home := Getenv("HOME"); home != "" {
|
||||
return home, nil
|
||||
|
|
@ -107,7 +94,6 @@ func UserHomeDir() (string, error) {
|
|||
}
|
||||
|
||||
// WriteFile mirrors os.WriteFile.
|
||||
//
|
||||
func WriteFile(path string, data []byte, perm fs.FileMode) error {
|
||||
return coreio.Local.WriteMode(path, string(data), perm)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,10 @@ func (w fdWriter) Write(p []byte) (int, error) {
|
|||
}
|
||||
|
||||
// Stdin exposes process stdin without importing os.
|
||||
//
|
||||
var Stdin io.Reader = fdReader{fd: 0}
|
||||
|
||||
// Stdout exposes process stdout without importing os.
|
||||
//
|
||||
var Stdout io.Writer = fdWriter{fd: 1}
|
||||
|
||||
// Stderr exposes process stderr without importing os.
|
||||
//
|
||||
var Stderr io.Writer = fdWriter{fd: 2}
|
||||
|
|
|
|||
|
|
@ -11,29 +11,24 @@ import (
|
|||
)
|
||||
|
||||
// Builder provides a strings.Builder-like type without importing strings.
|
||||
//
|
||||
type Builder = bytes.Buffer
|
||||
|
||||
// Contains mirrors strings.Contains.
|
||||
//
|
||||
func Contains(s, substr string) bool {
|
||||
return core.Contains(s, substr)
|
||||
}
|
||||
|
||||
// ContainsAny mirrors strings.ContainsAny.
|
||||
//
|
||||
func ContainsAny(s, chars string) bool {
|
||||
return bytes.IndexAny([]byte(s), chars) >= 0
|
||||
}
|
||||
|
||||
// EqualFold mirrors strings.EqualFold.
|
||||
//
|
||||
func EqualFold(s, t string) bool {
|
||||
return bytes.EqualFold([]byte(s), []byte(t))
|
||||
}
|
||||
|
||||
// Fields mirrors strings.Fields.
|
||||
//
|
||||
func Fields(s string) []string {
|
||||
scanner := bufio.NewScanner(NewReader(s))
|
||||
scanner.Split(bufio.ScanWords)
|
||||
|
|
@ -45,37 +40,31 @@ func Fields(s string) []string {
|
|||
}
|
||||
|
||||
// HasPrefix mirrors strings.HasPrefix.
|
||||
//
|
||||
func HasPrefix(s, prefix string) bool {
|
||||
return core.HasPrefix(s, prefix)
|
||||
}
|
||||
|
||||
// HasSuffix mirrors strings.HasSuffix.
|
||||
//
|
||||
func HasSuffix(s, suffix string) bool {
|
||||
return core.HasSuffix(s, suffix)
|
||||
}
|
||||
|
||||
// Join mirrors strings.Join.
|
||||
//
|
||||
func Join(elems []string, sep string) string {
|
||||
return core.Join(sep, elems...)
|
||||
}
|
||||
|
||||
// LastIndex mirrors strings.LastIndex.
|
||||
//
|
||||
func LastIndex(s, substr string) int {
|
||||
return bytes.LastIndex([]byte(s), []byte(substr))
|
||||
}
|
||||
|
||||
// NewReader mirrors strings.NewReader.
|
||||
//
|
||||
func NewReader(s string) *bytes.Reader {
|
||||
return bytes.NewReader([]byte(s))
|
||||
}
|
||||
|
||||
// Repeat mirrors strings.Repeat.
|
||||
//
|
||||
func Repeat(s string, count int) string {
|
||||
if count <= 0 {
|
||||
return ""
|
||||
|
|
@ -84,31 +73,26 @@ func Repeat(s string, count int) string {
|
|||
}
|
||||
|
||||
// ReplaceAll mirrors strings.ReplaceAll.
|
||||
//
|
||||
func ReplaceAll(s, old, new string) string {
|
||||
return core.Replace(s, old, new)
|
||||
}
|
||||
|
||||
// Replace mirrors strings.Replace for replace-all call sites.
|
||||
//
|
||||
func Replace(s, old, new string, _ int) string {
|
||||
return ReplaceAll(s, old, new)
|
||||
}
|
||||
|
||||
// Split mirrors strings.Split.
|
||||
//
|
||||
func Split(s, sep string) []string {
|
||||
return core.Split(s, sep)
|
||||
}
|
||||
|
||||
// SplitN mirrors strings.SplitN.
|
||||
//
|
||||
func SplitN(s, sep string, n int) []string {
|
||||
return core.SplitN(s, sep, n)
|
||||
}
|
||||
|
||||
// SplitSeq mirrors strings.SplitSeq.
|
||||
//
|
||||
func SplitSeq(s, sep string) iter.Seq[string] {
|
||||
parts := Split(s, sep)
|
||||
return func(yield func(string) bool) {
|
||||
|
|
@ -121,31 +105,26 @@ func SplitSeq(s, sep string) iter.Seq[string] {
|
|||
}
|
||||
|
||||
// ToLower mirrors strings.ToLower.
|
||||
//
|
||||
func ToLower(s string) string {
|
||||
return core.Lower(s)
|
||||
}
|
||||
|
||||
// ToUpper mirrors strings.ToUpper.
|
||||
//
|
||||
func ToUpper(s string) string {
|
||||
return core.Upper(s)
|
||||
}
|
||||
|
||||
// TrimPrefix mirrors strings.TrimPrefix.
|
||||
//
|
||||
func TrimPrefix(s, prefix string) string {
|
||||
return core.TrimPrefix(s, prefix)
|
||||
}
|
||||
|
||||
// TrimSpace mirrors strings.TrimSpace.
|
||||
//
|
||||
func TrimSpace(s string) string {
|
||||
return core.Trim(s)
|
||||
}
|
||||
|
||||
// TrimSuffix mirrors strings.TrimSuffix.
|
||||
//
|
||||
func TrimSuffix(s, suffix string) string {
|
||||
return core.TrimSuffix(s, suffix)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,20 +13,17 @@ import (
|
|||
)
|
||||
|
||||
// Config configures a ForgejoSource.
|
||||
//
|
||||
type Config struct {
|
||||
Repos []string // "owner/repo" format
|
||||
}
|
||||
|
||||
// ForgejoSource polls a Forgejo instance for pipeline signals from epic issues.
|
||||
//
|
||||
type ForgejoSource struct {
|
||||
repos []string
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// New creates a ForgejoSource using the given forge client.
|
||||
//
|
||||
func New(cfg Config, client *forge.Client) *ForgejoSource {
|
||||
return &ForgejoSource{
|
||||
repos: cfg.Repos,
|
||||
|
|
|
|||
|
|
@ -18,13 +18,11 @@ const (
|
|||
)
|
||||
|
||||
// CompletionHandler manages issue state when an agent finishes work.
|
||||
//
|
||||
type CompletionHandler struct {
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// NewCompletionHandler creates a handler for agent completion events.
|
||||
//
|
||||
func NewCompletionHandler(client *forge.Client) *CompletionHandler {
|
||||
return &CompletionHandler{
|
||||
forge: client,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ const (
|
|||
|
||||
// DispatchTicket is the JSON payload written to the agent's queue.
|
||||
// The ForgeToken is transferred separately via a .env file with 0600 permissions.
|
||||
//
|
||||
type DispatchTicket struct {
|
||||
ID string `json:"id"`
|
||||
RepoOwner string `json:"repo_owner"`
|
||||
|
|
@ -55,7 +54,6 @@ type DispatchTicket struct {
|
|||
}
|
||||
|
||||
// DispatchHandler dispatches coding work to remote agent machines via SSH.
|
||||
//
|
||||
type DispatchHandler struct {
|
||||
forge *forge.Client
|
||||
forgeURL string
|
||||
|
|
@ -64,7 +62,6 @@ type DispatchHandler struct {
|
|||
}
|
||||
|
||||
// NewDispatchHandler creates a handler that dispatches tickets to agent machines.
|
||||
//
|
||||
func NewDispatchHandler(client *forge.Client, forgeURL, token string, spinner *agentci.Spinner) *DispatchHandler {
|
||||
return &DispatchHandler{
|
||||
forge: client,
|
||||
|
|
|
|||
|
|
@ -12,13 +12,11 @@ import (
|
|||
)
|
||||
|
||||
// EnableAutoMergeHandler merges a PR that is ready using squash strategy.
|
||||
//
|
||||
type EnableAutoMergeHandler struct {
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// NewEnableAutoMergeHandler creates a handler that merges ready PRs.
|
||||
//
|
||||
func NewEnableAutoMergeHandler(f *forge.Client) *EnableAutoMergeHandler {
|
||||
return &EnableAutoMergeHandler{forge: f}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,11 @@ import (
|
|||
)
|
||||
|
||||
// PublishDraftHandler marks a draft PR as ready for review once its checks pass.
|
||||
//
|
||||
type PublishDraftHandler struct {
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// NewPublishDraftHandler creates a handler that publishes draft PRs.
|
||||
//
|
||||
func NewPublishDraftHandler(f *forge.Client) *PublishDraftHandler {
|
||||
return &PublishDraftHandler{forge: f}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@ import (
|
|||
// DismissReviewsHandler dismisses stale "request changes" reviews on a PR.
|
||||
// This replaces the GitHub-only ResolveThreadsHandler because Forgejo does
|
||||
// not have a thread resolution API.
|
||||
//
|
||||
type DismissReviewsHandler struct {
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// NewDismissReviewsHandler creates a handler that dismisses stale reviews.
|
||||
//
|
||||
func NewDismissReviewsHandler(f *forge.Client) *DismissReviewsHandler {
|
||||
return &DismissReviewsHandler{forge: f}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,11 @@ import (
|
|||
|
||||
// SendFixCommandHandler posts a comment on a PR asking for conflict or
|
||||
// review fixes.
|
||||
//
|
||||
type SendFixCommandHandler struct {
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// NewSendFixCommandHandler creates a handler that posts fix commands.
|
||||
//
|
||||
func NewSendFixCommandHandler(f *forge.Client) *SendFixCommandHandler {
|
||||
return &SendFixCommandHandler{forge: f}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@ import (
|
|||
|
||||
// TickParentHandler ticks a child checkbox in the parent epic issue body
|
||||
// after the child's PR has been merged.
|
||||
//
|
||||
type TickParentHandler struct {
|
||||
forge *forge.Client
|
||||
}
|
||||
|
||||
// NewTickParentHandler creates a handler that ticks parent epic checkboxes.
|
||||
//
|
||||
func NewTickParentHandler(f *forge.Client) *TickParentHandler {
|
||||
return &TickParentHandler{forge: f}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import (
|
|||
var validPathComponent = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9._-]*$`)
|
||||
|
||||
// JournalEntry is a single line in the JSONL audit log.
|
||||
//
|
||||
type JournalEntry struct {
|
||||
Timestamp string `json:"ts"`
|
||||
Epic int `json:"epic"`
|
||||
|
|
@ -32,7 +31,6 @@ type JournalEntry struct {
|
|||
}
|
||||
|
||||
// SignalSnapshot captures the structural state of a PR at the time of action.
|
||||
//
|
||||
type SignalSnapshot struct {
|
||||
PRState string `json:"pr_state"`
|
||||
IsDraft bool `json:"is_draft"`
|
||||
|
|
@ -43,7 +41,6 @@ type SignalSnapshot struct {
|
|||
}
|
||||
|
||||
// ResultSnapshot captures the outcome of an action.
|
||||
//
|
||||
type ResultSnapshot struct {
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
|
|
@ -51,14 +48,12 @@ type ResultSnapshot struct {
|
|||
}
|
||||
|
||||
// Journal writes ActionResult entries to date-partitioned JSONL files.
|
||||
//
|
||||
type Journal struct {
|
||||
baseDir string
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewJournal creates a new Journal rooted at baseDir.
|
||||
//
|
||||
func NewJournal(baseDir string) (*Journal, error) {
|
||||
if baseDir == "" {
|
||||
return nil, coreerr.E("jobrunner.NewJournal", "base directory is required", nil)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
)
|
||||
|
||||
// PollerConfig configures a Poller.
|
||||
//
|
||||
type PollerConfig struct {
|
||||
Sources []JobSource
|
||||
Handlers []JobHandler
|
||||
|
|
@ -21,7 +20,6 @@ type PollerConfig struct {
|
|||
}
|
||||
|
||||
// Poller discovers signals from sources and dispatches them to handlers.
|
||||
//
|
||||
type Poller struct {
|
||||
mu sync.RWMutex
|
||||
sources []JobSource
|
||||
|
|
@ -33,7 +31,6 @@ type Poller struct {
|
|||
}
|
||||
|
||||
// NewPoller creates a Poller from the given config.
|
||||
//
|
||||
func NewPoller(cfg PollerConfig) *Poller {
|
||||
interval := cfg.PollInterval
|
||||
if interval <= 0 {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
// PipelineSignal is the structural snapshot of a child issue/PR.
|
||||
// Carries structural state plus issue title/body for dispatch prompts.
|
||||
//
|
||||
type PipelineSignal struct {
|
||||
EpicNumber int
|
||||
ChildNumber int
|
||||
|
|
@ -46,7 +45,6 @@ func (s *PipelineSignal) HasUnresolvedThreads() bool {
|
|||
}
|
||||
|
||||
// ActionResult carries the outcome of a handler execution.
|
||||
//
|
||||
type ActionResult struct {
|
||||
Action string `json:"action"`
|
||||
RepoOwner string `json:"repo_owner"`
|
||||
|
|
@ -62,7 +60,6 @@ type ActionResult struct {
|
|||
}
|
||||
|
||||
// JobSource discovers actionable work from an external system.
|
||||
//
|
||||
type JobSource interface {
|
||||
Name() string
|
||||
Poll(ctx context.Context) ([]*PipelineSignal, error)
|
||||
|
|
@ -70,7 +67,6 @@ type JobSource interface {
|
|||
}
|
||||
|
||||
// JobHandler processes a single pipeline signal.
|
||||
//
|
||||
type JobHandler interface {
|
||||
Name() string
|
||||
Match(signal *PipelineSignal) bool
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ package locales
|
|||
|
||||
import "embed"
|
||||
|
||||
//
|
||||
//
|
||||
//go:embed *.json
|
||||
var FS embed.FS
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import (
|
|||
// CompiledManifest is the distribution-ready form of a manifest, written as
|
||||
// core.json at the repository root (not inside .core/). It embeds the
|
||||
// original Manifest and adds build metadata stapled at compile time.
|
||||
//
|
||||
type CompiledManifest struct {
|
||||
Manifest `json:",inline" yaml:",inline"`
|
||||
|
||||
|
|
@ -27,7 +26,6 @@ type CompiledManifest struct {
|
|||
}
|
||||
|
||||
// CompileOptions controls how Compile populates the build metadata.
|
||||
//
|
||||
type CompileOptions struct {
|
||||
Commit string // Git commit hash
|
||||
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
|
||||
// options. If opts.SignKey is provided the manifest is signed first.
|
||||
//
|
||||
func Compile(m *Manifest, opts CompileOptions) (*CompiledManifest, error) {
|
||||
if m == 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.
|
||||
//
|
||||
func MarshalJSON(cm *CompiledManifest) ([]byte, error) {
|
||||
return json.MarshalIndent(cm, "", " ")
|
||||
}
|
||||
|
||||
// ParseCompiled decodes a core.json into a CompiledManifest.
|
||||
//
|
||||
func ParseCompiled(data []byte) (*CompiledManifest, error) {
|
||||
var cm CompiledManifest
|
||||
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
|
||||
// directory. The file lives at the distribution root, not inside .core/.
|
||||
//
|
||||
func WriteCompiled(medium io.Medium, root string, cm *CompiledManifest) error {
|
||||
data, err := MarshalJSON(cm)
|
||||
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.
|
||||
//
|
||||
func LoadCompiled(medium io.Medium, root string) (*CompiledManifest, error) {
|
||||
path := filepath.Join(root, compiledPath)
|
||||
data, err := medium.Read(path)
|
||||
|
|
|
|||
|
|
@ -14,13 +14,11 @@ import (
|
|||
const manifestPath = ".core/manifest.yaml"
|
||||
|
||||
// MarshalYAML serializes a manifest to YAML bytes.
|
||||
//
|
||||
func MarshalYAML(m *Manifest) ([]byte, error) {
|
||||
return yaml.Marshal(m)
|
||||
}
|
||||
|
||||
// Load reads and parses a .core/manifest.yaml from the given root directory.
|
||||
//
|
||||
func Load(medium io.Medium, root string) (*Manifest, error) {
|
||||
path := filepath.Join(root, manifestPath)
|
||||
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.
|
||||
//
|
||||
func LoadVerified(medium io.Medium, root string, pub ed25519.PublicKey) (*Manifest, error) {
|
||||
m, err := Load(medium, root)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
)
|
||||
|
||||
// Manifest represents a .core/manifest.yaml application manifest.
|
||||
//
|
||||
type Manifest struct {
|
||||
Code string `yaml:"code" json:"code"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
|
|
@ -34,7 +33,6 @@ type Manifest struct {
|
|||
}
|
||||
|
||||
// ElementSpec describes a web component for GUI rendering.
|
||||
//
|
||||
type ElementSpec struct {
|
||||
// Tag is the custom element tag name, e.g. "core-cool-widget".
|
||||
Tag string `yaml:"tag" json:"tag"`
|
||||
|
|
@ -50,7 +48,6 @@ func (m *Manifest) IsProvider() bool {
|
|||
}
|
||||
|
||||
// Permissions declares the I/O capabilities a module requires.
|
||||
//
|
||||
type Permissions struct {
|
||||
Read []string `yaml:"read" json:"read"`
|
||||
Write []string `yaml:"write" json:"write"`
|
||||
|
|
@ -59,7 +56,6 @@ type Permissions struct {
|
|||
}
|
||||
|
||||
// DaemonSpec describes a long-running process managed by the runtime.
|
||||
//
|
||||
type DaemonSpec struct {
|
||||
Binary string `yaml:"binary,omitempty" json:"binary,omitempty"`
|
||||
Args []string `yaml:"args,omitempty" json:"args,omitempty"`
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ func signable(m *Manifest) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Sign computes the ed25519 signature and stores it in m.Sign (base64).
|
||||
//
|
||||
func Sign(m *Manifest, priv ed25519.PrivateKey) error {
|
||||
msg, err := signable(m)
|
||||
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.
|
||||
//
|
||||
func Verify(m *Manifest, pub ed25519.PublicKey) (bool, error) {
|
||||
if m.Sign == "" {
|
||||
return false, coreerr.E("manifest.Verify", "no signature present", nil)
|
||||
|
|
|
|||
|
|
@ -16,12 +16,10 @@ import (
|
|||
)
|
||||
|
||||
// IndexVersion is the current marketplace index format version.
|
||||
//
|
||||
const IndexVersion = 1
|
||||
|
||||
// Builder constructs a marketplace Index by crawling directories for
|
||||
// core.json (compiled manifests) or .core/manifest.yaml files.
|
||||
//
|
||||
type Builder struct {
|
||||
// BaseURL is the prefix for constructing repository URLs, e.g.
|
||||
// "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.
|
||||
// This is useful when manifests have already been collected (e.g. from
|
||||
// a Forge API crawl).
|
||||
//
|
||||
func BuildFromManifests(manifests []*manifest.Manifest) *Index {
|
||||
var modules []Module
|
||||
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.
|
||||
//
|
||||
func WriteIndex(path string, idx *Index) error {
|
||||
if err := coreio.Local.EnsureDir(filepath.Dir(path)); err != nil {
|
||||
return coreerr.E("marketplace.WriteIndex", "mkdir failed", err)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
)
|
||||
|
||||
// DiscoveredProvider represents a runtime provider found on disk.
|
||||
//
|
||||
type DiscoveredProvider struct {
|
||||
// Dir is the absolute path to the provider directory.
|
||||
Dir string
|
||||
|
|
@ -27,7 +26,6 @@ type DiscoveredProvider struct {
|
|||
// Each subdirectory is checked for a .core/manifest.yaml file. Directories
|
||||
// without a valid manifest are skipped with a log warning.
|
||||
// Only manifests with provider fields (namespace + binary) are returned.
|
||||
//
|
||||
func DiscoverProviders(dir string) ([]DiscoveredProvider, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
|
|
@ -73,7 +71,6 @@ func DiscoverProviders(dir string) ([]DiscoveredProvider, error) {
|
|||
}
|
||||
|
||||
// ProviderRegistryEntry records metadata about an installed provider.
|
||||
//
|
||||
type ProviderRegistryEntry struct {
|
||||
Installed string `yaml:"installed" json:"installed"`
|
||||
Version string `yaml:"version" json:"version"`
|
||||
|
|
@ -82,7 +79,6 @@ type ProviderRegistryEntry struct {
|
|||
}
|
||||
|
||||
// ProviderRegistryFile represents the registry.yaml file tracking installed providers.
|
||||
//
|
||||
type ProviderRegistryFile struct {
|
||||
Version int `yaml:"version" json:"version"`
|
||||
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.
|
||||
// Returns an empty registry if the file does not exist.
|
||||
//
|
||||
func LoadProviderRegistry(path string) (*ProviderRegistryFile, error) {
|
||||
raw, err := coreio.Local.Read(path)
|
||||
if err != nil {
|
||||
|
|
@ -116,7 +111,6 @@ func LoadProviderRegistry(path string) (*ProviderRegistryFile, error) {
|
|||
}
|
||||
|
||||
// SaveProviderRegistry writes the registry to the given path.
|
||||
//
|
||||
func SaveProviderRegistry(path string, reg *ProviderRegistryFile) error {
|
||||
if err := coreio.Local.EnsureDir(filepath.Dir(path)); err != nil {
|
||||
return coreerr.E("marketplace.SaveProviderRegistry", "ensure directory", err)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
const storeGroup = "_modules"
|
||||
|
||||
// Installer handles module installation from Git repos.
|
||||
//
|
||||
type Installer struct {
|
||||
medium io.Medium
|
||||
modulesDir string
|
||||
|
|
@ -29,7 +28,6 @@ type Installer struct {
|
|||
}
|
||||
|
||||
// NewInstaller creates a new module installer.
|
||||
//
|
||||
func NewInstaller(m io.Medium, modulesDir string, st *store.Store) *Installer {
|
||||
return &Installer{
|
||||
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.
|
||||
//
|
||||
type InstalledModule struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
)
|
||||
|
||||
// Module is a marketplace entry pointing to a module's Git repo.
|
||||
//
|
||||
type Module struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
|
|
@ -20,7 +19,6 @@ type Module struct {
|
|||
}
|
||||
|
||||
// Index is the root marketplace catalog.
|
||||
//
|
||||
type Index struct {
|
||||
Version int `json:"version"`
|
||||
Modules []Module `json:"modules"`
|
||||
|
|
@ -28,7 +26,6 @@ type Index struct {
|
|||
}
|
||||
|
||||
// ParseIndex decodes a marketplace index.json.
|
||||
//
|
||||
func ParseIndex(data []byte) (*Index, error) {
|
||||
var idx Index
|
||||
if err := json.Unmarshal(data, &idx); err != nil {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,5 @@ import "embed"
|
|||
// 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.
|
||||
//
|
||||
//
|
||||
//
|
||||
//go:embed all:ui/dist
|
||||
var Assets embed.FS
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import (
|
|||
// ScmProvider wraps go-scm marketplace, manifest, and registry operations
|
||||
// as a service provider. It implements Provider, Streamable, Describable,
|
||||
// and Renderable.
|
||||
//
|
||||
type ScmProvider struct {
|
||||
index *marketplace.Index
|
||||
installer *marketplace.Installer
|
||||
|
|
@ -46,7 +45,6 @@ var (
|
|||
// NewProvider creates an SCM provider backed by the given marketplace index,
|
||||
// installer, and registry. The WS hub is used to emit real-time events.
|
||||
// Pass nil for any dependency that is not available.
|
||||
//
|
||||
func NewProvider(idx *marketplace.Index, inst *marketplace.Installer, reg *repos.Registry, hub *ws.Hub) *ScmProvider {
|
||||
return &ScmProvider{
|
||||
index: idx,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
package plugin
|
||||
|
||||
// PluginConfig holds configuration for a single installed plugin.
|
||||
//
|
||||
type PluginConfig struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Version string `json:"version" yaml:"version"`
|
||||
|
|
|
|||
|
|
@ -17,14 +17,12 @@ import (
|
|||
)
|
||||
|
||||
// Installer handles plugin installation from GitHub.
|
||||
//
|
||||
type Installer struct {
|
||||
medium io.Medium
|
||||
registry *Registry
|
||||
}
|
||||
|
||||
// NewInstaller creates a new plugin installer.
|
||||
//
|
||||
func NewInstaller(m io.Medium, registry *Registry) *Installer {
|
||||
return &Installer{
|
||||
medium: m,
|
||||
|
|
@ -182,8 +180,6 @@ func (i *Installer) cloneRepo(ctx context.Context, org, repo, version, dest stri
|
|||
// Accepted formats:
|
||||
// - "org/repo" -> org="org", repo="repo", version=""
|
||||
// - "org/repo@v1.0" -> org="org", repo="repo", version="v1.0"
|
||||
//
|
||||
//
|
||||
func ParseSource(source string) (org, repo, version string, err error) {
|
||||
source, err = url.PathUnescape(source)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -10,14 +10,12 @@ import (
|
|||
)
|
||||
|
||||
// Loader loads plugins from the filesystem.
|
||||
//
|
||||
type Loader struct {
|
||||
medium io.Medium
|
||||
baseDir string
|
||||
}
|
||||
|
||||
// NewLoader creates a new plugin loader.
|
||||
//
|
||||
func NewLoader(m io.Medium, baseDir string) *Loader {
|
||||
return &Loader{
|
||||
medium: m,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
// Manifest represents a plugin.json manifest file.
|
||||
// Each plugin repository must contain a plugin.json at its root.
|
||||
//
|
||||
type Manifest struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
|
|
@ -23,7 +22,6 @@ type Manifest struct {
|
|||
}
|
||||
|
||||
// LoadManifest reads and parses a plugin.json file from the given path.
|
||||
//
|
||||
func LoadManifest(m io.Medium, path string) (*Manifest, error) {
|
||||
content, err := m.Read(path)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ package plugin
|
|||
import "context"
|
||||
|
||||
// Plugin is the interface that all plugins must implement.
|
||||
//
|
||||
type Plugin interface {
|
||||
// Name returns the plugin's unique identifier.
|
||||
Name() string
|
||||
|
|
@ -36,7 +35,6 @@ type Plugin interface {
|
|||
|
||||
// BasePlugin provides a default implementation of Plugin.
|
||||
// Embed this in concrete plugin types to inherit default behaviour.
|
||||
//
|
||||
type BasePlugin struct {
|
||||
PluginName string
|
||||
PluginVersion string
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ const registryFilename = "registry.json"
|
|||
|
||||
// Registry manages installed plugins.
|
||||
// Plugin metadata is stored in a registry.json file under the base path.
|
||||
//
|
||||
type Registry struct {
|
||||
medium io.Medium
|
||||
basePath string // e.g., ~/.core/plugins/
|
||||
|
|
@ -24,7 +23,6 @@ type Registry struct {
|
|||
}
|
||||
|
||||
// NewRegistry creates a new plugin registry.
|
||||
//
|
||||
func NewRegistry(m io.Medium, basePath string) *Registry {
|
||||
return &Registry{
|
||||
medium: m,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
|
||||
// GitState holds per-machine git sync state for a workspace.
|
||||
// Stored at .core/git.yaml and .gitignored (not shared across machines).
|
||||
//
|
||||
type GitState struct {
|
||||
Version int `yaml:"version"`
|
||||
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.
|
||||
//
|
||||
type RepoGitState struct {
|
||||
LastPull time.Time `yaml:"last_pull,omitempty"`
|
||||
LastPush time.Time `yaml:"last_push,omitempty"`
|
||||
|
|
@ -32,7 +30,6 @@ type RepoGitState struct {
|
|||
}
|
||||
|
||||
// AgentState tracks which agent last touched which repos.
|
||||
//
|
||||
type AgentState struct {
|
||||
LastSeen time.Time `yaml:"last_seen"`
|
||||
Active []string `yaml:"active,omitempty"`
|
||||
|
|
@ -40,7 +37,6 @@ type AgentState struct {
|
|||
|
||||
// LoadGitState reads .core/git.yaml from the given workspace root directory.
|
||||
// Returns a new empty GitState if the file does not exist.
|
||||
//
|
||||
func LoadGitState(m io.Medium, root string) (*GitState, error) {
|
||||
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.
|
||||
//
|
||||
func SaveGitState(m io.Medium, root string, gs *GitState) error {
|
||||
coreDir := filepath.Join(root, ".core")
|
||||
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.
|
||||
//
|
||||
func NewGitState() *GitState {
|
||||
return &GitState{
|
||||
Version: 1,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
|
||||
// KBConfig holds knowledge base configuration for a workspace.
|
||||
// Stored at .core/kb.yaml and checked into git.
|
||||
//
|
||||
type KBConfig struct {
|
||||
Version int `yaml:"version"`
|
||||
Wiki WikiConfig `yaml:"wiki"`
|
||||
|
|
@ -21,7 +20,6 @@ type KBConfig struct {
|
|||
}
|
||||
|
||||
// WikiConfig controls local wiki mirror behaviour.
|
||||
//
|
||||
type WikiConfig struct {
|
||||
// Enabled toggles wiki cloning on sync.
|
||||
Enabled bool `yaml:"enabled"`
|
||||
|
|
@ -33,7 +31,6 @@ type WikiConfig struct {
|
|||
}
|
||||
|
||||
// KBSearch configures vector search against the OpenBrain Qdrant collection.
|
||||
//
|
||||
type KBSearch struct {
|
||||
// QdrantHost is the Qdrant server (gRPC).
|
||||
QdrantHost string `yaml:"qdrant_host"`
|
||||
|
|
@ -50,7 +47,6 @@ type KBSearch struct {
|
|||
}
|
||||
|
||||
// DefaultKBConfig returns sensible defaults for knowledge base config.
|
||||
//
|
||||
func DefaultKBConfig() *KBConfig {
|
||||
return &KBConfig{
|
||||
Version: 1,
|
||||
|
|
@ -72,7 +68,6 @@ func DefaultKBConfig() *KBConfig {
|
|||
|
||||
// LoadKBConfig reads .core/kb.yaml from the given workspace root directory.
|
||||
// Returns defaults if the file does not exist.
|
||||
//
|
||||
func LoadKBConfig(m io.Medium, root string) (*KBConfig, error) {
|
||||
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.
|
||||
//
|
||||
func SaveKBConfig(m io.Medium, root string, kb *KBConfig) error {
|
||||
coreDir := filepath.Join(root, ".core")
|
||||
if err := m.EnsureDir(coreDir); err != nil {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
)
|
||||
|
||||
// Registry represents a collection of repositories defined in repos.yaml.
|
||||
//
|
||||
type Registry struct {
|
||||
Version int `yaml:"version"`
|
||||
Org string `yaml:"org"`
|
||||
|
|
@ -27,7 +26,6 @@ type Registry struct {
|
|||
}
|
||||
|
||||
// RegistryDefaults contains default values applied to all repos.
|
||||
//
|
||||
type RegistryDefaults struct {
|
||||
CI string `yaml:"ci"`
|
||||
License string `yaml:"license"`
|
||||
|
|
@ -35,7 +33,6 @@ type RegistryDefaults struct {
|
|||
}
|
||||
|
||||
// RepoType indicates the role of a repository in the ecosystem.
|
||||
//
|
||||
type RepoType string
|
||||
|
||||
// Repository type constants for ecosystem classification.
|
||||
|
|
@ -55,7 +52,6 @@ const (
|
|||
)
|
||||
|
||||
// Repo represents a single repository in the registry.
|
||||
//
|
||||
type Repo struct {
|
||||
Name string `yaml:"-"` // Set from map key
|
||||
Type string `yaml:"type"`
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
|
||||
// WorkConfig holds sync policy for a workspace.
|
||||
// Stored at .core/work.yaml and checked into git (shared across the team).
|
||||
//
|
||||
type WorkConfig struct {
|
||||
Version int `yaml:"version"`
|
||||
Sync SyncConfig `yaml:"sync"`
|
||||
|
|
@ -22,7 +21,6 @@ type WorkConfig struct {
|
|||
}
|
||||
|
||||
// SyncConfig controls how and when repos are synced.
|
||||
//
|
||||
type SyncConfig struct {
|
||||
Interval time.Duration `yaml:"interval"`
|
||||
AutoPull bool `yaml:"auto_pull"`
|
||||
|
|
@ -31,7 +29,6 @@ type SyncConfig struct {
|
|||
}
|
||||
|
||||
// AgentPolicy controls multi-agent clash prevention.
|
||||
//
|
||||
type AgentPolicy struct {
|
||||
Heartbeat time.Duration `yaml:"heartbeat"`
|
||||
StaleAfter time.Duration `yaml:"stale_after"`
|
||||
|
|
@ -39,7 +36,6 @@ type AgentPolicy struct {
|
|||
}
|
||||
|
||||
// DefaultWorkConfig returns sensible defaults for workspace sync.
|
||||
//
|
||||
func DefaultWorkConfig() *WorkConfig {
|
||||
return &WorkConfig{
|
||||
Version: 1,
|
||||
|
|
@ -60,7 +56,6 @@ func DefaultWorkConfig() *WorkConfig {
|
|||
|
||||
// LoadWorkConfig reads .core/work.yaml from the given workspace root directory.
|
||||
// Returns defaults if the file does not exist.
|
||||
//
|
||||
func LoadWorkConfig(m io.Medium, root string) (*WorkConfig, error) {
|
||||
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.
|
||||
//
|
||||
func SaveWorkConfig(m io.Medium, root string, wc *WorkConfig) error {
|
||||
coreDir := filepath.Join(root, ".core")
|
||||
if err := m.EnsureDir(coreDir); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue