2026-03-30 00:54:20 +00:00
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
2026-03-29 23:59:48 +00:00
|
|
|
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
package repos
|
|
|
|
|
|
|
|
|
|
import (
|
2026-03-29 23:59:48 +00:00
|
|
|
filepath "dappco.re/go/core/scm/internal/ax/filepathx"
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
"time"
|
|
|
|
|
|
2026-03-21 23:54:23 +00:00
|
|
|
"dappco.re/go/core/io"
|
2026-03-29 23:59:48 +00:00
|
|
|
coreerr "dappco.re/go/core/log"
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// WorkConfig holds sync policy for a workspace.
|
|
|
|
|
// Stored at .core/work.yaml and checked into git (shared across the team).
|
|
|
|
|
type WorkConfig struct {
|
2026-03-29 23:59:48 +00:00
|
|
|
Version int `yaml:"version"`
|
|
|
|
|
Sync SyncConfig `yaml:"sync"`
|
|
|
|
|
Agents AgentPolicy `yaml:"agents"`
|
|
|
|
|
Triggers []string `yaml:"triggers,omitempty"`
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SyncConfig controls how and when repos are synced.
|
|
|
|
|
type SyncConfig struct {
|
|
|
|
|
Interval time.Duration `yaml:"interval"`
|
|
|
|
|
AutoPull bool `yaml:"auto_pull"`
|
|
|
|
|
AutoPush bool `yaml:"auto_push"`
|
|
|
|
|
CloneMissing bool `yaml:"clone_missing"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AgentPolicy controls multi-agent clash prevention.
|
|
|
|
|
type AgentPolicy struct {
|
2026-03-29 23:59:48 +00:00
|
|
|
Heartbeat time.Duration `yaml:"heartbeat"`
|
|
|
|
|
StaleAfter time.Duration `yaml:"stale_after"`
|
|
|
|
|
WarnOnOverlap bool `yaml:"warn_on_overlap"`
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultWorkConfig returns sensible defaults for workspace sync.
|
|
|
|
|
func DefaultWorkConfig() *WorkConfig {
|
|
|
|
|
return &WorkConfig{
|
|
|
|
|
Version: 1,
|
|
|
|
|
Sync: SyncConfig{
|
|
|
|
|
Interval: 5 * time.Minute,
|
|
|
|
|
AutoPull: true,
|
|
|
|
|
AutoPush: false,
|
|
|
|
|
CloneMissing: true,
|
|
|
|
|
},
|
|
|
|
|
Agents: AgentPolicy{
|
|
|
|
|
Heartbeat: 2 * time.Minute,
|
|
|
|
|
StaleAfter: 10 * time.Minute,
|
|
|
|
|
WarnOnOverlap: true,
|
|
|
|
|
},
|
|
|
|
|
Triggers: []string{"on_activate", "on_commit", "scheduled"},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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")
|
|
|
|
|
|
|
|
|
|
if !m.Exists(path) {
|
|
|
|
|
return DefaultWorkConfig(), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
content, err := m.Read(path)
|
|
|
|
|
if err != nil {
|
2026-03-16 20:37:25 +00:00
|
|
|
return nil, coreerr.E("repos.LoadWorkConfig", "failed to read work config", err)
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wc := DefaultWorkConfig()
|
|
|
|
|
if err := yaml.Unmarshal([]byte(content), wc); err != nil {
|
2026-03-16 20:37:25 +00:00
|
|
|
return nil, coreerr.E("repos.LoadWorkConfig", "failed to parse work config", err)
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return wc, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 {
|
2026-03-16 20:37:25 +00:00
|
|
|
return coreerr.E("repos.SaveWorkConfig", "failed to create .core directory", err)
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, err := yaml.Marshal(wc)
|
|
|
|
|
if err != nil {
|
2026-03-16 20:37:25 +00:00
|
|
|
return coreerr.E("repos.SaveWorkConfig", "failed to marshal work config", err)
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path := filepath.Join(coreDir, "work.yaml")
|
|
|
|
|
if err := m.Write(path, string(data)); err != nil {
|
2026-03-16 20:37:25 +00:00
|
|
|
return coreerr.E("repos.SaveWorkConfig", "failed to write work config", err)
|
feat(repos): add git.yaml state tracking and work.yaml sync config
GitState (.core/git.yaml, .gitignored):
- Per-repo sync timestamps (last pull/push), branch, ahead/behind
- Agent heartbeats with active package lists
- Stale agent detection, overlap queries, NeedsPull check
WorkConfig (.core/work.yaml, checked in):
- Sync policy: interval, auto_pull, auto_push, clone_missing
- Agent policy: heartbeat interval, stale timeout, overlap warnings
- Trigger list: on_activate, on_commit, scheduled
Both use io.Medium for testability (MockMedium in all tests).
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HasTrigger returns true if the given trigger name is in the triggers list.
|
|
|
|
|
func (wc *WorkConfig) HasTrigger(name string) bool {
|
|
|
|
|
for _, t := range wc.Triggers {
|
|
|
|
|
if t == name {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|