@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.
Files changed (163) hide show
  1. package/.github/screenshot.png +0 -0
  2. package/README.md +266 -0
  3. package/bin/cli.js +229 -0
  4. package/package.json +53 -0
  5. package/packages/client/dist/assets/BufferResource-Ddjob236.js +185 -0
  6. package/packages/client/dist/assets/CanvasRenderer-B0w6SYyW.js +1 -0
  7. package/packages/client/dist/assets/Filter-NcMGuiK-.js +1 -0
  8. package/packages/client/dist/assets/RenderTargetSystem-DgAzY5_U.js +172 -0
  9. package/packages/client/dist/assets/WebGLRenderer-DUWXDPIX.js +156 -0
  10. package/packages/client/dist/assets/WebGPURenderer-C1HbrllR.js +41 -0
  11. package/packages/client/dist/assets/browserAll-CaF1Fl0O.js +14 -0
  12. package/packages/client/dist/assets/index-CMmR_RuS.css +1 -0
  13. package/packages/client/dist/assets/index-Dh8yWoLP.js +711 -0
  14. package/packages/client/dist/assets/webworkerAll-BJ6UhC7r.js +83 -0
  15. package/packages/client/dist/favicon.svg +27 -0
  16. package/packages/client/dist/index.html +167 -0
  17. package/packages/client/package.json +19 -0
  18. package/packages/server/dist/config.d.ts +12 -0
  19. package/packages/server/dist/config.d.ts.map +1 -0
  20. package/packages/server/dist/config.js +19 -0
  21. package/packages/server/dist/config.js.map +1 -0
  22. package/packages/server/dist/hooks/hook-event-manager.d.ts +39 -0
  23. package/packages/server/dist/hooks/hook-event-manager.d.ts.map +1 -0
  24. package/packages/server/dist/hooks/hook-event-manager.js +161 -0
  25. package/packages/server/dist/hooks/hook-event-manager.js.map +1 -0
  26. package/packages/server/dist/hooks/hook-installer.d.ts +14 -0
  27. package/packages/server/dist/hooks/hook-installer.d.ts.map +1 -0
  28. package/packages/server/dist/hooks/hook-installer.js +179 -0
  29. package/packages/server/dist/hooks/hook-installer.js.map +1 -0
  30. package/packages/server/dist/index.d.ts +4 -0
  31. package/packages/server/dist/index.d.ts.map +1 -0
  32. package/packages/server/dist/index.js +3544 -0
  33. package/packages/server/dist/index.js.map +1 -0
  34. package/packages/server/dist/routes/api.d.ts +4 -0
  35. package/packages/server/dist/routes/api.d.ts.map +1 -0
  36. package/packages/server/dist/routes/api.js +27 -0
  37. package/packages/server/dist/routes/api.js.map +1 -0
  38. package/packages/server/dist/state/activity-processor.d.ts +31 -0
  39. package/packages/server/dist/state/activity-processor.d.ts.map +1 -0
  40. package/packages/server/dist/state/activity-processor.js +417 -0
  41. package/packages/server/dist/state/activity-processor.js.map +1 -0
  42. package/packages/server/dist/state/agent-state-manager.d.ts +107 -0
  43. package/packages/server/dist/state/agent-state-manager.d.ts.map +1 -0
  44. package/packages/server/dist/state/agent-state-manager.js +1622 -0
  45. package/packages/server/dist/state/agent-state-manager.js.map +1 -0
  46. package/packages/server/dist/state/anomaly-detector.d.ts +23 -0
  47. package/packages/server/dist/state/anomaly-detector.d.ts.map +1 -0
  48. package/packages/server/dist/state/anomaly-detector.js +272 -0
  49. package/packages/server/dist/state/anomaly-detector.js.map +1 -0
  50. package/packages/server/dist/state/identity-manager.d.ts +31 -0
  51. package/packages/server/dist/state/identity-manager.d.ts.map +1 -0
  52. package/packages/server/dist/state/identity-manager.js +63 -0
  53. package/packages/server/dist/state/identity-manager.js.map +1 -0
  54. package/packages/server/dist/state/role-resolver.d.ts +23 -0
  55. package/packages/server/dist/state/role-resolver.d.ts.map +1 -0
  56. package/packages/server/dist/state/role-resolver.js +43 -0
  57. package/packages/server/dist/state/role-resolver.js.map +1 -0
  58. package/packages/server/dist/state/task-graph-manager.d.ts +31 -0
  59. package/packages/server/dist/state/task-graph-manager.d.ts.map +1 -0
  60. package/packages/server/dist/state/task-graph-manager.js +191 -0
  61. package/packages/server/dist/state/task-graph-manager.js.map +1 -0
  62. package/packages/server/dist/state/tool-chain-tracker.d.ts +23 -0
  63. package/packages/server/dist/state/tool-chain-tracker.d.ts.map +1 -0
  64. package/packages/server/dist/state/tool-chain-tracker.js +113 -0
  65. package/packages/server/dist/state/tool-chain-tracker.js.map +1 -0
  66. package/packages/server/dist/watcher/agent-watcher.d.ts +16 -0
  67. package/packages/server/dist/watcher/agent-watcher.d.ts.map +1 -0
  68. package/packages/server/dist/watcher/agent-watcher.js +0 -0
  69. package/packages/server/dist/watcher/agent-watcher.js.map +1 -0
  70. package/packages/server/dist/watcher/claude-paths.d.ts +32 -0
  71. package/packages/server/dist/watcher/claude-paths.d.ts.map +1 -0
  72. package/packages/server/dist/watcher/claude-paths.js +104 -0
  73. package/packages/server/dist/watcher/claude-paths.js.map +1 -0
  74. package/packages/server/dist/watcher/file-watcher.d.ts +17 -0
  75. package/packages/server/dist/watcher/file-watcher.d.ts.map +1 -0
  76. package/packages/server/dist/watcher/file-watcher.js +347 -0
  77. package/packages/server/dist/watcher/file-watcher.js.map +1 -0
  78. package/packages/server/dist/watcher/git-info.d.ts +3 -0
  79. package/packages/server/dist/watcher/git-info.d.ts.map +1 -0
  80. package/packages/server/dist/watcher/git-info.js +35 -0
  81. package/packages/server/dist/watcher/git-info.js.map +1 -0
  82. package/packages/server/dist/watcher/jsonl-parser.d.ts +21 -0
  83. package/packages/server/dist/watcher/jsonl-parser.d.ts.map +1 -0
  84. package/packages/server/dist/watcher/jsonl-parser.js +95 -0
  85. package/packages/server/dist/watcher/jsonl-parser.js.map +1 -0
  86. package/packages/server/dist/watcher/opencode/opencode-parser.d.ts +58 -0
  87. package/packages/server/dist/watcher/opencode/opencode-parser.d.ts.map +1 -0
  88. package/packages/server/dist/watcher/opencode/opencode-parser.js +256 -0
  89. package/packages/server/dist/watcher/opencode/opencode-parser.js.map +1 -0
  90. package/packages/server/dist/watcher/opencode/opencode-paths.d.ts +20 -0
  91. package/packages/server/dist/watcher/opencode/opencode-paths.d.ts.map +1 -0
  92. package/packages/server/dist/watcher/opencode/opencode-paths.js +35 -0
  93. package/packages/server/dist/watcher/opencode/opencode-paths.js.map +1 -0
  94. package/packages/server/dist/watcher/opencode/opencode-watcher.d.ts +49 -0
  95. package/packages/server/dist/watcher/opencode/opencode-watcher.d.ts.map +1 -0
  96. package/packages/server/dist/watcher/opencode/opencode-watcher.js +1292 -0
  97. package/packages/server/dist/watcher/opencode/opencode-watcher.js.map +1 -0
  98. package/packages/server/dist/watcher/session-scanner.d.ts +7 -0
  99. package/packages/server/dist/watcher/session-scanner.d.ts.map +1 -0
  100. package/packages/server/dist/watcher/session-scanner.js +69 -0
  101. package/packages/server/dist/watcher/session-scanner.js.map +1 -0
  102. package/packages/server/dist/ws/broadcaster.d.ts +18 -0
  103. package/packages/server/dist/ws/broadcaster.d.ts.map +1 -0
  104. package/packages/server/dist/ws/broadcaster.js +152 -0
  105. package/packages/server/dist/ws/broadcaster.js.map +1 -0
  106. package/packages/server/dist/ws/ws-handler.d.ts +6 -0
  107. package/packages/server/dist/ws/ws-handler.d.ts.map +1 -0
  108. package/packages/server/dist/ws/ws-handler.js +55 -0
  109. package/packages/server/dist/ws/ws-handler.js.map +1 -0
  110. package/packages/server/package.json +25 -0
  111. package/packages/shared/dist/constants/colors.d.ts +46 -0
  112. package/packages/shared/dist/constants/colors.d.ts.map +1 -0
  113. package/packages/shared/dist/constants/colors.js +178 -0
  114. package/packages/shared/dist/constants/colors.js.map +1 -0
  115. package/packages/shared/dist/constants/names.d.ts +6 -0
  116. package/packages/shared/dist/constants/names.d.ts.map +1 -0
  117. package/packages/shared/dist/constants/names.js +28 -0
  118. package/packages/shared/dist/constants/names.js.map +1 -0
  119. package/packages/shared/dist/constants/tools.d.ts +15 -0
  120. package/packages/shared/dist/constants/tools.d.ts.map +1 -0
  121. package/packages/shared/dist/constants/tools.js +120 -0
  122. package/packages/shared/dist/constants/tools.js.map +1 -0
  123. package/packages/shared/dist/constants/zones.d.ts +37 -0
  124. package/packages/shared/dist/constants/zones.d.ts.map +1 -0
  125. package/packages/shared/dist/constants/zones.js +128 -0
  126. package/packages/shared/dist/constants/zones.js.map +1 -0
  127. package/packages/shared/dist/index.d.ts +15 -0
  128. package/packages/shared/dist/index.d.ts.map +1 -0
  129. package/packages/shared/dist/index.js +7 -0
  130. package/packages/shared/dist/index.js.map +1 -0
  131. package/packages/shared/dist/types/agent.d.ts +85 -0
  132. package/packages/shared/dist/types/agent.d.ts.map +1 -0
  133. package/packages/shared/dist/types/agent.js +2 -0
  134. package/packages/shared/dist/types/agent.js.map +1 -0
  135. package/packages/shared/dist/types/anomaly.d.ts +18 -0
  136. package/packages/shared/dist/types/anomaly.d.ts.map +1 -0
  137. package/packages/shared/dist/types/anomaly.js +6 -0
  138. package/packages/shared/dist/types/anomaly.js.map +1 -0
  139. package/packages/shared/dist/types/hooks.d.ts +51 -0
  140. package/packages/shared/dist/types/hooks.d.ts.map +1 -0
  141. package/packages/shared/dist/types/hooks.js +2 -0
  142. package/packages/shared/dist/types/hooks.js.map +1 -0
  143. package/packages/shared/dist/types/jsonl.d.ts +62 -0
  144. package/packages/shared/dist/types/jsonl.d.ts.map +1 -0
  145. package/packages/shared/dist/types/jsonl.js +3 -0
  146. package/packages/shared/dist/types/jsonl.js.map +1 -0
  147. package/packages/shared/dist/types/task-graph.d.ts +20 -0
  148. package/packages/shared/dist/types/task-graph.d.ts.map +1 -0
  149. package/packages/shared/dist/types/task-graph.js +2 -0
  150. package/packages/shared/dist/types/task-graph.js.map +1 -0
  151. package/packages/shared/dist/types/tool-chain.d.ts +17 -0
  152. package/packages/shared/dist/types/tool-chain.d.ts.map +1 -0
  153. package/packages/shared/dist/types/tool-chain.js +2 -0
  154. package/packages/shared/dist/types/tool-chain.js.map +1 -0
  155. package/packages/shared/dist/types/websocket.d.ts +132 -0
  156. package/packages/shared/dist/types/websocket.d.ts.map +1 -0
  157. package/packages/shared/dist/types/websocket.js +2 -0
  158. package/packages/shared/dist/types/websocket.js.map +1 -0
  159. package/packages/shared/dist/types/zone.d.ts +21 -0
  160. package/packages/shared/dist/types/zone.d.ts.map +1 -0
  161. package/packages/shared/dist/types/zone.js +2 -0
  162. package/packages/shared/dist/types/zone.js.map +1 -0
  163. 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
+ [![npm version](https://img.shields.io/npm/v/agent-move)](https://www.npmjs.com/package/agent-move)
21
+ [![license](https://img.shields.io/npm/l/agent-move)](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
+ }