Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ec97a06d2 |
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.21.12 — 2026-10-06 08:01
|
||||||
|
|
||||||
|
- Battery monitoring now ignores a 0% reading: a 0 (or any non-positive) `batteryLevel` is treated as an invalid/no-data value (node has no battery wired or is misconfigured) and no longer produces a "⚠️ battery low" alert, while genuinely-low readings (1–20%) still alert exactly as before. One-line guard added to `BatteryAlertService.shouldAlert` right after the `undefined` check. Tests: 3 new specs in the `check threshold` block — a 0% node is excluded from the batch (and a lone 0% sends nothing) while a 1% node still alerts.
|
||||||
|
|
||||||
## v0.21.11 — 2026-10-05 14:47
|
## v0.21.11 — 2026-10-05 14:47
|
||||||
|
|
||||||
- Migrated the opencode notifier to the v2 API routes: discovery is now `GET {api}{proxyPath}/api/session` (a `{ data, cursor }` envelope; sessions filtered by `location.directory`, most-recent `time.updated` wins) and send is now `POST {api}{proxyPath}/api/session/{sid}/prompt` with a `{text}` body, instead of the v1 `GET /session` + `POST /session/{id}/message` (`{parts:[{type:"text",text}]}`) routes. CodeNomad's per-workspace instance proxy was upgraded and now only serves opencode v2 `/api/*` — every v1 `/session/…` call 403s, which was breaking all notifications. v2 returns 2xx immediately (no longer holds the response until the turn finishes), so the 15 s read-timeout-as-delivered branch is kept only as a harmless safety net.
|
- Migrated the opencode notifier to the v2 API routes: discovery is now `GET {api}{proxyPath}/api/session` (a `{ data, cursor }` envelope; sessions filtered by `location.directory`, most-recent `time.updated` wins) and send is now `POST {api}{proxyPath}/api/session/{sid}/prompt` with a `{text}` body, instead of the v1 `GET /session` + `POST /session/{id}/message` (`{parts:[{type:"text",text}]}`) routes. CodeNomad's per-workspace instance proxy was upgraded and now only serves opencode v2 `/api/*` — every v1 `/session/…` call 403s, which was breaking all notifications. v2 returns 2xx immediately (no longer holds the response until the turn finishes), so the 15 s read-timeout-as-delivered branch is kept only as a harmless safety net.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mesh-bot",
|
"name": "mesh-bot",
|
||||||
"version": "0.21.11",
|
"version": "0.21.12",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -119,6 +119,47 @@ describe('BatteryAlertService check threshold', () => {
|
|||||||
expect(sendText).not.toHaveBeenCalled();
|
expect(sendText).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('ignores a 0% reading (invalid/no battery) even though 0 <= threshold', async () => {
|
||||||
|
const sendText = vi.fn(async (..._args: unknown[]) => 1);
|
||||||
|
// 0% must not alert, but a genuinely-low 5% node in the same batch must
|
||||||
|
const svc = makeService([node(1, 0), node(2, 5)], sendText);
|
||||||
|
|
||||||
|
await svc.check();
|
||||||
|
|
||||||
|
expect(sendText).toHaveBeenCalledTimes(1);
|
||||||
|
// only the 5% node — the 0% node is excluded entirely
|
||||||
|
expect(sendText.mock.calls[0]).toEqual([
|
||||||
|
BROADCAST_ADDR,
|
||||||
|
'⚠️ battery low: @!00000002 5%',
|
||||||
|
undefined,
|
||||||
|
2,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores a lone 0% reading (no broadcast at all)', async () => {
|
||||||
|
const sendText = vi.fn(async (..._args: unknown[]) => 1);
|
||||||
|
const svc = makeService([node(1, 0)], sendText); // only an invalid 0% reading
|
||||||
|
|
||||||
|
await svc.check();
|
||||||
|
|
||||||
|
expect(sendText).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('still alerts a genuine 1% reading (lowest valid value)', async () => {
|
||||||
|
const sendText = vi.fn(async (..._args: unknown[]) => 1);
|
||||||
|
const svc = makeService([node(1, 1)], sendText);
|
||||||
|
|
||||||
|
await svc.check();
|
||||||
|
|
||||||
|
expect(sendText).toHaveBeenCalledTimes(1);
|
||||||
|
expect(sendText.mock.calls[0]).toEqual([
|
||||||
|
BROADCAST_ADDR,
|
||||||
|
'⚠️ battery low: @!00000001 1%',
|
||||||
|
undefined,
|
||||||
|
2,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('merges all qualifying nodes into exactly ONE broadcast with the broadcast target', async () => {
|
it('merges all qualifying nodes into exactly ONE broadcast with the broadcast target', async () => {
|
||||||
const sendText = vi.fn(async (..._args: unknown[]) => 1);
|
const sendText = vi.fn(async (..._args: unknown[]) => 1);
|
||||||
const svc = makeService(
|
const svc = makeService(
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export class BatteryAlertService {
|
|||||||
|
|
||||||
private shouldAlert(node: NodeSummary, now: number): boolean {
|
private shouldAlert(node: NodeSummary, now: number): boolean {
|
||||||
if (node.batteryLevel === undefined) return false; // no battery reported — skip
|
if (node.batteryLevel === undefined) return false; // no battery reported — skip
|
||||||
|
if (node.batteryLevel <= 0) return false; // 0/invalid reading — no battery wired or misconfigured node, not a real low-battery alert
|
||||||
// <= on purpose: a node at exactly the threshold is already "low" (spec allowed either < or <=; tests pin this choice)
|
// <= on purpose: a node at exactly the threshold is already "low" (spec allowed either < or <=; tests pin this choice)
|
||||||
if (!(node.batteryLevel <= this.threshold)) return false;
|
if (!(node.batteryLevel <= this.threshold)) return false;
|
||||||
const last = this.lastAlertAt.get(node.num);
|
const last = this.lastAlertAt.get(node.num);
|
||||||
|
|||||||
Reference in New Issue
Block a user