@foothill/agent-move 1.0.6
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/.github/screenshot.png +0 -0
- package/README.md +266 -0
- package/bin/cli.js +229 -0
- package/package.json +53 -0
- package/packages/client/dist/assets/BufferResource-Ddjob236.js +185 -0
- package/packages/client/dist/assets/CanvasRenderer-B0w6SYyW.js +1 -0
- package/packages/client/dist/assets/Filter-NcMGuiK-.js +1 -0
- package/packages/client/dist/assets/RenderTargetSystem-DgAzY5_U.js +172 -0
- package/packages/client/dist/assets/WebGLRenderer-DUWXDPIX.js +156 -0
- package/packages/client/dist/assets/WebGPURenderer-C1HbrllR.js +41 -0
- package/packages/client/dist/assets/browserAll-CaF1Fl0O.js +14 -0
- package/packages/client/dist/assets/index-CMmR_RuS.css +1 -0
- package/packages/client/dist/assets/index-Dh8yWoLP.js +711 -0
- package/packages/client/dist/assets/webworkerAll-BJ6UhC7r.js +83 -0
- package/packages/client/dist/favicon.svg +27 -0
- package/packages/client/dist/index.html +167 -0
- package/packages/client/package.json +19 -0
- package/packages/server/dist/config.d.ts +12 -0
- package/packages/server/dist/config.d.ts.map +1 -0
- package/packages/server/dist/config.js +19 -0
- package/packages/server/dist/config.js.map +1 -0
- package/packages/server/dist/hooks/hook-event-manager.d.ts +39 -0
- package/packages/server/dist/hooks/hook-event-manager.d.ts.map +1 -0
- package/packages/server/dist/hooks/hook-event-manager.js +161 -0
- package/packages/server/dist/hooks/hook-event-manager.js.map +1 -0
- package/packages/server/dist/hooks/hook-installer.d.ts +14 -0
- package/packages/server/dist/hooks/hook-installer.d.ts.map +1 -0
- package/packages/server/dist/hooks/hook-installer.js +179 -0
- package/packages/server/dist/hooks/hook-installer.js.map +1 -0
- package/packages/server/dist/index.d.ts +4 -0
- package/packages/server/dist/index.d.ts.map +1 -0
- package/packages/server/dist/index.js +3544 -0
- package/packages/server/dist/index.js.map +1 -0
- package/packages/server/dist/routes/api.d.ts +4 -0
- package/packages/server/dist/routes/api.d.ts.map +1 -0
- package/packages/server/dist/routes/api.js +27 -0
- package/packages/server/dist/routes/api.js.map +1 -0
- package/packages/server/dist/state/activity-processor.d.ts +31 -0
- package/packages/server/dist/state/activity-processor.d.ts.map +1 -0
- package/packages/server/dist/state/activity-processor.js +417 -0
- package/packages/server/dist/state/activity-processor.js.map +1 -0
- package/packages/server/dist/state/agent-state-manager.d.ts +107 -0
- package/packages/server/dist/state/agent-state-manager.d.ts.map +1 -0
- package/packages/server/dist/state/agent-state-manager.js +1622 -0
- package/packages/server/dist/state/agent-state-manager.js.map +1 -0
- package/packages/server/dist/state/anomaly-detector.d.ts +23 -0
- package/packages/server/dist/state/anomaly-detector.d.ts.map +1 -0
- package/packages/server/dist/state/anomaly-detector.js +272 -0
- package/packages/server/dist/state/anomaly-detector.js.map +1 -0
- package/packages/server/dist/state/identity-manager.d.ts +31 -0
- package/packages/server/dist/state/identity-manager.d.ts.map +1 -0
- package/packages/server/dist/state/identity-manager.js +63 -0
- package/packages/server/dist/state/identity-manager.js.map +1 -0
- package/packages/server/dist/state/role-resolver.d.ts +23 -0
- package/packages/server/dist/state/role-resolver.d.ts.map +1 -0
- package/packages/server/dist/state/role-resolver.js +43 -0
- package/packages/server/dist/state/role-resolver.js.map +1 -0
- package/packages/server/dist/state/task-graph-manager.d.ts +31 -0
- package/packages/server/dist/state/task-graph-manager.d.ts.map +1 -0
- package/packages/server/dist/state/task-graph-manager.js +191 -0
- package/packages/server/dist/state/task-graph-manager.js.map +1 -0
- package/packages/server/dist/state/tool-chain-tracker.d.ts +23 -0
- package/packages/server/dist/state/tool-chain-tracker.d.ts.map +1 -0
- package/packages/server/dist/state/tool-chain-tracker.js +113 -0
- package/packages/server/dist/state/tool-chain-tracker.js.map +1 -0
- package/packages/server/dist/watcher/agent-watcher.d.ts +16 -0
- package/packages/server/dist/watcher/agent-watcher.d.ts.map +1 -0
- package/packages/server/dist/watcher/agent-watcher.js +0 -0
- package/packages/server/dist/watcher/agent-watcher.js.map +1 -0
- package/packages/server/dist/watcher/claude-paths.d.ts +32 -0
- package/packages/server/dist/watcher/claude-paths.d.ts.map +1 -0
- package/packages/server/dist/watcher/claude-paths.js +104 -0
- package/packages/server/dist/watcher/claude-paths.js.map +1 -0
- package/packages/server/dist/watcher/file-watcher.d.ts +17 -0
- package/packages/server/dist/watcher/file-watcher.d.ts.map +1 -0
- package/packages/server/dist/watcher/file-watcher.js +347 -0
- package/packages/server/dist/watcher/file-watcher.js.map +1 -0
- package/packages/server/dist/watcher/git-info.d.ts +3 -0
- package/packages/server/dist/watcher/git-info.d.ts.map +1 -0
- package/packages/server/dist/watcher/git-info.js +35 -0
- package/packages/server/dist/watcher/git-info.js.map +1 -0
- package/packages/server/dist/watcher/jsonl-parser.d.ts +21 -0
- package/packages/server/dist/watcher/jsonl-parser.d.ts.map +1 -0
- package/packages/server/dist/watcher/jsonl-parser.js +95 -0
- package/packages/server/dist/watcher/jsonl-parser.js.map +1 -0
- package/packages/server/dist/watcher/opencode/opencode-parser.d.ts +58 -0
- package/packages/server/dist/watcher/opencode/opencode-parser.d.ts.map +1 -0
- package/packages/server/dist/watcher/opencode/opencode-parser.js +256 -0
- package/packages/server/dist/watcher/opencode/opencode-parser.js.map +1 -0
- package/packages/server/dist/watcher/opencode/opencode-paths.d.ts +20 -0
- package/packages/server/dist/watcher/opencode/opencode-paths.d.ts.map +1 -0
- package/packages/server/dist/watcher/opencode/opencode-paths.js +35 -0
- package/packages/server/dist/watcher/opencode/opencode-paths.js.map +1 -0
- package/packages/server/dist/watcher/opencode/opencode-watcher.d.ts +49 -0
- package/packages/server/dist/watcher/opencode/opencode-watcher.d.ts.map +1 -0
- package/packages/server/dist/watcher/opencode/opencode-watcher.js +1292 -0
- package/packages/server/dist/watcher/opencode/opencode-watcher.js.map +1 -0
- package/packages/server/dist/watcher/session-scanner.d.ts +7 -0
- package/packages/server/dist/watcher/session-scanner.d.ts.map +1 -0
- package/packages/server/dist/watcher/session-scanner.js +69 -0
- package/packages/server/dist/watcher/session-scanner.js.map +1 -0
- package/packages/server/dist/ws/broadcaster.d.ts +18 -0
- package/packages/server/dist/ws/broadcaster.d.ts.map +1 -0
- package/packages/server/dist/ws/broadcaster.js +152 -0
- package/packages/server/dist/ws/broadcaster.js.map +1 -0
- package/packages/server/dist/ws/ws-handler.d.ts +6 -0
- package/packages/server/dist/ws/ws-handler.d.ts.map +1 -0
- package/packages/server/dist/ws/ws-handler.js +55 -0
- package/packages/server/dist/ws/ws-handler.js.map +1 -0
- package/packages/server/package.json +25 -0
- package/packages/shared/dist/constants/colors.d.ts +46 -0
- package/packages/shared/dist/constants/colors.d.ts.map +1 -0
- package/packages/shared/dist/constants/colors.js +178 -0
- package/packages/shared/dist/constants/colors.js.map +1 -0
- package/packages/shared/dist/constants/names.d.ts +6 -0
- package/packages/shared/dist/constants/names.d.ts.map +1 -0
- package/packages/shared/dist/constants/names.js +28 -0
- package/packages/shared/dist/constants/names.js.map +1 -0
- package/packages/shared/dist/constants/tools.d.ts +15 -0
- package/packages/shared/dist/constants/tools.d.ts.map +1 -0
- package/packages/shared/dist/constants/tools.js +120 -0
- package/packages/shared/dist/constants/tools.js.map +1 -0
- package/packages/shared/dist/constants/zones.d.ts +37 -0
- package/packages/shared/dist/constants/zones.d.ts.map +1 -0
- package/packages/shared/dist/constants/zones.js +128 -0
- package/packages/shared/dist/constants/zones.js.map +1 -0
- package/packages/shared/dist/index.d.ts +15 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +7 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/shared/dist/types/agent.d.ts +85 -0
- package/packages/shared/dist/types/agent.d.ts.map +1 -0
- package/packages/shared/dist/types/agent.js +2 -0
- package/packages/shared/dist/types/agent.js.map +1 -0
- package/packages/shared/dist/types/anomaly.d.ts +18 -0
- package/packages/shared/dist/types/anomaly.d.ts.map +1 -0
- package/packages/shared/dist/types/anomaly.js +6 -0
- package/packages/shared/dist/types/anomaly.js.map +1 -0
- package/packages/shared/dist/types/hooks.d.ts +51 -0
- package/packages/shared/dist/types/hooks.d.ts.map +1 -0
- package/packages/shared/dist/types/hooks.js +2 -0
- package/packages/shared/dist/types/hooks.js.map +1 -0
- package/packages/shared/dist/types/jsonl.d.ts +62 -0
- package/packages/shared/dist/types/jsonl.d.ts.map +1 -0
- package/packages/shared/dist/types/jsonl.js +3 -0
- package/packages/shared/dist/types/jsonl.js.map +1 -0
- package/packages/shared/dist/types/task-graph.d.ts +20 -0
- package/packages/shared/dist/types/task-graph.d.ts.map +1 -0
- package/packages/shared/dist/types/task-graph.js +2 -0
- package/packages/shared/dist/types/task-graph.js.map +1 -0
- package/packages/shared/dist/types/tool-chain.d.ts +17 -0
- package/packages/shared/dist/types/tool-chain.d.ts.map +1 -0
- package/packages/shared/dist/types/tool-chain.js +2 -0
- package/packages/shared/dist/types/tool-chain.js.map +1 -0
- package/packages/shared/dist/types/websocket.d.ts +132 -0
- package/packages/shared/dist/types/websocket.d.ts.map +1 -0
- package/packages/shared/dist/types/websocket.js +2 -0
- package/packages/shared/dist/types/websocket.js.map +1 -0
- package/packages/shared/dist/types/zone.d.ts +21 -0
- package/packages/shared/dist/types/zone.d.ts.map +1 -0
- package/packages/shared/dist/types/zone.js +2 -0
- package/packages/shared/dist/types/zone.js.map +1 -0
- package/packages/shared/package.json +15 -0
|
Binary file
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# AgentMove
|
|
4
|
+
|
|
5
|
+
**Watch your AI coding agents come alive.**
|
|
6
|
+
|
|
7
|
+
A real-time pixel-art visualizer that turns AI coding sessions into a living 2D world. Agents walk between rooms, use tools, chat, and rest — all rendered at 60fps in your browser.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npx agent-move@latest
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
<br>
|
|
14
|
+
|
|
15
|
+
<img src=".github/screenshot.png" alt="AgentMove screenshot showing pixel-art agents in a 2D world with 9 activity zones" width="800">
|
|
16
|
+
|
|
17
|
+
<br>
|
|
18
|
+
<br>
|
|
19
|
+
|
|
20
|
+
[](https://www.npmjs.com/package/agent-move)
|
|
21
|
+
[](LICENSE)
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## What You're Looking At
|
|
28
|
+
|
|
29
|
+
AgentMove reads AI coding agent session files and maps every tool call to one of **9 activity zones**. Each agent gets a unique pixel-art character that physically walks between zones as it works.
|
|
30
|
+
|
|
31
|
+
It uses a **hybrid data pipeline** — JSONL file watching for rich data (tokens, costs, full text) combined with Claude Code hooks for precise lifecycle events (session start/end, tool success/failure, permissions).
|
|
32
|
+
|
|
33
|
+
| Zone | What Happens There | Tools |
|
|
34
|
+
|------|--------------------|-------|
|
|
35
|
+
| **Files** | Reading, writing, editing code | Read, Write, Edit, Glob |
|
|
36
|
+
| **Terminal** | Running shell commands | Bash |
|
|
37
|
+
| **Search** | Searching code and the web | Grep, WebSearch |
|
|
38
|
+
| **Web** | Browsing, fetching, MCP tools | WebFetch, Playwright, MCP `*` |
|
|
39
|
+
| **Thinking** | Planning and asking questions | EnterPlanMode, AskUserQuestion |
|
|
40
|
+
| **Messaging** | Talking to other agents | SendMessage |
|
|
41
|
+
| **Tasks** | Managing work items | TaskCreate, TaskUpdate |
|
|
42
|
+
| **Spawn** | Agents arriving and departing | Agent, TeamCreate |
|
|
43
|
+
| **Idle** | Resting after inactivity | — |
|
|
44
|
+
|
|
45
|
+
## Getting Started
|
|
46
|
+
|
|
47
|
+
### Prerequisites
|
|
48
|
+
|
|
49
|
+
- **Node.js 18+**
|
|
50
|
+
- **Claude Code** installed and used at least once (so `~/.claude/` exists)
|
|
51
|
+
- Works on **Windows**, **macOS**, and **Linux**
|
|
52
|
+
|
|
53
|
+
### One Command
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx agent-move@latest
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
That's it. The server starts, hooks are auto-installed, your browser opens, and any active coding session is visualized immediately.
|
|
60
|
+
|
|
61
|
+
On first run, AgentMove automatically:
|
|
62
|
+
1. Installs Claude Code hooks into `~/.claude/settings.json` (17 event types)
|
|
63
|
+
2. Creates a hook script at `~/.agent-move/hooks/hook-sender.js`
|
|
64
|
+
3. Starts the server and opens your browser
|
|
65
|
+
|
|
66
|
+
### Options
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx agent-move@latest --port 4000 # custom port (default: 3333)
|
|
70
|
+
npx agent-move@latest --no-open # don't auto-open the browser
|
|
71
|
+
npx agent-move@latest --help # show all options
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Hooks Management
|
|
75
|
+
|
|
76
|
+
Hooks are auto-installed on first run. You can also manage them manually:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx agent-move@latest hooks status # check if hooks are installed
|
|
80
|
+
npx agent-move@latest hooks install # (re)install hooks
|
|
81
|
+
npx agent-move@latest hooks uninstall # remove hooks
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
AgentMove works without hooks too — it falls back to JSONL file watching. Hooks add precise session lifecycle, tool success/failure tracking, and permission management.
|
|
85
|
+
|
|
86
|
+
### From Source (for development)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/AbdullahSAhmad/agent-move.git
|
|
90
|
+
cd agent-move
|
|
91
|
+
npm install
|
|
92
|
+
npm run dev
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
This starts the server on `:3333` and the Vite dev server on `:5173` with hot reload.
|
|
96
|
+
|
|
97
|
+
## Features
|
|
98
|
+
|
|
99
|
+
### Hooks Integration
|
|
100
|
+
|
|
101
|
+
- **Auto-install** — hooks are set up on first run, no manual config needed
|
|
102
|
+
- **17 event types** — SessionStart, SessionEnd, PreToolUse, PostToolUse, PermissionRequest, SubagentStart, and more
|
|
103
|
+
- **Precise lifecycle** — exact session start/end instead of timeout guessing
|
|
104
|
+
- **Tool outcomes** — see green (success) vs red (failure) on completed tool calls
|
|
105
|
+
- **Permission management** — approve/deny tool permissions from the visualization UI
|
|
106
|
+
- **Notification dashboard** — priority-based feed of permissions, failures, idle alerts
|
|
107
|
+
- **Graceful fallback** — everything works without hooks via JSONL watching
|
|
108
|
+
|
|
109
|
+
### Visualization
|
|
110
|
+
|
|
111
|
+
- **Programmatic pixel-art sprites** — 16x16 characters rendered at 3x scale, no external image assets
|
|
112
|
+
- **12 color palettes** — each agent gets a distinct look
|
|
113
|
+
- **6 sprite variants** — Human, Robot, Wizard, Ninja, Skeleton, Slime
|
|
114
|
+
- **Animations** — idle breathing, walking between zones, working effects
|
|
115
|
+
- **Role badges** — MAIN, SUB, LEAD, MEMBER based on session type
|
|
116
|
+
- **Speech bubbles** — show the current tool or text output above each agent
|
|
117
|
+
- **Relationship lines** — dashed connections between parent/child and team agents
|
|
118
|
+
- **Zone glow** — rooms light up when agents are inside
|
|
119
|
+
- **Particle effects** — sparkles on tool use
|
|
120
|
+
- **Agent trails** — toggle fading trail dots behind moving agents (`T`)
|
|
121
|
+
- **Day/night cycle** — ambient lighting based on your local time (`N`)
|
|
122
|
+
- **4 themes** — Office, Space, Castle, Cyberpunk — selectable from the top bar
|
|
123
|
+
- **Glassmorphism UI** — modern bento-grid layout with flow lines
|
|
124
|
+
|
|
125
|
+
### Dashboard
|
|
126
|
+
|
|
127
|
+
- **Sidebar navigation** — collapsible sidebar with section navigation
|
|
128
|
+
- **Top bar** — live stats (active agents, idle count, total cost, token velocity), and quick actions
|
|
129
|
+
- **Agent list** — live sidebar with zone, current tool, token counts, and status indicators
|
|
130
|
+
- **Agent detail panel** — click any agent to see model, role, tokens, uptime, git branch, recent files with diff viewer, and scrolling activity feed
|
|
131
|
+
- **Agent customization** — rename agents and change their color palette (persisted in localStorage)
|
|
132
|
+
- **Minimap** — clickable overview showing zone layout, agent positions, and viewport (`` ` ``)
|
|
133
|
+
- **Activity feed** — scrollable event log with timestamps and filtering
|
|
134
|
+
- **Waterfall view** — Chrome DevTools-style timeline showing tool durations per agent
|
|
135
|
+
- **Relationship graph** — interactive force-directed graph of agent parent/child/teammate connections
|
|
136
|
+
|
|
137
|
+
### Analytics
|
|
138
|
+
|
|
139
|
+
- **Total cost tracking** — real-time cost estimation including cache read/creation token pricing
|
|
140
|
+
- **Cache efficiency** — cache hit rate percentage and estimated savings
|
|
141
|
+
- **Token velocity** — tokens/min with sparkline chart and trend indicator
|
|
142
|
+
- **Cost by agent** — per-agent cost breakdown with bar charts
|
|
143
|
+
- **Time by zone** — cumulative time distribution across zones (including idle)
|
|
144
|
+
- **Tool usage** — frequency breakdown of the most-used tools
|
|
145
|
+
- **Session duration** — per-agent uptime with active/idle status
|
|
146
|
+
- **Cost threshold alerts** — configurable budget alert with visual notification
|
|
147
|
+
|
|
148
|
+
### Leaderboard
|
|
149
|
+
|
|
150
|
+
- **Agent rankings** — sortable by tokens, cost, duration, or tool count
|
|
151
|
+
- **Medal badges** — top 3 agents highlighted
|
|
152
|
+
- **Visual bars** — proportional token usage comparison
|
|
153
|
+
|
|
154
|
+
### Navigation & Controls
|
|
155
|
+
|
|
156
|
+
- **Pan & zoom** — scroll wheel to zoom, click and drag to pan the world
|
|
157
|
+
- **Command palette** — fuzzy search for any action (`Ctrl+K`)
|
|
158
|
+
- **Focus mode** — follow an agent with smooth camera tracking (`F` to cycle, `Esc` to exit)
|
|
159
|
+
- **Timeline** — scrubber with live/replay modes, speed control (0.5x–8x), event filters, and per-agent swim lanes
|
|
160
|
+
- **Session export** — generate a markdown report of the session (`E`)
|
|
161
|
+
- **Sound effects** — synthesized audio for spawn, zone changes, tool use, idle, and shutdown (`M` to mute)
|
|
162
|
+
- **Toast notifications** — popup alerts for agent lifecycle events (spawn, idle, shutdown)
|
|
163
|
+
- **Keyboard shortcuts** — press `?` to see all available shortcuts
|
|
164
|
+
- **Auto-reconnect** — WebSocket reconnects with exponential backoff if the connection drops
|
|
165
|
+
|
|
166
|
+
## How It Works
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
┌─────────────────┐
|
|
170
|
+
Hook events ──────→ │ │
|
|
171
|
+
(17 types, │ AgentState │
|
|
172
|
+
push-based) │ Manager │──→ Broadcaster ──→ WebSocket ──→ Client
|
|
173
|
+
│ │
|
|
174
|
+
JSONL watching ───→ │ (merged state) │
|
|
175
|
+
(byte-offset, └─────────────────┘
|
|
176
|
+
pull-based)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Hook events provide **lifecycle accuracy** (exact session start/end, tool success/failure).
|
|
180
|
+
JSONL parsing provides **rich data** (token counts, costs, full response text).
|
|
181
|
+
|
|
182
|
+
## Architecture
|
|
183
|
+
|
|
184
|
+
Three-package monorepo (npm workspaces):
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
agent-move/
|
|
188
|
+
├── bin/cli.js # npx entry point (auto-installs hooks)
|
|
189
|
+
├── packages/
|
|
190
|
+
│ ├── shared/ # Types & constants (zero dependencies)
|
|
191
|
+
│ │ └── src/
|
|
192
|
+
│ │ ├── types/ AgentState, HookEvent, ServerMessage, ZoneConfig
|
|
193
|
+
│ │ └── constants/ tool→zone map, zone configs, color palettes
|
|
194
|
+
│ ├── server/ # Fastify backend
|
|
195
|
+
│ │ └── src/
|
|
196
|
+
│ │ ├── hooks/ hook event manager, hook installer
|
|
197
|
+
│ │ ├── watcher/ chokidar file watcher, JSONL parser
|
|
198
|
+
│ │ ├── state/ agent state machine, anomaly detector, tool chains
|
|
199
|
+
│ │ ├── ws/ WebSocket broadcaster
|
|
200
|
+
│ │ └── routes/ REST API
|
|
201
|
+
│ └── client/ # Pixi.js frontend
|
|
202
|
+
│ └── src/
|
|
203
|
+
│ ├── sprites/ pixel-art data, palette resolver, sprite variants
|
|
204
|
+
│ ├── world/ zone renderer, grid, camera, themes, layout engine
|
|
205
|
+
│ ├── agents/ sprite logic, movement, relationships
|
|
206
|
+
│ ├── effects/ particles, zone glow, agent trails, flow lines
|
|
207
|
+
│ ├── connection/ WebSocket client, state store
|
|
208
|
+
│ ├── audio/ sound effects, notifications
|
|
209
|
+
│ └── ui/ sidebar, panels, overlays, waterfall, activity feed
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Keyboard Shortcuts
|
|
213
|
+
|
|
214
|
+
| Key | Action |
|
|
215
|
+
|-----|--------|
|
|
216
|
+
| `Ctrl+K` | Command palette |
|
|
217
|
+
| `?` | Shortcuts help |
|
|
218
|
+
| `F` | Cycle focus between agents |
|
|
219
|
+
| `Esc` | Exit focus mode |
|
|
220
|
+
| `A` | Toggle analytics |
|
|
221
|
+
| `L` | Toggle leaderboard |
|
|
222
|
+
| `T` | Toggle agent trails |
|
|
223
|
+
| `N` | Toggle day/night cycle |
|
|
224
|
+
| `M` | Toggle sound |
|
|
225
|
+
| `E` | Export session |
|
|
226
|
+
| `` ` `` | Toggle minimap |
|
|
227
|
+
| `P` | Cycle theme |
|
|
228
|
+
| `H` | Toggle heatmap |
|
|
229
|
+
|
|
230
|
+
## API
|
|
231
|
+
|
|
232
|
+
| Endpoint | Description |
|
|
233
|
+
|----------|-------------|
|
|
234
|
+
| `GET /api/health` | Health check |
|
|
235
|
+
| `GET /api/state` | All agent states as JSON |
|
|
236
|
+
| `POST /hook` | Claude Code hook event receiver |
|
|
237
|
+
| `WS /ws` | Real-time agent event stream |
|
|
238
|
+
|
|
239
|
+
The WebSocket sends a `full_state` snapshot on connect, then incremental events: `agent:spawn`, `agent:update`, `agent:idle`, `agent:shutdown`, `permission:request`, `hooks:status`.
|
|
240
|
+
|
|
241
|
+
## Troubleshooting
|
|
242
|
+
|
|
243
|
+
| Problem | Solution |
|
|
244
|
+
|---------|----------|
|
|
245
|
+
| Port already in use | `npx agent-move@latest --port 4444` |
|
|
246
|
+
| Hooks not working | `npx agent-move@latest hooks status` to check, then `hooks install` to fix |
|
|
247
|
+
| No agents showing up | Make sure Claude Code is running — agents appear when sessions are active |
|
|
248
|
+
| Build artifacts missing (from source) | Run `npm run build` |
|
|
249
|
+
| Permission denied on port | Use a port above 1024: `--port 3333` |
|
|
250
|
+
| Browser didn't open | Visit `http://localhost:3333` manually, or check `--no-open` flag |
|
|
251
|
+
|
|
252
|
+
Need more help? [Open an issue](https://github.com/AbdullahSAhmad/agent-move/issues)
|
|
253
|
+
|
|
254
|
+
## Tech Stack
|
|
255
|
+
|
|
256
|
+
| Layer | Technology |
|
|
257
|
+
|-------|------------|
|
|
258
|
+
| Renderer | [Pixi.js](https://pixijs.com/) v8 (WebGL) |
|
|
259
|
+
| Server | [Fastify](https://fastify.dev/) + [@fastify/websocket](https://github.com/fastify/fastify-websocket) |
|
|
260
|
+
| File watching | [chokidar](https://github.com/paulmillr/chokidar) v3 |
|
|
261
|
+
| Client build | [Vite](https://vite.dev/) |
|
|
262
|
+
| Language | TypeScript (strict, ES modules) |
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
|
|
5
|
+
// ── Colors (works on all terminals, no dependencies) ────────────────────────
|
|
6
|
+
const c = {
|
|
7
|
+
reset: '\x1b[0m',
|
|
8
|
+
bold: '\x1b[1m',
|
|
9
|
+
dim: '\x1b[2m',
|
|
10
|
+
cyan: '\x1b[36m',
|
|
11
|
+
green: '\x1b[32m',
|
|
12
|
+
yellow: '\x1b[33m',
|
|
13
|
+
red: '\x1b[31m',
|
|
14
|
+
magenta: '\x1b[35m',
|
|
15
|
+
blue: '\x1b[34m',
|
|
16
|
+
white: '\x1b[37m',
|
|
17
|
+
bgCyan: '\x1b[46m',
|
|
18
|
+
bgBlue: '\x1b[44m',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Disable colors if NO_COLOR env or dumb terminal
|
|
22
|
+
const noColor = process.env.NO_COLOR || process.env.TERM === 'dumb';
|
|
23
|
+
if (noColor) Object.keys(c).forEach(k => { c[k] = ''; });
|
|
24
|
+
|
|
25
|
+
function logo() {
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(`${c.cyan}${c.bold} _ _ __ __`);
|
|
28
|
+
console.log(` / \\ __ _ ___ _ __ | |_| \\/ | _____ _____`);
|
|
29
|
+
console.log(` / _ \\ / _\` |/ _ \\ '_ \\| __| |\\/| |/ _ \\ \\ / / _ \\`);
|
|
30
|
+
console.log(` / ___ \\ (_| | __/ | | | |_| | | | (_) \\ V / __/`);
|
|
31
|
+
console.log(` /_/ \\_\\__, |\\___|_| |_|\\__|_| |_|\\___/ \\_/ \\___|`);
|
|
32
|
+
console.log(` |___/`);
|
|
33
|
+
console.log(`${c.reset}${c.dim} Watch your AI agents come alive as pixel-art characters${c.reset}`);
|
|
34
|
+
console.log();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function status(icon, label, detail) {
|
|
38
|
+
console.log(` ${icon} ${c.bold}${label}${c.reset} ${c.dim}${detail}${c.reset}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function troubleshooting() {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(`${c.dim} ── Troubleshooting ──────────────────────────────────────${c.reset}`);
|
|
44
|
+
console.log(`${c.dim} Port in use? ${c.reset}npx @foothill/agent-move --port 4444`);
|
|
45
|
+
console.log(`${c.dim} Hooks not working? ${c.reset}npx @foothill/agent-move hooks status`);
|
|
46
|
+
console.log(`${c.dim} Reinstall hooks: ${c.reset}npx @foothill/agent-move hooks install`);
|
|
47
|
+
console.log(`${c.dim} Remove hooks: ${c.reset}npx @foothill/agent-move hooks uninstall`);
|
|
48
|
+
console.log(`${c.dim} Report issues: ${c.reset}https://github.com/FoothillSolutions/agent-move/issues`);
|
|
49
|
+
console.log();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── help ──────────────────────────────────────────────────────────────────────
|
|
53
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
54
|
+
logo();
|
|
55
|
+
console.log(`${c.bold} Usage:${c.reset}`);
|
|
56
|
+
console.log(` ${c.cyan}npx @foothill/agent-move${c.reset} Start the visualization server`);
|
|
57
|
+
console.log(` ${c.cyan}npx @foothill/agent-move --port 4444${c.reset} Use a custom port`);
|
|
58
|
+
console.log(` ${c.cyan}npx @foothill/agent-move hooks install${c.reset} Install Claude Code hooks`);
|
|
59
|
+
console.log(` ${c.cyan}npx @foothill/agent-move hooks uninstall${c.reset} Remove Claude Code hooks`);
|
|
60
|
+
console.log(` ${c.cyan}npx @foothill/agent-move hooks status${c.reset} Check hooks installation`);
|
|
61
|
+
console.log();
|
|
62
|
+
console.log(`${c.bold} Options:${c.reset}`);
|
|
63
|
+
console.log(` ${c.dim}--port <n>${c.reset} Server port (default: 3333)`);
|
|
64
|
+
console.log(` ${c.dim}--no-open${c.reset} Don't auto-open the browser`);
|
|
65
|
+
console.log(` ${c.dim}--help${c.reset} Show this help`);
|
|
66
|
+
console.log();
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── hooks subcommand ──────────────────────────────────────────────────────────
|
|
71
|
+
if (args[0] === 'hooks') {
|
|
72
|
+
const sub = args[1];
|
|
73
|
+
async function runHooks() {
|
|
74
|
+
const { installHooks, uninstallHooks, checkHookStatus } =
|
|
75
|
+
await import('../packages/server/dist/hooks/hook-installer.js');
|
|
76
|
+
|
|
77
|
+
if (sub === 'install') {
|
|
78
|
+
const portIdx = args.indexOf('--port');
|
|
79
|
+
const port = portIdx !== -1 ? parseInt(args[portIdx + 1], 10) : 3333;
|
|
80
|
+
const result = installHooks(port);
|
|
81
|
+
console.log();
|
|
82
|
+
status(`${c.green}+${c.reset}`, 'Hooks installed', `(${result.scriptPath})`);
|
|
83
|
+
status(`${c.green}+${c.reset}`, 'Settings updated', `(${result.settingsPath})`);
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(`${c.dim} Hooks will send events to http://localhost:${port}/hook${c.reset}`);
|
|
86
|
+
console.log(`${c.dim} Start the server with: ${c.reset}npx @foothill/agent-move`);
|
|
87
|
+
console.log();
|
|
88
|
+
} else if (sub === 'uninstall') {
|
|
89
|
+
const result = uninstallHooks();
|
|
90
|
+
console.log();
|
|
91
|
+
status(`${c.yellow}-${c.reset}`, 'Hooks removed', result.message);
|
|
92
|
+
console.log();
|
|
93
|
+
} else if (sub === 'status') {
|
|
94
|
+
const s = checkHookStatus();
|
|
95
|
+
console.log();
|
|
96
|
+
if (s.installed) {
|
|
97
|
+
status(`${c.green}*${c.reset}`, 'Hooks installed', `(${s.events.length} events registered)`);
|
|
98
|
+
status(s.scriptExists ? `${c.green}*${c.reset}` : `${c.red}!${c.reset}`, 'Hook script', s.scriptExists ? 'exists' : 'MISSING — run `agent-move hooks install`');
|
|
99
|
+
} else {
|
|
100
|
+
status(`${c.dim}-${c.reset}`, 'Hooks not installed', '');
|
|
101
|
+
console.log(`${c.dim} Run ${c.reset}npx @foothill/agent-move hooks install${c.dim} to enable real-time events.${c.reset}`);
|
|
102
|
+
}
|
|
103
|
+
console.log();
|
|
104
|
+
} else {
|
|
105
|
+
console.log();
|
|
106
|
+
console.log(`${c.bold} Usage:${c.reset} agent-move hooks <install|uninstall|status> [--port <n>]`);
|
|
107
|
+
console.log();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
runHooks().catch((err) => {
|
|
111
|
+
console.error(`\n ${c.red}!${c.reset} ${err?.message ?? err}\n`);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
} else {
|
|
116
|
+
// ── server (default) ────────────────────────────────────────────────────────
|
|
117
|
+
const preferredPort = (() => {
|
|
118
|
+
const idx = args.indexOf('--port');
|
|
119
|
+
if (idx !== -1 && args[idx + 1]) {
|
|
120
|
+
const p = parseInt(args[idx + 1], 10);
|
|
121
|
+
if (!Number.isNaN(p) && p > 0 && p < 65536) return p;
|
|
122
|
+
console.error(`\n ${c.red}!${c.reset} Invalid port: ${args[idx + 1]}\n`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
return 3333;
|
|
126
|
+
})();
|
|
127
|
+
|
|
128
|
+
const skipOpen = args.includes('--no-open');
|
|
129
|
+
|
|
130
|
+
process.env.AGENT_MOVE_PORT = String(preferredPort);
|
|
131
|
+
process.env.__AGENT_MOVE_CLI = '1';
|
|
132
|
+
|
|
133
|
+
async function run() {
|
|
134
|
+
logo();
|
|
135
|
+
|
|
136
|
+
// ── Step 1: Auto-install hooks ──────────────────────────────────────────
|
|
137
|
+
try {
|
|
138
|
+
const { checkHookStatus, installHooks } =
|
|
139
|
+
await import('../packages/server/dist/hooks/hook-installer.js');
|
|
140
|
+
const hookStatus = checkHookStatus();
|
|
141
|
+
if (!hookStatus.installed) {
|
|
142
|
+
const result = installHooks(preferredPort);
|
|
143
|
+
status(`${c.green}+${c.reset}`, 'Hooks', `auto-installed (${result.scriptPath})`);
|
|
144
|
+
} else if (!hookStatus.scriptExists) {
|
|
145
|
+
// Hooks registered but script missing — reinstall
|
|
146
|
+
const result = installHooks(preferredPort);
|
|
147
|
+
status(`${c.yellow}~${c.reset}`, 'Hooks', `reinstalled (script was missing)`);
|
|
148
|
+
} else {
|
|
149
|
+
status(`${c.green}*${c.reset}`, 'Hooks', `ready (${hookStatus.events.length} events)`);
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
status(`${c.yellow}!${c.reset}`, 'Hooks', `skipped — ${err?.message ?? 'unknown error'}`);
|
|
153
|
+
console.log(`${c.dim} You can install manually: npx @foothill/agent-move hooks install${c.reset}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Step 2: Start server ────────────────────────────────────────────────
|
|
157
|
+
const { main } = await import('../packages/server/dist/index.js');
|
|
158
|
+
const { port } = await main();
|
|
159
|
+
|
|
160
|
+
if (port !== preferredPort) {
|
|
161
|
+
status(`${c.yellow}~${c.reset}`, 'Port', `${preferredPort} was busy, using ${port}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ── Step 3: Detect platform ─────────────────────────────────────────────
|
|
165
|
+
const platforms = { win32: 'Windows', darwin: 'macOS', linux: 'Linux' };
|
|
166
|
+
const platformName = platforms[process.platform] || process.platform;
|
|
167
|
+
status(`${c.blue}*${c.reset}`, 'Platform', platformName);
|
|
168
|
+
|
|
169
|
+
// ── Step 4: JSONL watch path ────────────────────────────────────────────
|
|
170
|
+
const os = await import('os');
|
|
171
|
+
const path = await import('path');
|
|
172
|
+
const claudeHome = path.join(os.homedir(), '.claude');
|
|
173
|
+
status(`${c.blue}*${c.reset}`, 'Watching', claudeHome);
|
|
174
|
+
|
|
175
|
+
// ── Ready banner ────────────────────────────────────────────────────────
|
|
176
|
+
const url = `http://localhost:${port}`;
|
|
177
|
+
console.log();
|
|
178
|
+
console.log(` ${c.bgBlue}${c.white}${c.bold} READY ${c.reset} ${c.cyan}${c.bold}${url}${c.reset}`);
|
|
179
|
+
console.log();
|
|
180
|
+
console.log(`${c.dim} Press ${c.reset}Ctrl+C${c.dim} to stop the server${c.reset}`);
|
|
181
|
+
|
|
182
|
+
troubleshooting();
|
|
183
|
+
|
|
184
|
+
// ── Step 5: Auto-open browser ───────────────────────────────────────────
|
|
185
|
+
if (!skipOpen) {
|
|
186
|
+
const { exec } = await import('child_process');
|
|
187
|
+
let cmd;
|
|
188
|
+
switch (process.platform) {
|
|
189
|
+
case 'win32':
|
|
190
|
+
cmd = `start "" "${url}"`;
|
|
191
|
+
break;
|
|
192
|
+
case 'darwin':
|
|
193
|
+
cmd = `open "${url}"`;
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
// Linux and others — try xdg-open, fall back to nothing
|
|
197
|
+
cmd = `xdg-open "${url}" 2>/dev/null || true`;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
exec(cmd, () => {});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
run().catch((err) => {
|
|
205
|
+
console.error();
|
|
206
|
+
console.error(` ${c.red}${c.bold} FAILED ${c.reset} Could not start AgentMove`);
|
|
207
|
+
console.error();
|
|
208
|
+
|
|
209
|
+
const msg = err?.message ?? String(err);
|
|
210
|
+
|
|
211
|
+
if (msg.includes('EADDRINUSE')) {
|
|
212
|
+
console.error(` ${c.red}!${c.reset} Port ${preferredPort} is already in use.`);
|
|
213
|
+
console.error(`${c.dim} Try: ${c.reset}npx @foothill/agent-move --port ${preferredPort + 1}`);
|
|
214
|
+
} else if (msg.includes('EACCES')) {
|
|
215
|
+
console.error(` ${c.red}!${c.reset} Permission denied on port ${preferredPort}.`);
|
|
216
|
+
console.error(`${c.dim} Try a port above 1024: ${c.reset}npx @foothill/agent-move --port 3333`);
|
|
217
|
+
} else if (msg.includes('Cannot find module')) {
|
|
218
|
+
console.error(` ${c.red}!${c.reset} Build artifacts missing.`);
|
|
219
|
+
console.error(`${c.dim} Run: ${c.reset}npm run build`);
|
|
220
|
+
} else {
|
|
221
|
+
console.error(` ${c.red}!${c.reset} ${msg}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.error();
|
|
225
|
+
console.error(`${c.dim} Need help? https://github.com/FoothillSolutions/agent-move/issues${c.reset}`);
|
|
226
|
+
console.error();
|
|
227
|
+
process.exit(1);
|
|
228
|
+
});
|
|
229
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@foothill/agent-move",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"description": "Watch your AI coding agents come alive as pixel-art characters in a 2D world",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/FoothillSolutions/agent-move"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"agent-move": "bin/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/",
|
|
19
|
+
".github/screenshot.png",
|
|
20
|
+
"packages/shared/dist/",
|
|
21
|
+
"packages/shared/package.json",
|
|
22
|
+
"packages/server/dist/",
|
|
23
|
+
"packages/server/package.json",
|
|
24
|
+
"packages/client/dist/",
|
|
25
|
+
"packages/client/package.json"
|
|
26
|
+
],
|
|
27
|
+
"workspaces": [
|
|
28
|
+
"packages/shared",
|
|
29
|
+
"packages/server",
|
|
30
|
+
"packages/client"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"dev": "npm run build -w @agent-move/shared && concurrently -n server,client -c blue,green \"npm run dev -w @agent-move/server\" \"npm run dev -w @agent-move/client\"",
|
|
34
|
+
"build": "npm run build -w @agent-move/shared && npm run build -w @agent-move/server && npm run build -w @agent-move/client",
|
|
35
|
+
"typecheck": "tsc -b",
|
|
36
|
+
"prepublishOnly": "npm run build"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@fastify/cors": "^10.0.2",
|
|
40
|
+
"@fastify/static": "^8.1.0",
|
|
41
|
+
"@fastify/websocket": "^11.0.2",
|
|
42
|
+
"chokidar": "^3.6.0",
|
|
43
|
+
"fastify": "^5.2.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"concurrently": "^9.1.2",
|
|
47
|
+
"esbuild": "^0.27.3",
|
|
48
|
+
"typescript": "^5.7.3"
|
|
49
|
+
},
|
|
50
|
+
"optionalDependencies": {
|
|
51
|
+
"@rollup/rollup-win32-x64-msvc": "^4.59.0"
|
|
52
|
+
}
|
|
53
|
+
}
|