Merge remote-tracking branch 'origin/main' into review/pr-5-machine-federation-fixes

# Conflicts:
#	src/client/src/api/clients.ts
#	src/client/src/components/PiWebApp.ts
#	src/client/src/components/PromptEditor.ts
#	src/server/app.ts
#	src/server/terminalProxyRoutes.ts
#	src/server/workspaces/fileSuggestions.ts
This commit is contained in:
Federico Jaramillo Martinez
2026-06-02 17:42:16 +02:00
71 changed files with 3146 additions and 699 deletions
+9 -5
View File
@@ -308,19 +308,23 @@ export interface PiWebStatusMessage {
command?: string;
}
export interface PiWebStatusResponse {
export interface PiWebVersionResponse {
packageName: string;
generatedAt: string;
components: {
web: PiWebComponentStatus;
sessiond: PiWebComponentStatus;
};
}
export interface PiWebStatusResponse extends PiWebVersionResponse {
release: PiWebReleaseStatus;
commands: {
update: string;
restart: string;
restartSystemd: string;
restartDev: string;
update?: string;
restart?: string;
restartWeb?: string;
restartSessiond?: string;
status?: string;
};
messages: PiWebStatusMessage[];
}
+58
View File
@@ -0,0 +1,58 @@
import type { PiWebComponentStatus, PiWebInstallationInfo, PiWebVersionResponse } from "./apiTypes.js";
export function parsePiWebVersionResponse(value: unknown): PiWebVersionResponse | undefined {
if (!isRecord(value)) return undefined;
const packageName = value["packageName"];
const generatedAt = value["generatedAt"];
const components = value["components"];
if (typeof packageName !== "string" || packageName === "" || typeof generatedAt !== "string" || generatedAt === "" || !isRecord(components)) return undefined;
const web = parsePiWebComponentStatus(components["web"]);
const sessiond = parsePiWebComponentStatus(components["sessiond"]);
if (web === undefined || sessiond === undefined) return undefined;
return { packageName, generatedAt, components: { web, sessiond } };
}
export function parsePiWebComponentStatus(value: unknown): PiWebComponentStatus | undefined {
if (!isRecord(value)) return undefined;
const component = value["component"];
const label = value["label"];
const runtimeVersion = value["runtimeVersion"];
const installedVersion = value["installedVersion"];
const stale = value["stale"];
const available = value["available"];
const error = value["error"];
const installation = parsePiWebInstallationInfo(value["installation"]);
if (component !== "web" && component !== "sessiond") return undefined;
if (typeof label !== "string" || label === "" || typeof stale !== "boolean" || typeof available !== "boolean") return undefined;
return {
component,
label,
...(typeof runtimeVersion === "string" ? { runtimeVersion } : {}),
...(typeof installedVersion === "string" ? { installedVersion } : {}),
stale,
available,
...(installation === undefined ? {} : { installation }),
...(typeof error === "string" ? { error } : {}),
};
}
export function parsePiWebInstallationInfo(value: unknown): PiWebInstallationInfo | undefined {
if (!isRecord(value)) return undefined;
const kind = value["kind"];
const path = value["path"];
const source = value["source"];
const scope = value["scope"];
const npmRoot = value["npmRoot"];
if (kind !== "pi-package" && kind !== "npm-global" && kind !== "local" && kind !== "unknown") return undefined;
return {
kind,
...(typeof path === "string" ? { path } : {}),
...(typeof source === "string" ? { source } : {}),
...(scope === "user" || scope === "project" ? { scope } : {}),
...(typeof npmRoot === "string" ? { npmRoot } : {}),
};
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}