package state import ( "fmt" "os" "strings" "github.com/voocel/ainovel-cli/domain" ) // SavePremise 保存故事前提到 premise.md。 func (s *Store) SavePremise(content string) error { return s.writeMarkdown("premise.md", content) } // LoadPremise 读取 premise.md。不存在时返回空字符串。 func (s *Store) LoadPremise() (string, error) { data, err := s.readFile("premise.md") if os.IsNotExist(err) { return "", nil } return string(data), err } // SaveOutline 同时保存 outline.json(机器读)和 outline.md(人读)。 func (s *Store) SaveOutline(entries []domain.OutlineEntry) error { if err := s.writeJSON("outline.json", entries); err != nil { return err } return s.writeMarkdown("outline.md", renderOutline(entries)) } // LoadOutline 从 outline.json 读取结构化大纲。 func (s *Store) LoadOutline() ([]domain.OutlineEntry, error) { var entries []domain.OutlineEntry if err := s.readJSON("outline.json", &entries); err != nil { if os.IsNotExist(err) { return nil, nil } return nil, err } return entries, nil } // GetChapterOutline 获取指定章节的大纲条目。 func (s *Store) GetChapterOutline(chapter int) (*domain.OutlineEntry, error) { entries, err := s.LoadOutline() if err != nil { return nil, err } for i := range entries { if entries[i].Chapter == chapter { return &entries[i], nil } } return nil, fmt.Errorf("chapter %d not found in outline", chapter) } func renderOutline(entries []domain.OutlineEntry) string { var b strings.Builder b.WriteString("# 大纲\n\n") for _, e := range entries { fmt.Fprintf(&b, "## 第 %d 章:%s\n\n", e.Chapter, e.Title) fmt.Fprintf(&b, "**核心事件**:%s\n\n", e.CoreEvent) if e.Hook != "" { fmt.Fprintf(&b, "**钩子**:%s\n\n", e.Hook) } if len(e.Scenes) > 0 { b.WriteString("**场景**:\n") for i, sc := range e.Scenes { fmt.Fprintf(&b, "%d. %s\n", i+1, sc) } b.WriteString("\n") } } return b.String() }