2026-03-16 11:10:33 +00:00
// SPDX-License-Identifier: EUPL-1.2
package agentic
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"os"
"time"
2026-03-22 03:41:07 +00:00
core "dappco.re/go/core"
2026-03-16 11:10:33 +00:00
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// Plan represents an implementation plan for agent work.
2026-03-22 03:41:07 +00:00
//
// plan := &Plan{ID: "migrate-core-abc", Title: "Migrate Core", Status: "draft", Objective: "..."}
// writePlan(PlansRoot(), plan)
2026-03-16 11:10:33 +00:00
type Plan struct {
ID string ` json:"id" `
Title string ` json:"title" `
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
Status string ` json:"status" ` // draft, ready, in_progress, needs_verification, verified, approved
2026-03-16 11:10:33 +00:00
Repo string ` json:"repo,omitempty" `
Org string ` json:"org,omitempty" `
Objective string ` json:"objective" `
Phases [ ] Phase ` json:"phases,omitempty" `
Notes string ` json:"notes,omitempty" `
Agent string ` json:"agent,omitempty" `
CreatedAt time . Time ` json:"created_at" `
UpdatedAt time . Time ` json:"updated_at" `
}
// Phase represents a phase within an implementation plan.
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
//
// phase := agentic.Phase{Number: 1, Name: "Migrate strings", Status: "in_progress"}
2026-03-16 11:10:33 +00:00
type Phase struct {
Number int ` json:"number" `
Name string ` json:"name" `
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
Status string ` json:"status" ` // pending, in_progress, done
2026-03-16 11:10:33 +00:00
Criteria [ ] string ` json:"criteria,omitempty" `
Tests int ` json:"tests,omitempty" `
Notes string ` json:"notes,omitempty" `
}
// --- Input/Output types ---
// PlanCreateInput is the input for agentic_plan_create.
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
//
// input := agentic.PlanCreateInput{Title: "Migrate pkg/agentic", Objective: "Use Core primitives everywhere"}
2026-03-16 11:10:33 +00:00
type PlanCreateInput struct {
Title string ` json:"title" `
Objective string ` json:"objective" `
Repo string ` json:"repo,omitempty" `
Org string ` json:"org,omitempty" `
Phases [ ] Phase ` json:"phases,omitempty" `
Notes string ` json:"notes,omitempty" `
}
// PlanCreateOutput is the output for agentic_plan_create.
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
//
// out := agentic.PlanCreateOutput{Success: true, ID: "migrate-pkg-agentic-abc123"}
2026-03-16 11:10:33 +00:00
type PlanCreateOutput struct {
Success bool ` json:"success" `
ID string ` json:"id" `
Path string ` json:"path" `
}
// PlanReadInput is the input for agentic_plan_read.
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
//
// input := agentic.PlanReadInput{ID: "migrate-pkg-agentic-abc123"}
2026-03-16 11:10:33 +00:00
type PlanReadInput struct {
ID string ` json:"id" `
}
// PlanReadOutput is the output for agentic_plan_read.
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
//
// out := agentic.PlanReadOutput{Success: true, Plan: agentic.Plan{ID: "migrate-pkg-agentic-abc123"}}
2026-03-16 11:10:33 +00:00
type PlanReadOutput struct {
Success bool ` json:"success" `
Plan Plan ` json:"plan" `
}
// PlanUpdateInput is the input for agentic_plan_update.
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
//
// input := agentic.PlanUpdateInput{ID: "migrate-pkg-agentic-abc123", Status: "verified"}
2026-03-16 11:10:33 +00:00
type PlanUpdateInput struct {
ID string ` json:"id" `
Status string ` json:"status,omitempty" `
Title string ` json:"title,omitempty" `
Objective string ` json:"objective,omitempty" `
Phases [ ] Phase ` json:"phases,omitempty" `
Notes string ` json:"notes,omitempty" `
Agent string ` json:"agent,omitempty" `
}
// PlanUpdateOutput is the output for agentic_plan_update.
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
//
// out := agentic.PlanUpdateOutput{Success: true, Plan: agentic.Plan{Status: "verified"}}
2026-03-16 11:10:33 +00:00
type PlanUpdateOutput struct {
Success bool ` json:"success" `
Plan Plan ` json:"plan" `
}
// PlanDeleteInput is the input for agentic_plan_delete.
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
//
// input := agentic.PlanDeleteInput{ID: "migrate-pkg-agentic-abc123"}
2026-03-16 11:10:33 +00:00
type PlanDeleteInput struct {
ID string ` json:"id" `
}
// PlanDeleteOutput is the output for agentic_plan_delete.
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
//
// out := agentic.PlanDeleteOutput{Success: true, Deleted: "migrate-pkg-agentic-abc123"}
2026-03-16 11:10:33 +00:00
type PlanDeleteOutput struct {
Success bool ` json:"success" `
Deleted string ` json:"deleted" `
}
// PlanListInput is the input for agentic_plan_list.
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
//
// input := agentic.PlanListInput{Repo: "go-io", Status: "ready"}
2026-03-16 11:10:33 +00:00
type PlanListInput struct {
Status string ` json:"status,omitempty" `
Repo string ` json:"repo,omitempty" `
}
// PlanListOutput is the output for agentic_plan_list.
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
//
// out := agentic.PlanListOutput{Success: true, Count: 2, Plans: []agentic.Plan{{ID: "migrate-pkg-agentic-abc123"}}}
2026-03-16 11:10:33 +00:00
type PlanListOutput struct {
Success bool ` json:"success" `
Count int ` json:"count" `
Plans [ ] Plan ` json:"plans" `
}
// --- Registration ---
func ( s * PrepSubsystem ) registerPlanTools ( server * mcp . Server ) {
mcp . AddTool ( server , & mcp . Tool {
Name : "agentic_plan_create" ,
Description : "Create an implementation plan. Plans track phased work with acceptance criteria, status lifecycle (draft → ready → in_progress → needs_verification → verified → approved), and per-phase progress." ,
} , s . planCreate )
mcp . AddTool ( server , & mcp . Tool {
Name : "agentic_plan_read" ,
Description : "Read an implementation plan by ID. Returns the full plan with all phases, criteria, and status." ,
} , s . planRead )
mcp . AddTool ( server , & mcp . Tool {
Name : "agentic_plan_update" ,
Description : "Update an implementation plan. Supports partial updates — only provided fields are changed. Use this to advance status, update phases, or add notes." ,
} , s . planUpdate )
mcp . AddTool ( server , & mcp . Tool {
Name : "agentic_plan_delete" ,
Description : "Delete an implementation plan by ID. Permanently removes the plan file." ,
} , s . planDelete )
mcp . AddTool ( server , & mcp . Tool {
Name : "agentic_plan_list" ,
Description : "List implementation plans. Supports filtering by status (draft, ready, in_progress, etc.) and repo." ,
} , s . planList )
}
// --- Handlers ---
func ( s * PrepSubsystem ) planCreate ( _ context . Context , _ * mcp . CallToolRequest , input PlanCreateInput ) ( * mcp . CallToolResult , PlanCreateOutput , error ) {
if input . Title == "" {
2026-03-22 03:41:07 +00:00
return nil , PlanCreateOutput { } , core . E ( "planCreate" , "title is required" , nil )
2026-03-16 11:10:33 +00:00
}
if input . Objective == "" {
2026-03-22 03:41:07 +00:00
return nil , PlanCreateOutput { } , core . E ( "planCreate" , "objective is required" , nil )
2026-03-16 11:10:33 +00:00
}
id := generatePlanID ( input . Title )
plan := Plan {
ID : id ,
Title : input . Title ,
Status : "draft" ,
Repo : input . Repo ,
Org : input . Org ,
Objective : input . Objective ,
Phases : input . Phases ,
Notes : input . Notes ,
CreatedAt : time . Now ( ) ,
UpdatedAt : time . Now ( ) ,
}
// Default phase status to pending
for i := range plan . Phases {
if plan . Phases [ i ] . Status == "" {
plan . Phases [ i ] . Status = "pending"
}
if plan . Phases [ i ] . Number == 0 {
plan . Phases [ i ] . Number = i + 1
}
}
2026-03-17 19:35:15 +00:00
path , err := writePlan ( PlansRoot ( ) , & plan )
2026-03-16 11:10:33 +00:00
if err != nil {
2026-03-22 03:41:07 +00:00
return nil , PlanCreateOutput { } , core . E ( "planCreate" , "failed to write plan" , err )
2026-03-16 11:10:33 +00:00
}
return nil , PlanCreateOutput {
Success : true ,
ID : id ,
Path : path ,
} , nil
}
func ( s * PrepSubsystem ) planRead ( _ context . Context , _ * mcp . CallToolRequest , input PlanReadInput ) ( * mcp . CallToolResult , PlanReadOutput , error ) {
if input . ID == "" {
2026-03-22 03:41:07 +00:00
return nil , PlanReadOutput { } , core . E ( "planRead" , "id is required" , nil )
2026-03-16 11:10:33 +00:00
}
2026-03-17 19:35:15 +00:00
plan , err := readPlan ( PlansRoot ( ) , input . ID )
2026-03-16 11:10:33 +00:00
if err != nil {
return nil , PlanReadOutput { } , err
}
return nil , PlanReadOutput {
Success : true ,
Plan : * plan ,
} , nil
}
func ( s * PrepSubsystem ) planUpdate ( _ context . Context , _ * mcp . CallToolRequest , input PlanUpdateInput ) ( * mcp . CallToolResult , PlanUpdateOutput , error ) {
if input . ID == "" {
2026-03-22 03:41:07 +00:00
return nil , PlanUpdateOutput { } , core . E ( "planUpdate" , "id is required" , nil )
2026-03-16 11:10:33 +00:00
}
2026-03-17 19:35:15 +00:00
plan , err := readPlan ( PlansRoot ( ) , input . ID )
2026-03-16 11:10:33 +00:00
if err != nil {
return nil , PlanUpdateOutput { } , err
}
// Apply partial updates
if input . Status != "" {
if ! validPlanStatus ( input . Status ) {
2026-03-22 03:41:07 +00:00
return nil , PlanUpdateOutput { } , core . E ( "planUpdate" , "invalid status: " + input . Status + " (valid: draft, ready, in_progress, needs_verification, verified, approved)" , nil )
2026-03-16 11:10:33 +00:00
}
plan . Status = input . Status
}
if input . Title != "" {
plan . Title = input . Title
}
if input . Objective != "" {
plan . Objective = input . Objective
}
if input . Phases != nil {
plan . Phases = input . Phases
}
if input . Notes != "" {
plan . Notes = input . Notes
}
if input . Agent != "" {
plan . Agent = input . Agent
}
plan . UpdatedAt = time . Now ( )
2026-03-17 19:35:15 +00:00
if _ , err := writePlan ( PlansRoot ( ) , plan ) ; err != nil {
2026-03-22 03:41:07 +00:00
return nil , PlanUpdateOutput { } , core . E ( "planUpdate" , "failed to write plan" , err )
2026-03-16 11:10:33 +00:00
}
return nil , PlanUpdateOutput {
Success : true ,
Plan : * plan ,
} , nil
}
func ( s * PrepSubsystem ) planDelete ( _ context . Context , _ * mcp . CallToolRequest , input PlanDeleteInput ) ( * mcp . CallToolResult , PlanDeleteOutput , error ) {
if input . ID == "" {
2026-03-22 03:41:07 +00:00
return nil , PlanDeleteOutput { } , core . E ( "planDelete" , "id is required" , nil )
2026-03-16 11:10:33 +00:00
}
2026-03-17 19:35:15 +00:00
path := planPath ( PlansRoot ( ) , input . ID )
refactor(agentic): route file I/O through core.Fs
Replace raw os.* file operations with Core Fs equivalents:
- os.Stat → fs.Exists/fs.IsFile/fs.IsDir (resume, pr, plan, mirror, prep)
- os.ReadDir → fs.List (queue, status, plan, mirror, review_queue)
- os.Remove → fs.Delete (dispatch)
- os.OpenFile(append) → fs.Append (events, review_queue)
- strings.Replace → core.Replace (scan)
Eliminates os import from resume.go, pr.go. Eliminates strings
import from scan.go. Trades os for io in events.go.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:45 +00:00
if ! fs . Exists ( path ) {
2026-03-22 03:41:07 +00:00
return nil , PlanDeleteOutput { } , core . E ( "planDelete" , "plan not found: " + input . ID , nil )
2026-03-16 11:10:33 +00:00
}
2026-03-22 03:41:07 +00:00
if r := fs . Delete ( path ) ; ! r . OK {
2026-03-22 03:45:50 +00:00
err , _ := r . Value . ( error )
return nil , PlanDeleteOutput { } , core . E ( "planDelete" , "failed to delete plan" , err )
2026-03-16 11:10:33 +00:00
}
return nil , PlanDeleteOutput {
Success : true ,
Deleted : input . ID ,
} , nil
}
func ( s * PrepSubsystem ) planList ( _ context . Context , _ * mcp . CallToolRequest , input PlanListInput ) ( * mcp . CallToolResult , PlanListOutput , error ) {
2026-03-17 19:35:15 +00:00
dir := PlansRoot ( )
2026-03-22 03:41:07 +00:00
if r := fs . EnsureDir ( dir ) ; ! r . OK {
2026-03-22 03:45:50 +00:00
err , _ := r . Value . ( error )
return nil , PlanListOutput { } , core . E ( "planList" , "failed to access plans directory" , err )
2026-03-16 11:10:33 +00:00
}
refactor(agentic): route file I/O through core.Fs
Replace raw os.* file operations with Core Fs equivalents:
- os.Stat → fs.Exists/fs.IsFile/fs.IsDir (resume, pr, plan, mirror, prep)
- os.ReadDir → fs.List (queue, status, plan, mirror, review_queue)
- os.Remove → fs.Delete (dispatch)
- os.OpenFile(append) → fs.Append (events, review_queue)
- strings.Replace → core.Replace (scan)
Eliminates os import from resume.go, pr.go. Eliminates strings
import from scan.go. Trades os for io in events.go.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:45 +00:00
r := fs . List ( dir )
if ! r . OK {
return nil , PlanListOutput { } , nil
2026-03-16 11:10:33 +00:00
}
refactor(agentic): route file I/O through core.Fs
Replace raw os.* file operations with Core Fs equivalents:
- os.Stat → fs.Exists/fs.IsFile/fs.IsDir (resume, pr, plan, mirror, prep)
- os.ReadDir → fs.List (queue, status, plan, mirror, review_queue)
- os.Remove → fs.Delete (dispatch)
- os.OpenFile(append) → fs.Append (events, review_queue)
- strings.Replace → core.Replace (scan)
Eliminates os import from resume.go, pr.go. Eliminates strings
import from scan.go. Trades os for io in events.go.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:45 +00:00
entries := r . Value . ( [ ] os . DirEntry )
2026-03-16 11:10:33 +00:00
var plans [ ] Plan
for _ , entry := range entries {
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
if entry . IsDir ( ) || ! core . HasSuffix ( entry . Name ( ) , ".json" ) {
2026-03-16 11:10:33 +00:00
continue
}
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
id := core . TrimSuffix ( entry . Name ( ) , ".json" )
2026-03-16 11:10:33 +00:00
plan , err := readPlan ( dir , id )
if err != nil {
continue
}
// Apply filters
if input . Status != "" && plan . Status != input . Status {
continue
}
if input . Repo != "" && plan . Repo != input . Repo {
continue
}
plans = append ( plans , * plan )
}
return nil , PlanListOutput {
Success : true ,
Count : len ( plans ) ,
Plans : plans ,
} , nil
}
// --- Helpers ---
func planPath ( dir , id string ) string {
2026-03-21 17:57:03 +00:00
// Sanitise ID to prevent path traversal
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
safe := core . PathBase ( id )
2026-03-21 17:57:03 +00:00
if safe == "." || safe == ".." || safe == "" {
safe = "invalid"
}
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
return core . JoinPath ( dir , safe + ".json" )
2026-03-16 11:10:33 +00:00
}
func generatePlanID ( title string ) string {
feat: devops plugin, CLI commands, Codex dispatch fixes, AX sweep
DevOps plugin (5 skills):
- install-core-agent, repair-core-agent, merge-workspace,
update-deps, clean-workspaces
CLI commands: version, check, extract for diagnostics.
Codex dispatch: --skip-git-repo-check, removed broken
--model-reasoning-effort, --sandbox workspace-write via
--full-auto. Workspace template extracts to wsDir not srcDir.
AX sweep (Codex-generated): sanitise.go extracted from prep/plan,
mirror.go JSON parsing via encoding/json, setup/config.go URL
parsing via net/url, strings/fmt imports eliminated from setup.
CODEX.md template updated with Env/Path patterns.
Review workspace template with audit-only PROMPT.md.
Marketplace updated with devops plugin.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:30:27 +00:00
slug := sanitisePlanSlug ( title )
2026-03-16 11:10:33 +00:00
// Append short random suffix for uniqueness
b := make ( [ ] byte , 3 )
rand . Read ( b )
return slug + "-" + hex . EncodeToString ( b )
}
func readPlan ( dir , id string ) ( * Plan , error ) {
2026-03-22 03:41:07 +00:00
r := fs . Read ( planPath ( dir , id ) )
if ! r . OK {
return nil , core . E ( "readPlan" , "plan not found: " + id , nil )
2026-03-16 11:10:33 +00:00
}
var plan Plan
2026-03-22 03:41:07 +00:00
if err := json . Unmarshal ( [ ] byte ( r . Value . ( string ) ) , & plan ) ; err != nil {
return nil , core . E ( "readPlan" , "failed to parse plan " + id , err )
2026-03-16 11:10:33 +00:00
}
return & plan , nil
}
func writePlan ( dir string , plan * Plan ) ( string , error ) {
2026-03-22 03:41:07 +00:00
if r := fs . EnsureDir ( dir ) ; ! r . OK {
2026-03-22 03:45:50 +00:00
err , _ := r . Value . ( error )
return "" , core . E ( "writePlan" , "failed to create plans directory" , err )
2026-03-16 11:10:33 +00:00
}
path := planPath ( dir , plan . ID )
data , err := json . MarshalIndent ( plan , "" , " " )
if err != nil {
return "" , err
}
2026-03-22 03:41:07 +00:00
if r := fs . Write ( path , string ( data ) ) ; ! r . OK {
2026-03-22 03:45:50 +00:00
err , _ := r . Value . ( error )
return "" , core . E ( "writePlan" , "failed to write plan" , err )
2026-03-22 03:41:07 +00:00
}
return path , nil
2026-03-16 11:10:33 +00:00
}
func validPlanStatus ( status string ) bool {
switch status {
case "draft" , "ready" , "in_progress" , "needs_verification" , "verified" , "approved" :
return true
}
return false
}