mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
feat(sheets): add +recover shortcut (方案B, full-document revision rollback)
Splits 方案B (recover) into its own MR, shipping ahead of 方案A (undo). +recover rolls the whole spreadsheet back to a past revision via the facade recover_to_revision write tool; only the recover shortcut and its flag live here. undo (方案A) and the read/write transaction_id split stay in PR #1321.
This commit is contained in:
@@ -1,4 +1,37 @@
|
||||
{
|
||||
"+recover": {
|
||||
"risk": "write",
|
||||
"flags": [
|
||||
{
|
||||
"name": "url",
|
||||
"kind": "public",
|
||||
"type": "string",
|
||||
"required": "xor",
|
||||
"desc": "Spreadsheet URL (XOR with `--spreadsheet-token`)"
|
||||
},
|
||||
{
|
||||
"name": "spreadsheet-token",
|
||||
"kind": "public",
|
||||
"type": "string",
|
||||
"required": "xor",
|
||||
"desc": "Spreadsheet token (XOR with `--url`)"
|
||||
},
|
||||
{
|
||||
"name": "to-revision",
|
||||
"kind": "own",
|
||||
"type": "int",
|
||||
"required": "required",
|
||||
"desc": "Restore the whole spreadsheet to this revision (a revision number returned by a prior write)"
|
||||
},
|
||||
{
|
||||
"name": "dry-run",
|
||||
"kind": "system",
|
||||
"type": "bool",
|
||||
"required": "optional",
|
||||
"desc": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"+workbook-info": {
|
||||
"risk": "read",
|
||||
"flags": [
|
||||
@@ -54,7 +87,7 @@
|
||||
"kind": "own",
|
||||
"type": "int",
|
||||
"required": "optional",
|
||||
"desc": "Insert position (0-based); appended to the end when omitted",
|
||||
"desc": "Insert position; appended to the end when omitted",
|
||||
"default": "-1"
|
||||
},
|
||||
{
|
||||
@@ -2020,7 +2053,7 @@
|
||||
"kind": "own",
|
||||
"type": "string",
|
||||
"required": "required",
|
||||
"desc": "RFC 4180 CSV text; values or formulas (a leading = is evaluated as a formula); no styles / comments / images (use +cells-set for those).",
|
||||
"desc": "RFC 4180 CSV text; plain values only (no formulas / styles / comments)",
|
||||
"input": [
|
||||
"file",
|
||||
"stdin"
|
||||
|
||||
@@ -319,7 +319,7 @@ var flagDefs = map[string]commandDef{
|
||||
{Name: "sheet-id", Kind: "public", Type: "string", Required: "xor", Desc: "Sheet reference_id (XOR with `--sheet-name`)"},
|
||||
{Name: "sheet-name", Kind: "public", Type: "string", Required: "xor", Desc: "Sheet name (XOR with `--sheet-id`)"},
|
||||
{Name: "start-cell", Kind: "own", Type: "string", Required: "required", Desc: "Top-left A1 anchor (e.g. `A1`, `B5`; no sheet prefix — use `--sheet-id` / `--sheet-name` to select the sheet); must be a single cell, range notation not accepted; the bottom-right is inferred from CSV row/column counts", Default: "A1"},
|
||||
{Name: "csv", Kind: "own", Type: "string", Required: "required", Desc: "RFC 4180 CSV text; values or formulas (a leading = is evaluated as a formula); no styles / comments / images (use +cells-set for those).", Input: []string{"file", "stdin"}},
|
||||
{Name: "csv", Kind: "own", Type: "string", Required: "required", Desc: "RFC 4180 CSV text; plain values only (no formulas / styles / comments)", Input: []string{"file", "stdin"}},
|
||||
{Name: "allow-overwrite", Kind: "own", Type: "bool", Required: "optional", Desc: "Allow overwriting (default true); set false to error if any target cell is non-empty", Default: "true"},
|
||||
{Name: "range", Kind: "own", Type: "string", Required: "optional", Desc: "alias for --start-cell (parity with +csv-get / +cells-set, which locate with --range); a range like A1:H17 collapses to its top-left cell", Hidden: true},
|
||||
{Name: "dry-run", Kind: "system", Type: "bool", Required: "optional"},
|
||||
@@ -734,6 +734,15 @@ var flagDefs = map[string]commandDef{
|
||||
{Name: "dry-run", Kind: "system", Type: "bool", Required: "optional"},
|
||||
},
|
||||
},
|
||||
"+recover": {
|
||||
Risk: "write",
|
||||
Flags: []flagDef{
|
||||
{Name: "url", Kind: "public", Type: "string", Required: "xor", Desc: "Spreadsheet URL (XOR with `--spreadsheet-token`)"},
|
||||
{Name: "spreadsheet-token", Kind: "public", Type: "string", Required: "xor", Desc: "Spreadsheet token (XOR with `--url`)"},
|
||||
{Name: "to-revision", Kind: "own", Type: "int", Required: "required", Desc: "Restore the whole spreadsheet to this revision (a revision number returned by a prior write)"},
|
||||
{Name: "dry-run", Kind: "system", Type: "bool", Required: "optional"},
|
||||
},
|
||||
},
|
||||
"+rows-resize": {
|
||||
Risk: "write",
|
||||
Flags: []flagDef{
|
||||
|
||||
85
shortcuts/sheets/lark_sheet_recover.go
Normal file
85
shortcuts/sheets/lark_sheet_recover.go
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package sheets
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/larksuite/cli/shortcuts/common"
|
||||
)
|
||||
|
||||
// ─── lark_sheet_recover ───────────────────────────────────────────────
|
||||
//
|
||||
// Wraps:
|
||||
// - recover_to_revision (write) — powers +recover
|
||||
//
|
||||
// Rolls the WHOLE spreadsheet back to a past revision (the undo design doc's
|
||||
// "方案 B"). Unlike +undo — which is precise, per-edit, and scoped to this CLI
|
||||
// link — +recover is a full-document version restore. The facade gateway
|
||||
// already owns this capability (the same revert-by-revision path the web
|
||||
// "history" panel drives): it submits a single RECOVER changeset that reverts
|
||||
// every sheet to the target revision and produces a new revision. The CLI only
|
||||
// passes the target revision; all the work stays server-side.
|
||||
//
|
||||
// ⚠️ Full-table overwrite: +recover discards EVERY change made after
|
||||
// --to-revision, including other collaborators' (and the web UI's) edits. Use
|
||||
// it only on agent scratch spreadsheets, or when a whole-document rollback is
|
||||
// acceptable. For precise, this-link-only undo, use +undo instead.
|
||||
var Recover = common.Shortcut{
|
||||
Service: "sheets",
|
||||
Command: "+recover",
|
||||
Description: "Roll the whole spreadsheet back to a past revision (full-document restore; discards all later edits).",
|
||||
Risk: "write",
|
||||
Scopes: []string{"sheets:spreadsheet:write_only"},
|
||||
AuthTypes: []string{"user", "bot"},
|
||||
HasFormat: true,
|
||||
Flags: flagsFor("+recover"),
|
||||
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
|
||||
token, err := resolveSpreadsheetToken(runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = recoverInput(runtime, token)
|
||||
return err
|
||||
},
|
||||
DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
|
||||
token, _ := resolveSpreadsheetToken(runtime)
|
||||
input, _ := recoverInput(runtime, token)
|
||||
return invokeToolDryRun(token, ToolKindWrite, "recover_to_revision", input)
|
||||
},
|
||||
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
|
||||
token, err := resolveSpreadsheetToken(runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input, err := recoverInput(runtime, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := callTool(ctx, runtime, token, ToolKindWrite, "recover_to_revision", input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.Out(out, nil)
|
||||
return nil
|
||||
},
|
||||
Tips: []string{
|
||||
"+recover is a FULL-DOCUMENT rollback — it discards every edit made after --to-revision, including other collaborators'. For precise, this-link-only undo, use +undo instead.",
|
||||
"--to-revision takes a revision number returned by a prior write (the `revision` field in the response).",
|
||||
"Use --dry-run to preview the recover request before running it.",
|
||||
},
|
||||
}
|
||||
|
||||
// recoverInput builds the recover_to_revision tool body. Network-free; shared
|
||||
// by Validate, DryRun, and Execute.
|
||||
func recoverInput(runtime flagView, token string) (map[string]interface{}, error) {
|
||||
rev := runtime.Int("to-revision")
|
||||
if rev < 1 {
|
||||
return nil, common.FlagErrorf("--to-revision must be a positive revision number")
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"excel_id": token,
|
||||
"to_revision": rev,
|
||||
}, nil
|
||||
}
|
||||
@@ -61,6 +61,9 @@ func shortcutList() []common.Shortcut {
|
||||
DropdownGet,
|
||||
TableGet,
|
||||
|
||||
// lark_sheet_recover
|
||||
Recover,
|
||||
|
||||
// lark_sheet_search_replace
|
||||
CellsSearch,
|
||||
CellsReplace,
|
||||
|
||||
Reference in New Issue
Block a user