feat: remove ai cmd

This commit is contained in:
2025-11-05 09:44:42 +08:00
parent ad8ca2b1f7
commit bf7cfc8224
24 changed files with 0 additions and 3112 deletions

View File

@@ -1,108 +0,0 @@
package contract
import (
"bufio"
"context"
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/rogeecn/renamer/internal/ai/plan"
"github.com/rogeecn/renamer/internal/ai/prompt"
)
func TestAIApplyLedgerMetadataContract(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "sample.txt"))
candidate := plan.Candidate{
OriginalPath: "sample.txt",
SizeBytes: 4,
Depth: 0,
}
response := prompt.RenameResponse{
Items: []prompt.RenameItem{
{
Original: "sample.txt",
Proposed: "001_sample-final.txt",
Sequence: 1,
},
},
Model: "test-model",
PromptHash: "prompt-hash-123",
}
policy := prompt.NamingPolicyConfig{Prefix: "proj", Casing: "kebab"}
entry, err := plan.Apply(context.Background(), plan.ApplyOptions{
WorkingDir: root,
Candidates: []plan.Candidate{candidate},
Response: response,
Policies: policy,
PromptHash: response.PromptHash,
})
if err != nil {
t.Fatalf("apply: %v", err)
}
if len(entry.Operations) != 1 {
t.Fatalf("expected 1 operation, got %d", len(entry.Operations))
}
planFile := filepath.Join(root, "001_sample-final.txt")
if _, err := os.Stat(planFile); err != nil {
t.Fatalf("expected renamed file: %v", err)
}
ledgerPath := filepath.Join(root, ".renamer")
file, err := os.Open(ledgerPath)
if err != nil {
t.Fatalf("open ledger: %v", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
var lastLine string
for scanner.Scan() {
lastLine = scanner.Text()
}
if err := scanner.Err(); err != nil {
t.Fatalf("scan ledger: %v", err)
}
var recorded map[string]any
if err := json.Unmarshal([]byte(lastLine), &recorded); err != nil {
t.Fatalf("unmarshal ledger entry: %v", err)
}
metaRaw, ok := recorded["metadata"].(map[string]any)
if !ok {
t.Fatalf("expected metadata in ledger entry")
}
aiRaw, ok := metaRaw["ai"].(map[string]any)
if !ok {
t.Fatalf("expected ai metadata in ledger entry")
}
if aiRaw["model"] != "test-model" {
t.Fatalf("expected model test-model, got %v", aiRaw["model"])
}
if aiRaw["promptHash"] != "prompt-hash-123" {
t.Fatalf("expected prompt hash recorded, got %v", aiRaw["promptHash"])
}
if aiRaw["batchSize"].(float64) != 1 {
t.Fatalf("expected batch size 1, got %v", aiRaw["batchSize"])
}
}
func writeFile(t *testing.T, path string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatalf("mkdir %s: %v", path, err)
}
if err := os.WriteFile(path, []byte("data"), 0o644); err != nil {
t.Fatalf("write file %s: %v", path, err)
}
}

View File

@@ -1,102 +0,0 @@
package contract
import (
"bytes"
"context"
"os"
"path/filepath"
"testing"
renamercmd "github.com/rogeecn/renamer/cmd"
"github.com/rogeecn/renamer/internal/ai/genkit"
"github.com/rogeecn/renamer/internal/ai/prompt"
)
type captureWorkflow struct {
request genkit.Request
}
func (c *captureWorkflow) Run(ctx context.Context, req genkit.Request) (genkit.Result, error) {
c.request = req
return genkit.Result{
Response: prompt.RenameResponse{
Items: []prompt.RenameItem{
{
Original: "alpha.txt",
Proposed: "proj_001_sample_file.txt",
Sequence: 1,
},
},
Model: "test-model",
},
}, nil
}
func TestAICommandUsesDefaultPoliciesInPrompt(t *testing.T) {
genkit.ResetWorkflowFactory()
stub := &captureWorkflow{}
genkit.OverrideWorkflowFactory(func(ctx context.Context, opts genkit.Options) (genkit.WorkflowRunner, error) {
return stub, nil
})
t.Cleanup(genkit.ResetWorkflowFactory)
rootDir := t.TempDir()
createPolicyTestFile(t, filepath.Join(rootDir, "alpha.txt"))
rootCmd := renamercmd.NewRootCommand()
var stdout, stderr bytes.Buffer
rootCmd.SetOut(&stdout)
rootCmd.SetErr(&stderr)
rootCmd.SetArgs([]string{
"ai",
"--path", rootDir,
"--dry-run",
})
if err := rootCmd.Execute(); err != nil {
if stdout.Len() > 0 {
t.Logf("stdout: %s", stdout.String())
}
if stderr.Len() > 0 {
t.Logf("stderr: %s", stderr.String())
}
t.Fatalf("command execute: %v", err)
}
req := stub.request
policies := req.Payload.Policies
if policies.Prefix != "" {
t.Fatalf("expected empty prefix, got %q", policies.Prefix)
}
if policies.Casing != "kebab" {
t.Fatalf("expected default casing kebab, got %q", policies.Casing)
}
if policies.AllowSpaces {
t.Fatalf("expected allow spaces default false")
}
if policies.KeepOriginalOrder {
t.Fatalf("expected keep original order default false")
}
banned := req.Payload.BannedTerms
containsDefault := false
for _, term := range banned {
if term == "clickbait" {
containsDefault = true
break
}
}
if !containsDefault {
t.Fatalf("expected default banned terms propagated, got %#v", banned)
}
}
func createPolicyTestFile(t *testing.T, path string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatalf("mkdir %s: %v", path, err)
}
if err := os.WriteFile(path, []byte("demo"), 0o644); err != nil {
t.Fatalf("write file %s: %v", path, err)
}
}

View File

@@ -1,126 +0,0 @@
package contract
import (
"encoding/json"
"path/filepath"
"testing"
"time"
aiprompt "github.com/rogeecn/renamer/internal/ai/prompt"
)
func TestRenamePromptSchemaAlignment(t *testing.T) {
builder := aiprompt.NewBuilder(
aiprompt.WithClock(func() time.Time {
return time.Date(2025, 11, 3, 15, 4, 5, 0, time.UTC)
}),
aiprompt.WithMaxSamples(2),
)
input := aiprompt.BuildInput{
WorkingDir: "/tmp/workspace",
TotalCount: 3,
Sequence: aiprompt.SequenceRule{
Style: "prefix",
Width: 3,
Start: 1,
Separator: "_",
},
Policies: aiprompt.PolicyConfig{
Casing: "kebab",
},
BannedTerms: []string{"Promo", " ", "promo", "ads"},
Samples: []aiprompt.SampleCandidate{
{
RelativePath: "promo SALE 01.JPG",
SizeBytes: 2048,
Depth: 0,
},
{
RelativePath: filepath.ToSlash(filepath.Join("nested", "Report FINAL.PDF")),
SizeBytes: 1024,
Depth: 1,
},
{
RelativePath: "notes.txt",
SizeBytes: 128,
Depth: 0,
},
},
Metadata: map[string]string{
"cliVersion": "test-build",
},
}
promptPayload, err := builder.Build(input)
if err != nil {
t.Fatalf("Build error: %v", err)
}
if promptPayload.WorkingDir != input.WorkingDir {
t.Fatalf("expected working dir %q, got %q", input.WorkingDir, promptPayload.WorkingDir)
}
if promptPayload.TotalCount != input.TotalCount {
t.Fatalf("expected total count %d, got %d", input.TotalCount, promptPayload.TotalCount)
}
if len(promptPayload.Samples) != 2 {
t.Fatalf("expected 2 samples after max cap, got %d", len(promptPayload.Samples))
}
first := promptPayload.Samples[0]
if first.OriginalName != "nested/Report FINAL.PDF" {
t.Fatalf("unexpected first sample name: %q", first.OriginalName)
}
if first.Extension != ".PDF" {
t.Fatalf("expected extension to remain case-sensitive, got %q", first.Extension)
}
if first.SizeBytes != 1024 {
t.Fatalf("expected size 1024, got %d", first.SizeBytes)
}
if first.PathDepth != 1 {
t.Fatalf("expected depth 1, got %d", first.PathDepth)
}
seq := promptPayload.SequenceRule
if seq.Style != "prefix" || seq.Width != 3 || seq.Start != 1 || seq.Separator != "_" {
t.Fatalf("sequence rule mismatch: %#v", seq)
}
if promptPayload.Policies.Casing != "kebab" {
t.Fatalf("expected casing kebab, got %q", promptPayload.Policies.Casing)
}
expectedTerms := []string{"ads", "promo"}
if len(promptPayload.BannedTerms) != len(expectedTerms) {
t.Fatalf("expected %d banned terms, got %d", len(expectedTerms), len(promptPayload.BannedTerms))
}
for i, term := range expectedTerms {
if promptPayload.BannedTerms[i] != term {
t.Fatalf("banned term at %d mismatch: expected %q got %q", i, term, promptPayload.BannedTerms[i])
}
}
if promptPayload.Metadata["cliVersion"] != "test-build" {
t.Fatalf("metadata cliVersion mismatch: %s", promptPayload.Metadata["cliVersion"])
}
if promptPayload.Metadata["generatedAt"] != "2025-11-03T15:04:05Z" {
t.Fatalf("expected generatedAt timestamp preserved, got %q", promptPayload.Metadata["generatedAt"])
}
raw, err := json.Marshal(promptPayload)
if err != nil {
t.Fatalf("marshal error: %v", err)
}
var decoded map[string]any
if err := json.Unmarshal(raw, &decoded); err != nil {
t.Fatalf("unmarshal round-trip error: %v", err)
}
for _, key := range []string{"workingDir", "samples", "totalCount", "sequenceRule", "policies"} {
if _, ok := decoded[key]; !ok {
t.Fatalf("prompt JSON missing key %q", key)
}
}
}