Files
paseo/plugins/muse-provider/server/recovery.ts
T
Mohamed Boudraandmillerben95 8332f4d1ff feat(muse): add Muse Code as a built-in provider plugin (#5719)
* 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>
2026-09-30 14:56:41 +01:00

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);
}
}