From 81c36bcf85d01747e86a9636982b82ae09ff0a85 Mon Sep 17 00:00:00 2001 From: "songtianyi.theo" Date: Fri, 3 Jul 2026 02:25:52 +0800 Subject: [PATCH] feat: expose svglide complete and author actions --- shortcuts/slides/slides_create_svglide.go | 18 +++- .../slides/slides_create_svglide_test.go | 101 ++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/shortcuts/slides/slides_create_svglide.go b/shortcuts/slides/slides_create_svglide.go index cd4dd21b..20e7e9c2 100644 --- a/shortcuts/slides/slides_create_svglide.go +++ b/shortcuts/slides/slides_create_svglide.go @@ -20,8 +20,8 @@ var SlidesCreateSVGlide = common.Shortcut{ Risk: "write", AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ - {Name: "action", Desc: "runtime action: init, status, next, validate, preview", Required: true, Enum: []string{"init", "status", "next", "validate", "preview"}}, - {Name: "run", Desc: "existing run directory for status/next/validate/preview"}, + {Name: "action", Desc: "runtime action: init, status, next, complete, author, validate, preview", Required: true, Enum: []string{"init", "status", "next", "complete", "author", "validate", "preview"}}, + {Name: "run", Desc: "existing run directory for status/next/complete/author/validate/preview"}, {Name: "title", Desc: "deck title for init"}, {Name: "input", Desc: "local source markdown/text path for init"}, {Name: "audience", Desc: "final audience for the deck"}, @@ -93,6 +93,20 @@ var SlidesCreateSVGlide = common.Shortcut{ } runtime.Out(report, nil) return nil + case "complete": + report, err := svglide.CompleteCurrentStage(runtime.Str("run")) + if err != nil { + return err + } + runtime.Out(report, nil) + return nil + case "author": + report, err := svglide.AuthorSlides(runtime.Str("run")) + if err != nil { + return err + } + runtime.Out(report, nil) + return nil case "validate": report, err := svglide.ValidateRun(runtime.Str("run")) if err != nil { diff --git a/shortcuts/slides/slides_create_svglide_test.go b/shortcuts/slides/slides_create_svglide_test.go index 7ee14ac9..7c21c605 100644 --- a/shortcuts/slides/slides_create_svglide_test.go +++ b/shortcuts/slides/slides_create_svglide_test.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/larksuite/cli/internal/cmdutil" + "github.com/larksuite/cli/shortcuts/common" ) func TestSlidesCreateSVGlideInitShortcut(t *testing.T) { @@ -153,6 +154,87 @@ func TestSlidesCreateSVGlidePreviewActionOutputsReport(t *testing.T) { } } +func TestSlidesCreateSVGlideActionEnumIncludesCompleteAndAuthor(t *testing.T) { + actionFlag := findSVGlideShortcutFlag(t, "action") + want := map[string]bool{ + "complete": false, + "author": false, + } + for _, value := range actionFlag.Enum { + if _, ok := want[value]; ok { + want[value] = true + } + if value == "repair" { + t.Fatal("action enum contains repair, want Task 5 to add it later") + } + } + for value, found := range want { + if !found { + t.Fatalf("action enum missing %q: %+v", value, actionFlag.Enum) + } + if !strings.Contains(actionFlag.Desc, value) { + t.Fatalf("action desc %q missing %q", actionFlag.Desc, value) + } + } +} + +func TestSlidesCreateSVGlideCompleteActionAdvancesRequestStage(t *testing.T) { + dir := initSVGlideShortcutRun(t) + f, stdout, _, _ := cmdutil.TestFactory(t, slidesTestConfig(t, "")) + + err := runSlidesShortcut(t, f, stdout, SlidesCreateSVGlide, []string{ + "+create-svglide", + "--action", "complete", + "--run", "run-demo", + "--as", "user", + }) + if err != nil { + t.Fatal(err) + } + data := decodeShortcutData(t, stdout) + if data["current_stage"] != "research" { + t.Fatalf("current_stage = %v, want research; data=%+v", data["current_stage"], data) + } + receiptPath := filepath.Join(dir, "run-demo", "receipts", "request.json") + raw, err := os.ReadFile(receiptPath) + if err != nil { + t.Fatalf("missing request receipt: %v", err) + } + var receipt map[string]any + if err := json.Unmarshal(raw, &receipt); err != nil { + t.Fatalf("invalid request receipt: %v", err) + } + if receipt["stage"] != "request" || receipt["status"] != "done" { + t.Fatalf("receipt = %+v, want request done", receipt) + } +} + +func TestSlidesCreateSVGlideAuthorActionWritesSVG(t *testing.T) { + initSVGlideShortcutRunWithAuthorInputs(t) + f, stdout, _, _ := cmdutil.TestFactory(t, slidesTestConfig(t, "")) + + err := runSlidesShortcut(t, f, stdout, SlidesCreateSVGlide, []string{ + "+create-svglide", + "--action", "author", + "--run", "run-demo", + "--as", "user", + }) + if err != nil { + t.Fatal(err) + } + data := decodeShortcutData(t, stdout) + if data["status"] != "done" { + t.Fatalf("status = %v, want done; data=%+v", data["status"], data) + } + raw, err := os.ReadFile(filepath.Join("run-demo", "slides", "01.svg")) + if err != nil { + t.Fatalf("missing authored SVG: %v", err) + } + if !strings.Contains(string(raw), `slide:role="slide"`) { + t.Fatalf("authored SVG missing slide role:\n%s", string(raw)) + } +} + func TestSlidesCreateSVGlideValidateActionDoesNotErrorOnValidationFailure(t *testing.T) { initSVGlideShortcutRun(t) writeSVGlideShortcutDeck(t, "slides/missing.svg") @@ -188,6 +270,14 @@ func initSVGlideShortcutRunWithDeck(t *testing.T) { writeSVGlideShortcutFile(t, filepath.Join("run-demo", "slides", "01.svg"), svglideShortcutVisibleTextSVG()) } +func initSVGlideShortcutRunWithAuthorInputs(t *testing.T) { + initSVGlideShortcutRun(t) + writeSVGlideShortcutDeck(t, "slides/01.svg") + writeSVGlideShortcutFile(t, filepath.Join("run-demo", "brief", "visual_system.json"), `{"color_system":{"background":"#FFFFFF","ink":"#111827","muted":"#6B7280","accent":"#2563EB"},"typography":{"title":32,"body":16},"layout_language":"analyst deck"}`) + writeSVGlideShortcutFile(t, filepath.Join("run-demo", "content", "slide_content.json"), `{"slides":[{"id":"cover","content":"Point A\nPoint B","notes":"Speaker note"}]}`) + writeSVGlideShortcutFile(t, filepath.Join("run-demo", "assets", "assets_plan.json"), `{"assets":[]}`) +} + func initSVGlideShortcutRun(t *testing.T) string { t.Helper() dir := t.TempDir() @@ -209,6 +299,17 @@ func initSVGlideShortcutRun(t *testing.T) string { return dir } +func findSVGlideShortcutFlag(t *testing.T, name string) common.Flag { + t.Helper() + for _, flag := range SlidesCreateSVGlide.Flags { + if flag.Name == name { + return flag + } + } + t.Fatalf("missing flag %q", name) + return common.Flag{} +} + func writeSVGlideShortcutDeck(t *testing.T, slidePath string) { t.Helper() deck := map[string]any{