vibe-monitor 1.0.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 +281 -0
- package/assets/generate-icons.js +86 -0
- package/assets/icon-128.png +0 -0
- package/assets/icon-16.png +0 -0
- package/assets/icon-256.png +0 -0
- package/assets/icon-32.png +0 -0
- package/assets/icon-64.png +0 -0
- package/assets/icon-generator.html +221 -0
- package/assets/icon.icns +0 -0
- package/assets/icon.ico +0 -0
- package/assets/icon.png +0 -0
- package/bin/cli.js +11 -0
- package/index.html +56 -0
- package/main.js +504 -0
- package/package.json +81 -0
- package/preload.js +9 -0
- package/renderer.js +222 -0
- package/styles.css +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Vibe Monitor Desktop App
|
|
2
|
+
|
|
3
|
+
Electron-based desktop app for real-time monitoring of AI coding assistants (Claude Code, Kiro IDE/CLI) with pixel art character.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Frameless Window**: Clean floating design
|
|
8
|
+
- **Always on Top**: Always displayed above other windows
|
|
9
|
+
- **System Tray**: Quick control from the menu bar
|
|
10
|
+
- **HTTP API**: Easy integration with IDE hooks (Claude Code, Kiro)
|
|
11
|
+
- **Draggable**: Move the window to any position
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd desktop
|
|
17
|
+
npm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Run the App
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm start
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Update Status via HTTP API
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Change to working state
|
|
32
|
+
curl -X POST http://127.0.0.1:19280/status \
|
|
33
|
+
-H "Content-Type: application/json" \
|
|
34
|
+
-d '{"state":"working","tool":"Bash","project":"my-project","model":"opus","memory":"45%"}'
|
|
35
|
+
|
|
36
|
+
# Check current status
|
|
37
|
+
curl http://127.0.0.1:19280/status
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### IDE Hooks Integration
|
|
41
|
+
|
|
42
|
+
#### Claude Code
|
|
43
|
+
|
|
44
|
+
Uses `hooks/vibe-monitor.sh` - see [main README](../README.md#claude-code-setup) for setup.
|
|
45
|
+
|
|
46
|
+
#### Kiro IDE
|
|
47
|
+
|
|
48
|
+
Copy hook files to `~/.kiro/hooks/` (or your project's `.kiro/hooks/` folder):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Global installation (recommended)
|
|
52
|
+
mkdir -p ~/.kiro/hooks
|
|
53
|
+
cp config/kiro/hooks/*.kiro.hook ~/.kiro/hooks/
|
|
54
|
+
|
|
55
|
+
# Or project-level installation
|
|
56
|
+
# cp config/kiro/hooks/*.kiro.hook your-project/.kiro/hooks/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Hook files:**
|
|
60
|
+
- `vibe-monitor-agent-spawn.kiro.hook` - Sends `start` on `agentSpawn`
|
|
61
|
+
- `vibe-monitor-prompt-submit.kiro.hook` - Sends `working` on `promptSubmit`
|
|
62
|
+
- `vibe-monitor-pre-tool-use.kiro.hook` - Sends `working` on `preToolUse`
|
|
63
|
+
- `vibe-monitor-agent-stop.kiro.hook` - Sends `idle` on `agentStop`
|
|
64
|
+
|
|
65
|
+
## Supported IDEs
|
|
66
|
+
|
|
67
|
+
| IDE | Hook System | Status |
|
|
68
|
+
|-----|-------------|--------|
|
|
69
|
+
| **Claude Code** | Shell hooks via `settings.json` | ✅ Supported |
|
|
70
|
+
| **Kiro IDE** | `.kiro.hook` files in `.kiro/hooks/` | ✅ Supported |
|
|
71
|
+
|
|
72
|
+
## States & Characters
|
|
73
|
+
|
|
74
|
+
See [main README](../README.md#state-display) for details on states, animations, and characters.
|
|
75
|
+
|
|
76
|
+
## API
|
|
77
|
+
|
|
78
|
+
### POST /status
|
|
79
|
+
|
|
80
|
+
Update status
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"state": "working",
|
|
85
|
+
"event": "PreToolUse",
|
|
86
|
+
"tool": "Bash",
|
|
87
|
+
"project": "vibe-monitor",
|
|
88
|
+
"model": "opus",
|
|
89
|
+
"memory": "45%",
|
|
90
|
+
"character": "clawd"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### GET /status
|
|
95
|
+
|
|
96
|
+
Get current status
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"state": "working",
|
|
101
|
+
"project": "vibe-monitor",
|
|
102
|
+
"tool": "Bash",
|
|
103
|
+
"model": "opus",
|
|
104
|
+
"memory": "45%"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### GET /health
|
|
109
|
+
|
|
110
|
+
Health check endpoint
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"status": "ok"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### POST /show
|
|
119
|
+
|
|
120
|
+
Show window and position to top-right corner
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"success": true
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### GET /debug
|
|
129
|
+
|
|
130
|
+
Get display and window debug information (useful for troubleshooting positioning issues)
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"primaryDisplay": {
|
|
135
|
+
"bounds": { "x": 0, "y": 0, "width": 1920, "height": 1080 },
|
|
136
|
+
"workArea": { "x": 0, "y": 0, "width": 1920, "height": 1040 },
|
|
137
|
+
"scaleFactor": 1
|
|
138
|
+
},
|
|
139
|
+
"window": { "x": 1748, "y": 0, "width": 172, "height": 348 },
|
|
140
|
+
"platform": "darwin"
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## WSL (Windows Subsystem for Linux)
|
|
145
|
+
|
|
146
|
+
Running the Electron app on WSL requires WSLg (Windows 11) and additional dependencies.
|
|
147
|
+
|
|
148
|
+
### Prerequisites
|
|
149
|
+
|
|
150
|
+
1. **Windows 11** with WSLg support
|
|
151
|
+
2. **Update WSL**:
|
|
152
|
+
```bash
|
|
153
|
+
wsl --update
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Install Dependencies
|
|
157
|
+
|
|
158
|
+
Electron requires several system libraries that are not installed by default on WSL:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Ubuntu 24.04 (Noble) or later
|
|
162
|
+
sudo apt-get update && sudo apt-get install -y \
|
|
163
|
+
libasound2t64 \
|
|
164
|
+
libatk1.0-0 \
|
|
165
|
+
libatk-bridge2.0-0 \
|
|
166
|
+
libcups2 \
|
|
167
|
+
libdrm2 \
|
|
168
|
+
libgbm1 \
|
|
169
|
+
libgtk-3-0 \
|
|
170
|
+
libnss3 \
|
|
171
|
+
libxcomposite1 \
|
|
172
|
+
libxdamage1 \
|
|
173
|
+
libxfixes3 \
|
|
174
|
+
libxkbcommon0 \
|
|
175
|
+
libxrandr2 \
|
|
176
|
+
libxshmfence1 \
|
|
177
|
+
libglu1-mesa
|
|
178
|
+
|
|
179
|
+
# Ubuntu 22.04 (Jammy) or earlier
|
|
180
|
+
sudo apt-get update && sudo apt-get install -y \
|
|
181
|
+
libasound2 \
|
|
182
|
+
libatk1.0-0 \
|
|
183
|
+
libatk-bridge2.0-0 \
|
|
184
|
+
libcups2 \
|
|
185
|
+
libdrm2 \
|
|
186
|
+
libgbm1 \
|
|
187
|
+
libgtk-3-0 \
|
|
188
|
+
libnss3 \
|
|
189
|
+
libxcomposite1 \
|
|
190
|
+
libxdamage1 \
|
|
191
|
+
libxfixes3 \
|
|
192
|
+
libxkbcommon0 \
|
|
193
|
+
libxrandr2
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Run
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
cd desktop
|
|
200
|
+
npm install
|
|
201
|
+
npm start
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Troubleshooting
|
|
205
|
+
|
|
206
|
+
**Error: `libasound.so.2: cannot open shared object file`**
|
|
207
|
+
|
|
208
|
+
Install the audio library:
|
|
209
|
+
```bash
|
|
210
|
+
# Ubuntu 24.04+
|
|
211
|
+
sudo apt-get install -y libasound2t64
|
|
212
|
+
|
|
213
|
+
# Ubuntu 22.04 or earlier
|
|
214
|
+
sudo apt-get install -y libasound2
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**GPU process errors (can be ignored)**
|
|
218
|
+
|
|
219
|
+
WSL may show GPU-related warnings like:
|
|
220
|
+
```
|
|
221
|
+
Exiting GPU process due to errors during initialization
|
|
222
|
+
```
|
|
223
|
+
These warnings don't affect app functionality.
|
|
224
|
+
|
|
225
|
+
**Window not appearing**
|
|
226
|
+
|
|
227
|
+
Ensure WSLg is working:
|
|
228
|
+
```bash
|
|
229
|
+
# Test with a simple GUI app
|
|
230
|
+
sudo apt-get install -y x11-apps
|
|
231
|
+
xclock
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
If xclock doesn't appear, WSLg may need to be enabled or updated.
|
|
235
|
+
|
|
236
|
+
## Build
|
|
237
|
+
|
|
238
|
+
Build for macOS:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm run build:mac
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Build DMG only:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
npm run build:dmg
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Build for Windows:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
npm run build:win
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Build for Linux:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
npm run build:linux
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Build for all platforms:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
npm run build:all
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Tray Menu
|
|
269
|
+
|
|
270
|
+
Click the system tray icon to:
|
|
271
|
+
- Check current status
|
|
272
|
+
- Manually change status
|
|
273
|
+
- Toggle Always on Top
|
|
274
|
+
- Show/Hide window
|
|
275
|
+
- Quit
|
|
276
|
+
|
|
277
|
+
## Port
|
|
278
|
+
|
|
279
|
+
Default HTTP server port: `19280`
|
|
280
|
+
|
|
281
|
+
(Can be changed via `HTTP_PORT` constant in main.js)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const { createCanvas } = require('canvas');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const COLOR_CLAUDE = '#D97757';
|
|
6
|
+
const COLOR_EYE = '#000000';
|
|
7
|
+
const COLOR_BG = '#FFCC00';
|
|
8
|
+
|
|
9
|
+
function drawIcon(size) {
|
|
10
|
+
const canvas = createCanvas(size, size);
|
|
11
|
+
const ctx = canvas.getContext('2d');
|
|
12
|
+
const scale = size / 64;
|
|
13
|
+
|
|
14
|
+
function rect(x, y, w, h, color) {
|
|
15
|
+
ctx.fillStyle = color;
|
|
16
|
+
ctx.fillRect(x * scale, y * scale, w * scale, h * scale);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Round rectangle background
|
|
20
|
+
const radius = size * 0.15;
|
|
21
|
+
ctx.fillStyle = COLOR_BG;
|
|
22
|
+
ctx.beginPath();
|
|
23
|
+
ctx.roundRect(0, 0, size, size, radius);
|
|
24
|
+
ctx.fill();
|
|
25
|
+
|
|
26
|
+
// Character positioning
|
|
27
|
+
const offsetX = 0;
|
|
28
|
+
const offsetY = 4;
|
|
29
|
+
|
|
30
|
+
// Main body (52x36)
|
|
31
|
+
rect(6 + offsetX, 8 + offsetY, 52, 36, COLOR_CLAUDE);
|
|
32
|
+
|
|
33
|
+
// Arms (6x10)
|
|
34
|
+
rect(0 + offsetX, 22 + offsetY, 6, 10, COLOR_CLAUDE);
|
|
35
|
+
rect(58 + offsetX, 22 + offsetY, 6, 10, COLOR_CLAUDE);
|
|
36
|
+
|
|
37
|
+
// Legs (4 legs)
|
|
38
|
+
rect(10 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE);
|
|
39
|
+
rect(18 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE);
|
|
40
|
+
rect(40 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE);
|
|
41
|
+
rect(48 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE);
|
|
42
|
+
|
|
43
|
+
// Alert eyes (round)
|
|
44
|
+
const leftX = 14 + offsetX;
|
|
45
|
+
const rightX = 44 + offsetX;
|
|
46
|
+
const eyeY = 22 + offsetY;
|
|
47
|
+
|
|
48
|
+
// Left eye
|
|
49
|
+
rect(leftX + 1, eyeY, 4, 6, COLOR_EYE);
|
|
50
|
+
rect(leftX, eyeY + 1, 6, 4, COLOR_EYE);
|
|
51
|
+
|
|
52
|
+
// Right eye
|
|
53
|
+
rect(rightX + 1, eyeY, 4, 6, COLOR_EYE);
|
|
54
|
+
rect(rightX, eyeY + 1, 6, 4, COLOR_EYE);
|
|
55
|
+
|
|
56
|
+
// Question mark
|
|
57
|
+
const qx = 50 + offsetX;
|
|
58
|
+
const qy = 2 + offsetY;
|
|
59
|
+
rect(qx + 1, qy, 4, 2, COLOR_EYE);
|
|
60
|
+
rect(qx + 4, qy + 2, 2, 2, COLOR_EYE);
|
|
61
|
+
rect(qx + 2, qy + 4, 2, 2, COLOR_EYE);
|
|
62
|
+
rect(qx + 2, qy + 6, 2, 2, COLOR_EYE);
|
|
63
|
+
rect(qx + 2, qy + 10, 2, 2, COLOR_EYE);
|
|
64
|
+
|
|
65
|
+
return canvas;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Generate icons
|
|
69
|
+
const sizes = [512, 256, 128, 64, 32, 16];
|
|
70
|
+
const assetsDir = __dirname;
|
|
71
|
+
|
|
72
|
+
console.log('Generating icons...');
|
|
73
|
+
|
|
74
|
+
sizes.forEach(size => {
|
|
75
|
+
const canvas = drawIcon(size);
|
|
76
|
+
const filename = size === 512 ? 'icon.png' : `icon-${size}.png`;
|
|
77
|
+
const filepath = path.join(assetsDir, filename);
|
|
78
|
+
const buffer = canvas.toBuffer('image/png');
|
|
79
|
+
fs.writeFileSync(filepath, buffer);
|
|
80
|
+
console.log(`Created: ${filename} (${size}x${size})`);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
console.log('\nDone! PNG files created.');
|
|
84
|
+
console.log('\nNext steps:');
|
|
85
|
+
console.log('1. For Windows (.ico): convert icon-256.png icon-128.png icon-64.png icon-32.png icon-16.png icon.ico');
|
|
86
|
+
console.log('2. For macOS (.icns): See instructions in icon-generator.html');
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Vibe Monitor Icon Generator</title>
|
|
6
|
+
<style>
|
|
7
|
+
body {
|
|
8
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
9
|
+
background: #1a1a2e;
|
|
10
|
+
color: white;
|
|
11
|
+
padding: 40px;
|
|
12
|
+
text-align: center;
|
|
13
|
+
}
|
|
14
|
+
.container {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-wrap: wrap;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
gap: 40px;
|
|
19
|
+
margin-top: 30px;
|
|
20
|
+
}
|
|
21
|
+
.icon-box {
|
|
22
|
+
background: #2d2d2d;
|
|
23
|
+
padding: 20px;
|
|
24
|
+
border-radius: 12px;
|
|
25
|
+
}
|
|
26
|
+
.icon-box h3 {
|
|
27
|
+
margin: 0 0 15px 0;
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
color: #888;
|
|
30
|
+
}
|
|
31
|
+
canvas {
|
|
32
|
+
display: block;
|
|
33
|
+
margin: 0 auto 15px;
|
|
34
|
+
border-radius: 8px;
|
|
35
|
+
}
|
|
36
|
+
button {
|
|
37
|
+
background: #D97757;
|
|
38
|
+
color: white;
|
|
39
|
+
border: none;
|
|
40
|
+
padding: 10px 20px;
|
|
41
|
+
border-radius: 6px;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
font-size: 14px;
|
|
44
|
+
margin: 5px;
|
|
45
|
+
}
|
|
46
|
+
button:hover {
|
|
47
|
+
background: #c86a2f;
|
|
48
|
+
}
|
|
49
|
+
.info {
|
|
50
|
+
max-width: 600px;
|
|
51
|
+
margin: 30px auto;
|
|
52
|
+
text-align: left;
|
|
53
|
+
background: #2d2d2d;
|
|
54
|
+
padding: 20px;
|
|
55
|
+
border-radius: 12px;
|
|
56
|
+
}
|
|
57
|
+
.info h2 {
|
|
58
|
+
margin-top: 0;
|
|
59
|
+
color: #D97757;
|
|
60
|
+
}
|
|
61
|
+
.info code {
|
|
62
|
+
background: #1a1a1a;
|
|
63
|
+
padding: 2px 6px;
|
|
64
|
+
border-radius: 4px;
|
|
65
|
+
}
|
|
66
|
+
.info pre {
|
|
67
|
+
background: #1a1a1a;
|
|
68
|
+
padding: 10px;
|
|
69
|
+
border-radius: 6px;
|
|
70
|
+
overflow-x: auto;
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
73
|
+
</head>
|
|
74
|
+
<body>
|
|
75
|
+
<h1>Vibe Monitor Icon Generator</h1>
|
|
76
|
+
<p>Notification character icons for desktop app</p>
|
|
77
|
+
|
|
78
|
+
<div class="container">
|
|
79
|
+
<div class="icon-box">
|
|
80
|
+
<h3>512x512 (Linux)</h3>
|
|
81
|
+
<canvas id="icon512" width="512" height="512"></canvas>
|
|
82
|
+
<button onclick="download('icon512', 'icon.png')">Download PNG</button>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="icon-box">
|
|
85
|
+
<h3>256x256 (Windows)</h3>
|
|
86
|
+
<canvas id="icon256" width="256" height="256"></canvas>
|
|
87
|
+
<button onclick="download('icon256', 'icon-256.png')">Download PNG</button>
|
|
88
|
+
</div>
|
|
89
|
+
<div class="icon-box">
|
|
90
|
+
<h3>128x128</h3>
|
|
91
|
+
<canvas id="icon128" width="128" height="128"></canvas>
|
|
92
|
+
<button onclick="download('icon128', 'icon-128.png')">Download PNG</button>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="icon-box">
|
|
95
|
+
<h3>64x64</h3>
|
|
96
|
+
<canvas id="icon64" width="64" height="64"></canvas>
|
|
97
|
+
<button onclick="download('icon64', 'icon-64.png')">Download PNG</button>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="icon-box">
|
|
100
|
+
<h3>32x32</h3>
|
|
101
|
+
<canvas id="icon32" width="32" height="32"></canvas>
|
|
102
|
+
<button onclick="download('icon32', 'icon-32.png')">Download PNG</button>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="icon-box">
|
|
105
|
+
<h3>16x16</h3>
|
|
106
|
+
<canvas id="icon16" width="16" height="16"></canvas>
|
|
107
|
+
<button onclick="download('icon16', 'icon-16.png')">Download PNG</button>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="info">
|
|
112
|
+
<h2>How to Create Icon Files</h2>
|
|
113
|
+
<p><strong>1. Download the PNG files</strong></p>
|
|
114
|
+
<p><strong>2. For Windows (.ico):</strong></p>
|
|
115
|
+
<pre>brew install imagemagick
|
|
116
|
+
convert icon-256.png icon-128.png icon-64.png icon-32.png icon-16.png icon.ico</pre>
|
|
117
|
+
|
|
118
|
+
<p><strong>3. For macOS (.icns):</strong></p>
|
|
119
|
+
<pre>mkdir icon.iconset
|
|
120
|
+
cp icon.png icon.iconset/icon_512x512.png
|
|
121
|
+
sips -z 256 256 icon.png --out icon.iconset/icon_256x256.png
|
|
122
|
+
sips -z 128 128 icon.png --out icon.iconset/icon_128x128.png
|
|
123
|
+
sips -z 64 64 icon.png --out icon.iconset/icon_64x64.png
|
|
124
|
+
sips -z 32 32 icon.png --out icon.iconset/icon_32x32.png
|
|
125
|
+
sips -z 16 16 icon.png --out icon.iconset/icon_16x16.png
|
|
126
|
+
iconutil -c icns icon.iconset</pre>
|
|
127
|
+
|
|
128
|
+
<p><strong>4. Place files in <code>desktop/assets/</code>:</strong></p>
|
|
129
|
+
<ul>
|
|
130
|
+
<li><code>icon.png</code> - 512x512 for Linux</li>
|
|
131
|
+
<li><code>icon.ico</code> - for Windows</li>
|
|
132
|
+
<li><code>icon.icns</code> - for macOS</li>
|
|
133
|
+
</ul>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<script>
|
|
137
|
+
const COLOR_CLAUDE = '#D97757';
|
|
138
|
+
const COLOR_EYE = '#000000';
|
|
139
|
+
|
|
140
|
+
// Base design is 64x64, scale up for larger sizes
|
|
141
|
+
function drawIcon(canvasId, size) {
|
|
142
|
+
const canvas = document.getElementById(canvasId);
|
|
143
|
+
const ctx = canvas.getContext('2d');
|
|
144
|
+
const scale = size / 64;
|
|
145
|
+
|
|
146
|
+
function rect(x, y, w, h, color) {
|
|
147
|
+
ctx.fillStyle = color;
|
|
148
|
+
ctx.fillRect(x * scale, y * scale, w * scale, h * scale);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Clear with transparent background
|
|
152
|
+
ctx.clearRect(0, 0, size, size);
|
|
153
|
+
|
|
154
|
+
// Round rectangle background (optional - for rounded icon look)
|
|
155
|
+
const radius = size * 0.15;
|
|
156
|
+
ctx.fillStyle = '#FFCC00';
|
|
157
|
+
ctx.beginPath();
|
|
158
|
+
ctx.roundRect(0, 0, size, size, radius);
|
|
159
|
+
ctx.fill();
|
|
160
|
+
|
|
161
|
+
// Character body - centered in 64x64 space
|
|
162
|
+
// Original positions adjusted for centering
|
|
163
|
+
const offsetX = 0;
|
|
164
|
+
const offsetY = 4;
|
|
165
|
+
|
|
166
|
+
// Main body (52x36 at position 6,8)
|
|
167
|
+
rect(6 + offsetX, 8 + offsetY, 52, 36, COLOR_CLAUDE);
|
|
168
|
+
|
|
169
|
+
// Arms (6x10)
|
|
170
|
+
rect(0 + offsetX, 22 + offsetY, 6, 10, COLOR_CLAUDE); // Left
|
|
171
|
+
rect(58 + offsetX, 22 + offsetY, 6, 10, COLOR_CLAUDE); // Right
|
|
172
|
+
|
|
173
|
+
// Legs (4 legs)
|
|
174
|
+
rect(10 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE); // Left outer
|
|
175
|
+
rect(18 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE); // Left inner
|
|
176
|
+
rect(40 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE); // Right inner
|
|
177
|
+
rect(48 + offsetX, 44 + offsetY, 6, 12, COLOR_CLAUDE); // Right outer
|
|
178
|
+
|
|
179
|
+
// Alert eyes (round)
|
|
180
|
+
const leftX = 14 + offsetX;
|
|
181
|
+
const rightX = 44 + offsetX;
|
|
182
|
+
const eyeY = 22 + offsetY;
|
|
183
|
+
|
|
184
|
+
// Left eye (circle approximation)
|
|
185
|
+
rect(leftX + 1, eyeY, 4, 6, COLOR_EYE);
|
|
186
|
+
rect(leftX, eyeY + 1, 6, 4, COLOR_EYE);
|
|
187
|
+
|
|
188
|
+
// Right eye (circle approximation)
|
|
189
|
+
rect(rightX + 1, eyeY, 4, 6, COLOR_EYE);
|
|
190
|
+
rect(rightX, eyeY + 1, 6, 4, COLOR_EYE);
|
|
191
|
+
|
|
192
|
+
// Question mark above head
|
|
193
|
+
const qx = 50 + offsetX;
|
|
194
|
+
const qy = 2 + offsetY;
|
|
195
|
+
rect(qx + 1, qy, 4, 2, COLOR_EYE); // Top curve
|
|
196
|
+
rect(qx + 4, qy + 2, 2, 2, COLOR_EYE); // Right side
|
|
197
|
+
rect(qx + 2, qy + 4, 2, 2, COLOR_EYE); // Middle
|
|
198
|
+
rect(qx + 2, qy + 6, 2, 2, COLOR_EYE); // Lower middle
|
|
199
|
+
rect(qx + 2, qy + 10, 2, 2, COLOR_EYE); // Dot
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function download(canvasId, filename) {
|
|
203
|
+
const canvas = document.getElementById(canvasId);
|
|
204
|
+
const link = document.createElement('a');
|
|
205
|
+
link.download = filename;
|
|
206
|
+
link.href = canvas.toDataURL('image/png');
|
|
207
|
+
link.click();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Draw all icons
|
|
211
|
+
window.onload = function() {
|
|
212
|
+
drawIcon('icon512', 512);
|
|
213
|
+
drawIcon('icon256', 256);
|
|
214
|
+
drawIcon('icon128', 128);
|
|
215
|
+
drawIcon('icon64', 64);
|
|
216
|
+
drawIcon('icon32', 32);
|
|
217
|
+
drawIcon('icon16', 16);
|
|
218
|
+
};
|
|
219
|
+
</script>
|
|
220
|
+
</body>
|
|
221
|
+
</html>
|
package/assets/icon.icns
ADDED
|
Binary file
|
package/assets/icon.ico
ADDED
|
Binary file
|
package/assets/icon.png
ADDED
|
Binary file
|
package/bin/cli.js
ADDED
package/index.html
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Vibe Monitor</title>
|
|
7
|
+
<link rel="stylesheet" href="../shared/styles.css">
|
|
8
|
+
<link rel="stylesheet" href="styles.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<!-- Draggable Title Bar -->
|
|
12
|
+
<div class="title-bar">
|
|
13
|
+
<div class="title-bar-buttons">
|
|
14
|
+
<button class="title-bar-btn btn-close" onclick="window.electronAPI.closeWindow()"></button>
|
|
15
|
+
<button class="title-bar-btn btn-minimize" onclick="window.electronAPI.minimizeWindow()"></button>
|
|
16
|
+
</div>
|
|
17
|
+
<span class="title-text">VibeMon</span>
|
|
18
|
+
<div style="width: 20px;"></div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<!-- Display -->
|
|
22
|
+
<div class="device-frame">
|
|
23
|
+
<div class="display" id="display">
|
|
24
|
+
<canvas id="character-canvas" width="128" height="128"></canvas>
|
|
25
|
+
<div class="status-text" id="status-text">Ready</div>
|
|
26
|
+
<div class="loading-dots" id="loading-dots">
|
|
27
|
+
<div class="dot dim"></div>
|
|
28
|
+
<div class="dot dim"></div>
|
|
29
|
+
<div class="dot dim"></div>
|
|
30
|
+
<div class="dot dim"></div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="info-text project-text">
|
|
33
|
+
<span class="info-label"><span class="emoji-icon">📂 </span><canvas class="pixel-icon" id="icon-project" width="8" height="8"></canvas></span>
|
|
34
|
+
<span class="info-value" id="project-value">-</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="info-text tool-text" id="tool-line">
|
|
37
|
+
<span class="info-label"><span class="emoji-icon">🛠️ </span><canvas class="pixel-icon" id="icon-tool" width="8" height="8"></canvas></span>
|
|
38
|
+
<span class="info-value" id="tool-value">-</span>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="info-text model-text" id="model-line">
|
|
41
|
+
<span class="info-label"><span class="emoji-icon">🤖 </span><canvas class="pixel-icon" id="icon-model" width="8" height="8"></canvas></span>
|
|
42
|
+
<span class="info-value" id="model-value">-</span>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="info-text memory-text" id="memory-line">
|
|
45
|
+
<span class="info-label"><span class="emoji-icon">🧠 </span><canvas class="pixel-icon" id="icon-memory" width="8" height="8"></canvas></span>
|
|
46
|
+
<span class="info-value" id="memory-value">-</span>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="memory-bar-container" id="memory-bar-container">
|
|
49
|
+
<div class="memory-bar" id="memory-bar"></div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<script type="module" src="renderer.js"></script>
|
|
55
|
+
</body>
|
|
56
|
+
</html>
|