From cd01ebb417f77307875d294a502e51d4b1c627df Mon Sep 17 00:00:00 2001 From: dotta Date: Wed, 18 Mar 2026 15:24:22 -0500 Subject: [PATCH] Add click-to-copy workspace path on Paperclip workspace source label When a skill's source is "Paperclip workspace", clicking the label now copies the absolute path to the managed skills workspace to the clipboard and shows a toast confirmation. - Add sourcePath field to CompanySkillDetail and CompanySkillListItem types - Return managedRoot path as sourcePath from deriveSkillSourceInfo for Paperclip workspace skills - Make source label a clickable button in SkillPane detail view Co-Authored-By: Paperclip --- packages/shared/src/types/company-skill.ts | 2 ++ server/src/services/company-skills.ts | 8 ++++++++ ui/src/pages/CompanySkills.tsx | 16 +++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/types/company-skill.ts b/packages/shared/src/types/company-skill.ts index 917a73ef..5d6ed598 100644 --- a/packages/shared/src/types/company-skill.ts +++ b/packages/shared/src/types/company-skill.ts @@ -50,6 +50,7 @@ export interface CompanySkillListItem { editableReason: string | null; sourceLabel: string | null; sourceBadge: CompanySkillSourceBadge; + sourcePath: string | null; } export interface CompanySkillUsageAgent { @@ -68,6 +69,7 @@ export interface CompanySkillDetail extends CompanySkill { editableReason: string | null; sourceLabel: string | null; sourceBadge: CompanySkillSourceBadge; + sourcePath: string | null; } export interface CompanySkillUpdateStatus { diff --git a/server/src/services/company-skills.ts b/server/src/services/company-skills.ts index 173e9c63..c3b6a5e3 100644 --- a/server/src/services/company-skills.ts +++ b/server/src/services/company-skills.ts @@ -1233,6 +1233,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { editableReason: string | null; sourceLabel: string | null; sourceBadge: CompanySkillSourceBadge; + sourcePath: string | null; } { const metadata = getSkillMeta(skill); const localSkillDir = normalizeSkillDirectory(skill); @@ -1242,6 +1243,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { editableReason: "Bundled Paperclip skills are read-only.", sourceLabel: "Paperclip bundled", sourceBadge: "paperclip", + sourcePath: null, }; } @@ -1253,6 +1255,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { editableReason: "Remote GitHub skills are read-only. Fork or import locally to edit them.", sourceLabel: owner && repo ? `${owner}/${repo}` : skill.sourceLocator, sourceBadge: "github", + sourcePath: null, }; } @@ -1262,6 +1265,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { editableReason: "URL-based skills are read-only. Save them locally to edit them.", sourceLabel: skill.sourceLocator, sourceBadge: "url", + sourcePath: null, }; } @@ -1276,6 +1280,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { editableReason: null, sourceLabel: "Paperclip workspace", sourceBadge: "paperclip", + sourcePath: managedRoot, }; } @@ -1287,6 +1292,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { || skill.sourceLocator : skill.sourceLocator, sourceBadge: "local", + sourcePath: null, }; } @@ -1295,6 +1301,7 @@ function deriveSkillSourceInfo(skill: CompanySkill): { editableReason: "This skill source is read-only.", sourceLabel: skill.sourceLocator, sourceBadge: "catalog", + sourcePath: null, }; } @@ -1330,6 +1337,7 @@ function toCompanySkillListItem(skill: CompanySkill, attachedAgentCount: number) editableReason: source.editableReason, sourceLabel: source.sourceLabel, sourceBadge: source.sourceBadge, + sourcePath: source.sourcePath, }; } diff --git a/ui/src/pages/CompanySkills.tsx b/ui/src/pages/CompanySkills.tsx index 193c9721..afeeb01f 100644 --- a/ui/src/pages/CompanySkills.tsx +++ b/ui/src/pages/CompanySkills.tsx @@ -523,6 +523,8 @@ function SkillPane({ onSave: () => void; savePending: boolean; }) { + const { pushToast } = useToast(); + if (!detail) { if (loading) { return ; @@ -574,7 +576,19 @@ function SkillPane({ Source - {source.label} + {detail.sourcePath ? ( + + ) : ( + {source.label} + )} {detail.sourceType === "github" && (