@extenshi/mcp
Version:
Extenshi MCP server — bring the extension catalog (search, security, market research) and pre-publish scanning into your AI tools
111 lines • 6.44 kB
TypeScript
/**
* Extension templates — the "what kind of extension is this?" taxonomy.
*
* A template is not a folder of files to copy. It is a small set of claims
* about the extension's shape: which manifest components it cannot work
* without, which permissions those components force, and which files the
* scaffold has to write so the manifest does not point at something that isn't
* there. Everything downstream — the picker in the manifest generator, the
* locked checkboxes, the scaffolded file set, and (next phase) the MCP tool
* that hands this catalog to a developer's own agent — reads THIS module.
*
* It lives in shared-types rather than in dojo because the readers span
* packages: the website, catalog-bff (answering a developer's own agent), and
* the published `@extenshi/mcp` package, whose tool tells an agent what kinds of
* extension exist and what each costs in permissions. All three must give the
* same answer.
*
* SELF-CONTAINED ON PURPOSE — no imports, so it can be copied verbatim into
* `@extenshi/mcp`, which cannot depend on unpublished workspace packages (same
* constraint and same solution as welcome-agent-brief.ts).
*
* SINGLE SOURCE, TWO COPIES, byte-identical:
* shared-types/extension-templates.ts ← canonical
* tools/extenshi-mcp/src/extension-templates.ts ← copy, pinned by a test
* Edit the canonical file and copy it over; the sync test in the MCP package
* fails on any divergence inside the monorepo and skips in the npm tarball.
*
* Templates COMBINE. A side panel with a content script is one extension with
* two capabilities, not a fifth template — the picker is multi-select and every
* helper here takes a list and unions the result. That is why requirements are
* expressed as components + permissions rather than as whole manifests.
*/
export declare const EXTENSION_TEMPLATE_IDS: readonly ["popup", "sidepanel", "content", "overlay"];
export type ExtensionTemplateId = (typeof EXTENSION_TEMPLATE_IDS)[number];
/**
* The template applied when a project has never picked one.
*
* `popup` is deliberately the same shape the scaffold produced before templates
* existed, so an old project regenerates byte-for-byte what it did yesterday.
*/
export declare const DEFAULT_EXTENSION_TEMPLATE: ExtensionTemplateId;
/**
* Manifest components a template can require.
*
* These are the things the UI can lock: a side-panel extension whose
* `side_panel` key is turned off is not a side-panel extension, it is a broken
* one. Each maps to a group of fields in the manifest draft.
*/
export declare const EXTENSION_TEMPLATE_COMPONENTS: readonly ["action", "sidePanel", "contentScript"];
export type ExtensionTemplateComponent = (typeof EXTENSION_TEMPLATE_COMPONENTS)[number];
/** Where scaffolded source goes, so the manifest and the file writer agree. */
export declare const EXTENSION_TEMPLATE_SOURCE_DIR = "src";
/**
* The background service worker every template gets, template or not.
*
* It is not part of any one template because it carries the integration the
* whole product is built around: `setUninstallURL` must be registered at
* startup, and a template that skipped the background script would silently
* ship an extension that can never report why someone uninstalled it.
*/
export declare const EXTENSION_BACKGROUND_PATH = "src/background.js";
export interface ExtensionTemplate {
id: ExtensionTemplateId;
label: string;
/** One line on the picker card: what this kind of extension is for. */
summary: string;
/** Components locked on while this template is selected. */
requires: readonly ExtensionTemplateComponent[];
/**
* Permissions the manifest cannot drop while this template is selected.
*
* Chromium vocabulary. Firefox reaches the same capability through a
* different manifest key and needs no permission for it (`sidebar_action`
* instead of `sidePanel` + `side_panel`), so a per-browser manifest builder
* is expected to translate rather than to emit these verbatim.
*/
requiredPermissions: readonly string[];
/** Pre-ticked because the template usually needs them — always removable. */
recommendedPermissions: readonly string[];
/** Repo-relative file the required component points at. */
entry: string;
/** Every file the scaffold writes for this template, `entry` included. */
emits: readonly string[];
/** Seed match patterns, for the templates whose component is a content script. */
defaultMatches?: readonly string[];
}
export declare const EXTENSION_TEMPLATE_CATALOG: readonly ExtensionTemplate[];
export declare function isExtensionTemplateId(value: unknown): value is ExtensionTemplateId;
export declare function getExtensionTemplate(id: ExtensionTemplateId): ExtensionTemplate;
/**
* Clean a persisted or client-supplied list into templates we know.
*
* Saved tool state is free-form JSON written by whatever build was live at the
* time, so an unknown id is expected rather than exceptional: it is dropped,
* not thrown on. Order follows the catalog so two projects that picked the same
* set produce the same manifest, and duplicates collapse.
*/
export declare function normalizeExtensionTemplates(value: unknown): ExtensionTemplateId[];
/** The selection to build with: what was picked, or the default when nothing was. */
export declare function effectiveExtensionTemplates(value: unknown): ExtensionTemplateId[];
/** Permissions the selection forces into the manifest (locked in the UI). */
export declare function extensionTemplateRequiredPermissions(ids: readonly ExtensionTemplateId[]): string[];
/** Permissions ticked when a template is picked, minus the ones already forced. */
export declare function extensionTemplateRecommendedPermissions(ids: readonly ExtensionTemplateId[]): string[];
/** Components the selection locks on. */
export declare function extensionTemplateComponents(ids: readonly ExtensionTemplateId[]): ExtensionTemplateComponent[];
/** Templates whose component is a content script, in catalog order. */
export declare function extensionTemplatesWithContentScripts(ids: readonly ExtensionTemplateId[]): ExtensionTemplate[];
/** Every file the scaffold writes for a selection, background script included. */
export declare function extensionTemplateFiles(ids: readonly ExtensionTemplateId[]): string[];
//# sourceMappingURL=extension-templates.d.ts.map