2026-03-17 04:19:48 +00:00
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
package agentic
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"time"
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
|
2026-03-31 07:27:15 +00:00
|
|
|
"dappco.re/go/agent/pkg/messages"
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
core "dappco.re/go/core"
|
2026-03-17 04:19:48 +00:00
|
|
|
)
|
|
|
|
|
|
2026-03-30 22:54:19 +00:00
|
|
|
// s.autoCreatePR("/srv/.core/workspace/core/go-io/task-5")
|
2026-03-30 21:22:54 +00:00
|
|
|
func (s *PrepSubsystem) autoCreatePR(workspaceDir string) {
|
|
|
|
|
result := ReadStatusResult(workspaceDir)
|
2026-03-30 21:11:06 +00:00
|
|
|
workspaceStatus, ok := workspaceStatusValue(result)
|
|
|
|
|
if !ok || workspaceStatus.Branch == "" || workspaceStatus.Repo == "" {
|
2026-03-17 04:19:48 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 09:51:57 +00:00
|
|
|
ctx := context.Background()
|
2026-03-30 21:22:54 +00:00
|
|
|
repoDir := WorkspaceRepoDir(workspaceDir)
|
2026-03-30 15:48:21 +00:00
|
|
|
process := s.Core().Process()
|
2026-03-17 04:19:48 +00:00
|
|
|
|
2026-03-30 21:37:15 +00:00
|
|
|
defaultBranch := "dev"
|
2026-03-21 16:22:18 +00:00
|
|
|
|
2026-03-30 21:37:15 +00:00
|
|
|
processResult := process.RunIn(ctx, repoDir, "git", "log", "--oneline", core.Concat("origin/", defaultBranch, "..HEAD"))
|
2026-03-30 21:11:06 +00:00
|
|
|
if !processResult.OK {
|
2026-03-30 15:48:21 +00:00
|
|
|
return
|
|
|
|
|
}
|
2026-03-30 21:37:15 +00:00
|
|
|
commitLogOutput := core.Trim(processResult.Value.(string))
|
|
|
|
|
if commitLogOutput == "" {
|
2026-03-17 04:19:48 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 21:37:15 +00:00
|
|
|
commitCount := len(core.Split(commitLogOutput, "\n"))
|
2026-03-17 04:19:48 +00:00
|
|
|
|
2026-03-30 21:11:06 +00:00
|
|
|
org := workspaceStatus.Org
|
2026-03-17 04:19:48 +00:00
|
|
|
if org == "" {
|
|
|
|
|
org = "core"
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 21:11:06 +00:00
|
|
|
forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, workspaceStatus.Repo)
|
|
|
|
|
if !process.RunIn(ctx, repoDir, "git", "push", forgeRemote, workspaceStatus.Branch).OK {
|
2026-03-30 21:22:54 +00:00
|
|
|
if result := ReadStatusResult(workspaceDir); result.OK {
|
2026-03-30 21:11:06 +00:00
|
|
|
workspaceStatusUpdate, ok := workspaceStatusValue(result)
|
2026-03-30 19:40:02 +00:00
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-30 21:11:06 +00:00
|
|
|
workspaceStatusUpdate.Question = "PR push failed"
|
2026-03-30 21:22:54 +00:00
|
|
|
writeStatusResult(workspaceDir, workspaceStatusUpdate)
|
2026-03-17 04:19:48 +00:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-31 07:27:15 +00:00
|
|
|
if s.ServiceRuntime != nil {
|
|
|
|
|
s.Core().ACTION(messages.WorkspacePushed{
|
|
|
|
|
Repo: workspaceStatus.Repo,
|
|
|
|
|
Branch: workspaceStatus.Branch,
|
|
|
|
|
Org: org,
|
|
|
|
|
})
|
|
|
|
|
}
|
2026-03-17 04:19:48 +00:00
|
|
|
|
2026-03-30 21:11:06 +00:00
|
|
|
title := core.Sprintf("[agent/%s] %s", workspaceStatus.Agent, truncate(workspaceStatus.Task, 60))
|
|
|
|
|
body := s.buildAutoPRBody(workspaceStatus, commitCount)
|
2026-03-17 04:19:48 +00:00
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
2026-03-30 21:37:15 +00:00
|
|
|
pullRequestURL, _, err := s.forgeCreatePR(ctx, org, workspaceStatus.Repo, workspaceStatus.Branch, defaultBranch, title, body)
|
2026-03-17 04:19:48 +00:00
|
|
|
if err != nil {
|
2026-03-30 21:22:54 +00:00
|
|
|
if result := ReadStatusResult(workspaceDir); result.OK {
|
2026-03-30 21:11:06 +00:00
|
|
|
workspaceStatusUpdate, ok := workspaceStatusValue(result)
|
2026-03-30 19:40:02 +00:00
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-30 21:11:06 +00:00
|
|
|
workspaceStatusUpdate.Question = core.Sprintf("PR creation failed: %v", err)
|
2026-03-30 21:22:54 +00:00
|
|
|
writeStatusResult(workspaceDir, workspaceStatusUpdate)
|
2026-03-17 04:19:48 +00:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 01:59:03 +00:00
|
|
|
s.cleanupForgeBranch(ctx, repoDir, forgeRemote, workspaceStatus.Branch)
|
|
|
|
|
|
2026-03-30 21:22:54 +00:00
|
|
|
if result := ReadStatusResult(workspaceDir); result.OK {
|
2026-03-30 21:11:06 +00:00
|
|
|
workspaceStatusUpdate, ok := workspaceStatusValue(result)
|
2026-03-30 19:40:02 +00:00
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-30 21:37:15 +00:00
|
|
|
workspaceStatusUpdate.PRURL = pullRequestURL
|
2026-03-30 21:22:54 +00:00
|
|
|
writeStatusResult(workspaceDir, workspaceStatusUpdate)
|
2026-03-17 04:19:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 21:11:06 +00:00
|
|
|
func (s *PrepSubsystem) buildAutoPRBody(workspaceStatus *WorkspaceStatus, commits int) string {
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
b := core.NewBuilder()
|
2026-03-17 04:19:48 +00:00
|
|
|
b.WriteString("## Task\n\n")
|
2026-03-30 21:11:06 +00:00
|
|
|
b.WriteString(workspaceStatus.Task)
|
2026-03-17 04:19:48 +00:00
|
|
|
b.WriteString("\n\n")
|
2026-03-30 21:11:06 +00:00
|
|
|
if workspaceStatus.Issue > 0 {
|
|
|
|
|
b.WriteString(core.Sprintf("Closes #%d\n\n", workspaceStatus.Issue))
|
2026-03-23 12:53:33 +00:00
|
|
|
}
|
2026-03-30 21:11:06 +00:00
|
|
|
b.WriteString(core.Sprintf("**Agent:** %s\n", workspaceStatus.Agent))
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
b.WriteString(core.Sprintf("**Commits:** %d\n", commits))
|
2026-03-30 21:11:06 +00:00
|
|
|
b.WriteString(core.Sprintf("**Branch:** `%s`\n", workspaceStatus.Branch))
|
2026-03-17 04:19:48 +00:00
|
|
|
b.WriteString("\n---\n")
|
|
|
|
|
b.WriteString("Auto-created by core-agent dispatch system.\n")
|
|
|
|
|
b.WriteString("Co-Authored-By: Virgil <virgil@lethean.io>\n")
|
|
|
|
|
return b.String()
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 01:59:03 +00:00
|
|
|
// cleanupForgeBranch removes an agent branch from the Forge remote after the PR is published.
|
|
|
|
|
//
|
|
|
|
|
// s.cleanupForgeBranch(context.Background(), "/workspace/repo", "ssh://git@forge.lthn.ai:2223/core/go-io.git", "agent/fix-tests")
|
|
|
|
|
func (s *PrepSubsystem) cleanupForgeBranch(ctx context.Context, repoDir, remote, branch string) bool {
|
|
|
|
|
if repoDir == "" || remote == "" || branch == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s == nil || s.ServiceRuntime == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result := s.Core().Process().RunIn(ctx, repoDir, "git", "push", remote, "--delete", branch)
|
|
|
|
|
return result.OK
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-17 04:19:48 +00:00
|
|
|
func truncate(s string, max int) string {
|
|
|
|
|
if len(s) <= max {
|
|
|
|
|
return s
|
|
|
|
|
}
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
return core.Concat(s[:max], "...")
|
2026-03-17 04:19:48 +00:00
|
|
|
}
|