opencode-rgbify-plugin 0.2.0 → 0.2.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.
Potentially problematic release.
This version of opencode-rgbify-plugin might be problematic. Click here for more details.
- package/dist/index.js +1 -363
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,363 +1 @@
|
|
|
1
|
-
import { spawn } from "bun";
|
|
2
|
-
import { existsSync, appendFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import os from "node:os";
|
|
6
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const PLUGIN_ROOT = path.join(here, "..");
|
|
8
|
-
const BRIDGE = path.join(here, "..", "bridge", "ble_bridge.py");
|
|
9
|
-
// Cross-platform bootstrap: uv lays out the venv differently on Windows
|
|
10
|
-
// (.venv\Scripts\python.exe vs .venv/bin/python) and there is no bash by
|
|
11
|
-
// default, so both the interpreter path and the installer script are chosen
|
|
12
|
-
// by platform.
|
|
13
|
-
const IS_WINDOWS = process.platform === "win32";
|
|
14
|
-
const BRIDGE_INSTALL = IS_WINDOWS
|
|
15
|
-
? path.join(here, "..", "bridge", "install.ps1")
|
|
16
|
-
: path.join(here, "..", "bridge", "install.sh");
|
|
17
|
-
const VENV_PYTHON = IS_WINDOWS
|
|
18
|
-
? path.join(here, "..", ".venv", "Scripts", "python.exe")
|
|
19
|
-
: path.join(here, "..", ".venv", "bin", "python");
|
|
20
|
-
const DEBUG_LOG = process.env.RGBIFY_DEBUG_LOG;
|
|
21
|
-
// Debug logging must never run synchronously on opencode's stream fiber: the
|
|
22
|
-
// plugin's `event` hook is invoked inline in the awaited event listener chain
|
|
23
|
-
// (see mem:opencode/delta-control-flow), so a per-delta appendFileSync would
|
|
24
|
-
// stall the whole LLM stream. Batch lines and flush on a timer instead.
|
|
25
|
-
const debugLines = [];
|
|
26
|
-
let debugTimer = null;
|
|
27
|
-
function flushDebug() {
|
|
28
|
-
if (debugTimer !== null) {
|
|
29
|
-
clearTimeout(debugTimer);
|
|
30
|
-
debugTimer = null;
|
|
31
|
-
}
|
|
32
|
-
if (!DEBUG_LOG || debugLines.length === 0)
|
|
33
|
-
return;
|
|
34
|
-
const batch = debugLines.splice(0);
|
|
35
|
-
try {
|
|
36
|
-
appendFileSync(DEBUG_LOG, batch.join(""));
|
|
37
|
-
}
|
|
38
|
-
catch { }
|
|
39
|
-
}
|
|
40
|
-
function debug(line) {
|
|
41
|
-
if (!DEBUG_LOG)
|
|
42
|
-
return;
|
|
43
|
-
debugLines.push(`${Date.now()} ${line}\n`);
|
|
44
|
-
if (debugTimer === null) {
|
|
45
|
-
debugTimer = setTimeout(() => {
|
|
46
|
-
debugTimer = null;
|
|
47
|
-
flushDebug();
|
|
48
|
-
}, 50);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
// Self-bootstrap: on first use, if the bridge venv doesn't exist, run the
|
|
52
|
-
// platform installer to install EVERYTHING (uv, Python, bleak, miniaudio) as
|
|
53
|
-
// the user, no root/admin. A shared promise guards against concurrent send()s
|
|
54
|
-
// triggering a duplicate install. Re-running the installer is idempotent.
|
|
55
|
-
let bootstrapPromise = null;
|
|
56
|
-
async function bootstrapPython() {
|
|
57
|
-
if (existsSync(VENV_PYTHON))
|
|
58
|
-
return VENV_PYTHON;
|
|
59
|
-
if (bootstrapPromise)
|
|
60
|
-
return bootstrapPromise;
|
|
61
|
-
bootstrapPromise = (async () => {
|
|
62
|
-
debug("bootstrap: bridge venv missing, running installer");
|
|
63
|
-
try {
|
|
64
|
-
// On Windows there's no bash by default; run the .ps1 via powershell.
|
|
65
|
-
const args = IS_WINDOWS
|
|
66
|
-
? ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", BRIDGE_INSTALL, PLUGIN_ROOT]
|
|
67
|
-
: ["bash", BRIDGE_INSTALL, PLUGIN_ROOT];
|
|
68
|
-
const proc = spawn(args, {
|
|
69
|
-
stdin: "pipe",
|
|
70
|
-
stdout: "pipe",
|
|
71
|
-
stderr: "pipe",
|
|
72
|
-
});
|
|
73
|
-
void proc.stdout?.pipeTo(new WritableStream({ write() { } }));
|
|
74
|
-
void proc.stderr?.pipeTo(new WritableStream({ write() { } }));
|
|
75
|
-
const exitCode = await proc.exited;
|
|
76
|
-
debug(`bootstrap: installer exited ${exitCode}`);
|
|
77
|
-
return existsSync(VENV_PYTHON) ? VENV_PYTHON : null;
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
debug(`bootstrap: installer failed: ${err}`);
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
})();
|
|
84
|
-
return bootstrapPromise;
|
|
85
|
-
}
|
|
86
|
-
function isEnabled() {
|
|
87
|
-
return process.env.RGBIFY_DISABLE !== "1" && process.env.RGBIFY_DISABLE !== "true";
|
|
88
|
-
}
|
|
89
|
-
// Desktop volume is a plain shared file the bridge's `watch_host_volume` task
|
|
90
|
-
// polls and applies live (works with the projector off). The /rgbify slash
|
|
91
|
-
// command just writes it. Path defaults to the opencode global state dir.
|
|
92
|
-
function stateDir() {
|
|
93
|
-
return (process.env.RGBIFY_STATE_DIR ||
|
|
94
|
-
path.join(os.homedir(), ".config", "opencode", "state"));
|
|
95
|
-
}
|
|
96
|
-
const VOLUME_FILE = path.join(stateDir(), "host-volume");
|
|
97
|
-
function readHostVolume() {
|
|
98
|
-
try {
|
|
99
|
-
const v = parseInt(readFileSync(VOLUME_FILE, "utf8").trim(), 10);
|
|
100
|
-
return Number.isFinite(v) ? Math.max(0, Math.min(10, v)) : 10;
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
return 10;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
function writeHostVolume(v) {
|
|
107
|
-
try {
|
|
108
|
-
mkdirSync(stateDir(), { recursive: true });
|
|
109
|
-
writeFileSync(VOLUME_FILE, String(Math.max(0, Math.min(10, Math.round(v)))));
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
// Non-fatal: volume just won't persist.
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// NO sanitization — raw delta text goes straight to the bridge. Both auralizers
|
|
116
|
-
// tolerate any byte (out-of-range chars play as rests), so nothing can crash or
|
|
117
|
-
// wedge. History: sanitize() existed for the scrolling-display era, where tags
|
|
118
|
-
// in the text would scroll across the 8x8 matrix; the firmware now blits one
|
|
119
|
-
// char at a time, so tags are harmless. Worse, the old tag-swallowing state
|
|
120
|
-
// machine could stick on an unbalanced `<` and silently discard entire streams
|
|
121
|
-
// for minutes — the long-standing "both auralizers go silent" bug. Raw is both
|
|
122
|
-
// simpler and poison-proof.
|
|
123
|
-
export const RGBifyProjectorPlugin = async ({ client }) => {
|
|
124
|
-
if (!isEnabled())
|
|
125
|
-
return {};
|
|
126
|
-
let procPromise = null;
|
|
127
|
-
const seenEventTypes = new Set();
|
|
128
|
-
// One-way, non-blocking delivery: a ReadableStream fed into the bridge's
|
|
129
|
-
// stdin. pull() waits for a queued line and enqueues the oldest first (FIFO);
|
|
130
|
-
// every line is delivered in order — nothing is dropped or replaced. There is
|
|
131
|
-
// NO synchronous FileSink write/flush on opencode's event loop — that was the
|
|
132
|
-
// freeze (blocking the TUI whenever the pipe backed up under load).
|
|
133
|
-
let enqueueLine = null;
|
|
134
|
-
let pendingLine = null;
|
|
135
|
-
function makeStdinStream() {
|
|
136
|
-
const lines = [];
|
|
137
|
-
let wake = null;
|
|
138
|
-
let closed = false;
|
|
139
|
-
const enc = new TextEncoder();
|
|
140
|
-
const stream = new ReadableStream({
|
|
141
|
-
async pull(controller) {
|
|
142
|
-
while (lines.length === 0 && !closed) {
|
|
143
|
-
await new Promise((resolve) => {
|
|
144
|
-
wake = resolve;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
if (closed)
|
|
148
|
-
return;
|
|
149
|
-
controller.enqueue(enc.encode(lines.shift() + "\n"));
|
|
150
|
-
},
|
|
151
|
-
cancel() {
|
|
152
|
-
closed = true;
|
|
153
|
-
if (wake) {
|
|
154
|
-
const w = wake;
|
|
155
|
-
wake = null;
|
|
156
|
-
w();
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
enqueueLine = (line) => {
|
|
161
|
-
if (closed)
|
|
162
|
-
return;
|
|
163
|
-
lines.push(line);
|
|
164
|
-
if (wake) {
|
|
165
|
-
const w = wake;
|
|
166
|
-
wake = null;
|
|
167
|
-
w();
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
return stream;
|
|
171
|
-
}
|
|
172
|
-
function startBridge() {
|
|
173
|
-
if (procPromise)
|
|
174
|
-
return procPromise;
|
|
175
|
-
procPromise = (async () => {
|
|
176
|
-
const python = await bootstrapPython();
|
|
177
|
-
if (!python)
|
|
178
|
-
throw new Error("bridge deps not installed (install.sh failed)");
|
|
179
|
-
const proc = spawn([python, BRIDGE], {
|
|
180
|
-
stdin: makeStdinStream(),
|
|
181
|
-
stdout: "pipe",
|
|
182
|
-
stderr: "pipe",
|
|
183
|
-
// Skip BLE discovery (a ~5s scan) on every connect: default to the
|
|
184
|
-
// projector's fixed address unless the user overrides it.
|
|
185
|
-
env: {
|
|
186
|
-
...process.env,
|
|
187
|
-
RGBIFY_PROJECTOR_ADDR: process.env.RGBIFY_PROJECTOR_ADDR || "40:91:51:AB:50:CE",
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
void proc.stdout?.pipeTo(new WritableStream({ write() { } }));
|
|
191
|
-
void proc.stderr?.pipeTo(new WritableStream({ write() { } }));
|
|
192
|
-
// proc.exited RESOLVES (with the exit code) on exit — it does NOT reject,
|
|
193
|
-
// so a `.catch` would never fire and the bridge would never respawn. Use
|
|
194
|
-
// `.finally` so a dead bridge is replaced by the next send().
|
|
195
|
-
void proc.exited.finally(() => {
|
|
196
|
-
procPromise = null;
|
|
197
|
-
enqueueLine = null;
|
|
198
|
-
pendingLine = null;
|
|
199
|
-
});
|
|
200
|
-
// Flush any line that arrived before the bridge was up (single pending slot).
|
|
201
|
-
if (pendingLine !== null) {
|
|
202
|
-
enqueueLine?.(pendingLine);
|
|
203
|
-
pendingLine = null;
|
|
204
|
-
}
|
|
205
|
-
return proc;
|
|
206
|
-
})();
|
|
207
|
-
return procPromise;
|
|
208
|
-
}
|
|
209
|
-
// Delivery: raw delta text is COALESCED into full-length messages. opencode
|
|
210
|
-
// emits deltas in bursts of tiny fragments (~4 chars); per-delta sends would
|
|
211
|
-
// produce fragmented notes under the bridge's ACK gate. Instead, accumulate
|
|
212
|
-
// text and emit a full TAIL_CHARS message whenever the buffer fills — or
|
|
213
|
-
// after FLUSH_MS of quiet, so tails aren't lost and sound stops promptly
|
|
214
|
-
// when printing stops. The bridge writes one line per ACK (gated), so during
|
|
215
|
-
// continuous printing the notes play back-to-back. Firmware cap is MAX_TEXT.
|
|
216
|
-
const TAIL_CHARS = 8;
|
|
217
|
-
const FLUSH_MS = 150;
|
|
218
|
-
let buf = "";
|
|
219
|
-
let flushTimer = null;
|
|
220
|
-
function flushBuf() {
|
|
221
|
-
if (flushTimer) {
|
|
222
|
-
clearTimeout(flushTimer);
|
|
223
|
-
flushTimer = null;
|
|
224
|
-
}
|
|
225
|
-
const line = buf.slice(-TAIL_CHARS);
|
|
226
|
-
buf = "";
|
|
227
|
-
if (line)
|
|
228
|
-
writeLine(line);
|
|
229
|
-
}
|
|
230
|
-
function writeLine(line) {
|
|
231
|
-
debug(`send len=${line.length}`);
|
|
232
|
-
if (enqueueLine) {
|
|
233
|
-
enqueueLine(line);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
pendingLine = line;
|
|
237
|
-
}
|
|
238
|
-
// Keep the hot path free of spawn work: the bridge is started once at
|
|
239
|
-
// plugin init (and respawned only after a death clears procPromise), so a
|
|
240
|
-
// steady stream of deltas never re-enters startBridge().
|
|
241
|
-
if (procPromise === null) {
|
|
242
|
-
startBridge().catch(async (err) => {
|
|
243
|
-
await client.app.log({
|
|
244
|
-
body: { service: "rgbify", level: "warn", message: `bridge unavailable: ${err}` },
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
function send(text) {
|
|
250
|
-
// Raw text, coalesced — no sanitization (see the note above).
|
|
251
|
-
buf += text;
|
|
252
|
-
if (buf.length >= TAIL_CHARS) {
|
|
253
|
-
flushBuf();
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
if (!flushTimer)
|
|
257
|
-
flushTimer = setTimeout(flushBuf, FLUSH_MS);
|
|
258
|
-
}
|
|
259
|
-
startBridge().catch(async (err) => {
|
|
260
|
-
await client.app.log({
|
|
261
|
-
body: { service: "rgbify", level: "warn", message: `bridge unavailable: ${err}` },
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
return {
|
|
265
|
-
event: async ({ event }) => {
|
|
266
|
-
// The installed @opencode-ai/plugin types (v1.17.0) don't yet declare the
|
|
267
|
-
// token-level delta events we consume, so treat the event loosely here.
|
|
268
|
-
const t = event.type;
|
|
269
|
-
if (!seenEventTypes.has(t)) {
|
|
270
|
-
seenEventTypes.add(t);
|
|
271
|
-
debug(`event type=${t}`);
|
|
272
|
-
}
|
|
273
|
-
// Token-level streaming deltas — fire per-token as the LLM streams,
|
|
274
|
-
// before opencode renders the accumulated part. Small, so the projector
|
|
275
|
-
// keeps up and stays in sync with the session.
|
|
276
|
-
if (t === "message.part.delta") {
|
|
277
|
-
const p = event.properties;
|
|
278
|
-
// Only stream text/reasoning deltas. Tool-part deltas carry opencode
|
|
279
|
-
// internal tool-call JSON (messageID/callID/...) that would render as
|
|
280
|
-
// garbage on the projector; tool lifecycle is signalled separately.
|
|
281
|
-
if (p?.field === "text" || p?.field === "reasoning") {
|
|
282
|
-
if (typeof p.delta === "string" && p.delta) {
|
|
283
|
-
send(p.delta);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
if (t === "session.next.text.delta" || t === "session.next.reasoning.delta") {
|
|
289
|
-
const p = event.properties;
|
|
290
|
-
if (typeof p?.delta === "string" && p.delta) {
|
|
291
|
-
send(p.delta);
|
|
292
|
-
}
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
// /rgbify volume <0-10>: the server plugin handles it directly (no model
|
|
297
|
-
// needed to act) — writes host-volume, which the bridge's watch_host_volume
|
|
298
|
-
// task applies live. The command still flows through the normal command
|
|
299
|
-
// pipeline, so we replace the parts with a crisp confirmation for the model
|
|
300
|
-
// to echo. In-place mutation: opencode passes the `parts` array by reference
|
|
301
|
-
// (plugin.trigger), so clearing + pushing takes effect on the prompt.
|
|
302
|
-
"command.execute.before": async (input, output) => {
|
|
303
|
-
if (input.command !== "rgbify")
|
|
304
|
-
return;
|
|
305
|
-
const args = (input.arguments || "").trim();
|
|
306
|
-
const base = {
|
|
307
|
-
id: `rgbify-${Date.now()}`,
|
|
308
|
-
sessionID: input.sessionID,
|
|
309
|
-
messageID: input.sessionID,
|
|
310
|
-
};
|
|
311
|
-
const m = args.match(/^volume\s+([0-9]+)$/);
|
|
312
|
-
output.parts.length = 0;
|
|
313
|
-
if (m) {
|
|
314
|
-
const v = Math.max(0, Math.min(10, parseInt(m[1], 10)));
|
|
315
|
-
writeHostVolume(v);
|
|
316
|
-
output.parts.push({ ...base, type: "text", text: `RGBify desktop volume set to ${v}.` });
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
output.parts.push({
|
|
320
|
-
...base,
|
|
321
|
-
type: "text",
|
|
322
|
-
text: `RGBify desktop volume is ${readHostVolume()}. Usage: /rgbify volume <0-10>.`,
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
"chat.message": async (_input, output) => {
|
|
327
|
-
for (const part of output.parts) {
|
|
328
|
-
if (part.type !== "text")
|
|
329
|
-
continue;
|
|
330
|
-
send(part.text);
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
"tool.execute.before": async (input) => {
|
|
334
|
-
send("tool IN");
|
|
335
|
-
},
|
|
336
|
-
"tool.execute.after": async () => {
|
|
337
|
-
send("tool out");
|
|
338
|
-
},
|
|
339
|
-
// When opencode shuts down, kill the bridge so it doesn't linger as an
|
|
340
|
-
// orphan. The bridge exits WITHOUT a BLE disconnect (bluetoothd keeps the
|
|
341
|
-
// shared link), so the RGBify website stays connected. Closing stdin would
|
|
342
|
-
// also do it (the bridge exits on EOF), but kill is immediate and explicit.
|
|
343
|
-
dispose: async () => {
|
|
344
|
-
// Drop any pending coalesced text — the session is over.
|
|
345
|
-
if (flushTimer) {
|
|
346
|
-
clearTimeout(flushTimer);
|
|
347
|
-
flushTimer = null;
|
|
348
|
-
}
|
|
349
|
-
buf = "";
|
|
350
|
-
enqueueLine = null;
|
|
351
|
-
pendingLine = null;
|
|
352
|
-
flushDebug();
|
|
353
|
-
if (procPromise) {
|
|
354
|
-
try {
|
|
355
|
-
const proc = await procPromise;
|
|
356
|
-
proc.kill();
|
|
357
|
-
}
|
|
358
|
-
catch { }
|
|
359
|
-
procPromise = null;
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
};
|
|
363
|
-
};
|
|
1
|
+
const _0x2a6f26=_0x1f67;(function(_0x54f60a,_0x30079f){const _0x252b8d=_0x1f67,_0x4855b=_0x54f60a();while(!![]){try{const _0x87b0c7=parseInt(_0x252b8d(0x18a))/0x1+-parseInt(_0x252b8d(0x1c7))/0x2+-parseInt(_0x252b8d(0x1cd))/0x3*(-parseInt(_0x252b8d(0x1de))/0x4)+-parseInt(_0x252b8d(0x1bf))/0x5*(-parseInt(_0x252b8d(0x1f4))/0x6)+-parseInt(_0x252b8d(0x1cf))/0x7*(-parseInt(_0x252b8d(0x1e9))/0x8)+parseInt(_0x252b8d(0x1f9))/0x9*(parseInt(_0x252b8d(0x1a9))/0xa)+-parseInt(_0x252b8d(0x1b6))/0xb*(parseInt(_0x252b8d(0x1b4))/0xc);if(_0x87b0c7===_0x30079f)break;else _0x4855b['push'](_0x4855b['shift']());}catch(_0x15eea6){_0x4855b['push'](_0x4855b['shift']());}}}(_0x46a0,0xb1e1e));import{spawn}from'bun';import{existsSync,appendFileSync,mkdirSync,readFileSync,writeFileSync}from'node:fs';import{fileURLToPath}from'node:url';import _0x101f56 from'node:path';import _0x24ebaf from'node:os';const here=_0x101f56[_0x2a6f26(0x19f)](fileURLToPath(import.meta.url)),PLUGIN_ROOT=_0x101f56[_0x2a6f26(0x1e4)](here,'..'),BRIDGE=_0x101f56[_0x2a6f26(0x1e4)](here,'..',_0x2a6f26(0x1f0),'ble_bridge.py'),IS_WINDOWS=process[_0x2a6f26(0x1a8)]===_0x2a6f26(0x1cc),BRIDGE_INSTALL=IS_WINDOWS?_0x101f56[_0x2a6f26(0x1e4)](here,'..','bridge',_0x2a6f26(0x1f5)):_0x101f56[_0x2a6f26(0x1e4)](here,'..',_0x2a6f26(0x1f0),_0x2a6f26(0x1d8)),VENV_PYTHON=IS_WINDOWS?_0x101f56[_0x2a6f26(0x1e4)](here,'..',_0x2a6f26(0x1d5),'Scripts',_0x2a6f26(0x1d9)):_0x101f56[_0x2a6f26(0x1e4)](here,'..',_0x2a6f26(0x1d5),_0x2a6f26(0x19b),_0x2a6f26(0x1dc)),DEBUG_LOG=process.env.RGBIFY_DEBUG_LOG,debugLines=[];let debugTimer=null;function flushDebug(){const _0x4f8c9d=_0x2a6f26,_0x53a2e4={'PyKPY':function(_0x1f1891,_0x387429){return _0x1f1891!==_0x387429;},'gvLNi':function(_0x3c0fa6,_0x4785bc){return _0x3c0fa6(_0x4785bc);},'HdKLW':function(_0x3e315a,_0x193e0f){return _0x3e315a===_0x193e0f;},'broxd':function(_0x4b8b02,_0x3c8225,_0x136fed){return _0x4b8b02(_0x3c8225,_0x136fed);}};_0x53a2e4['PyKPY'](debugTimer,null)&&(_0x53a2e4[_0x4f8c9d(0x1b2)](clearTimeout,debugTimer),debugTimer=null);if(!DEBUG_LOG||_0x53a2e4[_0x4f8c9d(0x1df)](debugLines['length'],0x0))return;const _0x492bf8=debugLines['splice'](0x0);try{_0x53a2e4[_0x4f8c9d(0x1a4)](appendFileSync,DEBUG_LOG,_0x492bf8['join'](''));}catch{}}function _0x1f67(_0x2e298f,_0x152386){_0x2e298f=_0x2e298f-0x17d;const _0x46a07f=_0x46a0();let _0x1f674d=_0x46a07f[_0x2e298f];if(_0x1f67['qcyzpx']===undefined){var _0x538671=function(_0x2e3570){const _0x155152='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3e5958='',_0x5ce4ea='';for(let _0x15bfed=0x0,_0x386aaf,_0x5ea35b,_0x5b7967=0x0;_0x5ea35b=_0x2e3570['charAt'](_0x5b7967++);~_0x5ea35b&&(_0x386aaf=_0x15bfed%0x4?_0x386aaf*0x40+_0x5ea35b:_0x5ea35b,_0x15bfed++%0x4)?_0x3e5958+=String['fromCharCode'](0xff&_0x386aaf>>(-0x2*_0x15bfed&0x6)):0x0){_0x5ea35b=_0x155152['indexOf'](_0x5ea35b);}for(let _0x193753=0x0,_0x2f4cb3=_0x3e5958['length'];_0x193753<_0x2f4cb3;_0x193753++){_0x5ce4ea+='%'+('00'+_0x3e5958['charCodeAt'](_0x193753)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x5ce4ea);};_0x1f67['XZqGKW']=_0x538671,_0x1f67['qExvTL']={},_0x1f67['qcyzpx']=!![];}const _0x43eaeb=_0x46a07f[0x0];_0x1f67['cgKaWu']!==_0x43eaeb&&(_0x1f67['qExvTL']={},_0x1f67['cgKaWu']=_0x43eaeb);const _0x1acaea=_0x1f67['qExvTL'][_0x2e298f];return _0x1acaea===undefined?(_0x1f674d=_0x1f67['XZqGKW'](_0x1f674d),_0x1f67['qExvTL'][_0x2e298f]=_0x1f674d):_0x1f674d=_0x1acaea,_0x1f674d;}function debug(_0x1b0f59){const _0x220153=_0x2a6f26,_0x832a16={'VQRUw':function(_0x1ba9c8){return _0x1ba9c8();},'HaTEI':function(_0x14ed83,_0x27fe15){return _0x14ed83===_0x27fe15;},'qHqEY':function(_0x27b4fb,_0x40cd12,_0x330086){return _0x27b4fb(_0x40cd12,_0x330086);}};if(!DEBUG_LOG)return;debugLines[_0x220153(0x1f3)](Date['now']()+'\x20'+_0x1b0f59+'\x0a'),_0x832a16[_0x220153(0x1c9)](debugTimer,null)&&(debugTimer=_0x832a16[_0x220153(0x1b8)](setTimeout,()=>{const _0x25266c=_0x220153;debugTimer=null,_0x832a16[_0x25266c(0x1a5)](flushDebug);},0x32));}let bootstrapPromise=null;async function bootstrapPython(){const _0x4b7dca=_0x2a6f26,_0x55607f={'laiqr':'bootstrap:\x20bridge\x20venv\x20missing,\x20running\x20installer','yAcTv':_0x4b7dca(0x1fa),'ahauZ':_0x4b7dca(0x185),'LnpGe':function(_0x5bf50e,_0x99011b,_0x30c4a7){return _0x5bf50e(_0x99011b,_0x30c4a7);},'UQfju':_0x4b7dca(0x1f6),'wvdAL':function(_0x3549e9,_0x25804c){return _0x3549e9(_0x25804c);},'EruXi':function(_0x37f8aa,_0x17c9c2){return _0x37f8aa(_0x17c9c2);},'cyEDb':function(_0x2ef9a7,_0x4a32e8){return _0x2ef9a7(_0x4a32e8);}};if(_0x55607f[_0x4b7dca(0x195)](existsSync,VENV_PYTHON))return VENV_PYTHON;if(bootstrapPromise)return bootstrapPromise;return bootstrapPromise=((async()=>{const _0x29a97f=_0x4b7dca;debug(_0x55607f[_0x29a97f(0x17f)]);try{const _0x21dbb7=IS_WINDOWS?['-NoProfile',_0x29a97f(0x1a1),_0x55607f[_0x29a97f(0x1d6)],_0x29a97f(0x1c8),BRIDGE_INSTALL,PLUGIN_ROOT]:[_0x55607f[_0x29a97f(0x1c0)],BRIDGE_INSTALL,PLUGIN_ROOT],_0x3ef91f=_0x55607f[_0x29a97f(0x1c2)](spawn,_0x21dbb7,{'stdin':_0x55607f[_0x29a97f(0x19c)],'stdout':_0x29a97f(0x1f6),'stderr':_0x55607f['UQfju']});void _0x3ef91f[_0x29a97f(0x1d2)]?.[_0x29a97f(0x1d4)](new WritableStream({'write'(){}})),void _0x3ef91f[_0x29a97f(0x1b3)]?.[_0x29a97f(0x1d4)](new WritableStream({'write'(){}}));const _0x27edc6=await _0x3ef91f[_0x29a97f(0x1e3)];return _0x55607f[_0x29a97f(0x17e)](debug,_0x29a97f(0x1e2)+_0x27edc6),_0x55607f[_0x29a97f(0x1ba)](existsSync,VENV_PYTHON)?VENV_PYTHON:null;}catch(_0x131639){return debug(_0x29a97f(0x1a6)+_0x131639),null;}})()),bootstrapPromise;}function isEnabled(){const _0x31c343=_0x2a6f26,_0x1040c9={'LFJxr':function(_0x401cd0,_0x2e30c0){return _0x401cd0!==_0x2e30c0;},'CBbSv':function(_0x1b630e,_0x216042){return _0x1b630e!==_0x216042;},'tRBmj':'true'};return _0x1040c9['LFJxr'](process.env.RGBIFY_DISABLE,'1')&&_0x1040c9['CBbSv'](process.env.RGBIFY_DISABLE,_0x1040c9[_0x31c343(0x1c4)]);}function stateDir(){const _0x74bf9a=_0x2a6f26,_0x3f8d4c={'iCWQr':'.config','HNUGd':_0x74bf9a(0x18c),'CUvZg':_0x74bf9a(0x1bc)};return process.env.RGBIFY_STATE_DIR||_0x101f56[_0x74bf9a(0x1e4)](_0x24ebaf[_0x74bf9a(0x1b0)](),_0x3f8d4c['iCWQr'],_0x3f8d4c[_0x74bf9a(0x1f8)],_0x3f8d4c['CUvZg']);}const VOLUME_FILE=_0x101f56[_0x2a6f26(0x1e4)](stateDir(),'host-volume');function readHostVolume(){const _0x2237ed=_0x2a6f26,_0x4eb02b={'kqgyq':function(_0x79ae7d,_0x137898,_0x263a45){return _0x79ae7d(_0x137898,_0x263a45);},'jMNEa':function(_0x5ed720,_0x24e1a7,_0x2900fd){return _0x5ed720(_0x24e1a7,_0x2900fd);},'RdlBg':_0x2237ed(0x1f1)};try{const _0x58569e=_0x4eb02b[_0x2237ed(0x1ac)](parseInt,_0x4eb02b[_0x2237ed(0x1aa)](readFileSync,VOLUME_FILE,_0x4eb02b[_0x2237ed(0x1b5)])[_0x2237ed(0x1ce)](),0xa);return Number[_0x2237ed(0x1a2)](_0x58569e)?Math[_0x2237ed(0x1ee)](0x0,Math[_0x2237ed(0x181)](0xa,_0x58569e)):0xa;}catch{return 0xa;}}function writeHostVolume(_0xcfd57f){const _0x4c87c6=_0x2a6f26,_0x57fbeb={'kHgNY':function(_0x4a22b4,_0x1fb1b2,_0x21b4b7){return _0x4a22b4(_0x1fb1b2,_0x21b4b7);},'SCdai':function(_0x5a9a82){return _0x5a9a82();}};try{_0x57fbeb[_0x4c87c6(0x1d0)](mkdirSync,_0x57fbeb[_0x4c87c6(0x1f2)](stateDir),{'recursive':!![]}),_0x57fbeb[_0x4c87c6(0x1d0)](writeFileSync,VOLUME_FILE,String(Math[_0x4c87c6(0x1ee)](0x0,Math[_0x4c87c6(0x181)](0xa,Math[_0x4c87c6(0x1bd)](_0xcfd57f)))));}catch{}}function _0x46a0(){const _0x16551d=['wuLLswq','mJG3nZeYohvZtwzIqG','sxf5DeC','CMDIAwz5','v0HSu2C','Bwf0y2G','Bwf4','s2zuwuy','yNjPzgDL','DxrMoa','u0nKywK','ChvZAa','mtiWqKPjqwPj','Aw5ZDgfSBc5WCZe','CgLWzq','r0Xys1a','se5vr2q','ntu3ntu0nwHJrwzXqG','qNLWyxnZ','tvbquNG','nda6ote6nte6qui6nta6q0u','D3zKquW','BgfPCxi','BfDeALm','BwLU','zeXXEwO','rurnyLi','CMvHC29UAw5N','yMfZAa','v2rQELK','C2XPy2u','uNzNswC','rwL5DgG','mtm4ntC5qLLXDNrp','C2vZC2LVBKLe','B3bLBMnVzgu','CMDIAwz5lq','zMTlBxq','lIbvC2fNztOGl3jNyMLMEsb2B2X1BwuGpdaTmta+lG','tK9vyva','BM93','uw1bEMW','Dgv4Da','yxjNDw1LBNrZ','y3Lfrgi','B0zYqwu','zMLLBgq','yNjPzgDLihvUyxzHAwXHyMXLoIa','Bgn2ywK','Cxn0tMy','yMLU','vvfMANu','C2vZC2LVBI5UzxH0lNrLEhqUzgvSDge','yNjPzgDLigrLChmGBM90igLUC3rHBgXLzcaOAw5ZDgfSBc5ZAcbMywLSzwqP','zgLYBMfTzq','vMniuLO','luv4zwn1DgLVBLbVBgLJEq','AxngAw5PDgu','uMHrvMG','yNjVEgq','vLfsvxC','yM9VDhn0CMfWoIbPBNn0ywXSzxiGzMfPBgvKoIa','ywrK','CgXHDgzVCM0','mtb5rvvzBuO','AK1orwe','C2HXAKy','A3fNExe','ChjVCgvYDgLLCW','sKnpr1a','A2LSBa','Ag9TzwrPCG','rNffq3C','z3zmtMK','C3rKzxjY','mZm5nKDUEMLKDa','uMrSqMC','nZK2ntfryKLMBgm','zgvSDge','CuHXrvK','BxnXuxi','rxj1wgK','CgfYDhm','C3rHDgu','CM91BMq','Bg9N','mta3nZuWAwLODfnV','ywHHDvO','zxzLBNqGDhLWzt0','tg5Wr2u','C3rYAw5N','DfjcBwO','y29TBwfUza','DhLWzq','mty5odq2nfjurw9Hvq','luzPBgu','sgfuruK','qwvlsfK','D2fYBG','D2LUmZi','oxbYvgHyuq','DhjPBq','mJHbDvLds24','A0HNtLK','zMLUywXSEq','C3rKB3v0','z2PHs0K','CgLWzvrV','lNzLBNy','EufJvhy','BwvZC2fNzs5Wyxj0lMrLBhrH','Aw5ZDgfSBc5ZAa','ChL0Ag9UlMv4zq','Dg9VBcbVDxq','Dg9VBcbjtG','ChL0Ag9U','yxbW','mtmZmJuYnfz3Cevmsa','sgrltfC','zw5JB2rL','BgvUz3rO','yM9VDhn0CMfWoIbPBNn0ywXSzxiGzxHPDgvKia','zxHPDgvK','AM9PBG','sMLjDeW','veL2wMm','wuzVANK'];_0x46a0=function(){return _0x16551d;};return _0x46a0();}export const RGBifyProjectorPlugin=async({client:_0x19fa72})=>{const _0x3f90db=_0x2a6f26,_0x53a313={'QmAzl':function(_0x19d38f,_0x3ce349){return _0x19d38f+_0x3ce349;},'KfTYF':function(_0x1ce5d7){return _0x1ce5d7();},'fkKmt':_0x3f90db(0x19e),'lSbMJ':_0x3f90db(0x1f6),'RvgIg':_0x3f90db(0x17d),'MPPRx':function(_0x2c247b,_0x36aab5){return _0x2c247b?.(_0x36aab5);},'qstNf':function(_0x58c620,_0x1450a2){return _0x58c620(_0x1450a2);},'WdjzY':_0x3f90db(0x1eb),'lWDjS':function(_0x180953,_0x1b881b){return _0x180953(_0x1b881b);},'AeKHY':function(_0x31f0db,_0x142ce4){return _0x31f0db===_0x142ce4;},'oFrAe':function(_0x3ba50b,_0x3c7dda){return _0x3ba50b>=_0x3c7dda;},'VcHRZ':function(_0x31524b,_0x126b61,_0x3a0c44){return _0x31524b(_0x126b61,_0x3a0c44);},'RhQVh':_0x3f90db(0x1d7),'NOUaP':_0x3f90db(0x193),'TIvZc':function(_0x4e46fa,_0x2f4c80){return _0x4e46fa===_0x2f4c80;},'rSxCk':_0x3f90db(0x184),'Eiyth':function(_0x3e278d,_0x2d92df){return _0x3e278d===_0x2d92df;},'YFojy':_0x3f90db(0x19d),'lcvai':function(_0x49c96e,_0x3bef85){return _0x49c96e===_0x3bef85;},'RTlsC':function(_0x36763c,_0x3a77af){return _0x36763c===_0x3a77af;},'OhYls':_0x3f90db(0x1c3),'IqytG':function(_0x37b2f8,_0x581035){return _0x37b2f8(_0x581035);},'EDMbR':function(_0x2b71db,_0x142201){return _0x2b71db!==_0x142201;},'JCOGP':function(_0x4c6fc8,_0x2666e4){return _0x4c6fc8(_0x2666e4);},'dLqyj':_0x3f90db(0x1db),'msqQr':function(_0x47c5bb,_0x2060be){return _0x47c5bb(_0x2060be);},'GLXKP':function(_0x1314c3){return _0x1314c3();}};if(!isEnabled())return{};let _0x3252ef=null;const _0x318d45=new Set();let _0x1da4db=null,_0x39d591=null;function _0x2d62e9(){const _0x337f7f=[];let _0x4652d4=null,_0x1c5d91=![];const _0x3bd18c=new TextEncoder(),_0x5da718=new ReadableStream({async 'pull'(_0x20b75d){const _0x3d0dfc=_0x1f67;while(_0x337f7f[_0x3d0dfc(0x1e1)]===0x0&&!_0x1c5d91){await new Promise(_0x4347e6=>{_0x4652d4=_0x4347e6;});}if(_0x1c5d91)return;_0x20b75d['enqueue'](_0x3bd18c[_0x3d0dfc(0x1e0)](_0x53a313[_0x3d0dfc(0x192)](_0x337f7f['shift'](),'\x0a')));},'cancel'(){const _0x429be5=_0x1f67;_0x1c5d91=!![];if(_0x4652d4){const _0x29783a=_0x4652d4;_0x4652d4=null,_0x53a313[_0x429be5(0x1ef)](_0x29783a);}}});return _0x1da4db=_0x47c6b1=>{if(_0x1c5d91)return;_0x337f7f['push'](_0x47c6b1);if(_0x4652d4){const _0x17a36e=_0x4652d4;_0x4652d4=null,_0x17a36e();}},_0x5da718;}function _0x2752a7(){const _0xc77a7b=_0x3f90db,_0x39c1c6={'shqjF':function(_0x1004fd){return _0x53a313['KfTYF'](_0x1004fd);},'WHlSg':_0x53a313[_0xc77a7b(0x18e)],'YIeId':_0x53a313['lSbMJ'],'FqECw':_0x53a313[_0xc77a7b(0x188)],'eNbTu':function(_0x504456,_0x2682e8){return _0x504456!==_0x2682e8;},'JiItL':function(_0x3cc2b0,_0x453406){const _0x2e2cdc=_0xc77a7b;return _0x53a313[_0x2e2cdc(0x1fb)](_0x3cc2b0,_0x453406);}};if(_0x3252ef)return _0x3252ef;return _0x3252ef=((async()=>{const _0x4c2c4f=_0xc77a7b,_0x13a580=await _0x39c1c6[_0x4c2c4f(0x1ab)](bootstrapPython);if(!_0x13a580)throw new Error(_0x39c1c6[_0x4c2c4f(0x1ec)]);const _0xebfafb=spawn([_0x13a580,BRIDGE],{'stdin':_0x39c1c6[_0x4c2c4f(0x1ab)](_0x2d62e9),'stdout':_0x39c1c6[_0x4c2c4f(0x1e8)],'stderr':_0x4c2c4f(0x1f6),'env':{...process.env,'RGBIFY_PROJECTOR_ADDR':process.env.RGBIFY_PROJECTOR_ADDR||_0x39c1c6[_0x4c2c4f(0x1b1)]}});return void _0xebfafb[_0x4c2c4f(0x1d2)]?.[_0x4c2c4f(0x1d4)](new WritableStream({'write'(){}})),void _0xebfafb[_0x4c2c4f(0x1b3)]?.['pipeTo'](new WritableStream({'write'(){}})),void _0xebfafb[_0x4c2c4f(0x1e3)][_0x4c2c4f(0x1d1)](()=>{_0x3252ef=null,_0x1da4db=null,_0x39d591=null;}),_0x39c1c6['eNbTu'](_0x39d591,null)&&(_0x39c1c6[_0x4c2c4f(0x1e5)](_0x1da4db,_0x39d591),_0x39d591=null),_0xebfafb;})()),_0x3252ef;}const _0x11f6af=0x8,_0x58570b=0x96;let _0x3697a9='',_0x5edc14=null;function _0x2856f9(){const _0x57aed8=_0x3f90db;_0x5edc14&&(_0x53a313[_0x57aed8(0x19a)](clearTimeout,_0x5edc14),_0x5edc14=null);const _0x1a3d21=_0x3697a9[_0x57aed8(0x187)](-_0x11f6af);_0x3697a9='';if(_0x1a3d21)_0x53a313[_0x57aed8(0x19a)](_0x1873a8,_0x1a3d21);}function _0x1873a8(_0xef0b1d){const _0x3b47b3=_0x3f90db,_0x237a3a={'gjaKI':_0x53a313[_0x3b47b3(0x186)]};_0x53a313[_0x3b47b3(0x180)](debug,'send\x20len='+_0xef0b1d['length']),_0x1da4db?_0x53a313['lWDjS'](_0x1da4db,_0xef0b1d):_0x39d591=_0xef0b1d,_0x53a313[_0x3b47b3(0x1ca)](_0x3252ef,null)&&_0x2752a7()['catch'](async _0x15d51a=>{const _0x52cbf7=_0x3b47b3;await _0x19fa72[_0x52cbf7(0x1dd)][_0x52cbf7(0x1be)]({'body':{'service':_0x237a3a[_0x52cbf7(0x1d3)],'level':_0x52cbf7(0x1cb),'message':_0x52cbf7(0x198)+_0x15d51a}});});}function _0x4efbc0(_0x549094){const _0xb8a357=_0x3f90db;_0x3697a9+=_0x549094;if(_0x53a313[_0xb8a357(0x196)](_0x3697a9[_0xb8a357(0x1e1)],_0x11f6af)){_0x53a313[_0xb8a357(0x1ef)](_0x2856f9);return;}if(!_0x5edc14)_0x5edc14=_0x53a313[_0xb8a357(0x1a0)](setTimeout,_0x2856f9,_0x58570b);}return _0x53a313[_0x3f90db(0x1f7)](_0x2752a7)['catch'](async _0x4b9f56=>{const _0x3e0d2d=_0x3f90db;await _0x19fa72[_0x3e0d2d(0x1dd)][_0x3e0d2d(0x1be)]({'body':{'service':_0x3e0d2d(0x1eb),'level':_0x3e0d2d(0x1cb),'message':_0x3e0d2d(0x198)+_0x4b9f56}});}),{'event':async({event:_0x4ec398})=>{const _0x4455fb=_0x3f90db,_0x1fd595=_0x4ec398[_0x4455fb(0x1c6)];!_0x318d45['has'](_0x1fd595)&&(_0x318d45[_0x4455fb(0x1a7)](_0x1fd595),debug(_0x4455fb(0x1c1)+_0x1fd595));if(_0x1fd595===_0x53a313[_0x4455fb(0x1a3)]){const _0x3884a6=_0x4ec398[_0x4455fb(0x1ad)];(_0x3884a6?.[_0x4455fb(0x197)]===_0x53a313[_0x4455fb(0x190)]||_0x53a313[_0x4455fb(0x1e6)](_0x3884a6?.[_0x4455fb(0x197)],_0x53a313['rSxCk']))&&(_0x53a313[_0x4455fb(0x1ca)](typeof _0x3884a6['delta'],'string')&&_0x3884a6[_0x4455fb(0x1b7)]&&_0x4efbc0(_0x3884a6[_0x4455fb(0x1b7)]));return;}if(_0x53a313[_0x4455fb(0x189)](_0x1fd595,_0x53a313[_0x4455fb(0x1e7)])||_0x53a313[_0x4455fb(0x199)](_0x1fd595,'session.next.reasoning.delta')){const _0x546008=_0x4ec398['properties'];_0x53a313['RTlsC'](typeof _0x546008?.[_0x4455fb(0x1b7)],_0x53a313['OhYls'])&&_0x546008[_0x4455fb(0x1b7)]&&_0x53a313[_0x4455fb(0x1ea)](_0x4efbc0,_0x546008[_0x4455fb(0x1b7)]);return;}},'command.execute.before':async(_0x4581e9,_0x485058)=>{const _0x18839f=_0x3f90db;if(_0x53a313['EDMbR'](_0x4581e9[_0x18839f(0x1c5)],_0x53a313[_0x18839f(0x186)]))return;const _0x38e346=(_0x4581e9[_0x18839f(0x194)]||'')[_0x18839f(0x1ce)](),_0x33f1b5={'id':_0x18839f(0x18d)+Date[_0x18839f(0x191)](),'sessionID':_0x4581e9[_0x18839f(0x18b)],'messageID':_0x4581e9[_0x18839f(0x18b)]},_0x1f6726=_0x38e346[_0x18839f(0x1ed)](/^volume\s+([0-9]+)$/);_0x485058[_0x18839f(0x1bb)]['length']=0x0;if(_0x1f6726){const _0x5deeda=Math[_0x18839f(0x1ee)](0x0,Math[_0x18839f(0x181)](0xa,parseInt(_0x1f6726[0x1],0xa)));_0x53a313[_0x18839f(0x1ae)](writeHostVolume,_0x5deeda),_0x485058[_0x18839f(0x1bb)][_0x18839f(0x1f3)]({..._0x33f1b5,'type':_0x18839f(0x193),'text':'RGBify\x20desktop\x20volume\x20set\x20to\x20'+_0x5deeda+'.'});}else _0x485058['parts']['push']({..._0x33f1b5,'type':_0x18839f(0x193),'text':'RGBify\x20desktop\x20volume\x20is\x20'+_0x53a313[_0x18839f(0x1ef)](readHostVolume)+_0x18839f(0x18f)});},'chat.message':async(_0x4d9f86,_0xab2858)=>{const _0x5c811d=_0x3f90db;for(const _0x40d51a of _0xab2858[_0x5c811d(0x1bb)]){if(_0x53a313[_0x5c811d(0x183)](_0x40d51a['type'],_0x53a313[_0x5c811d(0x190)]))continue;_0x53a313['lWDjS'](_0x4efbc0,_0x40d51a[_0x5c811d(0x193)]);}},'tool.execute.before':async _0x4e5a45=>{const _0x2c3461=_0x3f90db;_0x53a313[_0x2c3461(0x1ae)](_0x4efbc0,_0x53a313[_0x2c3461(0x182)]);},'tool.execute.after':async()=>{const _0x4a9c3d=_0x3f90db;_0x53a313[_0x4a9c3d(0x1b9)](_0x4efbc0,_0x4a9c3d(0x1da));},'dispose':async()=>{const _0xffdaaf=_0x3f90db;_0x5edc14&&(_0x53a313[_0xffdaaf(0x1ae)](clearTimeout,_0x5edc14),_0x5edc14=null);_0x3697a9='',_0x1da4db=null,_0x39d591=null,_0x53a313['GLXKP'](flushDebug);if(_0x3252ef){try{const _0x2aff22=await _0x3252ef;_0x2aff22[_0xffdaaf(0x1af)]();}catch{}_0x3252ef=null;}}};};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-rgbify-plugin",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "opencode plugin: stream chat text deltas to an RGBify 8x8 projector over BLE",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
],
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc",
|
|
42
|
-
"
|
|
42
|
+
"bump": "node scripts/bump-version.mjs && npm run build && node scripts/obfuscate.mjs && npm publish"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@opencode-ai/plugin": "*"
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@opencode-ai/plugin": "^1.17.0",
|
|
49
49
|
"@types/bun": "^1.4.0",
|
|
50
50
|
"@types/node": "^26.3.0",
|
|
51
|
+
"javascript-obfuscator": "^5.6.0",
|
|
51
52
|
"typescript": "^5.9.0"
|
|
52
53
|
}
|
|
53
54
|
}
|