{"version":3,"file":"spooled_markdown_artifact-vd6eNtIP.mjs","names":["#format","#resolveFormat","#resolveRecords","#parsed","#resolveIndex","#index","#frontmatter"],"sources":["../src/lib/classes/spooled_json_artifact.ts","../src/lib/classes/spooled_markdown_artifact.ts"],"sourcesContent":["import { default as JSON5 } from 'json5'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { isInstanceOf, isObject } from '../utils/guards'\nimport { resolveSpoolReader } from '../contracts/reader_resolvers'\nimport { ENCODE_METHOD, DECODE_METHOD } from '../utils/encoder_symbols'\nimport {\n  SpooledArtifact,\n  defaultSerialise,\n  collectArtifactCompatibleIds,\n  resolveArtifactById,\n} from './spooled_artifact'\nimport type { AdkEncodableSnapshot } from './encodable'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\nimport type { ReaderDescriptor } from '../contracts/reader_descriptor'\n\n/**\n * The set of JSON-derived formats that {@link SpooledJsonArtifact} can handle.\n *\n * @remarks\n * - `json` — a single JSON value spanning the entire artifact (strict RFC 8259).\n * - `json5` — a single JSON5 value spanning the entire artifact; permits comments, trailing\n *   commas, unquoted keys, and other relaxed syntax via the `json5` package.\n * - `jsonl` — newline-delimited JSON; each non-empty line is an independent JSON value.\n * - `ndjson` — alias for `jsonl`; both names are accepted and behave identically.\n */\nexport type JsonArtifactFormat = 'json' | 'json5' | 'jsonl' | 'ndjson'\n\n/**\n * Detects the {@link JsonArtifactFormat} of a raw string.\n *\n * @remarks\n * Detection strategy (in order):\n * 1. If the content parses as strict JSON → `json`.\n * 2. If every non-empty line parses as strict JSON → `jsonl`.\n * 3. If the content parses as JSON5 → `json5`.\n * 4. Otherwise throws.\n *\n * Strict JSON is tried before JSON5 so that well-formed JSON files are not unnecessarily\n * classified as JSON5.\n *\n * @param content - The full artifact text to inspect.\n * @returns The inferred format.\n * @throws `Error` when the content cannot be classified as any supported JSON format.\n */\nfunction inferFormat(content: string): JsonArtifactFormat {\n  const trimmed = content.trim()\n\n  // 1. Try strict JSON\n  try {\n    JSON.parse(trimmed)\n    return 'json'\n  } catch {\n    // fall through\n  }\n\n  // 2. Try JSONL (every non-empty line is valid JSON)\n  const nonEmptyLines = trimmed.split('\\n').filter((l) => l.trim().length > 0)\n  if (\n    nonEmptyLines.length > 0 &&\n    nonEmptyLines.every((l) => {\n      try {\n        JSON.parse(l)\n        return true\n      } catch {\n        return false\n      }\n    })\n  ) {\n    return 'jsonl'\n  }\n\n  // 3. Try JSON5\n  try {\n    JSON5.parse(trimmed)\n    return 'json5'\n  } catch {\n    // fall through\n  }\n\n  throw new Error('Unable to infer JSON format: content is not valid JSON, JSONL, NDJSON, or JSON5')\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds JSON-aware read operations.\n *\n * @typeParam T - The expected shape of each parsed record. Defaults to `unknown`.\n *\n * @remarks\n * Construct with an optional `format` hint. When omitted the format is auto-detected on first\n * access by reading the full artifact and inferring the format. Once detected (or\n * provided), the format is cached for the lifetime of the instance.\n *\n * All JSON methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`json_get`, `json_filter`, `json_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions. Full JSONPath syntax\n * is supported, including recursive descent (`..`), filter expressions (`[?(@.age > 18)]`),\n * and union selectors.\n */\nexport class SpooledJsonArtifact<T = unknown> extends SpooledArtifact {\n  #format: JsonArtifactFormat | undefined\n  #parsed: T[] | undefined\n\n  /**\n   * @param reader - The backing store to read from.\n   * @param format - Optional format hint. When omitted, the format is inferred on first access.\n   */\n  constructor(reader: SpoolReader, format?: JsonArtifactFormat) {\n    super(reader)\n    this.#format = format\n  }\n\n  /**\n   * Returns `true` if `value` is a {@link SpooledJsonArtifact} instance.\n   *\n   * @remarks\n   * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n   * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n   * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n   * `SpooledJsonArtifact` classes coexist in the same realm.\n   *\n   * @param value - The value to test.\n   * @returns `true` when `value` is a {@link SpooledJsonArtifact} instance.\n   */\n  public static isSpooledJsonArtifact(value: unknown): value is SpooledJsonArtifact {\n    return isInstanceOf(value, 'SpooledJsonArtifact', SpooledJsonArtifact)\n  }\n\n  /**\n   * The JSON-specific artifact-query descriptors this class adds on top of the base set.\n   *\n   * @remarks\n   * Lists `artifact_json_type`, `artifact_json_keys`, `artifact_json_length`,\n   * `artifact_json_get`, `artifact_json_filter`, `artifact_json_slice`, `artifact_json_pluck`.\n   * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n   * forged separately by {@link SpooledJsonArtifact.forgeTools}, which calls\n   * `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then registers\n   * its own JSON tools on the result. Downstream consumers building custom subclasses\n   * should follow the same pattern: own only your own descriptors; override `forgeTools` to\n   * compose with the base output.\n   */\n  public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n    {\n      name: 'artifact_json_type',\n      method: 'json_type',\n      description:\n        'Return the JSON format (json | json5 | jsonl | ndjson) of a JSON artifact produced earlier in this turn.',\n      argsSchema: validator.object({}),\n    },\n    {\n      name: 'artifact_json_keys',\n      method: 'json_keys',\n      description: 'Return the top-level keys of a JSON artifact produced earlier in this turn.',\n      argsSchema: validator.object({}),\n    },\n    {\n      name: 'artifact_json_length',\n      method: 'json_length',\n      description:\n        'Return the record count of a JSON artifact produced earlier in this turn (1 for json/json5; line count for jsonl/ndjson).',\n      argsSchema: validator.object({}),\n    },\n    {\n      name: 'artifact_json_get',\n      method: 'json_get',\n      description:\n        'Evaluate a JSONPath expression against a JSON artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        path: validator.string().required().description(\"JSONPath expression, e.g. '$.user.name'.\"),\n      }),\n    },\n    {\n      name: 'artifact_json_filter',\n      method: 'json_filter',\n      description:\n        'Return records of a JSON artifact (produced earlier in this turn) matched by a JSONPath filter.',\n      argsSchema: validator.object({\n        path: validator\n          .string()\n          .required()\n          .description(\"JSONPath filter expression, e.g. '$[?(@.age>18)]'.\"),\n      }),\n    },\n    {\n      name: 'artifact_json_slice',\n      method: 'json_slice',\n      description:\n        'Return a slice of records by index range from a JSON artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        start: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('Start index (inclusive).'),\n        end: validator.number().integer().min(0).optional().description('End index (exclusive).'),\n      }),\n    },\n    {\n      name: 'artifact_json_pluck',\n      method: 'json_pluck',\n      description:\n        'Return all values matched by a JSONPath expression across every record of a JSON artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        path: validator.string().required().description(\"JSONPath expression, e.g. '$..name'.\"),\n      }),\n    },\n  ])\n\n  /**\n   * Forges base-class tools plus JSON-specific tools narrowed to {@link SpooledJsonArtifact}.\n   *\n   * @remarks\n   * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n   * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n   * register one `ArtifactTool` per JSON-specific descriptor narrowed to JSON artifacts.\n   * Downstream consumers building their own subclasses should follow the same shape.\n   */\n  public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n    const registry = SpooledArtifact.forgeTools(ctx)\n    const requires = SpooledJsonArtifact\n    const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n    if (compatibleIds.length === 0) return registry\n\n    for (const descriptor of this.toolMethods) {\n      const callIdSchema = validator\n        .string()\n        .valid(...compatibleIds)\n        .required()\n        .description('ToolCall id of the artifact to query.')\n\n      const argsSchema = (\n        descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n      ).append({\n        callId: callIdSchema,\n      })\n\n      const tool = new ArtifactTool({\n        name: descriptor.name,\n        description: descriptor.description,\n        inputSchema: argsSchema,\n        ephemeral: true,\n        onCollision: 'replace',\n        handler: async (rawArgs, ctxInner) => {\n          const args = rawArgs as Record<string, unknown> & { callId: string }\n          const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n          if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n          const artifact = resolved.artifact\n          const methodArgs: unknown[] = []\n          if (\n            descriptor.method === 'json_get' ||\n            descriptor.method === 'json_filter' ||\n            descriptor.method === 'json_pluck'\n          ) {\n            methodArgs.push(args.path as string)\n          } else if (descriptor.method === 'json_slice') {\n            methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n          }\n          const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n            descriptor.method\n          ]\n          if (typeof fn !== 'function') {\n            return `Error: artifact has no method ${descriptor.method}`\n          }\n          const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n          const serialise = descriptor.serialise ?? defaultSerialise\n          return serialise(result)\n        },\n      })\n      registry.register(tool)\n    }\n    return registry\n  }\n\n  /**\n   * Resolves and caches the detected or provided format.\n   */\n  async #resolveFormat(): Promise<JsonArtifactFormat> {\n    if (this.#format !== undefined) {\n      return this.#format\n    }\n    const lines = await this.cat()\n    this.#format = inferFormat(lines.join('\\n'))\n    return this.#format\n  }\n\n  /**\n   * Parses and caches all records from the artifact.\n   *\n   * @remarks\n   * For `json`/`json5` format: returns a single-element array containing the parsed root value.\n   * For `jsonl`/`ndjson` format: returns one element per non-empty line.\n   */\n  async #resolveRecords(): Promise<T[]> {\n    if (this.#parsed !== undefined) {\n      return this.#parsed\n    }\n    const format = await this.#resolveFormat()\n    const lines = await this.cat()\n    if (format === 'json') {\n      this.#parsed = [JSON.parse(lines.join('\\n')) as T]\n    } else if (format === 'json5') {\n      this.#parsed = [JSON5.parse(lines.join('\\n')) as T]\n    } else {\n      // jsonl / ndjson\n      this.#parsed = lines.filter((l) => l.trim().length > 0).map((l) => JSON.parse(l) as T)\n    }\n    return this.#parsed\n  }\n\n  /**\n   * Returns the detected or provided format for this artifact.\n   *\n   * @returns One of `'json'`, `'json5'`, `'jsonl'`, or `'ndjson'`.\n   */\n  async json_type(): Promise<JsonArtifactFormat> {\n    return this.#resolveFormat()\n  }\n\n  /**\n   * Returns the top-level keys of the parsed content.\n   *\n   * @remarks\n   * - For `json`/`json5`: returns the keys of the root object, or `undefined` when the root is\n   *   not a plain object (e.g. an array or scalar).\n   * - For `jsonl`/`ndjson`: returns the union of keys across all records that are plain objects.\n   *   Duplicate keys are deduplicated.\n   *\n   * @returns Array of key strings, or `undefined` when no object keys are present.\n   */\n  async json_keys(): Promise<string[] | undefined> {\n    const records = await this.#resolveRecords()\n    const format = await this.#resolveFormat()\n    if (format === 'json' || format === 'json5') {\n      const root = records[0]\n      if (isObject(root)) {\n        return Object.keys(root as object)\n      }\n      return undefined\n    }\n    const keySet = new Set<string>()\n    for (const record of records) {\n      if (isObject(record)) {\n        for (const key of Object.keys(record as object)) {\n          keySet.add(key)\n        }\n      }\n    }\n    return keySet.size > 0 ? Array.from(keySet) : undefined\n  }\n\n  /**\n   * Returns the total number of records in the artifact.\n   *\n   * @remarks\n   * - For `json`/`json5`: always `1` (the entire artifact is a single value).\n   * - For `jsonl`/`ndjson`: the number of non-empty lines.\n   *\n   * @returns The record count.\n   */\n  async json_length(): Promise<number> {\n    const records = await this.#resolveRecords()\n    return records.length\n  }\n\n  /**\n   * Evaluates a JSONPath expression against the parsed content.\n   *\n   * @remarks\n   * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n   * supported: recursive descent (`$..*`), filter expressions (`$[?(@.age > 18)]`), union\n   * selectors, and more.\n   *\n   * - For `json`/`json5`: evaluates the expression against the root value.\n   * - For `jsonl`/`ndjson`: evaluates the expression against each record and returns a flat\n   *   array of all matches across all records.\n   *\n   * @param path - A JSONPath expression (e.g. `'$.user.address.city'`, `'$..name'`).\n   * @returns Array of matched values. Empty array when no matches are found.\n   */\n  async json_get(path: string): Promise<unknown[]> {\n    const records = await this.#resolveRecords()\n    const format = await this.#resolveFormat()\n    if (format === 'json' || format === 'json5') {\n      return JSONPath({ path, json: records[0] as object })\n    }\n    return records.flatMap((r) => JSONPath({ path, json: r as object }))\n  }\n\n  /**\n   * Returns a slice of the parsed records by index range.\n   *\n   * @remarks\n   * For `json`/`json5`: always returns `[root]` — the artifact is a single record so slicing is\n   * not meaningful. For `jsonl`/`ndjson`: behaves like `Array.prototype.slice`.\n   *\n   * @param start - Start index (inclusive). Defaults to `0`.\n   * @param end - End index (exclusive). Defaults to the record count.\n   * @returns Array of sliced records.\n   */\n  async json_slice(start?: number, end?: number): Promise<T[]> {\n    const records = await this.#resolveRecords()\n    const format = await this.#resolveFormat()\n    if (format === 'json' || format === 'json5') {\n      return records\n    }\n    return records.slice(start, end)\n  }\n\n  /**\n   * Returns records matched by a JSONPath filter expression.\n   *\n   * @remarks\n   * Evaluates `path` against each record and returns those for which the expression produces at\n   * least one match. For `json`/`json5`, evaluates against the root value and returns it in an\n   * array if matched.\n   *\n   * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n   * @returns Array of matching records.\n   */\n  async json_filter(path: string): Promise<T[]> {\n    const records = await this.#resolveRecords()\n    return records.filter((r) => {\n      const matches = JSONPath({ path, json: r as object })\n      return Array.isArray(matches) && matches.length > 0\n    })\n  }\n\n  /**\n   * Returns all values matched by a JSONPath expression across every record.\n   *\n   * @remarks\n   * Convenience over {@link SpooledJsonArtifact.json_get} with an identical signature — use\n   * whichever name better communicates intent at the call site. `json_pluck` reads well for\n   * extracting a single field column; `json_get` reads well for structured queries.\n   *\n   * @param path - A JSONPath expression (e.g. `'$..name'`).\n   * @returns Array of matched values.\n   */\n  async json_pluck(path: string): Promise<unknown[]> {\n    return this.json_get(path)\n  }\n\n  /**\n   * Serialise this SpooledJsonArtifact into an `@nhtio/encoder` snapshot — the reader **handle** plus\n   * the `format` discriminator.\n   *\n   * @remarks\n   * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's `format` hint (the\n   * parsed-record cache is derived and not encoded). Round-trips via\n   * {@link SpooledJsonArtifact.[DECODE_METHOD]}.\n   *\n   * @returns A snapshot consumed by {@link SpooledJsonArtifact.[DECODE_METHOD]}.\n   */\n  [ENCODE_METHOD](): AdkEncodableSnapshot {\n    return { reader: this.readerDescriptor(), format: this.#format }\n  }\n\n  /**\n   * Reconstruct a {@link SpooledJsonArtifact} from a {@link SpooledJsonArtifact.[ENCODE_METHOD]}\n   * snapshot.\n   *\n   * @param data - The snapshot produced by {@link SpooledJsonArtifact.[ENCODE_METHOD]}.\n   * @returns A fresh {@link SpooledJsonArtifact} backed by a freshly-resolved reader.\n   */\n  static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledJsonArtifact {\n    const snapshot = data as {\n      reader: ReaderDescriptor\n      format?: JsonArtifactFormat\n    }\n    return new SpooledJsonArtifact(resolveSpoolReader(snapshot.reader), snapshot.format)\n  }\n}\n","import { remark } from 'remark'\nimport { visit } from 'unist-util-visit'\nimport { load as yamlLoad } from 'js-yaml'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { default as remarkGfm } from 'remark-gfm'\nimport { toString as mdastToString } from 'mdast-util-to-string'\nimport { default as remarkFrontmatter } from 'remark-frontmatter'\nimport { resolveSpoolReader } from '../contracts/reader_resolvers'\nimport { ENCODE_METHOD, DECODE_METHOD } from '../utils/encoder_symbols'\nimport {\n  SpooledArtifact,\n  defaultSerialise,\n  collectArtifactCompatibleIds,\n  resolveArtifactById,\n} from './spooled_artifact'\nimport type { Root, Link, Image } from 'mdast'\nimport type { AdkEncodableSnapshot } from './encodable'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\nimport type { ReaderDescriptor } from '../contracts/reader_descriptor'\n\n/**\n * A single heading entry in the document's structural index.\n *\n * @remarks\n * `startLine` is the 0-based line of the heading itself. `endLine` is the 0-based index of the\n * last line belonging to this section (inclusive) — the line immediately before the next heading\n * of equal or lesser depth, or the last line of the document.\n */\nexport interface MarkdownHeadingEntry {\n  /** ATX heading depth: 1 (`#`) through 6 (`######`). */\n  depth: 1 | 2 | 3 | 4 | 5 | 6\n  /** The heading text with the leading `#` prefix stripped and trimmed. */\n  text: string\n  /** 0-based line index of the heading line itself. */\n  startLine: number\n  /** 0-based line index of the last line in this section (inclusive). */\n  endLine: number\n}\n\n/**\n * A single fenced code block entry in the document's structural index.\n */\nexport interface MarkdownCodeEntry {\n  /** The language identifier immediately after the opening fence, or `null` when absent. */\n  lang: string | null\n  /** 0-based line index of the opening fence line. */\n  startLine: number\n  /** 0-based line index of the closing fence line. */\n  endLine: number\n}\n\ninterface MarkdownIndex {\n  headings: MarkdownHeadingEntry[]\n  codeBlocks: MarkdownCodeEntry[]\n}\n\n/**\n * A section of a markdown document as returned by {@link SpooledMarkdownArtifact.md_sections}.\n *\n * @remarks\n * Contains only line-range metadata — no content is fetched until the caller explicitly\n * requests it via `cat(bodyStartLine, bodyEndLine + 1)`.\n */\nexport interface MarkdownSection {\n  /** ATX heading depth: 1 (`#`) through 6 (`######`). */\n  depth: 1 | 2 | 3 | 4 | 5 | 6\n  /** The heading text. */\n  heading: string\n  /** 0-based line of the heading itself. */\n  headingLine: number\n  /** 0-based line of the first body line (heading line + 1). */\n  bodyStartLine: number\n  /** 0-based line of the last body line (inclusive). */\n  bodyEndLine: number\n}\n\n/**\n * Returns a configured remark processor with frontmatter and GFM support.\n */\nfunction processor() {\n  return remark().use(remarkFrontmatter).use(remarkGfm)\n}\n\n/**\n * Parses a heading line (e.g. `## My Heading`) and returns `{ depth, text }`, or `null` when\n * the line is not an ATX heading.\n */\nfunction parseHeadingLine(line: string): { depth: 1 | 2 | 3 | 4 | 5 | 6; text: string } | null {\n  const match = /^(#{1,6})\\s+(.*)$/.exec(line)\n  if (!match) return null\n  const depth = match[1].length as 1 | 2 | 3 | 4 | 5 | 6\n  return { depth, text: match[2].trim() }\n}\n\n/**\n * Returns the length of a fence marker at the start of `line` (3+), or `0` if the line is not\n * a fence opener/closer. Handles both backtick (` ``` `) and tilde (`~~~`) fences.\n */\nfunction fenceLength(line: string): number {\n  const trimmed = line.trimStart()\n  const match = /^(`{3,}|~{3,})/.exec(trimmed)\n  return match ? match[1].length : 0\n}\n\n/**\n * Extracts the language identifier from a fence opener line (e.g. ` ```ts ` → `'ts'`), or\n * `null` when none is present.\n */\nfunction fenceLang(line: string): string | null {\n  const trimmed = line.trimStart()\n  const match = /^(?:`{3,}|~{3,})(\\S+)/.exec(trimmed)\n  return match ? match[1] : null\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds markdown-aware structural queries.\n *\n * @remarks\n * Designed for large markdown documents where loading the full content into memory is\n * impractical. The structural index (heading positions, code block positions) is built by a\n * single line-by-line scan of the {@link @nhtio/adk!SpoolReader} without retaining any content. Only the\n * tiny metadata index and the parsed frontmatter object are cached.\n *\n * Content retrieval is always bounded — use `cat(start, end)` or the `startLine`/`endLine`\n * parameters on inline methods to fetch only the lines you need.\n *\n * Inline methods (`md_links`, `md_images`, `md_text`, `md_ast`) accept optional line-range\n * arguments. Without a range they read the full document — documented trade-off, caller\n * responsibility to bound the range for large documents.\n *\n * The processor always applies `remark-gfm` (tables, task lists, strikethrough, autolinks)\n * in addition to standard CommonMark and YAML frontmatter.\n */\nexport class SpooledMarkdownArtifact extends SpooledArtifact {\n  #index: MarkdownIndex | undefined\n  #frontmatter: Record<string, unknown> | null | undefined\n\n  /**\n   * @param reader - The backing store to read from.\n   */\n  constructor(reader: SpoolReader) {\n    super(reader)\n  }\n\n  /**\n   * Returns `true` if `value` is a {@link SpooledMarkdownArtifact} instance.\n   *\n   * @remarks\n   * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n   * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n   * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n   * `SpooledMarkdownArtifact` classes coexist in the same realm.\n   */\n  public static isSpooledMarkdownArtifact(value: unknown): value is SpooledMarkdownArtifact {\n    return isInstanceOf(value, 'SpooledMarkdownArtifact', SpooledMarkdownArtifact)\n  }\n\n  /**\n   * The markdown-specific artifact-query descriptors this class adds on top of the base set.\n   *\n   * @remarks\n   * Lists `artifact_md_frontmatter`, `artifact_md_headings`, `artifact_md_code_blocks`,\n   * `artifact_md_sections`, `artifact_md_links`, `artifact_md_images`, `artifact_md_text`,\n   * `artifact_md_ast`. The base seven descriptors (`artifact_head`, etc.) are NOT included\n   * here — they are forged separately by {@link SpooledMarkdownArtifact.forgeTools}, which\n   * calls `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then\n   * registers its own markdown tools on the result. Downstream consumers building custom\n   * subclasses should follow the same pattern: own only your own descriptors; override\n   * `forgeTools` to compose with the base output.\n   */\n  public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n    {\n      name: 'artifact_md_frontmatter',\n      method: 'md_frontmatter',\n      description:\n        'Return parsed YAML frontmatter (or undefined) from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({}),\n    },\n    {\n      name: 'artifact_md_headings',\n      method: 'md_headings',\n      description:\n        'Return all headings, optionally filtered by depth, from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        depth: validator\n          .number()\n          .integer()\n          .min(1)\n          .max(6)\n          .optional()\n          .description('ATX heading depth (1-6).'),\n      }),\n    },\n    {\n      name: 'artifact_md_code_blocks',\n      method: 'md_code_blocks',\n      description:\n        'Return all fenced code block entries, optionally filtered by language, from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        lang: validator\n          .string()\n          .allow('')\n          .optional()\n          .description('Language identifier. Pass empty string to match blocks with no lang.'),\n      }),\n    },\n    {\n      name: 'artifact_md_sections',\n      method: 'md_sections',\n      description:\n        'Return document sections (line-range metadata only) from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        depth: validator\n          .number()\n          .integer()\n          .min(1)\n          .max(6)\n          .optional()\n          .description('ATX heading depth (1-6).'),\n      }),\n    },\n    {\n      name: 'artifact_md_links',\n      method: 'md_links',\n      description:\n        'Return all inline and reference links within the given line range from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        startLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('Start line (inclusive).'),\n        endLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('End line (exclusive).'),\n      }),\n    },\n    {\n      name: 'artifact_md_images',\n      method: 'md_images',\n      description:\n        'Return all images within the given line range from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        startLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('Start line (inclusive).'),\n        endLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('End line (exclusive).'),\n      }),\n    },\n    {\n      name: 'artifact_md_text',\n      method: 'md_text',\n      description:\n        'Return plain text with markup stripped, for the given line range, from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        startLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('Start line (inclusive).'),\n        endLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('End line (exclusive).'),\n      }),\n    },\n    {\n      name: 'artifact_md_ast',\n      method: 'md_ast',\n      description:\n        'Return the full MDAST Root for the specified line range from a markdown artifact produced earlier in this turn.',\n      argsSchema: validator.object({\n        startLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('Start line (inclusive).'),\n        endLine: validator\n          .number()\n          .integer()\n          .min(0)\n          .optional()\n          .description('End line (exclusive).'),\n      }),\n    },\n  ])\n\n  /**\n   * Forges base-class tools plus markdown-specific tools narrowed to\n   * {@link SpooledMarkdownArtifact}.\n   *\n   * @remarks\n   * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n   * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n   * register one `ArtifactTool` per markdown-specific descriptor narrowed to markdown\n   * artifacts. Downstream consumers building their own subclasses should follow the same\n   * shape.\n   */\n  public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n    const registry = SpooledArtifact.forgeTools(ctx)\n    const requires = SpooledMarkdownArtifact\n    const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n    if (compatibleIds.length === 0) return registry\n\n    for (const descriptor of this.toolMethods) {\n      const callIdSchema = validator\n        .string()\n        .valid(...compatibleIds)\n        .required()\n        .description('ToolCall id of the artifact to query.')\n\n      const argsSchema = (\n        descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n      ).append({\n        callId: callIdSchema,\n      })\n\n      const tool = new ArtifactTool({\n        name: descriptor.name,\n        description: descriptor.description,\n        inputSchema: argsSchema,\n        ephemeral: true,\n        onCollision: 'replace',\n        handler: async (rawArgs, ctxInner) => {\n          const args = rawArgs as Record<string, unknown> & { callId: string }\n          const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n          if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n          const artifact = resolved.artifact\n          const methodArgs: unknown[] = []\n          if (descriptor.method === 'md_headings' || descriptor.method === 'md_sections') {\n            methodArgs.push(args.depth as number | undefined)\n          } else if (descriptor.method === 'md_code_blocks') {\n            methodArgs.push(args.lang as string | undefined)\n          } else if (\n            descriptor.method === 'md_links' ||\n            descriptor.method === 'md_images' ||\n            descriptor.method === 'md_text' ||\n            descriptor.method === 'md_ast'\n          ) {\n            methodArgs.push(\n              args.startLine as number | undefined,\n              args.endLine as number | undefined\n            )\n          }\n          const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n            descriptor.method\n          ]\n          if (typeof fn !== 'function') {\n            return `Error: artifact has no method ${descriptor.method}`\n          }\n          const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n          const serialise = descriptor.serialise ?? defaultSerialise\n          return serialise(result)\n        },\n      })\n      registry.register(tool)\n    }\n    return registry\n  }\n\n  /**\n   * Builds the structural index in a single top-to-bottom pass, retaining only metadata.\n   */\n  async #resolveIndex(): Promise<MarkdownIndex> {\n    if (this.#index !== undefined) return this.#index\n\n    const count = await this.lineCount()\n    const headingsRaw: Array<{\n      depth: 1 | 2 | 3 | 4 | 5 | 6\n      text: string\n      startLine: number\n    }> = []\n    const codeBlocks: MarkdownCodeEntry[] = []\n\n    let inFrontmatter = false\n    let frontmatterClosed = false\n    let inCodeBlock = false\n    let openFenceLen = 0\n    let openFenceStartLine = 0\n    let openFenceLang: string | null = null\n\n    for (let i = 0; i < count; i++) {\n      const rawLine = await this.line(i)\n      const l = rawLine ?? ''\n\n      // Handle frontmatter block at the top of the document\n      if (i === 0 && l.trim() === '---') {\n        inFrontmatter = true\n        continue\n      }\n      if (inFrontmatter) {\n        if (l.trim() === '---') {\n          inFrontmatter = false\n          frontmatterClosed = true\n        }\n        continue\n      }\n      if (!frontmatterClosed && i === 0) {\n        // No frontmatter — treat as normal document from the start\n      }\n\n      // Handle fenced code blocks\n      const fLen = fenceLength(l)\n      if (!inCodeBlock && fLen >= 3) {\n        inCodeBlock = true\n        openFenceLen = fLen\n        openFenceStartLine = i\n        openFenceLang = fenceLang(l)\n        continue\n      }\n      if (inCodeBlock) {\n        // A closing fence must use the same fence character (` or ~) and be at least as long.\n        if (fLen >= openFenceLen) {\n          const openLine = (await this.line(openFenceStartLine)) ?? ''\n          const openChar = openLine.trimStart()[0]\n          const closeChar = l.trimStart()[0]\n          if (closeChar === openChar) {\n            codeBlocks.push({\n              lang: openFenceLang,\n              startLine: openFenceStartLine,\n              endLine: i,\n            })\n            inCodeBlock = false\n            openFenceLen = 0\n          }\n        }\n        continue\n      }\n\n      // Detect ATX headings (not inside code blocks, not in frontmatter)\n      const heading = parseHeadingLine(l)\n      if (heading) {\n        headingsRaw.push({ ...heading, startLine: i })\n      }\n    }\n\n    // Unclosed code block — record it anyway\n    if (inCodeBlock) {\n      codeBlocks.push({\n        lang: openFenceLang,\n        startLine: openFenceStartLine,\n        endLine: count - 1,\n      })\n    }\n\n    // Post-process heading endLine values\n    const headings: MarkdownHeadingEntry[] = headingsRaw.map((h, idx) => {\n      const nextBoundary = headingsRaw.slice(idx + 1).find((n) => n.depth <= h.depth)\n      const endLine = nextBoundary ? nextBoundary.startLine - 1 : count - 1\n      return { ...h, endLine }\n    })\n\n    this.#index = { headings, codeBlocks }\n    return this.#index\n  }\n\n  // ── Frontmatter ───────────────────────────────────────────────────────────\n\n  /**\n   * Returns the parsed YAML frontmatter, or `undefined` when no frontmatter block is present.\n   *\n   * @remarks\n   * Short-circuits after reading the frontmatter block — never reads the document body. Caches\n   * the result so subsequent calls are free. The result is `undefined` (not an empty object)\n   * when no frontmatter is found, distinguishing \"no frontmatter\" from \"empty frontmatter\".\n   */\n  async md_frontmatter(): Promise<Record<string, unknown> | undefined> {\n    if (this.#frontmatter !== undefined) return this.#frontmatter ?? undefined\n\n    const firstLine = await this.line(0)\n    if (firstLine?.trim() !== '---') {\n      this.#frontmatter = null\n      return undefined\n    }\n\n    const maxScan = Math.min(await this.lineCount(), 200)\n    const yamlLines: string[] = []\n    let closed = false\n    for (let i = 1; i < maxScan; i++) {\n      const l = await this.line(i)\n      if (l?.trim() === '---') {\n        closed = true\n        break\n      }\n      yamlLines.push(l ?? '')\n    }\n\n    if (!closed) {\n      this.#frontmatter = null\n      return undefined\n    }\n\n    this.#frontmatter = yamlLoad(yamlLines.join('\\n')) as Record<string, unknown>\n    return this.#frontmatter\n  }\n\n  // ── Structural index queries ──────────────────────────────────────────────\n\n  /**\n   * Returns all headings in document order, optionally filtered by depth.\n   *\n   * @remarks\n   * Uses the cached structural index — no content is fetched from the {@link @nhtio/adk!SpoolReader}.\n   *\n   * @param depth - When provided, only headings at this ATX depth (1–6) are returned.\n   */\n  async md_headings(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownHeadingEntry[]> {\n    const index = await this.#resolveIndex()\n    if (depth === undefined) return index.headings.slice()\n    return index.headings.filter((h) => h.depth === depth)\n  }\n\n  /**\n   * Returns all fenced code block entries, optionally filtered by language identifier.\n   *\n   * @remarks\n   * Returns line-range metadata only — no content is fetched. Use `cat(entry.startLine + 1,\n   * entry.endLine)` to retrieve the code body (excluding fence lines).\n   *\n   * @param lang - When provided, only blocks with this exact lang identifier are returned.\n   *   Pass an empty string to match blocks with no lang identifier.\n   */\n  async md_code_blocks(lang?: string): Promise<MarkdownCodeEntry[]> {\n    const index = await this.#resolveIndex()\n    if (lang === undefined) return index.codeBlocks.slice()\n    const target = lang === '' ? null : lang\n    return index.codeBlocks.filter((b) => b.lang === target)\n  }\n\n  /**\n   * Returns document sections derived from the structural index.\n   *\n   * @remarks\n   * Returns only line-range metadata — body content is never fetched. To retrieve the body of a\n   * section, call `cat(section.bodyStartLine, section.bodyEndLine + 1)`.\n   *\n   * When `depth` is provided, only sections introduced by a heading at that depth are returned;\n   * deeper headings become part of the body.\n   *\n   * @param depth - When provided, only sections at this ATX depth (1–6) are returned.\n   */\n  async md_sections(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownSection[]> {\n    const index = await this.#resolveIndex()\n    const headings =\n      depth !== undefined ? index.headings.filter((h) => h.depth === depth) : index.headings\n    return headings.map((h) => ({\n      depth: h.depth,\n      heading: h.text,\n      headingLine: h.startLine,\n      bodyStartLine: h.startLine + 1,\n      bodyEndLine: h.endLine,\n    }))\n  }\n\n  // ── Inline queries (bounded) ──────────────────────────────────────────────\n\n  /**\n   * Returns the full MDAST Root for the specified line range.\n   *\n   * @remarks\n   * Without a range, reads the full document — for large documents, use\n   * {@link SpooledMarkdownArtifact.md_sections} to locate sections and pass\n   * bounded line ranges here.\n   *\n   * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n   * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n   */\n  async md_ast(startLine?: number, endLine?: number): Promise<Root> {\n    const lines = await this.cat(startLine, endLine)\n    return processor().parse(lines.join('\\n')) as Root\n  }\n\n  /**\n   * Returns all inline and reference links in the specified line range.\n   *\n   * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n   * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n   */\n  async md_links(\n    startLine?: number,\n    endLine?: number\n  ): Promise<Array<{ text: string; url: string; title?: string }>> {\n    const lines = await this.cat(startLine, endLine)\n    const ast = processor().parse(lines.join('\\n'))\n    const results: Array<{ text: string; url: string; title?: string }> = []\n    visit(ast, 'link', (node: Link) => {\n      results.push({\n        text: mdastToString(node),\n        url: node.url,\n        title: node.title ?? undefined,\n      })\n    })\n    return results\n  }\n\n  /**\n   * Returns all images in the specified line range.\n   *\n   * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n   * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n   */\n  async md_images(\n    startLine?: number,\n    endLine?: number\n  ): Promise<Array<{ alt: string; url: string; title?: string }>> {\n    const lines = await this.cat(startLine, endLine)\n    const ast = processor().parse(lines.join('\\n'))\n    const results: Array<{ alt: string; url: string; title?: string }> = []\n    visit(ast, 'image', (node: Image) => {\n      results.push({\n        alt: node.alt ?? '',\n        url: node.url,\n        title: node.title ?? undefined,\n      })\n    })\n    return results\n  }\n\n  /**\n   * Returns all document text with markup stripped, for the specified line range.\n   *\n   * @remarks\n   * Uses `mdast-util-to-string` to extract plain text from the AST — code, link text, and\n   * alt text are included; markdown syntax is removed.\n   *\n   * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n   * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n   */\n  async md_text(startLine?: number, endLine?: number): Promise<string> {\n    const lines = await this.cat(startLine, endLine)\n    const ast = processor().parse(lines.join('\\n'))\n    return mdastToString(ast)\n  }\n\n  /**\n   * Serialise this SpooledMarkdownArtifact into an `@nhtio/encoder` snapshot — the reader **handle**.\n   *\n   * @remarks\n   * The structural index and frontmatter caches are derived and not encoded. Round-trips via\n   * {@link SpooledMarkdownArtifact.[DECODE_METHOD]}.\n   *\n   * @returns A snapshot consumed by {@link SpooledMarkdownArtifact.[DECODE_METHOD]}.\n   */\n  [ENCODE_METHOD](): AdkEncodableSnapshot {\n    return { reader: this.readerDescriptor() }\n  }\n\n  /**\n   * Reconstruct a {@link SpooledMarkdownArtifact} from a\n   * {@link SpooledMarkdownArtifact.[ENCODE_METHOD]} snapshot.\n   *\n   * @param data - The snapshot produced by {@link SpooledMarkdownArtifact.[ENCODE_METHOD]}.\n   * @returns A fresh {@link SpooledMarkdownArtifact} backed by a freshly-resolved reader.\n   */\n  static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledMarkdownArtifact {\n    const snapshot = data as { reader: ReaderDescriptor }\n    return new SpooledMarkdownArtifact(resolveSpoolReader(snapshot.reader))\n  }\n}\n"],"mappings":"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"}