/**
* Zod schemas for manifest YAML validation.
* These schemas define the canonical data model for tools and workflows.
*/
import { z } from 'zod';
/**
* Availability flags for different runtimes.
*/
export const availabilitySchema = z
.object({
mcp: z.boolean().default(true),
cli: z.boolean().default(true),
})
.strict();
export type Availability = z.infer<typeof availabilitySchema>;
/**
* Routing hints for daemon-backed CLI execution.
*/
export const routingSchema = z
.object({
stateful: z.boolean().default(false),
})
.strict();
export type Routing = z.infer<typeof routingSchema>;
/**
* MCP tool annotations (hints for clients).
* All properties are optional hints, not guarantees.
*/
export const annotationsSchema = z.object({
title: z.string().optional(),
readOnlyHint: z.boolean().optional(),
destructiveHint: z.boolean().optional(),
idempotentHint: z.boolean().optional(),
openWorldHint: z.boolean().optional(),
});
export type Annotations = z.infer<typeof annotationsSchema>;
/**
* Tool names for MCP and CLI.
*/
export const toolNamesSchema = z.object({
/** MCP name is required and must be globally unique */
mcp: z.string(),
/** CLI name is optional; if omitted, derived from MCP name */
cli: z.string().optional(),
});
export type ToolNames = z.infer<typeof toolNamesSchema>;
/**
* Tool manifest entry schema.
* Describes a single tool's metadata and configuration.
*/
export const toolManifestEntrySchema = z.object({
/** Unique tool identifier */
id: z.string(),
/**
* Module path (extensionless, package-relative).
* Resolved to build/<module>.js at runtime.
*/
module: z.string(),
/** Tool names for MCP and CLI */
names: toolNamesSchema,
/** Tool description */
description: z.string().optional(),
/** Per-runtime availability flags */
availability: availabilitySchema.default({ mcp: true, cli: true }),
/** Predicate names for visibility filtering (all must pass) */
predicates: z.array(z.string()).default([]),
/** Routing hints for daemon */
routing: routingSchema.optional(),
/** MCP annotations (hints for clients) */
annotations: annotationsSchema.optional(),
});
export type ToolManifestEntry = z.infer<typeof toolManifestEntrySchema>;
/**
* MCP-specific workflow selection rules.
*/
export const workflowSelectionMcpSchema = z.object({
/** Used when config.enabledWorkflows is empty */
defaultEnabled: z.boolean().default(false),
/** Include when predicates pass, regardless of user selection */
autoInclude: z.boolean().default(false),
});
export type WorkflowSelectionMcp = z.infer<typeof workflowSelectionMcpSchema>;
/**
* Workflow selection rules.
*/
export const workflowSelectionSchema = z.object({
mcp: workflowSelectionMcpSchema.optional(),
});
export type WorkflowSelection = z.infer<typeof workflowSelectionSchema>;
/**
* Workflow manifest entry schema.
* Describes a workflow's metadata and tool composition.
*/
export const workflowManifestEntrySchema = z.object({
/** Unique workflow identifier (matches directory name) */
id: z.string(),
/** Display title for the workflow */
title: z.string(),
/** Workflow description */
description: z.string(),
/** Per-runtime availability flags */
availability: availabilitySchema.default({ mcp: true, cli: true }),
/** MCP selection rules */
selection: workflowSelectionSchema.optional(),
/** Predicate names for visibility filtering (all must pass) */
predicates: z.array(z.string()).default([]),
/** Tool IDs belonging to this workflow */
tools: z.array(z.string()),
});
export type WorkflowManifestEntry = z.infer<typeof workflowManifestEntrySchema>;
/**
* Resolved manifest containing all tools and workflows.
*/
export interface ResolvedManifest {
tools: Map<string, ToolManifestEntry>;
workflows: Map<string, WorkflowManifestEntry>;
}
/**
* Derive CLI name from MCP name using kebab-case conversion.
* - Underscores become hyphens
* - camelCase becomes kebab-case
*/
export function deriveCliName(mcpName: string): string {
return mcpName
.replace(/_/g, '-')
.replace(/([a-z])([A-Z])/g, '$1-$2')
.toLowerCase();
}
/**
* Get the effective CLI name for a tool.
*/
export function getEffectiveCliName(tool: ToolManifestEntry): string {
return tool.names.cli ?? deriveCliName(tool.names.mcp);
}