@agentdeck/bridge 1.0.11 → 1.0.13
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/assets/fm-helper/agentdeck-fm-helper +0 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +34 -19
- package/dist/cli.js.map +1 -1
- package/dist/d200h/hid-protocol.d.ts +62 -0
- package/dist/d200h/hid-protocol.d.ts.map +1 -0
- package/dist/d200h/hid-protocol.js +124 -0
- package/dist/d200h/hid-protocol.js.map +1 -0
- package/dist/d200h/image-renderer.d.ts +24 -0
- package/dist/d200h/image-renderer.d.ts.map +1 -0
- package/dist/d200h/image-renderer.js +321 -0
- package/dist/d200h/image-renderer.js.map +1 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +47 -1
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/hook-migration.d.ts +2 -0
- package/dist/hook-migration.d.ts.map +1 -0
- package/dist/hook-migration.js +116 -0
- package/dist/hook-migration.js.map +1 -0
- package/dist/modules/d200h-module.d.ts +65 -0
- package/dist/modules/d200h-module.d.ts.map +1 -0
- package/dist/modules/d200h-module.js +495 -0
- package/dist/modules/d200h-module.js.map +1 -0
- package/dist/modules/d200h-renderer.d.ts +7 -0
- package/dist/modules/d200h-renderer.d.ts.map +1 -0
- package/dist/modules/d200h-renderer.js +321 -0
- package/dist/modules/d200h-renderer.js.map +1 -0
- package/dist/modules/trmnl-module.d.ts +38 -0
- package/dist/modules/trmnl-module.d.ts.map +1 -0
- package/dist/modules/trmnl-module.js +111 -0
- package/dist/modules/trmnl-module.js.map +1 -0
- package/dist/passive-observer.d.ts +14 -1
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +90 -15
- package/dist/passive-observer.js.map +1 -1
- package/dist/trmnl/byos-server.d.ts +39 -0
- package/dist/trmnl/byos-server.d.ts.map +1 -0
- package/dist/trmnl/byos-server.js +301 -0
- package/dist/trmnl/byos-server.js.map +1 -0
- package/dist/trmnl/frame-cache.d.ts +37 -0
- package/dist/trmnl/frame-cache.d.ts.map +1 -0
- package/dist/trmnl/frame-cache.js +157 -0
- package/dist/trmnl/frame-cache.js.map +1 -0
- package/dist/trmnl/image-renderer.d.ts +27 -0
- package/dist/trmnl/image-renderer.d.ts.map +1 -0
- package/dist/trmnl/image-renderer.js +235 -0
- package/dist/trmnl/image-renderer.js.map +1 -0
- package/dist/trmnl/trmnl-settings.d.ts +96 -0
- package/dist/trmnl/trmnl-settings.d.ts.map +1 -0
- package/dist/trmnl/trmnl-settings.js +177 -0
- package/dist/trmnl/trmnl-settings.js.map +1 -0
- package/dist/trmnl/trmnl-telemetry.d.ts +47 -0
- package/dist/trmnl/trmnl-telemetry.d.ts.map +1 -0
- package/dist/trmnl/trmnl-telemetry.js +56 -0
- package/dist/trmnl/trmnl-telemetry.js.map +1 -0
- package/dist/whisper-server-manager.d.ts +19 -0
- package/dist/whisper-server-manager.d.ts.map +1 -0
- package/dist/whisper-server-manager.js +171 -0
- package/dist/whisper-server-manager.js.map +1 -0
- package/fm-helper/AgentDeckFMHelper.swift +111 -10
- package/package.json +3 -3
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D200H HID Device Module — communicates with Ulanzi D200H via stock HID protocol.
|
|
3
|
+
*
|
|
4
|
+
* The D200H boots into HID mode (VID 0x2207, PID 0x0019) after 4 seconds.
|
|
5
|
+
* This module:
|
|
6
|
+
* - Detects the device via node-hid enumeration
|
|
7
|
+
* - Sends dashboard images via SET_BUTTONS (ZIP with manifest.json + PNGs)
|
|
8
|
+
* - Receives button press events and dispatches commands
|
|
9
|
+
* - Manages brightness and keep-alive
|
|
10
|
+
*
|
|
11
|
+
* No ADB, no firmware modification, no on-device agent needed.
|
|
12
|
+
*/
|
|
13
|
+
import { buildZipPackets, buildBrightnessPacket, buildSmallWindowPacket, parseIncoming } from '../d200h/hid-protocol.js';
|
|
14
|
+
import { renderDashboardZip, stateHash, initRenderer, isResvgLoaded, buildButtonCommandMap } from '../d200h/image-renderer.js';
|
|
15
|
+
import { debug } from '../logger.js';
|
|
16
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
17
|
+
import { join } from 'path';
|
|
18
|
+
import { homedir } from 'os';
|
|
19
|
+
const TAG = 'd200h';
|
|
20
|
+
const VID = 0x2207;
|
|
21
|
+
const PID = 0x0019;
|
|
22
|
+
const CONSUMER_USAGE_PAGE = 12;
|
|
23
|
+
const KEYBOARD_USAGE_PAGE = 1;
|
|
24
|
+
const POLL_INTERVAL = 500; // Device detection polling (ms)
|
|
25
|
+
const READ_INTERVAL = 20; // HID read polling (ms)
|
|
26
|
+
const KEEPALIVE_INTERVAL = 30_000; // Keep-alive interval (ms)
|
|
27
|
+
// Button → command mapping is derived per-frame from the render layout
|
|
28
|
+
// (`buildButtonCommandMap`), so a key always does exactly what its rendered
|
|
29
|
+
// tile shows. See `currentCommandMap` below.
|
|
30
|
+
function isControllableSession(session) {
|
|
31
|
+
return !!session?.port && session.controlMode !== 'observed';
|
|
32
|
+
}
|
|
33
|
+
export class D200hModule {
|
|
34
|
+
name = 'd200h';
|
|
35
|
+
hidModule = null;
|
|
36
|
+
consumerDevice = null;
|
|
37
|
+
keyboardDevice = null;
|
|
38
|
+
pollTimer = null;
|
|
39
|
+
readTimer = null;
|
|
40
|
+
keepAliveTimer = null;
|
|
41
|
+
commandHandler = null;
|
|
42
|
+
lastStateHash = '';
|
|
43
|
+
lastState = {
|
|
44
|
+
state: 'IDLE',
|
|
45
|
+
projectName: '',
|
|
46
|
+
modelName: '',
|
|
47
|
+
mode: 'default',
|
|
48
|
+
agentType: 'daemon',
|
|
49
|
+
fiveHourPercent: 0,
|
|
50
|
+
sevenDayPercent: 0,
|
|
51
|
+
totalTokens: 0,
|
|
52
|
+
totalCost: 0,
|
|
53
|
+
options: [],
|
|
54
|
+
currentTool: '',
|
|
55
|
+
};
|
|
56
|
+
lastSessions = [];
|
|
57
|
+
hostDisplayOn = true;
|
|
58
|
+
dimEnabled = true;
|
|
59
|
+
dimMode = 'off';
|
|
60
|
+
dimLevel = 10;
|
|
61
|
+
lastDimSignature = '';
|
|
62
|
+
displaySuppressed = false;
|
|
63
|
+
// When true, the Ulanzi Studio plugin owns the D200H — direct-HID stands down
|
|
64
|
+
// (releases the device, suspends reconnect) so the two don't fight over it.
|
|
65
|
+
externalOwner = false;
|
|
66
|
+
// Physical-key index → command for the currently displayed frame. Rebuilt
|
|
67
|
+
// from the render layout on every updateDisplay so input matches the pixels.
|
|
68
|
+
currentCommandMap = new Map();
|
|
69
|
+
connected = false;
|
|
70
|
+
isUpdating = false;
|
|
71
|
+
pendingUpdate = null;
|
|
72
|
+
writeOK = 0;
|
|
73
|
+
writeFail = 0;
|
|
74
|
+
buttonPressCount = 0;
|
|
75
|
+
hidReportCount = 0;
|
|
76
|
+
lastWriteError = null;
|
|
77
|
+
lastOpenError = null;
|
|
78
|
+
async shouldActivate(config) {
|
|
79
|
+
if (config === false)
|
|
80
|
+
return false;
|
|
81
|
+
try {
|
|
82
|
+
this.hidModule = await this.loadHidModule();
|
|
83
|
+
if (!this.hidModule)
|
|
84
|
+
return false;
|
|
85
|
+
if (config === true)
|
|
86
|
+
return true;
|
|
87
|
+
// auto: check if D200H is connected
|
|
88
|
+
return this.findDevice() !== null;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async start(ctx) {
|
|
95
|
+
debug(TAG, 'Starting D200H HID module');
|
|
96
|
+
// Initialize SVG renderer (loads resvg-js if available)
|
|
97
|
+
await initRenderer();
|
|
98
|
+
// Wire command handler
|
|
99
|
+
this.commandHandler = (cmd) => ctx.wsServer.dispatchCommand(cmd);
|
|
100
|
+
// Forward state broadcasts to display
|
|
101
|
+
ctx.wsServer.onBroadcast((evt) => {
|
|
102
|
+
if (evt?.type === 'state_update') {
|
|
103
|
+
this.lastState = evt;
|
|
104
|
+
this.updateDisplay({ ...this.lastState, allSessions: this.lastSessions }).catch(() => { });
|
|
105
|
+
}
|
|
106
|
+
else if (evt?.type === 'usage_update') {
|
|
107
|
+
// Usage (5H/7D/tokens/cost) rides usage_update, NOT state_update — merge it
|
|
108
|
+
// in so the gauges aren't stuck at 0 (same gap fixed in the TRMNL module).
|
|
109
|
+
this.lastState = {
|
|
110
|
+
...this.lastState,
|
|
111
|
+
fiveHourPercent: evt.fiveHourPercent,
|
|
112
|
+
sevenDayPercent: evt.sevenDayPercent,
|
|
113
|
+
fiveHourResetsAt: evt.fiveHourResetsAt,
|
|
114
|
+
sevenDayResetsAt: evt.sevenDayResetsAt,
|
|
115
|
+
// Tri-state: distinguish "0% used" from "no quota data" so the gauges
|
|
116
|
+
// draw a "—" instead of a confident 0% (matches TRMNL / Ulanzi deck).
|
|
117
|
+
usageKnown: evt.usageStale === true
|
|
118
|
+
? false
|
|
119
|
+
: (evt.fiveHourPercent != null || evt.sevenDayPercent != null),
|
|
120
|
+
totalTokens: evt.totalTokens ?? ((evt.inputTokens ?? 0) + (evt.outputTokens ?? 0)),
|
|
121
|
+
totalCost: evt.totalCost ?? evt.estimatedCostUsd ?? this.lastState?.totalCost ?? 0,
|
|
122
|
+
};
|
|
123
|
+
this.updateDisplay({ ...this.lastState, allSessions: this.lastSessions }).catch(() => { });
|
|
124
|
+
}
|
|
125
|
+
else if (evt?.type === 'sessions_list') {
|
|
126
|
+
this.lastSessions = (evt.sessions ?? []).filter(isControllableSession);
|
|
127
|
+
if (this.lastState) {
|
|
128
|
+
this.updateDisplay({ ...this.lastState, allSessions: this.lastSessions }).catch(() => { });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (evt?.type === 'display_state') {
|
|
132
|
+
this.applyDisplayState(evt);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
// Stand down direct-HID whenever the Ulanzi Studio plugin is connected, so
|
|
136
|
+
// the daemon and Ulanzi Studio never drive the same device at once. Fires
|
|
137
|
+
// immediately with the current state.
|
|
138
|
+
ctx.wsServer.onUlanziPluginPresence((present) => this.setExternalOwner(present));
|
|
139
|
+
// Start device detection polling
|
|
140
|
+
this.tryConnect();
|
|
141
|
+
this.pollTimer = setInterval(() => {
|
|
142
|
+
if (!this.connected && !this.externalOwner) {
|
|
143
|
+
this.tryConnect();
|
|
144
|
+
}
|
|
145
|
+
}, POLL_INTERVAL);
|
|
146
|
+
}
|
|
147
|
+
async stop() {
|
|
148
|
+
debug(TAG, 'Stopping D200H HID module');
|
|
149
|
+
if (this.pollTimer) {
|
|
150
|
+
clearInterval(this.pollTimer);
|
|
151
|
+
this.pollTimer = null;
|
|
152
|
+
}
|
|
153
|
+
if (this.readTimer) {
|
|
154
|
+
clearInterval(this.readTimer);
|
|
155
|
+
this.readTimer = null;
|
|
156
|
+
}
|
|
157
|
+
if (this.keepAliveTimer) {
|
|
158
|
+
clearInterval(this.keepAliveTimer);
|
|
159
|
+
this.keepAliveTimer = null;
|
|
160
|
+
}
|
|
161
|
+
if (this.connected) {
|
|
162
|
+
this.isUpdating = false;
|
|
163
|
+
this.lastStateHash = '';
|
|
164
|
+
await this.updateDisplay({ ...this.lastState, state: 'DISCONNECTED', allSessions: this.lastSessions }).catch(() => { });
|
|
165
|
+
}
|
|
166
|
+
this.disconnect();
|
|
167
|
+
this.commandHandler = null;
|
|
168
|
+
}
|
|
169
|
+
statusSnapshot() {
|
|
170
|
+
return {
|
|
171
|
+
connected: this.connected,
|
|
172
|
+
externalOwner: this.externalOwner,
|
|
173
|
+
managerOpened: this.hidModule !== null,
|
|
174
|
+
resvgLoaded: isResvgLoaded(),
|
|
175
|
+
writeOK: this.writeOK,
|
|
176
|
+
writeFail: this.writeFail,
|
|
177
|
+
buttonPressCount: this.buttonPressCount,
|
|
178
|
+
hidReportCount: this.hidReportCount,
|
|
179
|
+
lastWriteError: this.lastWriteError,
|
|
180
|
+
lastOpenError: this.lastOpenError,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// --- Private methods ---
|
|
184
|
+
async loadHidModule() {
|
|
185
|
+
try {
|
|
186
|
+
const mod = await import('node-hid');
|
|
187
|
+
return (mod.default ?? mod);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
debug(TAG, 'node-hid not available');
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
findDevice() {
|
|
195
|
+
if (!this.hidModule)
|
|
196
|
+
return null;
|
|
197
|
+
const devices = this.hidModule.devices();
|
|
198
|
+
let consumerPath;
|
|
199
|
+
let keyboardPath;
|
|
200
|
+
let serial = '';
|
|
201
|
+
for (const d of devices) {
|
|
202
|
+
if (d.vendorId === VID && d.productId === PID) {
|
|
203
|
+
serial = d.serialNumber ?? '';
|
|
204
|
+
if (d.usagePage === CONSUMER_USAGE_PAGE) {
|
|
205
|
+
consumerPath = d.path;
|
|
206
|
+
}
|
|
207
|
+
else if (d.usagePage === KEYBOARD_USAGE_PAGE) {
|
|
208
|
+
keyboardPath = d.path;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (consumerPath) {
|
|
213
|
+
return { consumerPath, keyboardPath, serial };
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Arbitrate device ownership with the Ulanzi Studio plugin. When it connects,
|
|
219
|
+
* release the D200H and suspend reconnect so Ulanzi Studio drives it; when it
|
|
220
|
+
* disconnects, resume direct-HID.
|
|
221
|
+
*/
|
|
222
|
+
setExternalOwner(owner) {
|
|
223
|
+
if (this.externalOwner === owner)
|
|
224
|
+
return;
|
|
225
|
+
this.externalOwner = owner;
|
|
226
|
+
if (owner) {
|
|
227
|
+
debug(TAG, 'Ulanzi plugin active — releasing D200H to Ulanzi Studio');
|
|
228
|
+
if (this.pollTimer) {
|
|
229
|
+
clearInterval(this.pollTimer);
|
|
230
|
+
this.pollTimer = null;
|
|
231
|
+
}
|
|
232
|
+
this.disconnect();
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
debug(TAG, 'Ulanzi plugin gone — resuming direct-HID');
|
|
236
|
+
if (!this.pollTimer) {
|
|
237
|
+
this.pollTimer = setInterval(() => {
|
|
238
|
+
if (!this.connected && !this.externalOwner)
|
|
239
|
+
this.tryConnect();
|
|
240
|
+
}, POLL_INTERVAL);
|
|
241
|
+
}
|
|
242
|
+
this.tryConnect();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
tryConnect() {
|
|
246
|
+
if (this.externalOwner)
|
|
247
|
+
return;
|
|
248
|
+
if (!this.hidModule)
|
|
249
|
+
return;
|
|
250
|
+
const info = this.findDevice();
|
|
251
|
+
if (!info)
|
|
252
|
+
return;
|
|
253
|
+
try {
|
|
254
|
+
// Open consumer control interface (display updates + some events)
|
|
255
|
+
this.consumerDevice = new this.hidModule.HID(info.consumerPath);
|
|
256
|
+
this.lastOpenError = null;
|
|
257
|
+
debug(TAG, `Connected to D200H (serial: ${info.serial}) via Consumer Control`);
|
|
258
|
+
// Try to open keyboard interface (button events) — may fail on macOS
|
|
259
|
+
if (info.keyboardPath) {
|
|
260
|
+
try {
|
|
261
|
+
this.keyboardDevice = new this.hidModule.HID(info.keyboardPath);
|
|
262
|
+
debug(TAG, 'Opened keyboard interface for button events');
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
const errMsg = err?.message ?? String(err);
|
|
266
|
+
this.lastOpenError = `macOS Input Monitoring Permission Required: Please enable Input Monitoring for your terminal (e.g., iTerm, Terminal) in System Settings -> Privacy & Security -> Input Monitoring. (Error: ${errMsg})`;
|
|
267
|
+
debug(TAG, `Keyboard interface not available: ${this.lastOpenError}`);
|
|
268
|
+
// Trigger system preferences open once to guide the user
|
|
269
|
+
if (process.platform === 'darwin') {
|
|
270
|
+
import('child_process').then(({ exec }) => {
|
|
271
|
+
exec('open "x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent"', (e) => {
|
|
272
|
+
if (e)
|
|
273
|
+
debug(TAG, `Failed to open System Settings: ${e.message}`);
|
|
274
|
+
});
|
|
275
|
+
}).catch(() => { });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
this.connected = true;
|
|
280
|
+
// Start reading events
|
|
281
|
+
// If keyboard interface failed to open, buttons won't register, but
|
|
282
|
+
// readFrom still safely monitors events that might come via consumer control.
|
|
283
|
+
this.startReading();
|
|
284
|
+
// Start keep-alive
|
|
285
|
+
this.keepAliveTimer = setInterval(() => this.sendKeepAlive(), KEEPALIVE_INTERVAL);
|
|
286
|
+
// Set initial brightness, honoring a cached display_state if the host
|
|
287
|
+
// was already asleep when the D200H reconnected.
|
|
288
|
+
this.applyDisplayBrightness();
|
|
289
|
+
// Send initial display update (render offline/idle layout immediately)
|
|
290
|
+
this.updateDisplay(this.lastState).catch((err) => {
|
|
291
|
+
debug(TAG, `Initial display update failed: ${err}`);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
this.lastOpenError = String(err);
|
|
296
|
+
debug(TAG, `Failed to connect: ${err}`);
|
|
297
|
+
this.disconnect();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
disconnect() {
|
|
301
|
+
if (this.readTimer) {
|
|
302
|
+
clearInterval(this.readTimer);
|
|
303
|
+
this.readTimer = null;
|
|
304
|
+
}
|
|
305
|
+
if (this.keepAliveTimer) {
|
|
306
|
+
clearInterval(this.keepAliveTimer);
|
|
307
|
+
this.keepAliveTimer = null;
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
this.consumerDevice?.close();
|
|
311
|
+
}
|
|
312
|
+
catch { /* ignore */ }
|
|
313
|
+
try {
|
|
314
|
+
this.keyboardDevice?.close();
|
|
315
|
+
}
|
|
316
|
+
catch { /* ignore */ }
|
|
317
|
+
this.consumerDevice = null;
|
|
318
|
+
this.keyboardDevice = null;
|
|
319
|
+
this.connected = false;
|
|
320
|
+
this.lastStateHash = '';
|
|
321
|
+
}
|
|
322
|
+
startReading() {
|
|
323
|
+
if (this.readTimer) {
|
|
324
|
+
clearInterval(this.readTimer);
|
|
325
|
+
}
|
|
326
|
+
this.readTimer = setInterval(() => {
|
|
327
|
+
this.readFrom(this.consumerDevice);
|
|
328
|
+
this.readFrom(this.keyboardDevice);
|
|
329
|
+
}, READ_INTERVAL);
|
|
330
|
+
}
|
|
331
|
+
readFrom(device) {
|
|
332
|
+
if (!device)
|
|
333
|
+
return;
|
|
334
|
+
try {
|
|
335
|
+
// Use readTimeout for non-blocking behavior (node-hid v3+)
|
|
336
|
+
const data = device.readTimeout ? device.readTimeout(1) : device.read();
|
|
337
|
+
if (!data || (Array.isArray(data) && data.length === 0) || (Buffer.isBuffer(data) && data.length === 0))
|
|
338
|
+
return;
|
|
339
|
+
const buf = Buffer.from(data);
|
|
340
|
+
const event = parseIncoming(buf);
|
|
341
|
+
if (!event)
|
|
342
|
+
return;
|
|
343
|
+
this.hidReportCount++;
|
|
344
|
+
if (event.type === 'button' && event.data.pressed) {
|
|
345
|
+
this.buttonPressCount++;
|
|
346
|
+
// Real button input received → input path is empirically working.
|
|
347
|
+
// Clear any stale lastOpenError left by a failed keyboard-interface open
|
|
348
|
+
// (buttons arrive via the consumer-control interface regardless).
|
|
349
|
+
if (this.lastOpenError)
|
|
350
|
+
this.lastOpenError = null;
|
|
351
|
+
// The command is whatever the currently-displayed tile at this physical
|
|
352
|
+
// key does — derived from the same layout that was rendered, so the key
|
|
353
|
+
// can never act on stale or mismatched session ordering.
|
|
354
|
+
const cmd = this.currentCommandMap.get(event.data.index);
|
|
355
|
+
if (cmd) {
|
|
356
|
+
debug(TAG, `Button ${event.data.index} pressed → ${cmd.type}`);
|
|
357
|
+
this.commandHandler?.(cmd);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
debug(TAG, `Button ${event.data.index} pressed (inert tile)`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
else if (event.type === 'device_info') {
|
|
364
|
+
debug(TAG, `Device: ${event.data.deviceType} fw=${event.data.firmwareVersion} hw=${event.data.hardwareVersion}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
const msg = err?.message ?? '';
|
|
369
|
+
if (msg.includes('could not read') || msg.includes('disconnected') || msg.includes('transfer')) {
|
|
370
|
+
debug(TAG, `Device disconnected (${msg})`);
|
|
371
|
+
this.disconnect();
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
debug(TAG, `HID read error: ${msg}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async updateDisplay(stateEvt) {
|
|
379
|
+
const hash = stateHash(stateEvt);
|
|
380
|
+
if (hash === this.lastStateHash)
|
|
381
|
+
return;
|
|
382
|
+
if (this.isUpdating) {
|
|
383
|
+
this.pendingUpdate = stateEvt;
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.lastStateHash = hash;
|
|
387
|
+
this.isUpdating = true;
|
|
388
|
+
try {
|
|
389
|
+
const zip = renderDashboardZip(stateEvt);
|
|
390
|
+
// Rebuild the input map from the SAME state we just rendered, so a press
|
|
391
|
+
// always maps to what is currently on screen.
|
|
392
|
+
this.currentCommandMap = buildButtonCommandMap(stateEvt);
|
|
393
|
+
// Save ZIP to ~/.agentdeck/d200h-dumps/ for preview
|
|
394
|
+
try {
|
|
395
|
+
const dumpDir = join(homedir(), '.agentdeck', 'd200h-dumps');
|
|
396
|
+
if (!existsSync(dumpDir)) {
|
|
397
|
+
mkdirSync(dumpDir, { recursive: true });
|
|
398
|
+
}
|
|
399
|
+
const stamp = new Date().toISOString().replace(/[-T:]/g, '').split('.')[0];
|
|
400
|
+
const modeKey = (stateEvt?.mode || 'default').toLowerCase();
|
|
401
|
+
const sanitizedState = (stateEvt?.state || 'unknown').toLowerCase().replace(/[^a-z0-9_-]/g, '');
|
|
402
|
+
const sanitizedProject = (stateEvt?.projectName || '').toLowerCase().replace(/[^a-z0-9_-]/g, '');
|
|
403
|
+
const sanitized = [sanitizedState, sanitizedProject].filter(Boolean).join('-');
|
|
404
|
+
const filename = `${stamp}-set_buttons-${modeKey}-${zip.length}b-${sanitized}.zip`;
|
|
405
|
+
writeFileSync(join(dumpDir, filename), zip);
|
|
406
|
+
}
|
|
407
|
+
catch (dumpErr) {
|
|
408
|
+
debug(TAG, `Failed to dump ZIP to ~/.agentdeck/d200h-dumps/: ${dumpErr}`);
|
|
409
|
+
}
|
|
410
|
+
const packets = buildZipPackets(zip);
|
|
411
|
+
for (const pkt of packets) {
|
|
412
|
+
if (!this.connected)
|
|
413
|
+
break;
|
|
414
|
+
if (!this.writeToDevice(pkt)) {
|
|
415
|
+
throw new Error(this.lastWriteError ?? 'D200H write failed');
|
|
416
|
+
}
|
|
417
|
+
await new Promise(r => setTimeout(r, 8)); // Prevent hardware buffer overflow
|
|
418
|
+
}
|
|
419
|
+
debug(TAG, `Display updated: ${zip.length} bytes, ${packets.length} packets`);
|
|
420
|
+
}
|
|
421
|
+
catch (err) {
|
|
422
|
+
debug(TAG, `Display update failed: ${err}`);
|
|
423
|
+
this.lastStateHash = ''; // Reset hash so it can retry
|
|
424
|
+
}
|
|
425
|
+
finally {
|
|
426
|
+
this.isUpdating = false;
|
|
427
|
+
if (this.pendingUpdate) {
|
|
428
|
+
const next = this.pendingUpdate;
|
|
429
|
+
this.pendingUpdate = null;
|
|
430
|
+
void this.updateDisplay(next).catch(() => { });
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
sendKeepAlive() {
|
|
435
|
+
if (!this.connected)
|
|
436
|
+
return;
|
|
437
|
+
const now = new Date();
|
|
438
|
+
const timeStr = now.toTimeString().slice(0, 8);
|
|
439
|
+
const packet = buildSmallWindowPacket(1, 0, 0, timeStr, 0);
|
|
440
|
+
this.writeToDevice(packet);
|
|
441
|
+
}
|
|
442
|
+
applyDisplayState(evt) {
|
|
443
|
+
const dim = evt?.dim;
|
|
444
|
+
this.hostDisplayOn = evt?.displayOn ?? true;
|
|
445
|
+
const rawEnabled = dim?.enabled;
|
|
446
|
+
this.dimEnabled = typeof rawEnabled === 'boolean' ? rawEnabled : true;
|
|
447
|
+
this.dimMode = dim?.mode === 'min' ? 'min' : 'off';
|
|
448
|
+
const rawLevel = dim?.level;
|
|
449
|
+
const level = typeof rawLevel === 'number' && Number.isFinite(rawLevel) ? Math.round(rawLevel) : 10;
|
|
450
|
+
this.dimLevel = Math.max(1, Math.min(100, level));
|
|
451
|
+
const signature = `${this.hostDisplayOn}|${this.dimEnabled}|${this.dimMode}|${this.dimLevel}`;
|
|
452
|
+
if (signature === this.lastDimSignature)
|
|
453
|
+
return;
|
|
454
|
+
this.lastDimSignature = signature;
|
|
455
|
+
this.applyDisplayBrightness();
|
|
456
|
+
}
|
|
457
|
+
applyDisplayBrightness() {
|
|
458
|
+
if (!this.connected)
|
|
459
|
+
return;
|
|
460
|
+
const shouldSuppress = !this.hostDisplayOn && this.dimEnabled;
|
|
461
|
+
const target = shouldSuppress ? (this.dimMode === 'min' ? this.dimLevel : 0) : 100;
|
|
462
|
+
const wasSuppressed = this.displaySuppressed;
|
|
463
|
+
this.displaySuppressed = shouldSuppress;
|
|
464
|
+
this.writeToDevice(buildBrightnessPacket(target));
|
|
465
|
+
debug(TAG, `Display ${this.hostDisplayOn ? 'wake' : 'sleep'} — brightness ${target}`);
|
|
466
|
+
if (wasSuppressed && !shouldSuppress) {
|
|
467
|
+
this.lastStateHash = '';
|
|
468
|
+
this.updateDisplay({ ...this.lastState, allSessions: this.lastSessions }).catch(() => { });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
writeToDevice(packet) {
|
|
472
|
+
if (!this.consumerDevice)
|
|
473
|
+
return false;
|
|
474
|
+
try {
|
|
475
|
+
// node-hid on macOS requires the first byte to be the Report ID.
|
|
476
|
+
// If the device does not use Report IDs (like D200H), the first byte must be 0x00.
|
|
477
|
+
// node-hid will strip this 0x00 before sending the remaining 1024 bytes to the device.
|
|
478
|
+
const dataToWrite = [0x00, ...Array.from(packet)];
|
|
479
|
+
this.consumerDevice.write(dataToWrite);
|
|
480
|
+
this.writeOK++;
|
|
481
|
+
this.lastWriteError = null;
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
this.writeFail++;
|
|
486
|
+
this.lastWriteError = err?.message ?? String(err);
|
|
487
|
+
if (err?.message?.includes('could not write') || err?.message?.includes('could not send')) {
|
|
488
|
+
debug(TAG, 'Write failed — device disconnected');
|
|
489
|
+
this.disconnect();
|
|
490
|
+
}
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
//# sourceMappingURL=d200h-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"d200h-module.js","sourceRoot":"","sources":["../../src/modules/d200h-module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Render full dashboard and return raw BGRA framebuffer */
|
|
2
|
+
export declare function renderDashboard(stateEvt: any): Buffer;
|
|
3
|
+
/** Push framebuffer to D200H via ADB */
|
|
4
|
+
export declare function pushToDevice(fb: Buffer): boolean;
|
|
5
|
+
/** Render and push dashboard to D200H */
|
|
6
|
+
export declare function updateD200hDisplay(stateEvt: any): void;
|
|
7
|
+
//# sourceMappingURL=d200h-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"d200h-renderer.d.ts","sourceRoot":"","sources":["../../src/modules/d200h-renderer.ts"],"names":[],"mappings":"AAkUA,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,QAAQ,EAAE,GAAG,GAAG,MAAM,CAiBrD;AAED,wCAAwC;AACxC,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAgBhD;AAED,yCAAyC;AACzC,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI,CAOtD"}
|