import { z } from "zod"; import { approvalPolicy, capabilityReference } from "./capability-policy"; // Package requirements describe a ceiling. They never grant owner authority. export const skillRequirements = z.strictObject({ network: z.boolean().default(false), workspace: z.enum(["none", "read", "read-write"]).default("none"), externalCapabilities: z .array(capabilityReference) .max(8) .default([]) .refine( (items) => new Set( items.map((item) => JSON.stringify([item.source.kind, item.source.id, item.id]), ), ).size === items.length, "Declare each external capability once", ), }); export type SkillRequirements = z.infer; export const skillPermissionKinds = [ "execute", "network", "workspaceRead", "workspaceWrite", "externalCapabilities", ] as const; export type SkillPermissionKind = (typeof skillPermissionKinds)[number]; export const skillPermissionChoices = z.strictObject({ execute: approvalPolicy, network: approvalPolicy, workspaceRead: approvalPolicy, workspaceWrite: approvalPolicy, externalCapabilities: approvalPolicy, }); export type SkillPermissionChoices = z.infer; export const defaultSkillPermissions: SkillPermissionChoices = { execute: "ask", network: "never", workspaceRead: "never", workspaceWrite: "never", externalCapabilities: "never", }; export const skillPermissionRevision = z .number() .int() .nonnegative() .max(Number.MAX_SAFE_INTEGER - 1); export interface SkillPermissionAudit { revision: number; timestamp: string; before: SkillPermissionChoices; after: SkillPermissionChoices; } export interface SkillPermissionSnapshot { revision: number; choices: SkillPermissionChoices; audit: SkillPermissionAudit[]; } export function requiredSkillPermissions( requirements: SkillRequirements, scripts: readonly string[], ): SkillPermissionKind[] { if (!scripts.length) return []; return [ "execute", ...(requirements.network ? ["network" as const] : []), ...(requirements.workspace !== "none" ? ["workspaceRead" as const] : []), ...(requirements.workspace === "read-write" ? ["workspaceWrite" as const] : []), ...(requirements.externalCapabilities.length ? ["externalCapabilities" as const] : []), ]; }