@agentdeck/bridge 0.2.2 → 1.0.0
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/assets/fonts/IBMPlexSans-Bold.ttf +0 -0
- package/assets/fonts/IBMPlexSans-Regular.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Bold.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Regular.ttf +0 -0
- package/assets/fonts/LICENSES.md +22 -0
- package/dist/adapters/claude-code.d.ts +6 -0
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +8 -0
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/openclaw.d.ts +24 -0
- package/dist/adapters/openclaw.d.ts.map +1 -1
- package/dist/adapters/openclaw.js +291 -35
- package/dist/adapters/openclaw.js.map +1 -1
- package/dist/adapters/opencode-adapter.d.ts +59 -0
- package/dist/adapters/opencode-adapter.d.ts.map +1 -1
- package/dist/adapters/opencode-adapter.js +297 -35
- package/dist/adapters/opencode-adapter.js.map +1 -1
- package/dist/adb-reverse.d.ts +1 -1
- package/dist/adb-reverse.js +1 -1
- package/dist/antigravity-local.d.ts +1 -0
- package/dist/antigravity-local.d.ts.map +1 -1
- package/dist/antigravity-local.js +33 -0
- package/dist/antigravity-local.js.map +1 -1
- package/dist/apme/adapters/claude-hook.d.ts.map +1 -1
- package/dist/apme/adapters/claude-hook.js +5 -0
- package/dist/apme/adapters/claude-hook.js.map +1 -1
- package/dist/apme/adapters/codex-hook.d.ts +17 -0
- package/dist/apme/adapters/codex-hook.d.ts.map +1 -0
- package/dist/apme/adapters/codex-hook.js +95 -0
- package/dist/apme/adapters/codex-hook.js.map +1 -0
- package/dist/apme/adapters/codex-turn-manager.d.ts +86 -0
- package/dist/apme/adapters/codex-turn-manager.d.ts.map +1 -0
- package/dist/apme/adapters/codex-turn-manager.js +496 -0
- package/dist/apme/adapters/codex-turn-manager.js.map +1 -0
- package/dist/apme/adapters/openclaw-hook.d.ts +99 -0
- package/dist/apme/adapters/openclaw-hook.d.ts.map +1 -0
- package/dist/apme/adapters/openclaw-hook.js +234 -0
- package/dist/apme/adapters/openclaw-hook.js.map +1 -0
- package/dist/apme/adapters/opencode-hook.d.ts +56 -0
- package/dist/apme/adapters/opencode-hook.d.ts.map +1 -0
- package/dist/apme/adapters/opencode-hook.js +182 -0
- package/dist/apme/adapters/opencode-hook.js.map +1 -0
- package/dist/apme/adapters/timeline.d.ts.map +1 -1
- package/dist/apme/adapters/timeline.js +6 -1
- package/dist/apme/adapters/timeline.js.map +1 -1
- package/dist/apme/antigravity-transcript.d.ts +18 -0
- package/dist/apme/antigravity-transcript.d.ts.map +1 -0
- package/dist/apme/antigravity-transcript.js +94 -0
- package/dist/apme/antigravity-transcript.js.map +1 -0
- package/dist/apme/classify-turn.d.ts +13 -0
- package/dist/apme/classify-turn.d.ts.map +1 -0
- package/dist/apme/classify-turn.js +49 -0
- package/dist/apme/classify-turn.js.map +1 -0
- package/dist/apme/claude-transcript-reader.d.ts +10 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
- package/dist/apme/claude-transcript-reader.js +35 -0
- package/dist/apme/claude-transcript-reader.js.map +1 -1
- package/dist/apme/collector.d.ts +133 -6
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +471 -23
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/dashboard-html.d.ts.map +1 -1
- package/dist/apme/dashboard-html.js +117 -11
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +52 -6
- package/dist/apme/http.js.map +1 -1
- package/dist/apme/index.d.ts +26 -5
- package/dist/apme/index.d.ts.map +1 -1
- package/dist/apme/index.js +146 -9
- package/dist/apme/index.js.map +1 -1
- package/dist/apme/judge-detect.d.ts +26 -0
- package/dist/apme/judge-detect.d.ts.map +1 -0
- package/dist/apme/judge-detect.js +69 -0
- package/dist/apme/judge-detect.js.map +1 -0
- package/dist/apme/pareto.d.ts +39 -0
- package/dist/apme/pareto.d.ts.map +1 -0
- package/dist/apme/pareto.js +59 -0
- package/dist/apme/pareto.js.map +1 -0
- package/dist/apme/recommend.d.ts +3 -0
- package/dist/apme/recommend.d.ts.map +1 -1
- package/dist/apme/recommend.js +43 -1
- package/dist/apme/recommend.js.map +1 -1
- package/dist/apme/runner.d.ts +99 -4
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +743 -72
- package/dist/apme/runner.js.map +1 -1
- package/dist/apme/sample-to-timeline.d.ts +26 -0
- package/dist/apme/sample-to-timeline.d.ts.map +1 -0
- package/dist/apme/sample-to-timeline.js +95 -0
- package/dist/apme/sample-to-timeline.js.map +1 -0
- package/dist/apme/scorers/index.d.ts +47 -0
- package/dist/apme/scorers/index.d.ts.map +1 -0
- package/dist/apme/scorers/index.js +96 -0
- package/dist/apme/scorers/index.js.map +1 -0
- package/dist/apme/settings.d.ts +17 -11
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +30 -9
- package/dist/apme/settings.js.map +1 -1
- package/dist/apme/store.d.ts +33 -1
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +334 -25
- package/dist/apme/store.js.map +1 -1
- package/dist/awaiting-overlay.d.ts +112 -0
- package/dist/awaiting-overlay.d.ts.map +1 -0
- package/dist/awaiting-overlay.js +179 -0
- package/dist/awaiting-overlay.js.map +1 -0
- package/dist/ble-sync-spawn.d.ts +63 -0
- package/dist/ble-sync-spawn.d.ts.map +1 -0
- package/dist/ble-sync-spawn.js +196 -0
- package/dist/ble-sync-spawn.js.map +1 -0
- package/dist/bridge-core.d.ts +34 -1
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +207 -24
- package/dist/bridge-core.js.map +1 -1
- package/dist/broadcast.d.ts +3 -0
- package/dist/broadcast.d.ts.map +1 -0
- package/dist/broadcast.js +122 -0
- package/dist/broadcast.js.map +1 -0
- package/dist/check-deps.d.ts.map +1 -1
- package/dist/check-deps.js +25 -9
- package/dist/check-deps.js.map +1 -1
- package/dist/claude-permission-rules.d.ts +55 -0
- package/dist/claude-permission-rules.d.ts.map +1 -0
- package/dist/claude-permission-rules.js +197 -0
- package/dist/claude-permission-rules.js.map +1 -0
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1030 -93
- package/dist/cli.js.map +1 -1
- package/dist/codex-auth.d.ts +21 -0
- package/dist/codex-auth.d.ts.map +1 -1
- package/dist/codex-auth.js +52 -1
- package/dist/codex-auth.js.map +1 -1
- package/dist/codex-output-parser.d.ts +8 -0
- package/dist/codex-output-parser.d.ts.map +1 -1
- package/dist/codex-output-parser.js +110 -25
- package/dist/codex-output-parser.js.map +1 -1
- package/dist/codex-rate-limits.d.ts +16 -0
- package/dist/codex-rate-limits.d.ts.map +1 -0
- package/dist/codex-rate-limits.js +197 -0
- package/dist/codex-rate-limits.js.map +1 -0
- package/dist/codex-rollout-response.d.ts +31 -0
- package/dist/codex-rollout-response.d.ts.map +1 -0
- package/dist/codex-rollout-response.js +135 -0
- package/dist/codex-rollout-response.js.map +1 -0
- package/dist/d200h/image-renderer.d.ts +4 -16
- package/dist/d200h/image-renderer.d.ts.map +1 -1
- package/dist/d200h/image-renderer.js +46 -212
- package/dist/d200h/image-renderer.js.map +1 -1
- package/dist/daemon-server.d.ts +85 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +1975 -159
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon.js +15 -6
- package/dist/daemon.js.map +1 -1
- package/dist/display-dim.d.ts +9 -0
- package/dist/display-dim.d.ts.map +1 -0
- package/dist/display-dim.js +53 -0
- package/dist/display-dim.js.map +1 -0
- package/dist/display-monitor.d.ts +15 -2
- package/dist/display-monitor.d.ts.map +1 -1
- package/dist/display-monitor.js +104 -26
- package/dist/display-monitor.js.map +1 -1
- package/dist/esp32-serial.d.ts +190 -1
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +1090 -156
- package/dist/esp32-serial.js.map +1 -1
- package/dist/fallback-task-timeline.d.ts +42 -0
- package/dist/fallback-task-timeline.d.ts.map +1 -0
- package/dist/fallback-task-timeline.js +119 -0
- package/dist/fallback-task-timeline.js.map +1 -0
- package/dist/foundation-models-helper.d.ts +11 -0
- package/dist/foundation-models-helper.d.ts.map +1 -0
- package/dist/foundation-models-helper.js +241 -0
- package/dist/foundation-models-helper.js.map +1 -0
- package/dist/hook-migration.js +1 -1
- package/dist/hook-migration.js.map +1 -1
- package/dist/hook-server.d.ts +2 -3
- package/dist/hook-server.d.ts.map +1 -1
- package/dist/hook-server.js +23 -10
- package/dist/hook-server.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts +33 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.js +164 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts +18 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.js +85 -0
- package/dist/idotmatrix/idotmatrix-discover.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts +20 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-settings.js +57 -0
- package/dist/idotmatrix/idotmatrix-settings.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +217 -179
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +15 -16
- package/dist/log-stream.d.ts.map +1 -1
- package/dist/log-stream.js +18 -96
- package/dist/log-stream.js.map +1 -1
- package/dist/logger.d.ts +3 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +18 -5
- package/dist/logger.js.map +1 -1
- package/dist/mdns.d.ts +17 -0
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +52 -18
- package/dist/mdns.js.map +1 -1
- package/dist/model-catalog.d.ts +1 -1
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +2 -4
- package/dist/model-catalog.js.map +1 -1
- package/dist/modules/adb-module.d.ts +1 -1
- package/dist/modules/adb-module.d.ts.map +1 -1
- package/dist/modules/adb-module.js +4 -3
- package/dist/modules/adb-module.js.map +1 -1
- package/dist/modules/broadcast-module.d.ts +17 -0
- package/dist/modules/broadcast-module.d.ts.map +1 -0
- package/dist/modules/broadcast-module.js +26 -0
- package/dist/modules/broadcast-module.js.map +1 -0
- package/dist/modules/d200h-module.d.ts +22 -0
- package/dist/modules/d200h-module.d.ts.map +1 -1
- package/dist/modules/d200h-module.js +200 -65
- package/dist/modules/d200h-module.js.map +1 -1
- package/dist/modules/idotmatrix-module.d.ts +9 -0
- package/dist/modules/idotmatrix-module.d.ts.map +1 -0
- package/dist/modules/idotmatrix-module.js +46 -0
- package/dist/modules/idotmatrix-module.js.map +1 -0
- package/dist/modules/index.d.ts +3 -1
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +9 -3
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/pixoo-module.d.ts.map +1 -1
- package/dist/modules/pixoo-module.js +14 -4
- package/dist/modules/pixoo-module.js.map +1 -1
- package/dist/modules/serial-module.d.ts +4 -0
- package/dist/modules/serial-module.d.ts.map +1 -1
- package/dist/modules/serial-module.js +14 -12
- package/dist/modules/serial-module.js.map +1 -1
- package/dist/modules/timebox-module.d.ts +9 -0
- package/dist/modules/timebox-module.d.ts.map +1 -0
- package/dist/modules/timebox-module.js +46 -0
- package/dist/modules/timebox-module.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/modules/types.d.ts +4 -2
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/observed-steering.d.ts +93 -0
- package/dist/observed-steering.d.ts.map +1 -0
- package/dist/observed-steering.js +247 -0
- package/dist/observed-steering.js.map +1 -0
- package/dist/openclaw-session.d.ts +18 -0
- package/dist/openclaw-session.d.ts.map +1 -0
- package/dist/openclaw-session.js +34 -0
- package/dist/openclaw-session.js.map +1 -0
- package/dist/opencode-steering.d.ts +36 -0
- package/dist/opencode-steering.d.ts.map +1 -0
- package/dist/opencode-steering.js +84 -0
- package/dist/opencode-steering.js.map +1 -0
- package/dist/output-parser.d.ts +30 -0
- package/dist/output-parser.d.ts.map +1 -1
- package/dist/output-parser.js +172 -18
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +32 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +288 -49
- package/dist/passive-observer.js.map +1 -1
- package/dist/permission-resolver.d.ts +55 -0
- package/dist/permission-resolver.d.ts.map +1 -0
- package/dist/permission-resolver.js +112 -0
- package/dist/permission-resolver.js.map +1 -0
- package/dist/pixoo/micro-glyphs.d.ts +18 -0
- package/dist/pixoo/micro-glyphs.d.ts.map +1 -0
- package/dist/pixoo/micro-glyphs.js +143 -0
- package/dist/pixoo/micro-glyphs.js.map +1 -0
- package/dist/pixoo/official-dot-glyphs.generated.d.ts +8 -0
- package/dist/pixoo/official-dot-glyphs.generated.d.ts.map +1 -0
- package/dist/pixoo/official-dot-glyphs.generated.js +247 -0
- package/dist/pixoo/official-dot-glyphs.generated.js.map +1 -0
- package/dist/pixoo/pixoo-bridge.d.ts +16 -8
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -1
- package/dist/pixoo/pixoo-bridge.js +127 -35
- package/dist/pixoo/pixoo-bridge.js.map +1 -1
- package/dist/pixoo/pixoo-camera.d.ts +19 -3
- package/dist/pixoo/pixoo-camera.d.ts.map +1 -1
- package/dist/pixoo/pixoo-camera.js +62 -27
- package/dist/pixoo/pixoo-camera.js.map +1 -1
- package/dist/pixoo/pixoo-client.d.ts +13 -3
- package/dist/pixoo/pixoo-client.d.ts.map +1 -1
- package/dist/pixoo/pixoo-client.js +51 -22
- package/dist/pixoo/pixoo-client.js.map +1 -1
- package/dist/pixoo/pixoo-discover.d.ts +37 -0
- package/dist/pixoo/pixoo-discover.d.ts.map +1 -0
- package/dist/pixoo/pixoo-discover.js +105 -0
- package/dist/pixoo/pixoo-discover.js.map +1 -0
- package/dist/pixoo/pixoo-renderer.d.ts +27 -3
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +533 -135
- package/dist/pixoo/pixoo-renderer.js.map +1 -1
- package/dist/pixoo/pixoo-settings.d.ts +6 -0
- package/dist/pixoo/pixoo-settings.d.ts.map +1 -1
- package/dist/pixoo/pixoo-settings.js +9 -0
- package/dist/pixoo/pixoo-settings.js.map +1 -1
- package/dist/pixoo/pixoo-sprites.d.ts +84 -11
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -1
- package/dist/pixoo/pixoo-sprites.js +620 -209
- package/dist/pixoo/pixoo-sprites.js.map +1 -1
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +8 -2
- package/dist/pty-manager.js.map +1 -1
- package/dist/review-runner.d.ts +113 -0
- package/dist/review-runner.d.ts.map +1 -0
- package/dist/review-runner.js +428 -0
- package/dist/review-runner.js.map +1 -0
- package/dist/session-activity.d.ts +14 -0
- package/dist/session-activity.d.ts.map +1 -0
- package/dist/session-activity.js +160 -0
- package/dist/session-activity.js.map +1 -0
- package/dist/session-aggregator.d.ts +25 -0
- package/dist/session-aggregator.d.ts.map +1 -1
- package/dist/session-aggregator.js +48 -9
- package/dist/session-aggregator.js.map +1 -1
- package/dist/session-focus-relay.d.ts.map +1 -1
- package/dist/session-focus-relay.js +7 -1
- package/dist/session-focus-relay.js.map +1 -1
- package/dist/session-registry.d.ts +74 -3
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +140 -8
- package/dist/session-registry.js.map +1 -1
- package/dist/session-timeline-relay.d.ts.map +1 -1
- package/dist/session-timeline-relay.js +13 -4
- package/dist/session-timeline-relay.js.map +1 -1
- package/dist/session-transcript-timeline.d.ts +49 -0
- package/dist/session-transcript-timeline.d.ts.map +1 -0
- package/dist/session-transcript-timeline.js +276 -0
- package/dist/session-transcript-timeline.js.map +1 -0
- package/dist/state-machine.d.ts +6 -1
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +86 -28
- package/dist/state-machine.js.map +1 -1
- package/dist/timebox/timebox-daemon-sync.d.ts +19 -0
- package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -0
- package/dist/timebox/timebox-daemon-sync.js +135 -0
- package/dist/timebox/timebox-daemon-sync.js.map +1 -0
- package/dist/timebox/timebox-discover.d.ts +19 -0
- package/dist/timebox/timebox-discover.d.ts.map +1 -0
- package/dist/timebox/timebox-discover.js +87 -0
- package/dist/timebox/timebox-discover.js.map +1 -0
- package/dist/timebox/timebox-settings.d.ts +32 -0
- package/dist/timebox/timebox-settings.d.ts.map +1 -0
- package/dist/timebox/timebox-settings.js +80 -0
- package/dist/timebox/timebox-settings.js.map +1 -0
- package/dist/timeline-store.d.ts +112 -3
- package/dist/timeline-store.d.ts.map +1 -1
- package/dist/timeline-store.js +460 -14
- package/dist/timeline-store.js.map +1 -1
- package/dist/timeline-summarizer.d.ts.map +1 -1
- package/dist/timeline-summarizer.js +29 -5
- 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/tui/ansi.d.ts +0 -4
- package/dist/tui/ansi.d.ts.map +1 -1
- package/dist/tui/ansi.js +14 -7
- package/dist/tui/ansi.js.map +1 -1
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/tui/dashboard.d.ts.map +1 -1
- package/dist/tui/dashboard.js +38 -11
- package/dist/tui/dashboard.js.map +1 -1
- package/dist/tui/renderer.d.ts +36 -0
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +355 -121
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/terrarium.d.ts.map +1 -1
- package/dist/tui/terrarium.js +44 -51
- package/dist/tui/terrarium.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +7 -1
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts +10 -3
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +98 -13
- package/dist/usage-event.js.map +1 -1
- package/dist/utility-proxy.d.ts.map +1 -1
- package/dist/utility-proxy.js +8 -0
- package/dist/utility-proxy.js.map +1 -1
- package/dist/utils/project-name.d.ts +3 -0
- package/dist/utils/project-name.d.ts.map +1 -1
- package/dist/utils/project-name.js +44 -2
- package/dist/utils/project-name.js.map +1 -1
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +1 -17
- package/dist/version-check.js.map +1 -1
- package/dist/windows-service.d.ts +26 -0
- package/dist/windows-service.d.ts.map +1 -0
- package/dist/windows-service.js +145 -0
- package/dist/windows-service.js.map +1 -0
- package/dist/ws-server.d.ts +17 -3
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +78 -8
- package/dist/ws-server.js.map +1 -1
- package/fm-helper/AgentDeckFMHelper.swift +112 -0
- package/package.json +10 -4
- package/scripts/build-fm-helper.mjs +26 -0
- package/LICENSE +0 -21
- package/dist/apme/tuner.d.ts +0 -64
- package/dist/apme/tuner.d.ts.map +0 -1
- package/dist/apme/tuner.js +0 -297
- package/dist/apme/tuner.js.map +0 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TRMNL image renderer — rasterizes the shared 800×480 dashboard SVG to a
|
|
3
|
+
* 1-bit (black/white) grayscale PNG sized for the TRMNL 7.5" e-ink panel.
|
|
4
|
+
*
|
|
5
|
+
* Pipeline: shared `renderTrmnlDashboard` SVG → resvg rasterize (800×480 RGBA)
|
|
6
|
+
* → luminance threshold → packed 1-bit PNG (color type 0, bit depth 1) encoded
|
|
7
|
+
* with Node's built-in `zlib` (no new dependency). A 1-bit PNG of mostly-white
|
|
8
|
+
* line art deflates to a few KB, comfortably under TRMNL's 90 KB download cap.
|
|
9
|
+
*
|
|
10
|
+
* Falls back to a blank 1-bit PNG when resvg-js is unavailable (matches the
|
|
11
|
+
* D200H renderer's optional-dependency pattern).
|
|
12
|
+
*/
|
|
13
|
+
import { deflateSync } from 'zlib';
|
|
14
|
+
import { createHash } from 'crypto';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { renderTrmnlDashboard, TRMNL_WIDTH, TRMNL_HEIGHT } from '@agentdeck/shared';
|
|
19
|
+
import { debug, logTagged } from '../logger.js';
|
|
20
|
+
const TAG = 'trmnl-render';
|
|
21
|
+
// --- Font supply for resvg (same trap/fix as the D200H renderer) ---
|
|
22
|
+
// resvg drops every <text> element unless given a font to shape glyphs with.
|
|
23
|
+
// Load the bundled OFL faces via `fontFiles` for crisp Latin/mono, AND enable
|
|
24
|
+
// `loadSystemFonts` so resvg can FALL BACK to the OS's CJK faces — session goals
|
|
25
|
+
// are user prompts, often Korean/Chinese, which the Latin-only bundled fonts
|
|
26
|
+
// render as boxes. Unlike the 14-tile-per-frame D200H renderer, TRMNL renders one
|
|
27
|
+
// frame only on real state change, so the per-`new Resvg()` system-font scan is an
|
|
28
|
+
// acceptable cost here.
|
|
29
|
+
const FONT_OPTS = (() => {
|
|
30
|
+
try {
|
|
31
|
+
// bridge/{src,dist}/trmnl/image-renderer.{ts,js} → bridge/assets/fonts
|
|
32
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
const fontsDir = join(here, '..', '..', 'assets', 'fonts');
|
|
34
|
+
const files = [
|
|
35
|
+
'IBMPlexSans-Regular.ttf',
|
|
36
|
+
'IBMPlexSans-Bold.ttf',
|
|
37
|
+
'JetBrainsMono-Regular.ttf',
|
|
38
|
+
'JetBrainsMono-Bold.ttf',
|
|
39
|
+
]
|
|
40
|
+
.map((n) => join(fontsDir, n))
|
|
41
|
+
.filter((p) => existsSync(p));
|
|
42
|
+
if (files.length > 0) {
|
|
43
|
+
return { fontFiles: files, loadSystemFonts: true, defaultFontFamily: 'IBM Plex Sans' };
|
|
44
|
+
}
|
|
45
|
+
debug(TAG, `bundled fonts not found under ${fontsDir} — falling back to system fonts`);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
debug(TAG, `font path resolution failed (${err}) — falling back to system fonts`);
|
|
49
|
+
}
|
|
50
|
+
return { loadSystemFonts: true, defaultFontFamily: 'Helvetica Neue' };
|
|
51
|
+
})();
|
|
52
|
+
let Resvg = null;
|
|
53
|
+
let resvgLoaded = false;
|
|
54
|
+
async function loadResvg() {
|
|
55
|
+
if (resvgLoaded)
|
|
56
|
+
return Resvg;
|
|
57
|
+
resvgLoaded = true;
|
|
58
|
+
try {
|
|
59
|
+
const mod = await import('@resvg/resvg-js');
|
|
60
|
+
Resvg = mod.Resvg ?? mod.default?.Resvg;
|
|
61
|
+
debug(TAG, 'resvg-js loaded — SVG rendering enabled');
|
|
62
|
+
return Resvg;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
debug(TAG, 'resvg-js not available — falling back to blank 1-bit PNG');
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Initialize the renderer (loads resvg-js if available). Call once at start. */
|
|
70
|
+
export async function initTrmnlRenderer() {
|
|
71
|
+
await loadResvg();
|
|
72
|
+
}
|
|
73
|
+
export function isTrmnlResvgLoaded() {
|
|
74
|
+
return Resvg !== null;
|
|
75
|
+
}
|
|
76
|
+
// --- PNG (1-bit grayscale) encoding ---
|
|
77
|
+
const crcTable = new Uint32Array(256);
|
|
78
|
+
for (let n = 0; n < 256; n++) {
|
|
79
|
+
let c = n;
|
|
80
|
+
for (let k = 0; k < 8; k++)
|
|
81
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
82
|
+
crcTable[n] = c >>> 0;
|
|
83
|
+
}
|
|
84
|
+
function crc32(buf) {
|
|
85
|
+
let crc = 0xffffffff;
|
|
86
|
+
for (let i = 0; i < buf.length; i++)
|
|
87
|
+
crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
|
88
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
89
|
+
}
|
|
90
|
+
function pngChunk(type, data) {
|
|
91
|
+
const typeBytes = Buffer.from(type, 'ascii');
|
|
92
|
+
const len = Buffer.alloc(4);
|
|
93
|
+
len.writeUInt32BE(data.length, 0);
|
|
94
|
+
const crc = Buffer.alloc(4);
|
|
95
|
+
crc.writeUInt32BE(crc32(Buffer.concat([typeBytes, data])), 0);
|
|
96
|
+
return Buffer.concat([len, typeBytes, data, crc]);
|
|
97
|
+
}
|
|
98
|
+
const PNG_SIG = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
99
|
+
/**
|
|
100
|
+
* Encode a 1-bit grayscale PNG from a packed bitmap.
|
|
101
|
+
* `bits` holds one bit per pixel, MSB-first, `bytesPerRow` bytes per scanline,
|
|
102
|
+
* where 1 = white and 0 = black (PNG grayscale convention).
|
|
103
|
+
*/
|
|
104
|
+
function encode1BitPng(bits, width, height, bytesPerRow) {
|
|
105
|
+
const ihdr = Buffer.alloc(13);
|
|
106
|
+
ihdr.writeUInt32BE(width, 0);
|
|
107
|
+
ihdr.writeUInt32BE(height, 4);
|
|
108
|
+
ihdr[8] = 1; // bit depth
|
|
109
|
+
ihdr[9] = 0; // color type: grayscale
|
|
110
|
+
ihdr[10] = 0; // compression
|
|
111
|
+
ihdr[11] = 0; // filter
|
|
112
|
+
ihdr[12] = 0; // interlace
|
|
113
|
+
// Raw image data: each scanline prefixed with filter byte 0 (None).
|
|
114
|
+
const raw = Buffer.alloc((bytesPerRow + 1) * height);
|
|
115
|
+
for (let y = 0; y < height; y++) {
|
|
116
|
+
const dst = y * (bytesPerRow + 1);
|
|
117
|
+
raw[dst] = 0; // filter: None
|
|
118
|
+
for (let x = 0; x < bytesPerRow; x++)
|
|
119
|
+
raw[dst + 1 + x] = bits[y * bytesPerRow + x];
|
|
120
|
+
}
|
|
121
|
+
const idat = deflateSync(raw, { level: 9 });
|
|
122
|
+
return Buffer.concat([
|
|
123
|
+
PNG_SIG,
|
|
124
|
+
pngChunk('IHDR', ihdr),
|
|
125
|
+
pngChunk('IDAT', idat),
|
|
126
|
+
pngChunk('IEND', Buffer.alloc(0)),
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Box-downsample a supersampled RGBA buffer (`ss`× the target size) to a packed
|
|
131
|
+
* 1-bit bitmap (1 = white, 0 = black). Averaging each ss×ss block of luma BEFORE
|
|
132
|
+
* thresholding is what sharpens text on a 1-bit panel: a hard threshold of a
|
|
133
|
+
* 1×-rendered glyph drops/jaggies thin strokes (notably Hangul), whereas the
|
|
134
|
+
* averaged edge lands on the majority-coverage boundary, so the same glyph reads
|
|
135
|
+
* crisp. `ss === 1` degrades to a plain threshold.
|
|
136
|
+
*/
|
|
137
|
+
function rgbaToPacked1Bit(pixels, srcWidth, srcHeight, ss = 1) {
|
|
138
|
+
const width = Math.floor(srcWidth / ss);
|
|
139
|
+
const height = Math.floor(srcHeight / ss);
|
|
140
|
+
const bytesPerRow = (width + 7) >> 3;
|
|
141
|
+
const bits = new Uint8Array(bytesPerRow * height);
|
|
142
|
+
bits.fill(0xff); // default white
|
|
143
|
+
const norm = 1 / (ss * ss);
|
|
144
|
+
for (let y = 0; y < height; y++) {
|
|
145
|
+
for (let x = 0; x < width; x++) {
|
|
146
|
+
let sum = 0;
|
|
147
|
+
for (let dy = 0; dy < ss; dy++) {
|
|
148
|
+
const sy = Math.min(y * ss + dy, srcHeight - 1);
|
|
149
|
+
const rowBase = sy * srcWidth;
|
|
150
|
+
for (let dx = 0; dx < ss; dx++) {
|
|
151
|
+
const sx = Math.min(x * ss + dx, srcWidth - 1);
|
|
152
|
+
const p = (rowBase + sx) * 4;
|
|
153
|
+
// Rec.601 luma; transparent pixels (alpha 0) read as white since our SVG
|
|
154
|
+
// paints a full white background, so alpha is effectively always 255.
|
|
155
|
+
sum += (pixels[p] * 299 + pixels[p + 1] * 587 + pixels[p + 2] * 114) / 1000;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (sum * norm < 128) {
|
|
159
|
+
// black pixel → clear the bit
|
|
160
|
+
bits[y * bytesPerRow + (x >> 3)] &= ~(0x80 >> (x & 7));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { bits, bytesPerRow, width, height };
|
|
165
|
+
}
|
|
166
|
+
/** A fully-white 1-bit PNG (fallback when resvg is unavailable). */
|
|
167
|
+
function blankPng(width, height) {
|
|
168
|
+
const bytesPerRow = (width + 7) >> 3;
|
|
169
|
+
const bits = new Uint8Array(bytesPerRow * height).fill(0xff);
|
|
170
|
+
return encode1BitPng(bits, width, height, bytesPerRow);
|
|
171
|
+
}
|
|
172
|
+
function hashBuffer(buf) {
|
|
173
|
+
return createHash('sha1').update(buf).digest('hex').slice(0, 16);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Render the AgentDeck dashboard for the given broadcast state into a 1-bit PNG.
|
|
177
|
+
* Accepts a raw state event or a pre-parsed DashState (passed through to the
|
|
178
|
+
* shared layout). `now` may be supplied for deterministic tests.
|
|
179
|
+
*/
|
|
180
|
+
export function renderTrmnlFrame(stateEvt, now, size) {
|
|
181
|
+
const width = size?.width && size.width > 0 ? Math.round(size.width) : TRMNL_WIDTH;
|
|
182
|
+
const height = size?.height && size.height > 0 ? Math.round(size.height) : TRMNL_HEIGHT;
|
|
183
|
+
let buffer;
|
|
184
|
+
let degraded = false;
|
|
185
|
+
if (Resvg) {
|
|
186
|
+
try {
|
|
187
|
+
const svg = renderTrmnlDashboard(stateEvt, { ...(now ? { now } : {}), width, height });
|
|
188
|
+
// Supersample so the 1-bit threshold has sub-pixel edge info (crisper text,
|
|
189
|
+
// esp. Hangul). Cap the rasterized width so large panels don't blow up the
|
|
190
|
+
// per-frame render: 800→3×, ~1200→2×, ≥2400→1×.
|
|
191
|
+
const ss = Math.max(1, Math.min(3, Math.floor(2400 / width)));
|
|
192
|
+
const resvg = new Resvg(svg, {
|
|
193
|
+
fitTo: { mode: 'width', value: width * ss },
|
|
194
|
+
font: FONT_OPTS,
|
|
195
|
+
background: '#ffffff',
|
|
196
|
+
});
|
|
197
|
+
const rendered = resvg.render();
|
|
198
|
+
const packed = rgbaToPacked1Bit(rendered.pixels, rendered.width, rendered.height, ss);
|
|
199
|
+
buffer = encode1BitPng(packed.bits, packed.width, packed.height, packed.bytesPerRow);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
// Always visible (not debug-gated): a failed render used to silently ship
|
|
203
|
+
// a blank white frame to the panel — the classic "dashboard disappeared"
|
|
204
|
+
// report with zero trace. Rate-limited per error message.
|
|
205
|
+
noteRenderFailure(String(err));
|
|
206
|
+
buffer = blankPng(width, height);
|
|
207
|
+
degraded = true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
buffer = blankPng(width, height);
|
|
212
|
+
degraded = true;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
buffer,
|
|
216
|
+
contentHash: hashBuffer(buffer),
|
|
217
|
+
width,
|
|
218
|
+
height,
|
|
219
|
+
contentType: 'image/png',
|
|
220
|
+
...(degraded ? { degraded: true } : {}),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// Rate-limit render-failure logging so a hot broadcast loop can't spam stderr:
|
|
224
|
+
// each distinct error message logs at most once per minute.
|
|
225
|
+
const RENDER_FAIL_LOG_INTERVAL_MS = 60_000;
|
|
226
|
+
const lastRenderFailLogAt = new Map();
|
|
227
|
+
function noteRenderFailure(message) {
|
|
228
|
+
const now = Date.now();
|
|
229
|
+
const last = lastRenderFailLogAt.get(message) ?? 0;
|
|
230
|
+
if (now - last < RENDER_FAIL_LOG_INTERVAL_MS)
|
|
231
|
+
return;
|
|
232
|
+
lastRenderFailLogAt.set(message, now);
|
|
233
|
+
logTagged(TAG, `render failed (frame cache keeps the last good frame): ${message}`);
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=image-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-renderer.js","sourceRoot":"","sources":["../../src/trmnl/image-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export declare const TRMNL_DEFAULT_REFRESH = 180;
|
|
2
|
+
/**
|
|
3
|
+
* Cadence used only while an agent is AWAITING the user. NOT used for "working":
|
|
4
|
+
* a battery e-ink panel deep-sleeps between polls and full-flashes the screen on
|
|
5
|
+
* every refresh, so we only tighten the loop when the user actually needs to act.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TRMNL_DEFAULT_REFRESH_ACTIVE = 60;
|
|
8
|
+
/** Floor on any cadence — too-frequent polls drain the panel battery + flash it. */
|
|
9
|
+
export declare const TRMNL_MIN_REFRESH = 30;
|
|
10
|
+
/**
|
|
11
|
+
* Seconds the firmware waits for the image download before giving up (its
|
|
12
|
+
* `image_url_timeout`). Generous so a slow/flaky WiFi link doesn't trip the
|
|
13
|
+
* device's "not responding" (WIFI_FAILED) screen. Firmware caps at ~65s, so we
|
|
14
|
+
* keep a healthy default (most "not responding" cycles are a lossy image GET
|
|
15
|
+
* timing out, not a server error — see docs/devices.md TRMNL section).
|
|
16
|
+
*/
|
|
17
|
+
export declare const TRMNL_DEFAULT_IMAGE_TIMEOUT = 50;
|
|
18
|
+
/** Hard cap the firmware honors (it clamps `image_url_timeout` ~65s internally). */
|
|
19
|
+
export declare const TRMNL_MAX_IMAGE_TIMEOUT = 65;
|
|
20
|
+
/**
|
|
21
|
+
* RSSI (dBm) at or below which the panel's WiFi link is treated as weak/lossy.
|
|
22
|
+
* A weak link is the dominant real-world cause of "not responding" (WIFI_FAILED):
|
|
23
|
+
* the image download drops packets and times out. RSSI is sent by the firmware on
|
|
24
|
+
* every poll, so we can react per-poll. (-78 ≈ marginal; below it, retransmits
|
|
25
|
+
* stack up and the default window can be too tight.)
|
|
26
|
+
*/
|
|
27
|
+
export declare const TRMNL_WEAK_RSSI_DBM = -78;
|
|
28
|
+
/** Image-download window served on a weak link — near the firmware cap. */
|
|
29
|
+
export declare const TRMNL_WEAK_LINK_IMAGE_TIMEOUT = 60;
|
|
30
|
+
export interface TrmnlDevice {
|
|
31
|
+
/** Normalized (uppercase, colon-separated) MAC address — the device identity. */
|
|
32
|
+
mac: string;
|
|
33
|
+
/** Secret issued at /api/setup, presented back as the Access-Token header. */
|
|
34
|
+
apiKey: string;
|
|
35
|
+
/** Short human-friendly id shown on the device + in logs. */
|
|
36
|
+
friendlyId: string;
|
|
37
|
+
/** Optional user label. */
|
|
38
|
+
name?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface TrmnlConfig {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
/** Idle/working cadence (seconds) — the slow, battery-friendly default. */
|
|
43
|
+
refreshRate: number;
|
|
44
|
+
/** Cadence (seconds) while a session is AWAITING the user. */
|
|
45
|
+
refreshActive: number;
|
|
46
|
+
/** Image-download timeout (seconds) handed to the firmware as image_url_timeout. */
|
|
47
|
+
imageUrlTimeout: number;
|
|
48
|
+
autoRegister: boolean;
|
|
49
|
+
devices: TrmnlDevice[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Cadence for a poll. We only speed up for AWAITING (the user needs to act);
|
|
53
|
+
* "working" stays on the slow cadence because a deep-sleep e-ink panel can't be
|
|
54
|
+
* pushed and each wake full-flashes the screen + costs battery.
|
|
55
|
+
*/
|
|
56
|
+
export declare function effectiveRefreshRate(cfg: TrmnlConfig, activity: {
|
|
57
|
+
awaiting: number;
|
|
58
|
+
working: number;
|
|
59
|
+
}): number;
|
|
60
|
+
/**
|
|
61
|
+
* Image-download timeout (seconds) for a single poll. Widens toward the firmware
|
|
62
|
+
* cap when the panel reports a weak WiFi signal, so a lossy image GET still has
|
|
63
|
+
* the maximum window to finish before the firmware shows "not responding"
|
|
64
|
+
* (WIFI_FAILED) — the #1 source of TRMNL flicker on a marginal link. A strong link
|
|
65
|
+
* keeps the lower default so a genuinely dead link doesn't hold the radio on
|
|
66
|
+
* (battery). RSSI absent (older firmware) ⇒ default; the default itself is already
|
|
67
|
+
* generous. Clamped to [5, firmware cap].
|
|
68
|
+
*/
|
|
69
|
+
export declare function effectiveImageTimeout(cfg: TrmnlConfig, opts?: {
|
|
70
|
+
rssi?: number | null;
|
|
71
|
+
}): number;
|
|
72
|
+
/** Load the trmnl config with defaults filled in. */
|
|
73
|
+
export declare function loadTrmnlConfig(): TrmnlConfig;
|
|
74
|
+
/**
|
|
75
|
+
* Normalize a MAC to a stable identity key. A canonical 12-hex address becomes
|
|
76
|
+
* uppercase colon-separated pairs; any other id (some firmware/cloud setups
|
|
77
|
+
* report non-standard or punctuated identifiers) collapses to its bare uppercase
|
|
78
|
+
* hex digits. Returning the raw, untrimmed string for the odd case would orphan
|
|
79
|
+
* or duplicate a device whose punctuation varies between polls — so we always
|
|
80
|
+
* derive a deterministic key from the hex content.
|
|
81
|
+
*/
|
|
82
|
+
export declare function normalizeMac(mac: string): string;
|
|
83
|
+
/** True when two MAC spellings resolve to the same canonical identity. */
|
|
84
|
+
export declare function sameMac(a: string, b: string): boolean;
|
|
85
|
+
export declare function findDeviceByMac(mac: string): TrmnlDevice | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Find or create a device record for the given MAC. Returns the device and
|
|
88
|
+
* whether it was newly created. Respects `autoRegister`: when off, a new MAC
|
|
89
|
+
* is NOT persisted and `created` is false with `device` undefined.
|
|
90
|
+
*/
|
|
91
|
+
export declare function ensureDevice(mac: string, name?: string): {
|
|
92
|
+
device?: TrmnlDevice;
|
|
93
|
+
created: boolean;
|
|
94
|
+
};
|
|
95
|
+
export declare function removeDevice(mac: string): boolean;
|
|
96
|
+
//# sourceMappingURL=trmnl-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trmnl-settings.d.ts","sourceRoot":"","sources":["../../src/trmnl/trmnl-settings.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAC/C,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9C,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAAG,MAAM,CAMnG;AAeD,qDAAqD;AACrD,wBAAgB,eAAe,IAAI,WAAW,CAoB7C;AAQD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEpE;AAWD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAgBnG;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOjD"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TRMNL BYOS settings — reads/writes the `trmnl` block in
|
|
3
|
+
* ~/.agentdeck/settings.json, preserving all other keys (same pattern as
|
|
4
|
+
* pixoo-settings.ts).
|
|
5
|
+
*
|
|
6
|
+
* Shape:
|
|
7
|
+
* "trmnl": {
|
|
8
|
+
* "enabled": false, // force the module on even with no device yet
|
|
9
|
+
* "refreshRate": 180, // seconds between device polls
|
|
10
|
+
* "autoRegister": true, // auto-enroll a device that hits /api/setup
|
|
11
|
+
* "devices": [ { mac, apiKey, friendlyId, name? } ]
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
15
|
+
import { join } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
import { randomBytes } from 'crypto';
|
|
18
|
+
// Resolve lazily so tests (and explicit pinning) can redirect via
|
|
19
|
+
// AGENTDECK_DATA_DIR, matching apme/settings.ts and esp32-serial.ts.
|
|
20
|
+
function settingsDir() {
|
|
21
|
+
return process.env.AGENTDECK_DATA_DIR || join(homedir(), '.agentdeck');
|
|
22
|
+
}
|
|
23
|
+
function settingsPath() {
|
|
24
|
+
return join(settingsDir(), 'settings.json');
|
|
25
|
+
}
|
|
26
|
+
export const TRMNL_DEFAULT_REFRESH = 180;
|
|
27
|
+
/**
|
|
28
|
+
* Cadence used only while an agent is AWAITING the user. NOT used for "working":
|
|
29
|
+
* a battery e-ink panel deep-sleeps between polls and full-flashes the screen on
|
|
30
|
+
* every refresh, so we only tighten the loop when the user actually needs to act.
|
|
31
|
+
*/
|
|
32
|
+
export const TRMNL_DEFAULT_REFRESH_ACTIVE = 60;
|
|
33
|
+
/** Floor on any cadence — too-frequent polls drain the panel battery + flash it. */
|
|
34
|
+
export const TRMNL_MIN_REFRESH = 30;
|
|
35
|
+
/**
|
|
36
|
+
* Seconds the firmware waits for the image download before giving up (its
|
|
37
|
+
* `image_url_timeout`). Generous so a slow/flaky WiFi link doesn't trip the
|
|
38
|
+
* device's "not responding" (WIFI_FAILED) screen. Firmware caps at ~65s, so we
|
|
39
|
+
* keep a healthy default (most "not responding" cycles are a lossy image GET
|
|
40
|
+
* timing out, not a server error — see docs/devices.md TRMNL section).
|
|
41
|
+
*/
|
|
42
|
+
export const TRMNL_DEFAULT_IMAGE_TIMEOUT = 50;
|
|
43
|
+
/** Hard cap the firmware honors (it clamps `image_url_timeout` ~65s internally). */
|
|
44
|
+
export const TRMNL_MAX_IMAGE_TIMEOUT = 65;
|
|
45
|
+
/**
|
|
46
|
+
* RSSI (dBm) at or below which the panel's WiFi link is treated as weak/lossy.
|
|
47
|
+
* A weak link is the dominant real-world cause of "not responding" (WIFI_FAILED):
|
|
48
|
+
* the image download drops packets and times out. RSSI is sent by the firmware on
|
|
49
|
+
* every poll, so we can react per-poll. (-78 ≈ marginal; below it, retransmits
|
|
50
|
+
* stack up and the default window can be too tight.)
|
|
51
|
+
*/
|
|
52
|
+
export const TRMNL_WEAK_RSSI_DBM = -78;
|
|
53
|
+
/** Image-download window served on a weak link — near the firmware cap. */
|
|
54
|
+
export const TRMNL_WEAK_LINK_IMAGE_TIMEOUT = 60;
|
|
55
|
+
/**
|
|
56
|
+
* Cadence for a poll. We only speed up for AWAITING (the user needs to act);
|
|
57
|
+
* "working" stays on the slow cadence because a deep-sleep e-ink panel can't be
|
|
58
|
+
* pushed and each wake full-flashes the screen + costs battery.
|
|
59
|
+
*/
|
|
60
|
+
export function effectiveRefreshRate(cfg, activity) {
|
|
61
|
+
return Math.max(TRMNL_MIN_REFRESH, activity.awaiting > 0 ? cfg.refreshActive : cfg.refreshRate);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Image-download timeout (seconds) for a single poll. Widens toward the firmware
|
|
65
|
+
* cap when the panel reports a weak WiFi signal, so a lossy image GET still has
|
|
66
|
+
* the maximum window to finish before the firmware shows "not responding"
|
|
67
|
+
* (WIFI_FAILED) — the #1 source of TRMNL flicker on a marginal link. A strong link
|
|
68
|
+
* keeps the lower default so a genuinely dead link doesn't hold the radio on
|
|
69
|
+
* (battery). RSSI absent (older firmware) ⇒ default; the default itself is already
|
|
70
|
+
* generous. Clamped to [5, firmware cap].
|
|
71
|
+
*/
|
|
72
|
+
export function effectiveImageTimeout(cfg, opts = {}) {
|
|
73
|
+
let t = cfg.imageUrlTimeout;
|
|
74
|
+
if (opts.rssi != null && Number.isFinite(opts.rssi) && opts.rssi <= TRMNL_WEAK_RSSI_DBM) {
|
|
75
|
+
t = Math.max(t, TRMNL_WEAK_LINK_IMAGE_TIMEOUT);
|
|
76
|
+
}
|
|
77
|
+
return Math.min(TRMNL_MAX_IMAGE_TIMEOUT, Math.max(5, Math.floor(t)));
|
|
78
|
+
}
|
|
79
|
+
function readSettings() {
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(readFileSync(settingsPath(), 'utf-8'));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function writeSettings(settings) {
|
|
88
|
+
mkdirSync(settingsDir(), { recursive: true });
|
|
89
|
+
writeFileSync(settingsPath(), JSON.stringify(settings, null, 2) + '\n');
|
|
90
|
+
}
|
|
91
|
+
/** Load the trmnl config with defaults filled in. */
|
|
92
|
+
export function loadTrmnlConfig() {
|
|
93
|
+
const raw = (readSettings().trmnl ?? {});
|
|
94
|
+
const refreshRate = typeof raw.refreshRate === 'number' && raw.refreshRate >= 5 ? Math.floor(raw.refreshRate) : TRMNL_DEFAULT_REFRESH;
|
|
95
|
+
const refreshActive = typeof raw.refreshActive === 'number' && raw.refreshActive >= 5
|
|
96
|
+
? Math.floor(raw.refreshActive)
|
|
97
|
+
: TRMNL_DEFAULT_REFRESH_ACTIVE;
|
|
98
|
+
const imageUrlTimeout = typeof raw.imageUrlTimeout === 'number' && raw.imageUrlTimeout > 0
|
|
99
|
+
? Math.min(TRMNL_MAX_IMAGE_TIMEOUT, Math.floor(raw.imageUrlTimeout))
|
|
100
|
+
: TRMNL_DEFAULT_IMAGE_TIMEOUT;
|
|
101
|
+
return {
|
|
102
|
+
enabled: raw.enabled === true,
|
|
103
|
+
refreshRate,
|
|
104
|
+
refreshActive,
|
|
105
|
+
imageUrlTimeout,
|
|
106
|
+
autoRegister: raw.autoRegister !== false, // default on
|
|
107
|
+
devices: Array.isArray(raw.devices) ? raw.devices.filter((d) => d && typeof d.mac === 'string') : [],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function saveTrmnlConfig(cfg) {
|
|
111
|
+
const settings = readSettings();
|
|
112
|
+
settings.trmnl = cfg;
|
|
113
|
+
writeSettings(settings);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Normalize a MAC to a stable identity key. A canonical 12-hex address becomes
|
|
117
|
+
* uppercase colon-separated pairs; any other id (some firmware/cloud setups
|
|
118
|
+
* report non-standard or punctuated identifiers) collapses to its bare uppercase
|
|
119
|
+
* hex digits. Returning the raw, untrimmed string for the odd case would orphan
|
|
120
|
+
* or duplicate a device whose punctuation varies between polls — so we always
|
|
121
|
+
* derive a deterministic key from the hex content.
|
|
122
|
+
*/
|
|
123
|
+
export function normalizeMac(mac) {
|
|
124
|
+
const hex = (mac || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase();
|
|
125
|
+
if (hex.length === 12)
|
|
126
|
+
return hex.match(/.{2}/g).join(':');
|
|
127
|
+
return hex || (mac || '').trim().toUpperCase();
|
|
128
|
+
}
|
|
129
|
+
/** True when two MAC spellings resolve to the same canonical identity. */
|
|
130
|
+
export function sameMac(a, b) {
|
|
131
|
+
return normalizeMac(a) === normalizeMac(b);
|
|
132
|
+
}
|
|
133
|
+
export function findDeviceByMac(mac) {
|
|
134
|
+
return loadTrmnlConfig().devices.find((d) => sameMac(d.mac, mac));
|
|
135
|
+
}
|
|
136
|
+
function genFriendlyId() {
|
|
137
|
+
// 6 chars from an unambiguous base32 alphabet (no 0/1/O/I).
|
|
138
|
+
const alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
|
139
|
+
const bytes = randomBytes(6);
|
|
140
|
+
let out = '';
|
|
141
|
+
for (let i = 0; i < 6; i++)
|
|
142
|
+
out += alphabet[bytes[i] % alphabet.length];
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Find or create a device record for the given MAC. Returns the device and
|
|
147
|
+
* whether it was newly created. Respects `autoRegister`: when off, a new MAC
|
|
148
|
+
* is NOT persisted and `created` is false with `device` undefined.
|
|
149
|
+
*/
|
|
150
|
+
export function ensureDevice(mac, name) {
|
|
151
|
+
const cfg = loadTrmnlConfig();
|
|
152
|
+
const norm = normalizeMac(mac);
|
|
153
|
+
const existing = cfg.devices.find((d) => sameMac(d.mac, mac));
|
|
154
|
+
if (existing)
|
|
155
|
+
return { device: existing, created: false };
|
|
156
|
+
if (!cfg.autoRegister)
|
|
157
|
+
return { created: false };
|
|
158
|
+
const device = {
|
|
159
|
+
mac: norm,
|
|
160
|
+
apiKey: randomBytes(16).toString('hex'),
|
|
161
|
+
friendlyId: genFriendlyId(),
|
|
162
|
+
name,
|
|
163
|
+
};
|
|
164
|
+
cfg.devices.push(device);
|
|
165
|
+
saveTrmnlConfig(cfg);
|
|
166
|
+
return { device, created: true };
|
|
167
|
+
}
|
|
168
|
+
export function removeDevice(mac) {
|
|
169
|
+
const cfg = loadTrmnlConfig();
|
|
170
|
+
const filtered = cfg.devices.filter((d) => !sameMac(d.mac, mac));
|
|
171
|
+
if (filtered.length === cfg.devices.length)
|
|
172
|
+
return false;
|
|
173
|
+
cfg.devices = filtered;
|
|
174
|
+
saveTrmnlConfig(cfg);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=trmnl-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trmnl-settings.js","sourceRoot":"","sources":["../../src/trmnl/trmnl-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface DeviceTelemetry {
|
|
2
|
+
/** Normalized MAC identity (matches TrmnlDevice.mac). */
|
|
3
|
+
mac: string;
|
|
4
|
+
fwVersion: string;
|
|
5
|
+
batteryVoltage: number | null;
|
|
6
|
+
rssi: number | null;
|
|
7
|
+
width: number | null;
|
|
8
|
+
height: number | null;
|
|
9
|
+
/** Cadence the device says it's polling at (we still dictate it on response). */
|
|
10
|
+
refreshRate: number | null;
|
|
11
|
+
userAgent: string;
|
|
12
|
+
/** Epoch ms of the most recent poll. */
|
|
13
|
+
lastSeen: number;
|
|
14
|
+
}
|
|
15
|
+
export interface TelemetryInput {
|
|
16
|
+
fwVersion?: string;
|
|
17
|
+
batteryVoltage?: number | null;
|
|
18
|
+
rssi?: number | null;
|
|
19
|
+
width?: number | null;
|
|
20
|
+
height?: number | null;
|
|
21
|
+
refreshRate?: number | null;
|
|
22
|
+
userAgent?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Upsert the last-seen telemetry for a device. `now` is injected at the daemon
|
|
26
|
+
* boundary (defaults to wall clock) so layout/render code stays clock-free.
|
|
27
|
+
* Returns the previous `lastSeen` (epoch ms) so callers can detect poll gaps.
|
|
28
|
+
*/
|
|
29
|
+
export declare function recordTelemetry(mac: string, t: TelemetryInput, now?: number): number | null;
|
|
30
|
+
/** Snapshot of all known device telemetry, most-recently-seen first. */
|
|
31
|
+
export declare function getTelemetry(): DeviceTelemetry[];
|
|
32
|
+
/** Telemetry plus derived freshness — `secondsSinceSeen` and a `stale` flag. */
|
|
33
|
+
export interface DeviceHealth extends DeviceTelemetry {
|
|
34
|
+
secondsSinceSeen: number;
|
|
35
|
+
/** True when the panel hasn't polled in over 2× its expected cadence. */
|
|
36
|
+
stale: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Telemetry annotated with health. A panel that hasn't polled within 2× its
|
|
40
|
+
* cadence is flagged `stale` so the dashboard can distinguish "panel stuck /
|
|
41
|
+
* offline" from "nothing changed". `now`/`refreshRate` are injected at the daemon
|
|
42
|
+
* boundary so this stays clock- and config-free.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getTelemetryHealth(refreshRate: number, now?: number): DeviceHealth[];
|
|
45
|
+
/** Test helper — clear the runtime map. */
|
|
46
|
+
export declare function _resetTelemetry(): void;
|
|
47
|
+
//# sourceMappingURL=trmnl-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trmnl-telemetry.d.ts","sourceRoot":"","sources":["../../src/trmnl/trmnl-telemetry.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iFAAiF;IACjF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,GAAG,IAAI,CAgBvG;AAED,wEAAwE;AACxE,wBAAgB,YAAY,IAAI,eAAe,EAAE,CAEhD;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,YAAY,EAAE,CAMhG;AAED,2CAA2C;AAC3C,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TRMNL device telemetry — a runtime-only, per-MAC snapshot of the headers a
|
|
3
|
+
* BYOS panel reports on each /api/setup or /api/display poll (firmware version,
|
|
4
|
+
* battery voltage, WiFi signal, panel resolution). This is NOT persisted to
|
|
5
|
+
* settings.json: polls arrive every ~180s and writing the settings file on each
|
|
6
|
+
* one would thrash it and race the user's manual edits. The daemon status
|
|
7
|
+
* snapshot reads this map for diagnostics; it's lost on daemon restart, which is
|
|
8
|
+
* fine — the next poll repopulates it.
|
|
9
|
+
*/
|
|
10
|
+
import { normalizeMac } from './trmnl-settings.js';
|
|
11
|
+
const telemetry = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Upsert the last-seen telemetry for a device. `now` is injected at the daemon
|
|
14
|
+
* boundary (defaults to wall clock) so layout/render code stays clock-free.
|
|
15
|
+
* Returns the previous `lastSeen` (epoch ms) so callers can detect poll gaps.
|
|
16
|
+
*/
|
|
17
|
+
export function recordTelemetry(mac, t, now = Date.now()) {
|
|
18
|
+
const key = normalizeMac(mac);
|
|
19
|
+
if (!key)
|
|
20
|
+
return null;
|
|
21
|
+
const prevLastSeen = telemetry.get(key)?.lastSeen ?? null;
|
|
22
|
+
telemetry.set(key, {
|
|
23
|
+
mac: key,
|
|
24
|
+
fwVersion: t.fwVersion ?? '',
|
|
25
|
+
batteryVoltage: t.batteryVoltage ?? null,
|
|
26
|
+
rssi: t.rssi ?? null,
|
|
27
|
+
width: t.width ?? null,
|
|
28
|
+
height: t.height ?? null,
|
|
29
|
+
refreshRate: t.refreshRate ?? null,
|
|
30
|
+
userAgent: t.userAgent ?? '',
|
|
31
|
+
lastSeen: now,
|
|
32
|
+
});
|
|
33
|
+
return prevLastSeen;
|
|
34
|
+
}
|
|
35
|
+
/** Snapshot of all known device telemetry, most-recently-seen first. */
|
|
36
|
+
export function getTelemetry() {
|
|
37
|
+
return [...telemetry.values()].sort((a, b) => b.lastSeen - a.lastSeen);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Telemetry annotated with health. A panel that hasn't polled within 2× its
|
|
41
|
+
* cadence is flagged `stale` so the dashboard can distinguish "panel stuck /
|
|
42
|
+
* offline" from "nothing changed". `now`/`refreshRate` are injected at the daemon
|
|
43
|
+
* boundary so this stays clock- and config-free.
|
|
44
|
+
*/
|
|
45
|
+
export function getTelemetryHealth(refreshRate, now = Date.now()) {
|
|
46
|
+
const staleAfterMs = Math.max(30, refreshRate) * 2 * 1000;
|
|
47
|
+
return getTelemetry().map((t) => {
|
|
48
|
+
const ageMs = now - t.lastSeen;
|
|
49
|
+
return { ...t, secondsSinceSeen: Math.round(ageMs / 1000), stale: ageMs > staleAfterMs };
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Test helper — clear the runtime map. */
|
|
53
|
+
export function _resetTelemetry() {
|
|
54
|
+
telemetry.clear();
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=trmnl-telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trmnl-telemetry.js","sourceRoot":"","sources":["../../src/trmnl/trmnl-telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA2BnD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;AAErD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,CAAiB,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IACtF,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC1D,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE;QACjB,GAAG,EAAE,GAAG;QACR,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE;QAC5B,cAAc,EAAE,CAAC,CAAC,cAAc,IAAI,IAAI;QACxC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;QACpB,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;QACxB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;QAClC,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE;QAC5B,QAAQ,EAAE,GAAG;KACd,CAAC,CAAC;IACH,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC;AASD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IAC9E,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAC1D,OAAO,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC/B,OAAO,EAAE,GAAG,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,YAAY,EAAE,CAAC;IAC3F,CAAC,CAAC,CAAC;AACL,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,eAAe;IAC7B,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC"}
|