sensorium-mcp 2.17.26 → 2.17.27

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 (66) hide show
  1. package/dist/dashboard/routes/threads.d.ts.map +1 -1
  2. package/dist/dashboard/routes/threads.js +18 -5
  3. package/dist/dashboard/routes/threads.js.map +1 -1
  4. package/dist/data/memory/bootstrap.js +2 -2
  5. package/dist/data/memory/bootstrap.js.map +1 -1
  6. package/dist/data/memory/consolidation.d.ts.map +1 -1
  7. package/dist/data/memory/consolidation.js +75 -4
  8. package/dist/data/memory/consolidation.js.map +1 -1
  9. package/dist/data/memory/index.d.ts +1 -0
  10. package/dist/data/memory/index.d.ts.map +1 -1
  11. package/dist/data/memory/index.js +1 -0
  12. package/dist/data/memory/index.js.map +1 -1
  13. package/dist/data/memory/quality-scoring.d.ts +32 -0
  14. package/dist/data/memory/quality-scoring.d.ts.map +1 -0
  15. package/dist/data/memory/quality-scoring.js +182 -0
  16. package/dist/data/memory/quality-scoring.js.map +1 -0
  17. package/dist/data/memory/semantic.d.ts +12 -0
  18. package/dist/data/memory/semantic.d.ts.map +1 -1
  19. package/dist/data/memory/semantic.js +45 -2
  20. package/dist/data/memory/semantic.js.map +1 -1
  21. package/dist/data/memory/thread-registry.d.ts +7 -0
  22. package/dist/data/memory/thread-registry.d.ts.map +1 -1
  23. package/dist/data/memory/thread-registry.js +11 -1
  24. package/dist/data/memory/thread-registry.js.map +1 -1
  25. package/dist/index.js +17 -5
  26. package/dist/index.js.map +1 -1
  27. package/dist/tools/defs/memory-defs.d.ts.map +1 -1
  28. package/dist/tools/defs/memory-defs.js +19 -0
  29. package/dist/tools/defs/memory-defs.js.map +1 -1
  30. package/dist/tools/memory-tools.d.ts.map +1 -1
  31. package/dist/tools/memory-tools.js +15 -0
  32. package/dist/tools/memory-tools.js.map +1 -1
  33. package/dist/tools/thread-lifecycle.d.ts.map +1 -1
  34. package/dist/tools/thread-lifecycle.js +31 -17
  35. package/dist/tools/thread-lifecycle.js.map +1 -1
  36. package/package.json +10 -2
  37. package/scripts/install-supervisor.ps1 +67 -0
  38. package/scripts/install-supervisor.sh +43 -0
  39. package/scripts/start-supervisor.ps1 +46 -0
  40. package/scripts/start-supervisor.sh +20 -0
  41. package/supervisor/config.go +140 -0
  42. package/supervisor/go.mod +3 -0
  43. package/supervisor/health.go +390 -0
  44. package/supervisor/health_test.go +93 -0
  45. package/supervisor/keeper.go +303 -0
  46. package/supervisor/keeper_test.go +27 -0
  47. package/supervisor/lock.go +56 -0
  48. package/supervisor/lock_test.go +54 -0
  49. package/supervisor/log.go +114 -0
  50. package/supervisor/log_test.go +45 -0
  51. package/supervisor/main.go +325 -0
  52. package/supervisor/notify.go +53 -0
  53. package/supervisor/process.go +222 -0
  54. package/supervisor/process_test.go +94 -0
  55. package/supervisor/process_unix.go +14 -0
  56. package/supervisor/process_windows.go +15 -0
  57. package/supervisor/updater.go +281 -0
  58. package/templates/coding-task.default.md +12 -0
  59. package/dist/claude-keeper.d.ts +0 -24
  60. package/dist/claude-keeper.d.ts.map +0 -1
  61. package/dist/claude-keeper.js +0 -374
  62. package/dist/claude-keeper.js.map +0 -1
  63. package/dist/watcher-service.d.ts +0 -2
  64. package/dist/watcher-service.d.ts.map +0 -1
  65. package/dist/watcher-service.js +0 -997
  66. package/dist/watcher-service.js.map +0 -1
@@ -0,0 +1,15 @@
1
+ //go:build windows
2
+
3
+ package main
4
+
5
+ import (
6
+ "os/exec"
7
+ "syscall"
8
+ )
9
+
10
+ func setSysProcAttr(cmd *exec.Cmd) {
11
+ cmd.SysProcAttr = &syscall.SysProcAttr{
12
+ CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
13
+ HideWindow: true,
14
+ }
15
+ }
@@ -0,0 +1,281 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "fmt"
7
+ "net/http"
8
+ "os"
9
+ "path/filepath"
10
+ "runtime"
11
+ "strings"
12
+ "time"
13
+ )
14
+
15
+ const registryURL = "https://registry.npmjs.org/sensorium-mcp/latest"
16
+
17
+ // Updater checks the npm registry for new versions and performs updates.
18
+ type Updater struct {
19
+ cfg Config
20
+ mcp *MCPClient
21
+ log *Logger
22
+ startAt time.Time
23
+ cancel context.CancelFunc
24
+ done chan struct{}
25
+ }
26
+
27
+ func NewUpdater(cfg Config, mcp *MCPClient, log *Logger) *Updater {
28
+ return &Updater{
29
+ cfg: cfg,
30
+ mcp: mcp,
31
+ log: log,
32
+ startAt: time.Now(),
33
+ done: make(chan struct{}),
34
+ }
35
+ }
36
+
37
+ // Start begins the update check loop.
38
+ func (u *Updater) Start() {
39
+ ctx, cancel := context.WithCancel(context.Background())
40
+ u.cancel = cancel
41
+ go u.run(ctx)
42
+ }
43
+
44
+ // Stop signals the updater to shut down and waits.
45
+ func (u *Updater) Stop() {
46
+ if u.cancel != nil {
47
+ u.cancel()
48
+ }
49
+ <-u.done
50
+ }
51
+
52
+ func (u *Updater) run(ctx context.Context) {
53
+ defer close(u.done)
54
+ u.log.Info("Updater started (mode=%s)", u.cfg.Mode)
55
+
56
+ // In development mode, check every PollInterval.
57
+ // In production, check once per day at PollAtHour.
58
+ for {
59
+ var sleepDuration time.Duration
60
+ if u.cfg.Mode == "development" {
61
+ sleepDuration = u.cfg.PollInterval
62
+ } else {
63
+ sleepDuration = u.timeUntilNextPoll()
64
+ }
65
+ u.log.Debug("Updater: next version check in %v", sleepDuration.Round(time.Second))
66
+
67
+ select {
68
+ case <-ctx.Done():
69
+ return
70
+ case <-time.After(sleepDuration):
71
+ }
72
+
73
+ if ctx.Err() != nil {
74
+ return
75
+ }
76
+
77
+ u.checkAndUpdate(ctx)
78
+ }
79
+ }
80
+
81
+ func (u *Updater) timeUntilNextPoll() time.Duration {
82
+ now := time.Now()
83
+ next := time.Date(now.Year(), now.Month(), now.Day(), u.cfg.PollAtHour, 0, 0, 0, now.Location())
84
+ if next.Before(now) {
85
+ next = next.Add(24 * time.Hour)
86
+ }
87
+ return time.Until(next)
88
+ }
89
+
90
+ // getRemoteVersion fetches the latest version from npm registry.
91
+ func (u *Updater) getRemoteVersion(ctx context.Context) (string, error) {
92
+ ctx2, cancel := context.WithTimeout(ctx, 15*time.Second)
93
+ defer cancel()
94
+
95
+ req, err := http.NewRequestWithContext(ctx2, "GET", registryURL, nil)
96
+ if err != nil {
97
+ return "", err
98
+ }
99
+
100
+ resp, err := http.DefaultClient.Do(req)
101
+ if err != nil {
102
+ return "", err
103
+ }
104
+ defer resp.Body.Close()
105
+
106
+ if resp.StatusCode != 200 {
107
+ return "", fmt.Errorf("npm registry HTTP %d", resp.StatusCode)
108
+ }
109
+
110
+ var pkg struct {
111
+ Version string `json:"version"`
112
+ }
113
+ if err := json.NewDecoder(resp.Body).Decode(&pkg); err != nil {
114
+ return "", err
115
+ }
116
+ return pkg.Version, nil
117
+ }
118
+
119
+ // getLocalVersion reads the current version from the version file.
120
+ func (u *Updater) getLocalVersion() string {
121
+ data, err := os.ReadFile(u.cfg.Paths.VersionFile)
122
+ if err != nil {
123
+ return ""
124
+ }
125
+ return strings.TrimSpace(string(data))
126
+ }
127
+
128
+ func (u *Updater) setLocalVersion(v string) {
129
+ os.MkdirAll(u.cfg.DataDir, 0755)
130
+ if err := atomicWrite(u.cfg.Paths.VersionFile, []byte(v)); err != nil {
131
+ u.log.Warn("Failed to write version file: %v", err)
132
+ }
133
+ }
134
+
135
+ func (u *Updater) checkAndUpdate(ctx context.Context) {
136
+ // Enforce minimum uptime before updating
137
+ uptime := time.Since(u.startAt)
138
+ if uptime < u.cfg.MinUptime {
139
+ u.log.Info("Deferring update — too early (uptime %v < %v)", uptime.Round(time.Second), u.cfg.MinUptime)
140
+ return
141
+ }
142
+
143
+ remote, err := u.getRemoteVersion(ctx)
144
+ if err != nil {
145
+ u.log.Warn("Failed to check npm registry: %v", err)
146
+ return
147
+ }
148
+
149
+ local := u.getLocalVersion()
150
+ if local == "" {
151
+ u.log.Info("No local version recorded — storing %s", remote)
152
+ u.setLocalVersion(remote)
153
+ return
154
+ }
155
+
156
+ if local == remote {
157
+ u.log.Debug("Updater: version %s is up to date", local)
158
+ return
159
+ }
160
+
161
+ u.log.Info("Update available: %s → %s", local, remote)
162
+ NotifyOperator(u.cfg, u.log, fmt.Sprintf("⚙️ Supervisor: updating sensorium v%s → v%s. Grace period %v...", local, remote, u.cfg.GracePeriod), 0)
163
+
164
+ // Grace period
165
+ u.log.Info("Grace period %v...", u.cfg.GracePeriod)
166
+ select {
167
+ case <-ctx.Done():
168
+ return
169
+ case <-time.After(u.cfg.GracePeriod):
170
+ }
171
+
172
+ // Set maintenance flag — always clean up on exit
173
+ if err := atomicWrite(u.cfg.Paths.MaintenanceFlag, []byte(time.Now().Format(time.RFC3339))); err != nil {
174
+ u.log.Warn("Failed to write maintenance flag: %v", err)
175
+ }
176
+ defer os.Remove(u.cfg.Paths.MaintenanceFlag)
177
+
178
+ // Kill the current MCP server
179
+ if ctx.Err() != nil {
180
+ return
181
+ }
182
+ u.killServer()
183
+
184
+ // Clean npx cache
185
+ if ctx.Err() != nil {
186
+ return
187
+ }
188
+ u.clearNpxCache()
189
+
190
+ // Spawn new server — retry up to 3 times on failure
191
+ var pid int
192
+ for attempt := 1; attempt <= 3; attempt++ {
193
+ if ctx.Err() != nil {
194
+ return
195
+ }
196
+ pid, err = SpawnMCPServer(u.cfg, u.log)
197
+ if err == nil {
198
+ break
199
+ }
200
+ u.log.Error("Failed to spawn updated MCP server (attempt %d/3): %v", attempt, err)
201
+ if attempt < 3 {
202
+ time.Sleep(2 * time.Second)
203
+ }
204
+ }
205
+ if err != nil {
206
+ u.log.Error("All spawn attempts failed — server is down!")
207
+ NotifyOperator(u.cfg, u.log, "🔴 Supervisor: update FAILED — server is down! Manual intervention required.", 0)
208
+ return
209
+ }
210
+
211
+ // Wait for new server to be ready
212
+ if u.mcp.WaitForReady(ctx, 3*time.Second, 60*time.Second) {
213
+ u.log.Info("Updated MCP server ready (PID %d)", pid)
214
+ } else {
215
+ u.log.Warn("Updated server did not become ready in 60s")
216
+ }
217
+
218
+ u.setLocalVersion(remote)
219
+
220
+ NotifyOperator(u.cfg, u.log, fmt.Sprintf("✅ Supervisor: update to v%s complete. Server ready.", remote), 0)
221
+ u.log.Info("Update complete: v%s → v%s", local, remote)
222
+
223
+ // Reset start time for min uptime tracking
224
+ u.startAt = time.Now()
225
+ }
226
+
227
+ func (u *Updater) killServer() {
228
+ u.log.Info("Updater: stopping current MCP server for update")
229
+ pid, err := ReadPIDFile(u.cfg.Paths.ServerPID)
230
+ if err != nil {
231
+ u.log.Warn("Could not read server PID file: %v", err)
232
+ // Try killing by port as fallback
233
+ KillByPort(u.cfg.MCPHttpPort, u.log)
234
+ return
235
+ }
236
+ if err := KillProcess(pid, u.log); err != nil {
237
+ u.log.Error("Failed to kill server (PID %d): %v", pid, err)
238
+ KillByPort(u.cfg.MCPHttpPort, u.log)
239
+ }
240
+ }
241
+
242
+ // clearNpxCache removes the cached sensorium-mcp package from the npx cache
243
+ // so the next `npx -y sensorium-mcp@latest` fetches the new version.
244
+ func (u *Updater) clearNpxCache() {
245
+ u.log.Info("Updater: clearing npx cache")
246
+ var base string
247
+ if runtime.GOOS == "windows" {
248
+ localAppData := os.Getenv("LOCALAPPDATA")
249
+ if localAppData == "" {
250
+ home, _ := os.UserHomeDir()
251
+ localAppData = filepath.Join(home, "AppData", "Local")
252
+ }
253
+ base = filepath.Join(localAppData, "npm-cache", "_npx")
254
+ } else {
255
+ home, _ := os.UserHomeDir()
256
+ base = filepath.Join(home, ".npm", "_npx")
257
+ }
258
+
259
+ u.log.Info("Clearing sensorium-mcp from npx cache (%s)", base)
260
+
261
+ entries, err := os.ReadDir(base)
262
+ if err != nil {
263
+ return
264
+ }
265
+
266
+ for _, e := range entries {
267
+ if !e.IsDir() {
268
+ continue
269
+ }
270
+ pkgDir := filepath.Join(base, e.Name(), "node_modules", "sensorium-mcp")
271
+ // Validate path doesn't escape base directory
272
+ if !strings.HasPrefix(pkgDir, base) {
273
+ continue
274
+ }
275
+ if _, err := os.Stat(pkgDir); err == nil {
276
+ if err := os.RemoveAll(pkgDir); err != nil {
277
+ u.log.Warn("Failed to clear npx cache entry %s: %v", pkgDir, err)
278
+ }
279
+ }
280
+ }
281
+ }
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: Coding Task
3
+ triggers:
4
+ - code
5
+ - coding
6
+ - implement
7
+ replaces_orchestrator: true
8
+ ---
9
+
10
+ # Coding Task Skill
11
+
12
+ Load clean code skill before proceeding with the main task. Run an expert code review after implementation.
@@ -1,24 +0,0 @@
1
- /**
2
- * Thread keeper — monitors keep-alive threads and restarts them
3
- * via the start_thread MCP tool when they stop running.
4
- *
5
- * No direct process spawning — delegates to start_thread which handles
6
- * all lifecycle concerns (PID tracking, registry updates, MCP config).
7
- */
8
- export interface KeeperConfig {
9
- threadId: number;
10
- sessionName: string;
11
- client: string;
12
- mcpHttpPort: number;
13
- mcpHttpSecret: string | null;
14
- workingDirectory?: string;
15
- maxRetries?: number;
16
- cooldownMs?: number;
17
- /** Called when the keeper detects the thread process has died. */
18
- onDeath?: (threadId: number, sessionName: string) => void;
19
- }
20
- export interface KeeperHandle {
21
- stop(): Promise<void>;
22
- }
23
- export declare function startClaudeKeeper(config: KeeperConfig): Promise<KeeperHandle>;
24
- //# sourceMappingURL=claude-keeper.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claude-keeper.d.ts","sourceRoot":"","sources":["../src/claude-keeper.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuBH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AA4OD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAgHnF"}