Publish the exact sanitized Agent Skill and VS Code preview source tree with independent license boundaries, deterministic provenance manifests, and no private development history. Material design and implementation assistance was provided by OpenAI Codex. Signed-off-by: Cole Speelman <crspeelman@gmail.com>
105 lines
2.5 KiB
Go
105 lines
2.5 KiB
Go
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package main
|
|
|
|
import (
|
|
"archive/zip"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var skillFiles = []string{
|
|
"LICENSE",
|
|
"SKILL.md",
|
|
"agents/openai.yaml",
|
|
"references/authoring.md",
|
|
"references/workflows.md",
|
|
}
|
|
|
|
func main() {
|
|
root, err := filepath.Abs(filepath.Join("skills", "sandwich-hime"))
|
|
must(err)
|
|
artifactDir := "artifacts"
|
|
must(os.MkdirAll(artifactDir, 0o755))
|
|
outputPath := filepath.Join(artifactDir, "sandwich-hime-skill-v0.1.0.zip")
|
|
file, err := os.OpenFile(outputPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
|
must(err)
|
|
archive := zip.NewWriter(file)
|
|
fixed := time.Date(1980, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
sort.Strings(skillFiles)
|
|
for _, relative := range skillFiles {
|
|
path := filepath.Join(root, filepath.FromSlash(relative))
|
|
info, err := os.Lstat(path)
|
|
must(err)
|
|
if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
|
|
panic("skill archive input is not a regular file: " + relative)
|
|
}
|
|
header := &zip.FileHeader{Name: "sandwich-hime/" + relative, Method: zip.Deflate}
|
|
header.SetModTime(fixed)
|
|
header.SetMode(0o644)
|
|
writer, err := archive.CreateHeader(header)
|
|
must(err)
|
|
source, err := os.Open(path)
|
|
must(err)
|
|
_, copyErr := io.Copy(writer, source)
|
|
closeErr := source.Close()
|
|
must(copyErr)
|
|
must(closeErr)
|
|
}
|
|
must(archive.Close())
|
|
must(file.Close())
|
|
|
|
verifyExactTree(root)
|
|
content, err := os.ReadFile(outputPath)
|
|
must(err)
|
|
digest := fmt.Sprintf("%x", sha256.Sum256(content))
|
|
must(os.WriteFile(filepath.Join(artifactDir, "sandwich-hime-skill-v0.1.0.zip.sha256"), []byte(digest+" "+filepath.Base(outputPath)+"\n"), 0o644))
|
|
fmt.Printf("%s %s\n", digest, outputPath)
|
|
}
|
|
|
|
func verifyExactTree(root string) {
|
|
want := make(map[string]bool, len(skillFiles))
|
|
for _, file := range skillFiles {
|
|
want[file] = true
|
|
}
|
|
var actual []string
|
|
must(filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if entry.IsDir() {
|
|
return nil
|
|
}
|
|
relative, err := filepath.Rel(root, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
relative = filepath.ToSlash(relative)
|
|
actual = append(actual, relative)
|
|
if !want[relative] {
|
|
return fmt.Errorf("unexpected skill file: %s", relative)
|
|
}
|
|
return nil
|
|
}))
|
|
if len(actual) != len(want) {
|
|
panic(fmt.Sprintf("skill file count = %d, want %d", len(actual), len(want)))
|
|
}
|
|
for _, file := range actual {
|
|
if strings.TrimSpace(file) == "" {
|
|
panic("empty skill filename")
|
|
}
|
|
}
|
|
}
|
|
|
|
func must(err error) {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|