opencode-avatar 0.3.1 → 0.3.3
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 +2 -31
- package/dist/index.js +11 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A dynamic desktop avatar plugin for OpenCode that displays animated character reactions based on your coding activities.
|
|
4
4
|
|
|
5
|
-
<div align="center"><img src="
|
|
5
|
+
<div align="center"><img src="https://github.com/user-attachments/assets/504043c9-954d-4cfd-93ff-0904d2d4eb95" alt="Avatar" width="300" /></div>
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
@@ -17,12 +17,6 @@ A dynamic desktop avatar plugin for OpenCode that displays animated character re
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
### Option 1: From NPM (Recommended)
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm install -g opencode-avatar
|
|
24
|
-
```
|
|
25
|
-
|
|
26
20
|
Then add to your OpenCode config:
|
|
27
21
|
|
|
28
22
|
```json
|
|
@@ -32,15 +26,6 @@ Then add to your OpenCode config:
|
|
|
32
26
|
}
|
|
33
27
|
```
|
|
34
28
|
|
|
35
|
-
### Option 2: Local Development
|
|
36
|
-
|
|
37
|
-
1. Clone this repository
|
|
38
|
-
2. Run `npm install`
|
|
39
|
-
3. Run `npm run build`
|
|
40
|
-
4. Copy to your OpenCode plugins directory:
|
|
41
|
-
- Project: `.opencode/plugins/`
|
|
42
|
-
- Global: `~/.config/opencode/plugins/`
|
|
43
|
-
|
|
44
29
|
## Configuration
|
|
45
30
|
|
|
46
31
|
### API Key Configuration
|
|
@@ -101,20 +86,6 @@ All avatars are stored in `~/.config/opencode/` for persistence across updates.
|
|
|
101
86
|
| **Thinking** | User message | "Thinking hard" animation while processing |
|
|
102
87
|
| **Tool Active** | Tool execution | Pose based on current tool (write, read, etc.) |
|
|
103
88
|
|
|
104
|
-
### Tool Mappings
|
|
105
|
-
|
|
106
|
-
The avatar automatically detects which tools you're using and shows appropriate reactions:
|
|
107
|
-
|
|
108
|
-
| Tool | Avatar Pose |
|
|
109
|
-
|------|-------------|
|
|
110
|
-
| `write` | Writing with pencil |
|
|
111
|
-
| `read` | Reading a book |
|
|
112
|
-
| `edit` | Editing with scissors |
|
|
113
|
-
| `glob` | Searching with magnifying glass |
|
|
114
|
-
| `grep` | Detective searching |
|
|
115
|
-
| `bash` | Hacker typing |
|
|
116
|
-
| `webfetch` | Surfing the web |
|
|
117
|
-
|
|
118
89
|
### File Naming
|
|
119
90
|
|
|
120
91
|
Avatar images are cached with predictable filenames:
|
|
@@ -268,4 +239,4 @@ MIT License - see LICENSE file for details.
|
|
|
268
239
|
- Tool-based reactions
|
|
269
240
|
- Caching system
|
|
270
241
|
- Auto-shutdown
|
|
271
|
-
- Focus protection
|
|
242
|
+
- Focus protection
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,11 @@ import { spawn } from "child_process";
|
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as http from "http";
|
|
6
6
|
import * as fs from "fs";
|
|
7
|
+
import * as os from "os";
|
|
7
8
|
var __dirname = "/var/home/wizard/av";
|
|
8
9
|
var AVATAR_DIR = __dirname;
|
|
9
10
|
var DEFAULT_AVATAR = "avatar.png";
|
|
11
|
+
var USER_AVATAR = path.join(os.homedir(), ".config", "opencode", "avatar.png");
|
|
10
12
|
var THINKING_PROMPT = "thinking hard";
|
|
11
13
|
var AVATAR_PORT = 47291;
|
|
12
14
|
function getToolPrompt(toolName, toolDescription) {
|
|
@@ -17,11 +19,12 @@ function getToolPrompt(toolName, toolDescription) {
|
|
|
17
19
|
return toolName;
|
|
18
20
|
}
|
|
19
21
|
var electronProcess = null;
|
|
20
|
-
var currentAvatar =
|
|
22
|
+
var currentAvatar = getAvatarPath();
|
|
21
23
|
var isThinking = false;
|
|
22
24
|
var isToolActive = false;
|
|
23
25
|
var isShuttingDown = false;
|
|
24
26
|
var idleTriggered = false;
|
|
27
|
+
var currentRequestId = null;
|
|
25
28
|
var heartbeatInterval = null;
|
|
26
29
|
function sendHeartbeat() {
|
|
27
30
|
const req = http.request({
|
|
@@ -91,6 +94,9 @@ function promptToFilename(prompt, toolName) {
|
|
|
91
94
|
}
|
|
92
95
|
function getAvatarPath(prompt, toolName) {
|
|
93
96
|
if (!prompt) {
|
|
97
|
+
if (fs.existsSync(USER_AVATAR)) {
|
|
98
|
+
return USER_AVATAR;
|
|
99
|
+
}
|
|
94
100
|
return path.join(AVATAR_DIR, DEFAULT_AVATAR);
|
|
95
101
|
}
|
|
96
102
|
const filename = promptToFilename(prompt, toolName);
|
|
@@ -214,6 +220,8 @@ var AvatarPlugin = async ({ client }) => {
|
|
|
214
220
|
});
|
|
215
221
|
};
|
|
216
222
|
async function requestAvatarGeneration(prompt, showToasts = true, toolName) {
|
|
223
|
+
const requestId = `${Date.now()}-${Math.random()}`;
|
|
224
|
+
currentRequestId = requestId;
|
|
217
225
|
if (showToasts) {
|
|
218
226
|
showInfoToast(`Generating avatar: ${prompt}`);
|
|
219
227
|
}
|
|
@@ -236,7 +244,7 @@ var AvatarPlugin = async ({ client }) => {
|
|
|
236
244
|
if (showToasts) {
|
|
237
245
|
showInfoToast(`Avatar ready: ${prompt}`);
|
|
238
246
|
}
|
|
239
|
-
if (
|
|
247
|
+
if (currentRequestId === requestId) {
|
|
240
248
|
setAvatarViaHttp(prompt, toolName);
|
|
241
249
|
}
|
|
242
250
|
resolve();
|
|
@@ -294,6 +302,7 @@ var AvatarPlugin = async ({ client }) => {
|
|
|
294
302
|
idleTriggered = true;
|
|
295
303
|
isThinking = false;
|
|
296
304
|
isToolActive = false;
|
|
305
|
+
currentRequestId = null;
|
|
297
306
|
await setAvatarViaHttp();
|
|
298
307
|
}
|
|
299
308
|
}
|