import { DISPLAY_TEXT_CONTRACT, hasDisplayControlCharacters } from "@henryqw/pi-subagent"; import { Type, type Static } from "typebox"; const TASK_NAME_MAX_LENGTH = 29 as const; const TASK_NAME_LIMIT_WORDING = `about five words and fewer than ${TASK_NAME_MAX_LENGTH + 1} characters`; export const TASK_NAME_CONTRACT = { minLength: 1, maxLength: TASK_NAME_MAX_LENGTH, description: `Short descriptive task name, ${TASK_NAME_LIMIT_WORDING}; C0/C1 control characters are rejected.`, controlRanges: DISPLAY_TEXT_CONTRACT.controlRanges, pattern: DISPLAY_TEXT_CONTRACT.pattern, } as const; export const TaskNameSchema = Type.String({ minLength: TASK_NAME_CONTRACT.minLength, maxLength: TASK_NAME_CONTRACT.maxLength, description: TASK_NAME_CONTRACT.description, pattern: TASK_NAME_CONTRACT.pattern, }); export type TaskName = Static; export function normalizeTaskName(value: TaskName, path: string): TaskName { if (hasDisplayControlCharacters(value)) throw new Error(`${path} must not contain C0/C1 control characters.`); const normalized = value.trim(); if (!normalized) throw new Error(`${path} must be non-empty text.`); return normalized; }