/** * The one canonical skill format, shared by every platform adapter. * * Each adapter writes two kinds of file: a **canonical copy** under * `.aidlc/skills/`, which is platform-neutral and which every adapter writes to * the same path, and a **platform-visible file** whose shape that platform's own * validator dictates. This module owns the first only. * * The distinction is not cosmetic: `claude-code.ts` validates that its skill * file's frontmatter `name` equals the directory name, a rule the canonical copy * has no reason to follow, which is why AC-26 was retired and reissued as AC-47 * scoped to the canonical copy. * * What this fixes is a live defect rather than an inconsistency: claude-code and * codex already write `.aidlc/skills/.md` with **different** content — * claude-code wrote `skill.body` raw, with no frontmatter at all — so on a * two-platform project the canonical copy depended on adapter iteration order. * * Field order is pinned to the codex adapter's existing order so its canonical * output is unchanged (AC-22). * * Requirements: agent-portability/AC-47, AC-48, AC-22 * * @module */ import type { Skill } from '../core/types.js'; /** What a generated file says about itself, or `null` when it says nothing. */ export interface GeneratedMarker { /** The CLI version at which the body last changed — not the one that last wrote the file. */ version: string; /** The recorded hash of everything below the marker line. */ sha256: string; } /** * Build the marker block for a body, with the hash already correct. * * `body` is the text that will follow the marker. The returned string is the * marker lines plus a blank line, ready to prepend. */ export declare function markerFor(version: string, body: string): string; /** * Prepend the marker to a body, replacing any marker already there. * * Idempotent: re-stamping an already-stamped body yields the same result rather * than nesting markers, so it is safe on a body that has been round-tripped. * * `prior` is the marker the file on disk already carries. When it vouches for * exactly this body its version is kept, and since the hash is equal by * construction the machine line comes out byte for byte the same — so an * unchanged body is an unchanged file whatever CLI version emits it * (update-restamps-unchanged-skills/AC-1). Any other body takes `version` * (AC-2, AC-3). */ export declare function stampBody(body: string, version: string, prior?: GeneratedMarker | null): string; /** * Read what a generated file claims about itself. * * Searches the whole file rather than only its first line, because the codex * adapter writes directives above the body while the canonical copy does not — * the marker's position differs by platform, its presence does not. */ export declare function readMarker(content: string): GeneratedMarker | null; /** * The content a marker vouches for: everything after the marker block. * * Returns `null` when there is no marker, which the caller must distinguish from * an empty body — one means "not a generated file", the other "generated and * empty". */ export declare function contentBelowMarker(content: string): string | null; /** Remove a marker block from a body, leaving the bare prose. */ export declare function stripMarker(content: string): string; /** * Is this generated file still exactly what the emitter wrote? * * Distinguishable answers, which is what makes the doctor report useful rather * than merely red (update-overwrites-authored-context/AC-16): * * - `unmarked` — emitted before markers existed, or hand-created. Not evidence of * an edit. * - `edited` — the content no longer hashes to what its marker recorded, at any * version. Somebody changed the artifact. * - `newer-cli` — intact, but its body last changed at a version newer than the * running CLI. This CLI is behind, and its `aidlc update` would roll the prose * back, so the remedy is upgrading the CLI. * - `clean` — intact, at the running version or an older one. An older version is * normal: it is when the body last changed (update-restamps-unchanged-skills/AC-9). * * `newer-cli` was `version-skew`, raised on *any* mismatch. Once an unchanged body * keeps its version, that fired on every file after every release with a remedy * that could not clear it — so it was narrowed and renamed on purpose, the rename * so nobody reads the old meaning into it (AC-11). */ export type MarkerVerdict = { state: 'unmarked'; } | { state: 'newer-cli'; emittedBy: string; } | { state: 'edited'; emittedBy: string; } | { state: 'clean'; emittedBy: string; }; export declare function verifyMarker(content: string, runningVersion: string): MarkerVerdict; /** * Is `candidate` a strictly later `major.minor.patch` than `than`? * * Anything that is not three dot-separated whole numbers — a prerelease such as * `1.54.0-rc.1`, a hand-typed string — is never newer, so the hash alone decides * (update-restamps-unchanged-skills/AC-12). `update.ts` has its own `isOlderThan`, * but it lets a non-numeric part become `NaN` and compare as neither, which is a * silent answer this check should not give. */ export declare function isNewerVersion(candidate: string, than: string): boolean; /** * Format a skill as its canonical file content: frontmatter, then body. * * Order is `name, description, phase, trigger, priority` — fixed here so no * adapter can drift, and matching what codex already wrote so AC-22 holds. * Optional fields are omitted when absent rather than emitted empty. */ export declare function formatCanonicalSkill(skill: Skill): string; //# sourceMappingURL=skill-format.d.ts.map