{"version":3,"file":"server.mjs","names":["routes","rootSession","apiRoute","hookBeforeAgentStart","hookSessionStart","resourceDoompiUsePlan","toolRestrictionPlan","toolRestrictionPlanReadOnly","toolCompletePlan","toolRecordDebugEvidence","toolRunFablePlan","toolWritePlan"],"sources":["../../src/schemas/mcpTools.ts","../../src/services/mcpTools/index.ts","../../src/types/apiRoutes.ts","../../src/services/planApi/index.ts","../../src/services/planServerSession/index.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/plans/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompiUsePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/runFablePlan.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server.ts","../../generated/server.ts"],"sourcesContent":["import { Type } from 'typebox';\n\nconst markdown = Type.String({ minLength: 1 });\n\nexport const remoteWritePlanParameters = Type.Object({ markdown }, { additionalProperties: false });\nexport const writePlanParameters = Type.Object({ markdown: Type.Optional(markdown) }, { additionalProperties: false });\n","import type { DoomHeadlessTool } from '@agimon-ai/doompi-core/headless';\nimport type { DoomMcpPluginContext } from '@agimon-ai/doompi-core/mcpFacet';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { remoteWritePlanParameters } from '../../schemas/mcpTools';\n\nexport const PLAN_MCP_TOOLS_SERVICE = 'doom/plan-mcp-tools';\n\nconst MODE_ID = 'plan';\nconst MODE_LABEL = 'Plan';\n\nexport interface McpToolCatalog {\n  get(name: string): DoomHeadlessTool | undefined;\n  names(): readonly string[];\n}\n\nexport function mountMcpTools(tools: readonly DoomHeadlessTool[]) {\n  return (context: Context): void => {\n    context.plugin((providerContext) => {\n      providerContext.provide(PLAN_MCP_TOOLS_SERVICE, {\n        get: (name) => tools.find((tool) => tool.name === name),\n        names: () => tools.map((tool) => tool.name),\n      } satisfies McpToolCatalog);\n    });\n  };\n}\n\nexport function bindMcpTool(context: DoomMcpPluginContext, name: string): DoomHeadlessTool {\n  const catalog = context.services.get<McpToolCatalog>(PLAN_MCP_TOOLS_SERVICE);\n  const tool = catalog?.get(name);\n  if (!tool || !catalog) throw new Error(`Plan tool is unavailable: ${name}`);\n  const writesPlan = name === 'write_plan';\n  return {\n    ...tool,\n    ...(writesPlan\n      ? {\n          description:\n            'Save the supplied Markdown plan in the bound session. Requires active Plan mode. Saving does not approve implementation.',\n          parameters: remoteWritePlanParameters,\n          annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n        }\n      : {}),\n    execute(toolCallId, parameters, signal, onUpdate) {\n      const activeModes = context.selection.read().state?.['minor-mode'] ?? [];\n      if (!activeModes.includes(MODE_ID)) {\n        const inactiveTools = [...catalog.names()].sort().join(', ');\n        throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);\n      }\n      if (\n        writesPlan &&\n        (typeof parameters !== 'object' ||\n          parameters === null ||\n          !('markdown' in parameters) ||\n          typeof parameters.markdown !== 'string' ||\n          !parameters.markdown.trim())\n      ) {\n        throw new Error(\n          'Supply the complete visible plan in the markdown argument. Remote calls cannot read the ChatGPT transcript.',\n        );\n      }\n      const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);\n      return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);\n    },\n  };\n}\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport type { PlanDetailView, PlanSaveView } from './planApi';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/plans/`, so the mount is\n * stated once, by the folder that creates it. The paths used to be written\n * here as helpers, again in the contract, and again inside every URL the page\n * built, and the copies were free to disagree.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone.\n *\n * Neither route takes a query or a path parameter: a session has one current\n * plan, so `current` answers it and `save` takes the manual write back.\n */\nexport default defineApiRoutes({\n  current: {\n    method: 'GET',\n    path: '/current',\n    response: apiResponse<PlanDetailView>(),\n  },\n  save: {\n    method: 'PUT',\n    path: '/content',\n    response: apiResponse<PlanSaveView>(),\n  },\n});\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs/promises';\n\nimport type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\nimport { Hono } from 'hono';\n\nimport { PlanPointerService } from '../../services/planPointer';\nimport routes from '../../types/apiRoutes';\nimport { API_BASE_PATH, type PlanDetailView, type PlanSaveRequest, type PlanSaveView } from '../../types/planApi';\nimport type { PlanPointerPort } from '../../types/planPointer';\n\n/**\n * This package's HTTP surface: the session's current plan, and the manual save.\n *\n * Each path comes from the route table the browser reads, so a route the page\n * calls and the route this serves cannot be spelled apart. Both are relative\n * to the mount its host gives it, so nothing here repeats where it was mounted. The host is one session's own server, which is what\n * makes the session id available without the page supplying it.\n *\n * Neither route takes a path. A session has exactly one current plan, and the\n * file both routes act on is the one the pointer names, so a page can address\n * the plan and nothing else; there is no traversal question to answer because\n * there is no path to traverse.\n *\n * The save refuses unless the reader proves they were looking at the content\n * that is still on disk. The agent may rewrite the plan while a tab is open,\n * and silently discarding whichever side finished second is the one outcome\n * worth ruling out.\n */\n\n/** Past this, the plan is reported rather than carried. */\nexport const MAX_PLAN_BYTES = 1024 * 1024;\n\nconst NO_PLAN = 'This session has not written a plan yet.';\nconst STALE_SAVE = 'The plan changed since it was opened.';\nconst NOT_A_FILE = 'The plan file is no longer a regular file, so it was not written.';\n\nexport interface PlanApiOptions {\n  /** The session these routes answer for; absent when the host is the hub. */\n  sessionId?: string;\n  pointers?: PlanPointerPort;\n}\n\nfunction hashOf(content: string): string {\n  return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/** Reads the plan as the source view will show it, or says why it cannot. */\nasync function readPlan(\n  planPath: string,\n): Promise<Pick<PlanDetailView, 'content' | 'hash' | 'unavailable' | 'reason'>> {\n  let raw: Buffer;\n  try {\n    raw = await fs.readFile(planPath);\n  } catch {\n    return { content: '', hash: '', unavailable: true, reason: 'the plan file no longer exists' };\n  }\n  if (raw.byteLength > MAX_PLAN_BYTES) {\n    return { content: '', hash: '', unavailable: true, reason: `the plan is larger than ${MAX_PLAN_BYTES} bytes` };\n  }\n  const content = raw.toString('utf8');\n  return { content, hash: hashOf(content), unavailable: false };\n}\n\nexport function createPlanApi(options: PlanApiOptions = {}): Hono {\n  const app = new Hono();\n  const pointers = options.pointers ?? new PlanPointerService({ env: process.env });\n  const pointerFor = (): ReturnType<PlanPointerPort['read']> =>\n    options.sessionId === undefined ? undefined : pointers.read(options.sessionId);\n\n  app.get(routes.current.path, async (context) => {\n    const pointer = pointerFor();\n    if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n    const view: PlanDetailView = {\n      path: pointer.path,\n      title: pointer.title,\n      writtenAt: pointer.writtenAt,\n      ...(pointer.planId === undefined ? {} : { planId: pointer.planId }),\n      ...(await readPlan(pointer.path)),\n    };\n    return context.json(view);\n  });\n\n  app.put(routes.save.path, async (context) => {\n    let request: PlanSaveRequest;\n    try {\n      request = (await context.req.json()) as PlanSaveRequest;\n    } catch {\n      return context.json({ error: 'The save body is not JSON.' }, 400);\n    }\n    if (typeof request.content !== 'string' || typeof request.expectedHash !== 'string') {\n      return context.json({ error: 'A save carries the content to write and the hash it was read at.' }, 400);\n    }\n    const pointer = pointerFor();\n    if (pointer === undefined) return context.json({ error: NO_PLAN }, 404);\n\n    const current = await readPlan(pointer.path);\n    if (current.unavailable) return context.json({ error: current.reason ?? NO_PLAN }, 409);\n    if (current.hash !== request.expectedHash) {\n      return context.json({ error: STALE_SAVE, hash: current.hash }, 409);\n    }\n    // The same guard write_plan applies before it writes: a plan whose\n    // destination has become a symlink or gained a second name is not written\n    // through, whatever the pointer still says.\n    const stats = await fs.lstat(pointer.path);\n    if (!stats.isFile() || stats.nlink !== 1) return context.json({ error: NOT_A_FILE }, 409);\n\n    await fs.writeFile(pointer.path, request.content, { encoding: 'utf8', mode: 0o600 });\n    return context.json({ hash: hashOf(request.content) } satisfies PlanSaveView);\n  });\n\n  return app;\n}\n\n/** The named export a host imports from this package's built entry. */\nexport const api: DoomApi = {\n  basePath: API_BASE_PATH,\n  start(context: DoomApiContext): DoomApiHandler {\n    const app = createPlanApi(context.sessionId === undefined ? {} : { sessionId: context.sessionId });\n    return {\n      fetch: (request) => app.fetch(request),\n      // Nothing outlives a request here; an API that starts a watch or a timer\n      // tears it down in this callback.\n      close: () => undefined,\n    };\n  },\n};\n","import { readFile } from 'node:fs/promises';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { type DoomHeadlessHostService, type DoomHeadlessModelSettings } from '@agimon-ai/doompi-core/headless';\nimport { type DoomHeadlessToolResult } from '@agimon-ai/doompi-core/headless';\nimport { readPackageResource, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { DOOM_VOICE_AUTO_MODE_ID } from '@agimon-ai/doompi-core/voiceTools';\nimport { serverMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/doompi-minor-mode';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { writePlanParameters } from '../../schemas/mcpTools';\nimport { loadDoomConfig, resolvePlanningPlansDirectory } from '../../schemas/plan/config';\nimport {\n  buildFlavorPlanningPrompt,\n  buildPlanModeBasePrompt,\n  type DebugEvidencePacket,\n  type PlanHostCapabilities,\n  type PlanningFlavor,\n} from '../../services/prompts';\nimport {\n  CONTINUE_PLAN_DECISION,\n  EXIT_PLAN_DECISION,\n  PLAN_REVIEW_CHOICES,\n  PLAN_REVIEW_TITLE,\n  PLAN_STATUS_KEY,\n  formatPlanStatus,\n} from '../../types/planApi';\nimport {\n  DOOM_SUBAGENT_POLICY_SERVICE,\n  readDoomSubagentPolicyService,\n  type SubagentPolicy,\n  type SubagentPolicyHandle,\n} from '../optionalTeamServices';\nimport {\n  parseDebugEvidencePacket,\n  PLAN_CONTINUE_TEXT,\n  PLAN_EXIT_APPROVED_TEXT,\n  planStampOf,\n  planTitleOf,\n  planTitleSlug,\n  visiblePlanForToolCall,\n} from '../planMode';\nimport { PlanPointerService } from '../planPointer';\n\nconst RECORD_DEBUG_EVIDENCE_TOOL = 'record_debug_evidence';\nconst RUN_FABLE_PLAN_TOOL = 'run_fable_plan';\nconst WRITE_PLAN_TOOL = 'write_plan';\nconst COMPLETE_PLAN_TOOL = 'complete_plan';\nconst PLAN_MODE_ID = 'plan';\nconst PLAN_MODEL_SNAPSHOT = 'plan-server-model-snapshot';\nconst PLAN_FLAVOR_SNAPSHOT = 'plan-server-flavor';\nconst PLAN_DEBUG_EVIDENCE = 'plan-debug-evidence';\nconst PLAN_DOCUMENT = 'plan-document';\n/**\n * Fable needs a broker this host does not have, so `run_fable_plan` is a stub here. The stage is\n * reported honestly rather than as an idle run that is about to start.\n */\nconst PLAN_SERVER_FABLE_STAGE = 'unavailable';\n/**\n * What this facet's tools accept: complete_plan declares no parameters, there is no narrated\n * review to answer, and run_fable_plan is a stub because no broker seam is configured.\n */\nexport const PLAN_SERVER_CAPABILITIES: PlanHostCapabilities = {\n  completePlanTakesDecision: false,\n  narratesReview: false,\n  fableAvailable: false,\n};\nconst PLAN_SUBAGENT_POLICY_OWNER = '@agimon-ai/doompi-plan';\nconst PLAN_SUBAGENT_POLICY: SubagentPolicy = {\n  owner: PLAN_SUBAGENT_POLICY_OWNER,\n  allowedTools: ['read', 'bash', 'grep', 'find', 'ls', 'mcp'],\n  requiredTools: ['bash'],\n  allowMcpTools: true,\n  allowedExternalProfiles: [],\n  denyExtensions: false,\n};\n\nfunction serverPlanSubagentPolicy(host: DoomHeadlessHostService): (context: Context) => void {\n  return (context) => {\n    context.inject([DOOM_SUBAGENT_POLICY_SERVICE], (child) => {\n      const service = readDoomSubagentPolicyService(child);\n      if (!service) return undefined;\n      let handle: SubagentPolicyHandle | undefined;\n      const sync = (): void => {\n        if (modeSelected(host)) {\n          if (handle) handle.update(PLAN_SUBAGENT_POLICY);\n          else handle = service.register(PLAN_SUBAGENT_POLICY);\n        } else {\n          handle?.dispose();\n          handle = undefined;\n        }\n      };\n      sync();\n      child.effect(() => host.subscribeSelection(sync));\n      return () => handle?.dispose();\n    });\n  };\n}\n\nfunction modeSelected(host: DoomHeadlessHostService): boolean {\n  return (host.context.selection.state?.['minor-mode'] ?? []).includes(PLAN_MODE_ID);\n}\n\nfunction output(value: unknown, isError = false): DoomHeadlessToolResult {\n  return {\n    content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n    details: value,\n    ...(isError ? { isError: true } : {}),\n  };\n}\n\nexport function createPlanServerSession(\n  host: DoomHeadlessHostService,\n): Omit<DoomServerSessionPlugin, 'tools'> & { tools: Parameters<DoomHeadlessHostService['registerTool']>[0][] } {\n  let flavor: PlanningFlavor = 'normal';\n  let debugEvidence: DebugEvidencePacket | undefined;\n  let modeOwner: MinorModeOwner | undefined;\n  const selected = (): boolean => modeSelected(host);\n  const homeDirectory = (): string => host.context.environment.HOME ?? os.homedir();\n  // One resolution for the prompt and for write_plan. They named different directories before,\n  // so the prompt could advertise a path the tool would not write to.\n  const plansDirectory = (): string =>\n    resolvePlanningPlansDirectory(\n      loadDoomConfig(host.context.repoRoot, homeDirectory()).modes?.planning?.plansDirectory,\n      host.context.repoRoot,\n      homeDirectory(),\n    );\n  const pointers = new PlanPointerService({ env: host.context.environment });\n  /**\n   * The activity group's line, and the pointer its panel reads.\n   *\n   * A cockpit drives this facet and never the Pi runtime, so both were written\n   * only on the Pi side: the group never appeared, and when it did its panel\n   * had no pointer to answer from.\n   */\n  const announcePlanDocument = (filePath: string, title: string, writtenAt: string): void => {\n    try {\n      pointers.write(host.context.sessionId, { path: filePath, title, writtenAt });\n    } catch {\n      // The plan is on disk either way. Losing the cockpit's view of it is not\n      // a reason to fail the write that produced it.\n    }\n    host.context.client.setStatus(PLAN_STATUS_KEY, formatPlanStatus(title, planStampOf(writtenAt)));\n  };\n  const modeState = (): MinorModeState => {\n    const active = selected();\n    return {\n      activation: active ? 'active' : 'inactive',\n      condition: 'ready',\n      ...(active ? { detail: `${flavor} - read only`, modelContextVariant: flavor } : {}),\n      actions: [\n        {\n          id: 'activate',\n          enabled: true,\n        },\n        {\n          id: 'deactivate',\n          enabled: active,\n          ...(active ? {} : { disabledReason: 'Plan mode is inactive.' }),\n        },\n      ],\n    };\n  };\n  const publishMode = (): void => modeOwner?.publish();\n  const restoreModel = async (): Promise<void> => {\n    const session = host.context.session;\n    const entries = await session.entries({ type: 'custom', customType: PLAN_MODEL_SNAPSHOT, limit: 1 });\n    const data = entries[0]?.data;\n    if (data === undefined || data === null) return;\n    if (\n      typeof data !== 'object' ||\n      !('thinkingLevel' in data) ||\n      !['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'].includes(String(data.thinkingLevel))\n    )\n      throw new Error('The saved planning model settings are invalid.');\n    if (!session.setModelSettings) throw new Error('This session cannot restore its model settings.');\n    await session.setModelSettings(data as DoomHeadlessModelSettings);\n    await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n  };\n  const selectPlan = async (enabled: boolean, nextFlavor = flavor): Promise<void> => {\n    const wasEnabled = selected();\n    const session = host.context.session;\n    if (enabled && !wasEnabled) {\n      const config = loadDoomConfig(host.context.repoRoot, homeDirectory()).modes?.planning?.main;\n      if (config?.model || config?.thinking) {\n        if (!session.readModelSettings || !session.setModelSettings)\n          throw new Error('This session cannot apply planning model settings.');\n        const previous = await session.readModelSettings();\n        const settings: Partial<DoomHeadlessModelSettings> = {};\n        if (config.model) {\n          const separator = config.model.indexOf('/');\n          const provider = separator > 0 ? config.model.slice(0, separator) : previous.model?.provider;\n          if (!provider) throw new Error('The planning model needs a provider.');\n          settings.model = { provider, id: separator > 0 ? config.model.slice(separator + 1) : config.model };\n        }\n        if (config.thinking) settings.thinkingLevel = config.thinking;\n        await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, previous);\n        try {\n          await session.setModelSettings(settings);\n        } catch (error) {\n          await session.setModelSettings(previous);\n          await session.appendCustomEntry(PLAN_MODEL_SNAPSHOT, null);\n          throw error;\n        }\n      }\n    } else if (!enabled && wasEnabled) {\n      await restoreModel();\n    }\n    const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== PLAN_MODE_ID);\n    await host.changeSelection({\n      axis: 'state',\n      key: 'minor-mode',\n      values: enabled ? [...modes, PLAN_MODE_ID] : modes,\n    });\n    flavor = nextFlavor;\n    // Persisted because the minor mode survives a server restart while this local does not, and\n    // the prompt is built from it. Without this a restored debug session silently plans as normal.\n    await session.appendCustomEntry(PLAN_FLAVOR_SNAPSHOT, enabled ? { flavor } : null);\n    publishMode();\n  };\n\n  /** Newest value for a custom entry type, or undefined when none was recorded. */\n  const latestEntry = async (customType: string): Promise<unknown> => {\n    const entries = await host.context.session.entries({ type: 'custom', customType, limit: 1 });\n    return entries[0]?.data ?? undefined;\n  };\n\n  const restorePlanState = async (): Promise<void> => {\n    const saved = await latestEntry(PLAN_FLAVOR_SNAPSHOT);\n    if (saved !== undefined && saved !== null && typeof saved === 'object' && 'flavor' in saved) {\n      const candidate = String((saved as { flavor: unknown }).flavor);\n      if (candidate === 'normal' || candidate === 'debug' || candidate === 'fable') flavor = candidate;\n    }\n    const evidence = await latestEntry(PLAN_DEBUG_EVIDENCE);\n    if (evidence === undefined || evidence === null) return;\n    try {\n      debugEvidence = parseDebugEvidencePacket(evidence);\n    } catch {\n      // A packet written by an older shape must not stop the session from planning.\n      debugEvidence = undefined;\n    }\n  };\n  modeOwner = defineMinorMode({\n    descriptor: {\n      source: '@agimon-ai/doompi-plan',\n      id: PLAN_MODE_ID,\n      label: 'Plan',\n      description: 'Read-only planning with normal, debug, and Fable flavors.',\n      order: 40,\n      actions: [\n        {\n          id: 'activate',\n          label: 'Activate',\n          description: 'Activate plan mode or switch its planning flavor.',\n          contexts: ['headless'],\n          parameters: [\n            {\n              name: 'flavor',\n              label: 'Flavor',\n              kind: 'enum',\n              required: true,\n              choices: [\n                { value: 'normal', label: 'Normal' },\n                { value: 'debug', label: 'Debug' },\n                { value: 'fable', label: 'Fable' },\n              ],\n            },\n          ],\n        },\n        {\n          id: 'deactivate',\n          label: 'Deactivate',\n          description: 'Exit plan mode and restore the previous agent configuration.',\n          contexts: ['headless'],\n          parameters: [],\n        },\n      ],\n    },\n    state: () => modeState(),\n    async handleAction(_runtime, actionId, argumentsValue, { signal }) {\n      signal.throwIfAborted();\n      if (actionId === 'activate') {\n        const nextFlavor = argumentsValue.flavor;\n        if (nextFlavor !== 'normal' && nextFlavor !== 'debug' && nextFlavor !== 'fable')\n          throw new Error('A valid plan flavor is required.');\n        await selectPlan(true, nextFlavor);\n        return { message: `Plan mode is active with the ${nextFlavor} flavor.` };\n      }\n      if (actionId === 'deactivate') {\n        await selectPlan(false);\n        return { message: 'Plan mode deactivated.' };\n      }\n      throw new Error(`Unknown plan mode action: ${actionId}`);\n    },\n  }).createOwner(undefined);\n  return {\n    services: [serverMinorModes([modeOwner]), serverPlanSubagentPolicy(host)],\n    resources: [\n      {\n        when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n        name: 'doompi-use-plan',\n        kind: 'skill',\n        read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-use-plan/SKILL.md'),\n      },\n    ],\n    tools: [\n      {\n        when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n        name: RECORD_DEBUG_EVIDENCE_TOOL,\n        label: 'Record Debug Evidence',\n        description: 'Record bounded debug evidence as optional planning context.',\n        parameters: {\n          type: 'object',\n          properties: {\n            issue: { type: 'string' },\n            expectedBehavior: { type: 'string' },\n            reproductionAttempt: { type: 'string' },\n            actualBehavior: { type: 'string' },\n            logs: { type: 'array', items: { type: 'string' } },\n            correlatedTraceEvidence: { type: 'array', items: { type: 'string' } },\n            processOutput: { type: 'array', items: { type: 'string' } },\n            browserConsoleEvidence: { type: 'array', items: { type: 'string' } },\n            correlationIds: { type: 'array', items: { type: 'string' } },\n            timestamps: { type: 'array', items: { type: 'string' } },\n            verifiedFacts: { type: 'array', items: { type: 'string' } },\n            hypotheses: { type: 'array', items: { type: 'string' } },\n            unavailableEvidence: { type: 'array', items: { type: 'string' } },\n          },\n          required: ['issue'],\n          additionalProperties: false,\n        },\n        executionMode: 'serial',\n        async execute(_toolCallId, parameters) {\n          try {\n            const parsedEvidence = parseDebugEvidencePacket(parameters);\n            await host.context.session.appendCustomEntry(PLAN_DEBUG_EVIDENCE, parsedEvidence);\n            // Held in memory too: the debug prompt is rebuilt every turn from this packet.\n            debugEvidence = parsedEvidence;\n            return output({ recorded: true });\n          } catch (error) {\n            return output(error instanceof Error ? error.message : String(error), true);\n          }\n        },\n      },\n      {\n        when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n        name: RUN_FABLE_PLAN_TOOL,\n        label: 'Run Fable Plan',\n        description:\n          'Unavailable in this headless host: no Fable planning broker is configured. Plan using repository inspection instead.',\n        parameters: {\n          type: 'object',\n          properties: {\n            goal: { type: 'array', items: { type: 'string' } },\n            constraints: { type: 'array', items: { type: 'string' } },\n          },\n          required: ['goal'],\n          additionalProperties: false,\n        },\n        executionMode: 'serial',\n        async execute() {\n          return output(\n            'Fable planning is unavailable in the headless host because no broker seam is configured.',\n            true,\n          );\n        },\n      },\n      {\n        when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n        name: WRITE_PLAN_TOOL,\n        label: 'Write Plan',\n        description: 'Save the supplied Markdown plan, or the plan already presented in the local session.',\n        parameters: writePlanParameters,\n        executionMode: 'serial',\n        async execute(toolCallId, parameters, signal) {\n          try {\n            signal?.throwIfAborted();\n            // Remote callers supply their own visible Markdown. Only local calls may use the journal.\n            let content =\n              typeof parameters === 'object' && parameters !== null && 'markdown' in parameters\n                ? parameters.markdown\n                : undefined;\n            if (content !== undefined && typeof content !== 'string')\n              throw new Error('Plan Markdown must be a string.');\n            if (content === undefined)\n              content = visiblePlanForToolCall(await host.context.session.entries(), toolCallId);\n            if (content === undefined) {\n              if (host.context.selection.state?.['minor-mode']?.includes(DOOM_VOICE_AUTO_MODE_ID))\n                throw new Error('Supply Markdown to write_plan during autonomous Voice; UI input is unavailable.');\n              const requested = await host.context.client.request(\n                {\n                  kind: 'input',\n                  title: 'Implementation plan',\n                  multiline: true,\n                },\n                signal,\n              );\n              content = typeof requested === 'string' ? requested : '';\n            }\n            if (typeof content !== 'string' || !content.trim())\n              throw new Error('No implementation plan content was supplied.');\n            const directory = plansDirectory();\n            await mkdir(directory, { recursive: true, mode: 0o700 });\n            const title = planTitleOf(content);\n            const writtenAt = new Date().toISOString();\n            const filename = `${planTitleSlug(content)}-${Date.now()}.md`;\n            const filePath = path.join(directory, filename);\n            await writeFile(filePath, `${content.trim()}\\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });\n            await host.context.session.appendCustomEntry(PLAN_DOCUMENT, {\n              path: filePath,\n              content: content.trim(),\n              title,\n              writtenAt,\n            });\n            announcePlanDocument(filePath, title, writtenAt);\n            await selectPlan(true);\n            const saved = { path: filePath, written: true };\n            return { ...output(saved), structuredContent: saved };\n          } catch (error) {\n            return output(error instanceof Error ? error.message : String(error), true);\n          }\n        },\n      },\n      {\n        when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n        name: COMPLETE_PLAN_TOOL,\n        label: 'Complete Plan',\n        description:\n          'Request exit-or-continue approval in the local DoomPi UI. Requires the user to interact there; this is not a ChatGPT approval dialog.',\n        // No decision parameter: this facet has no narrated review to answer, so a model-supplied\n        // decision would be the agent approving its own plan instead of the reader approving it.\n        parameters: { type: 'object', properties: {}, additionalProperties: false },\n        executionMode: 'serial',\n        async execute(_toolCallId, _parameters, signal) {\n          try {\n            if (host.context.selection.state?.['minor-mode']?.includes(DOOM_VOICE_AUTO_MODE_ID))\n              throw new Error(\n                'UI plan review is unavailable during autonomous Voice. Wait for explicit user direction.',\n              );\n            // The client answers with the option's `value`, so the decision travels with the\n            // question instead of the facet having to recognise the label it rendered.\n            const decision = await host.context.client.request(\n              {\n                kind: 'select',\n                title: PLAN_REVIEW_TITLE,\n                options: PLAN_REVIEW_CHOICES.map((choice) => ({ ...choice })),\n              },\n              signal,\n            );\n            // A dismissed or aborted prompt answers with nothing, and that is not approval.\n            const exited = decision === EXIT_PLAN_DECISION;\n            await host.context.session.appendCustomEntry('plan-review', {\n              decision: exited ? EXIT_PLAN_DECISION : CONTINUE_PLAN_DECISION,\n            });\n            await selectPlan(!exited);\n            return {\n              content: [{ type: 'text', text: exited ? PLAN_EXIT_APPROVED_TEXT : PLAN_CONTINUE_TEXT }],\n              details: { exited },\n            };\n          } catch (error) {\n            return output(error instanceof Error ? error.message : String(error), true);\n          }\n        },\n      },\n    ],\n    hooks: [\n      {\n        when: { state: { 'minor-mode': PLAN_MODE_ID }, attribution: { kind: 'minor', mode: PLAN_MODE_ID } },\n        event: 'before_agent_start',\n        async handle(event) {\n          const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n          const directory = plansDirectory();\n          const sections = [\n            buildPlanModeBasePrompt(directory, PLAN_SERVER_CAPABILITIES),\n            buildFlavorPlanningPrompt(\n              flavor,\n              directory,\n              debugEvidence,\n              PLAN_SERVER_FABLE_STAGE,\n              PLAN_SERVER_CAPABILITIES,\n            ),\n          ];\n          const saved = await latestEntry(PLAN_DOCUMENT);\n          if (saved !== undefined && saved !== null && typeof saved === 'object' && 'path' in saved) {\n            const document = saved as { path: string; content?: string };\n            // Read from disk rather than from what write_plan remembered: the plan is editable in\n            // the cockpit, and a reader who corrected it expects that correction implemented.\n            let content = document.content ?? '';\n            try {\n              content = await readFile(document.path, 'utf8');\n            } catch {\n              content = document.content ?? '';\n            }\n            if (content.trim()) sections.push(`[CURRENT PLAN]\\nSource: ${document.path}\\n\\n${content}`);\n          }\n          return { systemPrompt: `${prompt}\\n\\n${sections.join('\\n\\n')}`.trim() };\n        },\n      },\n      {\n        event: 'session_start',\n        async handle() {\n          await restorePlanState();\n          // A plan written in an earlier session is still the session's plan, so\n          // the dock has to hear about it again on every restart.\n          const pointer = pointers.read(host.context.sessionId);\n          if (pointer)\n            host.context.client.setStatus(\n              PLAN_STATUS_KEY,\n              formatPlanStatus(pointer.title, planStampOf(pointer.writtenAt)),\n            );\n          // Restore a saved model override if Plan was not restored with the session.\n          if (!selected()) await restoreModel();\n        },\n      },\n    ],\n  };\n}\n","import { defineRoot, type RootDeclaration } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext, DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { mountMcpTools } from '../../../../services/mcpTools';\nimport { api } from '../../../../services/planApi';\nimport { createPlanServerSession } from '../../../../services/planServerSession';\n\nexport default defineRoot(\n  ({ agent }: DoomServerPluginContext): RootDeclaration<DoomServerSessionPlugin, DoomServerPluginContext> => {\n    const value = {\n      api: [api],\n      ...(agent ? createPlanServerSession(agent) : {}),\n    };\n    return {\n      value,\n      services: [...(value.services ?? []), ...(value.tools?.length ? [mountMcpTools(value.tools)] : [])],\n    };\n  },\n);\n","import { defineRoute, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../../root.server').default>>['value'];\n\nexport default defineRoute((context: WithRoot<unknown, Root>) => context.root.api![0]!);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[0], {\n  cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.hooks?.[1], {\n  cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.resources?.[0], {\n  cardinality: 'optional',\n});\n","import { defineToolRestriction } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomHeadlessToolRestriction } from '@agimon-ai/doompi-core/headless';\nimport { DOOM_VOICE_AUTO_MODE_ID } from '@agimon-ai/doompi-core/voiceTools';\n\nexport default defineToolRestriction({\n  when: { state: { 'minor-mode': DOOM_VOICE_AUTO_MODE_ID } },\n  excludedTools: ['complete_plan'],\n} satisfies DoomHeadlessToolRestriction);\n","import { defineToolRestriction } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomHeadlessToolRestriction } from '@agimon-ai/doompi-core/headless';\n\nexport default defineToolRestriction({\n  when: { state: { 'minor-mode': 'plan' } },\n  excludedTools: ['edit', 'write'],\n} satisfies DoomHeadlessToolRestriction);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[3], {\n  cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[0], {\n  cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[1], {\n  cardinality: 'optional',\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\ntype Root = Awaited<ReturnType<typeof import('../root.server').default>>['value'];\n\nexport default defineRoutedContribution((context: WithRoot<unknown, Root>) => context.root.tools?.[2], {\n  cardinality: 'optional',\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/plans/route.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/beforeAgentStart.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server';\nimport resourceDoompiUsePlan from '../src/extensions/workspaces/sessions/(backend)/resource/doompiUsePlan.server';\nimport toolRestrictionPlan from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/plan.server';\nimport toolRestrictionPlanReadOnly from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/planReadOnly.server';\nimport toolCompletePlan from '../src/extensions/workspaces/sessions/(backend)/tool/completePlan.server';\nimport toolRecordDebugEvidence from '../src/extensions/workspaces/sessions/(backend)/tool/recordDebugEvidence.server';\nimport toolRunFablePlan from '../src/extensions/workspaces/sessions/(backend)/tool/runFablePlan.server';\nimport toolWritePlan from '../src/extensions/workspaces/sessions/(backend)/tool/writePlan.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n  typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n  values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n  (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n  name: '@agimon-ai/doompi-plan',\n  session: async (context) => {\n    const scopeSession = await rootSession(context);\n    const contextSession = { ...context, root: scopeSession.value };\n    return {\n      ...composeRootHooks(scopeSession),\n      get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, contextSession)]; },\n      get hooks(): DoomServerSessionPlugin['hooks'] { return defined([via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession))]); },\n      get resources(): DoomServerSessionPlugin['resources'] { return defined([at(resourceDoompiUsePlan, contextSession)]); },\n      get toolRestrictions(): DoomServerSessionPlugin['toolRestrictions'] { return [at(toolRestrictionPlan, contextSession), at(toolRestrictionPlanReadOnly, contextSession)]; },\n      get tools(): DoomServerSessionPlugin['tools'] { return defined([via({ name: 'complete_plan' }, at(toolCompletePlan, contextSession)), via({ name: 'record_debug_evidence' }, at(toolRecordDebugEvidence, contextSession)), via({ name: 'run_fable_plan' }, at(toolRunFablePlan, contextSession)), via({ name: 'write_plan' }, at(toolWritePlan, contextSession))]); },\n      services: [...(scopeSession.services ?? [])],\n      get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n    };\n  },\n});\n\nexport default facet;\n"],"mappings":";;;;;;;;;;;;;;;AAEA,MAAM,WAAW,KAAK,OAAO,EAAE,WAAW,EAAE,CAAC;AAEJ,KAAK,OAAO,EAAE,SAAS,GAAG,EAAE,sBAAsB,MAAM,CAAC;AAClG,MAAa,sBAAsB,KAAK,OAAO,EAAE,UAAU,KAAK,SAAS,QAAQ,EAAE,GAAG,EAAE,sBAAsB,MAAM,CAAC;;;ACCrH,MAAa,yBAAyB;AAUtC,SAAgB,cAAc,OAAoC;CAChE,QAAQ,YAA2B;EACjC,QAAQ,QAAQ,oBAAoB;GAClC,gBAAgB,QAAQ,wBAAwB;IAC9C,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,SAAS,IAAI;IACtD,aAAa,MAAM,KAAK,SAAS,KAAK,IAAI;GAC5C,CAA0B;EAC5B,CAAC;CACH;AACF;;;;;;;;;;;;;;;;;;ACNA,IAAA,oBAAe,gBAAgB;CAC7B,SAAS;EACP,QAAQ;EACR,MAAM;EACN,UAAU,YAA4B;CACxC;CACA,MAAM;EACJ,QAAQ;EACR,MAAM;EACN,UAAU,YAA0B;CACtC;AACF,CAAC;;;;;;;;;;;;;;;;;;;;;;ACCD,MAAa,iBAAiB;AAE9B,MAAM,UAAU;AAChB,MAAM,aAAa;AACnB,MAAM,aAAa;AAQnB,SAAS,OAAO,SAAyB;CACvC,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,SAAS,MAAM,CAAC,CAAC,OAAO,KAAK;AAClE;;AAGA,eAAe,SACb,UAC8E;CAC9E,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,GAAG,SAAS,QAAQ;CAClC,QAAQ;EACN,OAAO;GAAE,SAAS;GAAI,MAAM;GAAI,aAAa;GAAM,QAAQ;EAAiC;CAC9F;CACA,IAAI,IAAI,aAAA,SACN,OAAO;EAAE,SAAS;EAAI,MAAM;EAAI,aAAa;EAAM,QAAQ,2BAA2B,eAAe;CAAQ;CAE/G,MAAM,UAAU,IAAI,SAAS,MAAM;CACnC,OAAO;EAAE;EAAS,MAAM,OAAO,OAAO;EAAG,aAAa;CAAM;AAC9D;AAEA,SAAgB,cAAc,UAA0B,CAAC,GAAS;CAChE,MAAM,MAAM,IAAI,KAAK;CACrB,MAAM,WAAW,QAAQ,YAAY,IAAI,mBAAmB,EAAE,KAAK,QAAQ,IAAI,CAAC;CAChF,MAAM,mBACJ,QAAQ,cAAc,KAAA,IAAY,KAAA,IAAY,SAAS,KAAK,QAAQ,SAAS;CAE/E,IAAI,IAAIA,kBAAO,QAAQ,MAAM,OAAO,YAAY;EAC9C,MAAM,UAAU,WAAW;EAC3B,IAAI,YAAY,KAAA,GAAW,OAAO,QAAQ,KAAK,EAAE,OAAO,QAAQ,GAAG,GAAG;EACtE,MAAM,OAAuB;GAC3B,MAAM,QAAQ;GACd,OAAO,QAAQ;GACf,WAAW,QAAQ;GACnB,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;GACjE,GAAI,MAAM,SAAS,QAAQ,IAAI;EACjC;EACA,OAAO,QAAQ,KAAK,IAAI;CAC1B,CAAC;CAED,IAAI,IAAIA,kBAAO,KAAK,MAAM,OAAO,YAAY;EAC3C,IAAI;EACJ,IAAI;GACF,UAAW,MAAM,QAAQ,IAAI,KAAK;EACpC,QAAQ;GACN,OAAO,QAAQ,KAAK,EAAE,OAAO,6BAA6B,GAAG,GAAG;EAClE;EACA,IAAI,OAAO,QAAQ,YAAY,YAAY,OAAO,QAAQ,iBAAiB,UACzE,OAAO,QAAQ,KAAK,EAAE,OAAO,mEAAmE,GAAG,GAAG;EAExG,MAAM,UAAU,WAAW;EAC3B,IAAI,YAAY,KAAA,GAAW,OAAO,QAAQ,KAAK,EAAE,OAAO,QAAQ,GAAG,GAAG;EAEtE,MAAM,UAAU,MAAM,SAAS,QAAQ,IAAI;EAC3C,IAAI,QAAQ,aAAa,OAAO,QAAQ,KAAK,EAAE,OAAO,QAAQ,UAAU,QAAQ,GAAG,GAAG;EACtF,IAAI,QAAQ,SAAS,QAAQ,cAC3B,OAAO,QAAQ,KAAK;GAAE,OAAO;GAAY,MAAM,QAAQ;EAAK,GAAG,GAAG;EAKpE,MAAM,QAAQ,MAAM,GAAG,MAAM,QAAQ,IAAI;EACzC,IAAI,CAAC,MAAM,OAAO,KAAK,MAAM,UAAU,GAAG,OAAO,QAAQ,KAAK,EAAE,OAAO,WAAW,GAAG,GAAG;EAExF,MAAM,GAAG,UAAU,QAAQ,MAAM,QAAQ,SAAS;GAAE,UAAU;GAAQ,MAAM;EAAM,CAAC;EACnF,OAAO,QAAQ,KAAK,EAAE,MAAM,OAAO,QAAQ,OAAO,EAAE,CAAwB;CAC9E,CAAC;CAED,OAAO;AACT;;AAGA,MAAa,MAAe;CAC1B,UAAU;CACV,MAAM,SAAyC;EAC7C,MAAM,MAAM,cAAc,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU,CAAC;EACjG,OAAO;GACL,QAAQ,YAAY,IAAI,MAAM,OAAO;GAGrC,aAAa,KAAA;EACf;CACF;AACF;;;AC/EA,MAAM,6BAA6B;AACnC,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,eAAe;AACrB,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAC5B,MAAM,gBAAgB;;;;;AAKtB,MAAM,0BAA0B;;;;;AAKhC,MAAa,2BAAiD;CAC5D,2BAA2B;CAC3B,gBAAgB;CAChB,gBAAgB;AAClB;AAEA,MAAM,uBAAuC;CAC3C,OAAO;CACP,cAAc;EAAC;EAAQ;EAAQ;EAAQ;EAAQ;EAAM;CAAK;CAC1D,eAAe,CAAC,MAAM;CACtB,eAAe;CACf,yBAAyB,CAAC;CAC1B,gBAAgB;AAClB;AAEA,SAAS,yBAAyB,MAA2D;CAC3F,QAAQ,YAAY;EAClB,QAAQ,OAAO,CAAC,4BAA4B,IAAI,UAAU;GACxD,MAAM,UAAU,8BAA8B,KAAK;GACnD,IAAI,CAAC,SAAS,OAAO,KAAA;GACrB,IAAI;GACJ,MAAM,aAAmB;IACvB,IAAI,aAAa,IAAI,GAAG;KACtB,IAAI,QAAQ,OAAO,OAAO,oBAAoB;UACzC,SAAS,QAAQ,SAAS,oBAAoB;IACrD,OAAO;KACL,QAAQ,QAAQ;KAChB,SAAS,KAAA;IACX;GACF;GACA,KAAK;GACL,MAAM,aAAa,KAAK,mBAAmB,IAAI,CAAC;GAChD,aAAa,QAAQ,QAAQ;EAC/B,CAAC;CACH;AACF;AAEA,SAAS,aAAa,MAAwC;CAC5D,QAAQ,KAAK,QAAQ,UAAU,QAAQ,iBAAiB,CAAC,EAAA,CAAG,SAAS,YAAY;AACnF;AAEA,SAAS,OAAO,OAAgB,UAAU,OAA+B;CACvE,OAAO;EACL,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,OAAO,MAAM,CAAC;EAAE,CAAC;EACpG,SAAS;EACT,GAAI,UAAU,EAAE,SAAS,KAAK,IAAI,CAAC;CACrC;AACF;AAEA,SAAgB,wBACd,MAC8G;CAC9G,IAAI,SAAyB;CAC7B,IAAI;CACJ,IAAI;CACJ,MAAM,iBAA0B,aAAa,IAAI;CACjD,MAAM,sBAA8B,KAAK,QAAQ,YAAY,QAAQ,GAAG,QAAQ;CAGhF,MAAM,uBACJ,8BACE,eAAe,KAAK,QAAQ,UAAU,cAAc,CAAC,CAAC,CAAC,OAAO,UAAU,gBACxE,KAAK,QAAQ,UACb,cAAc,CAChB;CACF,MAAM,WAAW,IAAI,mBAAmB,EAAE,KAAK,KAAK,QAAQ,YAAY,CAAC;;;;;;;;CAQzE,MAAM,wBAAwB,UAAkB,OAAe,cAA4B;EACzF,IAAI;GACF,SAAS,MAAM,KAAK,QAAQ,WAAW;IAAE,MAAM;IAAU;IAAO;GAAU,CAAC;EAC7E,QAAQ,CAGR;EACA,KAAK,QAAQ,OAAO,UAAU,iBAAiB,iBAAiB,OAAO,YAAY,SAAS,CAAC,CAAC;CAChG;CACA,MAAM,kBAAkC;EACtC,MAAM,SAAS,SAAS;EACxB,OAAO;GACL,YAAY,SAAS,WAAW;GAChC,WAAW;GACX,GAAI,SAAS;IAAE,QAAQ,GAAG,OAAO;IAAe,qBAAqB;GAAO,IAAI,CAAC;GACjF,SAAS,CACP;IACE,IAAI;IACJ,SAAS;GACX,GACA;IACE,IAAI;IACJ,SAAS;IACT,GAAI,SAAS,CAAC,IAAI,EAAE,gBAAgB,yBAAyB;GAC/D,CACF;EACF;CACF;CACA,MAAM,oBAA0B,WAAW,QAAQ;CACnD,MAAM,eAAe,YAA2B;EAC9C,MAAM,UAAU,KAAK,QAAQ;EAE7B,MAAM,QAAO,MADS,QAAQ,QAAQ;GAAE,MAAM;GAAU,YAAY;GAAqB,OAAO;EAAE,CAAC,EAAA,CAC9E,EAAE,EAAE;EACzB,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM;EACzC,IACE,OAAO,SAAS,YAChB,EAAE,mBAAmB,SACrB,CAAC;GAAC;GAAO;GAAW;GAAO;GAAU;GAAQ;GAAS;EAAK,CAAC,CAAC,SAAS,OAAO,KAAK,aAAa,CAAC,GAEhG,MAAM,IAAI,MAAM,gDAAgD;EAClE,IAAI,CAAC,QAAQ,kBAAkB,MAAM,IAAI,MAAM,iDAAiD;EAChG,MAAM,QAAQ,iBAAiB,IAAiC;EAChE,MAAM,QAAQ,kBAAkB,qBAAqB,IAAI;CAC3D;CACA,MAAM,aAAa,OAAO,SAAkB,aAAa,WAA0B;EACjF,MAAM,aAAa,SAAS;EAC5B,MAAM,UAAU,KAAK,QAAQ;EAC7B,IAAI,WAAW,CAAC,YAAY;GAC1B,MAAM,SAAS,eAAe,KAAK,QAAQ,UAAU,cAAc,CAAC,CAAC,CAAC,OAAO,UAAU;GACvF,IAAI,QAAQ,SAAS,QAAQ,UAAU;IACrC,IAAI,CAAC,QAAQ,qBAAqB,CAAC,QAAQ,kBACzC,MAAM,IAAI,MAAM,oDAAoD;IACtE,MAAM,WAAW,MAAM,QAAQ,kBAAkB;IACjD,MAAM,WAA+C,CAAC;IACtD,IAAI,OAAO,OAAO;KAChB,MAAM,YAAY,OAAO,MAAM,QAAQ,GAAG;KAC1C,MAAM,WAAW,YAAY,IAAI,OAAO,MAAM,MAAM,GAAG,SAAS,IAAI,SAAS,OAAO;KACpF,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,sCAAsC;KACrE,SAAS,QAAQ;MAAE;MAAU,IAAI,YAAY,IAAI,OAAO,MAAM,MAAM,YAAY,CAAC,IAAI,OAAO;KAAM;IACpG;IACA,IAAI,OAAO,UAAU,SAAS,gBAAgB,OAAO;IACrD,MAAM,QAAQ,kBAAkB,qBAAqB,QAAQ;IAC7D,IAAI;KACF,MAAM,QAAQ,iBAAiB,QAAQ;IACzC,SAAS,OAAO;KACd,MAAM,QAAQ,iBAAiB,QAAQ;KACvC,MAAM,QAAQ,kBAAkB,qBAAqB,IAAI;KACzD,MAAM;IACR;GACF;EACF,OAAO,IAAI,CAAC,WAAW,YACrB,MAAM,aAAa;EAErB,MAAM,SAAS,KAAK,QAAQ,UAAU,QAAQ,iBAAiB,CAAC,EAAA,CAAG,QAAQ,SAAS,SAAS,YAAY;EACzG,MAAM,KAAK,gBAAgB;GACzB,MAAM;GACN,KAAK;GACL,QAAQ,UAAU,CAAC,GAAG,OAAO,YAAY,IAAI;EAC/C,CAAC;EACD,SAAS;EAGT,MAAM,QAAQ,kBAAkB,sBAAsB,UAAU,EAAE,OAAO,IAAI,IAAI;EACjF,YAAY;CACd;;CAGA,MAAM,cAAc,OAAO,eAAyC;EAElE,QAAO,MADe,KAAK,QAAQ,QAAQ,QAAQ;GAAE,MAAM;GAAU;GAAY,OAAO;EAAE,CAAC,EAAA,CAC5E,EAAE,EAAE,QAAQ,KAAA;CAC7B;CAEA,MAAM,mBAAmB,YAA2B;EAClD,MAAM,QAAQ,MAAM,YAAY,oBAAoB;EACpD,IAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,OAAO,UAAU,YAAY,YAAY,OAAO;GAC3F,MAAM,YAAY,OAAQ,MAA8B,MAAM;GAC9D,IAAI,cAAc,YAAY,cAAc,WAAW,cAAc,SAAS,SAAS;EACzF;EACA,MAAM,WAAW,MAAM,YAAY,mBAAmB;EACtD,IAAI,aAAa,KAAA,KAAa,aAAa,MAAM;EACjD,IAAI;GACF,gBAAgB,yBAAyB,QAAQ;EACnD,QAAQ;GAEN,gBAAgB,KAAA;EAClB;CACF;CACA,YAAY,gBAAgB;EAC1B,YAAY;GACV,QAAQ;GACR,IAAI;GACJ,OAAO;GACP,aAAa;GACb,OAAO;GACP,SAAS,CACP;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,UAAU,CAAC,UAAU;IACrB,YAAY,CACV;KACE,MAAM;KACN,OAAO;KACP,MAAM;KACN,UAAU;KACV,SAAS;MACP;OAAE,OAAO;OAAU,OAAO;MAAS;MACnC;OAAE,OAAO;OAAS,OAAO;MAAQ;MACjC;OAAE,OAAO;OAAS,OAAO;MAAQ;KACnC;IACF,CACF;GACF,GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,UAAU,CAAC,UAAU;IACrB,YAAY,CAAC;GACf,CACF;EACF;EACA,aAAa,UAAU;EACvB,MAAM,aAAa,UAAU,UAAU,gBAAgB,EAAE,UAAU;GACjE,OAAO,eAAe;GACtB,IAAI,aAAa,YAAY;IAC3B,MAAM,aAAa,eAAe;IAClC,IAAI,eAAe,YAAY,eAAe,WAAW,eAAe,SACtE,MAAM,IAAI,MAAM,kCAAkC;IACpD,MAAM,WAAW,MAAM,UAAU;IACjC,OAAO,EAAE,SAAS,gCAAgC,WAAW,UAAU;GACzE;GACA,IAAI,aAAa,cAAc;IAC7B,MAAM,WAAW,KAAK;IACtB,OAAO,EAAE,SAAS,yBAAyB;GAC7C;GACA,MAAM,IAAI,MAAM,6BAA6B,UAAU;EACzD;CACF,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CACxB,OAAO;EACL,UAAU,CAAC,iBAAiB,CAAC,SAAS,CAAC,GAAG,yBAAyB,IAAI,CAAC;EACxE,WAAW,CACT;GACE,MAAM;IAAE,OAAO,EAAE,cAAc,aAAa;IAAG,aAAa;KAAE,MAAM;KAAS,MAAM;IAAa;GAAE;GAClG,MAAM;GACN,MAAM;GACN,YAAY,oBAAoB,YAAY,KAAK,sCAAsC;EACzF,CACF;EACA,OAAO;GACL;IACE,MAAM;KAAE,OAAO,EAAE,cAAc,aAAa;KAAG,aAAa;MAAE,MAAM;MAAS,MAAM;KAAa;IAAE;IAClG,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY;KACV,MAAM;KACN,YAAY;MACV,OAAO,EAAE,MAAM,SAAS;MACxB,kBAAkB,EAAE,MAAM,SAAS;MACnC,qBAAqB,EAAE,MAAM,SAAS;MACtC,gBAAgB,EAAE,MAAM,SAAS;MACjC,MAAM;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACjD,yBAAyB;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACpE,eAAe;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MAC1D,wBAAwB;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACnE,gBAAgB;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MAC3D,YAAY;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACvD,eAAe;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MAC1D,YAAY;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACvD,qBAAqB;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;KAClE;KACA,UAAU,CAAC,OAAO;KAClB,sBAAsB;IACxB;IACA,eAAe;IACf,MAAM,QAAQ,aAAa,YAAY;KACrC,IAAI;MACF,MAAM,iBAAiB,yBAAyB,UAAU;MAC1D,MAAM,KAAK,QAAQ,QAAQ,kBAAkB,qBAAqB,cAAc;MAEhF,gBAAgB;MAChB,OAAO,OAAO,EAAE,UAAU,KAAK,CAAC;KAClC,SAAS,OAAO;MACd,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI;KAC5E;IACF;GACF;GACA;IACE,MAAM;KAAE,OAAO,EAAE,cAAc,aAAa;KAAG,aAAa;MAAE,MAAM;MAAS,MAAM;KAAa;IAAE;IAClG,MAAM;IACN,OAAO;IACP,aACE;IACF,YAAY;KACV,MAAM;KACN,YAAY;MACV,MAAM;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACjD,aAAa;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;KAC1D;KACA,UAAU,CAAC,MAAM;KACjB,sBAAsB;IACxB;IACA,eAAe;IACf,MAAM,UAAU;KACd,OAAO,OACL,4FACA,IACF;IACF;GACF;GACA;IACE,MAAM;KAAE,OAAO,EAAE,cAAc,aAAa;KAAG,aAAa;MAAE,MAAM;MAAS,MAAM;KAAa;IAAE;IAClG,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY;IACZ,eAAe;IACf,MAAM,QAAQ,YAAY,YAAY,QAAQ;KAC5C,IAAI;MACF,QAAQ,eAAe;MAEvB,IAAI,UACF,OAAO,eAAe,YAAY,eAAe,QAAQ,cAAc,aACnE,WAAW,WACX,KAAA;MACN,IAAI,YAAY,KAAA,KAAa,OAAO,YAAY,UAC9C,MAAM,IAAI,MAAM,iCAAiC;MACnD,IAAI,YAAY,KAAA,GACd,UAAU,uBAAuB,MAAM,KAAK,QAAQ,QAAQ,QAAQ,GAAG,UAAU;MACnF,IAAI,YAAY,KAAA,GAAW;OACzB,IAAI,KAAK,QAAQ,UAAU,QAAQ,aAAa,EAAE,SAAS,uBAAuB,GAChF,MAAM,IAAI,MAAM,iFAAiF;OACnG,MAAM,YAAY,MAAM,KAAK,QAAQ,OAAO,QAC1C;QACE,MAAM;QACN,OAAO;QACP,WAAW;OACb,GACA,MACF;OACA,UAAU,OAAO,cAAc,WAAW,YAAY;MACxD;MACA,IAAI,OAAO,YAAY,YAAY,CAAC,QAAQ,KAAK,GAC/C,MAAM,IAAI,MAAM,8CAA8C;MAChE,MAAM,YAAY,eAAe;MACjC,MAAM,MAAM,WAAW;OAAE,WAAW;OAAM,MAAM;MAAM,CAAC;MACvD,MAAM,QAAQ,YAAY,OAAO;MACjC,MAAM,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;MACzC,MAAM,WAAW,GAAG,cAAc,OAAO,EAAE,GAAG,KAAK,IAAI,EAAE;MACzD,MAAM,WAAW,KAAK,KAAK,WAAW,QAAQ;MAC9C,MAAM,UAAU,UAAU,GAAG,QAAQ,KAAK,EAAE,KAAK;OAAE,UAAU;OAAQ,MAAM;OAAO,MAAM;MAAK,CAAC;MAC9F,MAAM,KAAK,QAAQ,QAAQ,kBAAkB,eAAe;OAC1D,MAAM;OACN,SAAS,QAAQ,KAAK;OACtB;OACA;MACF,CAAC;MACD,qBAAqB,UAAU,OAAO,SAAS;MAC/C,MAAM,WAAW,IAAI;MACrB,MAAM,QAAQ;OAAE,MAAM;OAAU,SAAS;MAAK;MAC9C,OAAO;OAAE,GAAG,OAAO,KAAK;OAAG,mBAAmB;MAAM;KACtD,SAAS,OAAO;MACd,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI;KAC5E;IACF;GACF;GACA;IACE,MAAM;KAAE,OAAO,EAAE,cAAc,aAAa;KAAG,aAAa;MAAE,MAAM;MAAS,MAAM;KAAa;IAAE;IAClG,MAAM;IACN,OAAO;IACP,aACE;IAGF,YAAY;KAAE,MAAM;KAAU,YAAY,CAAC;KAAG,sBAAsB;IAAM;IAC1E,eAAe;IACf,MAAM,QAAQ,aAAa,aAAa,QAAQ;KAC9C,IAAI;MACF,IAAI,KAAK,QAAQ,UAAU,QAAQ,aAAa,EAAE,SAAS,uBAAuB,GAChF,MAAM,IAAI,MACR,0FACF;MAYF,MAAM,SAAS,MATQ,KAAK,QAAQ,OAAO,QACzC;OACE,MAAM;OACN,OAAO;OACP,SAAS,oBAAoB,KAAK,YAAY,EAAE,GAAG,OAAO,EAAE;MAC9D,GACA,MACF,MAE4B;MAC5B,MAAM,KAAK,QAAQ,QAAQ,kBAAkB,eAAe,EAC1D,UAAU,SAAS,qBAAqB,uBAC1C,CAAC;MACD,MAAM,WAAW,CAAC,MAAM;MACxB,OAAO;OACL,SAAS,CAAC;QAAE,MAAM;QAAQ,MAAM,SAAS,0BAA0B;OAAmB,CAAC;OACvF,SAAS,EAAE,OAAO;MACpB;KACF,SAAS,OAAO;MACd,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI;KAC5E;IACF;GACF;EACF;EACA,OAAO,CACL;GACE,MAAM;IAAE,OAAO,EAAE,cAAc,aAAa;IAAG,aAAa;KAAE,MAAM;KAAS,MAAM;IAAa;GAAE;GAClG,OAAO;GACP,MAAM,OAAO,OAAO;IAClB,MAAM,SAAS,OAAO,MAAM,iBAAiB,WAAW,MAAM,eAAe;IAC7E,MAAM,YAAY,eAAe;IACjC,MAAM,WAAW,CACf,wBAAwB,WAAW,wBAAwB,GAC3D,0BACE,QACA,WACA,eACA,yBACA,wBACF,CACF;IACA,MAAM,QAAQ,MAAM,YAAY,aAAa;IAC7C,IAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,OAAO,UAAU,YAAY,UAAU,OAAO;KACzF,MAAM,WAAW;KAGjB,IAAI,UAAU,SAAS,WAAW;KAClC,IAAI;MACF,UAAU,MAAM,SAAS,SAAS,MAAM,MAAM;KAChD,QAAQ;MACN,UAAU,SAAS,WAAW;KAChC;KACA,IAAI,QAAQ,KAAK,GAAG,SAAS,KAAK,2BAA2B,SAAS,KAAK,MAAM,SAAS;IAC5F;IACA,OAAO,EAAE,cAAc,GAAG,OAAO,MAAM,SAAS,KAAK,MAAM,IAAI,KAAK,EAAE;GACxE;EACF,GACA;GACE,OAAO;GACP,MAAM,SAAS;IACb,MAAM,iBAAiB;IAGvB,MAAM,UAAU,SAAS,KAAK,KAAK,QAAQ,SAAS;IACpD,IAAI,SACF,KAAK,QAAQ,OAAO,UAClB,iBACA,iBAAiB,QAAQ,OAAO,YAAY,QAAQ,SAAS,CAAC,CAChE;IAEF,IAAI,CAAC,SAAS,GAAG,MAAM,aAAa;GACtC;EACF,CACF;CACF;AACF;;;AChgBA,IAAA,sBAAe,YACZ,EAAE,YAAwG;CACzG,MAAM,QAAQ;EACZ,KAAK,CAAC,GAAG;EACT,GAAI,QAAQ,wBAAwB,KAAK,IAAI,CAAC;CAChD;CACA,OAAO;EACL;EACA,UAAU,CAAC,GAAI,MAAM,YAAY,CAAC,GAAI,GAAI,MAAM,OAAO,SAAS,CAAC,cAAc,MAAM,KAAK,CAAC,IAAI,CAAC,CAAE;CACpG;AACF,CACF;;;ACdA,IAAA,uBAAe,aAAa,YAAqC,QAAQ,KAAK,IAAK,EAAG;;;ACAtF,IAAA,kCAAe,0BAA0B,YAAqC,QAAQ,KAAK,QAAQ,IAAI,EACrG,aAAa,WACf,CAAC;;;ACFD,IAAA,8BAAe,0BAA0B,YAAqC,QAAQ,KAAK,QAAQ,IAAI,EACrG,aAAa,WACf,CAAC;;;ACFD,IAAA,+BAAe,0BAA0B,YAAqC,QAAQ,KAAK,YAAY,IAAI,EACzG,aAAa,WACf,CAAC;;;ACFD,IAAA,sBAAe,sBAAsB;CACnC,MAAM,EAAE,OAAO,EAAE,cAAc,wBAAwB,EAAE;CACzD,eAAe,CAAC,eAAe;AACjC,CAAuC;;;ACJvC,IAAA,8BAAe,sBAAsB;CACnC,MAAM,EAAE,OAAO,EAAE,cAAc,OAAO,EAAE;CACxC,eAAe,CAAC,QAAQ,OAAO;AACjC,CAAuC;;;ACFvC,IAAA,8BAAe,0BAA0B,YAAqC,QAAQ,KAAK,QAAQ,IAAI,EACrG,aAAa,WACf,CAAC;;;ACFD,IAAA,qCAAe,0BAA0B,YAAqC,QAAQ,KAAK,QAAQ,IAAI,EACrG,aAAa,WACf,CAAC;;;ACFD,IAAA,8BAAe,0BAA0B,YAAqC,QAAQ,KAAK,QAAQ,IAAI,EACrG,aAAa,WACf,CAAC;;;ACFD,IAAA,2BAAe,0BAA0B,YAAqC,QAAQ,KAAK,QAAQ,IAAI,EACrG,aAAa,WACf,CAAC;;;ACWD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;;AAEpE,MAAM,WAAc,WAClB,OAAO,QAAQ,UAAsB,UAAU,KAAA,CAAS;AAC1D,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,QAAQ,mBAAmB;CACtC,MAAM;CACN,SAAS,OAAO,YAAY;EAC1B,MAAM,eAAe,MAAMC,oBAAY,OAAO;EAC9C,MAAM,iBAAiB;GAAE,GAAG;GAAS,MAAM,aAAa;EAAM;EAC9D,OAAO;GACL,GAAG,iBAAiB,YAAY;GAChC,IAAI,MAAsC;IAAE,OAAO,CAAC,GAAGC,sBAAU,cAAc,CAAC;GAAG;GACnF,IAAI,QAA0C;IAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,GAAG,GAAGC,iCAAsB,cAAc,CAAC,GAAG,IAAI,EAAE,OAAO,gBAAgB,GAAG,GAAGC,6BAAkB,cAAc,CAAC,CAAC,CAAC;GAAG;GACzN,IAAI,YAAkD;IAAE,OAAO,QAAQ,CAAC,GAAGC,8BAAuB,cAAc,CAAC,CAAC;GAAG;GACrH,IAAI,mBAAgE;IAAE,OAAO,CAAC,GAAGC,qBAAqB,cAAc,GAAG,GAAGC,6BAA6B,cAAc,CAAC;GAAG;GACzK,IAAI,QAA0C;IAAE,OAAO,QAAQ;KAAC,IAAI,EAAE,MAAM,gBAAgB,GAAG,GAAGC,6BAAkB,cAAc,CAAC;KAAG,IAAI,EAAE,MAAM,wBAAwB,GAAG,GAAGC,oCAAyB,cAAc,CAAC;KAAG,IAAI,EAAE,MAAM,iBAAiB,GAAG,GAAGC,6BAAkB,cAAc,CAAC;KAAG,IAAI,EAAE,MAAM,aAAa,GAAG,GAAGC,0BAAe,cAAc,CAAC;IAAC,CAAC;GAAG;GACpW,UAAU,CAAC,GAAI,aAAa,YAAY,CAAC,CAAE;GAC3C,IAAI,aAAoD;IAAE,OAAO,CAAC,GAAI,aAAa,cAAc,CAAC,CAAE;GAAG;EACzG;CACF;AACF,CAAC"}