import Type, { type Static } from "typebox"; const ARGUMENT_NAME_PATTERN = "^[A-Za-z0-9_.-]+$"; const RESERVED_ARGUMENT_NAME_SEGMENT_PATTERN = "(^|\\.)(__proto__|constructor|prototype)(\\.|$)"; const OCCURRENCE_VALUES = ["error", "first", "last", "append"] as const; const SCALAR_OCCURRENCE_VALUES = ["error", "first", "last"] as const; const SKILL_WIDGET_VALUES = [ "text", "textarea", "number", "toggle", "select", "radio", "multiselect", "path", "file", "directory", "command", "secret", "list", "key-value", "duration", "date", "time", "datetime", "url", "email", "json", "code", "stepper", "readonly", "computed", "confirm", ] as const; export const UnknownRecordYamlSchema = Type.Record(Type.String(), Type.Unknown()); const sharedArgumentYamlProperties = { description: Type.Optional(Type.String()), examples: Type.Optional(Type.Array(Type.String())), title: Type.Optional(Type.String()), required: Type.Optional(Type.Boolean()), placeholder: Type.Optional(Type.String()), occurrence: Type.Optional(Type.Enum(OCCURRENCE_VALUES)), position: Type.Optional(Type.Integer({ minimum: 0 })), rest: Type.Optional(Type.Boolean()), }; const noRequiredDefaultConflict = { not: { required: ["required", "default"], properties: { required: { const: true }, }, }, }; /** YAML `ui` object accepted by typed skill argument frontmatter. */ export const SkillArgumentUiYamlSchema = Type.Object( { widget: Type.Optional(Type.Enum(SKILL_WIDGET_VALUES)), rows: Type.Optional(Type.Integer({ minimum: 1 })), title: Type.Optional(Type.String()), disabled: Type.Optional(Type.Boolean()), visible_when: Type.Optional(Type.Boolean()), enabled_when: Type.Optional(Type.Boolean()), required_when: Type.Optional(Type.Boolean()), section: Type.Optional(Type.String()), advanced: Type.Optional(Type.Boolean()), copy_from: Type.Optional(Type.String()), }, { additionalProperties: false }, ); const sharedArgumentYamlPropertiesWithUi = { ...sharedArgumentYamlProperties, ui: Type.Optional(SkillArgumentUiYamlSchema), }; const uniqueStringArraySchema = Type.Array(Type.String({ minLength: 1 }), { uniqueItems: true, }); const stringListArraySchema = Type.Array(Type.String({ minLength: 1 })); const nonEmptyStringArraySchema = Type.Array(Type.String({ minLength: 1 }), { minItems: 1, uniqueItems: true, }); const enumOptionDescriptionsSchema = Type.Record(Type.String(), Type.String({ minLength: 1 })); /** YAML DTO for a `type: string` skill argument. */ export const StringSkillArgumentYamlSchema = Type.Object( { type: Type.Literal("string"), ...sharedArgumentYamlPropertiesWithUi, occurrence: Type.Optional(Type.Enum(SCALAR_OCCURRENCE_VALUES)), default: Type.Optional(Type.String()), min_length: Type.Optional(Type.Integer({ minimum: 0 })), max_length: Type.Optional(Type.Integer({ minimum: 0 })), pattern: Type.Optional(Type.String()), format: Type.Optional( Type.Enum(["email", "url", "date", "time", "datetime", "duration", "json"] as const), ), sensitive: Type.Optional(Type.Boolean()), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for a `type: number` skill argument. */ export const NumberSkillArgumentYamlSchema = Type.Object( { type: Type.Literal("number"), ...sharedArgumentYamlPropertiesWithUi, occurrence: Type.Optional(Type.Enum(SCALAR_OCCURRENCE_VALUES)), rest: Type.Optional(Type.Literal(false)), default: Type.Optional(Type.Number()), integer: Type.Optional(Type.Boolean()), min: Type.Optional(Type.Number()), max: Type.Optional(Type.Number()), step: Type.Optional(Type.Number({ exclusiveMinimum: 0 })), unit: Type.Optional(Type.String({ minLength: 1 })), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for a `type: boolean` skill argument. */ export const BooleanSkillArgumentYamlSchema = Type.Object( { type: Type.Literal("boolean"), ...sharedArgumentYamlPropertiesWithUi, occurrence: Type.Optional(Type.Enum(SCALAR_OCCURRENCE_VALUES)), rest: Type.Optional(Type.Literal(false)), default: Type.Optional(Type.Boolean()), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for a `type: enum` skill argument. */ export const EnumSkillArgumentYamlSchema = Type.Object( { type: Type.Literal("enum"), ...sharedArgumentYamlPropertiesWithUi, occurrence: Type.Optional(Type.Enum(SCALAR_OCCURRENCE_VALUES)), rest: Type.Optional(Type.Literal(false)), default: Type.Optional(Type.String()), values: nonEmptyStringArraySchema, option_descriptions: Type.Optional(enumOptionDescriptionsSchema), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for a `type: multi_enum` or `type: multi-enum` skill argument. */ export const MultiEnumSkillArgumentYamlSchema = Type.Object( { type: Type.Enum(["multi_enum", "multi-enum"] as const), ...sharedArgumentYamlPropertiesWithUi, default: Type.Optional(uniqueStringArraySchema), values: nonEmptyStringArraySchema, min_items: Type.Optional(Type.Integer({ minimum: 0 })), max_items: Type.Optional(Type.Integer({ minimum: 0 })), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for a repeatable freeform string list. */ export const StringListSkillArgumentYamlSchema = Type.Object( { type: Type.Enum(["string_list", "string-list"] as const), ...sharedArgumentYamlPropertiesWithUi, default: Type.Optional(stringListArraySchema), min_items: Type.Optional(Type.Integer({ minimum: 0 })), max_items: Type.Optional(Type.Integer({ minimum: 0 })), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for repeatable `key=value` entries. */ export const KeyValueSkillArgumentYamlSchema = Type.Object( { type: Type.Enum(["key_value", "key-value"] as const), ...sharedArgumentYamlPropertiesWithUi, rest: Type.Optional(Type.Literal(false)), default: Type.Optional(Type.Record(Type.String(), Type.String())), min_items: Type.Optional(Type.Integer({ minimum: 0 })), max_items: Type.Optional(Type.Integer({ minimum: 0 })), }, { additionalProperties: false, allOf: [noRequiredDefaultConflict] }, ); /** YAML DTO for one concrete typed skill argument. */ export const SkillArgumentYamlSchema = Type.Union([ StringSkillArgumentYamlSchema, NumberSkillArgumentYamlSchema, BooleanSkillArgumentYamlSchema, EnumSkillArgumentYamlSchema, MultiEnumSkillArgumentYamlSchema, StringListSkillArgumentYamlSchema, KeyValueSkillArgumentYamlSchema, ]); /** YAML frontmatter fields consumed by typed skill support. */ export const SkillFrontmatterYamlSchema = Type.Object( { name: Type.Optional(Type.String()), description: Type.Optional(Type.String()), form_title: Type.Optional(Type.String()), metadata: Type.Optional( Type.Object( { ghostText: Type.Optional(Type.String()), }, { additionalProperties: true }, ), ), arguments: Type.Optional(Type.Unknown()), }, { additionalProperties: true }, ); /** Recursive top-level YAML `arguments` map schema used for the published JSON Schema. */ export const SkillArgumentsYamlSchema = Type.Object( {}, { $schema: "https://json-schema.org/draft/2020-12/schema", $id: "https://raw.githubusercontent.com/zigai/pi-tweaks/master/packages/pi-typed-args/schemas/skill-arguments.schema.json", title: "Pi Typed Args Skill Arguments", description: "Schema for the top-level `arguments` field in SKILL.md frontmatter used by pi-typed-args.", propertyNames: Type.String({ allOf: [ { pattern: ARGUMENT_NAME_PATTERN }, { not: { pattern: RESERVED_ARGUMENT_NAME_SEGMENT_PATTERN } }, ], }), additionalProperties: Type.Ref("#/$defs/argumentOrNamespace"), $defs: { argumentName: Type.String({ allOf: [ { pattern: ARGUMENT_NAME_PATTERN }, { not: { pattern: RESERVED_ARGUMENT_NAME_SEGMENT_PATTERN } }, ], }), argumentOrNamespace: Type.Union([ Type.Ref("#/$defs/argument"), Type.Object( {}, { propertyNames: Type.Ref("#/$defs/argumentName"), additionalProperties: Type.Ref("#/$defs/argumentOrNamespace"), }, ), ]), shared: Type.Object(sharedArgumentYamlProperties, { allOf: [{ not: { required: ["aliases"] } }, noRequiredDefaultConflict], }), ui: SkillArgumentUiYamlSchema, stringArgument: StringSkillArgumentYamlSchema, numberArgument: NumberSkillArgumentYamlSchema, booleanArgument: BooleanSkillArgumentYamlSchema, enumArgument: EnumSkillArgumentYamlSchema, multiEnumArgument: MultiEnumSkillArgumentYamlSchema, stringListArgument: StringListSkillArgumentYamlSchema, keyValueArgument: KeyValueSkillArgumentYamlSchema, argument: Type.Union([ Type.Ref("#/$defs/stringArgument"), Type.Ref("#/$defs/numberArgument"), Type.Ref("#/$defs/booleanArgument"), Type.Ref("#/$defs/enumArgument"), Type.Ref("#/$defs/multiEnumArgument"), Type.Ref("#/$defs/stringListArgument"), Type.Ref("#/$defs/keyValueArgument"), ]), }, }, ); export type SkillArgumentUiYaml = Static; export type StringSkillArgumentYaml = Static; export type NumberSkillArgumentYaml = Static; export type BooleanSkillArgumentYaml = Static; export type EnumSkillArgumentYaml = Static; export type MultiEnumSkillArgumentYaml = Static; export type StringListSkillArgumentYaml = Static; export type KeyValueSkillArgumentYaml = Static; export type SkillArgumentYaml = Static; export type SkillFrontmatterYaml = Static; /** Return the JSON Schema published at `pi-typed-args/schema`. */ export function skillArgumentsJsonSchema(): typeof SkillArgumentsYamlSchema { return SkillArgumentsYamlSchema; }