From 04f78bcb154bbac77acfc20c733b3ba6f533ec01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=89=E6=BE=9C?= Date: Fri, 14 Aug 2026 11:58:27 +0800 Subject: [PATCH] fix(skills): remove ineffective app detection gate --- internal/app/skill_setup.go | 17 ++++++--------- internal/app/skill_setup_canonical_test.go | 3 ++- internal/upgrade/canonical_skills_test.go | 5 +++-- internal/upgrade/paths.go | 25 +++++++++------------- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/internal/app/skill_setup.go b/internal/app/skill_setup.go index 6c0becf4..9a4ebfb8 100644 --- a/internal/app/skill_setup.go +++ b/internal/app/skill_setup.go @@ -127,7 +127,6 @@ var ( skillSetupExecutable = os.Executable skillSetupGetwd = os.Getwd skillSetupUserHomeDir = os.UserHomeDir - skillSetupSystemHomeDir = os.UserHomeDir skillSetupRemoveAll = os.RemoveAll skillSetupBackupAndRemove = upgrade.BackupAndRemoveSkillDir skillSetupRestoreBackup = upgrade.RestoreSkillPath @@ -1097,24 +1096,20 @@ func detectExistingAgentHomes(home, mode string) []string { dests := []string{canonical} canonicalKey := skillSetupPathKey(canonical) seen := map[string]bool{canonicalKey: true} - systemHome, _ := skillSetupSystemHomeDir() - allowSystemApps := sameSkillSetupPath(home, systemHome) addDetected := func(rel, base string) { detectedDir := filepath.Dir(base) switch filepath.ToSlash(filepath.Clean(rel)) { case ".config/kimchi/harness/skills", ".tabnine/agent/skills": detectedDir = filepath.Dir(filepath.Dir(base)) case ".zcode/skills": - if allowSystemApps { - if info, err := skillSetupStat(filepath.Join(string(filepath.Separator), "Applications", "ZCode.app")); err == nil && info.IsDir() { - detectedDir = "" - } + // Application bundles are machine-scoped detection signals. Keep this + // independent of HOME so setup matches npm, Shell, and PowerShell. + if info, err := skillSetupStat(filepath.Join(string(filepath.Separator), "Applications", "ZCode.app")); err == nil && info.IsDir() { + detectedDir = "" } case ".minimax/skills": - if allowSystemApps { - if info, err := skillSetupStat(filepath.Join(string(filepath.Separator), "Applications", "MiniMax Code.app")); err == nil && info.IsDir() { - detectedDir = "" - } + if info, err := skillSetupStat(filepath.Join(string(filepath.Separator), "Applications", "MiniMax Code.app")); err == nil && info.IsDir() { + detectedDir = "" } } if detectedDir != "" { diff --git a/internal/app/skill_setup_canonical_test.go b/internal/app/skill_setup_canonical_test.go index c308298b..1932e55b 100644 --- a/internal/app/skill_setup_canonical_test.go +++ b/internal/app/skill_setup_canonical_test.go @@ -101,8 +101,9 @@ func TestCrossPlatformCoverageSkillSetupCanonicalTargetsAndAgentCapabilities(t * } func TestCrossPlatformCoverageSkillSetupDetectsShallowAndApplicationAgents(t *testing.T) { + // Keep the destination HOME synthetic: app-bundle detection is deliberately + // machine-scoped and must not depend on the selected installation HOME. home := t.TempDir() - testseam.Swap(t, &skillSetupSystemHomeDir, func() (string, error) { return home, nil }) testseam.Swap(t, &skillSetupGetenv, func(string) string { return "" }) for _, dir := range []string{filepath.Join(home, ".config", "kimchi"), filepath.Join(home, ".tabnine")} { if err := os.MkdirAll(dir, 0o755); err != nil { diff --git a/internal/upgrade/canonical_skills_test.go b/internal/upgrade/canonical_skills_test.go index 17f27a27..56d22520 100644 --- a/internal/upgrade/canonical_skills_test.go +++ b/internal/upgrade/canonical_skills_test.go @@ -162,8 +162,9 @@ func TestCrossPlatformCoverageCanonicalSkillLinksFallBackToCopies(t *testing.T) } func TestCrossPlatformCoverageConfiguredRootsDetectShallowAndApplicationAgents(t *testing.T) { + // Keep the destination HOME synthetic: app-bundle detection is deliberately + // machine-scoped and must not depend on the selected installation HOME. home := t.TempDir() - testseam.Swap(t, &upgradeSystemHomeDir, func() (string, error) { return home, nil }) testseam.Swap(t, &upgradeGetenv, func(string) string { return "" }) for _, dir := range []string{filepath.Join(home, ".config", "kimchi"), filepath.Join(home, ".tabnine")} { if err := os.MkdirAll(dir, 0o755); err != nil { @@ -196,7 +197,7 @@ func TestCrossPlatformCoverageConfiguredRootsDetectShallowAndApplicationAgents(t for _, root := range configuredSkillRoots(home) { label := filepath.ToSlash(root.label) if _, ok := want[label]; ok { - want[label] = skillRootDetectedBase(home, root) + want[label] = skillRootDetectedBase(root) } } for label, detected := range want { diff --git a/internal/upgrade/paths.go b/internal/upgrade/paths.go index f0424ae6..7b0ecc49 100644 --- a/internal/upgrade/paths.go +++ b/internal/upgrade/paths.go @@ -141,7 +141,6 @@ var universalSkillDirs = map[string]bool{ var ( upgradeUserHomeDir = os.UserHomeDir - upgradeSystemHomeDir = os.UserHomeDir upgradeExecutable = os.Executable upgradeEvalSymlinks = filepath.EvalSymlinks upgradeCopyDir = copyDir @@ -693,26 +692,22 @@ func configuredSkillRoots(homeDir string) []resolvedSkillRoot { return roots } -func skillRootDetectedBase(homeDir string, root resolvedSkillRoot) bool { +func skillRootDetectedBase(root resolvedSkillRoot) bool { detectedDir := filepath.Dir(root.base) - systemHome, _ := upgradeSystemHomeDir() - allowSystemApps := skillRootPathKey(homeDir) == skillRootPathKey(systemHome) switch filepath.ToSlash(filepath.Clean(root.label)) { case ".config/kimchi/harness/skills": detectedDir = filepath.Dir(filepath.Dir(root.base)) case ".tabnine/agent/skills": detectedDir = filepath.Dir(filepath.Dir(root.base)) case ".zcode/skills": - if allowSystemApps { - if info, err := upgradeStat(filepath.Join(string(filepath.Separator), "Applications", "ZCode.app")); err == nil && info.IsDir() { - return true - } + // Application bundles are machine-scoped detection signals. Keep this + // independent of HOME so upgrade matches npm, Shell, and PowerShell. + if info, err := upgradeStat(filepath.Join(string(filepath.Separator), "Applications", "ZCode.app")); err == nil && info.IsDir() { + return true } case ".minimax/skills": - if allowSystemApps { - if info, err := upgradeStat(filepath.Join(string(filepath.Separator), "Applications", "MiniMax Code.app")); err == nil && info.IsDir() { - return true - } + if info, err := upgradeStat(filepath.Join(string(filepath.Separator), "Applications", "MiniMax Code.app")); err == nil && info.IsDir() { + return true } } info, err := upgradeStat(detectedDir) @@ -738,7 +733,7 @@ func skillRootPathKey(path string) string { func hasDependentSkillRoot(homeDir, canonicalBase string) bool { for _, root := range configuredSkillRoots(homeDir) { - if root.canonical || root.universal || isBlacklisted(root.label) || !skillRootDetectedBase(homeDir, root) { + if root.canonical || root.universal || isBlacklisted(root.label) || !skillRootDetectedBase(root) { continue } if !samePhysicalSkillRoot(root.base, canonicalBase) { @@ -848,7 +843,7 @@ func upgradeMonoSkillLocations(homeDir, skillSrc string) (*SkillUpgradeResult, e result.Results = append(result.Results, SkillDirResult{Dir: destDir, Status: SkillDirBlacklisted}) continue } - if !skillRootDetectedBase(homeDir, root) { + if !skillRootDetectedBase(root) { result.Results = append(result.Results, SkillDirResult{Dir: destDir, Status: SkillDirSkipped}) continue } @@ -920,7 +915,7 @@ func upgradeMultiSkillLocations(homeDir, multiRoot string, skills []string) (*Sk result.Results = append(result.Results, SkillDirResult{Dir: destBase, Status: SkillDirBlacklisted}) continue } - if !skillRootDetectedBase(homeDir, root) { + if !skillRootDetectedBase(root) { result.Results = append(result.Results, SkillDirResult{Dir: destBase, Status: SkillDirSkipped}) continue }