go/pkg/git/service.go
Snider c21a271dcf feat(framework): add service layer to git and agentic packages
- Add pkg/framework/framework.go for cleaner imports
- Add pkg/git/service.go with Core service wrapper
- Add pkg/agentic/service.go with AI/Claude service wrapper
- Services use IPC pattern with ACTION() dispatch

Usage:
  import "github.com/host-uk/core/pkg/framework"

  app, _ := framework.New(
      framework.WithService(git.NewService(git.ServiceOptions{})),
      framework.WithServiceLock(),
  )

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 09:19:20 +00:00

102 lines
2.3 KiB
Go

package git
import (
"context"
"github.com/host-uk/core/pkg/framework"
)
// Actions for git service IPC
// ActionStatus requests git status for paths.
type ActionStatus struct {
Paths []string
Names map[string]string
}
// ActionPush requests git push for a path.
type ActionPush struct{ Path, Name string }
// ActionPull requests git pull for a path.
type ActionPull struct{ Path, Name string }
// ServiceOptions for configuring the git service.
type ServiceOptions struct {
WorkDir string
}
// Service provides git operations as a Core service.
type Service struct {
*framework.ServiceRuntime[ServiceOptions]
lastStatus []RepoStatus
}
// NewService creates a git service factory.
func NewService(opts ServiceOptions) func(*framework.Core) (any, error) {
return func(c *framework.Core) (any, error) {
return &Service{
ServiceRuntime: framework.NewServiceRuntime(c, opts),
}, nil
}
}
// OnStartup registers action handlers.
func (s *Service) OnStartup(ctx context.Context) error {
s.Core().RegisterAction(s.handle)
return nil
}
func (s *Service) handle(c *framework.Core, msg framework.Message) error {
switch m := msg.(type) {
case ActionStatus:
return s.handleStatus(m)
case ActionPush:
return s.handlePush(m)
case ActionPull:
return s.handlePull(m)
}
return nil
}
func (s *Service) handleStatus(action ActionStatus) error {
ctx := context.Background()
statuses := Status(ctx, StatusOptions{
Paths: action.Paths,
Names: action.Names,
})
s.lastStatus = statuses
return nil
}
func (s *Service) handlePush(action ActionPush) error {
return Push(context.Background(), action.Path)
}
func (s *Service) handlePull(action ActionPull) error {
return Pull(context.Background(), action.Path)
}
// Status returns last status result.
func (s *Service) Status() []RepoStatus { return s.lastStatus }
// DirtyRepos returns repos with uncommitted changes.
func (s *Service) DirtyRepos() []RepoStatus {
var dirty []RepoStatus
for _, st := range s.lastStatus {
if st.Error == nil && st.IsDirty() {
dirty = append(dirty, st)
}
}
return dirty
}
// AheadRepos returns repos with unpushed commits.
func (s *Service) AheadRepos() []RepoStatus {
var ahead []RepoStatus
for _, st := range s.lastStatus {
if st.Error == nil && st.HasUnpushed() {
ahead = append(ahead, st)
}
}
return ahead
}