@agentdeck/bridge 1.0.6 → 1.0.7
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/apme/collector.d.ts +10 -0
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +39 -10
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/dashboard-html.d.ts.map +1 -1
- package/dist/apme/dashboard-html.js +289 -0
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/graph.d.ts +48 -0
- package/dist/apme/graph.d.ts.map +1 -0
- package/dist/apme/graph.js +226 -0
- package/dist/apme/graph.js.map +1 -0
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +52 -0
- package/dist/apme/http.js.map +1 -1
- package/dist/apme/judge-detect.d.ts.map +1 -1
- package/dist/apme/judge-detect.js +26 -2
- package/dist/apme/judge-detect.js.map +1 -1
- package/dist/apme/store.d.ts +69 -1
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +238 -4
- package/dist/apme/store.js.map +1 -1
- package/dist/apme/types.d.ts +1 -1
- package/dist/apme/types.d.ts.map +1 -1
- package/dist/apme/types.js.map +1 -1
- package/dist/ble-sync-spawn.d.ts +25 -2
- package/dist/ble-sync-spawn.d.ts.map +1 -1
- package/dist/ble-sync-spawn.js +38 -2
- package/dist/ble-sync-spawn.js.map +1 -1
- package/dist/ble-sync-status.d.ts +77 -0
- package/dist/ble-sync-status.d.ts.map +1 -0
- package/dist/ble-sync-status.js +157 -0
- package/dist/ble-sync-status.js.map +1 -0
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +7 -1
- package/dist/bridge-core.js.map +1 -1
- package/dist/cli.js +0 -0
- package/dist/codex-rate-limits-live.d.ts +60 -0
- package/dist/codex-rate-limits-live.d.ts.map +1 -0
- package/dist/codex-rate-limits-live.js +282 -0
- package/dist/codex-rate-limits-live.js.map +1 -0
- 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 +79 -0
- 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/idotmatrix/idotmatrix-daemon-sync.d.ts +8 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.js +19 -3
- package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -1
- 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/idotmatrix-module.d.ts.map +1 -1
- package/dist/modules/idotmatrix-module.js +12 -1
- package/dist/modules/idotmatrix-module.js.map +1 -1
- package/dist/modules/timebox-module.d.ts.map +1 -1
- package/dist/modules/timebox-module.js +12 -1
- package/dist/modules/timebox-module.js.map +1 -1
- 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/timebox/timebox-daemon-sync.d.ts +8 -0
- package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -1
- package/dist/timebox/timebox-daemon-sync.js +29 -1
- package/dist/timebox/timebox-daemon-sync.js.map +1 -1
- package/dist/timeline-summarizer.d.ts +12 -2
- package/dist/timeline-summarizer.d.ts.map +1 -1
- package/dist/timeline-summarizer.js +66 -4
- package/dist/timeline-summarizer.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/package.json +13 -14
- package/src/idotmatrix/sync.py +16 -1
- package/src/pysync/matrix_sync_common.py +83 -0
- package/src/timebox/sync_ble.py +16 -0
|
@@ -10,6 +10,7 @@ so this module must stay dependency-free beyond the stdlib.
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
|
+
import sys
|
|
13
14
|
import urllib.request
|
|
14
15
|
|
|
15
16
|
DEFAULT_URL = "http://127.0.0.1:9120"
|
|
@@ -87,3 +88,85 @@ def resolve_display_brightness(display_state, normal_brightness, *, off_floor, l
|
|
|
87
88
|
if display_on or not dim_enabled:
|
|
88
89
|
return normal_brightness, False, signature, dim_mode
|
|
89
90
|
return (dim_level if dim_mode == "min" else off_floor), True, signature, dim_mode
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
# Link status reporting
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
# Prefix of the machine-readable status lines the daemon supervisor parses.
|
|
98
|
+
# Mirrored in bridge/src/ble-sync-spawn.ts (`BLE_STATUS_LINE_PREFIX`).
|
|
99
|
+
STATUS_LINE_PREFIX = "AGENTDECK_STATUS "
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class StatusReporter:
|
|
103
|
+
"""Report BLE link state to the daemon that spawned us, one line per change.
|
|
104
|
+
|
|
105
|
+
The Node daemon has no BLE of its own: it spawns this client and can only
|
|
106
|
+
watch the process. But both clients reconnect *inside* their own loop, so a
|
|
107
|
+
powered-off panel leaves the child running indefinitely and "process alive"
|
|
108
|
+
says nothing about whether the panel is being driven. Without this signal
|
|
109
|
+
the daemon's /health could only report the configured device list, and every
|
|
110
|
+
consumer that renders `connected` — macOS menubar, Dashboard rail, TUI —
|
|
111
|
+
drew both BLE panels as disconnected while they were streaming.
|
|
112
|
+
|
|
113
|
+
Emitting only on *change* keeps the frame loop from flooding the daemon log,
|
|
114
|
+
and the supervisor keeps these lines out of its diagnostic output ring so a
|
|
115
|
+
reconnect never looks like a new crash cycle.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
def __init__(self, emit=None):
|
|
119
|
+
self._emit = emit if emit is not None else _write_status_line
|
|
120
|
+
self._last = None
|
|
121
|
+
# Sticky: once we have painted the panel, our frame is on it even while
|
|
122
|
+
# the link is down. Matches `hasFrame` in the daemon's health shape.
|
|
123
|
+
self._has_frame = False
|
|
124
|
+
|
|
125
|
+
def _update(self, connected, phase, dimmed=False, error=None):
|
|
126
|
+
payload = {
|
|
127
|
+
"connected": bool(connected),
|
|
128
|
+
"phase": phase,
|
|
129
|
+
"hasFrame": self._has_frame,
|
|
130
|
+
"dimmed": bool(dimmed),
|
|
131
|
+
"error": error,
|
|
132
|
+
}
|
|
133
|
+
if payload == self._last:
|
|
134
|
+
return
|
|
135
|
+
self._last = payload
|
|
136
|
+
self._emit(payload)
|
|
137
|
+
|
|
138
|
+
def connecting(self):
|
|
139
|
+
self._update(False, "connecting")
|
|
140
|
+
|
|
141
|
+
def connected(self):
|
|
142
|
+
self._update(True, "connected")
|
|
143
|
+
|
|
144
|
+
def streaming(self, dimmed=False):
|
|
145
|
+
"""Link up and the frame loop is running — does not claim a painted frame.
|
|
146
|
+
|
|
147
|
+
Used on the dim/pause path, where a reconnect while the host display is
|
|
148
|
+
already asleep runs the loop without pushing anything.
|
|
149
|
+
"""
|
|
150
|
+
self._update(True, "streaming", dimmed=dimmed)
|
|
151
|
+
|
|
152
|
+
def frame_sent(self, dimmed=False):
|
|
153
|
+
self._has_frame = True
|
|
154
|
+
self.streaming(dimmed=dimmed)
|
|
155
|
+
|
|
156
|
+
def disconnected(self, error=None):
|
|
157
|
+
self._update(False, "disconnected", error=error)
|
|
158
|
+
|
|
159
|
+
def failed(self, error):
|
|
160
|
+
self._update(False, "error", error=str(error) if error is not None else None)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _write_status_line(payload):
|
|
164
|
+
"""Write one status line to stdout. Never raises — a closed pipe during
|
|
165
|
+
shutdown must not take the farewell frame down with it."""
|
|
166
|
+
try:
|
|
167
|
+
sys.stdout.write(
|
|
168
|
+
STATUS_LINE_PREFIX + json.dumps(payload, separators=(",", ":")) + "\n"
|
|
169
|
+
)
|
|
170
|
+
sys.stdout.flush()
|
|
171
|
+
except Exception:
|
|
172
|
+
pass
|
package/src/timebox/sync_ble.py
CHANGED
|
@@ -31,6 +31,7 @@ from matrix_sync_common import ( # noqa: E402
|
|
|
31
31
|
DEFAULT_URL,
|
|
32
32
|
POLL_INTERVAL,
|
|
33
33
|
BRIDGE_GONE_EXIT_SEC,
|
|
34
|
+
StatusReporter,
|
|
34
35
|
fetch_display_state,
|
|
35
36
|
bridge_reachable,
|
|
36
37
|
resolve_display_brightness as _resolve_display_brightness_common,
|
|
@@ -182,6 +183,11 @@ async def push_micro_frame(client, url, brightness, gamma, sat, contrast, last_k
|
|
|
182
183
|
|
|
183
184
|
async def run(address: str, url: str, brightness: int, gamma: float, sat: float, contrast: float, once: bool = False) -> None:
|
|
184
185
|
print(f"Starting Timebox Mini BLE sync: {address} <- {url} brightness={brightness}% gamma={gamma}")
|
|
186
|
+
# Machine-readable link state for the daemon supervisor — it spawns us but
|
|
187
|
+
# cannot see the BLE link, and we reconnect inside this loop rather than
|
|
188
|
+
# exiting, so process liveness tells it nothing about whether the panel is
|
|
189
|
+
# actually being driven.
|
|
190
|
+
status = StatusReporter()
|
|
185
191
|
stop = asyncio.Event()
|
|
186
192
|
# Why we're stopping — decides the farewell. 'signal' = clean daemon shutdown
|
|
187
193
|
# (no successor → blank the panel). 'orphan' = parent died (a successor daemon
|
|
@@ -238,12 +244,15 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
238
244
|
# the inner loop would spin forever on a dead link and the outer reconnect
|
|
239
245
|
# path (below) would never run.
|
|
240
246
|
print("BLE peripheral disconnected — will reconnect.", file=sys.stderr)
|
|
247
|
+
status.disconnected("BLE peripheral disconnected")
|
|
241
248
|
loop.call_soon_threadsafe(link_lost.set)
|
|
242
249
|
|
|
243
250
|
try:
|
|
244
251
|
print(f"Connecting BLE {address}...")
|
|
252
|
+
status.connecting()
|
|
245
253
|
async with BleakClient(address, timeout=15.0, disconnected_callback=on_disconnect) as client:
|
|
246
254
|
print(f"BLE connected (MTU={client.mtu_size})")
|
|
255
|
+
status.connected()
|
|
247
256
|
|
|
248
257
|
last_key = ""
|
|
249
258
|
last_sent_at = time.monotonic()
|
|
@@ -270,6 +279,7 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
270
279
|
# on a dead link — only this flag / is_connected reveals it.
|
|
271
280
|
if link_lost.is_set() or not client.is_connected:
|
|
272
281
|
print("BLE link lost — reconnecting.", file=sys.stderr)
|
|
282
|
+
status.disconnected("BLE link lost")
|
|
273
283
|
break
|
|
274
284
|
# 1. Apply host display sleep/wake. The daemon exposes the same
|
|
275
285
|
# display_state Pixoo/iDotMatrix/ESP32 receive; older session-
|
|
@@ -289,6 +299,7 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
289
299
|
# brightness on the transition (0 => blank sleep frame), then
|
|
290
300
|
# pause polling to save BLE bandwidth (mirrors iDotMatrix).
|
|
291
301
|
if display_dimmed:
|
|
302
|
+
status.streaming(dimmed=True)
|
|
292
303
|
if transitioned or once:
|
|
293
304
|
try:
|
|
294
305
|
last_key, sent = await push_micro_frame(
|
|
@@ -297,9 +308,11 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
297
308
|
if sent:
|
|
298
309
|
last_sent_at = time.monotonic()
|
|
299
310
|
last_bridge_ok = time.monotonic()
|
|
311
|
+
status.frame_sent(dimmed=True)
|
|
300
312
|
except Exception as e:
|
|
301
313
|
print(f"Dim-frame send error: {e}", file=sys.stderr)
|
|
302
314
|
if link_lost.is_set() or not client.is_connected:
|
|
315
|
+
status.disconnected(f"dim-frame send error: {e}")
|
|
303
316
|
break
|
|
304
317
|
if once:
|
|
305
318
|
return
|
|
@@ -321,6 +334,7 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
321
334
|
if sent:
|
|
322
335
|
last_sent_at = time.monotonic()
|
|
323
336
|
last_bridge_ok = time.monotonic()
|
|
337
|
+
status.frame_sent()
|
|
324
338
|
except Exception as e:
|
|
325
339
|
print(f"Frame fetch/send error: {e}", file=sys.stderr)
|
|
326
340
|
# A write error after the link dropped must escalate to a
|
|
@@ -328,6 +342,7 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
328
342
|
# not — keep streaming and let should_exit() handle a truly
|
|
329
343
|
# gone bridge.
|
|
330
344
|
if link_lost.is_set() or not client.is_connected:
|
|
345
|
+
status.disconnected(f"frame send error: {e}")
|
|
331
346
|
break
|
|
332
347
|
if once:
|
|
333
348
|
return
|
|
@@ -364,6 +379,7 @@ async def run(address: str, url: str, brightness: int, gamma: float, sat: float,
|
|
|
364
379
|
print(f"Farewell blank failed: {e}", file=sys.stderr)
|
|
365
380
|
except Exception as e:
|
|
366
381
|
print(f"BLE connection error: {e}", file=sys.stderr)
|
|
382
|
+
status.failed(f"BLE connection error: {e}")
|
|
367
383
|
if once:
|
|
368
384
|
raise
|
|
369
385
|
try:
|