first commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
// This file distributes a classified pi prompt/command package into pigo's
|
||||
// prompts directory so runtime.LoadUserCommandsDir picks it up (#160, #342).
|
||||
//
|
||||
// pigo loads declarative slash commands from $PIGO_HOME/prompts/*.md (and the
|
||||
// legacy $PIGO_HOME/commands/*.md) non-recursively: each markdown file defines
|
||||
// a "/name" command, named after the file, whose body is the prompt template.
|
||||
// A pi prompt package ships one or more such templates, conventionally under a
|
||||
// "prompts/" subdirectory (the pi convention); the legacy "commands/" subdir is
|
||||
// a fallback, and some packages place the .md files at the package root.
|
||||
//
|
||||
// Distribution copies those .md files (flattened, since the loader is
|
||||
// non-recursive) into $PIGO_HOME/prompts/. Every file laid down is returned so
|
||||
// the lockfile can remove precisely what was installed.
|
||||
package pkgmgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DistributePrompt copies the prompt package's command templates at pkgDir into
|
||||
// the commands directory. It looks first in "<pkgDir>/commands" for *.md files
|
||||
// and falls back to *.md at the package root. It returns the absolute paths of
|
||||
// every file it created, for the lockfile. An unresolvable commands dir, or a
|
||||
// package with no command templates, is an error.
|
||||
func DistributePrompt(pkgDir, name string) ([]string, error) {
|
||||
promptsDir := PromptsDir()
|
||||
if promptsDir == "" {
|
||||
return nil, fmt.Errorf("pkgmgr: cannot resolve prompts dir (PIGO_HOME/home unavailable)")
|
||||
}
|
||||
|
||||
// Prefer the pi-aligned prompts/ subdir, then the legacy commands/ subdir,
|
||||
// then root-level *.md as a last resort.
|
||||
srcDir := ""
|
||||
for _, sub := range []string{"prompts", "commands"} {
|
||||
if dirExists(filepath.Join(pkgDir, sub)) {
|
||||
srcDir = filepath.Join(pkgDir, sub)
|
||||
break
|
||||
}
|
||||
}
|
||||
if srcDir == "" {
|
||||
srcDir = pkgDir // fall back to root-level *.md
|
||||
}
|
||||
entries, err := os.ReadDir(srcDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pkgmgr: read prompt source dir: %w", err)
|
||||
}
|
||||
|
||||
var mds []string
|
||||
for _, e := range entries {
|
||||
if e.IsDir() || !strings.EqualFold(filepath.Ext(e.Name()), ".md") {
|
||||
continue
|
||||
}
|
||||
// A root-level README.md is not a command template; skip it when we've
|
||||
// fallen back to the package root.
|
||||
if srcDir == pkgDir && strings.EqualFold(e.Name(), "README.md") {
|
||||
continue
|
||||
}
|
||||
mds = append(mds, e.Name())
|
||||
}
|
||||
if len(mds) == 0 {
|
||||
return nil, fmt.Errorf("pkgmgr: prompt %q has no prompt templates (*.md)", name)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(promptsDir, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("pkgmgr: create prompts dir: %w", err)
|
||||
}
|
||||
|
||||
created := make([]string, 0, len(mds))
|
||||
for _, md := range mds {
|
||||
src := filepath.Join(srcDir, md)
|
||||
dst := filepath.Join(promptsDir, md)
|
||||
info, statErr := os.Stat(src)
|
||||
if statErr != nil {
|
||||
return created, fmt.Errorf("pkgmgr: stat command %q: %w", src, statErr)
|
||||
}
|
||||
if err := copyFile(src, dst, info.Mode()); err != nil {
|
||||
return created, fmt.Errorf("pkgmgr: copy command %q: %w", md, err)
|
||||
}
|
||||
created = append(created, dst)
|
||||
}
|
||||
return created, nil
|
||||
}
|
||||
Reference in New Issue
Block a user