mirror of
https://github.com/larksuite/cli.git
synced 2026-07-04 23:15:25 +08:00
## 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
137 lines
3.9 KiB
Go
137 lines
3.9 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package doc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/larksuite/cli/shortcuts/common"
|
|
)
|
|
|
|
// v1FetchFlags returns the flag definitions for the v1 (MCP) fetch path.
|
|
func v1FetchFlags() []common.Flag {
|
|
return []common.Flag{
|
|
{Name: "offset", Desc: "pagination offset", Hidden: true},
|
|
{Name: "limit", Desc: "pagination limit", Hidden: true},
|
|
}
|
|
}
|
|
|
|
var docsFetchFlagVersions = buildFlagVersionMap(v1FetchFlags(), v2FetchFlags())
|
|
|
|
// useV2Fetch returns true when the v2 (OpenAPI) fetch path should be used.
|
|
// Explicit --api-version v2 takes priority; otherwise auto-detect by the
|
|
// presence of any v2-only flag on the command line — we check pflag.Changed
|
|
// rather than the value so that explicitly typing `--detail simple` (equal
|
|
// to the default) still routes to v2.
|
|
func useV2Fetch(runtime *common.RuntimeContext) bool {
|
|
if runtime.Str("api-version") == "v2" {
|
|
return true
|
|
}
|
|
for _, name := range []string{"detail", "doc-format", "scope", "revision-id", "start-block-id", "end-block-id", "keyword", "context-before", "context-after", "max-depth"} {
|
|
if runtime.Changed(name) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
var DocsFetch = common.Shortcut{
|
|
Service: "docs",
|
|
Command: "+fetch",
|
|
Description: "Fetch Lark document content",
|
|
Risk: "read",
|
|
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"}},
|
|
{Name: "doc", Desc: "document URL or token", Required: true},
|
|
},
|
|
v1FetchFlags(),
|
|
v2FetchFlags(),
|
|
),
|
|
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
|
|
if useV2Fetch(runtime) {
|
|
return validateFetchV2(ctx, runtime)
|
|
}
|
|
return nil
|
|
},
|
|
DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
|
|
if useV2Fetch(runtime) {
|
|
return dryRunFetchV2(ctx, runtime)
|
|
}
|
|
return dryRunFetchV1(ctx, runtime)
|
|
},
|
|
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
|
|
if useV2Fetch(runtime) {
|
|
return executeFetchV2(ctx, runtime)
|
|
}
|
|
return executeFetchV1(ctx, runtime)
|
|
},
|
|
PostMount: func(cmd *cobra.Command) {
|
|
installVersionedHelp(cmd, "v1", docsFetchFlagVersions)
|
|
},
|
|
}
|
|
|
|
// ── V1 (MCP) implementation ──
|
|
|
|
func dryRunFetchV1(_ context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
|
|
args := buildFetchArgsV1(runtime)
|
|
return common.NewDryRunAPI().
|
|
POST(common.MCPEndpoint(runtime.Config.Brand)).
|
|
Desc("MCP tool: fetch-doc").
|
|
Body(map[string]interface{}{"method": "tools/call", "params": map[string]interface{}{"name": "fetch-doc", "arguments": args}}).
|
|
Set("mcp_tool", "fetch-doc").Set("args", args)
|
|
}
|
|
|
|
func executeFetchV1(_ context.Context, runtime *common.RuntimeContext) error {
|
|
warnDeprecatedV1(runtime, "+fetch")
|
|
args := buildFetchArgsV1(runtime)
|
|
|
|
result, err := common.CallMCPTool(runtime, "fetch-doc", args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if md, ok := result["markdown"].(string); ok {
|
|
result["markdown"] = fixExportedMarkdown(md)
|
|
}
|
|
|
|
runtime.OutFormat(result, nil, func(w io.Writer) {
|
|
if title, ok := result["title"].(string); ok && title != "" {
|
|
fmt.Fprintf(w, "# %s\n\n", title)
|
|
}
|
|
if md, ok := result["markdown"].(string); ok {
|
|
fmt.Fprintln(w, md)
|
|
}
|
|
if hasMore, ok := result["has_more"].(bool); ok && hasMore {
|
|
fmt.Fprintln(w, "\n--- more content available, use --offset and --limit to paginate ---")
|
|
}
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func buildFetchArgsV1(runtime *common.RuntimeContext) map[string]interface{} {
|
|
args := map[string]interface{}{
|
|
"doc_id": runtime.Str("doc"),
|
|
"skip_task_detail": true,
|
|
}
|
|
if v := runtime.Str("offset"); v != "" {
|
|
n, _ := strconv.Atoi(v)
|
|
args["offset"] = n
|
|
}
|
|
if v := runtime.Str("limit"); v != "" {
|
|
n, _ := strconv.Atoi(v)
|
|
args["limit"] = n
|
|
}
|
|
return args
|
|
}
|