Add unmanaged skill provenance to agent skills
Expose adapter-discovered user-installed skills with provenance metadata, share persistent skill snapshot classification across local adapters, and render unmanaged skills as a read-only section in the agent skills UI. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyAgentSkillSnapshot } from "./agent-skills-state";
|
||||
import { applyAgentSkillSnapshot, isReadOnlyUnmanagedSkillEntry } from "./agent-skills-state";
|
||||
|
||||
describe("applyAgentSkillSnapshot", () => {
|
||||
it("hydrates the initial snapshot without arming autosave", () => {
|
||||
@@ -55,4 +55,36 @@ describe("applyAgentSkillSnapshot", () => {
|
||||
shouldSkipAutosave: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("treats user-installed entries outside the company library as read-only unmanaged skills", () => {
|
||||
expect(isReadOnlyUnmanagedSkillEntry({
|
||||
key: "crack-python",
|
||||
runtimeName: "crack-python",
|
||||
desired: false,
|
||||
managed: false,
|
||||
state: "external",
|
||||
origin: "user_installed",
|
||||
}, new Set(["paperclip"]))).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps company-library entries in the managed section even when the adapter reports an external conflict", () => {
|
||||
expect(isReadOnlyUnmanagedSkillEntry({
|
||||
key: "paperclip",
|
||||
runtimeName: "paperclip",
|
||||
desired: true,
|
||||
managed: false,
|
||||
state: "external",
|
||||
origin: "company_managed",
|
||||
}, new Set(["paperclip"]))).toBe(false);
|
||||
});
|
||||
|
||||
it("falls back to legacy snapshots that only mark unmanaged external entries", () => {
|
||||
expect(isReadOnlyUnmanagedSkillEntry({
|
||||
key: "legacy-external",
|
||||
runtimeName: "legacy-external",
|
||||
desired: false,
|
||||
managed: false,
|
||||
state: "external",
|
||||
}, new Set())).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { AgentSkillEntry } from "@paperclipai/shared";
|
||||
|
||||
export interface AgentSkillDraftState {
|
||||
draft: string[];
|
||||
lastSaved: string[];
|
||||
@@ -27,3 +29,12 @@ export function applyAgentSkillSnapshot(
|
||||
shouldSkipAutosave: shouldReplaceDraft,
|
||||
};
|
||||
}
|
||||
|
||||
export function isReadOnlyUnmanagedSkillEntry(
|
||||
entry: AgentSkillEntry,
|
||||
companySkillKeys: Set<string>,
|
||||
): boolean {
|
||||
if (companySkillKeys.has(entry.key)) return false;
|
||||
if (entry.origin === "user_installed" || entry.origin === "external_unknown") return true;
|
||||
return entry.managed === false && entry.state === "external";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user