/** * Create Label Tool * Adds a new label to an existing AxLabelFile in a custom model. * * For each language that has a .label.txt file in the model, the tool: * 1. Checks that the label ID does not already exist * 2. Inserts the label in alphabetical order * 3. Writes the updated file back to disk * 4. Updates the SQLite label index * * If the AxLabelFile does not exist yet (new label file), the tool also * creates the XML descriptor files and directory structure. */ import type { CallToolRequest } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import type { XppServerContext } from '../../types/context.js'; import type { XppSymbolIndex } from '../../metadata/symbolIndex.js'; /** * Exported so argument validation can be tested WITHOUT calling the tool: the * create branch writes real .label.txt files into a live model, so a test that * exercises it through createLabelTool leaves labels behind in the environment. */ export declare const CreateLabelArgsSchema: z.ZodObject<{ labelId: z.ZodString; labelFileId: z.ZodString; model: z.ZodString; packageName: z.ZodOptional; translations: z.ZodArray; }, z.core.$strip>>; languages: z.ZodOptional>; description: z.ZodOptional; defaultComment: z.ZodOptional; packagePath: z.ZodOptional; projectPath: z.ZodOptional; solutionPath: z.ZodOptional; addToProject: z.ZodDefault>; createLabelFileIfMissing: z.ZodDefault>; allowExtensionLabelFile: z.ZodDefault>; updateIndex: z.ZodDefault>; sortLabels: z.ZodOptional; overwriteExisting: z.ZodDefault>; createIfMissing: z.ZodDefault>; }, z.core.$strip>; /** * Pull a `labels: [...]` array off the raw args, if present and non-empty. * Bulk callers pass shared fields (labelFileId, model, paths…) at the top level * and one entry per label ({ labelId, translations, … }). Returns null for the * ordinary single-label shape so the normal path runs unchanged. */ export declare function extractBulkLabels(raw: unknown): Array> | null; /** The single-label create signature, injectable so the fan-out is testable. */ export type SingleLabelRunner = (request: CallToolRequest, context: XppServerContext) => Promise; /** * Create many labels in one call. Each entry is merged over the shared top-level * fields and routed through the single-label path (which keeps validation, file * creation and indexing identical), then results are aggregated into one report. * Continues past per-label failures so one bad entry doesn't abort the batch. */ export declare function createLabelsBulk(entries: Array>, raw: Record, context: XppServerContext, runSingle?: SingleLabelRunner): Promise<{ content: Array<{ type: 'text'; text: string; }>; isError: boolean; }>; /** * Where an auto-resolved label is allowed to land, and the path plumbing the * caller has already resolved (passing it saves createLabelTool re-deriving it). */ export interface AutoLabelTarget { model: string; /** Overrides the label file pick; normally left out so the model's ORIGINAL file wins. */ labelFileId?: string; packagePath?: string; projectPath?: string; solutionPath?: string; addToProject?: boolean; } export interface AutoLabelRequest { /** The raw text as the caller wrote it. */ text: string; /** What is being labelled, for the reported note — e.g. `field "Status"`. */ what: string; /** * The enum an enum-typed field points at. Its own Label must NOT be reused: * xppbp reports BPErrorFieldLabelIsCopyOfEnumLabel, and the agent cannot see * that until a build runs. */ enumType?: string; } export interface AutoLabelResult { /** The reference to write. Absent when nothing could be resolved — keep the raw text. */ ref?: string; /** One line, in the shape the other auto-corrections report in. */ note: string; } /** * The model's ORIGINAL label file — never an `…_Extension…` one. * * New labels belong in the model's own file; an extension label file extends * one owned by ANOTHER model, and labels added there end up wrongly prefixed * (the same rule createLabelTool enforces with a hard error below). * The file named after the model is the convention, so it wins; otherwise the * one original file the model already has; otherwise the model name, which * createLabelFileIfMissing then creates. * * A file whose id cannot appear in an `@FileId:LabelId` reference is skipped * rather than preferred: a model named `fm-mcp` ships a label file `fm-mcp`, * and picking it hands the caller a reference xppbp rejects. When only such * files exist the model name is returned unchanged, and the callers below * refuse on {@link isValidLabelFileId} instead of writing an unusable label. */ export declare function pickOriginalLabelFileId(model: string, symbolIndex?: XppSymbolIndex): string; /** * Raw label text → a `@File:Id` reference, reusing an existing label when one * already carries that exact text and creating one when none does. * * Why this exists: `labels` was the second most-called tool in a 1,515-call * corpus — 268 calls against 171 writes — and `labels → labels` was the single * most frequent consecutive pair (177 times). The shape was always the same: * search for a label, read it back, create it, then write the object, once per * label. Every one of those is a round trip that re-bills the whole cached * context, and all of it is derivable from the text the write already carries. * * Nothing is invented silently: the returned note names the id that was reused * or created, because a label reference the caller never chose and cannot see * would be worse than the BP advisory this replaces. */ export declare function resolveOrCreateLabelRef(req: AutoLabelRequest, target: AutoLabelTarget, symbolIndex?: XppSymbolIndex): Promise; export declare function createLabelTool(request: CallToolRequest, context: XppServerContext): Promise<{ content: { type: string; text: string; }[]; isError: boolean; } | { isError?: undefined; content: { type: string; text: string; }[]; }>; //# sourceMappingURL=createLabel.d.ts.map