whiteboard

package
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var WhiteboardUpdate = common.Shortcut{
	Service:     "docs",
	Command:     "+whiteboard-update",
	Description: "Update an existing whiteboard in lark document with whiteboard dsl. Such DSL input from stdin. refer to lark-whiteboard skill for more details.",
	Risk:        "high-risk-write",
	Scopes:      []string{"board:whiteboard:node:read", "board:whiteboard:node:create", "board:whiteboard:node:delete"},
	AuthTypes:   []string{"user", "bot"},
	Flags: []common.Flag{
		{Name: "idempotent-token", Desc: "idempotent token to ensure the update is idempotent. Default is empty. min length is 10.", Required: false},
		{Name: "whiteboard-token", Desc: "whiteboard token of the whiteboard to update. You will need edit permission to update the whiteboard.", Required: true},
		{Name: "overwrite", Desc: "overwrite the whiteboard content, delete all existing content before update. Default is false.", Required: false, Type: "bool"},
	},
	HasFormat: false,
	Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {

		if err := validate.RejectControlChars(runtime.Str("whiteboard-token"), "whiteboard-token"); err != nil {
			return err
		}
		itoken := runtime.Str("idempotent-token")
		if err := validate.RejectControlChars(itoken, "idempotent-token"); err != nil {
			return err
		}
		if itoken != "" && len(itoken) < 10 {
			return common.FlagErrorf("--idempotent-token must be at least 10 characters long.")
		}
		stat, err := os.Stdin.Stat()
		if err != nil || (stat.Mode()&os.ModeCharDevice) != 0 {
			return output.ErrValidation("read stdin failed, please follow lark-whiteboard skill to pipe in input data")
		}
		return nil
	},
	DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {

		input, err := io.ReadAll(os.Stdin)
		if err != nil {
			return common.NewDryRunAPI().Desc("read stdin failed: " + err.Error())
		}
		var wbOutput WbCliOutput
		if err := json.Unmarshal(input, &wbOutput); err != nil {
			return common.NewDryRunAPI().Desc("unmarshal stdin json failed: " + err.Error())
		}
		if wbOutput.Code != 0 || wbOutput.Data.To != "openapi" {
			return common.NewDryRunAPI().Desc("whiteboard-draw failed. please check previous log.")
		}
		token := runtime.Str("whiteboard-token")
		overwrite := runtime.Bool("overwrite")
		descStr := "will call whiteboard open api to draw such DSL content."
		var delNum int
		if overwrite {

			delNum, _, err = clearWhiteboardContent(ctx, runtime, token, []string{}, true)
			if err != nil {
				return common.NewDryRunAPI().Desc("read whiteboard nodes failed: " + err.Error())
			}
			if delNum > 0 {
				descStr += fmt.Sprintf("%d existing nodes deleted before update.", delNum)
			}
		}
		desc := common.NewDryRunAPI().Desc(descStr)
		desc.POST(fmt.Sprintf("/open-apis/board/v1/whiteboards/%s/nodes", common.MaskToken(url.PathEscape(token)))).Body(wbOutput.Data.Result).Desc("create all nodes of the whiteboard.")
		if overwrite && delNum > 0 {

			desc.GET(fmt.Sprintf("/open-apis/board/v1/whiteboards/%s/nodes", common.MaskToken(url.PathEscape(token)))).Desc("get all nodes of the whiteboard to delete, then filter out newly created ones.")
			desc.DELETE(fmt.Sprintf("/open-apis/board/v1/whiteboards/%s/nodes/batch_delete", common.MaskToken(url.PathEscape(token)))).Body("{\"ids\":[\"...\"]}").
				Desc(fmt.Sprintf("delete all old nodes of the whiteboard 100 nodes at a time. This API may be called multiple times and is not reversible. %d whiteboard nodes will be deleted while update.", delNum))
		}
		return desc
	},
	Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {

		token := runtime.Str("whiteboard-token")
		overwrite := runtime.Bool("overwrite")
		idempotentToken := runtime.Str("idempotent-token")

		input, err := io.ReadAll(os.Stdin)
		if err != nil {
			return output.ErrValidation("read stdin failed: " + err.Error())
		}
		var wbOutput WbCliOutput
		if err := json.Unmarshal(input, &wbOutput); err != nil {
			return output.Errorf(output.ExitInternal, "parsing", fmt.Sprintf("unmarshal stdin json failed: %v", err))
		}
		if wbOutput.Code != 0 || wbOutput.Data.To != "openapi" {
			return output.Errorf(output.ExitValidation, "whiteboard-cli", "whiteboard-draw failed. please check previous log.")
		}
		outData := make(map[string]string)

		req := &larkcore.ApiReq{
			HttpMethod:  http.MethodPost,
			ApiPath:     fmt.Sprintf("/open-apis/board/v1/whiteboards/%s/nodes", url.PathEscape(token)),
			Body:        wbOutput.Data.Result,
			QueryParams: map[string][]string{},
		}
		if idempotentToken != "" {
			req.QueryParams["client_token"] = []string{idempotentToken}
		}
		resp, err := runtime.DoAPI(req)
		if err != nil {
			return output.ErrNetwork(fmt.Sprintf("update whiteboard failed: %v", err))
		}
		if resp.StatusCode != http.StatusOK {
			return output.ErrAPI(resp.StatusCode, string(resp.RawBody), nil)
		}
		var createResp createResponse
		err = json.Unmarshal(resp.RawBody, &createResp)
		if err != nil {
			return output.Errorf(output.ExitInternal, "parsing", fmt.Sprintf("parse whiteboard create response failed: %v", err))
		}
		if createResp.Code != 0 {
			return output.ErrAPI(createResp.Code, "update whiteboard failed", fmt.Sprintf("update whiteboard failed: %s", createResp.Msg))
		}
		outData["created_node_ids"] = strings.Join(createResp.Data.NodeIDs, ",")

		if overwrite {
			numNodes, _, err := clearWhiteboardContent(ctx, runtime, token, createResp.Data.NodeIDs, false)
			if err != nil {
				return err
			}
			outData["deleted_nodes_num"] = fmt.Sprintf("%d", numNodes)
		}
		runtime.OutFormat(outData, nil, func(w io.Writer) {
			if outData["deleted_nodes_num"] != "" {
				fmt.Fprintf(w, "%s existing nodes deleted.\n", outData["deleted_nodes_num"])
			}
			if outData["created_node_ids"] != "" {
				fmt.Fprintf(w, "%d new nodes created.\n", len(createResp.Data.NodeIDs))
			}
			fmt.Fprintf(w, "update whiteboard success")
		})
		return nil
	},
}

Functions

func Shortcuts

func Shortcuts() []common.Shortcut

Shortcuts returns all whiteboard shortcuts.

Types

type WbCliOutput

type WbCliOutput struct {
	Code int `json:"code"`
	Data WbCliOutputData
}

type WbCliOutputData

type WbCliOutputData struct {
	To     string      `json:"to"`
	Result interface{} `json:"result"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL