init
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { getSettingsForSource } from './settings.js'
|
||||
import type { CUSTOMIZATION_SURFACES } from './types.js'
|
||||
|
||||
export type CustomizationSurface = (typeof CUSTOMIZATION_SURFACES)[number]
|
||||
|
||||
/**
|
||||
* Check whether a customization surface is locked to plugin-only sources
|
||||
* by the managed `strictPluginOnlyCustomization` policy.
|
||||
*
|
||||
* "Locked" means user-level (~/.claude/*) and project-level (.claude/*)
|
||||
* sources are skipped for that surface. Managed (policySettings) and
|
||||
* plugin-provided sources always load regardless — the policy is admin-set,
|
||||
* so managed sources are already admin-controlled, and plugins are gated
|
||||
* separately via `strictKnownMarketplaces`.
|
||||
*
|
||||
* `true` locks all four surfaces; array form locks only those listed.
|
||||
* Absent/undefined → nothing locked (the default).
|
||||
*/
|
||||
export function isRestrictedToPluginOnly(
|
||||
surface: CustomizationSurface,
|
||||
): boolean {
|
||||
const policy =
|
||||
getSettingsForSource('policySettings')?.strictPluginOnlyCustomization
|
||||
if (policy === true) return true
|
||||
if (Array.isArray(policy)) return policy.includes(surface)
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Sources that bypass strictPluginOnlyCustomization. Admin-trusted because:
|
||||
* plugin — gated separately by strictKnownMarketplaces
|
||||
* policySettings — from managed settings, admin-controlled by definition
|
||||
* built-in / builtin / bundled — ship with the CLI, not user-authored
|
||||
*
|
||||
* Everything else (userSettings, projectSettings, localSettings, flagSettings,
|
||||
* mcp, undefined) is user-controlled and blocked when the relevant surface
|
||||
* is locked. Covers both AgentDefinition.source ('built-in' with hyphen) and
|
||||
* Command.source ('builtin' no hyphen, plus 'bundled').
|
||||
*/
|
||||
const ADMIN_TRUSTED_SOURCES: ReadonlySet<string> = new Set([
|
||||
'plugin',
|
||||
'policySettings',
|
||||
'built-in',
|
||||
'builtin',
|
||||
'bundled',
|
||||
])
|
||||
|
||||
/**
|
||||
* Whether a customization's source is admin-trusted under
|
||||
* strictPluginOnlyCustomization. Use this to gate frontmatter-hook
|
||||
* registration and similar per-item checks where the item carries a
|
||||
* source tag but the surface's filesystem loader already ran.
|
||||
*
|
||||
* Pattern at call sites:
|
||||
* const allowed = !isRestrictedToPluginOnly(surface) || isSourceAdminTrusted(item.source)
|
||||
* if (item.hooks && allowed) { register(...) }
|
||||
*/
|
||||
export function isSourceAdminTrusted(source: string | undefined): boolean {
|
||||
return source !== undefined && ADMIN_TRUSTED_SOURCES.has(source)
|
||||
}
|
||||
Reference in New Issue
Block a user