From 4c6296c1c1bc53c6b9483fc5491a48a8314b0276 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 08:58:17 +0000 Subject: [PATCH] refactor(agentic): replace core path helpers Co-Authored-By: Virgil --- pkg/agentic/commands_forge.go | 17 ++++++++--------- pkg/agentic/message.go | 2 +- pkg/agentic/plan.go | 25 ++++++++++++++++++++++--- pkg/agentic/prep.go | 16 +++++++--------- pkg/agentic/sanitise.go | 21 +++++++++++++++++++++ pkg/agentic/session.go | 2 +- pkg/agentic/state.go | 2 +- 7 files changed, 61 insertions(+), 24 deletions(-) diff --git a/pkg/agentic/commands_forge.go b/pkg/agentic/commands_forge.go index 99aa1e0..1dcb9bd 100644 --- a/pkg/agentic/commands_forge.go +++ b/pkg/agentic/commands_forge.go @@ -88,14 +88,14 @@ func parseForgeArgs(options core.Options) (org, repo string, num int64) { num, _ = strconv.ParseInt(v, 10, 64) } - if orgResult := core.ValidateName(org); orgResult.OK { - org = orgResult.Value.(string) + if validatedOrg, ok := validateName(org); ok { + org = validatedOrg } else { org = "" } - if repoResult := core.ValidateName(repo); repoResult.OK { - repo = repoResult.Value.(string) + if validatedRepo, ok := validateName(repo); ok { + repo = validatedRepo } else { repo = "" } @@ -504,13 +504,12 @@ func (s *PrepSubsystem) cmdRepoList(options core.Options) core.Result { if org == "" { org = "core" } - orgResult := core.ValidateName(org) - if !orgResult.OK { - err, _ := orgResult.Value.(error) + validatedOrg, ok := validateName(org) + if !ok { core.Print(nil, "usage: core-agent repo list [--org=core]") - return core.Result{Value: core.E("agentic.cmdRepoList", "invalid org name", err), OK: false} + return core.Result{Value: core.E("agentic.cmdRepoList", "invalid org name", nil), OK: false} } - org = orgResult.Value.(string) + org = validatedOrg repos, err := s.forge.Repos.ListOrgRepos(ctx, org) if err != nil { core.Print(nil, "error: %v", err) diff --git a/pkg/agentic/message.go b/pkg/agentic/message.go index f6c4081..0e6c305 100644 --- a/pkg/agentic/message.go +++ b/pkg/agentic/message.go @@ -316,7 +316,7 @@ func messageRoot() string { } func messagePath(workspace string) string { - return core.JoinPath(messageRoot(), core.Concat(core.SanitisePath(workspace), ".json")) + return core.JoinPath(messageRoot(), core.Concat(pathKey(workspace), ".json")) } func readWorkspaceMessages(workspace string) ([]AgentMessage, error) { diff --git a/pkg/agentic/plan.go b/pkg/agentic/plan.go index de33a8c..6c3be07 100644 --- a/pkg/agentic/plan.go +++ b/pkg/agentic/plan.go @@ -4,6 +4,10 @@ package agentic import ( "context" + "crypto/rand" + "encoding/hex" + "strconv" + "sync/atomic" "time" core "dappco.re/go/core" @@ -152,6 +156,8 @@ type PlanListOutput struct { const planListDefaultLimit = 20 +var planIDCounter atomic.Uint64 + // result := c.Action("plan.create").Run(ctx, core.NewOptions( // // core.Option{Key: "title", Value: "AX RFC follow-up"}, @@ -354,7 +360,7 @@ func (s *PrepSubsystem) planCreate(_ context.Context, _ *mcp.CallToolRequest, in return nil, PlanCreateOutput{}, core.E("planCreate", "objective is required", nil) } - id := core.ID() + id := planID() plan := Plan{ ID: id, Slug: planSlugValue(input.Slug, input.Title, id), @@ -558,8 +564,7 @@ func (s *PrepSubsystem) planList(_ context.Context, _ *mcp.CallToolRequest, inpu } func planPath(dir, id string) string { - safe := core.SanitisePath(id) - return core.JoinPath(dir, core.Concat(safe, ".json")) + return core.JoinPath(dir, core.Concat(pathKey(id), ".json")) } func planPhasesValue(options core.Options, keys ...string) []Phase { @@ -710,6 +715,20 @@ func phaseCriteriaValue(values ...any) []string { return nil } +func planID() string { + counter := planIDCounter.Add(1) + suffix := planRandomHex() + return core.Concat("id-", strconv.FormatUint(counter, 10), "-", suffix) +} + +func planRandomHex() string { + bytes := make([]byte, 3) + if _, err := rand.Read(bytes); err != nil { + return "000000" + } + return hex.EncodeToString(bytes) +} + func planTaskSliceValue(value any) []PlanTask { switch typed := value.(type) { case []PlanTask: diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index c2d14e7..9dc0116 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -522,19 +522,17 @@ func workspaceDir(org, repo string, input PrepInput) (string, error) { // r := workspaceDirResult("core", "go-io", PrepInput{Issue: 15}) // if r.OK { workspaceDir := r.Value.(string) } func workspaceDirResult(org, repo string, input PrepInput) core.Result { - orgName := core.ValidateName(org) - if !orgName.OK { - err, _ := orgName.Value.(error) - return core.Result{Value: core.E("workspaceDir", "invalid org name", err), OK: false} + orgName, ok := validateName(org) + if !ok { + return core.Result{Value: core.E("workspaceDir", "invalid org name", nil), OK: false} } - repoName := core.ValidateName(repo) - if !repoName.OK { - err, _ := repoName.Value.(error) - return core.Result{Value: core.E("workspaceDir", "invalid repo name", err), OK: false} + repoName, ok := validateName(repo) + if !ok { + return core.Result{Value: core.E("workspaceDir", "invalid repo name", nil), OK: false} } - base := core.JoinPath(WorkspaceRoot(), orgName.Value.(string), repoName.Value.(string)) + base := core.JoinPath(WorkspaceRoot(), orgName, repoName) switch { case input.PR > 0: return core.Result{Value: core.JoinPath(base, core.Sprintf("pr-%d", input.PR)), OK: true} diff --git a/pkg/agentic/sanitise.go b/pkg/agentic/sanitise.go index 5a90d76..23a4b2c 100644 --- a/pkg/agentic/sanitise.go +++ b/pkg/agentic/sanitise.go @@ -2,6 +2,27 @@ package agentic +import core "dappco.re/go/core" + +func validateName(text string) (string, bool) { + name := core.Trim(text) + if name == "" || name == "." || name == ".." { + return "", false + } + if core.Contains(name, "/") || core.Contains(name, "\\") { + return "", false + } + return name, true +} + +func pathKey(text string) string { + safe := core.PathBase(core.Trim(text)) + if safe == "." || safe == ".." || safe == "" { + return "invalid" + } + return safe +} + func sanitiseBranchSlug(text string, max int) string { out := make([]rune, 0, len(text)) for _, r := range text { diff --git a/pkg/agentic/session.go b/pkg/agentic/session.go index a3cc723..f76834a 100644 --- a/pkg/agentic/session.go +++ b/pkg/agentic/session.go @@ -916,7 +916,7 @@ func sessionCacheRoot() string { } func sessionCachePath(sessionID string) string { - return core.JoinPath(sessionCacheRoot(), core.Concat(core.SanitisePath(sessionID), ".json")) + return core.JoinPath(sessionCacheRoot(), core.Concat(pathKey(sessionID), ".json")) } func readSessionCache(sessionID string) (*Session, error) { diff --git a/pkg/agentic/state.go b/pkg/agentic/state.go index 3d16b62..0347122 100644 --- a/pkg/agentic/state.go +++ b/pkg/agentic/state.go @@ -339,7 +339,7 @@ func stateRoot() string { } func statePath(planSlug string) string { - return core.JoinPath(stateRoot(), core.Concat(core.SanitisePath(planSlug), ".json")) + return core.JoinPath(stateRoot(), core.Concat(pathKey(planSlug), ".json")) } func readPlanStates(planSlug string) ([]WorkspaceState, error) {