import { createHash } from "node:crypto"; import { existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, realpathSync, statSync, symlinkSync, } from "node:fs"; import { basename, isAbsolute, join, relative, resolve, sep, win32, } from "node:path"; import { tmpdir } from "node:os"; export type SkillPackageStatus = "active" | "deprecated" | "blocked"; export interface SkillPackageIdentity { name: string; version: string; sha256: string; sourceCommit: string | null; packagePath: string; status: SkillPackageStatus; } export type ResolvedSkillPackageIdentity = SkillPackageIdentity & { resolvedPath: string; }; export interface SkillPackageRegistryOptions { projectRoot?: string; registryPath?: string; } interface SkillPackageRegistryDocument { schemaVersion?: number; packages: SkillPackageIdentity[]; } const SHA256_PATTERN = /^[0-9a-f]{64}$/; const GIT_COMMIT_PATTERN = /^[0-9a-f]{40}$/; const NAME_PATTERN = /^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/; const VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/; const STATUS_VALUES = new Set([ "active", "deprecated", "blocked", ]); const IDENTITY_KEYS = new Set([ "name", "version", "sha256", "sourceCommit", "packagePath", "status", ]); const DEFAULT_REGISTRY_PATH = "skills/skill-package-registry.json"; const SOURCE_TREE_PROJECT_ROOT = process.env.JYOTISHA_PROJECT_ROOT ?? (existsSync(resolve(process.cwd(), DEFAULT_REGISTRY_PATH)) ? process.cwd() : resolve(process.cwd(), "..")); const PACKAGE_HASH_DOMAIN = "jyotisha-skill-package-v1\0"; const RUNTIME_SKILL_ROOT = mkdtempSync(join(tmpdir(), "jyotisha-skill-runtime-")); export class SkillPackageRegistryError extends Error { constructor(message: string) { super(message); this.name = "SkillPackageRegistryError"; } } function fail(message: string): never { throw new SkillPackageRegistryError(message); } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function assertString( value: unknown, field: keyof SkillPackageIdentity, index: number, ): string { if (typeof value !== "string" || value.length === 0) { return fail(`Registry package ${index} has invalid or missing ${field}`); } return value; } function validatePackagePath(packagePath: string, index: number): void { if ( packagePath.includes("\0") || packagePath.includes("\\") || isAbsolute(packagePath) || win32.isAbsolute(packagePath) ) { fail(`Registry package ${index} has an unsafe packagePath`); } const segments = packagePath.split("/"); if ( segments.length === 0 || segments.some( (segment) => segment === "" || segment === "." || segment === "..", ) ) { fail(`Registry package ${index} has an unsafe packagePath`); } } function parseIdentity(value: unknown, index: number): SkillPackageIdentity { if (!isRecord(value)) { return fail(`Registry package ${index} must be an object`); } const unknownKeys = Object.keys(value).filter((key) => !IDENTITY_KEYS.has(key)); if (unknownKeys.length > 0) { fail( `Registry package ${index} contains unknown fields: ${unknownKeys.join(", ")}`, ); } const name = assertString(value.name, "name", index); const version = assertString(value.version, "version", index); const sha256 = assertString(value.sha256, "sha256", index); const sourceCommit = value.sourceCommit === null ? null : assertString(value.sourceCommit, "sourceCommit", index); const packagePath = assertString(value.packagePath, "packagePath", index); const status = assertString(value.status, "status", index); if (!NAME_PATTERN.test(name)) { fail(`Registry package ${index} has an invalid name`); } if (!VERSION_PATTERN.test(version)) { fail(`Registry package ${index} has an invalid version`); } if (!SHA256_PATTERN.test(sha256)) { fail(`Registry package ${index} has an invalid sha256`); } if (sourceCommit !== null && !GIT_COMMIT_PATTERN.test(sourceCommit)) { fail(`Registry package ${index} has an invalid sourceCommit`); } validatePackagePath(packagePath, index); if (!STATUS_VALUES.has(status as SkillPackageStatus)) { fail(`Registry package ${index} has an invalid status`); } return Object.freeze({ name, version, sha256, sourceCommit, packagePath, status: status as SkillPackageStatus, }); } function parseRegistry(contents: string): SkillPackageRegistryDocument { let value: unknown; try { value = JSON.parse(contents); } catch (error) { fail( `Skill package registry is not valid JSON: ${ error instanceof Error ? error.message : "unknown parse error" }`, ); } if (!isRecord(value) || !Array.isArray(value.packages)) { return fail("Skill package registry must contain a packages array"); } if (value.schemaVersion !== undefined && value.schemaVersion !== 1) { fail("Skill package registry has an unsupported schemaVersion"); } const packages = value.packages.map(parseIdentity); const exactIdentities = new Set(); const activeNames = new Set(); for (const identity of packages) { const exactKey = `${identity.name}\0${identity.version}\0${identity.sha256}`; if (exactIdentities.has(exactKey)) { fail( `Registry contains duplicate identity ${identity.name}@${identity.version}#${identity.sha256}`, ); } exactIdentities.add(exactKey); if (identity.status === "active") { if (activeNames.has(identity.name)) { fail(`Registry contains duplicate active package ${identity.name}`); } activeNames.add(identity.name); } } return { schemaVersion: value.schemaVersion as number | undefined, packages }; } function isInside(rootPath: string, candidatePath: string): boolean { const relativePath = relative(rootPath, candidatePath); return ( relativePath === "" || (!relativePath.startsWith(`..${sep}`) && relativePath !== ".." && !isAbsolute(relativePath)) ); } function resolveExistingPath(pathValue: string, label: string): string { try { return realpathSync(pathValue); } catch (error) { return fail( `${label} does not exist or cannot be resolved: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } } function assertDirectory(pathValue: string, label: string): void { let stats; try { stats = statSync(pathValue); } catch (error) { fail( `${label} cannot be inspected: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } if (!stats.isDirectory()) { fail(`${label} must be a directory`); } } function assertRegularFile(pathValue: string, label: string): void { let stats; try { stats = statSync(pathValue); } catch (error) { fail( `${label} cannot be inspected: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } if (!stats.isFile()) { fail(`${label} must be a regular file`); } } function comparePathNames(left: string, right: string): number { if (left === right) return 0; return left < right ? -1 : 1; } function updateLengthPrefixed( hash: ReturnType, label: string, value: string | Buffer, ): void { const bytes = typeof value === "string" ? Buffer.from(value, "utf8") : value; hash.update(`${label}:${bytes.length}\0`, "utf8"); hash.update(bytes); hash.update("\0", "utf8"); } /** * Hash the complete immutable package tree, not just SKILL.md. Paths, * executable bits, and file bytes are framed deterministically so references, * scripts, and assets are part of the runtime identity. */ export function computeSkillPackageSha256(packageDirectory: string): string { const resolvedDirectory = resolveExistingPath( resolve(packageDirectory), "Skill package directory", ); assertDirectory(resolvedDirectory, "Skill package directory"); const hash = createHash("sha256"); hash.update(PACKAGE_HASH_DOMAIN, "utf8"); let fileCount = 0; const visit = (directory: string, relativeDirectory: string): void => { let entries; try { entries = readdirSync(directory, { withFileTypes: true }); } catch (error) { fail( `Skill package directory cannot be read: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } entries.sort((left, right) => comparePathNames(left.name, right.name)); for (const entry of entries) { const absolutePath = resolve(directory, entry.name); const relativePath = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name; let stats; try { stats = lstatSync(absolutePath); } catch (error) { fail( `Skill package entry ${relativePath} cannot be inspected: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } if (stats.isSymbolicLink()) { fail(`Skill package entry ${relativePath} must not be a symbolic link`); } if (stats.isDirectory()) { visit(absolutePath, relativePath); continue; } if (!stats.isFile()) { fail(`Skill package entry ${relativePath} must be a regular file`); } let bytes: Buffer; try { bytes = readFileSync(absolutePath); } catch (error) { fail( `Skill package entry ${relativePath} cannot be read: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } updateLengthPrefixed(hash, "path", relativePath); updateLengthPrefixed(hash, "executable", stats.mode & 0o111 ? "1" : "0"); updateLengthPrefixed(hash, "bytes", bytes); fileCount += 1; } }; visit(resolvedDirectory, ""); if (fileCount === 0) { fail("Skill package directory must contain at least one regular file"); } return hash.digest("hex"); } function normalizeLookupName(name: string): string { if (!NAME_PATTERN.test(name)) { fail("Skill package name is invalid"); } return name; } function normalizeLookupVersion(version: string): string { if (!VERSION_PATTERN.test(version)) { fail("Skill package version is invalid"); } return version; } function normalizeLookupHash(sha256: string): string { if (!SHA256_PATTERN.test(sha256)) { fail("Skill package sha256 is invalid"); } return sha256; } export class SkillPackageRegistry { readonly projectRoot: string; readonly registryPath: string; constructor(options: SkillPackageRegistryOptions = {}) { const requestedProjectRoot = resolve( options.projectRoot ?? process.env.JYOTISHA_PROJECT_ROOT ?? SOURCE_TREE_PROJECT_ROOT, ); this.projectRoot = resolveExistingPath( requestedProjectRoot, "Skill registry project root", ); assertDirectory(this.projectRoot, "Skill registry project root"); const requestedRegistryPath = options.registryPath ? isAbsolute(options.registryPath) ? resolve(options.registryPath) : resolve(this.projectRoot, options.registryPath) : resolve(this.projectRoot, DEFAULT_REGISTRY_PATH); const registryPath = resolveExistingPath( requestedRegistryPath, "Skill package registry", ); if (!isInside(this.projectRoot, registryPath)) { fail("Skill package registry escapes the project root"); } assertRegularFile(registryPath, "Skill package registry"); this.registryPath = registryPath; } resolveActiveSkillPackage(name: string): ResolvedSkillPackageIdentity { return this.resolveActive(name); } resolveActive(name: string): ResolvedSkillPackageIdentity { const normalizedName = normalizeLookupName(name); const registry = this.loadRegistry(); const identity = registry.packages.find( (candidate) => candidate.name === normalizedName && candidate.status === "active", ); if (!identity) { return fail(`No active skill package found for ${normalizedName}`); } return this.verifyIdentity(identity); } resolveExactSkillPackage( name: string, version: string, sha256: string, ): ResolvedSkillPackageIdentity { return this.resolveExact(name, version, sha256); } resolveExact( name: string, version: string, sha256: string, ): ResolvedSkillPackageIdentity { const normalizedName = normalizeLookupName(name); const normalizedVersion = normalizeLookupVersion(version); const normalizedHash = normalizeLookupHash(sha256); const registry = this.loadRegistry(); const identity = registry.packages.find( (candidate) => candidate.name === normalizedName && candidate.version === normalizedVersion && candidate.sha256 === normalizedHash, ); if (!identity) { return fail( `No exact skill package found for ${normalizedName}@${normalizedVersion}#${normalizedHash}`, ); } if (identity.status === "blocked") { return fail( `Skill package ${normalizedName}@${normalizedVersion} is blocked`, ); } return this.verifyIdentity(identity); } resolveSkillPackageVersion( name: string, version: string, ): ResolvedSkillPackageIdentity { return this.resolveVersion(name, version); } resolveVersion(name: string, version: string): ResolvedSkillPackageIdentity { const normalizedName = normalizeLookupName(name); const normalizedVersion = normalizeLookupVersion(version); const registry = this.loadRegistry(); const matches = registry.packages.filter( (candidate) => candidate.name === normalizedName && candidate.version === normalizedVersion, ); if (matches.length !== 1) { return fail( `Expected one registry identity for ${normalizedName}@${normalizedVersion}, found ${matches.length}`, ); } const [identity] = matches; if (identity.status === "blocked") { return fail( `Skill package ${normalizedName}@${normalizedVersion} is blocked`, ); } return this.verifyIdentity(identity); } verifyAllActiveSkillPackages(): readonly ResolvedSkillPackageIdentity[] { return this.verifyAllActive(); } verifyAllActive(): readonly ResolvedSkillPackageIdentity[] { const registry = this.loadRegistry(); return Object.freeze( registry.packages .filter((identity) => identity.status === "active") .map((identity) => this.verifyIdentity(identity)), ); } private loadRegistry(): SkillPackageRegistryDocument { const currentRegistryPath = resolveExistingPath( this.registryPath, "Skill package registry", ); if (!isInside(this.projectRoot, currentRegistryPath)) { return fail("Skill package registry escapes the project root"); } assertRegularFile(currentRegistryPath, "Skill package registry"); let contents: string; try { contents = readFileSync(currentRegistryPath, "utf8"); } catch (error) { return fail( `Skill package registry cannot be read: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } return parseRegistry(contents); } private verifyIdentity( identity: SkillPackageIdentity, ): ResolvedSkillPackageIdentity { const requestedPackagePath = resolve( this.projectRoot, identity.packagePath, ); if (!isInside(this.projectRoot, requestedPackagePath)) { return fail( `Skill package ${identity.name}@${identity.version} escapes the project root`, ); } const packageDirectory = resolveExistingPath( requestedPackagePath, `Skill package directory ${identity.packagePath}`, ); if (!isInside(this.projectRoot, packageDirectory)) { return fail( `Skill package ${identity.name}@${identity.version} resolves outside the project root`, ); } assertDirectory( packageDirectory, `Skill package directory ${identity.packagePath}`, ); if (packageDirectory !== requestedPackagePath) { return fail( `Skill package ${identity.name}@${identity.version} path must not contain symbolic links`, ); } const requestedSkillPath = resolve(packageDirectory, "SKILL.md"); const skillPath = resolveExistingPath( requestedSkillPath, `SKILL.md for ${identity.name}@${identity.version}`, ); if (!isInside(this.projectRoot, skillPath)) { return fail( `SKILL.md for ${identity.name}@${identity.version} resolves outside the project root`, ); } assertRegularFile( skillPath, `SKILL.md for ${identity.name}@${identity.version}`, ); const actualHash = computeSkillPackageSha256(packageDirectory); if (actualHash !== identity.sha256) { return fail( `SHA-256 mismatch for ${identity.name}@${identity.version}: expected ${identity.sha256}, got ${actualHash}`, ); } return Object.freeze({ ...identity, resolvedPath: packageDirectory }); } } export const LIVE_JYOTISH_SKILL_NAME = "jyotish-vedic-astrology"; export type LiveJyotishSkill = { name: typeof LIVE_JYOTISH_SKILL_NAME; version: string; resolvedPath: string; }; function parseSkillFrontmatter(raw: string): { name?: string; version?: string } { const block = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw); if (!block) return {}; const name = /^name:\s*["']?([a-z0-9](?:[a-z0-9._-]*[a-z0-9])?)["']?\s*$/im.exec(block[1]); const version = /^version:\s*["']?([^\s"']+)["']?\s*$/im.exec(block[1]); return { ...(name ? { name: name[1] } : {}), ...(version ? { version: version[1] } : {}), }; } function resolveSkillProjectRoot(options: SkillPackageRegistryOptions = {}): string { const requestedProjectRoot = resolve( options.projectRoot ?? process.env.JYOTISHA_PROJECT_ROOT ?? SOURCE_TREE_PROJECT_ROOT, ); const projectRoot = resolveExistingPath( requestedProjectRoot, "Skill registry project root", ); assertDirectory(projectRoot, "Skill registry project root"); return projectRoot; } const LIVE_SKILL_RUNTIME_ENTRIES = [ "SKILL.md", "references", "scripts", "assets", ] as const; export type LiveJyotishSkillOptions = SkillPackageRegistryOptions & { /** Overrides `JYOTISH_SKILL_PATH` when tests or callers pass an explicit tree. */ skillPath?: string; }; /** * The natal consult skill is the live tree the operator updates by hand. * It is not a hashed registry package: copy SKILL.md / references / scripts * and restart, without bumping a version or recomputing sha256. */ export function resolveLiveJyotishSkill( options: LiveJyotishSkillOptions = {}, ): LiveJyotishSkill { const projectRoot = resolveSkillProjectRoot(options); const configured = options.skillPath?.trim() || process.env.JYOTISH_SKILL_PATH?.trim(); const requested = configured ? (isAbsolute(configured) ? resolve(configured) : resolve(projectRoot, configured)) : resolve(projectRoot, "skills", LIVE_JYOTISH_SKILL_NAME); if (!isInside(projectRoot, requested)) { let realRequested: string; try { realRequested = realpathSync(requested); } catch { fail("Live Jyotish skill path escapes the project root"); } if (!isInside(projectRoot, realRequested)) { fail("Live Jyotish skill path escapes the project root"); } } const resolvedPath = resolveExistingPath(requested, "Live Jyotish skill directory"); if (!isInside(projectRoot, resolvedPath)) { fail("Live Jyotish skill directory resolves outside the project root"); } assertDirectory(resolvedPath, "Live Jyotish skill directory"); if (basename(resolvedPath) !== LIVE_JYOTISH_SKILL_NAME) { fail(`Live Jyotish skill directory must be named ${LIVE_JYOTISH_SKILL_NAME}`); } const skillPath = resolve(resolvedPath, "SKILL.md"); const skillFile = resolveExistingPath(skillPath, `SKILL.md for ${LIVE_JYOTISH_SKILL_NAME}`); if (!isInside(projectRoot, skillFile)) { fail(`SKILL.md for ${LIVE_JYOTISH_SKILL_NAME} resolves outside the project root`); } let raw: string; try { raw = readFileSync(skillFile, "utf8"); } catch (error) { fail( `SKILL.md for ${LIVE_JYOTISH_SKILL_NAME} cannot be read: ${ error instanceof Error ? error.message : "unknown filesystem error" }`, ); } const frontmatter = parseSkillFrontmatter(raw); if (frontmatter.name && frontmatter.name !== LIVE_JYOTISH_SKILL_NAME) { fail( `Live Jyotish skill frontmatter name must be ${LIVE_JYOTISH_SKILL_NAME}`, ); } for (const name of LIVE_SKILL_RUNTIME_ENTRIES) { const entry = resolve(resolvedPath, name); if (!existsSync(entry)) continue; const real = resolveExistingPath(entry, `Live Jyotish skill ${name}`); if (!isInside(projectRoot, real)) { fail(`Live Jyotish skill ${name} resolves outside the project root`); } } return Object.freeze({ name: LIVE_JYOTISH_SKILL_NAME, version: frontmatter.version || "live", resolvedPath, }); } /** * Mastra-compatible view of the live consult skill. * * The git-tracked live directory also contains leftover hashed * `versions/` snapshots. Those must not be on the loader path: Mastra walks * every real subdirectory, and the operator's updates live in the four * top-level entries (often git-tracked symlinks into the repo root). */ export function resolveLiveJyotishSkillRuntimePath( skill: LiveJyotishSkill, ): string { const token = createHash("sha256").update(skill.resolvedPath).digest("hex").slice(0, 12); const runtimeParent = join(RUNTIME_SKILL_ROOT, "live", token); mkdirSync(runtimeParent, { recursive: true }); const runtimePath = join(runtimeParent, skill.name); if (basename(runtimePath) !== skill.name) { fail(`Live runtime skill path must end with ${skill.name}`); } mkdirSync(runtimePath, { recursive: true }); for (const name of LIVE_SKILL_RUNTIME_ENTRIES) { const source = resolve(skill.resolvedPath, name); if (!existsSync(source)) continue; const target = resolveExistingPath(source, `Live Jyotish skill ${name}`); const dest = join(runtimePath, name); try { const existing = lstatSync(dest); if (!existing.isSymbolicLink()) { fail(`Live runtime entry ${name} is not a symbolic-link alias`); } const linked = resolveExistingPath(dest, `Live runtime alias for ${name}`); if (linked !== target) { fail(`Live runtime entry ${name} points at an unexpected path`); } } catch (error) { if (error instanceof SkillPackageRegistryError) throw error; try { const linkType = statSync(target).isDirectory() ? "dir" : "file"; symlinkSync(target, dest, linkType); } catch (linkError) { fail( `Live runtime alias for ${name} could not be created: ${ linkError instanceof Error ? linkError.message : "unknown filesystem error" }`, ); } } } return runtimePath; } /** * Return a Mastra-compatible read-only alias for a verified package. * * Mastra validates that the configured skill directory basename matches the * frontmatter name. Versioned registry packages intentionally live under a * numeric directory (for example, `versions/10.0.2`), so loading that * directory directly fails validation. The alias keeps the verified package * bytes and identity unchanged while exposing the canonical skill name at the * loader boundary. */ export function resolveSkillPackageRuntimePath( skillPackage: ResolvedSkillPackageIdentity, ): string { const packageDirectory = resolveExistingPath( skillPackage.resolvedPath, `Skill package directory ${skillPackage.packagePath}`, ); assertDirectory( packageDirectory, `Skill package directory ${skillPackage.packagePath}`, ); const actualHash = computeSkillPackageSha256(packageDirectory); if (actualHash !== skillPackage.sha256) { return fail( `SHA-256 mismatch before runtime loading for ${skillPackage.name}@${skillPackage.version}: expected ${skillPackage.sha256}, got ${actualHash}`, ); } const runtimeParent = join(RUNTIME_SKILL_ROOT, skillPackage.sha256); mkdirSync(runtimeParent, { recursive: true }); const runtimePath = join(runtimeParent, skillPackage.name); if (basename(runtimePath) !== skillPackage.name) { return fail( `Runtime skill path must end with the canonical skill name ${skillPackage.name}`, ); } try { const runtimeEntry = lstatSync(runtimePath); if (!runtimeEntry.isSymbolicLink()) { return fail(`Runtime skill path is not a symbolic-link alias: ${runtimePath}`); } const linkedTarget = resolveExistingPath( runtimePath, `Runtime skill alias for ${skillPackage.name}@${skillPackage.version}`, ); if (linkedTarget !== packageDirectory) { return fail( `Runtime skill alias for ${skillPackage.name} points to an unexpected package`, ); } } catch (error) { if (error instanceof SkillPackageRegistryError) throw error; try { symlinkSync(packageDirectory, runtimePath, "dir"); } catch (linkError) { return fail( `Runtime skill alias for ${skillPackage.name}@${skillPackage.version} could not be created: ${ linkError instanceof Error ? linkError.message : "unknown filesystem error" }`, ); } } return runtimePath; } export function createSkillPackageRegistry( options: SkillPackageRegistryOptions = {}, ): SkillPackageRegistry { return new SkillPackageRegistry(options); } export function resolveActiveSkillPackage( name: string, options?: SkillPackageRegistryOptions, ): ResolvedSkillPackageIdentity { return createSkillPackageRegistry(options).resolveActiveSkillPackage(name); } export function resolveActive( name: string, options?: SkillPackageRegistryOptions, ): ResolvedSkillPackageIdentity { return createSkillPackageRegistry(options).resolveActive(name); } export function resolveExactSkillPackage( name: string, version: string, sha256: string, options?: SkillPackageRegistryOptions, ): ResolvedSkillPackageIdentity { return createSkillPackageRegistry(options).resolveExactSkillPackage( name, version, sha256, ); } export function resolveExact( name: string, version: string, sha256: string, options?: SkillPackageRegistryOptions, ): ResolvedSkillPackageIdentity { return createSkillPackageRegistry(options).resolveExact(name, version, sha256); } export function resolveSkillPackageVersion( name: string, version: string, options?: SkillPackageRegistryOptions, ): ResolvedSkillPackageIdentity { return createSkillPackageRegistry(options).resolveSkillPackageVersion( name, version, ); } export function verifyAllActiveSkillPackages( options?: SkillPackageRegistryOptions, ): readonly ResolvedSkillPackageIdentity[] { return createSkillPackageRegistry(options).verifyAllActiveSkillPackages(); } export function verifyAllActive( options?: SkillPackageRegistryOptions, ): readonly ResolvedSkillPackageIdentity[] { return createSkillPackageRegistry(options).verifyAllActive(); }