cue-ai 0.3.0 → 0.4.0
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/README.md +309 -203
- package/package.json +1 -1
- package/profiles/_types.ts +1 -1
- package/profiles/core/profile.yaml +3 -0
- package/profiles/full/profile.yaml +0 -2
- package/profiles/{readme-writer-svg → readme-writer}/profile.yaml +3 -2
- package/profiles/threejs/profile.yaml +19 -0
- package/resources/mcps/configs/claude.sanitized.json +3 -0
- package/resources/mcps/configs/claude_runtime.sanitized.json +3 -0
- package/resources/mcps/configs/codex.sanitized.json +3 -0
- package/resources/mcps/cue-tty-watch/README.md +80 -0
- package/resources/mcps/cue-tty-watch/bin/cue-tty-watch +18 -0
- package/resources/mcps/cue-tty-watch/bun.lock +198 -0
- package/resources/mcps/cue-tty-watch/package.json +17 -0
- package/resources/mcps/cue-tty-watch/server.ts +181 -0
- package/resources/skills/skills/design/headless-gif-demo/SKILL.md +168 -0
- package/resources/skills/skills/meta/kiro-powers/SKILL.md +152 -0
- package/resources/skills/skills/research/find-skills/SKILL.md +127 -102
- package/src/commands/_index.ts +8 -0
- package/src/commands/launch.ts +11 -0
- package/src/commands/list.ts +15 -5
- package/src/commands/materialize.ts +135 -0
- package/src/commands/security.ts +35 -8
- package/src/commands/share.ts +230 -0
- package/src/commands/status.ts +5 -7
- package/src/commands/tree.ts +17 -2
- package/src/lib/agent-adapters.ts +302 -0
- package/src/lib/kitty-image.ts +12 -9
- package/src/lib/runtime-materializer.ts +27 -3
- package/bin/medusa-dev +0 -240
- package/bin/soul +0 -4
package/package.json
CHANGED
package/profiles/_types.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* import type { Profile, NpxSkillRef, MCPRef, SkillRef } from "../../profiles/_types";
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export type AgentKind = "claude-code" | "codex";
|
|
8
|
+
export type AgentKind = "claude-code" | "codex" | "cursor" | "cline" | "windsurf" | "gemini" | "copilot" | "roo" | "amp" | "aider";
|
|
9
9
|
|
|
10
10
|
export interface AgentScoped {
|
|
11
11
|
agents?: AgentKind[];
|
|
@@ -9,7 +9,10 @@ skills:
|
|
|
9
9
|
- meta/analyze
|
|
10
10
|
- meta/cue-usage
|
|
11
11
|
- meta/builtin-manager
|
|
12
|
+
- meta/kiro-powers
|
|
12
13
|
- caveman/caveman
|
|
13
14
|
- caveman/caveman-commit
|
|
15
|
+
mcps:
|
|
16
|
+
- cue-tty-watch # Claude's eyes inside X displays / tmux panes (screenshot, capture-pane, send-keys)
|
|
14
17
|
plugins:
|
|
15
18
|
- claude-mem@thedotmack
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
name: readme-writer
|
|
1
|
+
name: readme-writer
|
|
2
2
|
icon: "🎨"
|
|
3
3
|
description: "Beautiful README design with SVG diagrams — architecture flows, terminal mockups, and editorial visuals"
|
|
4
4
|
inherits: core
|
|
5
5
|
skills:
|
|
6
6
|
local:
|
|
7
7
|
- design/readme-svg-design
|
|
8
|
+
- design/headless-gif-demo
|
|
8
9
|
npx:
|
|
9
10
|
- repo: yizhiyanhua-ai/fireworks-tech-graph
|
|
10
11
|
skills: [fireworks-tech-graph]
|
|
11
12
|
- repo: cathrynlavery/diagram-design
|
|
12
13
|
skills: [diagram-design]
|
|
13
|
-
mcps: []
|
|
14
|
+
mcps: [] # cue-tty-watch comes from core via inheritance
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: threejs
|
|
2
|
+
icon: "🎲"
|
|
3
|
+
description: "Three.js 3D development — geometry, materials, shaders, animation, postprocessing, and interaction"
|
|
4
|
+
inherits: core
|
|
5
|
+
skills:
|
|
6
|
+
npx:
|
|
7
|
+
- repo: CloudAI-X/threejs-skills
|
|
8
|
+
skills:
|
|
9
|
+
- threejs-fundamentals
|
|
10
|
+
- threejs-geometry
|
|
11
|
+
- threejs-materials
|
|
12
|
+
- threejs-lighting
|
|
13
|
+
- threejs-textures
|
|
14
|
+
- threejs-animation
|
|
15
|
+
- threejs-loaders
|
|
16
|
+
- threejs-shaders
|
|
17
|
+
- threejs-postprocessing
|
|
18
|
+
- threejs-interaction
|
|
19
|
+
mcps: []
|
|
@@ -110,6 +110,9 @@
|
|
|
110
110
|
"~/Documents/soul/mcps/mcps/soul-skills/server.py"
|
|
111
111
|
],
|
|
112
112
|
"command": "~/.local/bin/uv"
|
|
113
|
+
},
|
|
114
|
+
"cue-tty-watch": {
|
|
115
|
+
"command": "/home/deadpool/Documents/cue/resources/mcps/cue-tty-watch/bin/cue-tty-watch"
|
|
113
116
|
}
|
|
114
117
|
},
|
|
115
118
|
"source": "claude_runtime",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# cue-tty-watch
|
|
2
|
+
|
|
3
|
+
> MCP server that gives Claude eyes inside X displays and tmux panes.
|
|
4
|
+
|
|
5
|
+
Built for the kitty + Xvfb + tmux GIF-capture pipeline ([`scripts/record-demo-kitty.sh`](../../../scripts/record-demo-kitty.sh)) where the only way to know what the headless terminal is doing was to wait for a human to take a screenshot. With this MCP, Claude can `screenshot` and `tmux_pane` directly.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Purpose | Returns |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `screenshot` | PNG of an X display (default `:99`) | Image |
|
|
12
|
+
| `tmux_pane` | Rendered text of a tmux pane | Text |
|
|
13
|
+
| `send_keys_tmux` | `tmux send-keys` into a pane | Text confirmation |
|
|
14
|
+
| `send_keys_xdotool` | `xdotool key` to a window by class | Text confirmation |
|
|
15
|
+
| `list_xwindows` | Windows on a display + their class/geom | Text table |
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
Already on most Linux dev boxes; install with `apt` if missing:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
sudo apt install xvfb x11-apps imagemagick xdotool
|
|
23
|
+
# tmux and bun should already be there
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The `xwd` binary (from `x11-apps`) is what captures the display; ImageMagick's `convert` turns the XWD blob into PNG.
|
|
27
|
+
|
|
28
|
+
## Install dependencies
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd resources/mcps/cue-tty-watch
|
|
32
|
+
bun install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Register with Claude Code
|
|
36
|
+
|
|
37
|
+
Add to your `~/.claude.json` (or `~/.config/claude/claude.json`) under `mcpServers`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"cue-tty-watch": {
|
|
43
|
+
"command": "/absolute/path/to/cue/resources/mcps/cue-tty-watch/bin/cue-tty-watch"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then **restart Claude Code** for the MCP to load.
|
|
50
|
+
|
|
51
|
+
## Register with cue profile
|
|
52
|
+
|
|
53
|
+
Add to any profile's `profile.yaml` that needs it (typically `readme-writer` for demo recording):
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
mcps:
|
|
57
|
+
- cue-tty-watch
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Usage from Claude
|
|
61
|
+
|
|
62
|
+
Once registered, Claude can call:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
screenshot(display=":99") # → see what's on Xvfb
|
|
66
|
+
tmux_pane(socket="cue-demo", session="demo") # → see what tmux is showing
|
|
67
|
+
send_keys_tmux(socket="cue-demo", session="demo",
|
|
68
|
+
keys=["cue list", "Enter"]) # → drive a demo
|
|
69
|
+
list_xwindows(display=":99") # → find a window by class
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Why this exists
|
|
73
|
+
|
|
74
|
+
Claude Code's built-in tools (`Bash`, `Read`, `Write`, etc.) can run commands and read files but can't *see* a graphical session. When debugging the kitty-graphics GIF capture, every iteration meant: run script (~50 s), wait for a human screenshot, infer what went wrong, patch, repeat.
|
|
75
|
+
|
|
76
|
+
With this MCP, the loop is: `send_keys → screenshot → adjust → send_keys → screenshot`, all inside one Claude turn.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT (same as parent repo).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cue-tty-watch — launcher shim for the MCP server
|
|
3
|
+
# Resolves the bun binary at run time so it works from any Claude Code session.
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
# Find bun: prefer ~/.bun/bin, then $PATH
|
|
8
|
+
if [ -x "$HOME/.bun/bin/bun" ]; then
|
|
9
|
+
BUN="$HOME/.bun/bin/bun"
|
|
10
|
+
elif command -v bun >/dev/null 2>&1; then
|
|
11
|
+
BUN="$(command -v bun)"
|
|
12
|
+
else
|
|
13
|
+
echo "cue-tty-watch: bun not found — install from https://bun.sh" >&2
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
DIR="$(dirname "$(readlink -f "$0")")/.."
|
|
18
|
+
exec "$BUN" run "$DIR/server.ts"
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "cue-tty-watch",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
9
|
+
"zod": "^3.23.0",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
"packages": {
|
|
14
|
+
"@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="],
|
|
15
|
+
|
|
16
|
+
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="],
|
|
17
|
+
|
|
18
|
+
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
|
19
|
+
|
|
20
|
+
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
|
21
|
+
|
|
22
|
+
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
|
|
23
|
+
|
|
24
|
+
"body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
|
|
25
|
+
|
|
26
|
+
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
|
27
|
+
|
|
28
|
+
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
|
29
|
+
|
|
30
|
+
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
|
31
|
+
|
|
32
|
+
"content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
|
|
33
|
+
|
|
34
|
+
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
|
35
|
+
|
|
36
|
+
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
|
37
|
+
|
|
38
|
+
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
|
39
|
+
|
|
40
|
+
"cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
|
|
41
|
+
|
|
42
|
+
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
|
43
|
+
|
|
44
|
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
|
45
|
+
|
|
46
|
+
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
|
47
|
+
|
|
48
|
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
|
49
|
+
|
|
50
|
+
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
|
51
|
+
|
|
52
|
+
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
|
53
|
+
|
|
54
|
+
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
|
55
|
+
|
|
56
|
+
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
|
57
|
+
|
|
58
|
+
"es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="],
|
|
59
|
+
|
|
60
|
+
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
|
61
|
+
|
|
62
|
+
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
|
63
|
+
|
|
64
|
+
"eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
|
|
65
|
+
|
|
66
|
+
"eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="],
|
|
67
|
+
|
|
68
|
+
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
|
|
69
|
+
|
|
70
|
+
"express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="],
|
|
71
|
+
|
|
72
|
+
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
73
|
+
|
|
74
|
+
"fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="],
|
|
75
|
+
|
|
76
|
+
"finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
|
|
77
|
+
|
|
78
|
+
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
|
79
|
+
|
|
80
|
+
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
|
81
|
+
|
|
82
|
+
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
|
83
|
+
|
|
84
|
+
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
|
85
|
+
|
|
86
|
+
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
|
87
|
+
|
|
88
|
+
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
|
89
|
+
|
|
90
|
+
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
|
91
|
+
|
|
92
|
+
"hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="],
|
|
93
|
+
|
|
94
|
+
"hono": ["hono@4.12.22", "", {}, "sha512-7fvVPbB92zNRsQke+uiRGwtTuef0tB2Dg4hWxYfFNvkQhIltWoyi0ONReM5LWA+jJWS3nfT5lTq+qbsIpX0IQw=="],
|
|
95
|
+
|
|
96
|
+
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
|
|
97
|
+
|
|
98
|
+
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
|
99
|
+
|
|
100
|
+
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
|
101
|
+
|
|
102
|
+
"ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="],
|
|
103
|
+
|
|
104
|
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
|
105
|
+
|
|
106
|
+
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
|
107
|
+
|
|
108
|
+
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
|
109
|
+
|
|
110
|
+
"jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="],
|
|
111
|
+
|
|
112
|
+
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
|
113
|
+
|
|
114
|
+
"json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
|
|
115
|
+
|
|
116
|
+
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
|
117
|
+
|
|
118
|
+
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
|
119
|
+
|
|
120
|
+
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
|
121
|
+
|
|
122
|
+
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
|
123
|
+
|
|
124
|
+
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
|
125
|
+
|
|
126
|
+
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
127
|
+
|
|
128
|
+
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
|
129
|
+
|
|
130
|
+
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
|
131
|
+
|
|
132
|
+
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
|
133
|
+
|
|
134
|
+
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
|
135
|
+
|
|
136
|
+
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
|
137
|
+
|
|
138
|
+
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
|
139
|
+
|
|
140
|
+
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
|
141
|
+
|
|
142
|
+
"path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
|
|
143
|
+
|
|
144
|
+
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
|
|
145
|
+
|
|
146
|
+
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
|
147
|
+
|
|
148
|
+
"qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="],
|
|
149
|
+
|
|
150
|
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
|
151
|
+
|
|
152
|
+
"raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
|
|
153
|
+
|
|
154
|
+
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
|
155
|
+
|
|
156
|
+
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
|
157
|
+
|
|
158
|
+
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
|
159
|
+
|
|
160
|
+
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
|
|
161
|
+
|
|
162
|
+
"serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
|
|
163
|
+
|
|
164
|
+
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
|
165
|
+
|
|
166
|
+
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
|
167
|
+
|
|
168
|
+
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
|
169
|
+
|
|
170
|
+
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
|
171
|
+
|
|
172
|
+
"side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="],
|
|
173
|
+
|
|
174
|
+
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
|
175
|
+
|
|
176
|
+
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
|
177
|
+
|
|
178
|
+
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
|
179
|
+
|
|
180
|
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
|
181
|
+
|
|
182
|
+
"type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="],
|
|
183
|
+
|
|
184
|
+
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
|
185
|
+
|
|
186
|
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
|
187
|
+
|
|
188
|
+
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
|
189
|
+
|
|
190
|
+
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
|
191
|
+
|
|
192
|
+
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
|
193
|
+
|
|
194
|
+
"zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
|
195
|
+
|
|
196
|
+
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cue-tty-watch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server giving Claude eyes inside X displays, tmux panes, and Xvfb sessions — screenshot, capture-pane, send-keys.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "bun server.ts"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"bun": ">=1.0.0"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
15
|
+
"zod": "^3.23.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* cue-tty-watch — MCP server giving Claude eyes inside X displays and tmux panes.
|
|
4
|
+
*
|
|
5
|
+
* Tools:
|
|
6
|
+
* screenshot → PNG of an X display (default :99 for Xvfb capture flows)
|
|
7
|
+
* tmux_pane → text contents of a tmux pane
|
|
8
|
+
* send_keys_tmux → tmux send-keys (Enter, Up, Down, "literal text", etc.)
|
|
9
|
+
* send_keys_xdotool → xdotool key against a window by --class
|
|
10
|
+
* list_xwindows → enumerate windows + their class on a display
|
|
11
|
+
*
|
|
12
|
+
* Designed for the kitty + Xvfb + tmux demo-capture pipeline in scripts/record-demo-kitty.sh.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
const server = new McpServer(
|
|
21
|
+
{ name: "cue-tty-watch", version: "0.1.0" },
|
|
22
|
+
{ capabilities: { tools: {} } }
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// ─── helpers ─────────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
const MAX_BUF = 100 * 1024 * 1024;
|
|
28
|
+
|
|
29
|
+
function err(text: string) {
|
|
30
|
+
return { content: [{ type: "text" as const, text }], isError: true };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function text(text: string) {
|
|
34
|
+
return { content: [{ type: "text" as const, text }] };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function image(base64: string) {
|
|
38
|
+
return { content: [{ type: "image" as const, data: base64, mimeType: "image/png" }] };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─── 1. screenshot ───────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
server.tool(
|
|
44
|
+
"screenshot",
|
|
45
|
+
"Capture a frame of an X display as a PNG. Use this to SEE what's actually rendering inside a kitty/tmux/Xvfb session. Default display ':99' matches the Xvfb capture pipeline in scripts/record-demo-kitty.sh. Image is downscaled to max 1400px width to keep payload reasonable.",
|
|
46
|
+
{
|
|
47
|
+
display: z.string().default(":99").describe("X display, e.g. ':99' (Xvfb) or ':0' (real)"),
|
|
48
|
+
max_width: z.number().int().min(200).max(2400).default(1400).describe("Resize to at most this width"),
|
|
49
|
+
},
|
|
50
|
+
async ({ display, max_width }) => {
|
|
51
|
+
const xwd = spawnSync("xwd", ["-root", "-silent", "-display", display], {
|
|
52
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
53
|
+
maxBuffer: MAX_BUF,
|
|
54
|
+
});
|
|
55
|
+
if (xwd.status !== 0) return err(`xwd failed (display ${display}): ${xwd.stderr?.toString() ?? "no output"}`);
|
|
56
|
+
|
|
57
|
+
const conv = spawnSync("convert", ["xwd:-", "-resize", `${max_width}>`, "png:-"], {
|
|
58
|
+
input: xwd.stdout,
|
|
59
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
60
|
+
maxBuffer: MAX_BUF,
|
|
61
|
+
});
|
|
62
|
+
if (conv.status !== 0) return err(`ImageMagick convert failed: ${conv.stderr?.toString() ?? "no output"}`);
|
|
63
|
+
|
|
64
|
+
return image(conv.stdout.toString("base64"));
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// ─── 2. tmux_pane ────────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
server.tool(
|
|
71
|
+
"tmux_pane",
|
|
72
|
+
"Read the current rendered text of a tmux pane. Use to verify what command was typed, what output appeared, whether a prompt is waiting.",
|
|
73
|
+
{
|
|
74
|
+
socket: z.string().default("").describe("tmux -L socket name (e.g. 'cue-demo'). Empty = default socket."),
|
|
75
|
+
session: z.string().describe("Session name, e.g. 'demo'"),
|
|
76
|
+
target: z.string().default("0").describe("Window.pane target, e.g. '0' or '0.1'"),
|
|
77
|
+
history_lines: z.number().int().min(0).max(5000).default(0).describe("Include this many scrollback lines (0 = visible only)"),
|
|
78
|
+
},
|
|
79
|
+
async ({ socket, session, target, history_lines }) => {
|
|
80
|
+
const args: string[] = [];
|
|
81
|
+
if (socket) args.push("-L", socket);
|
|
82
|
+
args.push("capture-pane", "-p", "-t", `${session}:${target}`);
|
|
83
|
+
if (history_lines > 0) args.push("-S", `-${history_lines}`);
|
|
84
|
+
|
|
85
|
+
const res = spawnSync("tmux", args, { encoding: "utf8" });
|
|
86
|
+
if (res.status !== 0) return err(`tmux capture-pane failed: ${res.stderr}`);
|
|
87
|
+
return text(res.stdout || "(empty pane)");
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// ─── 3. send_keys_tmux ───────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
server.tool(
|
|
94
|
+
"send_keys_tmux",
|
|
95
|
+
"Send keystrokes into a tmux pane via tmux send-keys. Each item in 'keys' is a separate argument: 'Enter', 'Up', 'Down', 'C-c', 'BSpace', or literal text strings.",
|
|
96
|
+
{
|
|
97
|
+
socket: z.string().default("").describe("tmux -L socket name. Empty = default socket."),
|
|
98
|
+
session: z.string().describe("Session name"),
|
|
99
|
+
target: z.string().default("0").describe("Window.pane target"),
|
|
100
|
+
keys: z.array(z.string()).min(1).describe("Array of args passed to tmux send-keys. Example: ['echo hi', 'Enter']"),
|
|
101
|
+
},
|
|
102
|
+
async ({ socket, session, target, keys }) => {
|
|
103
|
+
const args: string[] = [];
|
|
104
|
+
if (socket) args.push("-L", socket);
|
|
105
|
+
args.push("send-keys", "-t", `${session}:${target}`, ...keys);
|
|
106
|
+
|
|
107
|
+
const res = spawnSync("tmux", args, { encoding: "utf8" });
|
|
108
|
+
if (res.status !== 0) return err(`tmux send-keys failed: ${res.stderr}`);
|
|
109
|
+
return text(`sent ${keys.length} arg(s) to ${session}:${target}`);
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// ─── 4. send_keys_xdotool ────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
server.tool(
|
|
116
|
+
"send_keys_xdotool",
|
|
117
|
+
"Send keystrokes directly to an X window matched by WM_CLASS. Use when targeting a kitty window before tmux is attached, or for keys tmux can't pass cleanly.",
|
|
118
|
+
{
|
|
119
|
+
display: z.string().default(":99"),
|
|
120
|
+
window_class: z.string().describe("WM_CLASS to match (e.g. 'cue-demo')"),
|
|
121
|
+
keys: z.array(z.string()).min(1).describe("xdotool key specs, e.g. ['Down', 'Down', 'Return']"),
|
|
122
|
+
delay_ms: z.number().int().min(0).max(2000).default(80).describe("Inter-key delay"),
|
|
123
|
+
},
|
|
124
|
+
async ({ display, window_class, keys, delay_ms }) => {
|
|
125
|
+
const env = { ...process.env, DISPLAY: display };
|
|
126
|
+
const find = spawnSync("xdotool", ["search", "--class", window_class], { env, encoding: "utf8" });
|
|
127
|
+
if (find.status !== 0 || !find.stdout.trim()) {
|
|
128
|
+
return err(`No window matching class '${window_class}' on display ${display}`);
|
|
129
|
+
}
|
|
130
|
+
const wid = find.stdout.trim().split("\n")[0]!;
|
|
131
|
+
|
|
132
|
+
for (const k of keys) {
|
|
133
|
+
const r = spawnSync("xdotool", ["key", "--window", wid, "--delay", String(delay_ms), k], { env });
|
|
134
|
+
if (r.status !== 0) return err(`xdotool key '${k}' failed`);
|
|
135
|
+
}
|
|
136
|
+
return text(`sent ${keys.length} key(s) to window ${wid} (class=${window_class})`);
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// ─── 5. list_xwindows ────────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
server.tool(
|
|
143
|
+
"list_xwindows",
|
|
144
|
+
"List X windows on a display with their class and geometry. Use to find the right window_class before sending keys.",
|
|
145
|
+
{
|
|
146
|
+
display: z.string().default(":99"),
|
|
147
|
+
},
|
|
148
|
+
async ({ display }) => {
|
|
149
|
+
const env = { ...process.env, DISPLAY: display };
|
|
150
|
+
const search = spawnSync("xdotool", ["search", ".*"], { env, encoding: "utf8" });
|
|
151
|
+
if (search.status !== 0) return err(`xdotool search failed: ${search.stderr}`);
|
|
152
|
+
|
|
153
|
+
const wids = search.stdout.trim().split("\n").filter(Boolean);
|
|
154
|
+
if (!wids.length) return text("(no windows)");
|
|
155
|
+
|
|
156
|
+
const rows: string[] = [];
|
|
157
|
+
rows.push("WID CLASS GEOMETRY");
|
|
158
|
+
for (const wid of wids) {
|
|
159
|
+
const cls = spawnSync("xdotool", ["getwindowclassname", wid], { env, encoding: "utf8" });
|
|
160
|
+
const geo = spawnSync("xdotool", ["getwindowgeometry", "--shell", wid], { env, encoding: "utf8" });
|
|
161
|
+
const className = (cls.stdout || "").trim();
|
|
162
|
+
if (!className) continue; // skip unmapped / decoration-only windows
|
|
163
|
+
|
|
164
|
+
const geoVars: Record<string, string> = {};
|
|
165
|
+
for (const line of (geo.stdout || "").split("\n")) {
|
|
166
|
+
const m = line.match(/^(\w+)=(.+)$/);
|
|
167
|
+
if (m) geoVars[m[1]!] = m[2]!;
|
|
168
|
+
}
|
|
169
|
+
const geomStr = geoVars.WIDTH && geoVars.HEIGHT
|
|
170
|
+
? `${geoVars.WIDTH}x${geoVars.HEIGHT}+${geoVars.X ?? "?"}+${geoVars.Y ?? "?"}`
|
|
171
|
+
: "?";
|
|
172
|
+
rows.push(`${wid.padEnd(11)} ${className.padEnd(30)} ${geomStr}`);
|
|
173
|
+
}
|
|
174
|
+
return text(rows.join("\n"));
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// ─── start ───────────────────────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
const transport = new StdioServerTransport();
|
|
181
|
+
await server.connect(transport);
|