/** * Single source of truth for skill.json shape + validation. * * Imported directly by `registry.ts` (runtime loader) and — via the compiled * `dist/skill-schema.js` — by `scripts/build-manifest.mjs` and `scripts/smoke.mjs`. * Previously each of those reimplemented `normalizeEntry` and its own subset of * field checks, so "valid at build" ≠ "loadable at runtime". Centralizing here * means one definition of a well-formed skill. * * Error policy is the caller's choice: `validateSkillJson` returns a list of * human-readable problems (empty = OK). The runtime loader skips + warns; * the build treats them as fatal. */ export type SkillEntry = { type: 'python'; scriptPath: string; } | { type: 'http'; handler: string; } | { type: 'builtin'; handler: string; }; /** * Skill 类别 — 区分"创作期 / 消费期 / 元数据型" skill。 * * - "authoring": 创建 / 编辑模板期间使用,例如 template-registry / gen-script / * render-video(用于 try_render) / prepare-video-assets。 * - "consuming": 消费已有模板生成媒体,例如 export-jianying / video-parser / * web-screenshot / web-record(与"创建模板"无关,是消费侧场景)。 * - "asset": 生成单一类型素材的原子 skill:gen-image / gen-voice / * gen-video / gen-digital-human。authoring 也会用,但通过 stub * 方式占位;consuming 场景下是真调用。 * - "meta": 元 skill(如未来加入 doc-only 的 template-creator)。 * * 下游消费方(如 ab-template-studio)按 category 自动挑选白名单,避免每加一个 * skill 就要改两侧 hardcode。 */ export type SkillCategory = 'authoring' | 'consuming' | 'asset' | 'meta'; export declare const CATEGORY_VALUES: readonly ["authoring", "consuming", "asset", "meta"]; /** * Authorization requirement — consumed by the dispatcher's auth preflight. * Semantics are documented on `AuthMode` in src/auth/ensure.ts (kept there so * the runtime behavior and its description live together); this file only owns * the literal values and their validation. */ export type SkillAuthMode = 'required' | 'optional' | 'none'; export declare const AUTH_VALUES: readonly ["required", "optional", "none"]; /** * 参数的**展示分级** —— 给人填表用的,不影响调度。 * * `parameters` 是给 agent 的完整契约(十几个字段很正常);把它整份渲染成表单 * 就是把门槛从"不知道说什么"换成"不知道填什么"。所以每个 skill 自己声明哪些 * 字段该直出、哪些折叠、哪些**根本不该给人看见**(`json_output` / `seed` 这类 * 是给调用方的开关,不是给人的选项)。 * * 它和 schema 同住 skill.json,是刻意的:跨仓库的第二份名单必然漂移—— * ab-web 曾经用硬编码的 `ARCHETYPES` 常量对着后端字典表,最后两边对不上。 * * 未声明的字段自动落进 `advanced`(见 build-manifest 的 resolveUiHints): * 新加一个参数时,最坏情况是它多显示了一层,而不是静默消失。 */ export interface SkillUiHints { /** 表单展开即可见 */ primary?: string[]; /** 折叠在「高级」里 */ advanced?: string[]; /** 不渲染给人类 */ hidden?: string[]; } export interface RawSkillJson { name: string; toolName: string; description: string; title?: string; tier?: string; category?: SkillCategory; auth?: SkillAuthMode; parameters?: Record; /** 参数的展示分级;缺省时按 required → primary、其余 → advanced 推导。 */ ui?: SkillUiHints; scriptPath?: string; entry?: SkillEntry; envVars?: string[]; /** * Declares that this skill produces a finished video, so the dispatcher should * ensure a "take" (VideoProject + conversation) before running it and inject the * resulting CONVERSATION_ID. Declarative rather than a hardcoded skill name in * runner.ts, so the pipeline's shape stays visible in the skill's own manifest. */ createsTake?: boolean; /** * Declares that this skill contributes to a video but must never *start* one: * attach to an existing take if there is one, otherwise carry on unattributed. * A standalone `gen-image` run isn't a video, and an empty VideoProject is * worse clutter than an unattributed asset. */ joinsTake?: boolean; /** * Parsed-argv keys (snake_case, as produced by argv.ts) whose presence means * *this* invocation won't finish a video — `render-video --resolve-only` * resolves assets and stops. Such a run degrades from createsTake to * joinsTake: it still attaches to a take its own pipeline already started, * but never brings one — nor the lazily created 「未分类」 — into being for a * pass that may end in a contract error and no video at all. */ createsTakeUnless?: string[]; } /** * Resolve a skill's auth mode, defaulting for records that predate the field. * * The default is derived from `envVars` rather than hardcoded to `'required'`: * a skill that never declared PRIV_TOKEN cannot possibly need a credential, and * defaulting it to `required` would make a purely local skill (web-screenshot) * pop a browser. Every skill shipped in this package declares `auth` explicitly, * so this only covers externally supplied skill dirs (SKILL_BASE_DIR). */ export declare function resolveAuthMode(raw: Pick): SkillAuthMode; export declare const TIER_VALUES: readonly ["atomic", "orchestration", "tool"]; export declare const REQUIRED_SKILL_JSON_FIELDS: readonly ["name", "tier", "title", "description"]; /** * Resolve the dispatcher entry. A missing `entry` falls back to the legacy * top-level `scriptPath`, treated as `{ type: 'python', scriptPath }` so older * skills keep working untouched. Returns null when neither is present. */ export declare function normalizeEntry(raw: Pick): SkillEntry | null; /** * 把 `ui` 声明补全成三个互斥的完整分桶。没声明 `ui` 时按 required 推导。 * * **未提及的字段一律落进 advanced**:新增参数时最坏是多折一层,而不是消失。 * 返回 null 表示这个 skill 没有可填的参数(不该弹表单)。 */ export declare function resolveUiHints(raw: Pick): Required | null; /** * Validate a parsed skill.json against the directory it lives in. Returns an * array of problem strings; an empty array means the record is well-formed. */ export declare function validateSkillJson(raw: RawSkillJson, skillId: string): string[];