feat: human error states, operator toasts and a queue/origin view in the omp UI

- classify transport and API failures into a short state with the next step
- count undelivered messages and show them next to the sent counter
- toast on owner paired, connection recovered and reply not delivered (throttled)
- second status line previews the next queued turns
- host spinner names the Telegram prompt while its turn runs
- sanitize every Telegram-controlled string that reaches the widget
This commit is contained in:
evandrodevbr committed 2026-10-01 17:33:37 -03:00
1 parent 9435ff709b
commit 057281a3bb
19 files changed
+862 -22

No files matched your search

+23
View File
@@ -19,6 +19,8 @@ import {
hasExtensionContextPendingMessages,
isExtensionContextIdle,
isExtensionContextPassiveRunMode,
notifyExtensionContext,
setExtensionWorkingMessage,
} from "../lib/pi.ts";
type PiRuntimeApiHarness = Parameters<
@@ -169,3 +171,24 @@ test("Pi context model prefers omp's live models facade over a frozen ctx.model"
assert.equal(getExtensionContextModel(ompCtx), live);
assert.equal(getExtensionContextModel(piCtx), frozen);
});
test("Host UI helpers forward to the context and tolerate a host without a spinner API", () => {
const calls: string[] = [];
const full = {
ui: {
notify: (message: string, level: string) => {
calls.push(`notify:${level}:${message}`);
},
setWorkingMessage: (message?: string) => {
calls.push(`working:${message}`);
},
},
} as unknown as ExtensionContext;
notifyExtensionContext(full, "hello", "warning");
setExtensionWorkingMessage(full, "busy");
setExtensionWorkingMessage(full, undefined);
assert.deepEqual(calls, ["notify:warning:hello", "working:busy", "working:undefined"]);
const withoutSpinner = { ui: {} } as unknown as ExtensionContext;
assert.doesNotThrow(() => setExtensionWorkingMessage(withoutSpinner, "busy"));
});