feat: vendor add end-to-end with deterministic lockfile v2

- go-git in-process clone, default-branch/tag resolution, optional token auth
- web-tree URL normalization (github/gitlab) with implied discovery root
- discovery of skills/commands/agents/mcp, lenient frontmatter with warnings
- selection: all by default, --include with missing-entry hard errors
- external/<source>/<type>/ materialization preserving exec bits
- lockfile v2: deterministic JSON, pinned url/ref/rev, inventory, warnings
- offline black-box e2e suite against local fixture git repositories
This commit is contained in:
2026-08-22 21:52:30 +02:00
parent 2a6498dae1
commit 2c7200380b
16 changed files with 1648 additions and 2 deletions
+55
View File
@@ -0,0 +1,55 @@
package discovery
import (
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
)
// FsTree adapts a filesystem root to the Tree interface (used for scanning
// the work repository's own items).
type FsTree struct {
Root string
}
func (f *FsTree) Walk(fn func(rel string, isDir bool) error) error {
var paths []string
err := filepath.WalkDir(f.Root, func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if p == f.Root {
return nil
}
paths = append(paths, p)
return nil
})
if err != nil {
return err
}
sort.Strings(paths)
for _, p := range paths {
rel, err := filepath.Rel(f.Root, p)
if err != nil {
return err
}
info, err := os.Stat(p)
if err != nil {
return err
}
if err := fn(filepath.ToSlash(rel), info.IsDir()); err != nil {
return err
}
}
return nil
}
func (f *FsTree) ReadFile(rel string) ([]byte, error) {
clean := filepath.FromSlash(rel)
if strings.Contains(clean, "..") {
return nil, os.ErrNotExist
}
return os.ReadFile(filepath.Join(f.Root, clean))
}