cr修复
This commit is contained in:
+16
-57
@@ -1325,7 +1325,7 @@ ORG 类型授权不会出现在查询结果中。`,
|
||||
|
||||
通过 --workspace 指定知识库,支持传入知识库 ID 或知识库 URL。
|
||||
支持分页,通过 --cursor 传入上次返回的 nextToken 获取下一页。
|
||||
使用 --exclude-file 可排除文件相关动态(文档创建/文档更新等),仅保留文档操作(创建/更新/评论/点赞等)。
|
||||
使用 --exclude-file 可排除普通文件、媒体文件、文件夹及 Office 文件动态,仅保留在线文档操作(创建/更新/评论/点赞等)。
|
||||
当用户要求"只看文档操作""排除文件上传"等意图时,必须使用此 flag,
|
||||
禁止在客户端自行过滤。`,
|
||||
Example: ` dws wiki feed list --workspace <workspaceId>
|
||||
@@ -1357,8 +1357,12 @@ ORG 类型授权不会出现在查询结果中。`,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
deps.Out.PrintJSON(formatFeedTime(text))
|
||||
return nil
|
||||
// --format raw: 输出原始 MCP 文本,不做后处理
|
||||
if deps.Caller.Format() == "raw" {
|
||||
deps.Out.PrintRaw(text)
|
||||
return nil
|
||||
}
|
||||
return deps.Out.PrintJSON(formatFeedTime(text))
|
||||
},
|
||||
}
|
||||
DeclareLeafMetadata(feedListCmd, LeafSpec{
|
||||
@@ -1406,7 +1410,7 @@ ORG 类型授权不会出现在查询结果中。`,
|
||||
feedListCmd.Flags().String("workspace", "", "知识库 ID 或 URL (必填)")
|
||||
feedListCmd.Flags().Int("limit", 0, "每页数量 (默认 10,最大 20)。用户未明确要求条数时禁止加此 flag,让服务端走默认 10")
|
||||
feedListCmd.Flags().String("cursor", "", "分页游标 (首页留空)")
|
||||
feedListCmd.Flags().Bool("exclude-file", false, "排除文件相关动态(文档创建/更新/评论/点赞等),仅保留文档操作。用户要求排除文件/只看文档创建/更新/评论/点赞时必须使用此flag,禁止客户端过滤")
|
||||
feedListCmd.Flags().Bool("exclude-file", false, "排除普通文件、媒体文件、文件夹及 Office 文件动态,仅保留在线文档操作(创建/更新/评论/点赞)。用户要求排除文件/只看文档操作时必须使用此 flag,禁止客户端过滤")
|
||||
feedListCmd.Flags().String("workspace-id", "", "")
|
||||
_ = feedListCmd.Flags().MarkHidden("workspace-id")
|
||||
RegisterCrossProductAliases(feedListCmd)
|
||||
@@ -1448,9 +1452,8 @@ ORG 类型授权不会出现在查询结果中。`,
|
||||
var beijingLoc = time.FixedZone("CST", 8*3600)
|
||||
|
||||
// formatFeedTime 将知识库动态 feeds[].time 毫秒时间戳转为可读时间字符串,
|
||||
// 同时保留原始毫秒值至 timeMs 字段。解析失败时原样返回,不阻断输出。
|
||||
// 同时裁剪冗余字段(avatarUrl、docKey、parentDoc 等),减小输出体积,
|
||||
// 避免 Agent 因 JSON 过大而在后续处理中产生长耗时 echo 命令。
|
||||
// 写入 timeFormatted 字段,同时保留原始 time 毫秒时间戳不变(避免破坏已有脚本)。
|
||||
// 解析失败时原样返回,不阻断输出。
|
||||
func formatFeedTime(raw string) any {
|
||||
var result map[string]any
|
||||
if err := json.Unmarshal([]byte(raw), &result); err != nil {
|
||||
@@ -1469,65 +1472,21 @@ func formatFeedTime(raw string) any {
|
||||
if !ok || ms <= 0 {
|
||||
continue
|
||||
}
|
||||
item["timeMs"] = ms
|
||||
item["time"] = time.UnixMilli(int64(ms)).In(beijingLoc).Format("2006-01-02 15:04")
|
||||
trimFeedFields(item)
|
||||
// 保留原始 time 毫秒时间戳,新增 timeFormatted 可读字段
|
||||
item["timeFormatted"] = time.UnixMilli(int64(ms)).In(beijingLoc).Format("2006-01-02 15:04")
|
||||
enrichFeedFields(item)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// trimFeedFields 裁剪单条 feed 中对 Agent 无用的冗余字段,
|
||||
// 大幅减小 JSON 输出体积,避免 Agent 二次处理时产生超长 echo 命令。
|
||||
func trimFeedFields(item map[string]any) {
|
||||
// 移除大块冗余字段
|
||||
delete(item, "parentDoc")
|
||||
delete(item, "userInfo")
|
||||
|
||||
// enrichFeedFields 为单条 feed 补充可读字段(typeLabel),
|
||||
func enrichFeedFields(item map[string]any) {
|
||||
// 将 type 数字映射为可读标签,使 Agent 无需查表即可直接展示
|
||||
if typeNum, ok := item["type"].(float64); ok {
|
||||
if label, known := feedTypeLabels[int(typeNum)]; known {
|
||||
item["typeLabel"] = label
|
||||
}
|
||||
}
|
||||
|
||||
// 裁剪 users:仅保留 nick
|
||||
if users, ok := item["users"].([]any); ok {
|
||||
for _, u := range users {
|
||||
if user, ok := u.(map[string]any); ok {
|
||||
nick := user["nick"]
|
||||
for k := range user {
|
||||
delete(user, k)
|
||||
}
|
||||
if nick != nil {
|
||||
user["nick"] = nick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 裁剪 content:仅保留 content.doc.name 和 content.doc.extension
|
||||
// extension 区分文档类型(adoc=文档, asheet=表格等),Agent 需要用来区分更新对象
|
||||
if content, ok := item["content"].(map[string]any); ok {
|
||||
if doc, ok := content["doc"].(map[string]any); ok {
|
||||
name := doc["name"]
|
||||
extension := doc["extension"]
|
||||
for k := range doc {
|
||||
delete(doc, k)
|
||||
}
|
||||
if name != nil {
|
||||
doc["name"] = name
|
||||
}
|
||||
if extension != nil {
|
||||
doc["extension"] = extension
|
||||
}
|
||||
}
|
||||
// 移除 content 中除 doc 外的其他字段(如 dentryKey / workspaceKey 等)
|
||||
for k := range content {
|
||||
if k != "doc" {
|
||||
delete(content, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// feedTypeLabels 将知识库动态 type 数字映射为可读中文标签,
|
||||
@@ -1543,7 +1502,7 @@ var feedTypeLabels = map[int]string{
|
||||
7: "上传普通文件",
|
||||
8: "上传媒体文件",
|
||||
9: "上传文件夹",
|
||||
10: "上传文件夹",
|
||||
10: "上传文件夹 V2",
|
||||
11: "加入团队",
|
||||
12: "创建知识库",
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ---------- formatFeedTime unit tests ----------
|
||||
@@ -104,16 +102,10 @@ func TestCrossPlatformCoverageFormatFeedTimeTimeMissingOrInvalid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageFormatFeedTimeNormalPath(t *testing.T) {
|
||||
// 正常路径:毫秒时间戳被格式化,原始值保留到 timeMs
|
||||
// 2025-06-15 10:30:00 UTC = 2025-06-15 18:30:00 CST (UTC+8)
|
||||
// 正常路径:time 保留原始毫秒时间戳,timeFormatted 被格式化为北京时间
|
||||
// 1750067400000 ms = 2025-06-16 17:50 Beijing time (UTC+8)
|
||||
tsMs := float64(1750067400000)
|
||||
raw := `{"feeds":[{"time":` + json.Number(strings.TrimRight(strings.TrimRight(
|
||||
strings.Replace(
|
||||
string(mustMarshal(t, map[string]any{"v": tsMs})),
|
||||
`{"v":`, "", 1),
|
||||
"}"), "")).String() + `,"type":1,"id":"f1"}]}`
|
||||
// Build a cleaner JSON payload
|
||||
raw = buildFeedJSON(t, []map[string]any{
|
||||
raw := buildFeedJSON(t, []map[string]any{
|
||||
{"time": tsMs, "type": float64(1), "id": "f1"},
|
||||
})
|
||||
|
||||
@@ -128,19 +120,18 @@ func TestCrossPlatformCoverageFormatFeedTimeNormalPath(t *testing.T) {
|
||||
}
|
||||
item := feeds[0].(map[string]any)
|
||||
|
||||
// timeMs 保留原始毫秒值
|
||||
if ms, ok := item["timeMs"].(float64); !ok || ms != tsMs {
|
||||
t.Fatalf("timeMs = %v, want %v", item["timeMs"], tsMs)
|
||||
// time 保留原始毫秒时间戳不变
|
||||
if ms, ok := item["time"].(float64); !ok || ms != tsMs {
|
||||
t.Fatalf("time = %v (%T), want original ms %v", item["time"], item["time"], tsMs)
|
||||
}
|
||||
|
||||
// time 被格式化为北京时间字符串
|
||||
timeStr, ok := item["time"].(string)
|
||||
// timeFormatted 被格式化为北京时间字符串(硬编码期望值)
|
||||
timeStr, ok := item["timeFormatted"].(string)
|
||||
if !ok {
|
||||
t.Fatalf("time = %T, want string", item["time"])
|
||||
t.Fatalf("timeFormatted = %T, want string", item["timeFormatted"])
|
||||
}
|
||||
expected := time.UnixMilli(int64(tsMs)).In(beijingLoc).Format("2006-01-02 15:04")
|
||||
if timeStr != expected {
|
||||
t.Fatalf("time = %q, want %q", timeStr, expected)
|
||||
if timeStr != "2025-06-16 17:50" {
|
||||
t.Fatalf("timeFormatted = %q, want %q", timeStr, "2025-06-16 17:50")
|
||||
}
|
||||
|
||||
// typeLabel 被填充
|
||||
@@ -166,124 +157,108 @@ func TestCrossPlatformCoverageFormatFeedTimeMultipleFeeds(t *testing.T) {
|
||||
// 前两个有时间戳
|
||||
for i := 0; i < 2; i++ {
|
||||
item := feeds[i].(map[string]any)
|
||||
if _, ok := item["timeMs"].(float64); !ok {
|
||||
t.Fatalf("feed[%d] missing timeMs", i)
|
||||
if _, ok := item["time"].(float64); !ok {
|
||||
t.Fatalf("feed[%d] time should remain float64, got %T", i, item["time"])
|
||||
}
|
||||
if _, ok := item["time"].(string); !ok {
|
||||
t.Fatalf("feed[%d] time not string", i)
|
||||
if _, ok := item["timeFormatted"].(string); !ok {
|
||||
t.Fatalf("feed[%d] timeFormatted not string", i)
|
||||
}
|
||||
}
|
||||
|
||||
// 第三个没有时间戳
|
||||
item3 := feeds[2].(map[string]any)
|
||||
if _, hasTimeMs := item3["timeMs"]; hasTimeMs {
|
||||
t.Fatalf("feed[2] should not have timeMs")
|
||||
if _, hasTimeFormatted := item3["timeFormatted"]; hasTimeFormatted {
|
||||
t.Fatalf("feed[2] should not have timeFormatted")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- trimFeedFields unit tests ----------
|
||||
// ---------- enrichFeedFields unit tests ----------
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsRemovesParentDocAndUserInfo(t *testing.T) {
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsPreservesAllFields(t *testing.T) {
|
||||
// enrichFeedFields 不删除任何字段,仅新增 typeLabel
|
||||
item := map[string]any{
|
||||
"parentDoc": map[string]any{"name": "parent"},
|
||||
"userInfo": map[string]any{"nick": "user1"},
|
||||
"id": "f1",
|
||||
"type": float64(1),
|
||||
}
|
||||
trimFeedFields(item)
|
||||
if _, ok := item["parentDoc"]; ok {
|
||||
t.Fatal("parentDoc should be removed")
|
||||
enrichFeedFields(item)
|
||||
if _, ok := item["parentDoc"]; !ok {
|
||||
t.Fatal("parentDoc should be preserved")
|
||||
}
|
||||
if _, ok := item["userInfo"]; ok {
|
||||
t.Fatal("userInfo should be removed")
|
||||
if _, ok := item["userInfo"]; !ok {
|
||||
t.Fatal("userInfo should be preserved")
|
||||
}
|
||||
if item["id"] != "f1" {
|
||||
t.Fatal("id should be preserved")
|
||||
}
|
||||
if item["typeLabel"] != "更新文档" {
|
||||
t.Fatalf("typeLabel = %v, want 更新文档", item["typeLabel"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsTypeLabelKnown(t *testing.T) {
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsTypeLabelKnown(t *testing.T) {
|
||||
// 已知 type → 添加 typeLabel
|
||||
for typeNum, expectedLabel := range feedTypeLabels {
|
||||
item := map[string]any{"type": float64(typeNum)}
|
||||
trimFeedFields(item)
|
||||
enrichFeedFields(item)
|
||||
if item["typeLabel"] != expectedLabel {
|
||||
t.Fatalf("type %d: typeLabel = %v, want %q", typeNum, item["typeLabel"], expectedLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsTypeLabelUnknown(t *testing.T) {
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsTypeLabelUnknown(t *testing.T) {
|
||||
// 未知 type → 不添加 typeLabel
|
||||
item := map[string]any{"type": float64(999)}
|
||||
trimFeedFields(item)
|
||||
enrichFeedFields(item)
|
||||
if _, ok := item["typeLabel"]; ok {
|
||||
t.Fatal("typeLabel should not be set for unknown type 999")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsTypeNotFloat(t *testing.T) {
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsTypeNotFloat(t *testing.T) {
|
||||
// type 不是 float64 → 不添加 typeLabel
|
||||
item := map[string]any{"type": "string-type"}
|
||||
trimFeedFields(item)
|
||||
enrichFeedFields(item)
|
||||
if _, ok := item["typeLabel"]; ok {
|
||||
t.Fatal("typeLabel should not be set for non-float type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsUsersTrim(t *testing.T) {
|
||||
// users 数组中的 user 对象只保留 nick
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsUsersPreserved(t *testing.T) {
|
||||
// users 数组中的 user 对象所有字段保留不变
|
||||
item := map[string]any{
|
||||
"users": []any{
|
||||
map[string]any{"nick": "Alice", "avatarUrl": "http://img", "userId": "u1"},
|
||||
map[string]any{"nick": "Bob", "email": "bob@test"},
|
||||
},
|
||||
}
|
||||
trimFeedFields(item)
|
||||
enrichFeedFields(item)
|
||||
users := item["users"].([]any)
|
||||
for i, u := range users {
|
||||
user := u.(map[string]any)
|
||||
if _, ok := user["nick"]; !ok {
|
||||
t.Fatalf("users[%d] should have nick", i)
|
||||
}
|
||||
for k := range user {
|
||||
if k != "nick" {
|
||||
t.Fatalf("users[%d] unexpected field %q", i, k)
|
||||
}
|
||||
}
|
||||
u0 := users[0].(map[string]any)
|
||||
if u0["avatarUrl"] != "http://img" {
|
||||
t.Fatalf("users[0].avatarUrl should be preserved, got %v", u0["avatarUrl"])
|
||||
}
|
||||
if users[0].(map[string]any)["nick"] != "Alice" {
|
||||
t.Fatalf("users[0].nick = %v, want Alice", users[0].(map[string]any)["nick"])
|
||||
if u0["userId"] != "u1" {
|
||||
t.Fatalf("users[0].userId should be preserved, got %v", u0["userId"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsUsersNilNick(t *testing.T) {
|
||||
// users 中 nick 为 nil → 删除后不回填
|
||||
item := map[string]any{
|
||||
"users": []any{
|
||||
map[string]any{"userId": "u1"},
|
||||
},
|
||||
}
|
||||
trimFeedFields(item)
|
||||
user := item["users"].([]any)[0].(map[string]any)
|
||||
if len(user) != 0 {
|
||||
t.Fatalf("user should be empty after trimming nil nick, got %v", user)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsUsersNonMapItem(t *testing.T) {
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsUsersNonMapItem(t *testing.T) {
|
||||
// users 数组中有非 map 元素 → 不 panic
|
||||
item := map[string]any{
|
||||
"users": []any{"not-a-map", 42, nil},
|
||||
}
|
||||
trimFeedFields(item) // 不应 panic
|
||||
enrichFeedFields(item) // 不应 panic
|
||||
users := item["users"].([]any)
|
||||
if len(users) != 3 {
|
||||
t.Fatalf("users length changed: %d", len(users))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsContentDocTrim(t *testing.T) {
|
||||
// content.doc 只保留 name 和 extension
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsContentPreserved(t *testing.T) {
|
||||
// content 和 content.doc 所有字段保留不变
|
||||
item := map[string]any{
|
||||
"content": map[string]any{
|
||||
"doc": map[string]any{
|
||||
@@ -296,78 +271,42 @@ func TestCrossPlatformCoverageTrimFeedFieldsContentDocTrim(t *testing.T) {
|
||||
"workspaceKey": "ws1",
|
||||
},
|
||||
}
|
||||
trimFeedFields(item)
|
||||
enrichFeedFields(item)
|
||||
content := item["content"].(map[string]any)
|
||||
// content 中只保留 doc
|
||||
for k := range content {
|
||||
if k != "doc" {
|
||||
t.Fatalf("content should only have doc, found %q", k)
|
||||
}
|
||||
if content["dentryKey"] != "entry1" {
|
||||
t.Fatalf("content.dentryKey = %v, want entry1", content["dentryKey"])
|
||||
}
|
||||
if content["workspaceKey"] != "ws1" {
|
||||
t.Fatalf("content.workspaceKey = %v, want ws1", content["workspaceKey"])
|
||||
}
|
||||
doc := content["doc"].(map[string]any)
|
||||
if doc["name"] != "测试文档" {
|
||||
t.Fatalf("doc.name = %v, want 测试文档", doc["name"])
|
||||
}
|
||||
if doc["extension"] != "adoc" {
|
||||
t.Fatalf("doc.extension = %v, want adoc", doc["extension"])
|
||||
}
|
||||
for k := range doc {
|
||||
if k != "name" && k != "extension" {
|
||||
t.Fatalf("doc unexpected field %q", k)
|
||||
}
|
||||
if doc["docKey"] != "dk123" {
|
||||
t.Fatalf("doc.docKey = %v, want dk123", doc["docKey"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsContentDocNilFields(t *testing.T) {
|
||||
// content.doc 中 name 和 extension 缺失 → 不回填
|
||||
item := map[string]any{
|
||||
"content": map[string]any{
|
||||
"doc": map[string]any{
|
||||
"docKey": "dk123",
|
||||
},
|
||||
},
|
||||
}
|
||||
trimFeedFields(item)
|
||||
doc := item["content"].(map[string]any)["doc"].(map[string]any)
|
||||
if len(doc) != 0 {
|
||||
t.Fatalf("doc should be empty, got %v", doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsContentNoDoc(t *testing.T) {
|
||||
// content 存在但没有 doc 子字段 → 移除其他字段
|
||||
item := map[string]any{
|
||||
"content": map[string]any{
|
||||
"dentryKey": "entry1",
|
||||
"workspaceKey": "ws1",
|
||||
},
|
||||
}
|
||||
trimFeedFields(item)
|
||||
content := item["content"].(map[string]any)
|
||||
if len(content) != 0 {
|
||||
t.Fatalf("content should be empty, got %v", content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsNoContentNoUsers(t *testing.T) {
|
||||
// 没有 content / users / type → 仅删除 parentDoc / userInfo
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsNoContentNoUsers(t *testing.T) {
|
||||
// 没有 content / users / type → 所有字段保留
|
||||
item := map[string]any{
|
||||
"id": "f1",
|
||||
"parentDoc": map[string]any{"x": 1},
|
||||
}
|
||||
trimFeedFields(item)
|
||||
if _, ok := item["parentDoc"]; ok {
|
||||
t.Fatal("parentDoc should be removed")
|
||||
enrichFeedFields(item)
|
||||
if _, ok := item["parentDoc"]; !ok {
|
||||
t.Fatal("parentDoc should be preserved")
|
||||
}
|
||||
if item["id"] != "f1" {
|
||||
t.Fatal("id should be preserved")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrossPlatformCoverageTrimFeedFieldsEmptyItem(t *testing.T) {
|
||||
func TestCrossPlatformCoverageEnrichFeedFieldsEmptyItem(t *testing.T) {
|
||||
// 空 map → 不 panic
|
||||
item := map[string]any{}
|
||||
trimFeedFields(item)
|
||||
enrichFeedFields(item)
|
||||
if len(item) != 0 {
|
||||
t.Fatalf("empty item changed: %v", item)
|
||||
}
|
||||
@@ -453,38 +392,49 @@ func TestCrossPlatformCoverageWikiFeedListFormatIntegration(t *testing.T) {
|
||||
t.Fatalf("feeds length unexpected: %v", parsed["feeds"])
|
||||
}
|
||||
|
||||
// 第一个 feed 验证 timeMs 保留、time 格式化、字段裁剪
|
||||
// 第一个 feed 验证 time 保留、timeFormatted 格式化、所有原始字段保留
|
||||
f0 := feeds[0].(map[string]any)
|
||||
if f0["timeMs"] != ts {
|
||||
t.Fatalf("timeMs = %v, want %v", f0["timeMs"], ts)
|
||||
// time 保留原始毫秒时间戳
|
||||
if f0["time"] != ts {
|
||||
t.Fatalf("time = %v, want %v", f0["time"], ts)
|
||||
}
|
||||
if _, ok := f0["time"].(string); !ok {
|
||||
t.Fatalf("time should be string, got %T", f0["time"])
|
||||
// timeFormatted 被填充
|
||||
if _, ok := f0["timeFormatted"].(string); !ok {
|
||||
t.Fatalf("timeFormatted should be string, got %T", f0["timeFormatted"])
|
||||
}
|
||||
if _, ok := f0["parentDoc"]; ok {
|
||||
t.Fatal("parentDoc should be trimmed")
|
||||
// 所有原始字段保留(不删除任何字段)
|
||||
if _, ok := f0["parentDoc"]; !ok {
|
||||
t.Fatal("parentDoc should be preserved")
|
||||
}
|
||||
if _, ok := f0["userInfo"]; ok {
|
||||
t.Fatal("userInfo should be trimmed")
|
||||
if _, ok := f0["userInfo"]; !ok {
|
||||
t.Fatal("userInfo should be preserved")
|
||||
}
|
||||
if f0["typeLabel"] != "创建文档" {
|
||||
t.Fatalf("typeLabel = %v, want 创建文档", f0["typeLabel"])
|
||||
}
|
||||
|
||||
// users 裁剪验证
|
||||
// users 保留验证:avatarUrl / userId 均保留
|
||||
if users, ok := f0["users"].([]any); ok {
|
||||
for _, u := range users {
|
||||
um := u.(map[string]any)
|
||||
if _, ok := um["avatarUrl"]; ok {
|
||||
t.Fatal("user avatarUrl should be trimmed")
|
||||
}
|
||||
u0 := users[0].(map[string]any)
|
||||
if u0["avatarUrl"] != "http://avatar" {
|
||||
t.Fatalf("users[0].avatarUrl should be preserved, got %v", u0["avatarUrl"])
|
||||
}
|
||||
if u0["userId"] != "u1" {
|
||||
t.Fatalf("users[0].userId should be preserved, got %v", u0["userId"])
|
||||
}
|
||||
}
|
||||
|
||||
// content 裁剪验证
|
||||
// content 结构保留验证
|
||||
if content, ok := f0["content"].(map[string]any); ok {
|
||||
if _, ok := content["dentryKey"]; ok {
|
||||
t.Fatal("content.dentryKey should be trimmed")
|
||||
if content["dentryKey"] != "entry1" {
|
||||
t.Fatalf("content.dentryKey should be preserved, got %v", content["dentryKey"])
|
||||
}
|
||||
if content["workspaceKey"] != "ws1" {
|
||||
t.Fatalf("content.workspaceKey should be preserved, got %v", content["workspaceKey"])
|
||||
}
|
||||
doc := content["doc"].(map[string]any)
|
||||
if doc["docKey"] != "dk123" {
|
||||
t.Fatalf("content.doc.docKey should be preserved, got %v", doc["docKey"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ Flags:
|
||||
--workspace string 知识库 ID 或 URL (必填)
|
||||
--limit int 每页数量 (默认 10,最大 20)。用户未明确要求条数时禁止加此 flag,让服务端走默认 10
|
||||
--cursor string 分页游标 (首页留空)
|
||||
--exclude-file 排除文件相关动态(上传/更新 office 等),仅保留文档操作 (默认 false)
|
||||
--exclude-file 排除普通文件、媒体文件、文件夹及 Office 文件动态,仅保留在线文档操作 (默认 false)
|
||||
```
|
||||
|
||||
查询指定知识库的动态,返回谁在什么时间进行了更新、上传、评论等操作。
|
||||
@@ -225,7 +225,7 @@ Flags:
|
||||
|
||||
> **重要 — 展示规则(必须严格遵守)**:
|
||||
> 1. **typeLabel 字段**:CLI 已自动将 `type` 数字映射为 `typeLabel` 中文标签(如 `更新文档`、`创建文档`),**直接使用 `typeLabel` 展示即可**,无需自行查表映射。
|
||||
> 2. **time 字段**:已是北京时间字符串(格式如 `2026-07-30 08:00`),直接展示即可,无需任何转换。原始毫秒时间戳保存在 `timeMs` 字段中备用。
|
||||
> 2. **timeFormatted 字段**:已是北京时间字符串(格式如 `2026-07-30 08:00`),直接展示即可,无需任何转换。原始毫秒时间戳保存在 `time` 字段中(数字类型)。
|
||||
|
||||
### 列出知识库节点
|
||||
```
|
||||
|
||||
@@ -186,7 +186,7 @@ Flags:
|
||||
--workspace string 知识库 ID 或 URL (必填)
|
||||
--limit int 每页数量 (默认 10,最大 20)。用户未明确要求条数时禁止加此 flag,让服务端走默认 10
|
||||
--cursor string 分页游标 (首页留空)
|
||||
--exclude-file 排除文件相关动态(上传/更新 office 等),仅保留文档操作 (默认 false)
|
||||
--exclude-file 排除普通文件、媒体文件、文件夹及 Office 文件动态,仅保留在线文档操作 (默认 false)
|
||||
```
|
||||
|
||||
查询指定知识库的动态,返回谁在什么时间进行了更新、上传、评论等操作。
|
||||
@@ -215,7 +215,7 @@ Flags:
|
||||
|
||||
> **重要 — 展示规则(必须严格遵守)**:
|
||||
> 1. **typeLabel 字段**:CLI 已自动将 `type` 数字映射为 `typeLabel` 中文标签(如 `更新文档`、`创建文档`),**直接使用 `typeLabel` 展示即可**,无需自行查表映射。
|
||||
> 2. **time 字段**:已是北京时间字符串(格式如 `2026-07-30 08:00`),直接展示即可,无需任何转换。原始毫秒时间戳保存在 `timeMs` 字段中备用。
|
||||
> 2. **timeFormatted 字段**:已是北京时间字符串(格式如 `2026-07-30 08:00`),直接展示即可,无需任何转换。原始毫秒时间戳保存在 `time` 字段中(数字类型)。
|
||||
|
||||
### 列出知识库节点
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user