Manage orchestration skills per host (#3451)
* feat(skills): manage orchestration skills per host Agent skills execute on the daemon host, so their bundle, selection, and filesystem convergence must share that owner. Preserve the existing install semantics while letting every capable client manage the selected host and migrating the legacy desktop preference once. * fix(client): keep skill management internal Keep host skill management on the low-level daemon client used by the app. Do not expose daemon settings or the desktop-only compatibility migration through the shared Paseo API handed to plugins. * fix(e2e): declare skills fixture dependencies Use Playwright's required destructuring form for the test-scoped daemon sandbox fixture so CI can collect the real-host skills suite. * test(skills): use native managed paths Assert fixed skill targets relative to the daemon user's real home with platform-native path joining so the ownership contract holds on Windows and POSIX hosts.
This commit is contained in:
@@ -105,6 +105,9 @@ import type {
|
||||
WorkspaceRecoveryState,
|
||||
PluginListItem,
|
||||
PluginLogEntry,
|
||||
AgentSkillSelection,
|
||||
AgentSkillsStatus,
|
||||
AgentSkillsSaveResult,
|
||||
} from "@getpaseo/protocol/messages";
|
||||
import type {
|
||||
AgentPermissionRequest,
|
||||
@@ -4766,6 +4769,61 @@ export class DaemonClient {
|
||||
return payload.entries;
|
||||
}
|
||||
|
||||
async getAgentSkillsStatus(): Promise<AgentSkillsStatus> {
|
||||
const requestId = this.createRequestId();
|
||||
return this.sendCorrelatedSessionRequest({
|
||||
message: { type: "agent.skills.get_status.request", requestId },
|
||||
responseType: "agent.skills.get_status.response",
|
||||
});
|
||||
}
|
||||
|
||||
async reconcileAgentSkills(): Promise<AgentSkillsStatus> {
|
||||
const requestId = this.createRequestId();
|
||||
return this.sendCorrelatedSessionRequest({
|
||||
message: { type: "agent.skills.reconcile.request", requestId },
|
||||
responseType: "agent.skills.reconcile.response",
|
||||
});
|
||||
}
|
||||
|
||||
async uninstallAgentSkills(): Promise<AgentSkillsStatus> {
|
||||
const requestId = this.createRequestId();
|
||||
return this.sendCorrelatedSessionRequest({
|
||||
message: { type: "agent.skills.uninstall.request", requestId },
|
||||
responseType: "agent.skills.uninstall.response",
|
||||
});
|
||||
}
|
||||
|
||||
async saveAgentSkillsSelection(
|
||||
selection: AgentSkillSelection,
|
||||
confirmedRemovals?: readonly string[],
|
||||
): Promise<AgentSkillsSaveResult> {
|
||||
const requestId = this.createRequestId();
|
||||
return this.sendCorrelatedSessionRequest({
|
||||
message: {
|
||||
type: "agent.skills.save_selection.request",
|
||||
requestId,
|
||||
selection,
|
||||
...(confirmedRemovals ? { confirmedRemovals: [...confirmedRemovals] } : {}),
|
||||
},
|
||||
responseType: "agent.skills.save_selection.response",
|
||||
});
|
||||
}
|
||||
|
||||
async importLegacyAgentSkillsSelection(selection: AgentSkillSelection): Promise<{
|
||||
imported: boolean;
|
||||
selection: AgentSkillSelection;
|
||||
}> {
|
||||
const requestId = this.createRequestId();
|
||||
return this.sendCorrelatedSessionRequest({
|
||||
message: {
|
||||
type: "agent.skills.import_legacy_selection.request",
|
||||
requestId,
|
||||
selection,
|
||||
},
|
||||
responseType: "agent.skills.import_legacy_selection.response",
|
||||
});
|
||||
}
|
||||
|
||||
async installDirectoryPlugin(path: string, id?: string): Promise<PluginListItem> {
|
||||
const requestId = this.createRequestId();
|
||||
const payload = await this.sendCorrelatedSessionRequest({
|
||||
|
||||
@@ -227,6 +227,7 @@ test("createPaseoApi borrows daemon capabilities without exposing connection own
|
||||
expect(Object.keys(paseo).sort()).toEqual(["agents", "config", "providers", "workspaces"]);
|
||||
expect("connect" in paseo).toBe(false);
|
||||
expect("close" in paseo).toBe(false);
|
||||
expect("skills" in paseo.agents).toBe(false);
|
||||
});
|
||||
|
||||
test("agent actions list the daemon directory without exposing the low-level client", async () => {
|
||||
|
||||
Reference in New Issue
Block a user