diff --git a/internal/helpers/wiki.go b/internal/helpers/wiki.go index 78ef2f35..88c0272e 100644 --- a/internal/helpers/wiki.go +++ b/internal/helpers/wiki.go @@ -1357,8 +1357,9 @@ ORG 类型授权不会出现在查询结果中。`, if err != nil { return err } - // --format raw: 输出原始 MCP 文本,不做后处理 - if deps.Caller.Format() == "raw" { + // 保持与共享 dispatcher (callMCPToolInternalOpts) 一致的输出契约: + // 仅 --format json 做时间/标签增强,raw、table 及其他格式输出原始 MCP 文本 + if deps.Caller.Format() != "json" { deps.Out.PrintRaw(text) return nil } diff --git a/internal/helpers/wiki_feed_format_test.go b/internal/helpers/wiki_feed_format_test.go index 57adc218..37e34981 100644 --- a/internal/helpers/wiki_feed_format_test.go +++ b/internal/helpers/wiki_feed_format_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "io" "os" + "strings" "testing" ) @@ -316,7 +317,8 @@ func TestCrossPlatformCoverageEnrichFeedFieldsEmptyItem(t *testing.T) { func TestCrossPlatformCoverageWikiFeedListFormatIntegration(t *testing.T) { // 通过 scriptedToolCaller 返回真实结构的 feed JSON,验证 RunE 中 - // callMCPToolReturnText → formatFeedTime → PrintJSON 完整路径 + // callMCPToolReturnText → formatFeedTime → PrintJSON 完整路径(仅 --format json) + caller := &scriptedToolCaller{format: "json"} ts := float64(1750067400000) feedPayload := map[string]any{ "feeds": []any{ @@ -350,10 +352,7 @@ func TestCrossPlatformCoverageWikiFeedListFormatIntegration(t *testing.T) { if err != nil { t.Fatal(err) } - - caller := &scriptedToolCaller{ - steps: []scriptedToolStep{{text: string(payloadBytes)}}, - } + caller.steps = []scriptedToolStep{{text: string(payloadBytes)}} var out bytes.Buffer oldDeps := deps @@ -374,7 +373,7 @@ func TestCrossPlatformCoverageWikiFeedListFormatIntegration(t *testing.T) { root.SetErr(io.Discard) root.SetIn(os.Stdin) - args := []string{"feed", "list", "--workspace", "ws1", "--exclude-file"} + args := []string{"feed", "list", "--workspace", "ws1", "--exclude-file", "--format", "json"} root.SetArgs(args) os.Args = append([]string{"dws", "wiki"}, args...) @@ -481,6 +480,54 @@ func TestCrossPlatformCoverageWikiFeedListRawFormat(t *testing.T) { } } +func TestCrossPlatformCoverageWikiFeedListTableFormatMatchesDispatcher(t *testing.T) { + // --format table 回归:与共享 dispatcher (callMCPToolInternalOpts) 契约一致, + // 输出原始紧凑 MCP 文本,不做 pretty 化,也不注入 timeFormatted / typeLabel + rawPayload := `{"feeds":[{"time":1750067400000,"type":1,"id":"f1"}]}` + caller := &scriptedToolCaller{ + format: "table", + steps: []scriptedToolStep{{text: rawPayload}}, + } + + var out bytes.Buffer + oldDeps := deps + oldArgs := os.Args + InitDeps(caller) + deps.Out.w = &out + deps.Out.errW = io.Discard + t.Cleanup(func() { + deps = oldDeps + os.Args = oldArgs + }) + + root := newWikiCommand() + installExampleGlobalFlags(root) + root.SilenceErrors = true + root.SilenceUsage = true + root.SetOut(io.Discard) + root.SetErr(io.Discard) + root.SetIn(os.Stdin) + + args := []string{"feed", "list", "--workspace", "ws1", "--format", "table"} + root.SetArgs(args) + os.Args = append([]string{"dws", "wiki"}, args...) + + if err := root.Execute(); err != nil { + t.Fatalf("Execute: %v", err) + } + + // 与共享 dispatcher 一致:输出 = 原始 MCP 文本原文 + if got := strings.TrimSpace(out.String()); got != rawPayload { + t.Fatalf("table output should equal raw MCP payload,\ngot: %s\nwant: %s", got, rawPayload) + } + // 不注入任何增强字段 + for _, injected := range []string{"timeFormatted", "typeLabel"} { + if strings.Contains(out.String(), injected) { + t.Fatalf("table output should not inject %s, got: %s", injected, out.String()) + } + } +} + func TestCrossPlatformCoverageWikiFeedListEmptyResponse(t *testing.T) { // MCP 返回空结果 → formatFeedTime 处理空字符串 → 不报错 caller := &scriptedToolCaller{} // 无 steps → 空结果