{"version":3,"file":"validate-Bi7FGjoq.mjs","names":[],"sources":["../src/batteries/media/plan.ts","../src/batteries/media/verbs.ts","../src/batteries/media/validate.ts"],"sourcesContent":["/**\n * The neutral `MediaPlan` intermediate representation and its canonical serializers.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/media` entry. All three front-ends — the\n * chainable builder, the pipe-string parser, and the JSON ops array — compile to this one IR,\n * and the step runtime consumes only this IR. Invariants (frozen design, section 0.7):\n *\n * - **Serializable.** No live `RegExp`, `Media`, or function values — regexes are\n *   `{ source, flags }`, media refs are typed handles. A plan can be logged, content-hashed,\n *   and embedded in a tool result.\n * - **Round-trip is fixed-point.** `parsePipe(toPipe(plan))` produces an equal plan and\n *   `toPipe` is idempotent. `toPipe(parsePipe(s)) === s` is NOT promised (e.g. `2,3,4,5`\n *   renders as `2-5`).\n * - **Engine-agnostic.** Steps name verbs, never engines.\n */\n\nimport { isObject } from '@nhtio/adk/guards'\nimport { E_MEDIA_NOT_PIPE_EXPRESSIBLE } from './exceptions'\n\n/**\n * A serializable regex reference. Never a live `RegExp` in the IR.\n */\nexport interface RegExpRef {\n  /** The regex source, exactly as `RegExp.prototype.source` would report it. */\n  source: string\n  /** Sorted flag characters (canonicalized — `gi`, never `ig`). */\n  flags: string\n}\n\n/**\n * A reference to another media participating in a multi-input verb (`merge`, `diff`,\n * `apply_patch`, `slides.update_image`).\n *\n * @remarks\n * The `id` variant is the canonical model-facing form — the pipe syntax is an inline\n * `@id` token (`merge with=@018f…`) and the ops form carries the same id. The `builder`\n * variant is implementor-only (a nested chain: `mp(a).diff(mp(b).convert('txt'))`) and is\n * not expressible in a flat pipe string.\n */\nexport type MediaRef = { kind: 'id'; id: string } | { kind: 'builder'; plan: MediaPlan }\n\n/** Scalar arg values the flat pipe grammar can express directly. */\nexport type MediaArgScalar = string | number | boolean | RegExpRef | MediaRef\n\n/**\n * A structured (JSON-shaped) arg value. In the pipe surface these are written as quoted JSON\n * (`updates='[{\"address\":\"B2\",\"value\":3}]'`); in ops they are plain JSON. `null` is legal only\n * inside structured values (cell values), never as a top-level scalar.\n */\nexport type MediaArgJson =\n  | string\n  | number\n  | boolean\n  | null\n  | MediaArgJson[]\n  | { [key: string]: MediaArgJson }\n\n/**\n * The value space of a single verb arg in the IR.\n *\n * @remarks\n * Flat lists (`types=image,font` → `['image','font']`) are `MediaArgScalar[]`. Whether a\n * value parsed from quoted JSON or a flat token is decided by the verb's arg schema — the IR\n * stores the final shape only.\n */\nexport type MediaArgValue = MediaArgScalar | MediaArgScalar[] | MediaArgJson\n\n/** Source span carried by steps parsed from a pipe string, for error mapping. */\nexport interface SourceSpan {\n  /** Zero-based character offset into the source string. */\n  offset: number\n  /** One-based line number. */\n  line: number\n  /** One-based column number. */\n  col: number\n  /** Length of the spanned text in characters. */\n  length: number\n}\n\n/** One transform step: a canonical verb id plus its validated content args. */\nexport interface MediaStep {\n  /**\n   * Canonical verb id — dot-namespaced snake_case (`convert`, `select`, `extract.text`,\n   * `sheet.update_cells`, `image.resize`).\n   */\n  verb: string\n  /** Validated content args for this verb. */\n  args: Record<string, MediaArgValue>\n  /** Present when the step came from a pipe string; absent for builder/ops origins. */\n  span?: SourceSpan\n}\n\n/** The neutral plan: an ordered, linear list of steps. No branching. */\nexport interface MediaPlan {\n  /** The ordered transform steps. */\n  steps: MediaStep[]\n}\n\n/** The JSON ops front-end's step shape — identical to {@link MediaStep} minus the span. */\nexport interface MediaOp {\n  /** The canonical (or foldable) verb id. */\n  verb: string\n  /** The verb's named args. */\n  args: Record<string, MediaArgValue>\n}\n\n// ── guards ───────────────────────────────────────────────────────────────────\n\n/** `true` when `value` is a {@link RegExpRef}. */\nexport const isRegExpRef = (value: unknown): value is RegExpRef => {\n  if (!isObject(value)) return false\n  const v = value as Record<string, unknown>\n  return typeof v.source === 'string' && typeof v.flags === 'string' && Object.keys(v).length === 2\n}\n\n/** `true` when `value` is a {@link MediaRef}. */\nexport const isMediaRef = (value: unknown): value is MediaRef => {\n  if (!isObject(value)) return false\n  const v = value as MediaRef\n  if (v.kind === 'id') return typeof (v as { id?: unknown }).id === 'string'\n  if (v.kind === 'builder') return isObject((v as { plan?: unknown }).plan)\n  return false\n}\n\n// ── canonical rendering helpers ──────────────────────────────────────────────\n\n/** Characters legal in an unquoted bareword value. */\nconst BAREWORD = /^[A-Za-z0-9_]+$/\n/** Strings that would lex as a non-ident token and therefore must be quoted. */\nconst LEXES_AS_OTHER = /^(?:\\d+(?:-\\d+)?|\\d+\\.\\d+|true|false|@.*)$/\n\n/**\n * The frozen quoting predicate: quote any string that is empty, would lex as a number, range,\n * boolean, or `@id` token, starts with `/`, or contains a character outside `[A-Za-z0-9_]`.\n */\nconst renderString = (s: string): string => {\n  if (s.length === 0 || !BAREWORD.test(s) || LEXES_AS_OTHER.test(s) || s.startsWith('/')) {\n    return `\"${s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n')}\"`\n  }\n  return s\n}\n\n/** Canonicalize regex flags: validate against JS flags and sort. */\nexport const canonicalFlags = (flags: string): string => Array.from(flags).sort().join('')\n\n/** Render a {@link RegExpRef} back to a pipe regex literal, re-escaping bare slashes. */\nconst renderRegExp = (ref: RegExpRef): string => {\n  const source = ref.source.length === 0 ? '(?:)' : ref.source\n  // Escape bare `/` that are not already escaped and not inside a character class.\n  let out = ''\n  let inClass = false\n  for (let i = 0; i < source.length; i++) {\n    const ch = source[i]\n    if (ch === '\\\\') {\n      out += ch + (source[i + 1] ?? '')\n      i++\n      continue\n    }\n    if (ch === '[') inClass = true\n    else if (ch === ']') inClass = false\n    if (ch === '/' && !inClass) {\n      out += '\\\\/'\n      continue\n    }\n    out += ch\n  }\n  return `/${out}/${canonicalFlags(ref.flags)}`\n}\n\n/**\n * Compress maximal ascending consecutive runs in a number list to `a-b` range tokens.\n * Order-preserving and lossless on the array; never sorts or dedupes.\n */\nconst renderNumberList = (nums: number[]): string => {\n  const parts: string[] = []\n  let i = 0\n  while (i < nums.length) {\n    let j = i\n    while (\n      j + 1 < nums.length &&\n      Number.isInteger(nums[j]) &&\n      nums[j + 1] === (nums[j] as number) + 1\n    ) {\n      j++\n    }\n    if (j - i >= 1 && Number.isInteger(nums[i])) {\n      parts.push(`${nums[i]}-${nums[j]}`)\n    } else {\n      parts.push(String(nums[i]))\n      j = i\n    }\n    i = j + 1\n  }\n  return parts.join(',')\n}\n\nconst renderScalar = (value: MediaArgScalar): string => {\n  if (typeof value === 'number') return String(value)\n  if (typeof value === 'boolean') return String(value)\n  if (typeof value === 'string') return renderString(value)\n  if (isRegExpRef(value)) return renderRegExp(value)\n  // MediaRef\n  if (value.kind === 'id') return `@${value.id}`\n  throw new E_MEDIA_NOT_PIPE_EXPRESSIBLE(['nested builder refs have no pipe form; use toOps()'])\n}\n\nconst isScalar = (value: MediaArgValue): value is MediaArgScalar =>\n  typeof value === 'string' ||\n  typeof value === 'number' ||\n  typeof value === 'boolean' ||\n  isRegExpRef(value) ||\n  isMediaRef(value)\n\nconst renderValue = (value: MediaArgValue): string => {\n  if (value === null) {\n    // null is only legal inside structured JSON values\n    throw new E_MEDIA_NOT_PIPE_EXPRESSIBLE(['null is not a flat pipe value; use toOps()'])\n  }\n  if (Array.isArray(value)) {\n    const arr = value as MediaArgScalar[]\n    if (arr.length > 0 && arr.every((v) => typeof v === 'number')) {\n      return renderNumberList(arr as number[])\n    }\n    if (arr.every(isScalar)) {\n      return arr.map(renderScalar).join(',')\n    }\n    // structured (nested) array -> quoted JSON\n    return `'${JSON.stringify(value)}'`\n  }\n  if (isScalar(value)) return renderScalar(value)\n  // structured object -> quoted JSON\n  return `'${JSON.stringify(value)}'`\n}\n\n/**\n * Render a {@link MediaPlan} to its canonical pipe string.\n *\n * @remarks\n * Total for every plan except those containing builder-variant media refs, which throw\n * {@link E_MEDIA_NOT_PIPE_EXPRESSIBLE}. Structured args render as quoted JSON. The output is\n * canonical: dot-namespaced verbs render as space-separated words, number runs compress to\n * ranges, strings quote per the frozen predicate.\n *\n * @param plan - The plan to render.\n * @returns The canonical pipe expression.\n */\nexport const toPipe = (plan: MediaPlan): string =>\n  plan.steps\n    .map((step) => {\n      const verb = step.verb.replace(/\\./g, ' ')\n      const args = Object.entries(step.args)\n        .map(([k, v]) => `${k}=${renderValue(v)}`)\n        .join(' ')\n      return args.length > 0 ? `${verb} ${args}` : verb\n    })\n    .join(' | ')\n\n/**\n * Render a {@link MediaPlan} to its JSON ops array. Total — every plan has an ops form.\n *\n * @param plan - The plan to render.\n * @returns The ops array (spans stripped).\n */\nexport const toOps = (plan: MediaPlan): MediaOp[] =>\n  plan.steps.map((step) => ({ verb: step.verb, args: step.args }))\n\n/**\n * Build a {@link MediaPlan} from a JSON ops array. The inverse of {@link toOps}.\n *\n * @remarks\n * Performs structural normalization only (verb-id folding via the caller's verb table happens\n * in validation, not here). Steps carry no spans.\n *\n * @param ops - The ops array.\n * @returns The equivalent plan.\n */\nexport const fromOps = (ops: MediaOp[]): MediaPlan => ({\n  steps: ops.map((op) => ({ verb: op.verb, args: op.args })),\n})\n","/**\n * The canonical verb table: every verb the media DSL knows, with arg schemas, engine\n * requirements, format-family applicability, and output kinds.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/media` entry. This table is the single source\n * of truth consumed by:\n *\n * - the pipe parser's semantic validator (unknown-verb/arg detection, did-you-mean),\n * - the plan compiler (arg coercion + constraint checks),\n * - the engine-narrowing pass (which verbs a deployment advertises),\n * - the forge (generating the `media_query` tool description and few-shot examples),\n * - the builder (typed front-end methods map 1:1 onto entries here).\n *\n * Frozen design decisions (design doc section 0): canonical verb ids are dot-namespaced\n * snake_case; verb matching is separator-insensitive (space/`_`/`.` fold); args are named-only;\n * indices are 1-based everywhere; arg names follow one-meaning-one-name (`to`, `with`, `match`,\n * `replace`, `order`, `pages`, `at`).\n */\n\nimport { PCM_MIME } from './contracts'\n\n/** The value type of a single declared arg. */\nexport type VerbArgType =\n  | 'string'\n  | 'number'\n  | 'boolean'\n  | 'enum'\n  | 'number-list'\n  | 'string-list'\n  | 'regex-or-string-list'\n  | 'name-or-index'\n  | 'media-ref'\n  | 'media-ref-list'\n  | 'json'\n\n/** Declaration of one named arg on a verb. */\nexport interface VerbArgSpec {\n  /** The arg's value type. */\n  type: VerbArgType\n  /** Whether the statement must supply this arg. */\n  required?: boolean\n  /** Legal values when `type === 'enum'` (or per-element for list types). */\n  values?: readonly string[]\n  /** Inclusive minimum for numbers / per-element for number lists. */\n  min?: number\n  /** Inclusive maximum for numbers / per-element for number lists. */\n  max?: number\n  /** Model-facing description used in generated tool grammar text. */\n  description: string\n}\n\n/**\n * A verb's capability requirement against the deployment's engine registry. Verbs with no\n * requirement are always advertised; input-conditional engine needs (e.g. `extract.text`\n * needing OCR only for images) stay runtime checks inside the step implementation.\n */\nexport type VerbRequirement =\n  | { capability: 'convert'; from?: string; to?: string }\n  | { capability: 'mutate' }\n  | { capability: 'edit'; op?: string }\n\n/** Broad input families used for verb-applicability checks. */\nexport type FormatFamily =\n  | 'document' // pdf/docx/odt/rtf/txt/md/html...\n  | 'spreadsheet' // xlsx/ods/xls/csv\n  | 'presentation' // pptx/odp/ppt\n  | 'image'\n  | 'audio'\n  | 'any'\n\n/** What awaiting a chain ending in this verb resolves to. */\nexport type VerbOutput = 'media' | 'media-list' | 'text' | 'json'\n\n/** One verb table entry. */\nexport interface VerbSpec {\n  /** Canonical id: dot-namespaced snake_case (`extract.text`, `sheet.update_cells`). */\n  id: string\n  /** Model-facing one-line description. */\n  description: string\n  /** Named args (named-only grammar; no positionals). */\n  args: Record<string, VerbArgSpec>\n  /**\n   * Capability the verb always requires, if any — gates whether the verb is advertised and\n   * accepted under a given engine configuration. Input-conditional needs are handled (and\n   * error-messaged) by the step implementation at runtime.\n   */\n  requires?: VerbRequirement\n  /** Input families the verb applies to. */\n  appliesTo: readonly FormatFamily[]\n  /** Output kind. May be refined by an `out`-style arg (documented per verb). */\n  output: VerbOutput\n}\n\n/** Conversion targets supported by `convert` (the server's enum plus the SheetJS/data matrix). */\nexport const CONVERT_TARGETS = [\n  'pdf',\n  'html',\n  'txt',\n  'md',\n  'csv',\n  'json',\n  'yaml',\n  'docx',\n  'doc',\n  'rtf',\n  'odt',\n  'xlsx',\n  'xls',\n  'ods',\n  'xlsm',\n  'xlsb',\n  'fods',\n  'sylk',\n  'dif',\n  'dbf',\n  'numbers',\n  'pptx',\n  'ppt',\n  'odp',\n] as const\n\n/** Image output formats supported by `image.format`. */\nexport const IMAGE_FORMATS = ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif'] as const\n\n/** The canonical verb table. Order is presentation order in generated grammar text. */\nexport const VERBS: readonly VerbSpec[] = [\n  // ── root: document transforms ──────────────────────────────────────────────\n  {\n    id: 'convert',\n    description: 'Convert the media to another format.',\n    args: {\n      to: {\n        type: 'enum',\n        required: true,\n        values: CONVERT_TARGETS,\n        description: 'Target format.',\n      },\n    },\n    requires: { capability: 'convert' },\n    appliesTo: ['document', 'spreadsheet', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'select',\n    description: 'Keep only the listed pages/slides/sections (1-based), producing one file.',\n    args: {\n      pages: {\n        type: 'number-list',\n        required: true,\n        min: 1,\n        description: 'Pages (or slides/sections) to keep, 1-based. Ranges allowed: 2-5,8.',\n      },\n    },\n    appliesTo: ['document', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'split',\n    description: 'Split the media into multiple files by page or section.',\n    args: {\n      by: {\n        type: 'enum',\n        values: ['page', 'section'],\n        description: 'Split unit. Default: page.',\n      },\n      ranges: {\n        type: 'json',\n        description:\n          \"Explicit grouping as a JSON array of [start,end] pairs (1-based), e.g. '[[1,3],[5,7]]'.\",\n      },\n    },\n    appliesTo: ['document', 'presentation'],\n    output: 'media-list',\n  },\n  {\n    id: 'merge',\n    description: 'Merge other media into this one, in order.',\n    args: {\n      with: {\n        type: 'media-ref-list',\n        required: true,\n        description: 'Other media to append, as @id refs: with=@<media id>,@<media id>.',\n      },\n    },\n    appliesTo: ['document', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'reorder',\n    description: 'Reorder pages/slides/sections by the given 1-based index order.',\n    args: {\n      order: {\n        type: 'number-list',\n        required: true,\n        min: 1,\n        description: 'New order of existing 1-based indices.',\n      },\n    },\n    appliesTo: ['document', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'redact',\n    description:\n      'Redact matching text. Prefer literal strings; /regex/ is supported. PDF redaction is VISUAL (draw-over + metadata strip; content streams keep the text) — for content-level PDF redaction, extract text first.',\n    args: {\n      match: {\n        type: 'regex-or-string-list',\n        required: true,\n        description: 'Literal string(s) or a /regex/ to redact.',\n      },\n      replace: {\n        type: 'string',\n        description:\n          'Replacement text. Omit for the blackout/removal default; send an empty string to blank the match out with nothing.',\n      },\n    },\n    appliesTo: ['document', 'spreadsheet', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'sanitize',\n    description: 'Remove potentially unsafe embedded content from the media.',\n    args: {},\n    appliesTo: ['document', 'spreadsheet', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'normalize',\n    description: 'Normalize the media structure/encoding for downstream consistency.',\n    args: {},\n    appliesTo: ['document', 'spreadsheet', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'update_text',\n    description: 'Replace the first occurrence of an anchor text.',\n    args: {\n      anchor: {\n        type: 'string',\n        required: true,\n        description: 'Existing text to find.',\n      },\n      replace: {\n        type: 'string',\n        required: true,\n        description: 'Replacement text (empty string deletes).',\n      },\n    },\n    appliesTo: ['document', 'presentation'],\n    output: 'media',\n  },\n  {\n    id: 'diff',\n    description:\n      'Compare this media against another; returns a structured diff whose patch text feeds apply_patch directly.',\n    args: {\n      with: {\n        type: 'media-ref',\n        required: true,\n        description: 'The media to compare against, as an @id ref.',\n      },\n    },\n    appliesTo: ['document', 'spreadsheet', 'presentation'],\n    output: 'json',\n  },\n  {\n    id: 'apply_patch',\n    description:\n      'Apply a patch to the media text: a unified diff (as produced by the diff verb — that output feeds this verb directly), or a structured \"*** Begin Patch\" envelope (Add/Delete/Update File) for multi-file changes. In the structured envelope, add-file content lines must start with \"+\" (the unified-diff convention).',\n    args: {\n      patch: {\n        type: 'string',\n        required: true,\n        description:\n          'The patch content: unified diff, or a structured envelope starting with \"*** Begin Patch\". Add-file content lines must start with \"+\".',\n      },\n      with: {\n        type: 'media-ref-list',\n        description: 'Optional additional context media, as @id refs.',\n      },\n    },\n    appliesTo: ['document'],\n    output: 'media',\n  },\n  {\n    id: 'append',\n    description: 'Append text to text-family media (txt/md/csv/yaml).',\n    args: {\n      text: { type: 'string', required: true, description: 'The text to append.' },\n      newline: {\n        type: 'boolean',\n        description: 'Terminate with a newline (and separate from existing content). Default true.',\n      },\n    },\n    appliesTo: ['document', 'spreadsheet'],\n    output: 'media',\n  },\n  // ── data namespace (JSON/YAML structural ops) ───────────────────────────────\n  {\n    id: 'data.set',\n    description: 'Set a value at a path in JSON/YAML media (creates missing containers).',\n    args: {\n      path: {\n        type: 'string',\n        required: true,\n        description: 'Dot/bracket path, e.g. a.b[2].c',\n      },\n      value: {\n        type: 'string',\n        required: true,\n        description: \"JSON-encoded value: '42', '\\\"text\\\"', '{\\\"k\\\":1}'. Bare strings accepted.\",\n      },\n    },\n    appliesTo: ['document'],\n    output: 'media',\n  },\n  {\n    id: 'data.merge',\n    description: 'Merge a JSON object fragment into JSON/YAML media.',\n    args: {\n      fragment: {\n        type: 'string',\n        required: true,\n        description: 'The JSON object to merge, e.g. \\'{\"a\":{\"b\":1}}\\'.',\n      },\n      strategy: {\n        type: 'enum',\n        values: ['deep', 'shallow'],\n        description: 'Merge strategy. Default deep.',\n      },\n    },\n    appliesTo: ['document'],\n    output: 'media',\n  },\n  {\n    id: 'data.delete',\n    description: 'Delete a key or array element at a path in JSON/YAML media.',\n    args: {\n      path: {\n        type: 'string',\n        required: true,\n        description: 'Dot/bracket path of the key/element to remove.',\n      },\n    },\n    appliesTo: ['document'],\n    output: 'media',\n  },\n  // ── root: extraction ────────────────────────────────────────────────────────\n  {\n    id: 'extract.text',\n    description:\n      'Extract text from any supported media (document, spreadsheet, image). To limit pages: select pages=… | extract text.',\n    args: {\n      ocr: {\n        type: 'enum',\n        values: ['off', 'auto', 'force'],\n        description: 'OCR behavior. Default auto (OCR only when there is no text layer).',\n      },\n      ocr_out: {\n        type: 'enum',\n        values: ['txt', 'hocr', 'json'],\n        description: 'OCR output structure when OCR runs. Default txt.',\n      },\n      lang: {\n        type: 'string-list',\n        description: 'OCR language hint(s), e.g. lang=eng,deu. Quote tags with dashes.',\n      },\n    },\n    appliesTo: ['document', 'spreadsheet', 'presentation', 'image'],\n    output: 'text',\n  },\n  {\n    id: 'extract.metadata',\n    description: 'Extract document metadata (author, dates, page count) as JSON.',\n    args: {},\n    appliesTo: ['document', 'spreadsheet', 'presentation', 'image', 'audio'],\n    output: 'json',\n  },\n  {\n    id: 'extract.assets',\n    description: 'Extract embedded assets (images, fonts, attachments) as separate media.',\n    args: {\n      types: {\n        type: 'string-list',\n        values: ['image', 'font', 'attachment', 'all'],\n        description: 'Asset kinds to extract. Default all.',\n      },\n      format: {\n        type: 'enum',\n        values: IMAGE_FORMATS,\n        description:\n          'Re-encode extracted images to this format. Default: native encoding as stored.',\n      },\n    },\n    appliesTo: ['document', 'presentation', 'spreadsheet'],\n    output: 'media-list',\n  },\n  {\n    id: 'chunk',\n    description: 'Split extracted text into chunks for retrieval/indexing.',\n    args: {\n      by: {\n        type: 'enum',\n        values: ['sentence', 'paragraph', 'fixed'],\n        description: 'Chunking strategy. Default paragraph.',\n      },\n      size: {\n        type: 'number',\n        min: 1,\n        description: 'Chunk size for fixed strategy / max size otherwise.',\n      },\n      overlap: {\n        type: 'number',\n        min: 0,\n        description: 'Overlap between consecutive chunks.',\n      },\n    },\n    appliesTo: ['document', 'any'],\n    output: 'json',\n  },\n  // ── sheet namespace ─────────────────────────────────────────────────────────\n  {\n    id: 'sheet.add_rows',\n    description: 'Insert rows into a worksheet.',\n    args: {\n      sheet: {\n        type: 'name-or-index',\n        description: 'Target worksheet: bare number = 1-based index, quoted string = name.',\n      },\n      rows: {\n        type: 'json',\n        required: true,\n        description: 'Rows as a JSON array of arrays of cell values, e.g. \\'[[\"a\",1],[\"b\",2]]\\'.',\n      },\n      before: { type: 'number', min: 1, description: 'Insert before this 1-based row.' },\n      after: { type: 'number', min: 1, description: 'Insert after this 1-based row.' },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.add_columns',\n    description: 'Insert columns into a worksheet.',\n    args: {\n      sheet: { type: 'name-or-index', description: 'Target worksheet (index or quoted name).' },\n      headers: {\n        type: 'string-list',\n        description: 'Header names for the new columns (values empty).',\n      },\n      columns: {\n        type: 'json',\n        description: 'Full column descriptors as JSON: \\'[{\"header\":\"X\",\"values\":[1,2]}]\\'.',\n      },\n      before: { type: 'number', min: 1, description: 'Insert before this 1-based column.' },\n      after: { type: 'number', min: 1, description: 'Insert after this 1-based column.' },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.update_cells',\n    description: 'Update specific cells.',\n    args: {\n      sheet: { type: 'name-or-index', description: 'Target worksheet (index or quoted name).' },\n      updates: {\n        type: 'json',\n        required: true,\n        description:\n          'JSON array of updates: \\'[{\"address\":\"B2\",\"value\":42}]\\' or \\'[{\"row\":2,\"col\":3,\"value\":\"x\"}]\\'.',\n      },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.delete_rows',\n    description: 'Delete rows by 1-based index.',\n    args: {\n      sheet: { type: 'name-or-index', description: 'Target worksheet (index or quoted name).' },\n      rows: {\n        type: 'number-list',\n        required: true,\n        min: 1,\n        description: '1-based row indices to delete.',\n      },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.delete_columns',\n    description: 'Delete columns by 1-based index.',\n    args: {\n      sheet: { type: 'name-or-index', description: 'Target worksheet (index or quoted name).' },\n      columns: {\n        type: 'number-list',\n        required: true,\n        min: 1,\n        description: '1-based column indices to delete.',\n      },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.rename_sheet',\n    description: 'Rename a worksheet. The target must be a sheet NAME (quote it).',\n    args: {\n      sheet: {\n        type: 'string',\n        required: true,\n        description: 'Current sheet name (names only for rename; quote it).',\n      },\n      to: { type: 'string', required: true, description: 'New sheet name.' },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.add_sheet',\n    description: 'Add a new worksheet.',\n    args: {\n      name: { type: 'string', required: true, description: 'Name for the new worksheet.' },\n      at: { type: 'number', min: 1, description: 'Insert at this 1-based position.' },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.remove_sheet',\n    description: 'Remove a worksheet. The target must be a sheet NAME (quote it).',\n    args: {\n      sheet: {\n        type: 'string',\n        required: true,\n        description: 'Sheet name to remove (names only; quote it).',\n      },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.reorder_sheets',\n    description: 'Reorder worksheets.',\n    args: {\n      order: {\n        type: 'json',\n        required: true,\n        description:\n          'JSON array of sheet names and/or 1-based indices in the new order: \\'[\"Summary\",2,3]\\'.',\n      },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  {\n    id: 'sheet.transform_table',\n    description: 'Rename/select/drop table columns by header name.',\n    args: {\n      sheet: { type: 'name-or-index', description: 'Target worksheet (index or quoted name).' },\n      header_row: { type: 'number', min: 1, description: '1-based header row. Default 1.' },\n      select: { type: 'string-list', description: 'Column headers to keep.' },\n      drop: { type: 'string-list', description: 'Column headers to drop.' },\n      rename: {\n        type: 'json',\n        description: 'JSON array of renames: \\'[{\"from\":\"Old\",\"to\":\"New\"}]\\'.',\n      },\n    },\n    requires: { capability: 'edit' },\n    appliesTo: ['spreadsheet'],\n    output: 'media',\n  },\n  // ── slides namespace ────────────────────────────────────────────────────────\n  {\n    id: 'slides.add',\n    description: 'Add a new slide.',\n    args: {\n      at: { type: 'number', min: 1, description: 'Insert at this 1-based position.' },\n      title: { type: 'string', description: 'Title text for the new slide.' },\n      layout: { type: 'string', description: 'Layout name (template-dependent).' },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.update_text',\n    description: 'Update text on a slide.',\n    args: {\n      slide: {\n        type: 'name-or-index',\n        description: 'Target slide: bare number = 1-based index, quoted string = title.',\n      },\n      placeholder: { type: 'string', description: 'Placeholder/shape to target.' },\n      text: { type: 'string', required: true, description: 'Replacement text.' },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.update_table',\n    description: 'Update table cells on a slide.',\n    args: {\n      slide: { type: 'name-or-index', description: 'Target slide (index or quoted title).' },\n      updates: {\n        type: 'json',\n        required: true,\n        description: 'JSON array: \\'[{\"row\":1,\"col\":2,\"value\":\"x\"}]\\' (1-based).',\n      },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.update_image',\n    description: 'Replace an image on a slide with another media.',\n    args: {\n      slide: { type: 'name-or-index', description: 'Target slide (index or quoted title).' },\n      placeholder: { type: 'string', description: 'Placeholder/shape to target.' },\n      with: {\n        type: 'media-ref',\n        required: true,\n        description: 'The replacement image, as an @id ref.',\n      },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.update_chart',\n    description: 'Update chart data on a slide.',\n    args: {\n      slide: { type: 'name-or-index', description: 'Target slide (index or quoted title).' },\n      data: {\n        type: 'json',\n        description: 'JSON array-of-arrays of chart data: \\'[[\"Q1\",10],[\"Q2\",20]]\\'.',\n      },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.delete',\n    description: 'Delete slides by 1-based index.',\n    args: {\n      slides: {\n        type: 'number-list',\n        required: true,\n        min: 1,\n        description: '1-based slide indices to delete.',\n      },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.reorder',\n    description: 'Reorder slides.',\n    args: {\n      order: {\n        type: 'number-list',\n        required: true,\n        min: 1,\n        description: 'New order of existing 1-based slide indices.',\n      },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  {\n    id: 'slides.duplicate',\n    description: 'Duplicate a slide.',\n    args: {\n      slide: { type: 'number', required: true, min: 1, description: '1-based slide to copy.' },\n      at: { type: 'number', min: 1, description: 'Insert the copy at this position.' },\n    },\n    appliesTo: ['presentation'],\n    output: 'media',\n  },\n  // ── image namespace (split verbs; runtime fuses adjacent image.* steps) ─────\n  {\n    id: 'image.resize',\n    description: 'Resize the image.',\n    args: {\n      width: { type: 'number', min: 1, max: 16384, description: 'Target width in px.' },\n      height: { type: 'number', min: 1, max: 16384, description: 'Target height in px.' },\n      fit: {\n        type: 'enum',\n        values: ['cover', 'contain', 'fill', 'inside', 'outside'],\n        description: 'Resize fit mode. Default cover.',\n      },\n    },\n    requires: { capability: 'mutate' },\n    appliesTo: ['image'],\n    output: 'media',\n  },\n  {\n    id: 'image.format',\n    description: 'Re-encode the image to another format.',\n    args: {\n      to: {\n        type: 'enum',\n        required: true,\n        values: IMAGE_FORMATS,\n        description: 'Target image format.',\n      },\n      quality: { type: 'number', min: 1, max: 100, description: 'Quality for lossy formats.' },\n      strip_metadata: {\n        type: 'boolean',\n        description: 'Remove EXIF/ICC metadata from the output.',\n      },\n    },\n    requires: { capability: 'mutate' },\n    appliesTo: ['image'],\n    output: 'media',\n  },\n  {\n    id: 'image.rotate',\n    description: 'Rotate the image.',\n    args: {\n      deg: {\n        type: 'enum',\n        required: true,\n        values: ['90', '180', '270'],\n        description: 'Rotation in degrees (clockwise).',\n      },\n    },\n    requires: { capability: 'mutate' },\n    appliesTo: ['image'],\n    output: 'media',\n  },\n  {\n    id: 'image.flip',\n    description: 'Flip the image.',\n    args: {\n      axis: {\n        type: 'enum',\n        required: true,\n        values: ['horizontal', 'vertical', 'both'],\n        description: 'Flip axis.',\n      },\n    },\n    requires: { capability: 'mutate' },\n    appliesTo: ['image'],\n    output: 'media',\n  },\n  {\n    id: 'image.strip_metadata',\n    description: 'Remove EXIF/ICC metadata from the image without other changes.',\n    args: {},\n    requires: { capability: 'mutate' },\n    appliesTo: ['image'],\n    output: 'media',\n  },\n  {\n    id: 'image.annotate',\n    description: 'Draw vector shapes and text over the image.',\n    args: {\n      shapes: {\n        type: 'json',\n        required: true,\n        description: 'Array of rect, line, arrow, ellipse, or text primitives.',\n      },\n    },\n    requires: { capability: 'mutate' },\n    appliesTo: ['image'],\n    output: 'media',\n  },\n  // ── audio namespace ─────────────────────────────────────────────────────────\n  {\n    id: 'audio.transcribe',\n    description: 'Transcribe speech to text.',\n    args: {\n      lang: {\n        type: 'string',\n        description: 'Language hint, e.g. lang=en. Quote tags with dashes: lang=\"en-US\".',\n      },\n      out: {\n        type: 'enum',\n        values: ['txt', 'srt', 'vtt', 'json'],\n        description: 'Output format. Default txt. srt/vtt produce subtitles.',\n      },\n      translate: {\n        type: 'boolean',\n        description: 'Translate the transcription to English.',\n      },\n    },\n    requires: { capability: 'convert', from: PCM_MIME },\n    appliesTo: ['audio'],\n    output: 'text',\n  },\n] as const\n\n/** Map of canonical verb id → spec, for direct lookup. */\nexport const VERB_INDEX: ReadonlyMap<string, VerbSpec> = new Map(VERBS.map((v) => [v.id, v]))\n\n/**\n * Fold a verb token sequence to canonical form: lowercase, separators (space/`_`/`.`)\n * normalized so `extract_text` ≡ `extract text` ≡ `extract.text` all match `extract.text`.\n *\n * @param words - The verb word tokens as written (1 or 2 words, possibly containing `_`/`.`).\n * @returns The canonical verb id when a fold-match exists, otherwise `undefined`.\n */\nexport const foldVerb = (words: string[]): string | undefined => {\n  const flat = words\n    .join(' ')\n    .toLowerCase()\n    .replace(/[._\\s]+/g, ' ')\n    .trim()\n  return FOLDED_INDEX.get(flat)\n}\n\n/** Internal: folded \"word word\" form → canonical id. */\nconst FOLDED_INDEX: ReadonlyMap<string, string> = (() => {\n  const map = new Map<string, string>()\n  for (const v of VERBS) {\n    const folded = v.id.replace(/[._]+/g, ' ')\n    if (map.has(folded)) {\n      throw new Error(`verb table invariant violated: \"${folded}\" folds to multiple verbs`)\n    }\n    map.set(folded, v.id)\n  }\n  return map\n})()\n\n/**\n * All folded verb word-sequences, for the parser's longest-match verb recognition and for\n * generated grammar text.\n */\nexport const FOLDED_VERBS: readonly string[] = Array.from(FOLDED_INDEX.keys())\n\n/**\n * Suggest the nearest verbs to an unknown input, for did-you-mean errors. Matches whole folded\n * forms AND suffix words (`resize` suggests `image resize`), per the frozen error model.\n *\n * @param input - The unknown verb text as written.\n * @param candidates - The folded verb forms to search (pass the narrowed set to avoid\n *   suggesting unconfigured verbs).\n * @returns Up to three suggestions, best first.\n */\nexport const suggestVerbs = (input: string, candidates: readonly string[]): string[] => {\n  const folded = input\n    .toLowerCase()\n    .replace(/[._\\s]+/g, ' ')\n    .trim()\n  const scored: Array<{ name: string; score: number }> = []\n  for (const cand of candidates) {\n    const direct = levenshtein(folded, cand)\n    const words = cand.split(' ')\n    const suffix = words.length > 1 ? levenshtein(folded, words[words.length - 1]) : Infinity\n    const score = Math.min(direct, suffix)\n    if (score <= Math.max(2, Math.floor(folded.length / 3))) {\n      scored.push({ name: cand, score })\n    }\n  }\n  scored.sort((a, b) => a.score - b.score)\n  return scored.slice(0, 3).map((s) => s.name)\n}\n\n/** Classic two-row Levenshtein distance. */\nconst levenshtein = (a: string, b: string): number => {\n  if (a === b) return 0\n  if (a.length === 0) return b.length\n  if (b.length === 0) return a.length\n  let prev = Array.from({ length: b.length + 1 }, (_, i) => i)\n  let curr = new Array<number>(b.length + 1)\n  for (let i = 1; i <= a.length; i++) {\n    curr[0] = i\n    for (let j = 1; j <= b.length; j++) {\n      const cost = a[i - 1] === b[j - 1] ? 0 : 1\n      curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost)\n    }\n    ;[prev, curr] = [curr, prev]\n  }\n  return prev[b.length]\n}\n","/**\n * The semantic validator: checks raw parsed segments (or ops) against the verb table and the\n * deployment's configured engines, producing the validated {@link MediaPlan} or a\n * model-actionable error.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/media` entry. This is the layer no parser\n * toolkit could supply — every error names what was wrong, suggests the nearest valid form,\n * and shows a corrective exemplar (frozen design 0.14). Engine narrowing happens HERE, never\n * at parse time (frozen 0.3): the same string parses identically in every deployment; only\n * validation differs.\n */\n\nimport { isMediaRef, isRegExpRef } from './plan'\nimport { isError, isObject } from '@nhtio/adk/guards'\nimport { VERB_INDEX, suggestVerbs, foldVerb } from './verbs'\nimport {\n  E_MEDIA_UNKNOWN_VERB,\n  E_MEDIA_UNKNOWN_ARG,\n  E_MEDIA_BAD_ARG,\n  E_MEDIA_MISSING_ARG,\n  E_MEDIA_ENGINE_REQUIRED,\n} from './exceptions'\nimport type { RawSegment, RawArgValue } from './pipe'\nimport type { VerbSpec, VerbArgSpec, VerbRequirement } from './verbs'\nimport type { MediaPlan, MediaStep, MediaArgValue, MediaArgScalar, MediaOp } from './plan'\n\n/**\n * The minimal synchronous capability probe the validator narrows against. The pipeline's\n * engine registry implements it; tests stub it.\n */\nexport interface CapabilityProbe {\n  /** `true` when some engine declares a matching convert edge (omit either side for \"any\"). */\n  hasConvert(from?: string, to?: string): boolean\n  /** `true` when some engine declares a mutate capability. */\n  hasMutate(): boolean\n  /**\n   * `true` when some engine declares a matching edit capability (omit both for \"any\").\n   * Optional so existing probe stubs stay valid; absent means \"no edit engines\".\n   */\n  hasEdit?(mime?: string, op?: string): boolean\n}\n\n/** Options for {@link validateSegments} / {@link validateOps}. */\nexport interface ValidateOptions {\n  /** The deployment's capabilities. Narrows advertised verbs + error suggestions. */\n  capabilities: CapabilityProbe\n}\n\n/** `true` when the deployment satisfies a verb's capability requirement. */\nconst satisfies = (capabilities: CapabilityProbe, requires: VerbRequirement): boolean => {\n  if (requires.capability === 'mutate') return capabilities.hasMutate()\n  if (requires.capability === 'edit') return capabilities.hasEdit?.(undefined, requires.op) ?? false\n  return capabilities.hasConvert(requires.from, requires.to)\n}\n\n/** A human phrase for an unmet requirement, for the do-not-retry error. */\nconst requirementText = (requires: VerbRequirement): string => {\n  if (requires.capability === 'mutate') return 'an engine that can mutate this media'\n  if (requires.capability === 'edit') {\n    return `an engine that can edit this media${requires.op ? ` (op \"${requires.op}\")` : ''}`\n  }\n  const from = requires.from ? ` from ${requires.from}` : ''\n  const to = requires.to ? ` to ${requires.to}` : ''\n  return `an engine that can convert${from}${to}`\n}\n\n/** The folded verb forms available under a given capability configuration. */\nexport const availableVerbs = (capabilities: CapabilityProbe): string[] => {\n  const out: string[] = []\n  for (const [id, spec] of VERB_INDEX) {\n    if (spec.requires && !satisfies(capabilities, spec.requires)) continue\n    out.push(id.replace(/[._]+/g, ' '))\n  }\n  return out\n}\n\nconst levSuggest = (verbText: string, capabilities: CapabilityProbe): string => {\n  const suggestions = suggestVerbs(verbText, availableVerbs(capabilities))\n  return suggestions.length > 0 ? ` did you mean \"${suggestions[0]}\"?` : ''\n}\n\nconst verbList = (capabilities: CapabilityProbe): string => availableVerbs(capabilities).join(', ')\n\nconst resolveVerb = (\n  verbText: string,\n  capabilities: CapabilityProbe,\n  position: number\n): VerbSpec => {\n  const canonical = foldVerb(verbText.split(' ')) ?? verbText\n  const spec = VERB_INDEX.get(canonical)\n  if (!spec) {\n    throw new E_MEDIA_UNKNOWN_VERB([\n      `unknown verb \"${verbText}\" at segment ${position}.${levSuggest(verbText, capabilities)} Available verbs: ${verbList(capabilities)}`,\n    ])\n  }\n  if (spec.requires && !satisfies(capabilities, spec.requires)) {\n    throw new E_MEDIA_ENGINE_REQUIRED([\n      `verb \"${verbText}\" requires ${requirementText(spec.requires)}, and none is configured in this deployment. Do not retry this verb here. Available verbs: ${verbList(capabilities)}`,\n    ])\n  }\n  return spec\n}\n\nconst suggestArg = (name: string, spec: VerbSpec): string => {\n  const candidates = Object.keys(spec.args)\n  const ranked = suggestVerbs(name, candidates)\n  return ranked.length > 0 ? ` did you mean \"${ranked[0]}\"?` : ''\n}\n\nconst argList = (spec: VerbSpec): string => {\n  const names = Object.keys(spec.args)\n  return names.length > 0 ? names.join(', ') : '(none)'\n}\n\nconst exemplar = (spec: VerbSpec): string => {\n  const verb = spec.id.replace(/\\./g, ' ')\n  const parts: string[] = [verb]\n  for (const [name, arg] of Object.entries(spec.args)) {\n    if (!arg.required) continue\n    parts.push(`${name}=${exampleValue(arg)}`)\n  }\n  return parts.join(' ')\n}\n\nconst exampleValue = (arg: VerbArgSpec): string => {\n  switch (arg.type) {\n    case 'enum':\n      return arg.values?.[0] ?? 'value'\n    case 'number':\n      return String(arg.min ?? 1)\n    case 'number-list':\n      return '1-3,5'\n    case 'string-list':\n      return 'a,b'\n    case 'boolean':\n      return 'true'\n    case 'regex-or-string-list':\n      return '\"literal text\"'\n    case 'media-ref':\n      return '@<media id>'\n    case 'media-ref-list':\n      return '@<media id>'\n    case 'json':\n      return `'[…]'`\n    default:\n      return '\"value\"'\n  }\n}\n\n/** Coerce + check one arg value against its spec. Returns the IR-final value. */\nconst checkArg = (\n  verb: VerbSpec,\n  name: string,\n  raw: { value: MediaArgValue; quoted: boolean }\n): MediaArgValue => {\n  const spec = verb.args[name]\n  const verbText = verb.id.replace(/\\./g, ' ')\n  const where = `arg \"${name}\" on \"${verbText}\"`\n  const bad = (msg: string): never => {\n    throw new E_MEDIA_BAD_ARG([`${where}: ${msg}. Write it like: ${exemplar(verb)}`])\n  }\n  const v = raw.value\n  switch (spec.type) {\n    case 'name-or-index': {\n      if (typeof v === 'number') {\n        if (!Number.isInteger(v) || v < 1) bad('indices are 1-based integers')\n        return v\n      }\n      if (typeof v !== 'string') bad('expected a 1-based index or a quoted name')\n      return v\n    }\n    case 'string': {\n      if (typeof v === 'number' && !raw.quoted) return String(v)\n      if (typeof v !== 'string')\n        bad(`expected text${typeof v === 'object' ? ', got a structured value' : ''}`)\n      return v\n    }\n    case 'number': {\n      if (typeof v !== 'number') bad('expected a number')\n      const n = v as number\n      if (spec.min !== undefined && n < spec.min) bad(`must be ≥ ${spec.min} (indices are 1-based)`)\n      if (spec.max !== undefined && n > spec.max) bad(`must be ≤ ${spec.max}`)\n      return n\n    }\n    case 'boolean': {\n      if (typeof v !== 'boolean') bad('expected true or false')\n      return v\n    }\n    case 'enum': {\n      const s = typeof v === 'number' ? String(v) : v\n      if (typeof s !== 'string' || !spec.values?.includes(s)) {\n        bad(`\"${String(v)}\" is not valid; valid values: ${spec.values?.join(', ')}`)\n      }\n      return s as string\n    }\n    case 'number-list': {\n      const arr = Array.isArray(v) ? v : [v]\n      if (!arr.every((x): x is number => typeof x === 'number'))\n        bad('expected numbers (e.g. 1-3,5)')\n      const nums = arr as number[]\n      if (spec.min !== undefined && nums.some((n) => n < (spec.min as number))) {\n        bad(`values must be ≥ ${spec.min} (indices are 1-based)`)\n      }\n      return nums\n    }\n    case 'string-list': {\n      const arr = Array.isArray(v) ? v : [v]\n      if (!arr.every((x): x is string => typeof x === 'string'))\n        bad('expected names (quote values with special characters)')\n      const strs = arr as string[]\n      if (spec.values && !strs.every((s) => spec.values?.includes(s))) {\n        bad(`valid values: ${spec.values.join(', ')}`)\n      }\n      return strs\n    }\n    case 'regex-or-string-list': {\n      if (isRegExpRef(v)) return v\n      const arr = Array.isArray(v) ? v : [v]\n      if (arr.every((x) => typeof x === 'string' || isRegExpRef(x))) return arr as MediaArgScalar[]\n      bad('expected literal text, a list of literals, or a /regex/')\n      break\n    }\n    case 'media-ref': {\n      if (isMediaRef(v)) return v\n      bad('expected a media reference: with=@<media id> (get ids from list_media)')\n      break\n    }\n    case 'media-ref-list': {\n      const arr = Array.isArray(v) ? v : [v]\n      if (arr.every(isMediaRef)) return arr as MediaArgScalar[]\n      bad('expected media references: with=@<id>,@<id> (get ids from list_media)')\n      break\n    }\n    case 'json': {\n      // From pipe: a quoted string containing JSON. From ops: already-structured JSON.\n      if (typeof v === 'string') {\n        if (!raw.quoted) bad(`expected a quoted JSON value, e.g. ${name}='[…]'`)\n        try {\n          return JSON.parse(v) as MediaArgValue\n        } catch (err) {\n          const detail = isError(err) ? err.message : String(err)\n          bad(`the quoted value is not valid JSON (${detail})`)\n        }\n      }\n      if (isObject(v) || Array.isArray(v)) return v\n      bad(`expected a JSON value, e.g. ${name}='[…]'`)\n      break\n    }\n  }\n  /* unreachable */\n  throw new E_MEDIA_BAD_ARG([`${where}: invalid value`])\n}\n\nconst checkStep = (\n  spec: VerbSpec,\n  args: ReadonlyMap<string, { value: MediaArgValue; quoted: boolean }>\n): MediaStep => {\n  const verbText = spec.id.replace(/\\./g, ' ')\n  const finalArgs: Record<string, MediaArgValue> = {}\n  for (const [name, raw] of args) {\n    if (!(name in spec.args)) {\n      throw new E_MEDIA_UNKNOWN_ARG([\n        `verb \"${verbText}\" has no arg \"${name}\".${suggestArg(name, spec)} Args: ${argList(spec)}. Write it like: ${exemplar(spec)}`,\n      ])\n    }\n    finalArgs[name] = checkArg(spec, name, raw)\n  }\n  for (const [name, argSpec] of Object.entries(spec.args)) {\n    if (argSpec.required && !(name in finalArgs)) {\n      throw new E_MEDIA_MISSING_ARG([\n        `verb \"${verbText}\" requires arg \"${name}\" (${argSpec.description}). Write it like: ${exemplar(spec)}`,\n      ])\n    }\n  }\n  return { verb: spec.id, args: finalArgs }\n}\n\n/**\n * Validate raw pipe segments into a {@link MediaPlan}.\n *\n * @param segments - Output of `parsePipeRaw`.\n * @param options - The deployment's capability probe.\n * @returns The validated plan, spans preserved.\n */\nexport const validateSegments = (\n  segments: readonly RawSegment[],\n  options: ValidateOptions\n): MediaPlan => {\n  const steps: MediaStep[] = []\n  segments.forEach((seg, i) => {\n    const spec = resolveVerb(seg.verb.replace(/\\./g, ' '), options.capabilities, i + 1)\n    const step = checkStep(spec, seg.args)\n    step.span = seg.span\n    steps.push(step)\n  })\n  return { steps }\n}\n\n/**\n * Validate a JSON ops array into a {@link MediaPlan}. The same checks as the pipe path —\n * verbs fold the same way, args validate against the same specs — so the two front-ends\n * produce identical plans for equivalent statements.\n *\n * @param ops - The ops array.\n * @param options - The deployment's capability probe.\n * @returns The validated plan (no spans).\n */\nexport const validateOps = (ops: readonly MediaOp[], options: ValidateOptions): MediaPlan => {\n  const steps: MediaStep[] = []\n  ops.forEach((op, i) => {\n    const spec = resolveVerb(op.verb.replace(/[._]+/g, ' '), options.capabilities, i + 1)\n    const args = new Map<string, RawArgValue>(\n      Object.entries(op.args).map(([k, v]) => [\n        k,\n        {\n          value: v,\n          quoted: typeof v === 'string',\n          span: { offset: 0, line: 1, col: 1, length: 0 },\n        },\n      ])\n    )\n    steps.push(checkStep(spec, args))\n  })\n  return { steps }\n}\n"],"mappings":"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"}