From 0195532f833e6bc785ede175f4ca8db7934cdf93 Mon Sep 17 00:00:00 2001 From: kongenpei Date: Wed, 22 Apr 2026 13:43:02 +0800 Subject: [PATCH 1/3] fix(base): add default-table follow-up hint to base-create --- shortcuts/base/base_execute_test.go | 6 ++++++ shortcuts/base/base_ops.go | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/shortcuts/base/base_execute_test.go b/shortcuts/base/base_execute_test.go index e9f432ba2..b1c20e858 100644 --- a/shortcuts/base/base_execute_test.go +++ b/shortcuts/base/base_execute_test.go @@ -96,6 +96,9 @@ func TestBaseWorkspaceExecuteCreate(t *testing.T) { if data["created"] != true { t.Fatalf("created = %#v, want true", data["created"]) } + if data["hint"] != baseCreateHint { + t.Fatalf("hint = %#v, want %q", data["hint"], baseCreateHint) + } base, _ := data["base"].(map[string]interface{}) if got := common.GetString(base, "app_token"); got != "app_x" { t.Fatalf("base.app_token = %q, want %q", got, "app_x") @@ -198,6 +201,9 @@ func TestBaseWorkspaceExecuteCreateBotAutoGrantSkippedWithoutCurrentUser(t *test } data := decodeBaseEnvelope(t, stdout) + if data["hint"] != baseCreateHint { + t.Fatalf("hint = %#v, want %q", data["hint"], baseCreateHint) + } grant, _ := data["permission_grant"].(map[string]interface{}) if grant["status"] != common.PermissionGrantSkipped { t.Fatalf("permission_grant.status = %#v, want %q", grant["status"], common.PermissionGrantSkipped) diff --git a/shortcuts/base/base_ops.go b/shortcuts/base/base_ops.go index 20dbe2335..b1076ac8c 100644 --- a/shortcuts/base/base_ops.go +++ b/shortcuts/base/base_ops.go @@ -10,6 +10,8 @@ import ( "github.com/larksuite/cli/shortcuts/common" ) +const baseCreateHint = "New bases include a default empty table with 5-10 blank records. After finishing table/field setup on this base, ask whether to delete that default table. If yes, run +table-list first, then delete the default table." + func dryRunBaseGet(_ context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token"). @@ -62,7 +64,7 @@ func executeBaseCreate(runtime *common.RuntimeContext) error { if err != nil { return err } - out := map[string]interface{}{"base": data, "created": true} + out := map[string]interface{}{"base": data, "created": true, "hint": baseCreateHint} augmentBasePermissionGrant(runtime, out, data) runtime.Out(out, nil) return nil From fb416f26979b574a8daa286fa17ca02f1ab5621b Mon Sep 17 00:00:00 2001 From: kongenpei Date: Wed, 22 Apr 2026 14:07:31 +0800 Subject: [PATCH 2/3] fix(base): route base-create hint to stderr --- shortcuts/base/base_execute_test.go | 13 +++++++++---- shortcuts/base/base_ops.go | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/shortcuts/base/base_execute_test.go b/shortcuts/base/base_execute_test.go index b1c20e858..cb619f740 100644 --- a/shortcuts/base/base_execute_test.go +++ b/shortcuts/base/base_execute_test.go @@ -67,11 +67,15 @@ func runShortcutWithAuthTypes(t *testing.T, shortcut common.Shortcut, authTypes parent.SilenceErrors = true parent.SilenceUsage = true stdout.Reset() + if stderr, ok := factory.IOStreams.ErrOut.(*bytes.Buffer); ok { + stderr.Reset() + } return parent.ExecuteContext(context.Background()) } func TestBaseWorkspaceExecuteCreate(t *testing.T) { factory, stdout, reg := newExecuteFactory(t) + stderr, _ := factory.IOStreams.ErrOut.(*bytes.Buffer) permStub := &httpmock.Stub{ Method: "POST", URL: "/open-apis/drive/v1/permissions/app_x/members?need_notification=false&type=bitable", @@ -96,8 +100,8 @@ func TestBaseWorkspaceExecuteCreate(t *testing.T) { if data["created"] != true { t.Fatalf("created = %#v, want true", data["created"]) } - if data["hint"] != baseCreateHint { - t.Fatalf("hint = %#v, want %q", data["hint"], baseCreateHint) + if !strings.Contains(stderr.String(), baseCreateHint) { + t.Fatalf("stderr = %q, want %q", stderr.String(), baseCreateHint) } base, _ := data["base"].(map[string]interface{}) if got := common.GetString(base, "app_token"); got != "app_x" { @@ -187,6 +191,7 @@ func TestBaseWorkspaceExecuteGetAndCopy(t *testing.T) { func TestBaseWorkspaceExecuteCreateBotAutoGrantSkippedWithoutCurrentUser(t *testing.T) { factory, stdout, reg := newExecuteFactoryWithUserOpenID(t, "") + stderr, _ := factory.IOStreams.ErrOut.(*bytes.Buffer) reg.Register(&httpmock.Stub{ Method: "POST", URL: "/open-apis/base/v3/bases", @@ -201,8 +206,8 @@ func TestBaseWorkspaceExecuteCreateBotAutoGrantSkippedWithoutCurrentUser(t *test } data := decodeBaseEnvelope(t, stdout) - if data["hint"] != baseCreateHint { - t.Fatalf("hint = %#v, want %q", data["hint"], baseCreateHint) + if !strings.Contains(stderr.String(), baseCreateHint) { + t.Fatalf("stderr = %q, want %q", stderr.String(), baseCreateHint) } grant, _ := data["permission_grant"].(map[string]interface{}) if grant["status"] != common.PermissionGrantSkipped { diff --git a/shortcuts/base/base_ops.go b/shortcuts/base/base_ops.go index b1076ac8c..b327e6d8f 100644 --- a/shortcuts/base/base_ops.go +++ b/shortcuts/base/base_ops.go @@ -5,6 +5,7 @@ package base import ( "context" + "fmt" "strings" "github.com/larksuite/cli/shortcuts/common" @@ -64,9 +65,10 @@ func executeBaseCreate(runtime *common.RuntimeContext) error { if err != nil { return err } - out := map[string]interface{}{"base": data, "created": true, "hint": baseCreateHint} + out := map[string]interface{}{"base": data, "created": true} augmentBasePermissionGrant(runtime, out, data) runtime.Out(out, nil) + fmt.Fprintln(runtime.IO().ErrOut, baseCreateHint) return nil } From 7b2fefffbf92fbdbfc2cb714800dc0fe3ae594d8 Mon Sep 17 00:00:00 2001 From: kongenpei Date: Wed, 22 Apr 2026 14:11:46 +0800 Subject: [PATCH 3/3] fix(base): prefix base-create stderr tip --- shortcuts/base/base_ops.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shortcuts/base/base_ops.go b/shortcuts/base/base_ops.go index b327e6d8f..dc0bba5a7 100644 --- a/shortcuts/base/base_ops.go +++ b/shortcuts/base/base_ops.go @@ -11,7 +11,7 @@ import ( "github.com/larksuite/cli/shortcuts/common" ) -const baseCreateHint = "New bases include a default empty table with 5-10 blank records. After finishing table/field setup on this base, ask whether to delete that default table. If yes, run +table-list first, then delete the default table." +const baseCreateHint = "Tip: New bases include a default empty table with 5-10 blank records. After finishing table/field setup on this base, ask whether to delete that default table. If yes, run +table-list first, then delete the default table." func dryRunBaseGet(_ context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI().