sensorium-mcp 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/data/memory/thread-registry.js +1 -1
  2. package/dist/data/memory/thread-registry.js.map +1 -1
  3. package/dist/http-server.d.ts.map +1 -1
  4. package/dist/http-server.js +9 -1
  5. package/dist/http-server.js.map +1 -1
  6. package/dist/index.js +4 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/services/agent-spawn.service.d.ts.map +1 -1
  9. package/dist/services/agent-spawn.service.js +12 -5
  10. package/dist/services/agent-spawn.service.js.map +1 -1
  11. package/dist/services/reconnect-snapshot.service.d.ts +30 -0
  12. package/dist/services/reconnect-snapshot.service.d.ts.map +1 -0
  13. package/dist/services/reconnect-snapshot.service.js +83 -0
  14. package/dist/services/reconnect-snapshot.service.js.map +1 -0
  15. package/dist/services/thread-lifecycle.service.js +1 -1
  16. package/dist/services/thread-lifecycle.service.js.map +1 -1
  17. package/dist/services/worker-cleanup.service.d.ts.map +1 -1
  18. package/dist/services/worker-cleanup.service.js +30 -7
  19. package/dist/services/worker-cleanup.service.js.map +1 -1
  20. package/dist/sessions.d.ts +5 -0
  21. package/dist/sessions.d.ts.map +1 -1
  22. package/dist/sessions.js +7 -0
  23. package/dist/sessions.js.map +1 -1
  24. package/dist/stdio-server.d.ts.map +1 -1
  25. package/dist/stdio-server.js +7 -1
  26. package/dist/stdio-server.js.map +1 -1
  27. package/dist/tools/delegate-tool.d.ts.map +1 -1
  28. package/dist/tools/delegate-tool.js +1 -0
  29. package/dist/tools/delegate-tool.js.map +1 -1
  30. package/dist/tools/start-session-tool.d.ts.map +1 -1
  31. package/dist/tools/start-session-tool.js +9 -8
  32. package/dist/tools/start-session-tool.js.map +1 -1
  33. package/package.json +1 -1
  34. package/supervisor/config.go +1 -1
  35. package/supervisor/health.go +18 -12
  36. package/supervisor/keeper.go +27 -26
  37. package/supervisor/lock.go +1 -0
  38. package/supervisor/service_windows.go +98 -120
  39. package/supervisor/updater.go +6 -11
@@ -5,6 +5,7 @@ package main
5
5
  import (
6
6
  "fmt"
7
7
  "os"
8
+ "path/filepath"
8
9
  "time"
9
10
 
10
11
  "golang.org/x/sys/windows/svc"
@@ -58,159 +59,136 @@ func runAsService() error {
58
59
  return svc.Run(serviceName, &supervisorService{})
59
60
  }
60
61
 
61
- func installService(exePath, serviceUser, servicePassword string) error {
62
+ func withServiceManager(fn func(*mgr.Mgr) error) error {
62
63
  m, err := mgr.Connect()
63
64
  if err != nil {
64
- return fmt.Errorf("install failed: connect to service manager: %w", err)
65
+ return err
65
66
  }
66
67
  defer m.Disconnect()
68
+ return fn(m)
69
+ }
67
70
 
68
- s, err := m.OpenService(serviceName)
69
- if err == nil {
70
- s.Close()
71
- return fmt.Errorf("install failed: service %q already exists", serviceName)
72
- }
71
+ func installService(exePath, serviceUser, servicePassword string) error {
72
+ return withServiceManager(func(m *mgr.Mgr) error {
73
+ s, err := m.OpenService(serviceName)
74
+ if err == nil {
75
+ s.Close()
76
+ return fmt.Errorf("install failed: service %q already exists", serviceName)
77
+ }
73
78
 
74
- cfg := mgr.Config{
75
- DisplayName: serviceDisplay,
76
- Description: serviceDesc,
77
- StartType: mgr.StartAutomatic,
78
- DelayedAutoStart: true,
79
- }
80
- if serviceUser != "" {
81
- cfg.ServiceStartName = serviceUser
82
- cfg.Password = servicePassword
83
- if servicePassword == "" {
84
- fmt.Printf("Installing service as passwordless identity %q\n", serviceUser)
79
+ cfg := mgr.Config{
80
+ DisplayName: serviceDisplay,
81
+ Description: serviceDesc,
82
+ StartType: mgr.StartAutomatic,
83
+ DelayedAutoStart: true,
84
+ }
85
+ if serviceUser != "" {
86
+ cfg.ServiceStartName = serviceUser
87
+ cfg.Password = servicePassword
88
+ if servicePassword == "" {
89
+ fmt.Printf("Installing service as passwordless identity %q\n", serviceUser)
90
+ } else {
91
+ fmt.Printf("Installing service as user %q\n", serviceUser)
92
+ }
85
93
  } else {
86
- fmt.Printf("Installing service as user %q\n", serviceUser)
94
+ fmt.Println("Installing service as LocalSystem (default). Use -service-user to run as a specific user account.")
87
95
  }
88
- } else {
89
- fmt.Println("Installing service as LocalSystem (default). Use -service-user to run as a specific user account.")
90
- }
91
96
 
92
- s, err = m.CreateService(serviceName, exePath, cfg)
93
- if err != nil {
94
- return fmt.Errorf("install failed: create service: %w", err)
95
- }
96
- defer s.Close()
97
+ s, err = m.CreateService(serviceName, exePath, cfg)
98
+ if err != nil {
99
+ return fmt.Errorf("install failed: create service: %w", err)
100
+ }
101
+ defer s.Close()
97
102
 
98
- fmt.Printf("Service %q installed successfully.\n", serviceName)
99
- fmt.Printf("Start it with: %s start\n", filepathBase(exePath))
100
- return nil
103
+ fmt.Printf("Service %q installed successfully.\n", serviceName)
104
+ fmt.Printf("Start it with: %s start\n", filepath.Base(exePath))
105
+ return nil
106
+ })
101
107
  }
102
108
 
103
109
  func uninstallService() error {
104
- m, err := mgr.Connect()
105
- if err != nil {
106
- return fmt.Errorf("uninstall failed: connect to service manager: %w", err)
107
- }
108
- defer m.Disconnect()
109
-
110
- s, err := m.OpenService(serviceName)
111
- if err != nil {
112
- return fmt.Errorf("uninstall failed: service %q not found: %w", serviceName, err)
113
- }
114
- defer s.Close()
110
+ return withServiceManager(func(m *mgr.Mgr) error {
111
+ s, err := m.OpenService(serviceName)
112
+ if err != nil {
113
+ return fmt.Errorf("uninstall failed: service %q not found: %w", serviceName, err)
114
+ }
115
+ defer s.Close()
115
116
 
116
- if err := s.Delete(); err != nil {
117
- return fmt.Errorf("uninstall failed: delete service: %w", err)
118
- }
117
+ if err := s.Delete(); err != nil {
118
+ return fmt.Errorf("uninstall failed: delete service: %w", err)
119
+ }
119
120
 
120
- fmt.Printf("Service %q uninstalled.\n", serviceName)
121
- return nil
121
+ fmt.Printf("Service %q uninstalled.\n", serviceName)
122
+ return nil
123
+ })
122
124
  }
123
125
 
124
126
  func startService() error {
125
- m, err := mgr.Connect()
126
- if err != nil {
127
- return fmt.Errorf("start failed: connect to service manager: %w", err)
128
- }
129
- defer m.Disconnect()
130
-
131
- s, err := m.OpenService(serviceName)
132
- if err != nil {
133
- return fmt.Errorf("start failed: service %q not found: %w", serviceName, err)
134
- }
135
- defer s.Close()
127
+ return withServiceManager(func(m *mgr.Mgr) error {
128
+ s, err := m.OpenService(serviceName)
129
+ if err != nil {
130
+ return fmt.Errorf("start failed: service %q not found: %w", serviceName, err)
131
+ }
132
+ defer s.Close()
136
133
 
137
- if err := s.Start(); err != nil {
138
- return fmt.Errorf("start failed: %w", err)
139
- }
134
+ if err := s.Start(); err != nil {
135
+ return fmt.Errorf("start failed: %w", err)
136
+ }
140
137
 
141
- fmt.Printf("Service %q started.\n", serviceName)
142
- return nil
138
+ fmt.Printf("Service %q started.\n", serviceName)
139
+ return nil
140
+ })
143
141
  }
144
142
 
145
143
  func stopService() error {
146
- m, err := mgr.Connect()
147
- if err != nil {
148
- return fmt.Errorf("stop failed: connect to service manager: %w", err)
149
- }
150
- defer m.Disconnect()
151
-
152
- s, err := m.OpenService(serviceName)
153
- if err != nil {
154
- return fmt.Errorf("stop failed: service %q not found: %w", serviceName, err)
155
- }
156
- defer s.Close()
144
+ return withServiceManager(func(m *mgr.Mgr) error {
145
+ s, err := m.OpenService(serviceName)
146
+ if err != nil {
147
+ return fmt.Errorf("stop failed: service %q not found: %w", serviceName, err)
148
+ }
149
+ defer s.Close()
157
150
 
158
- if _, err := s.Control(svc.Stop); err != nil {
159
- return fmt.Errorf("stop failed: %w", err)
160
- }
151
+ if _, err := s.Control(svc.Stop); err != nil {
152
+ return fmt.Errorf("stop failed: %w", err)
153
+ }
161
154
 
162
- fmt.Printf("Service %q stopping.\n", serviceName)
163
- return nil
155
+ fmt.Printf("Service %q stopping.\n", serviceName)
156
+ return nil
157
+ })
164
158
  }
165
159
 
166
160
  func serviceStatus() error {
167
- m, err := mgr.Connect()
168
- if err != nil {
169
- return fmt.Errorf("status failed: connect to service manager: %w", err)
170
- }
171
- defer m.Disconnect()
172
-
173
- s, err := m.OpenService(serviceName)
174
- if err != nil {
175
- return fmt.Errorf("status failed: service %q not found: %w", serviceName, err)
176
- }
177
- defer s.Close()
161
+ return withServiceManager(func(m *mgr.Mgr) error {
162
+ s, err := m.OpenService(serviceName)
163
+ if err != nil {
164
+ return fmt.Errorf("status failed: service %q not found: %w", serviceName, err)
165
+ }
166
+ defer s.Close()
178
167
 
179
- st, err := s.Query()
180
- if err != nil {
181
- return fmt.Errorf("status failed: query service: %w", err)
182
- }
168
+ st, err := s.Query()
169
+ if err != nil {
170
+ return fmt.Errorf("status failed: query service: %w", err)
171
+ }
183
172
 
184
- states := map[svc.State]string{
185
- svc.Stopped: "Stopped",
186
- svc.StartPending: "StartPending",
187
- svc.StopPending: "StopPending",
188
- svc.Running: "Running",
189
- svc.ContinuePending: "ContinuePending",
190
- svc.PausePending: "PausePending",
191
- svc.Paused: "Paused",
192
- }
193
- state, ok := states[st.State]
194
- if !ok {
195
- state = fmt.Sprintf("Unknown(%d)", st.State)
196
- }
173
+ states := map[svc.State]string{
174
+ svc.Stopped: "Stopped",
175
+ svc.StartPending: "StartPending",
176
+ svc.StopPending: "StopPending",
177
+ svc.Running: "Running",
178
+ svc.ContinuePending: "ContinuePending",
179
+ svc.PausePending: "PausePending",
180
+ svc.Paused: "Paused",
181
+ }
182
+ state, ok := states[st.State]
183
+ if !ok {
184
+ state = fmt.Sprintf("Unknown(%d)", st.State)
185
+ }
197
186
 
198
- fmt.Printf("Service %q: %s\n", serviceName, state)
199
- return nil
187
+ fmt.Printf("Service %q: %s\n", serviceName, state)
188
+ return nil
189
+ })
200
190
  }
201
191
 
202
192
  func isWindowsService() (bool, error) {
203
193
  return svc.IsWindowsService()
204
194
  }
205
-
206
- func filepathBase(path string) string {
207
- if path == "" {
208
- return serviceName
209
- }
210
- for i := len(path) - 1; i >= 0; i-- {
211
- if path[i] == '\\' || path[i] == '/' {
212
- return path[i+1:]
213
- }
214
- }
215
- return path
216
- }
@@ -433,6 +433,9 @@ func (u *Updater) checkSupervisorUpdate(ctx context.Context) {
433
433
  u.state.Transition(updateScopeSupervisor, updatePhaseStaged, remote, local, "")
434
434
  notifyUpdaterOperator(u.cfg, u.log, fmt.Sprintf("⚙️ Supervisor: downloaded %s. Restarting supervisor to apply update...", remote), 0)
435
435
 
436
+ // Reset start time so minimum uptime is re-enforced after restart
437
+ u.startAt = time.Now()
438
+
436
439
  isService, err := isWindowsService()
437
440
  if err != nil {
438
441
  markFailed(err)
@@ -499,14 +502,6 @@ func (u *Updater) downloadSupervisorBinary(ctx context.Context, downloadURL stri
499
502
  return fmt.Errorf("downloaded empty binary")
500
503
  }
501
504
 
502
- info, err := os.Stat(tmpPath)
503
- if err != nil {
504
- return err
505
- }
506
- if info.Size() <= 0 {
507
- return fmt.Errorf("downloaded binary has invalid size %d", info.Size())
508
- }
509
-
510
505
  if err := os.Remove(u.cfg.Paths.PendingBinary); err != nil && !os.IsNotExist(err) {
511
506
  return err
512
507
  }
@@ -514,7 +509,7 @@ func (u *Updater) downloadSupervisorBinary(ctx context.Context, downloadURL stri
514
509
  return err
515
510
  }
516
511
 
517
- u.log.Info("Supervisor binary downloaded to %s (%d bytes)", u.cfg.Paths.PendingBinary, info.Size())
512
+ u.log.Info("Supervisor binary downloaded to %s (%d bytes)", u.cfg.Paths.PendingBinary, written)
518
513
  return nil
519
514
  }
520
515
 
@@ -548,7 +543,7 @@ func requestSupervisorRestart(log *Logger) error {
548
543
  }
549
544
 
550
545
  go func() {
551
- time.Sleep(250 * time.Millisecond)
546
+ time.Sleep(2 * time.Second)
552
547
  os.Exit(0)
553
548
  }()
554
549
 
@@ -600,7 +595,7 @@ func (u *Updater) clearNpxCache() {
600
595
  }
601
596
  pkgDir := filepath.Join(base, e.Name(), "node_modules", "sensorium-mcp")
602
597
  // Validate path doesn't escape base directory
603
- if !strings.HasPrefix(pkgDir, base) {
598
+ if !strings.HasPrefix(pkgDir, base+string(os.PathSeparator)) {
604
599
  continue
605
600
  }
606
601
  if _, err := os.Stat(pkgDir); err == nil {