feat: expose daemon-owned active agent profile

This commit is contained in:
Federico Jaramillo Martinez
2026-07-13 22:50:50 +02:00
parent a1a019e7b1
commit 141cda93c8
11 changed files with 362 additions and 25 deletions
+43
View File
@@ -0,0 +1,43 @@
import type { ActiveAgentProfileDescriptor } from "./apiTypes.js";
export const ACTIVE_AGENT_PROFILE_SCHEMA_VERSION = 1 as const;
const ACTIVE_AGENT_PROFILE_FIELDS = new Set([
"schemaVersion",
"revision",
"command",
"dir",
"sessionDirEnvKeys",
]);
const SHA256_REVISION_PATTERN = /^sha256:[0-9a-f]{64}$/u;
export function parseActiveAgentProfileDescriptor(value: unknown): ActiveAgentProfileDescriptor | undefined {
if (!isRecord(value) || Object.keys(value).some((key) => !ACTIVE_AGENT_PROFILE_FIELDS.has(key))) return undefined;
const schemaVersion = value["schemaVersion"];
const revision = value["revision"];
const command = value["command"];
const dir = value["dir"];
const sessionDirEnvKeys = value["sessionDirEnvKeys"];
if (schemaVersion !== ACTIVE_AGENT_PROFILE_SCHEMA_VERSION) return undefined;
if (typeof revision !== "string" || !SHA256_REVISION_PATTERN.test(revision)) return undefined;
if (typeof command !== "string" || command === "" || typeof dir !== "string" || dir === "") return undefined;
if (!isNonEmptyStringArray(sessionDirEnvKeys)) return undefined;
if (new Set(sessionDirEnvKeys).size !== sessionDirEnvKeys.length) return undefined;
return Object.freeze({
schemaVersion,
revision,
command,
dir,
sessionDirEnvKeys: Object.freeze([...sessionDirEnvKeys]),
});
}
function isNonEmptyStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((entry: unknown) => typeof entry === "string" && entry !== "");
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
+11
View File
@@ -593,12 +593,23 @@ export interface PiWebComponentStatus {
error?: string;
}
/** Secret-free identity of the Pi-compatible CLI/state profile fixed for one sessiond lifetime. */
export interface ActiveAgentProfileDescriptor {
readonly schemaVersion: 1;
readonly revision: string;
readonly command: string;
readonly dir: string;
readonly sessionDirEnvKeys: readonly string[];
}
export interface PiWebRuntimeComponent {
component: PiWebServiceComponent;
label: string;
runtimeVersion?: string;
available: boolean;
capabilities: PiWebCapability[];
/** Present only for a session daemon that supports active-profile reporting. */
activeAgentProfile?: ActiveAgentProfileDescriptor;
error?: string;
}
+50
View File
@@ -33,6 +33,56 @@ describe("PI WEB status parsing", () => {
})).toBeUndefined();
});
it("parses and freezes a session daemon active agent profile", () => {
const parsed = parsePiWebRuntimeResponse({
packageName: "@jmfederico/pi-web",
generatedAt: "now",
components: {
web: { component: "web", label: "Web/UI", available: true, capabilities: [] },
sessiond: {
component: "sessiond",
label: "Session daemon",
available: true,
capabilities: [],
activeAgentProfile: {
schemaVersion: 1,
revision: `sha256:${"a".repeat(64)}`,
command: "acme-agent",
dir: "/opt/acme-agent/state",
sessionDirEnvKeys: ["PI_WEB_AGENT_SESSION_DIR"],
},
},
},
capabilities: [],
});
expect(parsed?.components.sessiond.activeAgentProfile).toMatchObject({ command: "acme-agent", dir: "/opt/acme-agent/state" });
expect(Object.isFrozen(parsed?.components.sessiond.activeAgentProfile)).toBe(true);
expect(Object.isFrozen(parsed?.components.sessiond.activeAgentProfile?.sessionDirEnvKeys)).toBe(true);
});
it("rejects malformed, secret-bearing, or web-owned active profile descriptors", () => {
const profile = {
schemaVersion: 1,
revision: `sha256:${"a".repeat(64)}`,
command: "acme-agent",
dir: "/opt/acme-agent/state",
sessionDirEnvKeys: ["PI_WEB_AGENT_SESSION_DIR"],
};
const responseFor = (webProfile: unknown, sessiondProfile: unknown) => ({
packageName: "@jmfederico/pi-web",
generatedAt: "now",
components: {
web: { component: "web", label: "Web/UI", available: true, capabilities: [], ...(webProfile === undefined ? {} : { activeAgentProfile: webProfile }) },
sessiond: { component: "sessiond", label: "Session daemon", available: true, capabilities: [], ...(sessiondProfile === undefined ? {} : { activeAgentProfile: sessiondProfile }) },
},
capabilities: [],
});
expect(parsePiWebRuntimeResponse(responseFor(undefined, { ...profile, token: "secret" }))).toBeUndefined();
expect(parsePiWebRuntimeResponse(responseFor(profile, undefined))).toBeUndefined();
});
it("parses Docker installation metadata", () => {
expect(parsePiWebInstallationInfo({ kind: "docker", path: "/srv/pi-web-docker", dockerMode: "runtime" })).toEqual({
kind: "docker",
+5
View File
@@ -1,4 +1,5 @@
import type { PiWebComponentStatus, PiWebInstallationInfo, PiWebRuntimeComponent, PiWebRuntimeResponse, PiWebVersionResponse } from "./apiTypes.js";
import { parseActiveAgentProfileDescriptor } from "./activeAgentProfile.js";
import { parseKnownPiWebCapabilities } from "./capabilities.js";
export function parsePiWebVersionResponse(value: unknown): PiWebVersionResponse | undefined {
@@ -33,15 +34,19 @@ export function parsePiWebRuntimeComponent(value: unknown): PiWebRuntimeComponen
const runtimeVersion = value["runtimeVersion"];
const available = value["available"];
const capabilities = parseKnownPiWebCapabilities(value["capabilities"]);
const activeAgentProfileValue = value["activeAgentProfile"];
const activeAgentProfile = activeAgentProfileValue === undefined ? undefined : parseActiveAgentProfileDescriptor(activeAgentProfileValue);
const error = value["error"];
if (component !== "web" && component !== "sessiond") return undefined;
if (typeof label !== "string" || label === "" || typeof available !== "boolean" || capabilities === undefined) return undefined;
if (activeAgentProfileValue !== undefined && (component !== "sessiond" || activeAgentProfile === undefined)) return undefined;
return {
component,
label,
...(typeof runtimeVersion === "string" ? { runtimeVersion } : {}),
available,
capabilities,
...(activeAgentProfile === undefined ? {} : { activeAgentProfile }),
...(typeof error === "string" ? { error } : {}),
};
}