mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
Users who install or upgrade lark-cli via make install, go install, or
direct binary download end up with a binary but no AI agent skills,
degrading agent UX. This PR adds a startup-time skills version drift
notice (injected into JSON envelope _notice.skills, mirroring the
existing _notice.update pattern) and unifies lark-cli update's skills
sync across all three branches (npm / manual / already-latest) with
stamp-based dedup, so any explicit update invocation keeps skills in
sync regardless of how the binary was installed.
Changes:
- new internal/skillscheck package: notice (StaleNotice + atomic
pending), stamp (~/.lark-cli/skills.stamp), skip (CI / DEV /
non-release / LARKSUITE_CLI_NO_SKILLS_NOTIFIER opt-out), check
(synchronous Init)
- cmd/root.go: rename setupUpdateNotice -> setupNotices, compose
output.PendingNotice returning {update?, skills?}; capture
build.Version locally before spawning the async update goroutine
- cmd/update/update.go: add runSkillsAndStamp helper with stamp-based
dedup; rewire the three branches through shared applySkillsResult /
emitSkillsTextHints helpers; add skills_status block to --check JSON
output as a pure report (no side effects)
- internal/update: export IsRelease(version) bool / IsCIEnv() bool
for cross-package reuse; refresh UpdateInfo.Message to append
', run: lark-cli update' so both notices recommend the same fix
- AGENTS.md: add Notification Opt-Outs section documenting
LARKSUITE_CLI_NO_UPDATE_NOTIFIER and LARKSUITE_CLI_NO_SKILLS_NOTIFIER
- internal/binding/types.go: bump default exec-provider timeout from
5s to 10s (out-of-scope flake fix for TestResolveExecRef_JSONResponse
under heavy parallel test load)
69 lines
2.0 KiB
Go
69 lines
2.0 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package skillscheck
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
// clearSkillsSkipEnv unsets the env vars shouldSkip checks so the
|
|
// host environment cannot pollute test results.
|
|
func clearSkillsSkipEnv(t *testing.T) {
|
|
t.Helper()
|
|
for _, key := range []string{"LARKSUITE_CLI_NO_SKILLS_NOTIFIER", "CI", "BUILD_NUMBER", "RUN_ID"} {
|
|
t.Setenv(key, "")
|
|
os.Unsetenv(key)
|
|
}
|
|
}
|
|
|
|
func TestShouldSkip(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setup func(t *testing.T)
|
|
version string
|
|
want bool
|
|
}{
|
|
{"release_no_skip", clearSkillsSkipEnv, "1.0.21", false},
|
|
{"dev_uppercase", clearSkillsSkipEnv, "DEV", true},
|
|
{"dev_lowercase", clearSkillsSkipEnv, "dev", true},
|
|
{"empty_version", clearSkillsSkipEnv, "", true},
|
|
{"git_describe", clearSkillsSkipEnv, "1.0.0-12-g9b933f1-dirty", true},
|
|
{"opt_out", func(t *testing.T) {
|
|
clearSkillsSkipEnv(t)
|
|
t.Setenv("LARKSUITE_CLI_NO_SKILLS_NOTIFIER", "1")
|
|
}, "1.0.21", true},
|
|
{"ci_env", func(t *testing.T) {
|
|
clearSkillsSkipEnv(t)
|
|
t.Setenv("CI", "true")
|
|
}, "1.0.21", true},
|
|
{"build_number_env", func(t *testing.T) {
|
|
clearSkillsSkipEnv(t)
|
|
t.Setenv("BUILD_NUMBER", "42")
|
|
}, "1.0.21", true},
|
|
{"run_id_env", func(t *testing.T) {
|
|
clearSkillsSkipEnv(t)
|
|
t.Setenv("RUN_ID", "abc")
|
|
}, "1.0.21", true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.setup(t)
|
|
if got := shouldSkip(tt.version); got != tt.want {
|
|
t.Errorf("shouldSkip(%q) = %v, want %v", tt.version, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Independent opt-out: LARKSUITE_CLI_NO_SKILLS_NOTIFIER must NOT be
|
|
// affected by LARKSUITE_CLI_NO_UPDATE_NOTIFIER (different env vars).
|
|
func TestShouldSkip_OptOutIsIndependent(t *testing.T) {
|
|
clearSkillsSkipEnv(t)
|
|
t.Setenv("LARKSUITE_CLI_NO_UPDATE_NOTIFIER", "1") // update opt-out, not us
|
|
if shouldSkip("1.0.21") {
|
|
t.Error("shouldSkip(release) = true with only LARKSUITE_CLI_NO_UPDATE_NOTIFIER set, want false")
|
|
}
|
|
}
|