Bootstrap vm run tooling before attach
Speed up first use of repo backed VMs by bootstrapping obvious tools before the best effort LLM harness runs. Add a host side tooling plan for pinned Go, Node, Python, and Rust versions, summarize that plan in the uploaded prompt, and run repo mise install plus guest global mise use -g --pin steps before the bounded opencode inspection. Keep the harness non fatal, prefer host opencode attach when the client supports it, fall back to guest opencode over SSH for older clients, and cover the new flow with CLI plus planner tests. Validation: - go test ./internal/cli ./internal/toolingplan - GOCACHE=/tmp/banger-gocache go test ./... - make build
This commit is contained in:
parent
1e967140c3
commit
4813e844e2
10 changed files with 1126 additions and 13 deletions
94
internal/toolingplan/plan.go
Normal file
94
internal/toolingplan/plan.go
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package toolingplan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type InstallStep struct {
|
||||
Tool string
|
||||
Version string
|
||||
Source string
|
||||
Reason string
|
||||
}
|
||||
|
||||
type SkipNote struct {
|
||||
Target string
|
||||
Reason string
|
||||
}
|
||||
|
||||
type Plan struct {
|
||||
RepoManagedTools []string
|
||||
Steps []InstallStep
|
||||
Skips []SkipNote
|
||||
}
|
||||
|
||||
type detector interface {
|
||||
detect(context.Context, string, map[string]struct{}) detectionResult
|
||||
}
|
||||
|
||||
type detectionResult struct {
|
||||
Steps []InstallStep
|
||||
Skips []SkipNote
|
||||
}
|
||||
|
||||
var detectors = []detector{
|
||||
goDetector{},
|
||||
nodeDetector{},
|
||||
pythonDetector{},
|
||||
rustDetector{},
|
||||
}
|
||||
|
||||
func Build(ctx context.Context, repoRoot string) Plan {
|
||||
managedTools, managedSkips := repoManagedTools(repoRoot)
|
||||
steps := make([]InstallStep, 0)
|
||||
skips := append([]SkipNote(nil), managedSkips...)
|
||||
for _, detector := range detectors {
|
||||
result := detector.detect(ctx, repoRoot, managedTools)
|
||||
steps = append(steps, result.Steps...)
|
||||
skips = append(skips, result.Skips...)
|
||||
}
|
||||
sort.Slice(steps, func(i, j int) bool {
|
||||
if steps[i].Tool != steps[j].Tool {
|
||||
return steps[i].Tool < steps[j].Tool
|
||||
}
|
||||
if steps[i].Version != steps[j].Version {
|
||||
return steps[i].Version < steps[j].Version
|
||||
}
|
||||
return steps[i].Source < steps[j].Source
|
||||
})
|
||||
sort.Slice(skips, func(i, j int) bool {
|
||||
if skips[i].Target != skips[j].Target {
|
||||
return skips[i].Target < skips[j].Target
|
||||
}
|
||||
return skips[i].Reason < skips[j].Reason
|
||||
})
|
||||
repoManagedList := make([]string, 0, len(managedTools))
|
||||
for tool := range managedTools {
|
||||
repoManagedList = append(repoManagedList, tool)
|
||||
}
|
||||
sort.Strings(repoManagedList)
|
||||
return Plan{
|
||||
RepoManagedTools: repoManagedList,
|
||||
Steps: steps,
|
||||
Skips: skips,
|
||||
}
|
||||
}
|
||||
|
||||
func readRepoFile(repoRoot, relativePath string) (string, bool, error) {
|
||||
data, err := os.ReadFile(filepath.Join(repoRoot, relativePath))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", false, nil
|
||||
}
|
||||
return "", false, err
|
||||
}
|
||||
return string(data), true, nil
|
||||
}
|
||||
|
||||
func alreadyManaged(tool string, managedTools map[string]struct{}) bool {
|
||||
_, ok := managedTools[tool]
|
||||
return ok
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue