probe.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package main
  2. import (
  3. "os"
  4. "os/exec"
  5. "path/filepath"
  6. )
  7. // probe.go —— 运行环境探测(node 路径、dsh 入口、已装版本)。
  8. // 结果缓存于 Supervisor,probeMu 保证并发只探测一次;更新后调用 invalidateProbe 失效。
  9. func (s *Supervisor) nodePath() string {
  10. s.mu.Lock()
  11. if s.nodeCache != "" {
  12. v := s.nodeCache
  13. s.mu.Unlock()
  14. return v
  15. }
  16. s.mu.Unlock()
  17. p, err := exec.LookPath("node")
  18. if err != nil {
  19. return ""
  20. }
  21. s.mu.Lock()
  22. s.nodeCache = p
  23. s.mu.Unlock()
  24. return p
  25. }
  26. // dshBinJS 探测 dsh 的 bin.js(APPDATA\npm 与 npm root -g)。
  27. func (s *Supervisor) dshBinJS() string {
  28. s.probeMu.Lock()
  29. defer s.probeMu.Unlock()
  30. s.mu.Lock()
  31. if s.binCache != "" {
  32. v := s.binCache
  33. s.mu.Unlock()
  34. return v
  35. }
  36. s.mu.Unlock()
  37. var candidates []string
  38. if appdata := os.Getenv("APPDATA"); appdata != "" {
  39. candidates = append(candidates, filepath.Join(appdata, "npm", "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js"))
  40. }
  41. if root := npmGlobalRoot(); root != "" {
  42. candidates = append(candidates, filepath.Join(root, "@deepseek-ai", "dsh", "lib", "bin.js"))
  43. }
  44. for _, c := range candidates {
  45. if fileExists(c) {
  46. s.mu.Lock()
  47. s.binCache = c
  48. s.mu.Unlock()
  49. s.log.Printf("dsh 入口: %s", c)
  50. return c
  51. }
  52. }
  53. return ""
  54. }
  55. // invalidateProbe 使入口缓存失效(更新 dsh 后调用)。
  56. func (s *Supervisor) invalidateProbe() {
  57. s.mu.Lock()
  58. s.binCache = ""
  59. s.mu.Unlock()
  60. }
  61. // installedVersion 读取已安装 dsh 版本(空串表示未找到)。
  62. func (s *Supervisor) installedVersion() string {
  63. binJS := s.cfg.DshBinJS
  64. if binJS == "" {
  65. binJS = s.dshBinJS()
  66. }
  67. if binJS == "" {
  68. return ""
  69. }
  70. return readPackageVersion(filepath.Join(filepath.Dir(filepath.Dir(binJS)), "package.json"))
  71. }
  72. func fileExists(p string) bool {
  73. st, err := os.Stat(p)
  74. return err == nil && !st.IsDir()
  75. }