Layer 2 MCP Watcher v0 scaffold
Per spec/agent-watcher.md §4. TypeScript/Node implementation living in
mcp-watcher/ subdirectory, parallel to Layer 1 Collector at repo root.
What lands:
- Core MCP server (src/server.ts) with experimental['claude/channel']:{}
+ tools:{} capability declarations, stdio transport, channel-event
notifier wired through the inbox watcher.
- Identity resolution mirroring agent-ping's layered model
(PING_AGENT_IDENTITY env, $CLAUDE_HOME/ping-agent, ~/.ping-agent).
- Inbox reader with HWM tracking, sentinel deferral (warn-after-3),
atomic HWM writes via tmp+rename.
- chokidar-backed file watcher with coalesced drain, urgent-first
ordering, recentEvents map for tool sender lookup.
- Three reply tools (ack / respond / mark_handled) with cross-host
write discipline (writes to local inbox files; Syncthing replicates).
- Sentinel file (.<agent>.watcher-active) for hook coexistence per
spec §4.3 — agent-ping hook stands down when the watcher is in
charge of delivery on this host. Sentinel + hwm in .stignore.
- 35 unit tests passing (vitest): inbox parsing, HWM round-trip,
sentinel deferral semantics, identity layers, tool I/O, watcher
drain + ordering + restart-from-hwm.
- install.sh (Angus-executed, rule-2 compliant) installs deps,
builds, symlinks ~/.local/bin/agent-watcher-mcp, prints mcp.json
registration snippet for paste.
- README documents launch flag, sandbox CLAUDE_HOME pattern,
hook coexistence, observability, v2 limitations.
Not yet:
- Integration test against a real Claude Code session — gated on
Angus spinning up a sandbox CC session on the VPS with
CLAUDE_HOME=~/.claude-sandbox.
- agent-ping hook update to read the sentinel and stand down.
Separate small PR against agent-ping.
Interface contract with Layer 1: the inbox JSONL line shape from
inbox.ts::PingEvent matches inbox.Event in the Collector — bit-
identical reads regardless of source.
This commit is contained in:
parent
3eda72df28
commit
c22558c67a
18 changed files with 4786 additions and 0 deletions
118
mcp-watcher/install.sh
Executable file
118
mcp-watcher/install.sh
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env bash
|
||||
# install.sh — set up the agent-watcher MCP Watcher (Layer 2) on this host.
|
||||
#
|
||||
# Usage:
|
||||
# ./install.sh # install: npm ci, build, link binary, print mcp.json snippet
|
||||
# ./install.sh --no-mcp-json # everything but the mcp.json snippet (you handle registration)
|
||||
#
|
||||
# What it does:
|
||||
# 1. Verifies Node 18+ is available.
|
||||
# 2. Installs dependencies (npm ci) and builds (tsc).
|
||||
# 3. Symlinks dist/server.js to ~/.local/bin/agent-watcher-mcp (chmod +x).
|
||||
# 4. Adds .stignore patterns for the local-only watcher-active sentinel.
|
||||
# 5. Prints the mcp.json snippet for paste into Claude Code's config.
|
||||
#
|
||||
# Per CLAUDE.md rule #2, this is intended to be run by a human. The MCP
|
||||
# Watcher itself, like agent-ping, never invokes this script.
|
||||
#
|
||||
# Layer 1 (Collector) has its own install path. See the repo root install.sh.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
NO_MCP_JSON=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-mcp-json) NO_MCP_JSON=1 ;;
|
||||
*) echo "unknown arg: $arg" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
BIN_DIR="$HOME/.local/bin"
|
||||
WORKSPACE="$HOME/Nyx/workspace"
|
||||
STIGNORE="$WORKSPACE/.stignore"
|
||||
|
||||
echo "agent-watcher-mcp install"
|
||||
echo "repo: $REPO_DIR"
|
||||
echo
|
||||
|
||||
# 1. Node check
|
||||
echo "[1/5] checking Node"
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
echo " ERROR: 'node' not found. Install Node 18+ first." >&2
|
||||
exit 1
|
||||
fi
|
||||
NODE_MAJOR=$(node --version | sed 's/^v//' | cut -d. -f1)
|
||||
if [ "$NODE_MAJOR" -lt 18 ]; then
|
||||
echo " ERROR: Node 18+ required; found $(node --version)." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " $(node --version)"
|
||||
|
||||
# 2. Install deps + build
|
||||
echo "[2/5] npm ci + build"
|
||||
( cd "$REPO_DIR" && npm ci --silent && npx tsc )
|
||||
echo " built: $REPO_DIR/dist/server.js"
|
||||
|
||||
# 3. Binary symlink
|
||||
echo "[3/5] linking binary"
|
||||
mkdir -p "$BIN_DIR"
|
||||
ln -sf "$REPO_DIR/dist/server.js" "$BIN_DIR/agent-watcher-mcp"
|
||||
chmod +x "$REPO_DIR/dist/server.js"
|
||||
echo " linked: $BIN_DIR/agent-watcher-mcp -> $REPO_DIR/dist/server.js"
|
||||
|
||||
# 4. .stignore — sentinel + hwm files are local-only
|
||||
echo "[4/5] .stignore (sentinel + hwm are local-only per spec §4.3)"
|
||||
if [ -d "$WORKSPACE" ]; then
|
||||
touch "$STIGNORE"
|
||||
for pattern in "pings/.*.watcher-active" "pings/.*.hwm"; do
|
||||
if ! grep -qxF "$pattern" "$STIGNORE"; then
|
||||
echo "$pattern" >> "$STIGNORE"
|
||||
echo " added: $pattern"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo " $WORKSPACE not present — skipping (Syncthing not set up here)"
|
||||
fi
|
||||
|
||||
# 5. mcp.json snippet
|
||||
echo "[5/5] mcp.json registration"
|
||||
if [ "$NO_MCP_JSON" -eq 0 ]; then
|
||||
cat <<EOF
|
||||
|
||||
To register the watcher with Claude Code, add this to your MCP config.
|
||||
|
||||
For project-level (.mcp.json in the project root):
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-watcher": {
|
||||
"command": "agent-watcher-mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
For user-level (~/.claude.json):
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-watcher": {
|
||||
"command": "$BIN_DIR/agent-watcher-mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Then start Claude Code with the development flag (research preview):
|
||||
|
||||
claude --dangerously-load-development-channels server:agent-watcher
|
||||
|
||||
To use a sandbox identity instead of the default ~/.ping-agent:
|
||||
|
||||
CLAUDE_HOME=~/.claude-sandbox claude --dangerously-load-development-channels server:agent-watcher
|
||||
|
||||
(Drop a 'ping-agent' file in ~/.claude-sandbox containing the sandbox name first.)
|
||||
|
||||
EOF
|
||||
else
|
||||
echo " --no-mcp-json: skipping snippet"
|
||||
fi
|
||||
|
||||
echo "installation complete."
|
||||
Loading…
Add table
Add a link
Reference in a new issue