mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
feat: guide lark-doc v2 usage (#710)
## Summary
Add explicit guidance on the parent `docs` command so agents pick the right
lark-doc API version. Without this, agents that have an older lark-doc skill
installed can mistakenly mix v2 flags into a v1 flow.
## Changes
- Add `--api-version` help flag and a Tips section to `docs` so `lark docs --help`
(and `--api-version v2`) explain when v2 should be used.
- Refresh the lark-doc skill references and `docs_fetch_v2` keyword flag
description for clarity.
- Add `shortcuts/register_test.go` covering the new docs help wiring.
## Test Plan
- [x] Unit tests pass (`go test ./shortcuts/...`)
- [x] Manual local verification confirms the `lark docs --help` and
`lark docs --help --api-version v2` commands work as expected
## Related Issues
- None
Change-Id: Id3b3196e6a069bb52f95a6fc679b8258313faf3d
This commit is contained in:
@@ -43,6 +43,7 @@ var DocsCreate = common.Shortcut{
|
||||
Risk: "write",
|
||||
AuthTypes: []string{"user", "bot"},
|
||||
Scopes: []string{"docx:document:create"},
|
||||
Tips: docsVersionSelectionTips,
|
||||
Flags: concatFlags(
|
||||
[]common.Flag{
|
||||
{Name: "api-version", Desc: "API version", Default: "v1", Enum: []string{"v1", "v2"}},
|
||||
|
||||
@@ -49,6 +49,7 @@ var DocsFetch = common.Shortcut{
|
||||
Scopes: []string{"docx:document:readonly"},
|
||||
AuthTypes: []string{"user", "bot"},
|
||||
HasFormat: true,
|
||||
Tips: docsVersionSelectionTips,
|
||||
Flags: concatFlags(
|
||||
[]common.Flag{
|
||||
{Name: "api-version", Desc: "API version", Default: "v1", Enum: []string{"v1", "v2"}},
|
||||
|
||||
@@ -22,7 +22,7 @@ func v2FetchFlags() []common.Flag {
|
||||
{Name: "scope", Desc: "partial read scope: outline | range | keyword | section (omit to read whole doc)", Default: "full", Enum: []string{"full", "outline", "range", "keyword", "section"}},
|
||||
{Name: "start-block-id", Desc: "range/section mode: start (anchor) block id"},
|
||||
{Name: "end-block-id", Desc: "range mode: end block id; \"-1\" = to end of document"},
|
||||
{Name: "keyword", Desc: "keyword mode: search string (case-insensitive); use '|' to match multiple keywords, e.g. 'foo|bar|baz'"},
|
||||
{Name: "keyword", Desc: "keyword mode: substring + regex match (case-insensitive); use '|' for OR branches, e.g. 'foo|bar' or 'bug|缺陷'"},
|
||||
{Name: "context-before", Desc: "range/keyword/section mode: sibling blocks before match", Type: "int", Default: "0"},
|
||||
{Name: "context-after", Desc: "range/keyword/section mode: sibling blocks after match", Type: "int", Default: "0"},
|
||||
{Name: "max-depth", Desc: "outline: heading level cap; range/keyword/section: block subtree depth (-1 = unlimited)", Type: "int", Default: "-1"},
|
||||
|
||||
@@ -64,6 +64,7 @@ var DocsUpdate = common.Shortcut{
|
||||
Risk: "write",
|
||||
Scopes: []string{"docx:document:write_only", "docx:document:readonly"},
|
||||
AuthTypes: []string{"user", "bot"},
|
||||
Tips: docsVersionSelectionTips,
|
||||
Flags: concatFlags(
|
||||
[]common.Flag{
|
||||
{Name: "api-version", Desc: "API version", Default: "v1", Enum: []string{"v1", "v2"}},
|
||||
|
||||
@@ -3,7 +3,24 @@
|
||||
|
||||
package doc
|
||||
|
||||
import "github.com/larksuite/cli/shortcuts/common"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/larksuite/cli/internal/cmdutil"
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
const docsServiceHelpDefault = `Document and content operations.`
|
||||
|
||||
const docsServiceHelpV2 = `Document and content operations (v2).`
|
||||
|
||||
var docsVersionSelectionTips = []string{
|
||||
"Agent version rule: use --api-version v2 only when the installed lark-doc skill explicitly instructs docs +create, docs +fetch, or docs +update to use v2; otherwise use the default v1 flags.",
|
||||
"Do not mix versions: if the skill does not mention v2, follow its legacy v1 examples and flags.",
|
||||
}
|
||||
|
||||
// Shortcuts returns all docs shortcuts.
|
||||
func Shortcuts() []common.Shortcut {
|
||||
@@ -18,3 +35,48 @@ func Shortcuts() []common.Shortcut {
|
||||
DocMediaDownload,
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigureServiceHelp adds docs-specific guidance to the parent `docs` command.
|
||||
// The shortcut-level help remains compatible with legacy v1 skills; this parent
|
||||
// help gives agents enough context to choose v2 only when their installed skill
|
||||
// explicitly asks for `--api-version v2`.
|
||||
func ConfigureServiceHelp(cmd *cobra.Command) {
|
||||
if cmd == nil {
|
||||
return
|
||||
}
|
||||
serviceCmd := cmd
|
||||
cmd.Long = strings.TrimSpace(docsServiceHelpDefault)
|
||||
if cmd.Flags().Lookup("api-version") == nil {
|
||||
cmd.Flags().String("api-version", "", "show docs help for API version (v1|v2)")
|
||||
cmdutil.RegisterFlagCompletion(cmd, "api-version", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"v1", "v2"}, cobra.ShellCompDirectiveNoFileComp
|
||||
})
|
||||
}
|
||||
|
||||
defaultHelp := cmd.HelpFunc()
|
||||
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
||||
if cmd != serviceCmd {
|
||||
defaultHelp(cmd, args)
|
||||
return
|
||||
}
|
||||
|
||||
apiVersion, _ := cmd.Flags().GetString("api-version")
|
||||
previousLong := cmd.Long
|
||||
if apiVersion == "v2" {
|
||||
cmd.Long = strings.TrimSpace(docsServiceHelpV2)
|
||||
} else {
|
||||
cmd.Long = strings.TrimSpace(docsServiceHelpDefault)
|
||||
}
|
||||
defer func() {
|
||||
cmd.Long = previousLong
|
||||
}()
|
||||
|
||||
defaultHelp(cmd, args)
|
||||
out := cmd.OutOrStdout()
|
||||
fmt.Fprintln(out)
|
||||
fmt.Fprintln(out, "Tips:")
|
||||
for _, tip := range docsVersionSelectionTips {
|
||||
fmt.Fprintf(out, " • %s\n", tip)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -30,13 +30,6 @@ func installVersionedHelp(cmd *cobra.Command, defaultVersion string, flagVersion
|
||||
}
|
||||
})
|
||||
origHelp(cmd, args)
|
||||
if ver == "v1" {
|
||||
fmt.Fprintf(cmd.OutOrStdout(),
|
||||
"\n[NOTE] v1 API is deprecated and will be removed in a future release.\n"+
|
||||
" Use --api-version v2 for the latest API:\n"+
|
||||
" %s %s --api-version v2 --help\n",
|
||||
cmd.Parent().Name(), cmd.Name())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,9 @@ func RegisterShortcutsWithContext(ctx context.Context, program *cobra.Command, f
|
||||
}
|
||||
program.AddCommand(svc)
|
||||
}
|
||||
if service == "docs" {
|
||||
doc.ConfigureServiceHelp(svc)
|
||||
}
|
||||
|
||||
for _, shortcut := range shortcuts {
|
||||
shortcut.MountWithContext(ctx, svc, f)
|
||||
|
||||
@@ -4,16 +4,45 @@
|
||||
package shortcuts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/larksuite/cli/internal/cmdutil"
|
||||
"github.com/larksuite/cli/internal/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newRegisterTestFactory(t *testing.T) *cmdutil.Factory {
|
||||
t.Helper()
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
f, _, _, _ := cmdutil.TestFactory(t, &core.CliConfig{})
|
||||
return f
|
||||
}
|
||||
|
||||
func newRegisterTestProgramWithTipsHelp() *cobra.Command {
|
||||
program := &cobra.Command{Use: "root"}
|
||||
defaultHelp := program.HelpFunc()
|
||||
program.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
||||
defaultHelp(cmd, args)
|
||||
tips := cmdutil.GetTips(cmd)
|
||||
if len(tips) == 0 {
|
||||
return
|
||||
}
|
||||
out := cmd.OutOrStdout()
|
||||
fmt.Fprintln(out)
|
||||
fmt.Fprintln(out, "Tips:")
|
||||
for _, tip := range tips {
|
||||
fmt.Fprintf(out, " • %s\n", tip)
|
||||
}
|
||||
})
|
||||
return program
|
||||
}
|
||||
|
||||
func TestAllShortcutsScopesNotNil(t *testing.T) {
|
||||
for _, s := range allShortcuts {
|
||||
hasScopes := s.Scopes != nil || s.UserScopes != nil || s.BotScopes != nil
|
||||
@@ -48,7 +77,7 @@ func TestAllShortcutsReturnsCopyAndIncludesBase(t *testing.T) {
|
||||
|
||||
func TestRegisterShortcutsMountsBaseCommands(t *testing.T) {
|
||||
program := &cobra.Command{Use: "root"}
|
||||
RegisterShortcuts(program, &cmdutil.Factory{})
|
||||
RegisterShortcuts(program, newRegisterTestFactory(t))
|
||||
|
||||
baseCmd, _, err := program.Find([]string{"base"})
|
||||
if err != nil {
|
||||
@@ -69,7 +98,7 @@ func TestRegisterShortcutsMountsBaseCommands(t *testing.T) {
|
||||
|
||||
func TestRegisterShortcutsMountsDocsMediaPreview(t *testing.T) {
|
||||
program := &cobra.Command{Use: "root"}
|
||||
RegisterShortcuts(program, &cmdutil.Factory{})
|
||||
RegisterShortcuts(program, newRegisterTestFactory(t))
|
||||
|
||||
previewCmd, _, err := program.Find([]string{"docs", "+media-preview"})
|
||||
if err != nil {
|
||||
@@ -80,12 +109,182 @@ func TestRegisterShortcutsMountsDocsMediaPreview(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterShortcutsDocsHelpAddsVersionSelectorAndLegacyTips(t *testing.T) {
|
||||
program := &cobra.Command{Use: "root"}
|
||||
RegisterShortcuts(program, newRegisterTestFactory(t))
|
||||
|
||||
docsCmd, _, err := program.Find([]string{"docs"})
|
||||
if err != nil {
|
||||
t.Fatalf("find docs command: %v", err)
|
||||
}
|
||||
if docsCmd == nil || docsCmd.Name() != "docs" {
|
||||
t.Fatalf("docs command not mounted: %#v", docsCmd)
|
||||
}
|
||||
if docsCmd.Flags().Lookup("api-version") == nil {
|
||||
t.Fatal("docs command should expose --api-version for versioned help")
|
||||
}
|
||||
|
||||
if !strings.Contains(docsCmd.Long, "Document and content operations.") {
|
||||
t.Fatalf("docs long help missing default description:\n%s", docsCmd.Long)
|
||||
}
|
||||
|
||||
var defaultHelp bytes.Buffer
|
||||
docsCmd.SetOut(&defaultHelp)
|
||||
if err := docsCmd.Help(); err != nil {
|
||||
t.Fatalf("docs help failed: %v", err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"Tips:",
|
||||
"Agent version rule",
|
||||
"use --api-version v2 only when the installed lark-doc skill explicitly instructs",
|
||||
"otherwise use the default v1 flags",
|
||||
"if the skill does not mention v2",
|
||||
"legacy v1 examples and flags",
|
||||
} {
|
||||
if !strings.Contains(defaultHelp.String(), want) {
|
||||
t.Fatalf("docs default help missing %q:\n%s", want, defaultHelp.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterShortcutsDocsV2HelpUsesV2Description(t *testing.T) {
|
||||
program := &cobra.Command{Use: "root"}
|
||||
RegisterShortcuts(program, newRegisterTestFactory(t))
|
||||
|
||||
docsCmd, _, err := program.Find([]string{"docs"})
|
||||
if err != nil {
|
||||
t.Fatalf("find docs command: %v", err)
|
||||
}
|
||||
if err := docsCmd.Flags().Set("api-version", "v2"); err != nil {
|
||||
t.Fatalf("set docs api-version: %v", err)
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
docsCmd.SetOut(&out)
|
||||
if err := docsCmd.Help(); err != nil {
|
||||
t.Fatalf("docs v2 help failed: %v", err)
|
||||
}
|
||||
|
||||
for _, want := range []string{
|
||||
"Document and content operations (v2).",
|
||||
"Tips:",
|
||||
"Agent version rule",
|
||||
"otherwise use the default v1 flags",
|
||||
"if the skill does not mention v2",
|
||||
"legacy v1 examples and flags",
|
||||
} {
|
||||
if !strings.Contains(out.String(), want) {
|
||||
t.Fatalf("docs v2 help missing %q:\n%s", want, out.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterShortcutsDocsVersionedShortcutHelpAddsVersionTips(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
shortcut string
|
||||
apiVersion string
|
||||
shortcutHelp string
|
||||
versionedFlag string
|
||||
}{
|
||||
{
|
||||
name: "create v1",
|
||||
shortcut: "+create",
|
||||
apiVersion: "v1",
|
||||
shortcutHelp: "Create a Lark document",
|
||||
versionedFlag: "--markdown",
|
||||
},
|
||||
{
|
||||
name: "create v2",
|
||||
shortcut: "+create",
|
||||
apiVersion: "v2",
|
||||
shortcutHelp: "Create a Lark document",
|
||||
versionedFlag: "--content",
|
||||
},
|
||||
{
|
||||
name: "fetch v1",
|
||||
shortcut: "+fetch",
|
||||
apiVersion: "v1",
|
||||
shortcutHelp: "Fetch Lark document content",
|
||||
versionedFlag: "--offset",
|
||||
},
|
||||
{
|
||||
name: "fetch v2",
|
||||
shortcut: "+fetch",
|
||||
apiVersion: "v2",
|
||||
shortcutHelp: "Fetch Lark document content",
|
||||
versionedFlag: "partial read scope",
|
||||
},
|
||||
{
|
||||
name: "update v1",
|
||||
shortcut: "+update",
|
||||
apiVersion: "v1",
|
||||
shortcutHelp: "Update a Lark document",
|
||||
versionedFlag: "--mode",
|
||||
},
|
||||
{
|
||||
name: "update v2",
|
||||
shortcut: "+update",
|
||||
apiVersion: "v2",
|
||||
shortcutHelp: "Update a Lark document",
|
||||
versionedFlag: "--command",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
program := newRegisterTestProgramWithTipsHelp()
|
||||
RegisterShortcuts(program, newRegisterTestFactory(t))
|
||||
|
||||
cmd, _, err := program.Find([]string{"docs", tt.shortcut})
|
||||
if err != nil {
|
||||
t.Fatalf("find docs %s command: %v", tt.shortcut, err)
|
||||
}
|
||||
if cmd == nil || cmd.Name() != tt.shortcut {
|
||||
t.Fatalf("docs %s shortcut not mounted: %#v", tt.shortcut, cmd)
|
||||
}
|
||||
if err := cmd.Flags().Set("api-version", tt.apiVersion); err != nil {
|
||||
t.Fatalf("set docs %s api-version: %v", tt.shortcut, err)
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
cmd.SetOut(&out)
|
||||
if err := cmd.Help(); err != nil {
|
||||
t.Fatalf("docs %s help failed: %v", tt.shortcut, err)
|
||||
}
|
||||
|
||||
for _, want := range []string{
|
||||
tt.shortcutHelp,
|
||||
tt.versionedFlag,
|
||||
"Tips:",
|
||||
"Agent version rule",
|
||||
"use --api-version v2 only when the installed lark-doc skill explicitly instructs",
|
||||
"otherwise use the default v1 flags",
|
||||
"if the skill does not mention v2",
|
||||
"legacy v1 examples and flags",
|
||||
} {
|
||||
if !strings.Contains(out.String(), want) {
|
||||
t.Fatalf("docs %s %s help missing %q:\n%s", tt.shortcut, tt.apiVersion, want, out.String())
|
||||
}
|
||||
}
|
||||
for _, unwanted := range []string{
|
||||
"[NOTE]",
|
||||
"Use --api-version v2 for the latest API",
|
||||
} {
|
||||
if strings.Contains(out.String(), unwanted) {
|
||||
t.Fatalf("docs %s %s help should not include %q:\n%s", tt.shortcut, tt.apiVersion, unwanted, out.String())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterShortcutsReusesExistingServiceCommand(t *testing.T) {
|
||||
program := &cobra.Command{Use: "root"}
|
||||
existingBase := &cobra.Command{Use: "base", Short: "existing base service"}
|
||||
program.AddCommand(existingBase)
|
||||
|
||||
RegisterShortcuts(program, &cmdutil.Factory{})
|
||||
RegisterShortcuts(program, newRegisterTestFactory(t))
|
||||
|
||||
baseCount := 0
|
||||
for _, command := range program.Commands() {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
name: lark-doc
|
||||
version: 2.0.0
|
||||
description: "飞书云文档:创建和编辑飞书文档。默认使用 DocxXML 格式(也支持 Markdown)。创建文档、获取文档内容(支持 simple/with-ids/full 三种导出详细度,以及 full/outline/range/keyword/section 五种局部读取模式,可按目录、block id 区间、关键词或标题自动成节只拉部分内容以节省上下文)、更新文档(八种指令:str_replace/block_insert_after/block_copy_insert_after/block_replace/block_delete/block_move_after/overwrite/append)、上传和下载文档中的图片和文件、搜索云空间文档。当用户需要创建或编辑飞书文档、读取文档内容、在文档中插入图片、搜索云空间文档时使用;如果用户是想按名称或关键词先定位电子表格、报表等云空间对象,也优先使用本 skill 的 docs +search 做资源发现。"
|
||||
description: "飞书云文档(v2):创建和编辑飞书文档。使用本 skill 时,docs +create、docs +fetch、docs +update 必须携带 --api-version v2;默认使用 DocxXML 格式(也支持 Markdown)。创建文档、获取文档内容(支持 simple/with-ids/full 三种导出详细度,以及 full/outline/range/keyword/section 五种局部读取模式,可按目录、block id 区间、关键词或标题自动成节只拉部分内容以节省上下文)、更新文档(八种指令:str_replace/block_insert_after/block_copy_insert_after/block_replace/block_delete/block_move_after/overwrite/append)、上传和下载文档中的图片和文件、搜索云空间文档。当用户需要创建或编辑飞书文档、读取文档内容、在文档中插入图片、搜索云空间文档时使用;如果用户是想按名称或关键词先定位电子表格、报表等云空间对象,也优先使用本 skill 的 docs +search 做资源发现。"
|
||||
metadata:
|
||||
requires:
|
||||
bins: ["lark-cli"]
|
||||
cliHelp: "lark-cli docs --help"
|
||||
cliHelp: "lark-cli docs --api-version v2 --help; lark-cli docs +create --api-version v2 --help; lark-cli docs +fetch --api-version v2 --help; lark-cli docs +update --api-version v2 --help"
|
||||
---
|
||||
|
||||
# docs (v2)
|
||||
|
||||
@@ -74,7 +74,7 @@ lark-cli docs +create --api-version v2 --doc-format markdown --content $'# 项
|
||||
## 最佳实践
|
||||
|
||||
- 文档标题从内容中自动提取(XML `<title>` 或 Markdown `#`),不要在内容开头重复写标题
|
||||
- 创建较长的文档时,先创建基础内容,再用 `docs +update --command block_insert_after` 分段追加
|
||||
- **创建较长的文档时只建骨架**:`--content` 仅传标题 + 各级 heading + 简短占位摘要;正文留给后续 `docs +update --command append` 或 `block_insert_after` 分段追加。一次性塞超长 `--content` 既容易触发参数限制,调试也更难。
|
||||
- **视觉丰富度**:必须遵循 [`lark-doc-style.md`](style/lark-doc-style.md) 中的样式指南,主动使用结构化 block 丰富文档
|
||||
|
||||
## 参考
|
||||
|
||||
@@ -49,21 +49,21 @@ lark-cli docs +fetch --api-version v2 --doc Z1Fj...tnAc \
|
||||
| `outline` | 不知道结构,先看目录 | `--max-depth`(标题层级上限) | 扁平列出所有标题,**包括嵌在容器里的内嵌标题**(如 callout 里的 h3);这些 id 可直接作后续 `section` / `range` 端点 |
|
||||
| `section` | 读某个标题对应的整节 | `--start-block-id`(必填) | 顶层标题 → 展开到下一同级/更高级标题前;容器内节点(含内嵌标题) → 按"最小包容单元"返回容器/表格切片,不做 heading 扩展;顶层非标题块 → 仅该块 |
|
||||
| `range` | 已知精确起止 | `--start-block-id` / `--end-block-id` 至少一个;`-1` = 读到末尾 | 两端同顶层 → 顶层序列切片;两端同一容器 → 容器整体;两端同一表格 → 瘦身切片;**跨顶层 → 端点所在顶层块整块输出,不做瘦身** |
|
||||
| `keyword` | 只有模糊关键词 | `--keyword`(不区分大小写、子串,`\|` 分隔多词 OR) | 每处命中按"最小包容单元"输出;**自动去重**(同容器多命中 → 单个容器,同表格多行命中 → 合并切片) |
|
||||
| `keyword` | 只有模糊关键词 | `--keyword`(**多级自动 fallback**:子串 → 归一化 → 分词形变 → RE2 正则;`\|` 分隔多分支 OR) | 每处命中按"最小包容单元"输出;**自动去重**(同容器多命中 → 单个容器,同表格多行命中 → 合并切片) |
|
||||
|
||||
> 💡 **多关键词用 `\|` 拼接(OR 语义,任一命中即返回)**:例 `"部署\|发布\|上线"`,三词任一命中都进结果,适合**同义词/别名/多业务术语**一次召回(如 `bug\|缺陷\|故障`)。
|
||||
|
||||
**设置 `--scope` 时共用** `--context-before` / `--context-after` / `--max-depth`。
|
||||
|
||||
- `--max-depth`:`outline` = 标题层级上限(3 = h1~h3);其它模式 = 被选块的子树遍历深度(`-1` 不限,`0` 仅块自身)。
|
||||
- `--context-before/--context-after`:**只对整块顶层单元生效**;命中落在容器/表格内(返回容器或切片)时 before/after 被忽略,需要更大范围改用 `section` / `range` 显式指定。
|
||||
|
||||
**决策顺序**(核心原则:**局部获取优于全量获取**,能精确到节/区间就绝不全量拉取;**任何文档的第一次读取都应从 `outline` 开始**):
|
||||
1. **第一次接触文档 / 不知道结构** → 先 `outline` 探测目录(**强制首步,无论文档是"目标"还是"引用源"**),再回到 2/3 精读
|
||||
2. 改/读某个**标题对应的整节** → `section`(最省心,**首选精读方式**)
|
||||
3. 精确自定义起止 / 跨节连续区间 → `range`
|
||||
4. 只有模糊关键词 → `keyword`
|
||||
5. **兜底**:确实需要整篇文档时才不传 `--scope`(默认整篇);**不要为了省事就读整篇**,局部模式上下文更省、响应更快
|
||||
|
||||
**推荐双步流程**:`outline --max-depth 3` 拿目录 → `section --start-block-id <标题id> --detail with-ids` 精读该节。
|
||||
**决策顺序**(核心原则:**局部获取优于全量获取**,根据需求形态选起点,必要时多步组合收敛范围):
|
||||
1. 需求**直接给出待查的具体术语/错误码/标识** → 直接走 `keyword` 粗匹配(多级 fallback 自动覆盖形变),需要更大上下文时用返回的 `top-block-id` 走 `section` / `range`
|
||||
2. 需求**指向某个章节/标题**("修改 XX 章"、"总结第 3 节"、"关于 xx 的内容")→ 先 `outline --max-depth 3` 拿目录 → `section --start-block-id <标题id>` 精读
|
||||
3. 已知**精确起止 / 跨节连续区间** → `range`
|
||||
4. **结构未知且无明确关键词/章节线索** → `outline` 探测,再回到 2/3
|
||||
5. **兜底**:仅在确需整篇时才省略 `--scope`;不要为省事直接读整篇
|
||||
|
||||
## 局部读取的输出结构:`<fragment>` 与 `<excerpt>`
|
||||
|
||||
@@ -108,7 +108,7 @@ lark-cli docs +fetch --api-version v2 --doc Z1Fj...tnAc \
|
||||
| `--scope` | 否 | `outline` \| `range` \| `keyword` \| `section`(省略 = 读整篇) |
|
||||
| `--start-block-id` | 否 | `range`/`section` 起始/锚点 id(`section` 必填) |
|
||||
| `--end-block-id` | 否 | `range` 结束 id;`-1` 表示读到末尾 |
|
||||
| `--keyword` | 否 | `keyword` 模式关键词;`\|` 分隔多词 OR |
|
||||
| `--keyword` | 否 | `keyword` 模式关键词,**4 层自动 fallback**(子串 → 归一化 → 分词形变 → RE2 正则);`\|` 分隔多分支 OR |
|
||||
| `--context-before` | 否 | 命中前拉几个兄弟块(仅对顶层单元生效,默认 `0`) |
|
||||
| `--context-after` | 否 | 命中后拉几个兄弟块(仅对顶层单元生效,默认 `0`) |
|
||||
| `--max-depth` | 否 | `outline` = 标题层级上限;其它 = 子树深度(`-1` 不限,默认) |
|
||||
|
||||
@@ -85,7 +85,7 @@ p, h1-h9, ul, ol, li, table, thead, tbody, tr, th, td, blockquote, pre, code, hr
|
||||
- 合并单元格仅起始格输出 `colspan` / `rowspan`,被合并的格不出现
|
||||
|
||||
# 六、美化系统
|
||||
- 颜色优先使用命名色,也可写 `rgb(r,g,b)` / `rgba(r,g,b,a)`。**基础色(6 色)**:gray, red, orange, yellow, green, blue
|
||||
- 颜色优先使用命名色,也可写 `rgb(r,g,b)` / `rgba(r,g,b,a)`。**基础色(7 色)**:red, orange, yellow, green, blue, purple, gray
|
||||
| 属性 | 支持的命名色 |
|
||||
|-|-|
|
||||
| 文字颜色 `<span text-color>` | 基础色 |
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
1. 分析用户需求:受众、目的、范围
|
||||
2. 设计大纲——每个 h1/h2 章节至少规划 1 个非文本 block
|
||||
3. `docs +create --api-version v2` 创建文档:标题 + 开头 `<callout>` + 骨架(各级标题 + 简短占位摘要)
|
||||
3. `docs +create --api-version v2` **只建骨架**:标题 + 开头 `<callout>` + 各级标题 + 每节一句占位摘要
|
||||
- ⚠️ **不要**一次性把完整章节内容塞进 `--content`。超长 `--content` 容易触发字符/参数限制。
|
||||
- 完整内容留到第二波,由各 Agent 用 `docs +update --command append` 或 `block_insert_after` 分段写入。
|
||||
|
||||
### 第二波 — 内容撰写(并行 Agent)
|
||||
|
||||
@@ -46,5 +48,3 @@
|
||||
## Agent 子任务要求
|
||||
|
||||
Spawn Agent 时必须提供:文档 token、章节范围(标题/block ID)、`lark-doc-xml.md` 和 `lark-doc-style.md` 路径、具体的 `docs +update` command 和 `--block-id`。
|
||||
|
||||
章节较多时,先 `docs +create` 建骨架,再分段 `append` 追加,比一次性超长 `--content` 更可靠。
|
||||
|
||||
Reference in New Issue
Block a user