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.
- package/dist/data/memory/thread-registry.js +1 -1
- package/dist/data/memory/thread-registry.js.map +1 -1
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +9 -1
- package/dist/http-server.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/services/agent-spawn.service.d.ts.map +1 -1
- package/dist/services/agent-spawn.service.js +12 -5
- package/dist/services/agent-spawn.service.js.map +1 -1
- package/dist/services/reconnect-snapshot.service.d.ts +30 -0
- package/dist/services/reconnect-snapshot.service.d.ts.map +1 -0
- package/dist/services/reconnect-snapshot.service.js +83 -0
- package/dist/services/reconnect-snapshot.service.js.map +1 -0
- package/dist/services/thread-lifecycle.service.js +1 -1
- package/dist/services/thread-lifecycle.service.js.map +1 -1
- package/dist/services/worker-cleanup.service.d.ts.map +1 -1
- package/dist/services/worker-cleanup.service.js +30 -7
- package/dist/services/worker-cleanup.service.js.map +1 -1
- package/dist/sessions.d.ts +5 -0
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +7 -0
- package/dist/sessions.js.map +1 -1
- package/dist/stdio-server.d.ts.map +1 -1
- package/dist/stdio-server.js +7 -1
- package/dist/stdio-server.js.map +1 -1
- package/dist/tools/delegate-tool.d.ts.map +1 -1
- package/dist/tools/delegate-tool.js +1 -0
- package/dist/tools/delegate-tool.js.map +1 -1
- package/dist/tools/start-session-tool.d.ts.map +1 -1
- package/dist/tools/start-session-tool.js +9 -8
- package/dist/tools/start-session-tool.js.map +1 -1
- package/package.json +1 -1
- package/supervisor/config.go +1 -1
- package/supervisor/health.go +18 -12
- package/supervisor/keeper.go +27 -26
- package/supervisor/lock.go +1 -0
- package/supervisor/service_windows.go +98 -120
- 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
|
|
62
|
+
func withServiceManager(fn func(*mgr.Mgr) error) error {
|
|
62
63
|
m, err := mgr.Connect()
|
|
63
64
|
if err != nil {
|
|
64
|
-
return
|
|
65
|
+
return err
|
|
65
66
|
}
|
|
66
67
|
defer m.Disconnect()
|
|
68
|
+
return fn(m)
|
|
69
|
+
}
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
s.
|
|
71
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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.
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
if err := s.Delete(); err != nil {
|
|
118
|
+
return fmt.Errorf("uninstall failed: delete service: %w", err)
|
|
119
|
+
}
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
fmt.Printf("Service %q uninstalled.\n", serviceName)
|
|
122
|
+
return nil
|
|
123
|
+
})
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
func startService() error {
|
|
125
|
-
m
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
if err := s.Start(); err != nil {
|
|
135
|
+
return fmt.Errorf("start failed: %w", err)
|
|
136
|
+
}
|
|
140
137
|
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
fmt.Printf("Service %q started.\n", serviceName)
|
|
139
|
+
return nil
|
|
140
|
+
})
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
func stopService() error {
|
|
146
|
-
m
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
if _, err := s.Control(svc.Stop); err != nil {
|
|
152
|
+
return fmt.Errorf("stop failed: %w", err)
|
|
153
|
+
}
|
|
161
154
|
|
|
162
|
-
|
|
163
|
-
|
|
155
|
+
fmt.Printf("Service %q stopping.\n", serviceName)
|
|
156
|
+
return nil
|
|
157
|
+
})
|
|
164
158
|
}
|
|
165
159
|
|
|
166
160
|
func serviceStatus() error {
|
|
167
|
-
m
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
168
|
+
st, err := s.Query()
|
|
169
|
+
if err != nil {
|
|
170
|
+
return fmt.Errorf("status failed: query service: %w", err)
|
|
171
|
+
}
|
|
183
172
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
}
|
package/supervisor/updater.go
CHANGED
|
@@ -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,
|
|
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(
|
|
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 {
|