chore: scaffold llama-watch Stream Deck plugin

This commit is contained in:
bzuccaro committed 2026-08-14 10:33:48 -06:00
1 parent fc8f80c019
commit 1b388b7adc
12 files changed
+2664

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
node_modules/
*.streamDeckPlugin
.DS_Store
@@ -0,0 +1 @@
{ "type": "module" }
@@ -0,0 +1 @@
import e from"events";import t from"https";import s from"http";import n from"net";import i from"tls";import r from"crypto";import o from"stream";import a from"url";import c from"zlib";import l from"buffer";import h from"util";import d,{existsSync as u,readFileSync as f}from"node:fs";import p,{join as m}from"node:path";import{cwd as _}from"node:process";import{randomUUID as g}from"node:crypto";class v{events=new Map;addListener(e,t){return this.add(e,t,e=>e.push({listener:t}))}disposableOn(e,t){return this.add(e,t,e=>e.push({listener:t})),function(e){let t=!1;const s=()=>{t||(e(),t=!0)};return{[Symbol.dispose]:s,dispose:s}}(()=>this.removeListener(e,t))}emit(e,...t){const s=this.events.get(e);if(void 0===s)return!1;for(let n=0;n<s.length;){const{listener:i,once:r}=s[n];r?this.remove(e,s,n):n++,i(...t)}return!0}eventNames(){return Array.from(this.events.keys())}listenerCount(e,t){const s=this.events.get(e);if(void 0===s||null==t)return s?.length||0;let n=0;return s.forEach(e=>{e.listener===t&&n++}),n}listeners(e){return Array.from(this.events.get(e)||[]).map(({listener:e})=>e)}off(e,t){const s=this.events.get(e)??[];for(let n=s.length-1;n>=0;n--)s[n].listener===t&&this.remove(e,s,n);return this}on(e,t){return this.add(e,t,e=>e.push({listener:t}))}once(e,t){return this.add(e,t,e=>e.push({listener:t,once:!0}))}prependListener(e,t){return this.add(e,t,e=>e.splice(0,0,{listener:t}))}prependOnceListener(e,t){return this.add(e,t,e=>e.splice(0,0,{listener:t,once:!0}))}removeAllListeners(e){const t=this.events.get(e)??[];for(;t.length>0;)this.remove(e,t,0);return this.events.delete(e),this}removeListener(e,t){return this.off(e,t)}add(e,t,s){let n=this.events.get(e);if(void 0===n&&(n=[],this.events.set(e,n)),s(n),"newListener"!==e){const s=[e,t];this.emit("newListener",...s)}return this}remove(e,t,s){const[{listener:n}]=t.splice(s,1);if("removeListener"!==e){const t=[e,n];this.emit("removeListener",...t)}}}function y(e){null==e||"object"!=typeof e||Object.isFrozen(e)||(Object.freeze(e),Object.values(e).forEach(y))}function b(e,t){return t.split(".").reduce((e,t)=>e&&e[t],e)}class w{#e;#t=new Map;#s;#n=new v;constructor(e,t){this.#e=e,this.#s=t}get language(){return this.#e}set language(e){this.#e!==e&&(this.#e=e,this.#n.emit("languageChange",e))}onLanguageChange(e){return this.#n.disposableOn("languageChange",e)}t(e,t=this.language){return this.translate(e,t)}translate(e,t=this.language){const s=new Set([t,t.replaceAll("_","-").split("-").at(0),"en"]);for(const t of s){const s=b(this.getTranslations(t),e);if(s)return s.toString()}return e}getTranslations(e){let t=this.#t.get(e);return void 0===t&&(t=this.#s(e),y(t),this.#t.set(e,t)),t}}class S{#i;#r;#o;constructor(e){e instanceof S?(this.#i=e.#i,this.#r=e.#r):Array.isArray(e)?(this.#i=()=>e.values(),this.#r=()=>e.length):e instanceof Map||e instanceof Set?(this.#i=()=>e.values(),this.#r=()=>e.size):(this.#i=e,this.#r=()=>{let e=0;for(const t of this)e++;return e})}get length(){return this.#r()}*[Symbol.iterator](){for(const e of this.#i())yield e}asIndexedPairs(){return new S(function*(){let e=0;for(const t of this)yield[e++,t]}.bind(this))}drop(e){if(isNaN(e)||e<0)throw new RangeError("limit must be 0, or a positive number");return new S(function*(){let t=0;for(const s of this)t++>=e&&(yield s)}.bind(this))}every(e){for(const t of this)if(!e(t))return!1;return!0}filter(e){return new S(function*(){for(const t of this)e(t)&&(yield t)}.bind(this))}find(e){for(const t of this)if(e(t))return t}findLast(e){let t;for(const s of this)e(s)&&(t=s);return t}flatMap(e){return new S(function*(){for(const t of this)for(const s of e(t))yield s}.bind(this))}forEach(e){for(const t of this)e(t)}includes(e){return this.some(t=>t===e)}map(e){return new S(function*(){for(const t of this)yield e(t)}.bind(this))}next(...e){this.#o??=this.#i();const t=this.#o.next(...e);return t.done&&(this.#o=void 0),t}reduce(e,t){if(0===this.length){if(void 0===t)throw new TypeError("Reduce of empty enumerable with no initial value.");return t}let s=t;for(const t of this)s=void 0===s?t:e(s,t);return s}return(e){return this.#o=void 0,{done:!0,value:e}}some(e){for(const t of this)if(e(t))return!0;return!1}take(e){if(isNaN(e)||e<0)throw new RangeError("limit must be 0, or a positive number");return new S(function*(){let t=0;for(const s of this)t++<e&&(yield s)}.bind(this))}throw(e){throw e}toArray(){return Array.from(this)}toJSON(){return this.toArray()}toString(){return`${this.toArray()}`}}Symbol.dispose??=Symbol("Symbol.dispose");class E{#a=void 0;#c;constructor(e){this.#c=e}get value(){return void 0===this.#a&&(this.#a=this.#c()),this.#a}}function x(){let e,t;return{promise:new Promise((s,n)=>{e=s,t=n}),resolve:e,reject:t}}function k(e,t,s){function n(s,n){var i;Object.defineProperty(s,"_zod",{value:s._zod??{},enumerable:!1}),(i=s._zod).traits??(i.traits=new Set),s._zod.traits.add(e),t(s,n);for(const e in o.prototype)e in s||Object.defineProperty(s,e,{value:o.prototype[e].bind(s)});s._zod.constr=o,s._zodLine truncated
@@ -0,0 +1,16 @@
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/manifest.json",
"Name": "llama-watch",
"Version": "1.0.0.0",
"Author": "Bryce Zuccaro",
"Actions": [],
"Category": "llama-watch",
"CodePath": "bin/plugin.js",
"Description": "Monitor llama-swap: in-flight requests per model and live GPU metric graphs.",
"Icon": "imgs/plugin/icon",
"SDKVersion": 2,
"Software": { "MinimumVersion": "6.5" },
"OS": [{ "Platform": "mac", "MinimumVersion": "13" }],
"Nodejs": { "Version": "24" },
"UUID": "com.bryce.llamawatch"
}
+2559
View File
File diff suppressed because it is too large. Load diff
+28
View File
@@ -0,0 +1,28 @@
{
"name": "llama-watch",
"version": "1.0.0",
"description": "Stream Deck plugin to monitor llama-swap requests and GPU metrics.",
"private": true,
"type": "module",
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w --watch.onEnd=\"streamdeck restart com.bryce.llamawatch\"",
"test": "tsx --test tests/"
},
"devDependencies": {
"@elgato/cli": "^1.8.1",
"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@tsconfig/node20": "^20.1.4",
"@types/node": "22.13.0",
"rollup": "^4.32.1",
"tslib": "^2.8.1",
"tsx": "^4.19.2",
"typescript": "^5.7.3"
},
"dependencies": {
"@elgato/streamdeck": "^2.1.1"
}
}
+40
View File
@@ -0,0 +1,40 @@
import commonjs from "@rollup/plugin-commonjs";
import nodeResolve from "@rollup/plugin-node-resolve";
import terser from "@rollup/plugin-terser";
import typescript from "@rollup/plugin-typescript";
import path from "node:path";
import url from "node:url";
const isWatching = !!process.env.ROLLUP_WATCH;
const sdPlugin = "com.bryce.llamawatch.sdPlugin";
const config = {
input: "src/plugin.ts",
output: {
file: `${sdPlugin}/bin/plugin.js`,
sourcemap: isWatching,
sourcemapPathTransform: (relativeSourcePath, sourcemapPath) => {
return url.pathToFileURL(path.resolve(path.dirname(sourcemapPath), relativeSourcePath)).href;
},
},
plugins: [
{
name: "watch-externals",
buildStart: function () {
this.addWatchFile(`${sdPlugin}/manifest.json`);
},
},
typescript({ mapRoot: isWatching ? "./" : undefined }),
nodeResolve({ browser: false, exportConditions: ["node"], preferBuiltins: true }),
commonjs(),
!isWatching && terser(),
{
name: "emit-module-package-file",
generateBundle() {
this.emitFile({ fileName: "package.json", source: `{ "type": "module" }`, type: "asset" });
},
},
],
};
export default config;
+1
View File
@@ -0,0 +1 @@
export {};
+1
View File
@@ -0,0 +1 @@
export {};
+3
View File
@@ -0,0 +1,3 @@
import streamDeck from "@elgato/streamdeck";
streamDeck.connect();
View File
Whitespace-only changes.
+11
View File
@@ -0,0 +1,11 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"customConditions": ["node"],
"noImplicitOverride": true,
"module": "ES2022",
"moduleResolution": "Bundler"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}