3.9 KiB
3.9 KiB
AGENTS.md
Context for OpenCode sessions working on the Dynamic Deck Stream Deck plugin (com.ryan-kegel.dynamic-deck).
What this is
An Elgato Stream Deck plugin (SDK v3, Node.js 24) built with TypeScript + Rollup. Some actions are Windows-only because they shell out to PowerShell and use Win32 P/Invoke via the koffi FFI (user32.dll, kernel32.dll). Other actions are platform-agnostic.
Commands
npm run build— rollup production build tocom.ryan-kegel.dynamic-deck.sdPlugin/bin/plugin.js(terser-minified, no sourcemap).npm run watch— rollup watch with sourcemaps; on every rebuild triggersstreamdeck restart com.ryan-kegel.dynamic-deck.node generate-assets.cjs— writes 1x1 placeholder PNGs intoimgs/plugin/andimgs/actions/. Run once after cloning if those images are missing.- There is no test runner, linter, or typecheck script. The only verification is
npm run build(rollup runs the TS plugin, so type errors will surface here).
Source layout
src/plugin.ts— entrypoint. Registers actions, wiresAppMonitor(1s polling for foreground-window changes) andAppTrackerService(persisted toapp-stats.jsonin cwd), handles SIGINT/SIGTERM to flush stats, thenstreamDeck.connect()s.src/actions/<name>.ts— oneSingletonActionsubclass per Stream Deck action, each@action({ UUID: "com.ryan-kegel.dynamic-deck.<name>" }).src/services/—app-monitor.ts(Win32 FFI foreground tracking),app-tracker.ts(launch stats / ranking),blacklist-manager.ts.src/utils/app-launcher.ts— Start Menu.lnkscanning + 256x256 icon extraction via PowerShell + C#PrivateExtractIconsP/Invoke.src/ui/<action>.html+*.js— Property Inspector assets, copied as-is to the.sdPluginbundle.com.ryan-kegel.dynamic-deck.sdPlugin/— the built plugin bundle (output).manifest.json,bin/plugin.js, copiedui/,imgs/,scripts/,services/,utils/. This is what Stream Deck loads.
Conventions and gotchas
- Bundle shape is non-obvious.
rollup.config.mjscopiessrc/{ui,imgs,scripts,services,utils}into the.sdPlugin/folder alongside the builtbin/plugin.js. Edits to those files in the source tree won't appear until a rebuild copies them. The TS files copied underservices/andutils/are not the ones Rollup bundles — they are inert copies; the bundled code is what ends up inbin/plugin.js. RollupWatchPluginemits{"type":"module"}intobin/package.jsonso the host canimport()the bundle. Don't hand-edit that file.manifest.jsonis treated as a watched file; changes trigger a rebuild.- Several actions are currently commented out in
plugin.ts(e.g.IncrementCounter,EcobeeModeAction,EcobeeAction). To re-enable one, uncomment both the import and theregisterActionline. - The
app-stats.jsontracker file is written next toprocess.cwd()— i.e. inside the.sdPlugin/folder at runtime. Don't delete it without expecting reset ranking data. launch-app.tsusesev.action.setTitle()to write to Stream Deck's built-in Title field — do not add a custom title<input>inlaunch-app.html, you'll get two fields (see README §2).nodeengine is pinned to v24 viamanifest.json("Debug": "enabled"); debug by attaching VS Code to the running plugin process (the "Attach to Plugin" launch config in.vscode/launch.json).tsconfig.jsonextends@tsconfig/node20and usescustomConditions: ["node"]+moduleResolution: "Bundler"to match Rollup's resolution mode.
Things explicitly NOT to do
- Don't run
tscdirectly — there's no script and no outDir. The TS plugin runs as part of Rollup. - Don't add a
test/lintscript "just in case" — verify with the user first; none have been configured and the user may not want them. - Don't assume macOS support exists for app launching features —
app-launcher.tsandapp-monitor.tsuse Windows-specific APIs.