Revert "feat(skills): add dryRun flag for scan prune path"

This reverts commit 13f0fee7d86334291f6faa2794ba67e9c7e90f35.
This commit is contained in:
2026-04-13 00:36:53 +00:00
parent e739a2d130
commit 6094081a71
8 changed files with 1 additions and 92 deletions
-2
View File
@@ -176,7 +176,6 @@ export type {
CompanySkillProjectScanRequest, CompanySkillProjectScanRequest,
CompanySkillProjectScanSkipped, CompanySkillProjectScanSkipped,
CompanySkillProjectScanConflict, CompanySkillProjectScanConflict,
CompanySkillProjectScanPruned,
CompanySkillProjectScanResult, CompanySkillProjectScanResult,
CompanySkillCreateRequest, CompanySkillCreateRequest,
CompanySkillFileDetail, CompanySkillFileDetail,
@@ -562,7 +561,6 @@ export {
companySkillProjectScanRequestSchema, companySkillProjectScanRequestSchema,
companySkillProjectScanSkippedSchema, companySkillProjectScanSkippedSchema,
companySkillProjectScanConflictSchema, companySkillProjectScanConflictSchema,
companySkillProjectScanPrunedSchema,
companySkillProjectScanResultSchema, companySkillProjectScanResultSchema,
companySkillCreateSchema, companySkillCreateSchema,
companySkillFileDetailSchema, companySkillFileDetailSchema,
@@ -93,7 +93,6 @@ export interface CompanySkillImportResult {
export interface CompanySkillProjectScanRequest { export interface CompanySkillProjectScanRequest {
projectIds?: string[]; projectIds?: string[];
workspaceIds?: string[]; workspaceIds?: string[];
dryRun?: boolean;
} }
export interface CompanySkillProjectScanSkipped { export interface CompanySkillProjectScanSkipped {
@@ -119,14 +118,6 @@ export interface CompanySkillProjectScanConflict {
reason: string; reason: string;
} }
export interface CompanySkillProjectScanPruned {
skillId: string;
slug: string;
key: string;
sourceLocator: string | null;
affectedAgents: string[];
}
export interface CompanySkillProjectScanResult { export interface CompanySkillProjectScanResult {
scannedProjects: number; scannedProjects: number;
scannedWorkspaces: number; scannedWorkspaces: number;
@@ -135,9 +126,7 @@ export interface CompanySkillProjectScanResult {
updated: CompanySkill[]; updated: CompanySkill[];
skipped: CompanySkillProjectScanSkipped[]; skipped: CompanySkillProjectScanSkipped[];
conflicts: CompanySkillProjectScanConflict[]; conflicts: CompanySkillProjectScanConflict[];
pruned: CompanySkillProjectScanPruned[];
warnings: string[]; warnings: string[];
dryRun: boolean;
} }
export interface CompanySkillCreateRequest { export interface CompanySkillCreateRequest {
-1
View File
@@ -28,7 +28,6 @@ export type {
CompanySkillProjectScanRequest, CompanySkillProjectScanRequest,
CompanySkillProjectScanSkipped, CompanySkillProjectScanSkipped,
CompanySkillProjectScanConflict, CompanySkillProjectScanConflict,
CompanySkillProjectScanPruned,
CompanySkillProjectScanResult, CompanySkillProjectScanResult,
CompanySkillCreateRequest, CompanySkillCreateRequest,
CompanySkillFileDetail, CompanySkillFileDetail,
@@ -76,7 +76,6 @@ export const companySkillUpdateAuthSchema = z.object({
export const companySkillProjectScanRequestSchema = z.object({ export const companySkillProjectScanRequestSchema = z.object({
projectIds: z.array(z.string().uuid()).optional(), projectIds: z.array(z.string().uuid()).optional(),
workspaceIds: z.array(z.string().uuid()).optional(), workspaceIds: z.array(z.string().uuid()).optional(),
dryRun: z.boolean().optional(),
}); });
export const companySkillProjectScanSkippedSchema = z.object({ export const companySkillProjectScanSkippedSchema = z.object({
@@ -102,14 +101,6 @@ export const companySkillProjectScanConflictSchema = z.object({
reason: z.string().min(1), reason: z.string().min(1),
}); });
export const companySkillProjectScanPrunedSchema = z.object({
skillId: z.string().uuid(),
slug: z.string().min(1),
key: z.string().min(1),
sourceLocator: z.string().nullable(),
affectedAgents: z.array(z.string()),
});
export const companySkillProjectScanResultSchema = z.object({ export const companySkillProjectScanResultSchema = z.object({
scannedProjects: z.number().int().nonnegative(), scannedProjects: z.number().int().nonnegative(),
scannedWorkspaces: z.number().int().nonnegative(), scannedWorkspaces: z.number().int().nonnegative(),
@@ -118,9 +109,7 @@ export const companySkillProjectScanResultSchema = z.object({
updated: z.array(companySkillSchema), updated: z.array(companySkillSchema),
skipped: z.array(companySkillProjectScanSkippedSchema), skipped: z.array(companySkillProjectScanSkippedSchema),
conflicts: z.array(companySkillProjectScanConflictSchema), conflicts: z.array(companySkillProjectScanConflictSchema),
pruned: z.array(companySkillProjectScanPrunedSchema),
warnings: z.array(z.string()), warnings: z.array(z.string()),
dryRun: z.boolean(),
}); });
export const companySkillCreateSchema = z.object({ export const companySkillCreateSchema = z.object({
-1
View File
@@ -48,7 +48,6 @@ export {
companySkillProjectScanRequestSchema, companySkillProjectScanRequestSchema,
companySkillProjectScanSkippedSchema, companySkillProjectScanSkippedSchema,
companySkillProjectScanConflictSchema, companySkillProjectScanConflictSchema,
companySkillProjectScanPrunedSchema,
companySkillProjectScanResultSchema, companySkillProjectScanResultSchema,
companySkillCreateSchema, companySkillCreateSchema,
companySkillFileDetailSchema, companySkillFileDetailSchema,
@@ -282,46 +282,4 @@ describeEmbeddedPostgres("scanProjectWorkspaces prune path", () => {
]), ]),
); );
}); });
it("reports pruned skills without deleting when dryRun is true", async () => {
stubGitHubSource(["keep-skill"]);
const { companySkillService } = await import("../services/company-skills.js");
const svc = companySkillService(db);
const result = await svc.scanProjectWorkspaces(companyId, { dryRun: true });
// The result should flag dryRun and list what would be pruned
expect(result.dryRun).toBe(true);
expect(result.pruned).toEqual(
expect.arrayContaining([
expect.objectContaining({
slug: "prune-skill",
affectedAgents: expect.arrayContaining(["Builder"]),
}),
]),
);
// No warnings emitted (nothing was actually deleted)
const pruneWarnings = result.warnings.filter((w) => w.includes("prune-skill"));
expect(pruneWarnings).toHaveLength(0);
// Both skills should still exist in the database
const remaining = await db
.select()
.from(companySkills)
.where(eq(companySkills.companyId, companyId));
const remainingSlugs = remaining.map((r) => r.slug);
expect(remainingSlugs).toContain("keep-skill");
expect(remainingSlugs).toContain("prune-skill");
// Agent config should be unchanged
const [agentRow] = await db
.select()
.from(agents)
.where(eq(agents.id, agentId));
const config = agentRow!.adapterConfig as Record<string, unknown>;
const syncConfig = config.paperclipSkillSync as Record<string, unknown>;
const desiredSkills = syncConfig.desiredSkills as string[];
expect(desiredSkills).toContain("test-org/test-skills/prune-skill");
});
}); });
@@ -78,9 +78,7 @@ describe("company skill mutation permissions", () => {
updated: [], updated: [],
skipped: [], skipped: [],
conflicts: [], conflicts: [],
pruned: [],
warnings: [], warnings: [],
dryRun: false,
}); });
mockLogActivity.mockResolvedValue(undefined); mockLogActivity.mockResolvedValue(undefined);
mockAccessService.canUser.mockResolvedValue(true); mockAccessService.canUser.mockResolvedValue(true);
@@ -295,13 +293,9 @@ describe("company skill mutation permissions", () => {
updated: [], updated: [],
skipped: [], skipped: [],
conflicts: [], conflicts: [],
pruned: [
{ skillId: "skill-1", slug: "ghost-skill", key: "vercel-labs/agent-browser/ghost-skill", sourceLocator: "https://github.com/vercel-labs/agent-browser", affectedAgents: ["Builder"] },
],
warnings: [ warnings: [
'Skill "ghost-skill" was removed from https://github.com/vercel-labs/agent-browser and detached from Builder.', 'Skill "ghost-skill" was removed from https://github.com/vercel-labs/agent-browser and detached from Builder.',
], ],
dryRun: false,
}); });
const res = await request(await createApp({ const res = await request(await createApp({
+1 -18
View File
@@ -17,7 +17,6 @@ import type {
CompanySkillImportResult, CompanySkillImportResult,
CompanySkillListItem, CompanySkillListItem,
CompanySkillProjectScanConflict, CompanySkillProjectScanConflict,
CompanySkillProjectScanPruned,
CompanySkillProjectScanRequest, CompanySkillProjectScanRequest,
CompanySkillProjectScanResult, CompanySkillProjectScanResult,
CompanySkillProjectScanSkipped, CompanySkillProjectScanSkipped,
@@ -1861,10 +1860,8 @@ export function companySkillService(db: Db) {
? await projects.listByIds(companyId, input.projectIds) ? await projects.listByIds(companyId, input.projectIds)
: await projects.list(companyId); : await projects.list(companyId);
const workspaceFilter = new Set(input.workspaceIds ?? []); const workspaceFilter = new Set(input.workspaceIds ?? []);
const dryRun = input.dryRun === true;
const skipped: CompanySkillProjectScanSkipped[] = []; const skipped: CompanySkillProjectScanSkipped[] = [];
const conflicts: CompanySkillProjectScanConflict[] = []; const conflicts: CompanySkillProjectScanConflict[] = [];
const pruned: CompanySkillProjectScanPruned[] = [];
const warnings: string[] = []; const warnings: string[] = [];
const imported: CompanySkill[] = []; const imported: CompanySkill[] = [];
const updated: CompanySkill[] = []; const updated: CompanySkill[] = [];
@@ -2046,18 +2043,6 @@ export function companySkillService(db: Db) {
for (const skill of skillsAtSource) { for (const skill of skillsAtSource) {
if (currentSlugs.has(skill.slug)) continue; if (currentSlugs.has(skill.slug)) continue;
const usedByAgents = await usage(companyId, skill.key); const usedByAgents = await usage(companyId, skill.key);
const affectedAgentNames = usedByAgents.map((a) => a.name);
pruned.push({
skillId: skill.id,
slug: skill.slug,
key: skill.key,
sourceLocator: skill.sourceLocator,
affectedAgents: affectedAgentNames,
});
if (dryRun) continue;
if (usedByAgents.length > 0) { if (usedByAgents.length > 0) {
// Detach the skill from all agents that have it, then delete // Detach the skill from all agents that have it, then delete
for (const agent of usedByAgents) { for (const agent of usedByAgents) {
@@ -2074,7 +2059,7 @@ export function companySkillService(db: Db) {
} }
} }
warnings.push( warnings.push(
`Skill "${skill.slug}" was removed from ${sourceLocator} and detached from ${affectedAgentNames.join(", ")}.`, `Skill "${skill.slug}" was removed from ${sourceLocator} and detached from ${usedByAgents.map((a) => a.name).join(", ")}.`,
); );
} else { } else {
warnings.push( warnings.push(
@@ -2097,9 +2082,7 @@ export function companySkillService(db: Db) {
updated, updated,
skipped, skipped,
conflicts, conflicts,
pruned,
warnings, warnings,
dryRun,
}; };
} }