mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 17:52:49 +00:00
* fix(workspaces): observe setup output only in the visible setup panel Setup logs were requested for the whole session, including unrelated workspaces. Use directory status for discovery and source-owned workspace observations for details, preserving legacy delivery only for clients without the negotiated capability. * fix(workspaces): publish external setup progress once per daemon MCP and scheduled setup enter through the broadcast API. Publish them to the shared setup owner before session fanout so each observation gets one update and snapshots survive periods without connected clients. Keep the setup action available on older hosts to explain the required host update. * fix(app): replace setup details with each observation snapshot A host restart can return an empty setup snapshot. Apply that authoritative snapshot so an open panel does not retain output from the previous daemon. Assert setup membership requests as well as delivery in the browser lifecycle regression. * test(workspaces): cover setup status catch-up after directory release * test(workspaces): synchronize setup output and release fixture resources
77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
import { getE2EDaemonPort } from "./daemon-port";
|
|
import { createNodeWebSocketFactory, type NodeWebSocketFactory } from "./node-ws-factory";
|
|
|
|
export async function loadDaemonClientConstructor<ClientConfig, ClientInstance>(): Promise<
|
|
new (config: ClientConfig) => ClientInstance
|
|
> {
|
|
const repoRoot = path.resolve(__dirname, "../../../../../");
|
|
const moduleUrl = pathToFileURL(
|
|
path.join(repoRoot, "packages/client/dist/daemon-client.js"),
|
|
).href;
|
|
const mod = (await import(moduleUrl)) as {
|
|
DaemonClient: new (config: ClientConfig) => ClientInstance;
|
|
};
|
|
return mod.DaemonClient;
|
|
}
|
|
|
|
interface E2EDaemonClientConfig {
|
|
url: string;
|
|
clientId: string;
|
|
clientType: "cli";
|
|
appVersion?: string;
|
|
webSocketFactory?: NodeWebSocketFactory;
|
|
capabilities?: Record<string, unknown>;
|
|
}
|
|
|
|
function resolveDaemonWsUrl(port?: number): string {
|
|
return `ws://127.0.0.1:${port ?? getE2EDaemonPort()}/ws`;
|
|
}
|
|
|
|
export interface ConnectDaemonClientOptions {
|
|
clientIdPrefix: string;
|
|
appVersion?: string;
|
|
port?: number;
|
|
capabilities?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* Connects an in-test daemon client over the isolated E2E daemon's WebSocket.
|
|
* The port-6767 guard keeps tests off the developer daemon. Each helper passes
|
|
* its own typed client interface as the generic.
|
|
*/
|
|
export async function connectDaemonClient<ClientInstance extends { connect(): Promise<void> }>(
|
|
options: ConnectDaemonClientOptions,
|
|
): Promise<ClientInstance> {
|
|
const DaemonClient = await loadDaemonClientConstructor<E2EDaemonClientConfig, ClientInstance>();
|
|
const client = new DaemonClient({
|
|
url: resolveDaemonWsUrl(options.port),
|
|
clientId: `${options.clientIdPrefix}-${randomUUID()}`,
|
|
clientType: "cli",
|
|
appVersion: options.appVersion ?? loadAppVersion(),
|
|
webSocketFactory: createNodeWebSocketFactory(),
|
|
capabilities: options.capabilities,
|
|
});
|
|
await client.connect();
|
|
return client;
|
|
}
|
|
|
|
function loadAppVersion(): string {
|
|
const packageJsonPath = path.resolve(__dirname, "../../../package.json");
|
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { version?: unknown };
|
|
if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
|
|
throw new Error(`Missing app version in ${packageJsonPath}`);
|
|
}
|
|
return packageJson.version;
|
|
}
|
|
|
|
export async function loadProtocolSchemas(): Promise<typeof import("@getpaseo/protocol/messages")> {
|
|
const moduleUrl = pathToFileURL(
|
|
path.resolve(__dirname, "../../../../../packages/protocol/dist/messages.js"),
|
|
).href;
|
|
return import(moduleUrl);
|
|
}
|