Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
17a5f29
refactor(sheets): rebuild lark-sheets on sheet-skill-spec canonical +…
xiongyuanwen-byted May 15, 2026
b33a06c
feat(sheets): implement lark_sheet_workbook shortcuts (B1)
xiongyuanwen-byted May 15, 2026
ae728fe
feat(sheets): implement lark_sheet_sheet_structure shortcuts (B2)
xiongyuanwen-byted May 15, 2026
8494534
feat(sheets): implement read_data / search_replace / write_cells shor…
xiongyuanwen-byted May 16, 2026
0d35117
refactor(sheets): move +dropdown-update / +dropdown-delete to lark_sh…
xiongyuanwen-byted May 16, 2026
b3e99de
feat(sheets): implement lark_sheet_range_operations shortcuts (B4)
xiongyuanwen-byted May 16, 2026
ee4096f
feat(sheets): implement object-list shortcuts (B5)
xiongyuanwen-byted May 16, 2026
1cbc049
feat(sheets): implement object CRUD shortcuts (B6)
xiongyuanwen-byted May 16, 2026
705844f
feat(sheets): implement lark_sheet_batch_update shortcuts (B7)
xiongyuanwen-byted May 16, 2026
9898024
feat(sheets): implement cli-only shortcuts (B8) — 70/70 complete
xiongyuanwen-byted May 16, 2026
96f5742
test(sheets): cover all 70 shortcuts with dry-run + execute-path tests
xiongyuanwen-byted May 16, 2026
b9a1752
refactor(sheets): inline cli-only shortcuts into their canonical skil…
xiongyuanwen-byted May 16, 2026
2acff2b
refactor(sheets): sync shortcut flags with sheet-skill-spec v0.5.0
xiongyuanwen-byted May 18, 2026
be31975
refactor(sheets): align batch_update + cells-set with synced referenc…
xiongyuanwen-byted May 18, 2026
347d803
fix(sheets): repair cells-set-image rich_text embed payload
xiongyuanwen-byted May 18, 2026
184949f
refactor(sheets)!: split +dim-resize into +rows-resize and +cols-resize
xiongyuanwen-byted May 19, 2026
50190e8
feat(sheets): add --print-schema runtime introspection for composite …
xiongyuanwen-byted May 19, 2026
54914e6
docs(sheets): remove sandbox references and normalize tool names to C…
xiongyuanwen-byted May 19, 2026
460c794
feat(sheets): add flag-descriptions.en.json and wire applyFlagDescs i…
xiongyuanwen-byted May 20, 2026
ce852e2
feat(shortcuts): support int64 and float64 flag types
xiongyuanwen-byted May 20, 2026
3d3e2c7
refactor(sheets): build shortcut flags generically from flag-defs.json
xiongyuanwen-byted May 20, 2026
9048c70
docs(sheets): sync +batch-update CLI override schema (shortcut/input …
zhengzhijiej-tech May 20, 2026
0c2e5f5
feat(sheets): translate +batch-update sub-ops {shortcut,input} → MCP …
zhengzhijiej-tech May 20, 2026
0ea7c14
fix(sheets): make +batch-update sub-ops reuse standalone flag→body tr…
xiongyuanwen-byted May 21, 2026
1e05e7b
fix(sheets): align +cells-get/+csv-get range flags with synced spec
xiongyuanwen-byted May 21, 2026
8d0fefd
fix(sheets): push +batch-update sub-op validation down into xxxInput …
zhengzhijiej-tech May 21, 2026
4e44e66
fix(sheets): align +cond-format / +filter with server schema (#4 + #5)
zhengzhijiej-tech May 21, 2026
8e8a511
Merge pull request #1018 from zhengzhijiej-tech/fix/sheets-validation…
zhengzhijiej-tech May 21, 2026
5f3e8c6
feat(sheets): add +cells-batch-clear fan-out over batch_update
xiongyuanwen-byted May 21, 2026
300a5e8
docs(sheets): sync stdin guidance and sparkline reference
xiongyuanwen-byted May 21, 2026
d914c85
fix(sheets): require sparkline_id on +sparkline-update items (#6)
zhengzhijiej-tech May 21, 2026
5a42fb5
docs(sheets): sync lark-sheets skill from spec (audit 20260521)
zhengzhijiej-tech May 21, 2026
d91341b
Merge pull request #1023 from zhengzhijiej-tech/fix/sheets-audit-2026…
zhengzhijiej-tech May 21, 2026
e003d4a
feat(sheets): add +cells-set --copy-to-range and sync skill spec
xiongyuanwen-byted May 22, 2026
efcc554
docs(sheets): sync lark-sheets skill spec (chart/pivot wire mappings,…
xiongyuanwen-byted May 22, 2026
e0c22d6
fix(sheets): make --max-chars the single read cap for +cells-get / +c…
xiongyuanwen-byted May 23, 2026
2f5c625
docs(sheets): sync lark-sheets read docs — --max-chars as single read…
xiongyuanwen-byted May 23, 2026
b85311c
docs(sheets): sync lark-sheets skill spec from upstream
xiongyuanwen-byted May 23, 2026
48e6072
docs(sheets): sync chart properties schema (position/size required)
xiongyuanwen-byted May 23, 2026
370137e
docs(sheets): sync lark-sheets skill spec from upstream
xiongyuanwen-byted May 24, 2026
81bb613
docs(sheets): sync lark-sheets skill spec from upstream
xiongyuanwen-byted May 24, 2026
868beaf
docs(sheets): sync lark-sheets skill spec from upstream
xiongyuanwen-byted May 25, 2026
4be06c8
fix(sheets): correct +workbook-create initial fill and +dim-move endp…
xiongyuanwen-byted May 25, 2026
556b229
fix(sheets): align +workbook-create, +dropdown-*, +dim-move, +range-s…
zhengzhijiej-tech May 22, 2026
5926e89
revert(sheets): drop direct flag-defs.json edits — generated from spec
zhengzhijiej-tech May 22, 2026
9d06652
revert(sheets): drop direct edits to skills/lark-sheets/references/
zhengzhijiej-tech May 22, 2026
101c572
docs(sheets): sync from sheet-skill-spec — remove dropdown --colors /…
zhengzhijiej-tech May 22, 2026
96c3387
fix(sheets): restore +dropdown --colors / --highlight, map to canonic…
zhengzhijiej-tech May 22, 2026
2ee2a59
chore(sheets): re-sync from spec + loosen --colors length check
zhengzhijiej-tech May 25, 2026
09c02e8
docs(sheets): sync dropdown --colors/--highlight clarification from spec
zhengzhijiej-tech May 25, 2026
f0d218f
feat(sheets): +dropdown-set/-update --source-range for listFromRange …
zhengzhijiej-tech May 25, 2026
38ef6ad
docs(sheets): sync agent-voice rewrite of Dropdown 选项+配色 from spec
zhengzhijiej-tech May 25, 2026
fa503fa
chore(sheets): restore --colors in parseJSONFlag docstring example list
zhengzhijiej-tech May 25, 2026
f0dea38
fix(sheets): post-rebase test fixups after dropping superseded fix #1
zhengzhijiej-tech May 25, 2026
5eaa70b
Merge pull request #1030 from zhengzhijiej-tech/fix/sheets-e2e-fixes-…
zhengzhijiej-tech May 25, 2026
1a2d2d0
feat(sheets): +dropdown --highlight tri-state via Changed() for opt-out
zhengzhijiej-tech May 25, 2026
ff78ff4
chore(sheets): sync +dropdown flag desc + write-cells narrative from …
zhengzhijiej-tech May 25, 2026
ff493d4
Merge pull request #1075 from zhengzhijiej-tech/fix/sheets-e2e-fixes-…
zhengzhijiej-tech May 25, 2026
dece428
fix(sheets): validate +cells-set-image --image path in Validate
xiongyuanwen-byted May 25, 2026
5327e93
feat(sheets): support local --image in +float-image-create
xiongyuanwen-byted May 25, 2026
12b9474
fix(sheets): +dropdown-get accepts --sheet-id/--sheet-name + bare --r…
zhengzhijiej-tech May 25, 2026
9c447e7
fix(sheets): drop Sheet1! prefix from +cells-get / +csv-get / +csv-pu…
zhengzhijiej-tech May 25, 2026
927a73f
Merge pull request #1083 from zhengzhijiej-tech/fix/dropdown-get-shee…
zhengzhijiej-tech May 25, 2026
6cadbe8
feat: 把环境变量提交上去
zhengzhijiej-tech May 25, 2026
2082095
Merge pull request #1090 from zhengzhijiej-tech/fix/dropdown-get-shee…
zhengzhijiej-tech May 25, 2026
5880d07
fix(sheets): clarify batch --ranges prefix must be sheet display name
zhengzhijiej-tech May 25, 2026
f4bcb85
Merge pull request #1089 from zhengzhijiej-tech/fix/batch-ranges-pref…
zhengzhijiej-tech May 26, 2026
6b3c0b5
docs(sheets): sync lark-sheets skill docs from upstream spec
xiongyuanwen-byted May 26, 2026
a0d6472
feat: 同步 tools-schema.json 改动
zhengzhijiej-tech May 26, 2026
bb7ccae
fix(sheets): warn when +dropdown source-range exceeds 2000 cells with…
zhengzhijiej-tech May 26, 2026
930c9c7
docs(sheets): sync lark-sheets skill from spec — dropdown flag descs …
zhengzhijiej-tech May 26, 2026
08d0259
revert(sheets): drop tools-schema drift mirror from previous spec sync
zhengzhijiej-tech May 26, 2026
71eae77
docs(sheets): sync lark-sheets skill from spec — +filter-view-update …
zhengzhijiej-tech May 26, 2026
f53e55c
fix(sheets): align +cells-search/+cells-replace option keys with serv…
zhengzhijiej-tech May 26, 2026
4b16fe9
Merge pull request #1098 from zhengzhijiej-tech/fix/batch-ranges-pref…
zhengzhijiej-tech May 26, 2026
bea4c74
docs(sheets): sync float-image reference from spec — fix non-runnable…
zhengzhijiej-tech May 26, 2026
55ccbc5
feat: 同步 tools-schema.json 改动
zhengzhijiej-tech May 26, 2026
338cdaa
Merge pull request #1107 from zhengzhijiej-tech/sheets/float-image-re…
zhengzhijiej-tech May 26, 2026
08e8b5c
fix(sheets): allow +float-image-update to omit the image source
xiongyuanwen-byted May 27, 2026
60c61d8
docs(sheets): sync lark-sheets skill from spec
xiongyuanwen-byted May 27, 2026
a09593a
fix(sheets): allow +pivot-create to omit both sheet selectors
zhengzhijiej-tech May 27, 2026
e85afd6
Merge pull request #1130 from zhengzhijiej-tech/fix/pivot-create-sche…
zhengzhijiej-tech May 27, 2026
ce5878e
docs(sheets): clarify filter/filter-view rules update is whole-set PUT
xiongyuanwen-byted May 27, 2026
69d2851
refactor(sheets): switch dim-* / rows-cols-resize to A1-string range …
zhengzhijiej-tech May 27, 2026
0476dec
docs(sheets): sync +pivot-create placement reference from spec
zhengzhijiej-tech May 27, 2026
5ebb139
Merge pull request #1138 from zhengzhijiej-tech/feat/dim-resize-a1-ra…
zhengzhijiej-tech May 27, 2026
8e84f47
docs(sheets): sync +pivot-create summarize_by lowercase enum values f…
zhengzhijiej-tech May 28, 2026
77f86ec
docs(sheets): wrap sheet names in single quotes in A1 examples
zhengzhijiej-tech May 28, 2026
0f695b6
docs(sheets): wrap A1 sheet names in handwritten examples + bash hist…
zhengzhijiej-tech May 28, 2026
690e746
docs(sheets): drop bash histexpand section, fix write-cells table escape
zhengzhijiej-tech May 28, 2026
9c3d30a
feat(sheets): rename +pivot-create sheet selector → --target-sheet-{i…
zhengzhijiej-tech May 28, 2026
dce617e
docs(sheets): strip migration-history language from pivot reference /…
zhengzhijiej-tech May 28, 2026
da65e37
Merge pull request #1152 from zhengzhijiej-tech/fix/eval-issues
zhengzhijiej-tech May 28, 2026
e3eca66
docs(sheets): require +workbook-info before guessing sheet name
zhengzhijiej-tech May 28, 2026
7d24e2b
docs(sheets): tell agent to `set +H` for A1 references containing `!`
zhengzhijiej-tech May 28, 2026
74761a0
feat(sheets): add schema-driven JSON flag validation
xiongyuanwen-byted May 29, 2026
f99b5bf
Merge pull request #1160 from zhengzhijiej-tech/fix/eval-issues
zhengzhijiej-tech May 29, 2026
e58fa13
feat(sheets): add --rows-json output flag to +csv-get
zhengzhijiej-tech Jun 1, 2026
46066de
Merge pull request #1200 from zhengzhijiej-tech/feat/sheets-rows-get
zhengzhijiej-tech Jun 1, 2026
7dd479d
feat(cli): agent-friendly errors, proxy silencing, +csv-put --range
xiongyuanwen-byted Jun 1, 2026
5c22f91
feat(sheets): close P0-4 pivot gaps — enum case, clear→pivot-delete h…
xiongyuanwen-byted Jun 1, 2026
5aba007
feat(sheets): strip UTF-8 BOM from stdin/@file flag input
xiongyuanwen-byted Jun 2, 2026
fc6e60b
fix(sheets): drop dead --value-render-option flag from +csv-get
zhengzhijiej-tech Jun 2, 2026
ce9764e
Merge pull request #1215 from zhengzhijiej-tech/fix/delete-value-rend…
zhengzhijiej-tech Jun 2, 2026
9c7d5a4
Merge origin/main into feat/lark-sheets-refactor
xiongyuanwen-byted Jun 2, 2026
a8b29a1
chore: rename ppe x-tt-env lane to ppe_moa_canvas
xiongyuanwen-byted Jun 2, 2026
3bca545
docs(sheets): sync skill description from spec (cloud-drive alias, la…
xiongyuanwen-byted Jun 2, 2026
d2aa27d
Merge remote-tracking branch 'origin/main' into feat/lark-sheets-refa…
xiongyuanwen-byted Jun 2, 2026
bc1cd72
feat(sheets): restore pre-refactor shortcuts under backward/ for comp…
xiongyuanwen-byted May 21, 2026
4c24c6e
fix(sheets): resolve 30 golangci-lint v2.1.6 issues — copyloopvar, ni…
zhengzhijiej-tech Jun 2, 2026
fe1b6b7
feat(sheets): flag pre-refactor backward aliases via _notice and --he…
xiongyuanwen-byted Jun 2, 2026
aec1bd4
chore: drop hardcoded ppe lane routing from base security headers
xiongyuanwen-byted Jun 2, 2026
6e18185
chore(sheets): promote lark-sheets skill to 2.0.0
xiongyuanwen-byted Jun 3, 2026
ad7b209
fix(sheets): correct +dropdown-get sheet-locator doc, finalize skill …
zhengzhijiej-tech Jun 3, 2026
da198cf
fix(sheets): enforce required-flag contract in batch sub-ops
xiongyuanwen-byted Jun 3, 2026
d6a0aad
fix(cli): surface skill in deprecated_command notice
xiongyuanwen-byted Jun 3, 2026
e4309bb
fix(sheets): harden batch type-checking and +workbook-create edge cases
xiongyuanwen-byted Jun 3, 2026
6bd21ac
fix(cli): structured errors for unknown flags, print-schema, deprecat…
xiongyuanwen-byted Jun 3, 2026
27c6333
fix(sheets): resolve --sheet-name via title + keep bare sheet selecto…
zhengzhijiej-tech Jun 3, 2026
2132472
fix(sheets): silence nilerr/copyloopvar lint in batch type-check addi…
zhengzhijiej-tech Jun 3, 2026
cf47d9b
test(sheets): data-driven required-flag parity contract for batch sub…
xiongyuanwen-byted Jun 3, 2026
d05fbcf
refactor(sheets): drop unused int64 flag-type plumbing
zhengzhijiej-tech Jun 3, 2026
1decb43
test(sheets): drop redundant copyloopvar copy in required-flag parity…
xiongyuanwen-byted Jun 3, 2026
5ac35fd
revert(cli): drop non-interactive proxy-warning silencing
zhengzhijiej-tech Jun 3, 2026
46712cf
docs(sheets): correct +workbook-info output field and batch +sheet-mo…
zhengzhijiej-tech Jun 3, 2026
bd1d8dd
fix(sheets): reject non-integer numbers for batch int flags
zhengzhijiej-tech Jun 3, 2026
fc10338
fix(cli): align flag-before-subcommand unknown_flag detail schema
zhengzhijiej-tech Jun 3, 2026
3bc2308
perf(sheets): compile flag specs to Go to drop startup JSON parse
zhengzhijiej-tech Jun 3, 2026
65cbce4
ci(sheets): exempt internal/gen generators from forbidigo
xiongyuanwen-byted Jun 3, 2026
9f8dfa7
fix(cli): fail structured on flags before a missing subcommand
xiongyuanwen-byted Jun 3, 2026
f20aad6
fix(cli): don't flag group-valid globals as a missing subcommand
zhengzhijiej-tech Jun 3, 2026
694a455
Merge remote-tracking branch 'origin/main' into feat/lark-sheets-refa…
xiongyuanwen-byted Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ linters:
- path: internal/vfs/
linters:
- forbidigo
# internal/gen build-time generators (standalone `package main` run via
# go:generate) are not shortcut runtime code — no ctx/runtime/framework —
# so the shortcut forbidigo bans don't apply. Going "compliant" is also
# impossible here: a structured error return needs os.Exit (also banned),
# and the vfs.Xxx() alternative is blocked by depguard shortcuts-no-vfs.
- path: shortcuts/.*/internal/gen/
linters:
- forbidigo
# shortcuts-no-raw-http is shortcuts-only; internal/ wraps raw HTTP
# for the client / credential layer.
- path-except: shortcuts/
Expand Down
7 changes: 7 additions & 0 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ func buildInternal(ctx context.Context, inv cmdutil.InvocationContext, opts ...B

installTipsHelpFunc(rootCmd)
rootCmd.SilenceErrors = true
// SilenceUsage as a static field (not only in PersistentPreRun) so it also
// covers flag-parse errors, which fail before PreRun runs — otherwise cobra
// dumps usage instead of our structured error. SetFlagErrorFunc on root is
// inherited by every subcommand, turning unknown-flag errors into a
// structured "did you mean" envelope.
rootCmd.SilenceUsage = true
rootCmd.SetFlagErrorFunc(flagDidYouMean)

RegisterGlobalFlags(rootCmd.PersistentFlags(), &cfg.globals)
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
Expand Down
34 changes: 2 additions & 32 deletions cmd/event/suggestions.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

eventlib "github.com/larksuite/cli/internal/event"
"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/internal/suggest"
)

const maxSuggestions = 3
Expand All @@ -28,7 +29,7 @@ func suggestEventKeys(input string) []string {
hits = append(hits, match{def.Key, 0})
continue
}
if d := levenshtein(input, def.Key); d <= threshold {
if d := suggest.Levenshtein(input, def.Key); d <= threshold {
hits = append(hits, match{def.Key, d})
}
}
Expand Down Expand Up @@ -69,34 +70,3 @@ func unknownEventKeyErr(key string) error {
"Run 'lark-cli event list' to see available keys.",
)
}

// levenshtein computes classic edit distance (two-row DP).
func levenshtein(a, b string) int {
if a == b {
return 0
}
ra, rb := []rune(a), []rune(b)
if len(ra) == 0 {
return len(rb)
}
if len(rb) == 0 {
return len(ra)
}
prev := make([]int, len(rb)+1)
curr := make([]int, len(rb)+1)
for j := range prev {
prev[j] = j
}
for i := 1; i <= len(ra); i++ {
curr[0] = i
for j := 1; j <= len(rb); j++ {
cost := 1
if ra[i-1] == rb[j-1] {
cost = 0
}
curr[j] = min(prev[j]+1, curr[j-1]+1, prev[j-1]+cost)
}
prev, curr = curr, prev
}
return prev[len(rb)]
}
21 changes: 0 additions & 21 deletions cmd/event/suggestions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,6 @@ import (
_ "github.com/larksuite/cli/events"
)

func TestLevenshtein(t *testing.T) {
cases := []struct {
a, b string
want int
}{
{"", "", 0},
{"a", "", 1},
{"", "abc", 3},
{"kitten", "kitten", 0},
{"kitten", "sitten", 1},
{"kitten", "sitting", 3},
{"飞书", "飞书", 0},
{"飞书", "飞s", 1},
}
for _, tc := range cases {
if got := levenshtein(tc.a, tc.b); got != tc.want {
t.Errorf("levenshtein(%q,%q) = %d, want %d", tc.a, tc.b, got, tc.want)
}
}
}

func TestSuggestEventKeys(t *testing.T) {
cases := []struct {
name string
Expand Down
70 changes: 70 additions & 0 deletions cmd/flag_suggest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

package cmd

import (
"errors"
"slices"
"strings"
"testing"

"github.com/larksuite/cli/internal/output"
"github.com/spf13/cobra"
)

func TestUnknownFlagName(t *testing.T) {
cases := []struct {
in string
name string
ok bool
}{
{"unknown flag: --query", "query", true},
{"unknown flag: --with-styles", "with-styles", true},
{"unknown shorthand flag: 'z' in -z", "", false},
{"flag needs an argument: --find", "", false},
{`invalid argument "x" for "--count"`, "", false},
}
for _, c := range cases {
name, ok := unknownFlagName(errors.New(c.in))
if name != c.name || ok != c.ok {
t.Errorf("unknownFlagName(%q) = (%q,%v), want (%q,%v)", c.in, name, ok, c.name, c.ok)
}
}
}

func TestFlagDidYouMean_UnknownFlagSuggestsAndListsValid(t *testing.T) {
c := &cobra.Command{Use: "demo"}
c.Flags().String("range", "", "")
c.Flags().String("find", "", "")
c.Flags().Bool("dry-run", false, "")

err := flagDidYouMean(c, errors.New("unknown flag: --rang")) // typo of --range
var exitErr *output.ExitError
if !errors.As(err, &exitErr) {
t.Fatalf("expected *output.ExitError, got %T", err)
}
if exitErr.Detail.Type != "unknown_flag" {
t.Errorf("type = %q, want unknown_flag", exitErr.Detail.Type)
}
if !strings.Contains(exitErr.Detail.Hint, "--range") {
t.Errorf("hint should suggest --range, got %q", exitErr.Detail.Hint)
}
detail, _ := exitErr.Detail.Detail.(map[string]any)
valid, _ := detail["valid_flags"].([]string)
if !slices.Contains(valid, "find") || !slices.Contains(valid, "range") {
t.Errorf("valid_flags should list find & range, got %v", valid)
}
}

func TestFlagDidYouMean_OtherErrorStaysGeneric(t *testing.T) {
c := &cobra.Command{Use: "demo"}
err := flagDidYouMean(c, errors.New("flag needs an argument: --find"))
var exitErr *output.ExitError
if !errors.As(err, &exitErr) {
t.Fatalf("expected *output.ExitError, got %T", err)
}
if exitErr.Detail.Type != "flag_error" {
t.Errorf("type = %q, want flag_error (non-unknown-flag errors stay generic)", exitErr.Detail.Type)
}
}
61 changes: 61 additions & 0 deletions cmd/notice_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

package cmd

import (
"strings"
"testing"

"github.com/larksuite/cli/internal/deprecation"
)

// composePendingNotice must surface a deprecated-command alias under the
// "deprecated_command" key, with the migration target and a skill-update hint,
// so the JSON "_notice" envelope reaches users who run pre-refactor commands
// without ever reading --help.
func TestComposePendingNoticeDeprecatedCommand(t *testing.T) {
t.Cleanup(func() { deprecation.SetPending(nil) })

deprecation.SetPending(&deprecation.Notice{
Command: "+read",
Replacement: "+cells-get",
Skill: "lark-sheets",
})

got := composePendingNotice()
if got == nil {
t.Fatal("composePendingNotice() = nil, want deprecated_command entry")
}
entry, ok := got["deprecated_command"].(map[string]interface{})
if !ok {
t.Fatalf("missing deprecated_command key: %#v", got)
}
if entry["command"] != "+read" {
t.Errorf("command = %v, want +read", entry["command"])
}
if entry["replacement"] != "+cells-get" {
t.Errorf("replacement = %v, want +cells-get", entry["replacement"])
}
if entry["skill"] != "lark-sheets" {
t.Errorf("skill = %v, want lark-sheets", entry["skill"])
}
if msg, _ := entry["message"].(string); !strings.Contains(msg, "update your lark-sheets skill") {
t.Errorf("message missing skill-update hint: %q", msg)
}
}

// With nothing pending, the provider returns nil so no "_notice" field is
// emitted on a clean run.
func TestComposePendingNoticeEmpty(t *testing.T) {
t.Cleanup(func() { deprecation.SetPending(nil) })
deprecation.SetPending(nil)

if got := composePendingNotice(); got != nil {
// update/skills pending are process-global; only assert the absence of
// our own key to stay robust against unrelated pending state.
if _, ok := got["deprecated_command"]; ok {
t.Fatalf("deprecated_command present after clear: %#v", got)
}
}
}
Loading
Loading