140 lines
4.6 KiB
Go
140 lines
4.6 KiB
Go
package prompts
|
|
|
|
// Tests for project-level .pigo/prompts (US-006, #337): loaded at the project
|
|
// tier only when the project is trusted, overrides global same-name templates,
|
|
// and is suppressed by --no-prompt-templates.
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/smallnest/pigo/internal/cli"
|
|
"github.com/smallnest/pigo/internal/cli/testutil"
|
|
"github.com/smallnest/pigo/internal/runtime"
|
|
)
|
|
|
|
// TestBuildSlashRegistryLoadsProjectPromptsTrusted: with the project trusted,
|
|
// .pigo/prompts/*.md loads at the project tier.
|
|
func TestBuildSlashRegistryLoadsProjectPromptsTrusted(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("PIGO_HOME", home) // empty global
|
|
cwdTmp := t.TempDir()
|
|
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "review.md", "Review: $ARGUMENTS")
|
|
|
|
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
|
|
PromptTemplateSources{
|
|
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
|
|
ProjectTrusted: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("BuildSlashRegistry: %v", err)
|
|
}
|
|
out, err := reg.ResolveOutcome("/review diff")
|
|
if err != nil {
|
|
t.Fatalf("ResolveOutcome: %v", err)
|
|
}
|
|
if !out.Handled || out.Prompt != "Review: diff" {
|
|
t.Errorf("/review = handled=%v prompt=%q, want \"Review: diff\"", out.Handled, out.Prompt)
|
|
}
|
|
}
|
|
|
|
// TestBuildSlashRegistryProjectPromptsUntrustedSkipped: when the project is not
|
|
// trusted, .pigo/prompts is not loaded.
|
|
func TestBuildSlashRegistryProjectPromptsUntrustedSkipped(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("PIGO_HOME", home)
|
|
cwdTmp := t.TempDir()
|
|
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "review.md", "Review: $ARGUMENTS")
|
|
|
|
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
|
|
PromptTemplateSources{
|
|
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
|
|
ProjectTrusted: false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("BuildSlashRegistry: %v", err)
|
|
}
|
|
if _, ok := reg.Lookup("review"); ok {
|
|
t.Error("/review should NOT load from an untrusted project")
|
|
}
|
|
}
|
|
|
|
// TestBuildSlashRegistryProjectMissingDirNoError: a missing .pigo/prompts is
|
|
// not an error (most projects don't have one).
|
|
func TestBuildSlashRegistryProjectMissingDirNoError(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("PIGO_HOME", home)
|
|
cwdTmp := t.TempDir() // no .pigo/prompts created
|
|
|
|
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
|
|
PromptTemplateSources{
|
|
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
|
|
ProjectTrusted: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("missing .pigo/prompts should not error, got %v", err)
|
|
}
|
|
if reg == nil {
|
|
t.Fatal("registry is nil")
|
|
}
|
|
}
|
|
|
|
// TestBuildSlashRegistryProjectOverridesGlobal: a project template overrides a
|
|
// same-named global one (project tier wins, global shadowed).
|
|
func TestBuildSlashRegistryProjectOverridesGlobal(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("PIGO_HOME", home)
|
|
// global
|
|
testutil.WritePrompt(t, home, "prompts", "dup.md", "FROM GLOBAL")
|
|
// project
|
|
cwdTmp := t.TempDir()
|
|
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "dup.md", "FROM PROJECT")
|
|
|
|
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
|
|
PromptTemplateSources{
|
|
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
|
|
ProjectTrusted: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("BuildSlashRegistry: %v", err)
|
|
}
|
|
cmd, ok := reg.Lookup("dup")
|
|
if !ok {
|
|
t.Fatal("/dup not found")
|
|
}
|
|
if got := cmd.Expand(""); got != "FROM PROJECT" {
|
|
t.Errorf("project should override global, got %q", got)
|
|
}
|
|
found := false
|
|
for _, e := range reg.Shadowed() {
|
|
if e.Name == "dup" && e.Tier == runtime.TierGlobal {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("global dup should be shadowed with TierGlobal, got %v", reg.Shadowed())
|
|
}
|
|
}
|
|
|
|
// TestBuildSlashRegistryNoPromptTemplatesDisablesProject: --no-prompt-templates
|
|
// suppresses project prompts too.
|
|
func TestBuildSlashRegistryNoPromptTemplatesDisablesProject(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("PIGO_HOME", home)
|
|
cwdTmp := t.TempDir()
|
|
testutil.WritePrompt(t, cwdTmp, filepath.Join(".pigo", "prompts"), "review.md", "Review: $ARGUMENTS")
|
|
|
|
reg, err := BuildSlashRegistry(&cli.LiveConfig{Model: "test", ProviderName: "test"}, nil, nil,
|
|
PromptTemplateSources{
|
|
Disable: true,
|
|
ProjectDir: filepath.Join(cwdTmp, ".pigo", "prompts"),
|
|
ProjectTrusted: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("BuildSlashRegistry: %v", err)
|
|
}
|
|
if _, ok := reg.Lookup("review"); ok {
|
|
t.Error("/review should NOT load under --no-prompt-templates")
|
|
}
|
|
}
|