mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-26 11:12:53 +00:00
* test(muse): record real host protocol fixtures * feat(muse): add built-in MSP provider Co-authored-by: millerben95 <millerben95@users.noreply.github.com> * fix(muse): expose provider settings in the app The daemon registered host settings without a client contribution, leaving sandbox, network, and workspace trust unreachable. Share the definition with a settings screen and expose it through Command Center even when installed plugins are disabled. * docs(muse): publish setup and provider support * test: correct runtime fixtures and restart readiness * fix(muse): hide reminder housekeeping from the timeline * fix(muse): use the official Muse Code mark Source: https://muse.ai/images/favicon/app-squiggle.svg Preserve the official silhouette path verbatim. Remove its gradient definition and use currentColor, scaling the original 100-unit coordinates into the 24-unit viewBox. Black silhouette renders match pixel-for-pixel. * fix(muse): adapt to current plugin APIs Use the screen API introduced with sidebar plugin items. Usage reports now come from source account discovery; remove the retired agent usage-reference request and headline marker, and exercise discovery through the existing provider fixtures. --------- Co-authored-by: millerben95 <millerben95@users.noreply.github.com>
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import type { z } from "zod";
|
|
import { MspConnection, type Notification } from "./connection.js";
|
|
import { pageSchema } from "./wire.js";
|
|
|
|
// Two minutes accommodates slow model/tool work; polling repairs a lost live view without cancelling it.
|
|
const SILENCE_MS = 2 * 60 * 1000;
|
|
export class Recovery {
|
|
private timer: ReturnType<typeof setTimeout> | undefined;
|
|
private active = false;
|
|
private closed = false;
|
|
private cursor: string;
|
|
constructor(
|
|
private readonly host: MspConnection,
|
|
private readonly sessionId: string,
|
|
cursor: string,
|
|
private readonly apply: (event: Notification) => Promise<void>,
|
|
private readonly onSilent: () => void,
|
|
) {
|
|
this.cursor = cursor;
|
|
}
|
|
|
|
activity(cursor: string | undefined, active: boolean): void {
|
|
if (cursor !== undefined) this.cursor = cursor;
|
|
this.active = active;
|
|
clearTimeout(this.timer);
|
|
if (active && !this.closed) this.timer = setTimeout(this.onSilent, SILENCE_MS);
|
|
}
|
|
async backfill(after = this.cursor): Promise<void> {
|
|
let cursor: string | null = after;
|
|
do {
|
|
const page: z.infer<typeof pageSchema> = await this.host.request(
|
|
"view/page",
|
|
{ sessionId: this.sessionId, cursor, direction: "forward", limit: 1000 },
|
|
pageSchema,
|
|
);
|
|
for (const event of page.events) await this.apply(event);
|
|
cursor = page.nextCursor;
|
|
} while (cursor !== null && !this.closed);
|
|
this.activity(undefined, this.active);
|
|
}
|
|
close(): void {
|
|
this.closed = true;
|
|
clearTimeout(this.timer);
|
|
}
|
|
}
|