sensorium-mcp 3.0.80 → 3.0.84
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/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +131 -1
- package/dist/config.js.map +1 -1
- package/dist/dashboard/routes/threads.d.ts +6 -0
- package/dist/dashboard/routes/threads.d.ts.map +1 -1
- package/dist/dashboard/routes/threads.js +164 -9
- package/dist/dashboard/routes/threads.js.map +1 -1
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +13 -1
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/dashboard/spa.html +10 -10
- package/dist/data/memory/semantic.d.ts +6 -0
- package/dist/data/memory/semantic.d.ts.map +1 -1
- package/dist/data/memory/semantic.js +19 -0
- package/dist/data/memory/semantic.js.map +1 -1
- package/dist/services/claude-spawn.service.d.ts.map +1 -1
- package/dist/services/claude-spawn.service.js +4 -1
- package/dist/services/claude-spawn.service.js.map +1 -1
- package/dist/services/codex-spawn.service.js +2 -2
- package/dist/services/codex-spawn.service.js.map +1 -1
- package/dist/services/copilot-spawn.service.js +1 -1
- package/dist/services/copilot-spawn.service.js.map +1 -1
- package/dist/services/mcp-config.service.d.ts +14 -2
- package/dist/services/mcp-config.service.d.ts.map +1 -1
- package/dist/services/mcp-config.service.js +65 -5
- package/dist/services/mcp-config.service.js.map +1 -1
- package/package.json +1 -1
- package/templates/playwright.default.md +18 -6
- package/templates/sensorium-repair.default.md +17 -5
|
@@ -27,7 +27,8 @@ You are repairing **Sensorium itself** (this MCP server + its .NET supervisor)
|
|
|
27
27
|
- **Root cause over symptoms.** A restart "fixes" nothing if the bug recurs. Find the exact file:line and the commit that introduced it.
|
|
28
28
|
- **Verify file contents via terminal, never trust cached reads.** The `read_file` tool can serve a STALE copy (it served an old `package.json` version during a real incident). For anything you will edit or reason about critically, confirm with `git show HEAD:<path>` or `Get-Content <path>`.
|
|
29
29
|
- **Never trust a subagent's described diff.** Subagents have hallucinated multi-hundred-line diffs for files that were clean. Always confirm with `git diff` / `git status` in a terminal yourself.
|
|
30
|
-
- **
|
|
30
|
+
- **Phantom working-tree changes = stale VS Code editor buffers.** Files silently reverting to OLD versions on disk (a committed fix undone, `package.json` version rolled back) is caused by VS Code `files.autoSave` + `files.hotExit` writing a stale editor buffer to disk — NOT an agent, NOT you editing manually. It's the same mechanism that "clobbers" AI-edited files mid-session. Confirm: `git status`/`git diff` shows a stale revert; check `%APPDATA%\Code\Backups\**` for hot-exit backups whose mtime is *after* your last save (⇒ an unreloaded window is holding a stale buffer). Fix permanently: set `"files.autoSave": "off"` + `"files.hotExit": "off"` in User settings, then `Revert File` on the stale tabs and reload the window. Until the window reloads, the risk persists for it.
|
|
31
|
+
- **Watch for concurrent autonomous agents.** A Sensorium worker may be committing to this repo *while you work*. Re-check `git HEAD`, branch, and `git log` before and after edits; a fix you were about to write may already be committed. (But a spontaneous working-tree revert is usually the VS-Code-buffer issue above, not an agent — verify file mtimes: an agent write shows a recent mtime, a buffer flush may not.)
|
|
31
32
|
- **Git safety:** stage explicit paths only. NEVER `git add -A/./-u`, `git commit -a`. NEVER commit `tmp_*`, dumps, screenshots, or binaries.
|
|
32
33
|
- **Deploy ≠ push.** Pushing to git does not update the running system (see "Ship & deploy").
|
|
33
34
|
|
|
@@ -37,8 +38,8 @@ You are repairing **Sensorium itself** (this MCP server + its .NET supervisor)
|
|
|
37
38
|
- **Logs** under `~/.remote-copilot-mcp/logs/`:
|
|
38
39
|
- `mcp/server.log` — MCP app log (rotated ~5 MB).
|
|
39
40
|
- `mcp/mcp-stderr-YYYYMMDD.log` — captured MCP stderr (fatal errors, startup banners, `[wait]`/`[telegram]` activity).
|
|
40
|
-
- `supervisor/supervisor-YYYYMMDD.log` — supervisor restart/health decisions (very noisy with Telegram `getUpdates`; filter it out).
|
|
41
|
-
- **Process model:** the .NET supervisor process `sensorium-supervisor` supervises a Node MCP server (**HTTP port 3847**) + watcher (**3848**). MCP start command is either `node dist/index.js` (local build) or `npx -y sensorium-mcp@latest` (published). Workers are `claude`/`codex`/`copilot` processes whose command line references `.remote-copilot-mcp
|
|
41
|
+
- `supervisor/supervisor-YYYYMMDD.log` — supervisor restart/health decisions (very noisy with Telegram `getUpdates`; filter it out). **Timezone caveat:** MCP logs (`server.log`, `mcp-stderr`) are **UTC** (`...Z`); the supervisor log was historically **LOCAL**, but a `UtcTimestampFormatter` change can switch it to UTC — always cross-reference one shared event (e.g. "MCP server is ready" vs the node startup banner) to confirm which, before correlating timestamps.
|
|
42
|
+
- **Process model:** the .NET supervisor process `sensorium-supervisor` supervises a Node MCP server (**HTTP port 3847**) + watcher (**3848**). MCP start command is either `node dist/index.js` (local build) or `npx -y sensorium-mcp@latest` (published). Workers are `claude`/`codex`/`copilot` processes whose command line references `.remote-copilot-mcp` — **a process check that queries only `node`/`sensorium-supervisor` will MISS every worker and falsely report "no threads running." Always include `claude,codex,copilot`.**
|
|
42
43
|
- **`~/.remote-copilot-mcp/server.pid`** holds `{"pid":N}` — should match the port-3847 owner. A mismatch is the signature of a false-death loop.
|
|
43
44
|
- **Windows: `git` is often NOT on PATH.** Locate it (`%LOCALAPPDATA%\Programs\Git\cmd\git.exe` or `C:\Program Files\Git\cmd\git.exe`) and call it by full path.
|
|
44
45
|
- **Prior root causes are logged in memory:** read `/memories/repo/critical-fixes-log.md`, `/memories/repo/keeper-stuck-detection-bug.md`, `/memories/repo/sensorium-architecture.md` before theorizing — the bug may be known.
|
|
@@ -63,7 +64,8 @@ You are repairing **Sensorium itself** (this MCP server + its .NET supervisor)
|
|
|
63
64
|
- **Keeper "stuck" kills keepAlive threads.** `wait_for_instructions` long-poll didn't refresh the per-thread heartbeat → keeper declared stuck → killed. Fix: write `writeThreadHeartbeat()` in the poll loop.
|
|
64
65
|
- **Duplicate thread spawns.** Keeper checks the root threadId but `start_thread` creates a worker with a different id → always "not running" → re-spawns. Fix: track the worker id from the `start_thread` response.
|
|
65
66
|
- **Copilot process dies / no memory.** `copilot.bat` (VS Code wrapper) spawned detached dies silently — prefer `copilot.exe`; and a missing `thread_id` column crashed bootstrap. See critical-fixes-log.
|
|
66
|
-
- **
|
|
67
|
+
- **Reads but no reply — Claude worker answers into invisible stdout.** 👀 is set on message *consume*, not on reply (so 👀 ≠ answered). With Claude tool search active, reply tools (`report_progress`/`send_voice`/`send_message_to_thread`) are deferred, so a conversational agent emits answers as plain `text` → its stdout transcript, never delivered. Signature: `server.log` `Read N messages … Processing…` with no following delivery `tool_use`. First rule out routing (operator's topic must equal the thread's `thread_registry.telegram_topic_id`; inbound `resolveThreadForTopic`/outbound `resolveTelegramTopicId` are symmetric). Fix: `ENABLE_TOOL_SEARCH=false` so tools load upfront, then **respawn the worker** (see Deploy).
|
|
68
|
+
- **Self-update port-handoff race (real but often MIS-attributed — do not over-chase).** In theory a new node self-registers its pid asynchronously, so `server.pid` can transiently name a dead pid while HTTP is healthy. BUT the self-update poller is gated behind a ~10-min min-uptime **AND** `remoteVersion !== currentVersion`, so at the latest published version it is a silent no-op. Before blaming self-update, confirm it is ACTUALLY firing: look for `[self-update] New version detected` / `Closing HTTP server` and a non-empty `update-spawn.log`; a `[self-update] Deferring — uptime …s < min 600s` line proves it is NOT updating. In practice the recent restart loops were **event-loop freeze** (heavy startup work) and **network outages to Telegram**, not self-update.
|
|
67
69
|
|
|
68
70
|
## Emergency stop & restart
|
|
69
71
|
|
|
@@ -91,9 +93,19 @@ Then `Stop-Process -Id <pid> -Force` in the order above. Verify ports 3847/3848
|
|
|
91
93
|
- **Ship:** `npm version patch --no-git-tag-version` → commit explicit paths (`fix(...)` then `chore(release): x.y.z`) → `git push origin main`.
|
|
92
94
|
- **CI:** confirm green — `gh run watch <run-id> --repo <owner>/<repo> --exit-status`. Fix and re-push until green.
|
|
93
95
|
- **Deploy at runtime (push alone does NOT deploy):**
|
|
94
|
-
- **MCP server** running via `npx sensorium-mcp@latest` picks up a new version only after **`npm publish`** (the watcher auto-updates). A local `node dist/index.js` needs `npm run build`.
|
|
96
|
+
- **MCP server** running via `npx sensorium-mcp@latest` picks up a new version only after **`npm publish`** (the watcher auto-updates). A local `node dist/index.js` needs `npm run build`. **Already-running workers keep their old spawn behavior even after the server updates — respawn them to apply spawn-side fixes.** `ENABLE_TOOL_SEARCH=false` is the right knob (Claude ≥2.1.7), but an `env` block in `~/.claude/settings.json` overrides the spawn env, and the spawn copies that file wholesale into the per-thread `CLAUDE_CONFIG_DIR` (dragging in the operator's own MCP servers).
|
|
95
97
|
- **Supervisor** (.NET) needs a **rebuild + reinstall via `Install-Sensorium.ps1`** to apply supervisor code changes — a running supervisor keeps its old binary in memory.
|
|
96
98
|
|
|
99
|
+
## Field notes (hard-won — check these before deep code work)
|
|
100
|
+
|
|
101
|
+
- **"No threads connected" / a thread won't respond is usually NOT a dead thread.** First confirm liveness, don't assume: heartbeats in `~/.remote-copilot-mcp/heartbeats/{threadId}` fresh (age < ~5s) + a live `claude` worker per `pids/{threadId}.pid` = the thread IS alive. If threads are alive but the operator can't reach them, the break is the **Telegram delivery path** or the agent replying into stdout (see failure modes), not the thread.
|
|
102
|
+
- **The Claude worker's stream-json transcript is ground truth for agent behavior** — `~/.remote-copilot-mcp/logs/threads/<Name>_<threadId>_<YYYY-MM-DD>.json` (NDJSON; file-fd stdout+stderr, survives server restarts). Per `type:"assistant"` block: `text` = invisible to operator, `tool_use` of a delivery tool = actually sent. `type:"rate_limit_event"` = Claude 5-hour cap (`resetsAt` = epoch secs); `subtype:"api_retry"` = transient API errors. Fresh MCP heartbeat + **stale transcript mtime** = worker idle in the long-poll (normal), not frozen.
|
|
103
|
+
- **`[dispatcher] Poll error: fetch failed` (repeating every ~6s) + `.NET` supervisor `SocketException 10054 "connection forcibly closed by remote host"` = a NETWORK outage to `api.telegram.org`, not a code bug.** On laptops this correlates with Wi-Fi drops / Modern Standby / power-source flapping (see Windows Event Log `Kernel-Power` 105/506/507). Test reachability directly: `Resolve-DnsName api.telegram.org`, `Test-NetConnection api.telegram.org -Port 443`, `Invoke-WebRequest https://api.telegram.org -Method Head`. If those pass but the MCP still shows no successful polls, the dispatcher may not have recovered from the socket reset → **restart the MCP** to re-establish polling.
|
|
104
|
+
- **Responsive vs frozen vs exited — three different states, check explicitly.** `Invoke-WebRequest -Method Options http://127.0.0.1:3847/{health,ready,mcp}` returning **204** + `Get-Process -Id <pid>` `Responding=True` = event loop ALIVE (so any "silence" is a stuck sub-loop like the Telegram poller, not a freeze). No HTTP answer but port still LISTENing = frozen. Port CLOSED (`connection refused`) = process EXITED.
|
|
105
|
+
- **Use the lifecycle instrumentation (shipped 3.0.79+).** On a death, `server.log` gets `[lifecycle] process exit code=N uptime=Ns`; a real OS signal logs `[lifecycle] received signal ...`; a native fatal error writes `report*.json` in `logs/mcp/`; an internal self-kill attempt logs `[process] killProcessTree pid=… caller=…` or `[process] REFUSED kill … self-protection`. **`exit code=0 uptime=0-2s` markers are BENIGN** — short-lived launcher/duplicate processes that found the port taken and bailed cleanly, not the real server dying.
|
|
106
|
+
- **Windows Event Log is decisive for native crash vs external kill.** No `Application Error` (Event 1000) for `node.exe` at the death time ⇒ **not** a native crash (e.g. not `better_sqlite3`). No `[lifecycle]`/`[shutdown]`/`[fatal]` line either ⇒ the process was hard-killed externally (`taskkill /F` / `TerminateProcess`, which bypass signal handlers and WER) — audit the internal kill paths (`killProcessTree caller=…`) and any second supervisor doing `KillByPort`.
|
|
107
|
+
- **Event-loop freeze death-spiral.** Heavy synchronous startup work (better-sqlite3 consolidation, narrative backfill, per-thread `start_session` bootstrap embeddings across many reconnecting threads) blocks the loop past the supervisor's ~3s HTTP readiness probe → supervisor kills+respawns → the fresh process re-runs the same work → re-freeze. Mitigations: persist a per-day marker so consolidation/rotation run **once per day** across restarts (`src/data/daily-marker.ts`); defer/chunk heavy startup work off the readiness window.
|
|
108
|
+
|
|
97
109
|
## After an incident
|
|
98
110
|
|
|
99
111
|
Record the root cause, the fix, the commit hash, and the version in `/memories/repo/critical-fixes-log.md` (append, don't rewrite) so the next repair starts from knowledge, not zero.
|