opencode-avatar 0.3.6 → 0.3.8
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 -0
- package/dist/electron.js +8 -19
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ A dynamic desktop avatar plugin for OpenCode that displays animated character re
|
|
|
15
15
|
- **Toast Notifications**: Shows progress for avatar generation
|
|
16
16
|
- **Customizable Prompts**: Optional prompt configuration for personalized avatar styles
|
|
17
17
|
|
|
18
|
+
> **Warning:** If you use a lot of varied tools (like from an MCP), it will generate a lot of images per tool usage, which may cost alot with Nano Banana Pro. Character images for a tool are only generated as used.
|
|
19
|
+
|
|
18
20
|
## Installation
|
|
19
21
|
|
|
20
22
|
Then add to your OpenCode config:
|
package/dist/electron.js
CHANGED
|
@@ -405,11 +405,6 @@ import * as fs from "fs";
|
|
|
405
405
|
import * as os from "os";
|
|
406
406
|
import { fileURLToPath } from "url";
|
|
407
407
|
require_main().config();
|
|
408
|
-
var logFile = path.join(os.homedir(), "avatar.log");
|
|
409
|
-
function log(msg) {
|
|
410
|
-
fs.appendFileSync(logFile, new Date().toISOString() + ": " + msg + `
|
|
411
|
-
`);
|
|
412
|
-
}
|
|
413
408
|
function getConfig() {
|
|
414
409
|
try {
|
|
415
410
|
const configPath = path.join(os.homedir(), ".config", "opencode", "opencode-avatar.json");
|
|
@@ -424,7 +419,7 @@ function getConfig() {
|
|
|
424
419
|
}
|
|
425
420
|
var FAL_CDN_URL = "https://v3.fal.media";
|
|
426
421
|
var FAL_REST_URL = "https://rest.alpha.fal.ai";
|
|
427
|
-
var
|
|
422
|
+
var FAL_GROK_IMAGE_URL = "https://fal.run/xai/grok-imagine-image/edit";
|
|
428
423
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
429
424
|
var __dirnameResolved = path.dirname(__filename2);
|
|
430
425
|
var AVATAR_DIR = path.join(os.homedir(), ".config", "opencode");
|
|
@@ -517,11 +512,10 @@ var HTML_CONTENT = `<!DOCTYPE html>
|
|
|
517
512
|
img.src = canvas.toDataURL('image/png');
|
|
518
513
|
};
|
|
519
514
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
};
|
|
515
|
+
srcImg.onerror = function(e) {
|
|
516
|
+
console.error('Failed to load image:', e);
|
|
517
|
+
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
|
|
518
|
+
};
|
|
525
519
|
}
|
|
526
520
|
|
|
527
521
|
ipcRenderer.on('set-avatar', (event, avatarDataUrl) => {
|
|
@@ -601,7 +595,7 @@ async function uploadFile(filePath, falKey) {
|
|
|
601
595
|
return result.access_url || result.url || "";
|
|
602
596
|
}
|
|
603
597
|
async function generateAvatarImage(imageUrl, prompt, falKey) {
|
|
604
|
-
const response = await fetch(
|
|
598
|
+
const response = await fetch(FAL_GROK_IMAGE_URL, {
|
|
605
599
|
method: "POST",
|
|
606
600
|
headers: {
|
|
607
601
|
Authorization: `Key ${falKey}`,
|
|
@@ -609,7 +603,7 @@ async function generateAvatarImage(imageUrl, prompt, falKey) {
|
|
|
609
603
|
},
|
|
610
604
|
body: JSON.stringify({
|
|
611
605
|
prompt,
|
|
612
|
-
|
|
606
|
+
image_url: imageUrl
|
|
613
607
|
})
|
|
614
608
|
});
|
|
615
609
|
if (!response.ok) {
|
|
@@ -648,7 +642,7 @@ async function generateAvatarForPrompt(prompt) {
|
|
|
648
642
|
}
|
|
649
643
|
const sourceAvatar = path.join(AVATAR_DIR, "avatar.png");
|
|
650
644
|
const uploadedUrl = await uploadFile(sourceAvatar, config.falKey);
|
|
651
|
-
let fullPrompt = `make a character variant: ${prompt}. Keep the background as a solid green screen color. Do not let the green screen color appear in reflections or on the subject.`;
|
|
645
|
+
let fullPrompt = `make a character variant: ${prompt}, themed for Linux bash commands or MCP server services. Keep the background as a solid green screen color. Do not let the green screen color appear in reflections or on the subject.`;
|
|
652
646
|
if (config.prompt) {
|
|
653
647
|
fullPrompt += ` ${config.prompt}`;
|
|
654
648
|
}
|
|
@@ -690,7 +684,6 @@ function startAvatarServer() {
|
|
|
690
684
|
req.on("end", () => {
|
|
691
685
|
try {
|
|
692
686
|
const { avatarPath } = JSON.parse(body);
|
|
693
|
-
log("Set-avatar request with path: " + avatarPath);
|
|
694
687
|
if (mainWindow && avatarPath) {
|
|
695
688
|
const imageBuffer = fs.readFileSync(avatarPath);
|
|
696
689
|
const base64 = imageBuffer.toString("base64");
|
|
@@ -780,7 +773,6 @@ function createWindow() {
|
|
|
780
773
|
mainWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(HTML_CONTENT)}`);
|
|
781
774
|
mainWindow.webContents.on("did-finish-load", () => {
|
|
782
775
|
if (mainWindow) {
|
|
783
|
-
log("Window finished loading");
|
|
784
776
|
const avatarPath = getAvatarPath();
|
|
785
777
|
try {
|
|
786
778
|
const imageBuffer = fs.readFileSync(avatarPath);
|
|
@@ -834,7 +826,6 @@ function createTray() {
|
|
|
834
826
|
tray.on("click", () => mainWindow?.isVisible() ? mainWindow.hide() : mainWindow?.show());
|
|
835
827
|
}
|
|
836
828
|
function processTrayIcon(pngPath) {
|
|
837
|
-
log("Processing tray icon from: " + pngPath);
|
|
838
829
|
let trayIcon = nativeImage.createFromPath(pngPath);
|
|
839
830
|
if (!trayIcon.isEmpty()) {
|
|
840
831
|
const size = trayIcon.getSize();
|
|
@@ -852,9 +843,7 @@ function processTrayIcon(pngPath) {
|
|
|
852
843
|
}
|
|
853
844
|
}
|
|
854
845
|
trayIcon = nativeImage.createFromBitmap(bitmap, size);
|
|
855
|
-
log("Tray icon processed successfully");
|
|
856
846
|
} else {
|
|
857
|
-
log("Tray icon is empty, using fallback");
|
|
858
847
|
trayIcon = nativeImage.createFromDataURL("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==");
|
|
859
848
|
}
|
|
860
849
|
return trayIcon;
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as path from "path";
|
|
|
5
5
|
import * as http from "http";
|
|
6
6
|
import * as fs from "fs";
|
|
7
7
|
import * as os from "os";
|
|
8
|
-
var __dirname = "/var/home/wizard/
|
|
8
|
+
var __dirname = "/var/home/wizard/opencode-avatar";
|
|
9
9
|
var PLUGIN_DIR = __dirname;
|
|
10
10
|
var AVATAR_DIR = path.join(os.homedir(), ".config", "opencode");
|
|
11
11
|
var DEFAULT_AVATAR = "avatar.png";
|