@zooid/core 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/env-interpolation.ts","../src/acp-registry.ts","../src/approval-correlator.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { parse } from 'yaml'\nimport type { AcpAgentSpec } from './acp-types.js'\nimport { isPreset } from '@zooid/acp-client'\nimport { interpolateEnv, interpolateString } from './env-interpolation.js'\nimport type {\n AgentConfig,\n CliFlags,\n ContainerConfig,\n HttpBinding,\n HttpTransportConfig,\n MatrixBinding,\n MatrixTransportConfig,\n TransportConfig,\n ZooidConfig,\n ZooidContainerConfig,\n} from './types.js'\n\nconst AGENT_NAME_RE = /^[a-z][a-z0-9-]{0,31}$/\nconst MATRIX_USER_ID_RE = /^@[A-Za-z0-9._\\-=/+]+:[A-Za-z0-9.\\-]+$/\nconst MATRIX_USER_LOCALPART_RE = /^@[a-z0-9._=/+\\-]+$/\nconst MATRIX_ROOM_IDENT_RE = /^[#!]/\n\nfunction deriveServerName(userNamespace: string): string {\n // user_namespace is a regex like `@.*:localhost`. The part after the first\n // `:` is the server_name (strip a trailing `)` left over from a wrapped\n // group like `@(.*):localhost)`).\n const tail = userNamespace.split(':').slice(1).join(':').replace(/\\\\?\\)?$/, '')\n if (!tail) throw new Error(`user_namespace missing server_name: ${userNamespace}`)\n return tail\n}\n\nconst TRANSPORT_KINDS = ['matrix', 'http'] as const\ntype TransportKind = (typeof TRANSPORT_KINDS)[number]\n\nfunction parseAcpBlock(name: string, raw: unknown): AcpAgentSpec {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error(`agents.${name}.acp: must be a mapping with either preset or command`)\n }\n const a = raw as Record<string, unknown>\n const hasPreset = a.preset !== undefined\n const hasCommand = a.command !== undefined\n if (hasPreset && hasCommand) {\n throw new Error(\n `agents.${name}.acp: specify either preset or command, not both`,\n )\n }\n if (!hasPreset && !hasCommand) {\n throw new Error(\n `agents.${name}.acp: must specify either preset or command`,\n )\n }\n if (hasPreset) {\n if (typeof a.preset !== 'string' || a.preset.length === 0) {\n throw new Error(`agents.${name}.acp.preset: must be a non-empty string`)\n }\n if (!isPreset(a.preset)) {\n throw new Error(\n `agents.${name}.acp.preset: unknown preset \"${a.preset}\"`,\n )\n }\n const out: { preset: string; model?: string } = { preset: a.preset }\n if (a.model !== undefined) {\n if (typeof a.model !== 'string' || a.model.trim().length === 0) {\n throw new Error(`agents.${name}.acp.model: must be a non-empty string`)\n }\n out.model = a.model.trim()\n }\n return out as AcpAgentSpec\n }\n if (typeof a.command !== 'string' || a.command.length === 0) {\n throw new Error(`agents.${name}.acp.command: must be a non-empty string`)\n }\n const args: string[] = []\n if (a.args !== undefined) {\n if (!Array.isArray(a.args)) {\n throw new Error(`agents.${name}.acp.args: must be an array of strings`)\n }\n for (const v of a.args) {\n if (typeof v !== 'string') {\n throw new Error(`agents.${name}.acp.args[]: must be a string`)\n }\n args.push(v)\n }\n }\n return { command: a.command, args } as AcpAgentSpec\n}\n\nfunction parseApprovalTimeout(name: string, raw: unknown): number {\n if (raw === undefined) return 0\n if (raw === 0 || raw === '0') return 0\n if (typeof raw !== 'string') {\n throw new Error(\n `agents.${name}.approval_timeout: must be a duration like \"1h\", \"15m\", \"30s\", or 0 to disable (got ${JSON.stringify(raw)})`,\n )\n }\n const m = /^(\\d+)(s|m|h)$/.exec(raw)\n if (!m) {\n throw new Error(\n `agents.${name}.approval_timeout: \"${raw}\" is not a valid duration (use \"<n>s\", \"<n>m\", or \"<n>h\")`,\n )\n }\n const n = Number(m[1])\n switch (m[2]) {\n case 's':\n return n * 1000\n case 'm':\n return n * 60_000\n case 'h':\n return n * 60 * 60_000\n }\n throw new Error('unreachable')\n}\n\nfunction parseAgentContainer(\n name: string,\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n): ContainerConfig {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error(`agents.${name}.container must be a mapping`)\n }\n const r = raw as Record<string, unknown>\n const out: ContainerConfig = {}\n if (r.image !== undefined) {\n if (typeof r.image !== 'string' || r.image.length === 0) {\n throw new Error(`agents.${name}.container.image must be a non-empty string`)\n }\n out.image = r.image\n }\n if (r.env !== undefined && r.env !== null) {\n if (typeof r.env !== 'object' || Array.isArray(r.env)) {\n throw new Error(`agents.${name}.container.env must be a mapping`)\n }\n const rawEnv = r.env as Record<string, unknown>\n const stringEnv: Record<string, string> = {}\n for (const [k, v] of Object.entries(rawEnv)) {\n if (typeof v !== 'string') {\n throw new Error(\n `agents.${name}.container.env.${k}: must be a string (got ${typeof v})`,\n )\n }\n stringEnv[k] = v\n }\n out.env = interpolateEnv(stringEnv, processEnv, `agents.${name}.container.env`)\n }\n return out\n}\n\nfunction parseZooidContainer(raw: unknown): ZooidContainerConfig {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('container must be a mapping')\n }\n const r = raw as Record<string, unknown>\n const out: ZooidContainerConfig = {}\n if (r.env !== undefined) {\n throw new Error(\n \"Top-level 'container.env' is not supported (workforce-level env defaults are out of scope; see [ZOD043]). \" +\n 'Move env entries to per-agent container.env.',\n )\n }\n if (r.image !== undefined) {\n if (typeof r.image !== 'string' || r.image.length === 0) {\n throw new Error('container.image must be a non-empty string')\n }\n out.image = r.image\n }\n return out\n}\n\nfunction parseTransports(\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n): Record<string, TransportConfig> {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error('transports: must be a mapping with at least one entry')\n }\n const r = raw as Record<string, unknown>\n const names = Object.keys(r)\n if (names.length === 0) {\n throw new Error('transports: at least one transport must be declared')\n }\n const out: Record<string, TransportConfig> = {}\n for (const name of names) {\n out[name] = parseTransport(name, r[name], processEnv)\n }\n const matrixEntries = Object.entries(out).filter(\n (e): e is [string, MatrixTransportConfig] => e[1].type === 'matrix',\n )\n if (matrixEntries.length === 1) {\n const [, mt] = matrixEntries[0]!\n if (mt.as_token === '__INFER__') {\n const v = interpolateString('${MATRIX_AS_TOKEN}', processEnv)\n if (v.length === 0) {\n throw new Error(\n 'transports.matrix.as_token: env var MATRIX_AS_TOKEN is not set ' +\n '(set it in your shell or .env, or declare as_token explicitly in zooid.yaml)',\n )\n }\n mt.as_token = v\n }\n if (mt.hs_token === '__INFER__') {\n const v = interpolateString('${MATRIX_HS_TOKEN}', processEnv)\n if (v.length === 0) {\n throw new Error(\n 'transports.matrix.hs_token: env var MATRIX_HS_TOKEN is not set ' +\n '(set it in your shell or .env, or declare hs_token explicitly in zooid.yaml)',\n )\n }\n mt.hs_token = v\n }\n } else if (matrixEntries.length > 1) {\n for (const [tname, mt] of matrixEntries) {\n if (mt.as_token === '__INFER__' || mt.hs_token === '__INFER__') {\n throw new Error(\n `transports.${tname}: as_token / hs_token must be set explicitly when more than one matrix transport is declared ` +\n `(no sensible default env var across multiple transports)`,\n )\n }\n }\n }\n return out\n}\n\nfunction parseTransport(\n name: string,\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n): TransportConfig {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error(`transports.${name}: must be a mapping`)\n }\n const r = raw as Record<string, unknown>\n const inferredType =\n r.type ?? (name === 'matrix' || name === 'http' ? name : undefined)\n if (inferredType !== 'matrix' && inferredType !== 'http') {\n throw new Error(\n `transports.${name}.type must be \"matrix\" or \"http\" (got ${JSON.stringify(r.type)})`,\n )\n }\n if (inferredType === 'matrix') {\n if (r.sender_localpart === undefined) r.sender_localpart = 'zooid'\n if (r.user_namespace === undefined && typeof r.homeserver === 'string') {\n try {\n const host = new URL(\n interpolateString(r.homeserver as string, processEnv),\n ).hostname\n if (host) r.user_namespace = `@.*:${host}`\n } catch {\n // Fall through: the required-fields loop will fire its \"must be a\n // non-empty string\" error, which is the same message today's parser\n // would emit for a bad homeserver URL.\n }\n }\n if (r.as_token === undefined) r.as_token = '__INFER__'\n if (r.hs_token === undefined) r.hs_token = '__INFER__'\n const fields = [\n 'homeserver',\n 'as_token',\n 'hs_token',\n 'sender_localpart',\n 'user_namespace',\n ] as const\n for (const f of fields) {\n if (typeof r[f] !== 'string' || (r[f] as string).length === 0) {\n throw new Error(`transports.${name}.${f} must be a non-empty string`)\n }\n }\n const out: MatrixTransportConfig = {\n type: 'matrix',\n homeserver: interpolateString(r.homeserver as string, processEnv),\n as_token: interpolateString(r.as_token as string, processEnv),\n hs_token: interpolateString(r.hs_token as string, processEnv),\n sender_localpart: r.sender_localpart as string,\n user_namespace: r.user_namespace as string,\n }\n if (r.port !== undefined) {\n if (!Number.isInteger(r.port)) {\n throw new Error(\n `transports.${name}.port must be an integer (got ${JSON.stringify(r.port)})`,\n )\n }\n out.port = r.port as number\n }\n if (r.space !== undefined) {\n if (typeof r.space !== 'string' || r.space.length === 0) {\n throw new Error(\n `transports.${name}.space must be a non-empty string (got ${JSON.stringify(r.space)})`,\n )\n }\n out.space = r.space\n }\n return out\n }\n // type: 'http'\n const port = (r.port ?? 8080) as number\n if (!Number.isInteger(port)) {\n throw new Error(`transports.${name}.port must be an integer (got ${JSON.stringify(port)})`)\n }\n return { type: 'http', port }\n}\n\nfunction parseTransportBinding(\n name: string,\n entry: Record<string, unknown>,\n transports: Record<string, TransportConfig>,\n): { matrix?: MatrixBinding; http?: HttpBinding } {\n const present = TRANSPORT_KINDS.filter(\n (k) => entry[k] !== undefined && entry[k] !== null,\n )\n if (present.length === 0) {\n throw new Error(\n `agents.${name}: must declare exactly one transport-kind block ` +\n `(e.g. 'matrix:' or 'http:'). Saw none.`,\n )\n }\n if (present.length > 1) {\n throw new Error(\n `agents.${name}: must declare exactly one transport-kind block. ` +\n `Saw: ${present.join(', ')}. To run \"the same agent\" on two transports, ` +\n `declare two agents (e.g. ${name}-matrix and ${name}-http).`,\n )\n }\n const kind = present[0] as TransportKind\n const blockRaw = entry[kind]\n if (typeof blockRaw !== 'object' || blockRaw === null || Array.isArray(blockRaw)) {\n throw new Error(`agents.${name}.${kind}: must be a mapping`)\n }\n const block = blockRaw as Record<string, unknown>\n let refName: string\n if (typeof block.transport === 'string' && block.transport.length > 0) {\n refName = block.transport\n } else {\n const matches = Object.entries(transports).filter(\n ([, t]) => t.type === kind,\n )\n if (matches.length === 0) {\n throw new Error(\n `agents.${name}.${kind}: no transport of type ${kind} declared (add one under transports:)`,\n )\n }\n if (matches.length > 1) {\n throw new Error(\n `agents.${name}.${kind}.transport is required when more than one ${kind} transport is declared ` +\n `(saw: ${matches.map(([n]) => n).join(', ')})`,\n )\n }\n refName = matches[0]![0]\n }\n const refTransport = transports[refName]\n if (!refTransport) {\n throw new Error(\n `agents.${name}.${kind}.transport \"${refName}\" is not declared in transports`,\n )\n }\n if (refTransport.type !== kind) {\n throw new Error(\n `agents.${name}.${kind} references transport \"${refName}\" of type: ${refTransport.type}. ` +\n `Block name and referenced transport's type must match.`,\n )\n }\n\n if (kind === 'matrix') {\n if (refTransport.type !== 'matrix') {\n throw new Error(`agents.${name}.matrix: transport must be matrix`)\n }\n const serverName = deriveServerName(refTransport.user_namespace)\n\n const rawUserId =\n typeof block.user_id === 'string' && block.user_id.length > 0\n ? block.user_id\n : `@${name}`\n let userId = rawUserId\n if (!userId.includes(':') && MATRIX_USER_LOCALPART_RE.test(userId)) {\n userId = `${userId}:${serverName}`\n }\n if (!MATRIX_USER_ID_RE.test(userId)) {\n throw new Error(\n `agents.${name}.matrix.user_id must look like @localpart:server (got ${JSON.stringify(block.user_id)})`,\n )\n }\n\n if (!Array.isArray(block.rooms) || block.rooms.length === 0) {\n throw new Error(`agents.${name}.matrix.rooms is required and must be a non-empty array`)\n }\n const rooms: string[] = []\n for (const r of block.rooms) {\n if (typeof r !== 'string' || r.length === 0) {\n throw new Error(`agents.${name}.matrix.rooms[] must be a non-empty string`)\n }\n if (!MATRIX_ROOM_IDENT_RE.test(r)) {\n throw new Error(\n `agents.${name}.matrix.rooms[] must start with '#' or '!' (got ${JSON.stringify(r)})`,\n )\n }\n rooms.push(r.includes(':') ? r : `${r}:${serverName}`)\n }\n\n let displayName: string | undefined\n if (block.display_name !== undefined) {\n if (typeof block.display_name !== 'string') {\n throw new Error(\n `agents.${name}.matrix.display_name must be a string (got ${JSON.stringify(block.display_name)})`,\n )\n }\n const trimmed = block.display_name.trim()\n if (trimmed.length === 0) {\n throw new Error(`agents.${name}.matrix.display_name must be non-empty after trim`)\n }\n if (trimmed.length > 256) {\n throw new Error(`agents.${name}.matrix.display_name must be 256 characters or fewer`)\n }\n displayName = trimmed\n }\n\n const tr = block.trigger ?? 'mention'\n if (tr !== 'mention' && tr !== 'any') {\n throw new Error(\n `agents.${name}.matrix.trigger must be \"mention\" or \"any\" (got ${JSON.stringify(tr)})`,\n )\n }\n const matrix: MatrixBinding = {\n transport: refName,\n user_id: userId,\n rooms,\n trigger: tr,\n }\n if (displayName !== undefined) matrix.display_name = displayName\n return { matrix }\n }\n // kind === 'http'\n return { http: { transport: refName } }\n}\n\nfunction parseAgents(\n raw: unknown,\n runtime: 'local' | 'docker' | 'podman',\n transports: Record<string, TransportConfig>,\n daemonHooks: { pre_turn?: string; post_turn?: string },\n processEnv: NodeJS.ProcessEnv,\n): Record<string, AgentConfig> {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error('agents: must be a mapping')\n }\n const entries = Object.entries(raw as Record<string, unknown>)\n if (entries.length === 0) {\n throw new Error('agents: must have at least one entry')\n }\n const result: Record<string, AgentConfig> = {}\n for (const [name, val] of entries) {\n if (!AGENT_NAME_RE.test(name)) {\n throw new Error(`agents.${name}: name must match /^[a-z][a-z0-9-]{0,31}$/`)\n }\n if (!val || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`agents.${name} must be a mapping`)\n }\n const entry = val as Record<string, unknown>\n let workdir: string\n if (entry.workdir === undefined) {\n workdir = `./agents/${name}`\n } else if (typeof entry.workdir !== 'string' || entry.workdir.length === 0) {\n throw new Error(`agents.${name}.workdir must be a non-empty string`)\n } else {\n workdir = entry.workdir\n }\n\n if (entry.adapter !== undefined) {\n throw new Error(\n `agents.${name}: \"adapter\" is no longer supported; use \"acp\" — see epics/003-ZOD025-acp-migration/SPEC.md`,\n )\n }\n\n if (entry.acp === undefined) {\n throw new Error(`agents.${name}: missing required \"acp\" block`)\n }\n const acp = parseAcpBlock(name, entry.acp)\n const approval_timeout_ms = parseApprovalTimeout(name, entry.approval_timeout)\n\n // Reject legacy fields up front with pointers to [ZOD043].\n if (entry.docker !== undefined) {\n throw new Error(\n `agents.${name}.docker is no longer supported. ` +\n `Move 'image' to agents.${name}.container.image, and 'forward_env' entries to ` +\n `agents.${name}.container.env with \\${VAR} interpolation. See [ZOD043].`,\n )\n }\n if (typeof entry.transport === 'string') {\n throw new Error(\n `agents.${name}.transport (string) is no longer supported at the agent level. ` +\n `Move it inside a transport-kind block, e.g.:\\n` +\n ` matrix:\\n transport: <name>\\n user_id: \"@...\"\\n rooms: [...]\\n` +\n `See [ZOD043].`,\n )\n }\n for (const k of ['matrix_user_id', 'rooms', 'trigger'] as const) {\n if (entry[k] !== undefined) {\n throw new Error(\n `agents.${name}.${k} is no longer supported as a flat field. ` +\n `Move it inside a 'matrix:' block on the agent. See [ZOD043].`,\n )\n }\n }\n\n const agentHooks: AgentConfig['hooks'] = {}\n if (daemonHooks.pre_turn !== undefined) agentHooks.pre_turn = daemonHooks.pre_turn\n if (daemonHooks.post_turn !== undefined) agentHooks.post_turn = daemonHooks.post_turn\n if (entry.hooks !== undefined && entry.hooks !== null) {\n if (typeof entry.hooks !== 'object' || Array.isArray(entry.hooks)) {\n throw new Error(`agents.${name}.hooks must be a mapping`)\n }\n const h = entry.hooks as Record<string, unknown>\n if (Object.prototype.hasOwnProperty.call(h, 'pre_turn')) {\n if (typeof h.pre_turn === 'string') agentHooks.pre_turn = h.pre_turn\n else delete agentHooks.pre_turn\n }\n if (Object.prototype.hasOwnProperty.call(h, 'post_turn')) {\n if (typeof h.post_turn === 'string') agentHooks.post_turn = h.post_turn\n else delete agentHooks.post_turn\n }\n }\n\n let containerBlock: ContainerConfig | undefined\n if (entry.container !== undefined && entry.container !== null) {\n if (runtime === 'local') {\n throw new Error(\n `agents.${name}.container is only valid when runtime is 'docker' or 'podman'. ` +\n `runtime: local spawns agents as host child processes — there is no container, ` +\n `so 'image' is inert and 'env' would silently lie (the agent inherits the daemon's ` +\n `full process.env regardless).`,\n )\n }\n containerBlock = parseAgentContainer(name, entry.container, processEnv)\n }\n\n const binding = parseTransportBinding(name, entry, transports)\n\n const agentCfg: AgentConfig = {\n name,\n workdir,\n hooks: agentHooks,\n acp,\n approval_timeout_ms,\n }\n if (containerBlock) agentCfg.container = containerBlock\n if (binding.matrix) agentCfg.matrix = binding.matrix\n if (binding.http) agentCfg.http = binding.http\n result[name] = agentCfg\n }\n return result\n}\n\nfunction parseRuntime(raw: unknown): 'local' | 'docker' | 'podman' {\n const runtime = raw ?? 'docker'\n if (runtime !== 'local' && runtime !== 'docker' && runtime !== 'podman') {\n throw new Error(`runtime must be \"local\", \"docker\", or \"podman\" (got \"${runtime}\")`)\n }\n return runtime\n}\n\nfunction zooidHooks(raw: Record<string, unknown>): { pre_turn?: string; post_turn?: string } {\n const out: { pre_turn?: string; post_turn?: string } = {}\n if (raw.hooks && typeof raw.hooks === 'object') {\n const h = raw.hooks as Record<string, unknown>\n if (typeof h.pre_turn === 'string') out.pre_turn = h.pre_turn\n if (typeof h.post_turn === 'string') out.post_turn = h.post_turn\n }\n return out\n}\n\nexport function loadZooidConfig(yamlText: string): ZooidConfig {\n const raw = parse(yamlText) ?? {}\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('zooid.yaml must be a YAML object')\n }\n const r = raw as Record<string, unknown>\n\n if (r.transport !== undefined) {\n throw new Error(\n 'zooid.yaml: top-level \"transport:\" is no longer supported; declare entries under \"transports:\" instead',\n )\n }\n if (r.matrix !== undefined) {\n throw new Error(\n 'zooid.yaml: top-level \"matrix:\" is no longer supported; move it under \"transports.<name>: { type: matrix, ... }\"',\n )\n }\n if (r.workdir !== undefined) {\n throw new Error(\n 'top-level workdir is not supported; define agents: { <name>: { workdir: ... } } instead',\n )\n }\n if (r.docker !== undefined) {\n throw new Error(\n \"Top-level 'docker' block is no longer supported. \" +\n \"Move 'image' to top-level 'container.image'. See [ZOD043].\",\n )\n }\n if (r.agents === undefined) {\n throw new Error('agents: is required — zooid.yaml must define at least one agent')\n }\n\n const runtime = parseRuntime(r.runtime)\n const processEnv = process.env\n const transports = parseTransports(r.transports, processEnv)\n const hooks = zooidHooks(r)\n const agents = parseAgents(r.agents, runtime, transports, hooks, processEnv)\n\n const cfg: ZooidConfig = {\n runtime,\n transports,\n agents,\n hooks,\n }\n if (r.container !== undefined && r.container !== null) {\n if (runtime === 'local') {\n throw new Error(\n \"container is only valid when runtime is 'docker' or 'podman'. \" +\n 'runtime: local does not run agents in containers; image is ignored. See [ZOD043].',\n )\n }\n cfg.container = parseZooidContainer(r.container)\n }\n return cfg\n}\n\nexport function findTransport(\n cfg: ZooidConfig,\n name: string,\n): TransportConfig | undefined {\n return cfg.transports[name]\n}\n\nexport function findMatrixTransport(\n cfg: ZooidConfig,\n): { name: string; transport: MatrixTransportConfig } | null {\n const matrices = Object.entries(cfg.transports).filter(\n (e): e is [string, MatrixTransportConfig] => e[1].type === 'matrix',\n )\n if (matrices.length === 0) return null\n if (matrices.length > 1) {\n throw new Error(\n `findMatrixTransport: multiple matrix transports declared (${matrices\n .map((m) => m[0])\n .join(', ')}). Per-agent matrix routing is not supported yet.`,\n )\n }\n const [name, transport] = matrices[0]!\n return { name, transport }\n}\n\nexport function findHttpTransport(\n cfg: ZooidConfig,\n): { name: string; transport: HttpTransportConfig } | null {\n const https = Object.entries(cfg.transports).filter(\n (e): e is [string, HttpTransportConfig] => e[1].type === 'http',\n )\n if (https.length === 0) return null\n if (https.length > 1) {\n throw new Error(\n `findHttpTransport: multiple http transports declared (${https\n .map((h) => h[0])\n .join(', ')}). Per-agent http routing is not supported yet.`,\n )\n }\n const [name, transport] = https[0]!\n return { name, transport }\n}\n\nexport interface FoundConfigFile {\n path: string\n}\n\nexport function findConfigFile(cwd: string): FoundConfigFile | null {\n const z = join(cwd, 'zooid.yaml')\n if (existsSync(z)) return { path: z }\n const legacy = join(cwd, 'workforce.yaml')\n if (existsSync(legacy)) {\n throw new Error(\n `workforce.yaml is no longer supported. Rename it to zooid.yaml. See [ZOD045].`,\n )\n }\n return null\n}\n\nexport function mergeCliFlags(base: ZooidConfig, flags: CliFlags): ZooidConfig {\n const runtimeFlag = flags.runtime as 'local' | 'docker' | 'podman' | undefined\n if (\n runtimeFlag !== undefined &&\n runtimeFlag !== 'local' &&\n runtimeFlag !== 'docker' &&\n runtimeFlag !== 'podman'\n ) {\n throw new Error(`runtime must be \"local\", \"docker\", or \"podman\" (got \"${flags.runtime}\")`)\n }\n const runtime = runtimeFlag ?? base.runtime\n const merged: ZooidConfig = {\n runtime,\n transports: base.transports,\n agents: base.agents,\n hooks: { ...base.hooks },\n }\n if (runtime === 'docker' || runtime === 'podman') {\n const image = flags.image ?? base.container?.image\n if (image !== undefined) {\n merged.container = { image }\n } else if (base.container !== undefined) {\n merged.container = { ...base.container }\n }\n }\n return merged\n}\n","import dotenvExpand from 'dotenv-expand'\n\n/**\n * Matches compose-style env references inside a value string:\n * `${NAME}`, `$NAME`, `${NAME:-default}`, `${NAME-default}`,\n * `${NAME:+alt}`, `${NAME+alt}`.\n *\n * The captured group is always the referenced variable name.\n */\nconst REF_RE =\n /\\$\\{([A-Za-z_][A-Za-z0-9_]*)(?::?[-+][^}]*)?\\}|\\$([A-Za-z_][A-Za-z0-9_]*)/g\n\nexport class EnvInterpolationError extends Error {}\n\nconst isDenied = (name: string): boolean =>\n name === 'ZOOID_TOKEN' || name.startsWith('ZOOID_')\n\n/**\n * Run compose-style interpolation over a `{ KEY: literal-or-${ref} }` map.\n *\n * - Rejects keys in the `ZOOID_*` namespace.\n * - Rejects any `${ZOOID_*}` reference, including inside composed values\n * (e.g. `\"prefix-${ZOOID_INTERNAL}\"`).\n * - Otherwise delegates to `dotenv-expand` for the actual substitution,\n * preserving compose semantics (missing → empty string,\n * `${VAR:-default}`, `${VAR-default}`, `$$` escape).\n */\nexport function interpolateEnv(\n parsed: Record<string, string>,\n processEnv: NodeJS.ProcessEnv,\n scope: string,\n): Record<string, string> {\n for (const [key, val] of Object.entries(parsed)) {\n if (isDenied(key)) {\n throw new EnvInterpolationError(\n `${scope}.${key}: keys in the ZOOID_* namespace are not allowed`,\n )\n }\n if (typeof val !== 'string') {\n throw new EnvInterpolationError(\n `${scope}.${key}: env values must be strings (got ${typeof val})`,\n )\n }\n REF_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = REF_RE.exec(val)) !== null) {\n const ref = (m[1] ?? m[2]) as string\n if (isDenied(ref)) {\n throw new EnvInterpolationError(\n `${scope}.${key}: references to ZOOID_* vars are not allowed (saw \\${${ref}})`,\n )\n }\n }\n }\n // Process each value through interpolateString. Per-key processing avoids\n // dotenv-expand's \"processEnv shadows parsed\" behaviour, which would let the\n // daemon's `LOG_LEVEL=debug` overwrite a literal `LOG_LEVEL: info` declared in\n // zooid.yaml. References still resolve against the full processEnv.\n const out: Record<string, string> = {}\n for (const [key, val] of Object.entries(parsed)) {\n out[key] = interpolateString(val, processEnv)\n }\n return out\n}\n\n/**\n * Run compose-style interpolation over a single string value (e.g. a\n * transport's `as_token`). No denylist — transports legitimately reference\n * `ZOOID_*` tokens for the daemon itself (see [ZOD043] §Denylist note).\n */\nexport function interpolateString(\n value: string,\n processEnv: NodeJS.ProcessEnv,\n): string {\n // Fast path: literals with no `$` need no expansion. Skipping the dotenv-expand\n // call also avoids the library's \"processEnv shadows parsed\" merge behaviour,\n // which can leak unrelated env vars through a sentinel key.\n if (!value.includes('$')) return value\n const sentinel = '__zooid_interp_v1__'\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(processEnv)) {\n if (typeof v === 'string') env[k] = v\n }\n delete env[sentinel]\n const result = dotenvExpand.expand({\n parsed: { [sentinel]: value },\n processEnv: env,\n })\n return result.parsed?.[sentinel] ?? ''\n}\n","import { join } from 'node:path'\nimport {\n AcpClient,\n resolvePreset,\n type AgentEvent,\n type ApprovalDecision,\n type ApprovalRequest,\n type PromptInput,\n type PromptResult,\n type TapEvent,\n} from '@zooid/acp-client'\nimport type { AcpAgentSpec, AcpRuntime } from './acp-types.js'\nimport type { AgentConfig } from './types.js'\nimport type {\n ApprovalCorrelator,\n RegisteredApproval,\n} from './approval-correlator.js'\n\nexport type AcpRegistryEventHandler = (\n agentName: string,\n event: AgentEvent,\n) => void\nexport type AcpRegistryApprovalHandler = (\n agentName: string,\n req: ApprovalRequest,\n) => Promise<ApprovalDecision>\n\n/**\n * Daemon-side surface of the ACP agent fleet. The transport (HTTP) consumes\n * this; the CLI builds it via `buildAcpRegistry`. Long-lived: one\n * `AcpClient` per agent, kept alive across prompts.\n */\nexport interface AcpRegistry {\n hasAgent(name: string): boolean\n /** Whether an agent has a transport-context provider attached. */\n hasContextSpawn(name: string): boolean\n /** Per-agent approval timeout from zooid.yaml. 0 means no timeout. */\n getApprovalTimeoutMs(name: string): number\n ensureSession(name: string, threadId: string, channelId?: string): Promise<string>\n /** Drop the in-memory session for (agent, threadId). Next prompt re-creates one. */\n endSession(name: string, threadId: string): void\n prompt(name: string, input: PromptInput): Promise<PromptResult>\n /**\n * Cancel an in-flight prompt for (agent, sessionId). Sends `session/cancel`\n * via the underlying AcpClient and resolves any pending approvals with\n * `decision: 'cancel'`. Idempotent.\n */\n cancelSession(name: string, sessionId: string): Promise<void>\n stopAll(): Promise<void>\n /** Set by the transport. Receives every ACP event from any agent. */\n onEvent: AcpRegistryEventHandler\n /** Set by the transport. Resolves permission requests. */\n onApprovalRequest: AcpRegistryApprovalHandler\n}\n\nexport interface AcpAgentRegistryOptions {\n runtime: AcpRuntime\n agents: Record<string, AgentConfig>\n /** Per-agent env passed to each `AcpClient`'s spawn spec. */\n env?: Record<string, Record<string, string>>\n /** Per-agent container image. Used by DockerAcpRuntime; ignored by LocalAcpRuntime. */\n image?: Record<string, string | undefined>\n /** Initial event handler (the transport may overwrite at app creation). */\n onEvent?: AcpRegistryEventHandler\n /** Initial approval handler (the transport may overwrite at app creation). */\n onApprovalRequest?: AcpRegistryApprovalHandler\n /**\n * Optional correlator: when set, the registry's default\n * `onApprovalRequest` registers each request on the correlator (with the\n * agent's `approval_timeout_ms`) and returns the registered handle's\n * `decisionPromise`. Transports listen on the correlator's `'registered'`\n * + `'timeout'` events to drive the SSE wire and accept HTTP decisions.\n */\n approvals?: ApprovalCorrelator\n /** Called whenever the correlator-backed handler registers an approval. */\n onApprovalRegistered?: (approval: RegisteredApproval) => void\n /**\n * Optional observability tap. Forwarded to each AcpClient so the\n * unfiltered ACP protocol stream + turn-boundary events are visible to\n * the host (e.g. the dev CLI capturing them to disk).\n */\n onTap?: (agentName: string, event: TapEvent) => void\n /**\n * Root directory under which each agent gets a per-agent state dir\n * (`<agentsDir>/<agentName>/`). Used by the AcpClient session store to\n * persist ACP `sessionId`s across daemon restarts. Optional: when unset,\n * session continuity across restarts is disabled.\n */\n agentsDir?: string\n /**\n * Per-agent factory that returns a `mcpServers[]` entry for the\n * `zooid-context` MCP server. Forwarded to each AcpClient. Agents bound to\n * transports without a context provider (e.g. HTTP) have no entry here.\n */\n contextSpawns?: Record<string, ContextSpawnFactory | undefined>\n}\n\nexport type ContextSpawnFactory = (\n threadId: string,\n channelId?: string,\n) => Promise<{\n name: 'zooid-context'\n command: string\n args: string[]\n env: Array<{ name: string; value: string }>\n}>\n\nexport class AcpAgentRegistry implements AcpRegistry {\n readonly opts: AcpAgentRegistryOptions\n private readonly clients = new Map<string, AcpClient>()\n\n onEvent: AcpRegistryEventHandler\n onApprovalRequest: AcpRegistryApprovalHandler\n\n constructor(opts: AcpAgentRegistryOptions) {\n this.opts = opts\n this.onEvent = opts.onEvent ?? (() => {})\n if (opts.onApprovalRequest) {\n this.onApprovalRequest = opts.onApprovalRequest\n } else if (opts.approvals) {\n const correlator = opts.approvals\n this.onApprovalRequest = async (name, req) => {\n const cfg = this.opts.agents[name]\n const handle = correlator.register(name, req.sessionId, req, {\n timeoutMs: cfg?.approval_timeout_ms ?? 0,\n })\n this.opts.onApprovalRegistered?.(handle)\n return handle.decisionPromise\n }\n } else {\n this.onApprovalRequest = async () => ({ decision: 'cancel' })\n }\n }\n\n hasAgent(name: string): boolean {\n return Object.prototype.hasOwnProperty.call(this.opts.agents, name)\n }\n\n hasContextSpawn(name: string): boolean {\n return Boolean(this.opts.contextSpawns?.[name])\n }\n\n resolveSpawnEnv(name: string): Record<string, string> {\n return this.opts.env?.[name] ?? {}\n }\n\n resolveSpawnImage(name: string): string | undefined {\n return this.opts.image?.[name]\n }\n\n getApprovalTimeoutMs(name: string): number {\n return this.opts.agents[name]?.approval_timeout_ms ?? 0\n }\n\n async ensureSession(name: string, threadId: string, channelId?: string): Promise<string> {\n if (!this.hasAgent(name)) throw new Error(`unknown agent: ${name}`)\n const client = await this.ensureClient(name)\n return client.ensureSession(threadId, channelId)\n }\n\n endSession(name: string, threadId: string): void {\n if (!this.hasAgent(name)) return\n const client = this.clients.get(name)\n client?.endSession(threadId)\n }\n\n async cancelSession(name: string, sessionId: string): Promise<void> {\n if (!this.hasAgent(name)) return\n const client = this.clients.get(name)\n // Always nudge the correlator first so any pending approvals resolve with\n // 'cancel' regardless of whether the client is alive or already stopped.\n this.opts.approvals?.cancelSession(sessionId)\n if (!client) return\n try {\n await client.cancel(sessionId)\n } catch (err) {\n // ACP cancel is a notification; failures here are typically transport\n // errors after the agent has already exited.\n console.warn(`[acp:${name}] cancel(${sessionId}) failed:`, err)\n }\n }\n\n async prompt(name: string, input: PromptInput): Promise<PromptResult> {\n if (!this.hasAgent(name)) throw new Error(`unknown agent: ${name}`)\n const client = await this.ensureClient(name)\n return client.prompt(input)\n }\n\n async stopAll(): Promise<void> {\n await Promise.allSettled(\n [...this.clients.values()].map((c) => c.stop()),\n )\n this.clients.clear()\n }\n\n private async ensureClient(name: string): Promise<AcpClient> {\n const existing = this.clients.get(name)\n if (existing) return existing\n const cfg = this.opts.agents[name]\n if (!cfg.acp) throw new Error(`agents.${name}: missing acp block`)\n const spawn = resolveAcpAgentSpec(cfg.acp)\n const client = new AcpClient({\n agent: {\n id: name,\n command: spawn.command,\n args: spawn.args,\n env: this.opts.env?.[name],\n cwd: cfg.workdir,\n image: this.opts.image?.[name],\n },\n agentDataDir: this.opts.agentsDir ? join(this.opts.agentsDir, name) : undefined,\n runtime: this.opts.runtime,\n onEvent: (e) => this.onEvent(name, e),\n onApprovalRequest: (req) => this.onApprovalRequest(name, req),\n onTap: this.opts.onTap ? (e) => this.opts.onTap!(name, e) : undefined,\n contextSpawn: this.opts.contextSpawns?.[name],\n })\n await client.start()\n this.clients.set(name, client)\n return client\n }\n}\n\nexport function resolveAcpAgentSpec(spec: AcpAgentSpec): {\n command: string\n args: string[]\n} {\n if ('preset' in spec && spec.preset) {\n return resolvePreset(spec.preset, { model: spec.model })\n }\n if ('command' in spec && spec.command) {\n return { command: spec.command, args: spec.args ?? [] }\n }\n throw new Error('AcpAgentSpec: must specify either preset or command')\n}\n","import { EventEmitter } from 'node:events'\nimport { randomUUID } from 'node:crypto'\nimport type {\n ApprovalDecision,\n ApprovalRequest,\n} from '@zooid/acp-client'\n\nexport interface RegisteredApproval {\n approvalId: string\n agentName: string\n sessionId: string\n toolCallId: string\n toolKind?: string\n toolTitle?: string\n toolInput?: unknown\n options: ApprovalRequest['options']\n decisionPromise: Promise<ApprovalDecision>\n}\n\nexport interface RegisterOptions {\n /** Wall-clock timeout in ms. 0 = no timeout. */\n timeoutMs?: number\n}\n\ninterface PendingEntry extends RegisteredApproval {\n resolve(decision: ApprovalDecision): void\n timer?: ReturnType<typeof setTimeout>\n}\n\n/**\n * Correlates ACP approval requests (mid-prompt, originating in `AcpClient`)\n * with HTTP/transport-side decisions. The transport listens to:\n *\n * - `'registered'` — fires after `register()` so the transport can emit\n * `approval.request` on the right SSE stream.\n * - `'timeout'` — fires when an entry is auto-cancelled by the timer\n * so the transport can emit `approval.timeout`.\n */\nexport class ApprovalCorrelator extends EventEmitter {\n private readonly pending = new Map<string, PendingEntry>()\n private readonly bySession = new Map<string, Set<string>>()\n\n register(\n agentName: string,\n sessionId: string,\n req: ApprovalRequest,\n opts: RegisterOptions = {},\n ): RegisteredApproval {\n const approvalId = randomUUID()\n let resolve!: (d: ApprovalDecision) => void\n const decisionPromise = new Promise<ApprovalDecision>((r) => {\n resolve = r\n })\n const entry: PendingEntry = {\n approvalId,\n agentName,\n sessionId,\n toolCallId: req.toolCallId,\n toolKind: req.toolKind,\n toolTitle: req.toolTitle,\n toolInput: req.toolInput,\n options: req.options,\n decisionPromise,\n resolve,\n }\n if (opts.timeoutMs && opts.timeoutMs > 0) {\n entry.timer = setTimeout(() => {\n if (this.pending.get(approvalId) !== entry) return\n entry.resolve({ decision: 'cancel' })\n this.pending.delete(approvalId)\n this.bySession.get(sessionId)?.delete(approvalId)\n this.emit('timeout', { approvalId, sessionId, agentName })\n }, opts.timeoutMs)\n entry.timer.unref?.()\n }\n this.pending.set(approvalId, entry)\n let set = this.bySession.get(sessionId)\n if (!set) {\n set = new Set()\n this.bySession.set(sessionId, set)\n }\n set.add(approvalId)\n this.emit('registered', this.toPublic(entry))\n return this.toPublic(entry)\n }\n\n resolve(\n sessionId: string,\n approvalId: string,\n decision: ApprovalDecision,\n ): boolean {\n const entry = this.pending.get(approvalId)\n if (!entry || entry.sessionId !== sessionId) return false\n if (entry.timer) clearTimeout(entry.timer)\n entry.resolve(decision)\n this.pending.delete(approvalId)\n this.bySession.get(sessionId)?.delete(approvalId)\n return true\n }\n\n cancelSession(sessionId: string): void {\n const ids = this.bySession.get(sessionId)\n if (!ids) return\n for (const id of [...ids]) {\n const entry = this.pending.get(id)\n if (entry) {\n if (entry.timer) clearTimeout(entry.timer)\n entry.resolve({ decision: 'cancel' })\n this.pending.delete(id)\n }\n }\n this.bySession.delete(sessionId)\n }\n\n listPending(sessionId: string): RegisteredApproval[] {\n const ids = this.bySession.get(sessionId)\n if (!ids) return []\n const out: RegisteredApproval[] = []\n for (const id of ids) {\n const entry = this.pending.get(id)\n if (entry) out.push(this.toPublic(entry))\n }\n return out\n }\n\n size(): number {\n return this.pending.size\n }\n\n private toPublic(entry: PendingEntry): RegisteredApproval {\n return {\n approvalId: entry.approvalId,\n agentName: entry.agentName,\n sessionId: entry.sessionId,\n toolCallId: entry.toolCallId,\n toolKind: entry.toolKind,\n toolTitle: entry.toolTitle,\n toolInput: entry.toolInput,\n options: entry.options,\n decisionPromise: entry.decisionPromise,\n }\n }\n}\n"],"mappings":"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","names":["join"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/env-interpolation.ts","../src/acp-registry.ts","../src/approval-correlator.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { isAbsolute, join, resolve as pathResolve } from 'node:path'\nimport { parse } from 'yaml'\nimport type { AcpAgentSpec } from './acp-types.js'\nimport { isPreset } from '@zooid/acp-client'\nimport { interpolateEnv, interpolateString } from './env-interpolation.js'\nimport type {\n AgentConfig,\n CliFlags,\n ContainerConfig,\n HttpBinding,\n HttpTransportConfig,\n MatrixBinding,\n MatrixTransportConfig,\n MountConfig,\n RoomBinding,\n TransportConfig,\n ZooidConfig,\n ZooidContainerConfig,\n} from './types.js'\n\nexport interface LoadZooidConfigOptions {\n /**\n * Directory containing zooid.yaml. Required when any agent uses a\n * relative `container.mounts[].host` path; resolution happens at parse\n * time so the resulting `MountConfig` always carries an absolute host\n * path.\n */\n configDir?: string\n}\n\nconst AGENT_NAME_RE = /^[a-z][a-z0-9-]{0,31}$/\nconst MATRIX_USER_ID_RE = /^@[A-Za-z0-9._\\-=/+]+:[A-Za-z0-9.\\-]+$/\nconst MATRIX_USER_LOCALPART_RE = /^@[a-z0-9._=/+\\-]+$/\nconst MATRIX_ROOM_IDENT_RE = /^[#!]/\n\nfunction deriveServerName(userNamespace: string): string {\n // user_namespace is a regex like `@.*:localhost`. The part after the first\n // `:` is the server_name (strip a trailing `)` left over from a wrapped\n // group like `@(.*):localhost)`).\n const tail = userNamespace.split(':').slice(1).join(':').replace(/\\\\?\\)?$/, '')\n if (!tail) throw new Error(`user_namespace missing server_name: ${userNamespace}`)\n return tail\n}\n\nconst TRANSPORT_KINDS = ['matrix', 'http'] as const\ntype TransportKind = (typeof TRANSPORT_KINDS)[number]\n\nfunction parseAcpBlock(name: string, raw: unknown): AcpAgentSpec {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error(`agents.${name}.acp: must be a mapping with either preset or command`)\n }\n const a = raw as Record<string, unknown>\n const hasPreset = a.preset !== undefined\n const hasCommand = a.command !== undefined\n if (hasPreset && hasCommand) {\n throw new Error(\n `agents.${name}.acp: specify either preset or command, not both`,\n )\n }\n if (!hasPreset && !hasCommand) {\n throw new Error(\n `agents.${name}.acp: must specify either preset or command`,\n )\n }\n if (hasPreset) {\n if (typeof a.preset !== 'string' || a.preset.length === 0) {\n throw new Error(`agents.${name}.acp.preset: must be a non-empty string`)\n }\n if (!isPreset(a.preset)) {\n throw new Error(\n `agents.${name}.acp.preset: unknown preset \"${a.preset}\"`,\n )\n }\n const out: { preset: string; model?: string } = { preset: a.preset }\n if (a.model !== undefined) {\n if (typeof a.model !== 'string' || a.model.trim().length === 0) {\n throw new Error(`agents.${name}.acp.model: must be a non-empty string`)\n }\n out.model = a.model.trim()\n }\n return out as AcpAgentSpec\n }\n if (typeof a.command !== 'string' || a.command.length === 0) {\n throw new Error(`agents.${name}.acp.command: must be a non-empty string`)\n }\n const args: string[] = []\n if (a.args !== undefined) {\n if (!Array.isArray(a.args)) {\n throw new Error(`agents.${name}.acp.args: must be an array of strings`)\n }\n for (const v of a.args) {\n if (typeof v !== 'string') {\n throw new Error(`agents.${name}.acp.args[]: must be a string`)\n }\n args.push(v)\n }\n }\n return { command: a.command, args } as AcpAgentSpec\n}\n\nfunction parseApprovalTimeout(name: string, raw: unknown): number {\n if (raw === undefined) return 0\n if (raw === 0 || raw === '0') return 0\n if (typeof raw !== 'string') {\n throw new Error(\n `agents.${name}.approval_timeout: must be a duration like \"1h\", \"15m\", \"30s\", or 0 to disable (got ${JSON.stringify(raw)})`,\n )\n }\n const m = /^(\\d+)(s|m|h)$/.exec(raw)\n if (!m) {\n throw new Error(\n `agents.${name}.approval_timeout: \"${raw}\" is not a valid duration (use \"<n>s\", \"<n>m\", or \"<n>h\")`,\n )\n }\n const n = Number(m[1])\n switch (m[2]) {\n case 's':\n return n * 1000\n case 'm':\n return n * 60_000\n case 'h':\n return n * 60 * 60_000\n }\n throw new Error('unreachable')\n}\n\nfunction parseAgentContainer(\n name: string,\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n configDir: string | undefined,\n): ContainerConfig {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error(`agents.${name}.container must be a mapping`)\n }\n const r = raw as Record<string, unknown>\n const out: ContainerConfig = {}\n if (r.image !== undefined) {\n if (typeof r.image !== 'string' || r.image.length === 0) {\n throw new Error(`agents.${name}.container.image must be a non-empty string`)\n }\n out.image = r.image\n }\n if (r.env !== undefined && r.env !== null) {\n if (typeof r.env !== 'object' || Array.isArray(r.env)) {\n throw new Error(`agents.${name}.container.env must be a mapping`)\n }\n const rawEnv = r.env as Record<string, unknown>\n const stringEnv: Record<string, string> = {}\n for (const [k, v] of Object.entries(rawEnv)) {\n if (typeof v !== 'string') {\n throw new Error(\n `agents.${name}.container.env.${k}: must be a string (got ${typeof v})`,\n )\n }\n stringEnv[k] = v\n }\n out.env = interpolateEnv(stringEnv, processEnv, `agents.${name}.container.env`)\n }\n if (r.mounts !== undefined) {\n out.mounts = parseMountList(name, r.mounts, processEnv, configDir)\n }\n if (r.disable_mounts !== undefined) {\n out.disable_mounts = parseDisableMounts(name, r.disable_mounts)\n }\n return out\n}\n\nfunction parseMountList(\n agentName: string,\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n configDir: string | undefined,\n): MountConfig[] {\n if (!Array.isArray(raw)) {\n throw new Error(`agents.${agentName}.container.mounts must be an array`)\n }\n const out: MountConfig[] = []\n const seenIds = new Set<string>()\n for (let i = 0; i < raw.length; i++) {\n const entry = raw[i]\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n throw new Error(`agents.${agentName}.container.mounts[${i}] must be a mapping`)\n }\n const e = entry as Record<string, unknown>\n if (e.host === undefined) {\n throw new Error(`agents.${agentName}.container.mounts[${i}].host is required`)\n }\n if (e.target === undefined) {\n throw new Error(`agents.${agentName}.container.mounts[${i}].target is required`)\n }\n if (typeof e.host !== 'string' || e.host.length === 0) {\n throw new Error(\n `agents.${agentName}.container.mounts[${i}].host must be a non-empty string`,\n )\n }\n if (typeof e.target !== 'string' || e.target.length === 0) {\n throw new Error(\n `agents.${agentName}.container.mounts[${i}].target must be a non-empty string`,\n )\n }\n const mode = e.mode ?? 'rw'\n if (mode !== 'ro' && mode !== 'rw') {\n throw new Error(\n `agents.${agentName}.container.mounts[${i}].mode must be \"ro\" or \"rw\" (got ${JSON.stringify(e.mode)})`,\n )\n }\n let id: string | undefined\n if (e.id !== undefined) {\n if (typeof e.id !== 'string' || e.id.length === 0) {\n throw new Error(\n `agents.${agentName}.container.mounts[${i}].id must be a non-empty string`,\n )\n }\n if (e.id === 'workspace') {\n throw new Error(\n `agents.${agentName}.container.mounts[${i}].id: \"workspace\" is a reserved id (set by the workspace auto-mount). Use a different id or rely on disable_mounts to subtract.`,\n )\n }\n if (seenIds.has(e.id)) {\n throw new Error(\n `agents.${agentName}.container.mounts: duplicate id \"${e.id}\"`,\n )\n }\n seenIds.add(e.id)\n id = e.id\n }\n let create: boolean | undefined\n if (e.create !== undefined) {\n if (typeof e.create !== 'boolean') {\n throw new Error(\n `agents.${agentName}.container.mounts[${i}].create must be a boolean`,\n )\n }\n create = e.create\n }\n const host = resolveHostPath(\n agentName,\n i,\n interpolateString(e.host, processEnv),\n configDir,\n )\n const target = interpolateString(e.target, processEnv)\n const m: MountConfig = { host, target, mode }\n if (id !== undefined) m.id = id\n if (create !== undefined) m.create = create\n out.push(m)\n }\n return out\n}\n\nfunction resolveHostPath(\n agentName: string,\n index: number,\n host: string,\n configDir: string | undefined,\n): string {\n if (host.startsWith('~/')) {\n const home = process.env.HOME\n if (!home) {\n throw new Error(\n `agents.${agentName}.container.mounts[${index}].host: cannot expand ~ — $HOME is not set`,\n )\n }\n return `${home}/${host.slice(2)}`\n }\n if (host === '~') {\n const home = process.env.HOME\n if (!home) {\n throw new Error(\n `agents.${agentName}.container.mounts[${index}].host: cannot expand ~ — $HOME is not set`,\n )\n }\n return home\n }\n if (isAbsolute(host)) return host\n if (!configDir) {\n throw new Error(\n `agents.${agentName}.container.mounts[${index}]: relative host path \"${host}\" requires configDir (zooid.yaml directory) — pass it via loadZooidConfig(yaml, { configDir })`,\n )\n }\n return pathResolve(configDir, host)\n}\n\nfunction parseDisableMounts(agentName: string, raw: unknown): string[] {\n if (!Array.isArray(raw)) {\n throw new Error(`agents.${agentName}.container.disable_mounts must be an array of strings`)\n }\n const out: string[] = []\n for (let i = 0; i < raw.length; i++) {\n const v = raw[i]\n if (typeof v !== 'string' || v.length === 0) {\n throw new Error(\n `agents.${agentName}.container.disable_mounts[${i}] must be a non-empty string`,\n )\n }\n out.push(v)\n }\n return out\n}\n\nfunction parseZooidContainer(raw: unknown): ZooidContainerConfig {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('container must be a mapping')\n }\n const r = raw as Record<string, unknown>\n const out: ZooidContainerConfig = {}\n if (r.env !== undefined) {\n throw new Error(\n \"Top-level 'container.env' is not supported (workforce-level env defaults are out of scope; see [ZOD043]). \" +\n 'Move env entries to per-agent container.env.',\n )\n }\n if (r.image !== undefined) {\n if (typeof r.image !== 'string' || r.image.length === 0) {\n throw new Error('container.image must be a non-empty string')\n }\n out.image = r.image\n }\n return out\n}\n\nfunction parseTransports(\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n): Record<string, TransportConfig> {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error('transports: must be a mapping with at least one entry')\n }\n const r = raw as Record<string, unknown>\n const names = Object.keys(r)\n if (names.length === 0) {\n throw new Error('transports: at least one transport must be declared')\n }\n const out: Record<string, TransportConfig> = {}\n for (const name of names) {\n out[name] = parseTransport(name, r[name], processEnv)\n }\n const matrixEntries = Object.entries(out).filter(\n (e): e is [string, MatrixTransportConfig] => e[1].type === 'matrix',\n )\n if (matrixEntries.length === 1) {\n const [, mt] = matrixEntries[0]!\n if (mt.as_token === '__INFER__') {\n const v = interpolateString('${MATRIX_AS_TOKEN}', processEnv)\n if (v.length === 0) {\n throw new Error(\n 'transports.matrix.as_token: env var MATRIX_AS_TOKEN is not set ' +\n '(set it in your shell or .env, or declare as_token explicitly in zooid.yaml)',\n )\n }\n mt.as_token = v\n }\n if (mt.hs_token === '__INFER__') {\n const v = interpolateString('${MATRIX_HS_TOKEN}', processEnv)\n if (v.length === 0) {\n throw new Error(\n 'transports.matrix.hs_token: env var MATRIX_HS_TOKEN is not set ' +\n '(set it in your shell or .env, or declare hs_token explicitly in zooid.yaml)',\n )\n }\n mt.hs_token = v\n }\n } else if (matrixEntries.length > 1) {\n for (const [tname, mt] of matrixEntries) {\n if (mt.as_token === '__INFER__' || mt.hs_token === '__INFER__') {\n throw new Error(\n `transports.${tname}: as_token / hs_token must be set explicitly when more than one matrix transport is declared ` +\n `(no sensible default env var across multiple transports)`,\n )\n }\n }\n }\n return out\n}\n\nfunction parseTransport(\n name: string,\n raw: unknown,\n processEnv: NodeJS.ProcessEnv,\n): TransportConfig {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error(`transports.${name}: must be a mapping`)\n }\n const r = raw as Record<string, unknown>\n const inferredType =\n r.type ?? (name === 'matrix' || name === 'http' ? name : undefined)\n if (inferredType !== 'matrix' && inferredType !== 'http') {\n throw new Error(\n `transports.${name}.type must be \"matrix\" or \"http\" (got ${JSON.stringify(r.type)})`,\n )\n }\n if (inferredType === 'matrix') {\n if (r.sender_localpart === undefined) r.sender_localpart = 'zooid'\n if (r.user_namespace === undefined && typeof r.homeserver === 'string') {\n try {\n const host = new URL(\n interpolateString(r.homeserver as string, processEnv),\n ).hostname\n if (host) r.user_namespace = `@.*:${host}`\n } catch {\n // Fall through: the required-fields loop will fire its \"must be a\n // non-empty string\" error, which is the same message today's parser\n // would emit for a bad homeserver URL.\n }\n }\n if (r.as_token === undefined) r.as_token = '__INFER__'\n if (r.hs_token === undefined) r.hs_token = '__INFER__'\n const fields = [\n 'homeserver',\n 'as_token',\n 'hs_token',\n 'sender_localpart',\n 'user_namespace',\n ] as const\n for (const f of fields) {\n if (typeof r[f] !== 'string' || (r[f] as string).length === 0) {\n throw new Error(`transports.${name}.${f} must be a non-empty string`)\n }\n }\n const out: MatrixTransportConfig = {\n type: 'matrix',\n homeserver: interpolateString(r.homeserver as string, processEnv),\n as_token: interpolateString(r.as_token as string, processEnv),\n hs_token: interpolateString(r.hs_token as string, processEnv),\n sender_localpart: r.sender_localpart as string,\n user_namespace: r.user_namespace as string,\n }\n if (r.port !== undefined) {\n if (!Number.isInteger(r.port)) {\n throw new Error(\n `transports.${name}.port must be an integer (got ${JSON.stringify(r.port)})`,\n )\n }\n out.port = r.port as number\n }\n if (r.space !== undefined) {\n if (typeof r.space !== 'string' || r.space.length === 0) {\n throw new Error(\n `transports.${name}.space must be a non-empty string (got ${JSON.stringify(r.space)})`,\n )\n }\n out.space = r.space\n }\n return out\n }\n // type: 'http'\n const port = (r.port ?? 8080) as number\n if (!Number.isInteger(port)) {\n throw new Error(`transports.${name}.port must be an integer (got ${JSON.stringify(port)})`)\n }\n return { type: 'http', port }\n}\n\nfunction parseRoomBinding(path: string, raw: unknown, serverName: string): RoomBinding {\n function normalizeAlias(alias: string): string {\n if (alias.length === 0) {\n throw new Error(`${path}: must be a non-empty alias`)\n }\n if (!MATRIX_ROOM_IDENT_RE.test(alias)) {\n throw new Error(\n `${path}: must start with '#' or '!' (got ${JSON.stringify(alias)})`,\n )\n }\n return alias.includes(':') ? alias : `${alias}:${serverName}`\n }\n if (typeof raw === 'string') {\n return { alias: normalizeAlias(raw) }\n }\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error(`${path}: must be a string or { alias, power_level } object`)\n }\n const r = raw as Record<string, unknown>\n if (typeof r.alias !== 'string' || r.alias.length === 0) {\n throw new Error(`${path}.alias: must be a non-empty string`)\n }\n const out: RoomBinding = { alias: normalizeAlias(r.alias) }\n if (r.power_level !== undefined) {\n if (typeof r.power_level !== 'number' || !Number.isInteger(r.power_level)) {\n throw new Error(\n `${path}.power_level: must be an integer (got ${JSON.stringify(r.power_level)})`,\n )\n }\n out.powerLevel = r.power_level\n }\n return out\n}\n\nfunction parseTransportBinding(\n name: string,\n entry: Record<string, unknown>,\n transports: Record<string, TransportConfig>,\n): { matrix?: MatrixBinding; http?: HttpBinding } {\n const present = TRANSPORT_KINDS.filter(\n (k) => entry[k] !== undefined && entry[k] !== null,\n )\n if (present.length === 0) {\n throw new Error(\n `agents.${name}: must declare exactly one transport-kind block ` +\n `(e.g. 'matrix:' or 'http:'). Saw none.`,\n )\n }\n if (present.length > 1) {\n throw new Error(\n `agents.${name}: must declare exactly one transport-kind block. ` +\n `Saw: ${present.join(', ')}. To run \"the same agent\" on two transports, ` +\n `declare two agents (e.g. ${name}-matrix and ${name}-http).`,\n )\n }\n const kind = present[0] as TransportKind\n const blockRaw = entry[kind]\n if (typeof blockRaw !== 'object' || blockRaw === null || Array.isArray(blockRaw)) {\n throw new Error(`agents.${name}.${kind}: must be a mapping`)\n }\n const block = blockRaw as Record<string, unknown>\n let refName: string\n if (typeof block.transport === 'string' && block.transport.length > 0) {\n refName = block.transport\n } else {\n const matches = Object.entries(transports).filter(\n ([, t]) => t.type === kind,\n )\n if (matches.length === 0) {\n throw new Error(\n `agents.${name}.${kind}: no transport of type ${kind} declared (add one under transports:)`,\n )\n }\n if (matches.length > 1) {\n throw new Error(\n `agents.${name}.${kind}.transport is required when more than one ${kind} transport is declared ` +\n `(saw: ${matches.map(([n]) => n).join(', ')})`,\n )\n }\n refName = matches[0]![0]\n }\n const refTransport = transports[refName]\n if (!refTransport) {\n throw new Error(\n `agents.${name}.${kind}.transport \"${refName}\" is not declared in transports`,\n )\n }\n if (refTransport.type !== kind) {\n throw new Error(\n `agents.${name}.${kind} references transport \"${refName}\" of type: ${refTransport.type}. ` +\n `Block name and referenced transport's type must match.`,\n )\n }\n\n if (kind === 'matrix') {\n if (refTransport.type !== 'matrix') {\n throw new Error(`agents.${name}.matrix: transport must be matrix`)\n }\n const serverName = deriveServerName(refTransport.user_namespace)\n\n const rawUserId =\n typeof block.user_id === 'string' && block.user_id.length > 0\n ? block.user_id\n : `@${name}`\n let userId = rawUserId\n if (!userId.includes(':') && MATRIX_USER_LOCALPART_RE.test(userId)) {\n userId = `${userId}:${serverName}`\n }\n if (!MATRIX_USER_ID_RE.test(userId)) {\n throw new Error(\n `agents.${name}.matrix.user_id must look like @localpart:server (got ${JSON.stringify(block.user_id)})`,\n )\n }\n\n if (!Array.isArray(block.rooms) || block.rooms.length === 0) {\n throw new Error(`agents.${name}.matrix.rooms is required and must be a non-empty array`)\n }\n const rooms: RoomBinding[] = []\n for (let i = 0; i < block.rooms.length; i++) {\n rooms.push(parseRoomBinding(`agents.${name}.matrix.rooms[${i}]`, block.rooms[i], serverName))\n }\n\n let displayName: string | undefined\n if (block.display_name !== undefined) {\n if (typeof block.display_name !== 'string') {\n throw new Error(\n `agents.${name}.matrix.display_name must be a string (got ${JSON.stringify(block.display_name)})`,\n )\n }\n const trimmed = block.display_name.trim()\n if (trimmed.length === 0) {\n throw new Error(`agents.${name}.matrix.display_name must be non-empty after trim`)\n }\n if (trimmed.length > 256) {\n throw new Error(`agents.${name}.matrix.display_name must be 256 characters or fewer`)\n }\n displayName = trimmed\n }\n\n const tr = block.trigger ?? 'mention'\n if (tr !== 'mention' && tr !== 'any') {\n throw new Error(\n `agents.${name}.matrix.trigger must be \"mention\" or \"any\" (got ${JSON.stringify(tr)})`,\n )\n }\n const matrix: MatrixBinding = {\n transport: refName,\n user_id: userId,\n rooms,\n trigger: tr,\n }\n if (displayName !== undefined) matrix.display_name = displayName\n return { matrix }\n }\n // kind === 'http'\n return { http: { transport: refName } }\n}\n\nfunction parseAgents(\n raw: unknown,\n runtime: 'local' | 'docker' | 'podman',\n transports: Record<string, TransportConfig>,\n daemonHooks: { pre_turn?: string; post_turn?: string },\n processEnv: NodeJS.ProcessEnv,\n configDir: string | undefined,\n): Record<string, AgentConfig> {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n throw new Error('agents: must be a mapping')\n }\n const entries = Object.entries(raw as Record<string, unknown>)\n if (entries.length === 0) {\n throw new Error('agents: must have at least one entry')\n }\n const result: Record<string, AgentConfig> = {}\n for (const [name, val] of entries) {\n if (!AGENT_NAME_RE.test(name)) {\n throw new Error(`agents.${name}: name must match /^[a-z][a-z0-9-]{0,31}$/`)\n }\n if (!val || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`agents.${name} must be a mapping`)\n }\n const entry = val as Record<string, unknown>\n let workdir: string\n if (entry.workdir === undefined) {\n workdir = `./agents/${name}`\n } else if (typeof entry.workdir !== 'string' || entry.workdir.length === 0) {\n throw new Error(`agents.${name}.workdir must be a non-empty string`)\n } else {\n workdir = entry.workdir\n }\n\n if (entry.adapter !== undefined) {\n throw new Error(\n `agents.${name}: \"adapter\" is no longer supported; use \"acp\" — see epics/003-ZOD025-acp-migration/SPEC.md`,\n )\n }\n\n if (entry.acp === undefined) {\n throw new Error(`agents.${name}: missing required \"acp\" block`)\n }\n const acp = parseAcpBlock(name, entry.acp)\n const approval_timeout_ms = parseApprovalTimeout(name, entry.approval_timeout)\n\n // Reject legacy fields up front with pointers to [ZOD043].\n if (entry.docker !== undefined) {\n throw new Error(\n `agents.${name}.docker is no longer supported. ` +\n `Move 'image' to agents.${name}.container.image, and 'forward_env' entries to ` +\n `agents.${name}.container.env with \\${VAR} interpolation. See [ZOD043].`,\n )\n }\n if (typeof entry.transport === 'string') {\n throw new Error(\n `agents.${name}.transport (string) is no longer supported at the agent level. ` +\n `Move it inside a transport-kind block, e.g.:\\n` +\n ` matrix:\\n transport: <name>\\n user_id: \"@...\"\\n rooms: [...]\\n` +\n `See [ZOD043].`,\n )\n }\n for (const k of ['matrix_user_id', 'rooms', 'trigger'] as const) {\n if (entry[k] !== undefined) {\n throw new Error(\n `agents.${name}.${k} is no longer supported as a flat field. ` +\n `Move it inside a 'matrix:' block on the agent. See [ZOD043].`,\n )\n }\n }\n\n const agentHooks: AgentConfig['hooks'] = {}\n if (daemonHooks.pre_turn !== undefined) agentHooks.pre_turn = daemonHooks.pre_turn\n if (daemonHooks.post_turn !== undefined) agentHooks.post_turn = daemonHooks.post_turn\n if (entry.hooks !== undefined && entry.hooks !== null) {\n if (typeof entry.hooks !== 'object' || Array.isArray(entry.hooks)) {\n throw new Error(`agents.${name}.hooks must be a mapping`)\n }\n const h = entry.hooks as Record<string, unknown>\n if (Object.prototype.hasOwnProperty.call(h, 'pre_turn')) {\n if (typeof h.pre_turn === 'string') agentHooks.pre_turn = h.pre_turn\n else delete agentHooks.pre_turn\n }\n if (Object.prototype.hasOwnProperty.call(h, 'post_turn')) {\n if (typeof h.post_turn === 'string') agentHooks.post_turn = h.post_turn\n else delete agentHooks.post_turn\n }\n }\n\n let containerBlock: ContainerConfig | undefined\n if (entry.container !== undefined && entry.container !== null) {\n if (runtime === 'local') {\n // Under runtime: local, the parser only accepts mounts/disable_mounts\n // (which the compose layer ignores). image/env stay rejected because\n // they would silently lie: there's no container and the host inherits\n // the daemon's full process.env regardless.\n if (typeof entry.container !== 'object' || entry.container === null || Array.isArray(entry.container)) {\n throw new Error(`agents.${name}.container must be a mapping`)\n }\n const c = entry.container as Record<string, unknown>\n const disallowed = Object.keys(c).filter((k) => k !== 'mounts' && k !== 'disable_mounts')\n if (disallowed.length > 0) {\n throw new Error(\n `agents.${name}.container.${disallowed[0]} is only valid when runtime is 'docker' or 'podman'. ` +\n `runtime: local spawns agents as host child processes — there is no container, ` +\n `so 'image' is inert and 'env' would silently lie (the agent inherits the daemon's ` +\n `full process.env regardless). 'mounts' and 'disable_mounts' are accepted under ` +\n `runtime: local but ignored at compose time.`,\n )\n }\n }\n containerBlock = parseAgentContainer(name, entry.container, processEnv, configDir)\n }\n\n const binding = parseTransportBinding(name, entry, transports)\n\n const agentCfg: AgentConfig = {\n name,\n workdir,\n hooks: agentHooks,\n acp,\n approval_timeout_ms,\n }\n if (containerBlock) agentCfg.container = containerBlock\n if (binding.matrix) agentCfg.matrix = binding.matrix\n if (binding.http) agentCfg.http = binding.http\n result[name] = agentCfg\n }\n return result\n}\n\nfunction parseRuntime(raw: unknown): 'local' | 'docker' | 'podman' {\n const runtime = raw ?? 'docker'\n if (runtime !== 'local' && runtime !== 'docker' && runtime !== 'podman') {\n throw new Error(`runtime must be \"local\", \"docker\", or \"podman\" (got \"${runtime}\")`)\n }\n return runtime\n}\n\nfunction zooidHooks(raw: Record<string, unknown>): { pre_turn?: string; post_turn?: string } {\n const out: { pre_turn?: string; post_turn?: string } = {}\n if (raw.hooks && typeof raw.hooks === 'object') {\n const h = raw.hooks as Record<string, unknown>\n if (typeof h.pre_turn === 'string') out.pre_turn = h.pre_turn\n if (typeof h.post_turn === 'string') out.post_turn = h.post_turn\n }\n return out\n}\n\nexport function loadZooidConfig(\n yamlText: string,\n opts: LoadZooidConfigOptions = {},\n): ZooidConfig {\n const raw = parse(yamlText) ?? {}\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('zooid.yaml must be a YAML object')\n }\n const r = raw as Record<string, unknown>\n\n if (r.transport !== undefined) {\n throw new Error(\n 'zooid.yaml: top-level \"transport:\" is no longer supported; declare entries under \"transports:\" instead',\n )\n }\n if (r.matrix !== undefined) {\n throw new Error(\n 'zooid.yaml: top-level \"matrix:\" is no longer supported; move it under \"transports.<name>: { type: matrix, ... }\"',\n )\n }\n if (r.workdir !== undefined) {\n throw new Error(\n 'top-level workdir is not supported; define agents: { <name>: { workdir: ... } } instead',\n )\n }\n if (r.docker !== undefined) {\n throw new Error(\n \"Top-level 'docker' block is no longer supported. \" +\n \"Move 'image' to top-level 'container.image'. See [ZOD043].\",\n )\n }\n if (r.agents === undefined) {\n throw new Error('agents: is required — zooid.yaml must define at least one agent')\n }\n\n const runtime = parseRuntime(r.runtime)\n const processEnv = process.env\n const transports = parseTransports(r.transports, processEnv)\n const hooks = zooidHooks(r)\n const agents = parseAgents(r.agents, runtime, transports, hooks, processEnv, opts.configDir)\n\n const cfg: ZooidConfig = {\n runtime,\n transports,\n agents,\n hooks,\n }\n if (r.container !== undefined && r.container !== null) {\n if (runtime === 'local') {\n throw new Error(\n \"container is only valid when runtime is 'docker' or 'podman'. \" +\n 'runtime: local does not run agents in containers; image is ignored. See [ZOD043].',\n )\n }\n cfg.container = parseZooidContainer(r.container)\n }\n return cfg\n}\n\nexport function findTransport(\n cfg: ZooidConfig,\n name: string,\n): TransportConfig | undefined {\n return cfg.transports[name]\n}\n\nexport function findMatrixTransport(\n cfg: ZooidConfig,\n): { name: string; transport: MatrixTransportConfig } | null {\n const matrices = Object.entries(cfg.transports).filter(\n (e): e is [string, MatrixTransportConfig] => e[1].type === 'matrix',\n )\n if (matrices.length === 0) return null\n if (matrices.length > 1) {\n throw new Error(\n `findMatrixTransport: multiple matrix transports declared (${matrices\n .map((m) => m[0])\n .join(', ')}). Per-agent matrix routing is not supported yet.`,\n )\n }\n const [name, transport] = matrices[0]!\n return { name, transport }\n}\n\nexport function findHttpTransport(\n cfg: ZooidConfig,\n): { name: string; transport: HttpTransportConfig } | null {\n const https = Object.entries(cfg.transports).filter(\n (e): e is [string, HttpTransportConfig] => e[1].type === 'http',\n )\n if (https.length === 0) return null\n if (https.length > 1) {\n throw new Error(\n `findHttpTransport: multiple http transports declared (${https\n .map((h) => h[0])\n .join(', ')}). Per-agent http routing is not supported yet.`,\n )\n }\n const [name, transport] = https[0]!\n return { name, transport }\n}\n\nexport interface FoundConfigFile {\n path: string\n}\n\nexport function findConfigFile(cwd: string): FoundConfigFile | null {\n const z = join(cwd, 'zooid.yaml')\n if (existsSync(z)) return { path: z }\n const legacy = join(cwd, 'workforce.yaml')\n if (existsSync(legacy)) {\n throw new Error(\n `workforce.yaml is no longer supported. Rename it to zooid.yaml. See [ZOD045].`,\n )\n }\n return null\n}\n\nexport function mergeCliFlags(base: ZooidConfig, flags: CliFlags): ZooidConfig {\n const runtimeFlag = flags.runtime as 'local' | 'docker' | 'podman' | undefined\n if (\n runtimeFlag !== undefined &&\n runtimeFlag !== 'local' &&\n runtimeFlag !== 'docker' &&\n runtimeFlag !== 'podman'\n ) {\n throw new Error(`runtime must be \"local\", \"docker\", or \"podman\" (got \"${flags.runtime}\")`)\n }\n const runtime = runtimeFlag ?? base.runtime\n const merged: ZooidConfig = {\n runtime,\n transports: base.transports,\n agents: base.agents,\n hooks: { ...base.hooks },\n }\n if (runtime === 'docker' || runtime === 'podman') {\n const image = flags.image ?? base.container?.image\n if (image !== undefined) {\n merged.container = { image }\n } else if (base.container !== undefined) {\n merged.container = { ...base.container }\n }\n }\n return merged\n}\n","import dotenvExpand from 'dotenv-expand'\n\n/**\n * Matches compose-style env references inside a value string:\n * `${NAME}`, `$NAME`, `${NAME:-default}`, `${NAME-default}`,\n * `${NAME:+alt}`, `${NAME+alt}`.\n *\n * The captured group is always the referenced variable name.\n */\nconst REF_RE =\n /\\$\\{([A-Za-z_][A-Za-z0-9_]*)(?::?[-+][^}]*)?\\}|\\$([A-Za-z_][A-Za-z0-9_]*)/g\n\nexport class EnvInterpolationError extends Error {}\n\nconst isDenied = (name: string): boolean =>\n name === 'ZOOID_TOKEN' || name.startsWith('ZOOID_')\n\n/**\n * Run compose-style interpolation over a `{ KEY: literal-or-${ref} }` map.\n *\n * - Rejects keys in the `ZOOID_*` namespace.\n * - Rejects any `${ZOOID_*}` reference, including inside composed values\n * (e.g. `\"prefix-${ZOOID_INTERNAL}\"`).\n * - Otherwise delegates to `dotenv-expand` for the actual substitution,\n * preserving compose semantics (missing → empty string,\n * `${VAR:-default}`, `${VAR-default}`, `$$` escape).\n */\nexport function interpolateEnv(\n parsed: Record<string, string>,\n processEnv: NodeJS.ProcessEnv,\n scope: string,\n): Record<string, string> {\n for (const [key, val] of Object.entries(parsed)) {\n if (isDenied(key)) {\n throw new EnvInterpolationError(\n `${scope}.${key}: keys in the ZOOID_* namespace are not allowed`,\n )\n }\n if (typeof val !== 'string') {\n throw new EnvInterpolationError(\n `${scope}.${key}: env values must be strings (got ${typeof val})`,\n )\n }\n REF_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = REF_RE.exec(val)) !== null) {\n const ref = (m[1] ?? m[2]) as string\n if (isDenied(ref)) {\n throw new EnvInterpolationError(\n `${scope}.${key}: references to ZOOID_* vars are not allowed (saw \\${${ref}})`,\n )\n }\n }\n }\n // Process each value through interpolateString. Per-key processing avoids\n // dotenv-expand's \"processEnv shadows parsed\" behaviour, which would let the\n // daemon's `LOG_LEVEL=debug` overwrite a literal `LOG_LEVEL: info` declared in\n // zooid.yaml. References still resolve against the full processEnv.\n const out: Record<string, string> = {}\n for (const [key, val] of Object.entries(parsed)) {\n out[key] = interpolateString(val, processEnv)\n }\n return out\n}\n\n/**\n * Run compose-style interpolation over a single string value (e.g. a\n * transport's `as_token`). No denylist — transports legitimately reference\n * `ZOOID_*` tokens for the daemon itself (see [ZOD043] §Denylist note).\n */\nexport function interpolateString(\n value: string,\n processEnv: NodeJS.ProcessEnv,\n): string {\n // Fast path: literals with no `$` need no expansion. Skipping the dotenv-expand\n // call also avoids the library's \"processEnv shadows parsed\" merge behaviour,\n // which can leak unrelated env vars through a sentinel key.\n if (!value.includes('$')) return value\n const sentinel = '__zooid_interp_v1__'\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(processEnv)) {\n if (typeof v === 'string') env[k] = v\n }\n delete env[sentinel]\n const result = dotenvExpand.expand({\n parsed: { [sentinel]: value },\n processEnv: env,\n })\n return result.parsed?.[sentinel] ?? ''\n}\n","import { mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n AcpClient,\n resolvePreset,\n type AgentEvent,\n type ApprovalDecision,\n type ApprovalRequest,\n type PromptInput,\n type PromptResult,\n type TapEvent,\n} from '@zooid/acp-client'\nimport type { AcpAgentSpec, AcpMount, AcpRuntime } from './acp-types.js'\nimport type { AgentConfig } from './types.js'\nimport type {\n ApprovalCorrelator,\n RegisteredApproval,\n} from './approval-correlator.js'\n\nexport type AcpRegistryEventHandler = (\n agentName: string,\n event: AgentEvent,\n) => void\nexport type AcpRegistryApprovalHandler = (\n agentName: string,\n req: ApprovalRequest,\n) => Promise<ApprovalDecision>\n\n/**\n * Daemon-side surface of the ACP agent fleet. The transport (HTTP) consumes\n * this; the CLI builds it via `buildAcpRegistry`. Long-lived: one\n * `AcpClient` per agent, kept alive across prompts.\n */\nexport interface AcpRegistry {\n hasAgent(name: string): boolean\n /** Whether an agent has a transport-context provider attached. */\n hasContextSpawn(name: string): boolean\n /** Per-agent approval timeout from zooid.yaml. 0 means no timeout. */\n getApprovalTimeoutMs(name: string): number\n ensureSession(name: string, threadId: string, channelId?: string): Promise<string>\n /** Drop the in-memory session for (agent, threadId). Next prompt re-creates one. */\n endSession(name: string, threadId: string): void\n prompt(name: string, input: PromptInput): Promise<PromptResult>\n /**\n * Cancel an in-flight prompt for (agent, sessionId). Sends `session/cancel`\n * via the underlying AcpClient and resolves any pending approvals with\n * `decision: 'cancel'`. Idempotent.\n */\n cancelSession(name: string, sessionId: string): Promise<void>\n stopAll(): Promise<void>\n /** Set by the transport. Receives every ACP event from any agent. */\n onEvent: AcpRegistryEventHandler\n /** Set by the transport. Resolves permission requests. */\n onApprovalRequest: AcpRegistryApprovalHandler\n}\n\nexport interface AcpAgentRegistryOptions {\n runtime: AcpRuntime\n agents: Record<string, AgentConfig>\n /** Per-agent env passed to each `AcpClient`'s spawn spec. */\n env?: Record<string, Record<string, string>>\n /** Per-agent container image. Used by DockerAcpRuntime; ignored by LocalAcpRuntime. */\n image?: Record<string, string | undefined>\n /** Initial event handler (the transport may overwrite at app creation). */\n onEvent?: AcpRegistryEventHandler\n /** Initial approval handler (the transport may overwrite at app creation). */\n onApprovalRequest?: AcpRegistryApprovalHandler\n /**\n * Optional correlator: when set, the registry's default\n * `onApprovalRequest` registers each request on the correlator (with the\n * agent's `approval_timeout_ms`) and returns the registered handle's\n * `decisionPromise`. Transports listen on the correlator's `'registered'`\n * + `'timeout'` events to drive the SSE wire and accept HTTP decisions.\n */\n approvals?: ApprovalCorrelator\n /** Called whenever the correlator-backed handler registers an approval. */\n onApprovalRegistered?: (approval: RegisteredApproval) => void\n /**\n * Optional observability tap. Forwarded to each AcpClient so the\n * unfiltered ACP protocol stream + turn-boundary events are visible to\n * the host (e.g. the dev CLI capturing them to disk).\n */\n onTap?: (agentName: string, event: TapEvent) => void\n /**\n * Root directory under which each agent gets a per-agent state dir\n * (`<agentsDir>/<agentName>/`). Used by the AcpClient session store to\n * persist ACP `sessionId`s across daemon restarts. Optional: when unset,\n * session continuity across restarts is disabled.\n */\n agentsDir?: string\n /**\n * Per-agent factory that returns a `mcpServers[]` entry for the\n * `zooid-context` MCP server. Forwarded to each AcpClient. Agents bound to\n * transports without a context provider (e.g. HTTP) have no entry here.\n */\n contextSpawns?: Record<string, ContextSpawnFactory | undefined>\n /**\n * Per-agent resolved bind-mount list. Threaded into the AcpClient's spawn\n * spec; honoured by the docker runtime, ignored by the local runtime.\n */\n mounts?: Record<string, AcpMount[]>\n /**\n * Per-agent list of host directories to `mkdir -p` before the first\n * `runtime.spawn` for that agent. Subset of mount entries with `create: true`.\n */\n mkdirOnSpawn?: Record<string, string[]>\n /**\n * Per-agent override for the spawn-spec `cwd`. Set to e.g. `/workspace`\n * when the workspace mount is active; falls back to `agent.workdir`.\n */\n cwd?: Record<string, string>\n}\n\nexport type ContextSpawnFactory = (\n threadId: string,\n channelId?: string,\n) => Promise<{\n name: 'zooid-context'\n command: string\n args: string[]\n env: Array<{ name: string; value: string }>\n}>\n\nexport class AcpAgentRegistry implements AcpRegistry {\n readonly opts: AcpAgentRegistryOptions\n private readonly clients = new Map<string, AcpClient>()\n\n onEvent: AcpRegistryEventHandler\n onApprovalRequest: AcpRegistryApprovalHandler\n\n constructor(opts: AcpAgentRegistryOptions) {\n this.opts = opts\n this.onEvent = opts.onEvent ?? (() => {})\n if (opts.onApprovalRequest) {\n this.onApprovalRequest = opts.onApprovalRequest\n } else if (opts.approvals) {\n const correlator = opts.approvals\n this.onApprovalRequest = async (name, req) => {\n const cfg = this.opts.agents[name]\n const handle = correlator.register(name, req.sessionId, req, {\n timeoutMs: cfg?.approval_timeout_ms ?? 0,\n })\n this.opts.onApprovalRegistered?.(handle)\n return handle.decisionPromise\n }\n } else {\n this.onApprovalRequest = async () => ({ decision: 'cancel' })\n }\n }\n\n hasAgent(name: string): boolean {\n return Object.prototype.hasOwnProperty.call(this.opts.agents, name)\n }\n\n hasContextSpawn(name: string): boolean {\n return Boolean(this.opts.contextSpawns?.[name])\n }\n\n resolveSpawnEnv(name: string): Record<string, string> {\n return this.opts.env?.[name] ?? {}\n }\n\n resolveSpawnImage(name: string): string | undefined {\n return this.opts.image?.[name]\n }\n\n resolveSpawnMounts(name: string): AcpMount[] {\n return this.opts.mounts?.[name] ?? []\n }\n\n resolveSpawnCwd(name: string): string {\n return (\n this.opts.cwd?.[name] ??\n this.opts.agents[name]?.workdir ??\n process.cwd()\n )\n }\n\n agentNames(): string[] {\n return Object.keys(this.opts.agents)\n }\n\n getApprovalTimeoutMs(name: string): number {\n return this.opts.agents[name]?.approval_timeout_ms ?? 0\n }\n\n async ensureSession(name: string, threadId: string, channelId?: string): Promise<string> {\n if (!this.hasAgent(name)) throw new Error(`unknown agent: ${name}`)\n const client = await this.ensureClient(name)\n return client.ensureSession(threadId, channelId)\n }\n\n endSession(name: string, threadId: string): void {\n if (!this.hasAgent(name)) return\n const client = this.clients.get(name)\n client?.endSession(threadId)\n }\n\n async cancelSession(name: string, sessionId: string): Promise<void> {\n if (!this.hasAgent(name)) return\n const client = this.clients.get(name)\n // Always nudge the correlator first so any pending approvals resolve with\n // 'cancel' regardless of whether the client is alive or already stopped.\n this.opts.approvals?.cancelSession(sessionId)\n if (!client) return\n try {\n await client.cancel(sessionId)\n } catch (err) {\n // ACP cancel is a notification; failures here are typically transport\n // errors after the agent has already exited.\n console.warn(`[acp:${name}] cancel(${sessionId}) failed:`, err)\n }\n }\n\n async prompt(name: string, input: PromptInput): Promise<PromptResult> {\n if (!this.hasAgent(name)) throw new Error(`unknown agent: ${name}`)\n const client = await this.ensureClient(name)\n return client.prompt(input)\n }\n\n async stopAll(): Promise<void> {\n await Promise.allSettled(\n [...this.clients.values()].map((c) => c.stop()),\n )\n this.clients.clear()\n }\n\n private async ensureClient(name: string): Promise<AcpClient> {\n const existing = this.clients.get(name)\n if (existing) return existing\n const cfg = this.opts.agents[name]\n if (!cfg.acp) throw new Error(`agents.${name}: missing acp block`)\n const spawn = resolveAcpAgentSpec(cfg.acp)\n for (const dir of this.opts.mkdirOnSpawn?.[name] ?? []) {\n mkdirSync(dir, { recursive: true })\n }\n const client = new AcpClient({\n agent: {\n id: name,\n command: spawn.command,\n args: spawn.args,\n env: this.opts.env?.[name],\n cwd: this.resolveSpawnCwd(name),\n image: this.opts.image?.[name],\n mounts: this.resolveSpawnMounts(name),\n },\n agentDataDir: this.opts.agentsDir ? join(this.opts.agentsDir, name) : undefined,\n runtime: this.opts.runtime,\n onEvent: (e) => this.onEvent(name, e),\n onApprovalRequest: (req) => this.onApprovalRequest(name, req),\n onTap: this.opts.onTap ? (e) => this.opts.onTap!(name, e) : undefined,\n contextSpawn: this.opts.contextSpawns?.[name],\n })\n await client.start()\n this.clients.set(name, client)\n return client\n }\n}\n\nexport function resolveAcpAgentSpec(spec: AcpAgentSpec): {\n command: string\n args: string[]\n} {\n if ('preset' in spec && spec.preset) {\n return resolvePreset(spec.preset, { model: spec.model })\n }\n if ('command' in spec && spec.command) {\n return { command: spec.command, args: spec.args ?? [] }\n }\n throw new Error('AcpAgentSpec: must specify either preset or command')\n}\n","import { EventEmitter } from 'node:events'\nimport { randomUUID } from 'node:crypto'\nimport type {\n ApprovalDecision,\n ApprovalRequest,\n} from '@zooid/acp-client'\n\nexport interface RegisteredApproval {\n approvalId: string\n agentName: string\n sessionId: string\n toolCallId: string\n toolKind?: string\n toolTitle?: string\n toolInput?: unknown\n options: ApprovalRequest['options']\n decisionPromise: Promise<ApprovalDecision>\n}\n\nexport interface RegisterOptions {\n /** Wall-clock timeout in ms. 0 = no timeout. */\n timeoutMs?: number\n}\n\ninterface PendingEntry extends RegisteredApproval {\n resolve(decision: ApprovalDecision): void\n timer?: ReturnType<typeof setTimeout>\n}\n\n/**\n * Correlates ACP approval requests (mid-prompt, originating in `AcpClient`)\n * with HTTP/transport-side decisions. The transport listens to:\n *\n * - `'registered'` — fires after `register()` so the transport can emit\n * `approval.request` on the right SSE stream.\n * - `'timeout'` — fires when an entry is auto-cancelled by the timer\n * so the transport can emit `approval.timeout`.\n */\nexport class ApprovalCorrelator extends EventEmitter {\n private readonly pending = new Map<string, PendingEntry>()\n private readonly bySession = new Map<string, Set<string>>()\n\n register(\n agentName: string,\n sessionId: string,\n req: ApprovalRequest,\n opts: RegisterOptions = {},\n ): RegisteredApproval {\n const approvalId = randomUUID()\n let resolve!: (d: ApprovalDecision) => void\n const decisionPromise = new Promise<ApprovalDecision>((r) => {\n resolve = r\n })\n const entry: PendingEntry = {\n approvalId,\n agentName,\n sessionId,\n toolCallId: req.toolCallId,\n toolKind: req.toolKind,\n toolTitle: req.toolTitle,\n toolInput: req.toolInput,\n options: req.options,\n decisionPromise,\n resolve,\n }\n if (opts.timeoutMs && opts.timeoutMs > 0) {\n entry.timer = setTimeout(() => {\n if (this.pending.get(approvalId) !== entry) return\n entry.resolve({ decision: 'cancel' })\n this.pending.delete(approvalId)\n this.bySession.get(sessionId)?.delete(approvalId)\n this.emit('timeout', { approvalId, sessionId, agentName })\n }, opts.timeoutMs)\n entry.timer.unref?.()\n }\n this.pending.set(approvalId, entry)\n let set = this.bySession.get(sessionId)\n if (!set) {\n set = new Set()\n this.bySession.set(sessionId, set)\n }\n set.add(approvalId)\n this.emit('registered', this.toPublic(entry))\n return this.toPublic(entry)\n }\n\n resolve(\n sessionId: string,\n approvalId: string,\n decision: ApprovalDecision,\n ): boolean {\n const entry = this.pending.get(approvalId)\n if (!entry || entry.sessionId !== sessionId) return false\n if (entry.timer) clearTimeout(entry.timer)\n entry.resolve(decision)\n this.pending.delete(approvalId)\n this.bySession.get(sessionId)?.delete(approvalId)\n return true\n }\n\n cancelSession(sessionId: string): void {\n const ids = this.bySession.get(sessionId)\n if (!ids) return\n for (const id of [...ids]) {\n const entry = this.pending.get(id)\n if (entry) {\n if (entry.timer) clearTimeout(entry.timer)\n entry.resolve({ decision: 'cancel' })\n this.pending.delete(id)\n }\n }\n this.bySession.delete(sessionId)\n }\n\n listPending(sessionId: string): RegisteredApproval[] {\n const ids = this.bySession.get(sessionId)\n if (!ids) return []\n const out: RegisteredApproval[] = []\n for (const id of ids) {\n const entry = this.pending.get(id)\n if (entry) out.push(this.toPublic(entry))\n }\n return out\n }\n\n size(): number {\n return this.pending.size\n }\n\n private toPublic(entry: PendingEntry): RegisteredApproval {\n return {\n approvalId: entry.approvalId,\n agentName: entry.agentName,\n sessionId: entry.sessionId,\n toolCallId: entry.toolCallId,\n toolKind: entry.toolKind,\n toolTitle: entry.toolTitle,\n toolInput: entry.toolInput,\n options: entry.options,\n decisionPromise: entry.decisionPromise,\n }\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY,MAAM,WAAW,mBAAmB;AACzD,SAAS,aAAa;AAEtB,SAAS,gBAAgB;;;ACJzB,OAAO,kBAAkB;AASzB,IAAM,SACJ;AAEK,IAAM,wBAAN,cAAoC,MAAM;AAAC;AAElD,IAAM,WAAW,CAAC,SAChB,SAAS,iBAAiB,KAAK,WAAW,QAAQ;AAY7C,SAAS,eACd,QACA,YACA,OACwB;AACxB,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,QAAI,SAAS,GAAG,GAAG;AACjB,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,IAAI,GAAG;AAAA,MACjB;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,UAAU;AAC3B,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,IAAI,GAAG,qCAAqC,OAAO,GAAG;AAAA,MAChE;AAAA,IACF;AACA,WAAO,YAAY;AACnB,QAAI;AACJ,YAAQ,IAAI,OAAO,KAAK,GAAG,OAAO,MAAM;AACtC,YAAM,MAAO,EAAE,CAAC,KAAK,EAAE,CAAC;AACxB,UAAI,SAAS,GAAG,GAAG;AACjB,cAAM,IAAI;AAAA,UACR,GAAG,KAAK,IAAI,GAAG,wDAAwD,GAAG;AAAA,QAC5E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,QAAI,GAAG,IAAI,kBAAkB,KAAK,UAAU;AAAA,EAC9C;AACA,SAAO;AACT;AAOO,SAAS,kBACd,OACA,YACQ;AAIR,MAAI,CAAC,MAAM,SAAS,GAAG,EAAG,QAAO;AACjC,QAAM,WAAW;AACjB,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC/C,QAAI,OAAO,MAAM,SAAU,KAAI,CAAC,IAAI;AAAA,EACtC;AACA,SAAO,IAAI,QAAQ;AACnB,QAAM,SAAS,aAAa,OAAO;AAAA,IACjC,QAAQ,EAAE,CAAC,QAAQ,GAAG,MAAM;AAAA,IAC5B,YAAY;AAAA,EACd,CAAC;AACD,SAAO,OAAO,SAAS,QAAQ,KAAK;AACtC;;;AD1DA,IAAM,gBAAgB;AACtB,IAAM,oBAAoB;AAC1B,IAAM,2BAA2B;AACjC,IAAM,uBAAuB;AAE7B,SAAS,iBAAiB,eAA+B;AAIvD,QAAM,OAAO,cAAc,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,EAAE,QAAQ,WAAW,EAAE;AAC9E,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,uCAAuC,aAAa,EAAE;AACjF,SAAO;AACT;AAEA,IAAM,kBAAkB,CAAC,UAAU,MAAM;AAGzC,SAAS,cAAc,MAAc,KAA4B;AAC/D,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,MAAM,UAAU,IAAI,uDAAuD;AAAA,EACvF;AACA,QAAM,IAAI;AACV,QAAM,YAAY,EAAE,WAAW;AAC/B,QAAM,aAAa,EAAE,YAAY;AACjC,MAAI,aAAa,YAAY;AAC3B,UAAM,IAAI;AAAA,MACR,UAAU,IAAI;AAAA,IAChB;AAAA,EACF;AACA,MAAI,CAAC,aAAa,CAAC,YAAY;AAC7B,UAAM,IAAI;AAAA,MACR,UAAU,IAAI;AAAA,IAChB;AAAA,EACF;AACA,MAAI,WAAW;AACb,QAAI,OAAO,EAAE,WAAW,YAAY,EAAE,OAAO,WAAW,GAAG;AACzD,YAAM,IAAI,MAAM,UAAU,IAAI,yCAAyC;AAAA,IACzE;AACA,QAAI,CAAC,SAAS,EAAE,MAAM,GAAG;AACvB,YAAM,IAAI;AAAA,QACR,UAAU,IAAI,gCAAgC,EAAE,MAAM;AAAA,MACxD;AAAA,IACF;AACA,UAAM,MAA0C,EAAE,QAAQ,EAAE,OAAO;AACnE,QAAI,EAAE,UAAU,QAAW;AACzB,UAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,KAAK,EAAE,WAAW,GAAG;AAC9D,cAAM,IAAI,MAAM,UAAU,IAAI,wCAAwC;AAAA,MACxE;AACA,UAAI,QAAQ,EAAE,MAAM,KAAK;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AACA,MAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW,GAAG;AAC3D,UAAM,IAAI,MAAM,UAAU,IAAI,0CAA0C;AAAA,EAC1E;AACA,QAAM,OAAiB,CAAC;AACxB,MAAI,EAAE,SAAS,QAAW;AACxB,QAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,GAAG;AAC1B,YAAM,IAAI,MAAM,UAAU,IAAI,wCAAwC;AAAA,IACxE;AACA,eAAW,KAAK,EAAE,MAAM;AACtB,UAAI,OAAO,MAAM,UAAU;AACzB,cAAM,IAAI,MAAM,UAAU,IAAI,+BAA+B;AAAA,MAC/D;AACA,WAAK,KAAK,CAAC;AAAA,IACb;AAAA,EACF;AACA,SAAO,EAAE,SAAS,EAAE,SAAS,KAAK;AACpC;AAEA,SAAS,qBAAqB,MAAc,KAAsB;AAChE,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI,QAAQ,KAAK,QAAQ,IAAK,QAAO;AACrC,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI;AAAA,MACR,UAAU,IAAI,uFAAuF,KAAK,UAAU,GAAG,CAAC;AAAA,IAC1H;AAAA,EACF;AACA,QAAM,IAAI,iBAAiB,KAAK,GAAG;AACnC,MAAI,CAAC,GAAG;AACN,UAAM,IAAI;AAAA,MACR,UAAU,IAAI,uBAAuB,GAAG;AAAA,IAC1C;AAAA,EACF;AACA,QAAM,IAAI,OAAO,EAAE,CAAC,CAAC;AACrB,UAAQ,EAAE,CAAC,GAAG;AAAA,IACZ,KAAK;AACH,aAAO,IAAI;AAAA,IACb,KAAK;AACH,aAAO,IAAI;AAAA,IACb,KAAK;AACH,aAAO,IAAI,KAAK;AAAA,EACpB;AACA,QAAM,IAAI,MAAM,aAAa;AAC/B;AAEA,SAAS,oBACP,MACA,KACA,YACA,WACiB;AACjB,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,GAAG;AACjE,UAAM,IAAI,MAAM,UAAU,IAAI,8BAA8B;AAAA,EAC9D;AACA,QAAM,IAAI;AACV,QAAM,MAAuB,CAAC;AAC9B,MAAI,EAAE,UAAU,QAAW;AACzB,QAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,WAAW,GAAG;AACvD,YAAM,IAAI,MAAM,UAAU,IAAI,6CAA6C;AAAA,IAC7E;AACA,QAAI,QAAQ,EAAE;AAAA,EAChB;AACA,MAAI,EAAE,QAAQ,UAAa,EAAE,QAAQ,MAAM;AACzC,QAAI,OAAO,EAAE,QAAQ,YAAY,MAAM,QAAQ,EAAE,GAAG,GAAG;AACrD,YAAM,IAAI,MAAM,UAAU,IAAI,kCAAkC;AAAA,IAClE;AACA,UAAM,SAAS,EAAE;AACjB,UAAM,YAAoC,CAAC;AAC3C,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,UAAI,OAAO,MAAM,UAAU;AACzB,cAAM,IAAI;AAAA,UACR,UAAU,IAAI,kBAAkB,CAAC,2BAA2B,OAAO,CAAC;AAAA,QACtE;AAAA,MACF;AACA,gBAAU,CAAC,IAAI;AAAA,IACjB;AACA,QAAI,MAAM,eAAe,WAAW,YAAY,UAAU,IAAI,gBAAgB;AAAA,EAChF;AACA,MAAI,EAAE,WAAW,QAAW;AAC1B,QAAI,SAAS,eAAe,MAAM,EAAE,QAAQ,YAAY,SAAS;AAAA,EACnE;AACA,MAAI,EAAE,mBAAmB,QAAW;AAClC,QAAI,iBAAiB,mBAAmB,MAAM,EAAE,cAAc;AAAA,EAChE;AACA,SAAO;AACT;AAEA,SAAS,eACP,WACA,KACA,YACA,WACe;AACf,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,UAAM,IAAI,MAAM,UAAU,SAAS,oCAAoC;AAAA,EACzE;AACA,QAAM,MAAqB,CAAC;AAC5B,QAAM,UAAU,oBAAI,IAAY;AAChC,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,QAAQ,IAAI,CAAC;AACnB,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,YAAM,IAAI,MAAM,UAAU,SAAS,qBAAqB,CAAC,qBAAqB;AAAA,IAChF;AACA,UAAM,IAAI;AACV,QAAI,EAAE,SAAS,QAAW;AACxB,YAAM,IAAI,MAAM,UAAU,SAAS,qBAAqB,CAAC,oBAAoB;AAAA,IAC/E;AACA,QAAI,EAAE,WAAW,QAAW;AAC1B,YAAM,IAAI,MAAM,UAAU,SAAS,qBAAqB,CAAC,sBAAsB;AAAA,IACjF;AACA,QAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,WAAW,GAAG;AACrD,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,qBAAqB,CAAC;AAAA,MAC3C;AAAA,IACF;AACA,QAAI,OAAO,EAAE,WAAW,YAAY,EAAE,OAAO,WAAW,GAAG;AACzD,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,qBAAqB,CAAC;AAAA,MAC3C;AAAA,IACF;AACA,UAAM,OAAO,EAAE,QAAQ;AACvB,QAAI,SAAS,QAAQ,SAAS,MAAM;AAClC,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,qBAAqB,CAAC,oCAAoC,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,MACrG;AAAA,IACF;AACA,QAAI;AACJ,QAAI,EAAE,OAAO,QAAW;AACtB,UAAI,OAAO,EAAE,OAAO,YAAY,EAAE,GAAG,WAAW,GAAG;AACjD,cAAM,IAAI;AAAA,UACR,UAAU,SAAS,qBAAqB,CAAC;AAAA,QAC3C;AAAA,MACF;AACA,UAAI,EAAE,OAAO,aAAa;AACxB,cAAM,IAAI;AAAA,UACR,UAAU,SAAS,qBAAqB,CAAC;AAAA,QAC3C;AAAA,MACF;AACA,UAAI,QAAQ,IAAI,EAAE,EAAE,GAAG;AACrB,cAAM,IAAI;AAAA,UACR,UAAU,SAAS,oCAAoC,EAAE,EAAE;AAAA,QAC7D;AAAA,MACF;AACA,cAAQ,IAAI,EAAE,EAAE;AAChB,WAAK,EAAE;AAAA,IACT;AACA,QAAI;AACJ,QAAI,EAAE,WAAW,QAAW;AAC1B,UAAI,OAAO,EAAE,WAAW,WAAW;AACjC,cAAM,IAAI;AAAA,UACR,UAAU,SAAS,qBAAqB,CAAC;AAAA,QAC3C;AAAA,MACF;AACA,eAAS,EAAE;AAAA,IACb;AACA,UAAM,OAAO;AAAA,MACX;AAAA,MACA;AAAA,MACA,kBAAkB,EAAE,MAAM,UAAU;AAAA,MACpC;AAAA,IACF;AACA,UAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU;AACrD,UAAM,IAAiB,EAAE,MAAM,QAAQ,KAAK;AAC5C,QAAI,OAAO,OAAW,GAAE,KAAK;AAC7B,QAAI,WAAW,OAAW,GAAE,SAAS;AACrC,QAAI,KAAK,CAAC;AAAA,EACZ;AACA,SAAO;AACT;AAEA,SAAS,gBACP,WACA,OACA,MACA,WACQ;AACR,MAAI,KAAK,WAAW,IAAI,GAAG;AACzB,UAAM,OAAO,QAAQ,IAAI;AACzB,QAAI,CAAC,MAAM;AACT,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,qBAAqB,KAAK;AAAA,MAC/C;AAAA,IACF;AACA,WAAO,GAAG,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC;AAAA,EACjC;AACA,MAAI,SAAS,KAAK;AAChB,UAAM,OAAO,QAAQ,IAAI;AACzB,QAAI,CAAC,MAAM;AACT,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,qBAAqB,KAAK;AAAA,MAC/C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,WAAW,IAAI,EAAG,QAAO;AAC7B,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR,UAAU,SAAS,qBAAqB,KAAK,0BAA0B,IAAI;AAAA,IAC7E;AAAA,EACF;AACA,SAAO,YAAY,WAAW,IAAI;AACpC;AAEA,SAAS,mBAAmB,WAAmB,KAAwB;AACrE,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACvB,UAAM,IAAI,MAAM,UAAU,SAAS,uDAAuD;AAAA,EAC5F;AACA,QAAM,MAAgB,CAAC;AACvB,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,OAAO,MAAM,YAAY,EAAE,WAAW,GAAG;AAC3C,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,6BAA6B,CAAC;AAAA,MACnD;AAAA,IACF;AACA,QAAI,KAAK,CAAC;AAAA,EACZ;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAoC;AAC/D,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,GAAG;AACjE,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,IAAI;AACV,QAAM,MAA4B,CAAC;AACnC,MAAI,EAAE,QAAQ,QAAW;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,MAAI,EAAE,UAAU,QAAW;AACzB,QAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,WAAW,GAAG;AACvD,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,QAAI,QAAQ,EAAE;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,gBACP,KACA,YACiC;AACjC,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AACA,QAAM,IAAI;AACV,QAAM,QAAQ,OAAO,KAAK,CAAC;AAC3B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,QAAM,MAAuC,CAAC;AAC9C,aAAW,QAAQ,OAAO;AACxB,QAAI,IAAI,IAAI,eAAe,MAAM,EAAE,IAAI,GAAG,UAAU;AAAA,EACtD;AACA,QAAM,gBAAgB,OAAO,QAAQ,GAAG,EAAE;AAAA,IACxC,CAAC,MAA4C,EAAE,CAAC,EAAE,SAAS;AAAA,EAC7D;AACA,MAAI,cAAc,WAAW,GAAG;AAC9B,UAAM,CAAC,EAAE,EAAE,IAAI,cAAc,CAAC;AAC9B,QAAI,GAAG,aAAa,aAAa;AAC/B,YAAM,IAAI,kBAAkB,sBAAsB,UAAU;AAC5D,UAAI,EAAE,WAAW,GAAG;AAClB,cAAM,IAAI;AAAA,UACR;AAAA,QAEF;AAAA,MACF;AACA,SAAG,WAAW;AAAA,IAChB;AACA,QAAI,GAAG,aAAa,aAAa;AAC/B,YAAM,IAAI,kBAAkB,sBAAsB,UAAU;AAC5D,UAAI,EAAE,WAAW,GAAG;AAClB,cAAM,IAAI;AAAA,UACR;AAAA,QAEF;AAAA,MACF;AACA,SAAG,WAAW;AAAA,IAChB;AAAA,EACF,WAAW,cAAc,SAAS,GAAG;AACnC,eAAW,CAAC,OAAO,EAAE,KAAK,eAAe;AACvC,UAAI,GAAG,aAAa,eAAe,GAAG,aAAa,aAAa;AAC9D,cAAM,IAAI;AAAA,UACR,cAAc,KAAK;AAAA,QAErB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,eACP,MACA,KACA,YACiB;AACjB,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,MAAM,cAAc,IAAI,qBAAqB;AAAA,EACzD;AACA,QAAM,IAAI;AACV,QAAM,eACJ,EAAE,SAAS,SAAS,YAAY,SAAS,SAAS,OAAO;AAC3D,MAAI,iBAAiB,YAAY,iBAAiB,QAAQ;AACxD,UAAM,IAAI;AAAA,MACR,cAAc,IAAI,yCAAyC,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,IACnF;AAAA,EACF;AACA,MAAI,iBAAiB,UAAU;AAC7B,QAAI,EAAE,qBAAqB,OAAW,GAAE,mBAAmB;AAC3D,QAAI,EAAE,mBAAmB,UAAa,OAAO,EAAE,eAAe,UAAU;AACtE,UAAI;AACF,cAAM,OAAO,IAAI;AAAA,UACf,kBAAkB,EAAE,YAAsB,UAAU;AAAA,QACtD,EAAE;AACF,YAAI,KAAM,GAAE,iBAAiB,OAAO,IAAI;AAAA,MAC1C,QAAQ;AAAA,MAIR;AAAA,IACF;AACA,QAAI,EAAE,aAAa,OAAW,GAAE,WAAW;AAC3C,QAAI,EAAE,aAAa,OAAW,GAAE,WAAW;AAC3C,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,QAAQ;AACtB,UAAI,OAAO,EAAE,CAAC,MAAM,YAAa,EAAE,CAAC,EAAa,WAAW,GAAG;AAC7D,cAAM,IAAI,MAAM,cAAc,IAAI,IAAI,CAAC,6BAA6B;AAAA,MACtE;AAAA,IACF;AACA,UAAM,MAA6B;AAAA,MACjC,MAAM;AAAA,MACN,YAAY,kBAAkB,EAAE,YAAsB,UAAU;AAAA,MAChE,UAAU,kBAAkB,EAAE,UAAoB,UAAU;AAAA,MAC5D,UAAU,kBAAkB,EAAE,UAAoB,UAAU;AAAA,MAC5D,kBAAkB,EAAE;AAAA,MACpB,gBAAgB,EAAE;AAAA,IACpB;AACA,QAAI,EAAE,SAAS,QAAW;AACxB,UAAI,CAAC,OAAO,UAAU,EAAE,IAAI,GAAG;AAC7B,cAAM,IAAI;AAAA,UACR,cAAc,IAAI,iCAAiC,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,QAC3E;AAAA,MACF;AACA,UAAI,OAAO,EAAE;AAAA,IACf;AACA,QAAI,EAAE,UAAU,QAAW;AACzB,UAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,WAAW,GAAG;AACvD,cAAM,IAAI;AAAA,UACR,cAAc,IAAI,0CAA0C,KAAK,UAAU,EAAE,KAAK,CAAC;AAAA,QACrF;AAAA,MACF;AACA,UAAI,QAAQ,EAAE;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAQ,EAAE,QAAQ;AACxB,MAAI,CAAC,OAAO,UAAU,IAAI,GAAG;AAC3B,UAAM,IAAI,MAAM,cAAc,IAAI,iCAAiC,KAAK,UAAU,IAAI,CAAC,GAAG;AAAA,EAC5F;AACA,SAAO,EAAE,MAAM,QAAQ,KAAK;AAC9B;AAEA,SAAS,iBAAiB,MAAc,KAAc,YAAiC;AACrF,WAAS,eAAe,OAAuB;AAC7C,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,MAAM,GAAG,IAAI,6BAA6B;AAAA,IACtD;AACA,QAAI,CAAC,qBAAqB,KAAK,KAAK,GAAG;AACrC,YAAM,IAAI;AAAA,QACR,GAAG,IAAI,qCAAqC,KAAK,UAAU,KAAK,CAAC;AAAA,MACnE;AAAA,IACF;AACA,WAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,GAAG,KAAK,IAAI,UAAU;AAAA,EAC7D;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,EAAE,OAAO,eAAe,GAAG,EAAE;AAAA,EACtC;AACA,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,MAAM,GAAG,IAAI,qDAAqD;AAAA,EAC9E;AACA,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,GAAG,IAAI,oCAAoC;AAAA,EAC7D;AACA,QAAM,MAAmB,EAAE,OAAO,eAAe,EAAE,KAAK,EAAE;AAC1D,MAAI,EAAE,gBAAgB,QAAW;AAC/B,QAAI,OAAO,EAAE,gBAAgB,YAAY,CAAC,OAAO,UAAU,EAAE,WAAW,GAAG;AACzE,YAAM,IAAI;AAAA,QACR,GAAG,IAAI,yCAAyC,KAAK,UAAU,EAAE,WAAW,CAAC;AAAA,MAC/E;AAAA,IACF;AACA,QAAI,aAAa,EAAE;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,sBACP,MACA,OACA,YACgD;AAChD,QAAM,UAAU,gBAAgB;AAAA,IAC9B,CAAC,MAAM,MAAM,CAAC,MAAM,UAAa,MAAM,CAAC,MAAM;AAAA,EAChD;AACA,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI;AAAA,MACR,UAAU,IAAI;AAAA,IAEhB;AAAA,EACF;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,IAAI;AAAA,MACR,UAAU,IAAI,yDACJ,QAAQ,KAAK,IAAI,CAAC,yEACE,IAAI,eAAe,IAAI;AAAA,IACvD;AAAA,EACF;AACA,QAAM,OAAO,QAAQ,CAAC;AACtB,QAAM,WAAW,MAAM,IAAI;AAC3B,MAAI,OAAO,aAAa,YAAY,aAAa,QAAQ,MAAM,QAAQ,QAAQ,GAAG;AAChF,UAAM,IAAI,MAAM,UAAU,IAAI,IAAI,IAAI,qBAAqB;AAAA,EAC7D;AACA,QAAM,QAAQ;AACd,MAAI;AACJ,MAAI,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,SAAS,GAAG;AACrE,cAAU,MAAM;AAAA,EAClB,OAAO;AACL,UAAM,UAAU,OAAO,QAAQ,UAAU,EAAE;AAAA,MACzC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS;AAAA,IACxB;AACA,QAAI,QAAQ,WAAW,GAAG;AACxB,YAAM,IAAI;AAAA,QACR,UAAU,IAAI,IAAI,IAAI,0BAA0B,IAAI;AAAA,MACtD;AAAA,IACF;AACA,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,IAAI;AAAA,QACR,UAAU,IAAI,IAAI,IAAI,6CAA6C,IAAI,gCAC5D,QAAQ,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,MAC/C;AAAA,IACF;AACA,cAAU,QAAQ,CAAC,EAAG,CAAC;AAAA,EACzB;AACA,QAAM,eAAe,WAAW,OAAO;AACvC,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR,UAAU,IAAI,IAAI,IAAI,eAAe,OAAO;AAAA,IAC9C;AAAA,EACF;AACA,MAAI,aAAa,SAAS,MAAM;AAC9B,UAAM,IAAI;AAAA,MACR,UAAU,IAAI,IAAI,IAAI,0BAA0B,OAAO,cAAc,aAAa,IAAI;AAAA,IAExF;AAAA,EACF;AAEA,MAAI,SAAS,UAAU;AACrB,QAAI,aAAa,SAAS,UAAU;AAClC,YAAM,IAAI,MAAM,UAAU,IAAI,mCAAmC;AAAA,IACnE;AACA,UAAM,aAAa,iBAAiB,aAAa,cAAc;AAE/D,UAAM,YACJ,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,SAAS,IACxD,MAAM,UACN,IAAI,IAAI;AACd,QAAI,SAAS;AACb,QAAI,CAAC,OAAO,SAAS,GAAG,KAAK,yBAAyB,KAAK,MAAM,GAAG;AAClE,eAAS,GAAG,MAAM,IAAI,UAAU;AAAA,IAClC;AACA,QAAI,CAAC,kBAAkB,KAAK,MAAM,GAAG;AACnC,YAAM,IAAI;AAAA,QACR,UAAU,IAAI,yDAAyD,KAAK,UAAU,MAAM,OAAO,CAAC;AAAA,MACtG;AAAA,IACF;AAEA,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,WAAW,GAAG;AAC3D,YAAM,IAAI,MAAM,UAAU,IAAI,yDAAyD;AAAA,IACzF;AACA,UAAM,QAAuB,CAAC;AAC9B,aAAS,IAAI,GAAG,IAAI,MAAM,MAAM,QAAQ,KAAK;AAC3C,YAAM,KAAK,iBAAiB,UAAU,IAAI,iBAAiB,CAAC,KAAK,MAAM,MAAM,CAAC,GAAG,UAAU,CAAC;AAAA,IAC9F;AAEA,QAAI;AACJ,QAAI,MAAM,iBAAiB,QAAW;AACpC,UAAI,OAAO,MAAM,iBAAiB,UAAU;AAC1C,cAAM,IAAI;AAAA,UACR,UAAU,IAAI,8CAA8C,KAAK,UAAU,MAAM,YAAY,CAAC;AAAA,QAChG;AAAA,MACF;AACA,YAAM,UAAU,MAAM,aAAa,KAAK;AACxC,UAAI,QAAQ,WAAW,GAAG;AACxB,cAAM,IAAI,MAAM,UAAU,IAAI,mDAAmD;AAAA,MACnF;AACA,UAAI,QAAQ,SAAS,KAAK;AACxB,cAAM,IAAI,MAAM,UAAU,IAAI,sDAAsD;AAAA,MACtF;AACA,oBAAc;AAAA,IAChB;AAEA,UAAM,KAAK,MAAM,WAAW;AAC5B,QAAI,OAAO,aAAa,OAAO,OAAO;AACpC,YAAM,IAAI;AAAA,QACR,UAAU,IAAI,mDAAmD,KAAK,UAAU,EAAE,CAAC;AAAA,MACrF;AAAA,IACF;AACA,UAAM,SAAwB;AAAA,MAC5B,WAAW;AAAA,MACX,SAAS;AAAA,MACT;AAAA,MACA,SAAS;AAAA,IACX;AACA,QAAI,gBAAgB,OAAW,QAAO,eAAe;AACrD,WAAO,EAAE,OAAO;AAAA,EAClB;AAEA,SAAO,EAAE,MAAM,EAAE,WAAW,QAAQ,EAAE;AACxC;AAEA,SAAS,YACP,KACA,SACA,YACA,aACA,YACA,WAC6B;AAC7B,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,QAAM,UAAU,OAAO,QAAQ,GAA8B;AAC7D,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,QAAM,SAAsC,CAAC;AAC7C,aAAW,CAAC,MAAM,GAAG,KAAK,SAAS;AACjC,QAAI,CAAC,cAAc,KAAK,IAAI,GAAG;AAC7B,YAAM,IAAI,MAAM,UAAU,IAAI,4CAA4C;AAAA,IAC5E;AACA,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,YAAM,IAAI,MAAM,UAAU,IAAI,oBAAoB;AAAA,IACpD;AACA,UAAM,QAAQ;AACd,QAAI;AACJ,QAAI,MAAM,YAAY,QAAW;AAC/B,gBAAU,YAAY,IAAI;AAAA,IAC5B,WAAW,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,WAAW,GAAG;AAC1E,YAAM,IAAI,MAAM,UAAU,IAAI,qCAAqC;AAAA,IACrE,OAAO;AACL,gBAAU,MAAM;AAAA,IAClB;AAEA,QAAI,MAAM,YAAY,QAAW;AAC/B,YAAM,IAAI;AAAA,QACR,UAAU,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,QAAW;AAC3B,YAAM,IAAI,MAAM,UAAU,IAAI,gCAAgC;AAAA,IAChE;AACA,UAAM,MAAM,cAAc,MAAM,MAAM,GAAG;AACzC,UAAM,sBAAsB,qBAAqB,MAAM,MAAM,gBAAgB;AAG7E,QAAI,MAAM,WAAW,QAAW;AAC9B,YAAM,IAAI;AAAA,QACR,UAAU,IAAI,0DACc,IAAI,yDACpB,IAAI;AAAA,MAClB;AAAA,IACF;AACA,QAAI,OAAO,MAAM,cAAc,UAAU;AACvC,YAAM,IAAI;AAAA,QACR,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAIhB;AAAA,IACF;AACA,eAAW,KAAK,CAAC,kBAAkB,SAAS,SAAS,GAAY;AAC/D,UAAI,MAAM,CAAC,MAAM,QAAW;AAC1B,cAAM,IAAI;AAAA,UACR,UAAU,IAAI,IAAI,CAAC;AAAA,QAErB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAmC,CAAC;AAC1C,QAAI,YAAY,aAAa,OAAW,YAAW,WAAW,YAAY;AAC1E,QAAI,YAAY,cAAc,OAAW,YAAW,YAAY,YAAY;AAC5E,QAAI,MAAM,UAAU,UAAa,MAAM,UAAU,MAAM;AACrD,UAAI,OAAO,MAAM,UAAU,YAAY,MAAM,QAAQ,MAAM,KAAK,GAAG;AACjE,cAAM,IAAI,MAAM,UAAU,IAAI,0BAA0B;AAAA,MAC1D;AACA,YAAM,IAAI,MAAM;AAChB,UAAI,OAAO,UAAU,eAAe,KAAK,GAAG,UAAU,GAAG;AACvD,YAAI,OAAO,EAAE,aAAa,SAAU,YAAW,WAAW,EAAE;AAAA,YACvD,QAAO,WAAW;AAAA,MACzB;AACA,UAAI,OAAO,UAAU,eAAe,KAAK,GAAG,WAAW,GAAG;AACxD,YAAI,OAAO,EAAE,cAAc,SAAU,YAAW,YAAY,EAAE;AAAA,YACzD,QAAO,WAAW;AAAA,MACzB;AAAA,IACF;AAEA,QAAI;AACJ,QAAI,MAAM,cAAc,UAAa,MAAM,cAAc,MAAM;AAC7D,UAAI,YAAY,SAAS;AAKvB,YAAI,OAAO,MAAM,cAAc,YAAY,MAAM,cAAc,QAAQ,MAAM,QAAQ,MAAM,SAAS,GAAG;AACrG,gBAAM,IAAI,MAAM,UAAU,IAAI,8BAA8B;AAAA,QAC9D;AACA,cAAM,IAAI,MAAM;AAChB,cAAM,aAAa,OAAO,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,MAAM,YAAY,MAAM,gBAAgB;AACxF,YAAI,WAAW,SAAS,GAAG;AACzB,gBAAM,IAAI;AAAA,YACR,UAAU,IAAI,cAAc,WAAW,CAAC,CAAC;AAAA,UAK3C;AAAA,QACF;AAAA,MACF;AACA,uBAAiB,oBAAoB,MAAM,MAAM,WAAW,YAAY,SAAS;AAAA,IACnF;AAEA,UAAM,UAAU,sBAAsB,MAAM,OAAO,UAAU;AAE7D,UAAM,WAAwB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,IACF;AACA,QAAI,eAAgB,UAAS,YAAY;AACzC,QAAI,QAAQ,OAAQ,UAAS,SAAS,QAAQ;AAC9C,QAAI,QAAQ,KAAM,UAAS,OAAO,QAAQ;AAC1C,WAAO,IAAI,IAAI;AAAA,EACjB;AACA,SAAO;AACT;AAEA,SAAS,aAAa,KAA6C;AACjE,QAAM,UAAU,OAAO;AACvB,MAAI,YAAY,WAAW,YAAY,YAAY,YAAY,UAAU;AACvE,UAAM,IAAI,MAAM,wDAAwD,OAAO,IAAI;AAAA,EACrF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,KAAyE;AAC3F,QAAM,MAAiD,CAAC;AACxD,MAAI,IAAI,SAAS,OAAO,IAAI,UAAU,UAAU;AAC9C,UAAM,IAAI,IAAI;AACd,QAAI,OAAO,EAAE,aAAa,SAAU,KAAI,WAAW,EAAE;AACrD,QAAI,OAAO,EAAE,cAAc,SAAU,KAAI,YAAY,EAAE;AAAA,EACzD;AACA,SAAO;AACT;AAEO,SAAS,gBACd,UACA,OAA+B,CAAC,GACnB;AACb,QAAM,MAAM,MAAM,QAAQ,KAAK,CAAC;AAChC,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,GAAG;AACjE,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AACA,QAAM,IAAI;AAEV,MAAI,EAAE,cAAc,QAAW;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,QAAW;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,YAAY,QAAW;AAC3B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,QAAW;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,QAAW;AAC1B,UAAM,IAAI,MAAM,sEAAiE;AAAA,EACnF;AAEA,QAAM,UAAU,aAAa,EAAE,OAAO;AACtC,QAAM,aAAa,QAAQ;AAC3B,QAAM,aAAa,gBAAgB,EAAE,YAAY,UAAU;AAC3D,QAAM,QAAQ,WAAW,CAAC;AAC1B,QAAM,SAAS,YAAY,EAAE,QAAQ,SAAS,YAAY,OAAO,YAAY,KAAK,SAAS;AAE3F,QAAM,MAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,EAAE,cAAc,UAAa,EAAE,cAAc,MAAM;AACrD,QAAI,YAAY,SAAS;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,QAAI,YAAY,oBAAoB,EAAE,SAAS;AAAA,EACjD;AACA,SAAO;AACT;AAEO,SAAS,cACd,KACA,MAC6B;AAC7B,SAAO,IAAI,WAAW,IAAI;AAC5B;AAEO,SAAS,oBACd,KAC2D;AAC3D,QAAM,WAAW,OAAO,QAAQ,IAAI,UAAU,EAAE;AAAA,IAC9C,CAAC,MAA4C,EAAE,CAAC,EAAE,SAAS;AAAA,EAC7D;AACA,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,IAAI;AAAA,MACR,6DAA6D,SAC1D,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EACf,KAAK,IAAI,CAAC;AAAA,IACf;AAAA,EACF;AACA,QAAM,CAAC,MAAM,SAAS,IAAI,SAAS,CAAC;AACpC,SAAO,EAAE,MAAM,UAAU;AAC3B;AAEO,SAAS,kBACd,KACyD;AACzD,QAAM,QAAQ,OAAO,QAAQ,IAAI,UAAU,EAAE;AAAA,IAC3C,CAAC,MAA0C,EAAE,CAAC,EAAE,SAAS;AAAA,EAC3D;AACA,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,IAAI;AAAA,MACR,yDAAyD,MACtD,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EACf,KAAK,IAAI,CAAC;AAAA,IACf;AAAA,EACF;AACA,QAAM,CAAC,MAAM,SAAS,IAAI,MAAM,CAAC;AACjC,SAAO,EAAE,MAAM,UAAU;AAC3B;AAMO,SAAS,eAAe,KAAqC;AAClE,QAAM,IAAI,KAAK,KAAK,YAAY;AAChC,MAAI,WAAW,CAAC,EAAG,QAAO,EAAE,MAAM,EAAE;AACpC,QAAM,SAAS,KAAK,KAAK,gBAAgB;AACzC,MAAI,WAAW,MAAM,GAAG;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,MAAmB,OAA8B;AAC7E,QAAM,cAAc,MAAM;AAC1B,MACE,gBAAgB,UAChB,gBAAgB,WAChB,gBAAgB,YAChB,gBAAgB,UAChB;AACA,UAAM,IAAI,MAAM,wDAAwD,MAAM,OAAO,IAAI;AAAA,EAC3F;AACA,QAAM,UAAU,eAAe,KAAK;AACpC,QAAM,SAAsB;AAAA,IAC1B;AAAA,IACA,YAAY,KAAK;AAAA,IACjB,QAAQ,KAAK;AAAA,IACb,OAAO,EAAE,GAAG,KAAK,MAAM;AAAA,EACzB;AACA,MAAI,YAAY,YAAY,YAAY,UAAU;AAChD,UAAM,QAAQ,MAAM,SAAS,KAAK,WAAW;AAC7C,QAAI,UAAU,QAAW;AACvB,aAAO,YAAY,EAAE,MAAM;AAAA,IAC7B,WAAW,KAAK,cAAc,QAAW;AACvC,aAAO,YAAY,EAAE,GAAG,KAAK,UAAU;AAAA,IACzC;AAAA,EACF;AACA,SAAO;AACT;;;AEz4BA,SAAS,iBAAiB;AAC1B,SAAS,QAAAA,aAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,OAOK;AAgHA,IAAM,mBAAN,MAA8C;AAAA,EAC1C;AAAA,EACQ,UAAU,oBAAI,IAAuB;AAAA,EAEtD;AAAA,EACA;AAAA,EAEA,YAAY,MAA+B;AACzC,SAAK,OAAO;AACZ,SAAK,UAAU,KAAK,YAAY,MAAM;AAAA,IAAC;AACvC,QAAI,KAAK,mBAAmB;AAC1B,WAAK,oBAAoB,KAAK;AAAA,IAChC,WAAW,KAAK,WAAW;AACzB,YAAM,aAAa,KAAK;AACxB,WAAK,oBAAoB,OAAO,MAAM,QAAQ;AAC5C,cAAM,MAAM,KAAK,KAAK,OAAO,IAAI;AACjC,cAAM,SAAS,WAAW,SAAS,MAAM,IAAI,WAAW,KAAK;AAAA,UAC3D,WAAW,KAAK,uBAAuB;AAAA,QACzC,CAAC;AACD,aAAK,KAAK,uBAAuB,MAAM;AACvC,eAAO,OAAO;AAAA,MAChB;AAAA,IACF,OAAO;AACL,WAAK,oBAAoB,aAAa,EAAE,UAAU,SAAS;AAAA,IAC7D;AAAA,EACF;AAAA,EAEA,SAAS,MAAuB;AAC9B,WAAO,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK,QAAQ,IAAI;AAAA,EACpE;AAAA,EAEA,gBAAgB,MAAuB;AACrC,WAAO,QAAQ,KAAK,KAAK,gBAAgB,IAAI,CAAC;AAAA,EAChD;AAAA,EAEA,gBAAgB,MAAsC;AACpD,WAAO,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC;AAAA,EACnC;AAAA,EAEA,kBAAkB,MAAkC;AAClD,WAAO,KAAK,KAAK,QAAQ,IAAI;AAAA,EAC/B;AAAA,EAEA,mBAAmB,MAA0B;AAC3C,WAAO,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC;AAAA,EACtC;AAAA,EAEA,gBAAgB,MAAsB;AACpC,WACE,KAAK,KAAK,MAAM,IAAI,KACpB,KAAK,KAAK,OAAO,IAAI,GAAG,WACxB,QAAQ,IAAI;AAAA,EAEhB;AAAA,EAEA,aAAuB;AACrB,WAAO,OAAO,KAAK,KAAK,KAAK,MAAM;AAAA,EACrC;AAAA,EAEA,qBAAqB,MAAsB;AACzC,WAAO,KAAK,KAAK,OAAO,IAAI,GAAG,uBAAuB;AAAA,EACxD;AAAA,EAEA,MAAM,cAAc,MAAc,UAAkB,WAAqC;AACvF,QAAI,CAAC,KAAK,SAAS,IAAI,EAAG,OAAM,IAAI,MAAM,kBAAkB,IAAI,EAAE;AAClE,UAAM,SAAS,MAAM,KAAK,aAAa,IAAI;AAC3C,WAAO,OAAO,cAAc,UAAU,SAAS;AAAA,EACjD;AAAA,EAEA,WAAW,MAAc,UAAwB;AAC/C,QAAI,CAAC,KAAK,SAAS,IAAI,EAAG;AAC1B,UAAM,SAAS,KAAK,QAAQ,IAAI,IAAI;AACpC,YAAQ,WAAW,QAAQ;AAAA,EAC7B;AAAA,EAEA,MAAM,cAAc,MAAc,WAAkC;AAClE,QAAI,CAAC,KAAK,SAAS,IAAI,EAAG;AAC1B,UAAM,SAAS,KAAK,QAAQ,IAAI,IAAI;AAGpC,SAAK,KAAK,WAAW,cAAc,SAAS;AAC5C,QAAI,CAAC,OAAQ;AACb,QAAI;AACF,YAAM,OAAO,OAAO,SAAS;AAAA,IAC/B,SAAS,KAAK;AAGZ,cAAQ,KAAK,QAAQ,IAAI,YAAY,SAAS,aAAa,GAAG;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,MAAc,OAA2C;AACpE,QAAI,CAAC,KAAK,SAAS,IAAI,EAAG,OAAM,IAAI,MAAM,kBAAkB,IAAI,EAAE;AAClE,UAAM,SAAS,MAAM,KAAK,aAAa,IAAI;AAC3C,WAAO,OAAO,OAAO,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,QAAQ;AAAA,MACZ,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA,IAChD;AACA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,MAAc,aAAa,MAAkC;AAC3D,UAAM,WAAW,KAAK,QAAQ,IAAI,IAAI;AACtC,QAAI,SAAU,QAAO;AACrB,UAAM,MAAM,KAAK,KAAK,OAAO,IAAI;AACjC,QAAI,CAAC,IAAI,IAAK,OAAM,IAAI,MAAM,UAAU,IAAI,qBAAqB;AACjE,UAAM,QAAQ,oBAAoB,IAAI,GAAG;AACzC,eAAW,OAAO,KAAK,KAAK,eAAe,IAAI,KAAK,CAAC,GAAG;AACtD,gBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AACA,UAAM,SAAS,IAAI,UAAU;AAAA,MAC3B,OAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS,MAAM;AAAA,QACf,MAAM,MAAM;AAAA,QACZ,KAAK,KAAK,KAAK,MAAM,IAAI;AAAA,QACzB,KAAK,KAAK,gBAAgB,IAAI;AAAA,QAC9B,OAAO,KAAK,KAAK,QAAQ,IAAI;AAAA,QAC7B,QAAQ,KAAK,mBAAmB,IAAI;AAAA,MACtC;AAAA,MACA,cAAc,KAAK,KAAK,YAAYA,MAAK,KAAK,KAAK,WAAW,IAAI,IAAI;AAAA,MACtE,SAAS,KAAK,KAAK;AAAA,MACnB,SAAS,CAAC,MAAM,KAAK,QAAQ,MAAM,CAAC;AAAA,MACpC,mBAAmB,CAAC,QAAQ,KAAK,kBAAkB,MAAM,GAAG;AAAA,MAC5D,OAAO,KAAK,KAAK,QAAQ,CAAC,MAAM,KAAK,KAAK,MAAO,MAAM,CAAC,IAAI;AAAA,MAC5D,cAAc,KAAK,KAAK,gBAAgB,IAAI;AAAA,IAC9C,CAAC;AACD,UAAM,OAAO,MAAM;AACnB,SAAK,QAAQ,IAAI,MAAM,MAAM;AAC7B,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBAAoB,MAGlC;AACA,MAAI,YAAY,QAAQ,KAAK,QAAQ;AACnC,WAAO,cAAc,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;AAAA,EACzD;AACA,MAAI,aAAa,QAAQ,KAAK,SAAS;AACrC,WAAO,EAAE,SAAS,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC,EAAE;AAAA,EACxD;AACA,QAAM,IAAI,MAAM,qDAAqD;AACvE;;;AC9QA,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAqCpB,IAAM,qBAAN,cAAiC,aAAa;AAAA,EAClC,UAAU,oBAAI,IAA0B;AAAA,EACxC,YAAY,oBAAI,IAAyB;AAAA,EAE1D,SACE,WACA,WACA,KACA,OAAwB,CAAC,GACL;AACpB,UAAM,aAAa,WAAW;AAC9B,QAAI;AACJ,UAAM,kBAAkB,IAAI,QAA0B,CAAC,MAAM;AAC3D,gBAAU;AAAA,IACZ,CAAC;AACD,UAAM,QAAsB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,IAAI;AAAA,MAChB,UAAU,IAAI;AAAA,MACd,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,IACF;AACA,QAAI,KAAK,aAAa,KAAK,YAAY,GAAG;AACxC,YAAM,QAAQ,WAAW,MAAM;AAC7B,YAAI,KAAK,QAAQ,IAAI,UAAU,MAAM,MAAO;AAC5C,cAAM,QAAQ,EAAE,UAAU,SAAS,CAAC;AACpC,aAAK,QAAQ,OAAO,UAAU;AAC9B,aAAK,UAAU,IAAI,SAAS,GAAG,OAAO,UAAU;AAChD,aAAK,KAAK,WAAW,EAAE,YAAY,WAAW,UAAU,CAAC;AAAA,MAC3D,GAAG,KAAK,SAAS;AACjB,YAAM,MAAM,QAAQ;AAAA,IACtB;AACA,SAAK,QAAQ,IAAI,YAAY,KAAK;AAClC,QAAI,MAAM,KAAK,UAAU,IAAI,SAAS;AACtC,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,WAAK,UAAU,IAAI,WAAW,GAAG;AAAA,IACnC;AACA,QAAI,IAAI,UAAU;AAClB,SAAK,KAAK,cAAc,KAAK,SAAS,KAAK,CAAC;AAC5C,WAAO,KAAK,SAAS,KAAK;AAAA,EAC5B;AAAA,EAEA,QACE,WACA,YACA,UACS;AACT,UAAM,QAAQ,KAAK,QAAQ,IAAI,UAAU;AACzC,QAAI,CAAC,SAAS,MAAM,cAAc,UAAW,QAAO;AACpD,QAAI,MAAM,MAAO,cAAa,MAAM,KAAK;AACzC,UAAM,QAAQ,QAAQ;AACtB,SAAK,QAAQ,OAAO,UAAU;AAC9B,SAAK,UAAU,IAAI,SAAS,GAAG,OAAO,UAAU;AAChD,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAAyB;AACrC,UAAM,MAAM,KAAK,UAAU,IAAI,SAAS;AACxC,QAAI,CAAC,IAAK;AACV,eAAW,MAAM,CAAC,GAAG,GAAG,GAAG;AACzB,YAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,UAAI,OAAO;AACT,YAAI,MAAM,MAAO,cAAa,MAAM,KAAK;AACzC,cAAM,QAAQ,EAAE,UAAU,SAAS,CAAC;AACpC,aAAK,QAAQ,OAAO,EAAE;AAAA,MACxB;AAAA,IACF;AACA,SAAK,UAAU,OAAO,SAAS;AAAA,EACjC;AAAA,EAEA,YAAY,WAAyC;AACnD,UAAM,MAAM,KAAK,UAAU,IAAI,SAAS;AACxC,QAAI,CAAC,IAAK,QAAO,CAAC;AAClB,UAAM,MAA4B,CAAC;AACnC,eAAW,MAAM,KAAK;AACpB,YAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,UAAI,MAAO,KAAI,KAAK,KAAK,SAAS,KAAK,CAAC;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEQ,SAAS,OAAyC;AACxD,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,WAAW,MAAM;AAAA,MACjB,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,WAAW,MAAM;AAAA,MACjB,WAAW,MAAM;AAAA,MACjB,SAAS,MAAM;AAAA,MACf,iBAAiB,MAAM;AAAA,IACzB;AAAA,EACF;AACF;","names":["join"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zooid/core",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "zooid core: SessionRunner, Chunker, hooks, config parsing, and the Runtime/Adapter/Transport interfaces.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,7 +26,7 @@
26
26
  "dependencies": {
27
27
  "dotenv-expand": "^13.0.0",
28
28
  "yaml": "^2.5.0",
29
- "@zooid/acp-client": "^0.7.0"
29
+ "@zooid/acp-client": "^0.7.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",
@@ -1,3 +1,4 @@
1
+ import { mkdirSync } from 'node:fs'
1
2
  import { join } from 'node:path'
2
3
  import {
3
4
  AcpClient,
@@ -9,7 +10,7 @@ import {
9
10
  type PromptResult,
10
11
  type TapEvent,
11
12
  } from '@zooid/acp-client'
12
- import type { AcpAgentSpec, AcpRuntime } from './acp-types.js'
13
+ import type { AcpAgentSpec, AcpMount, AcpRuntime } from './acp-types.js'
13
14
  import type { AgentConfig } from './types.js'
14
15
  import type {
15
16
  ApprovalCorrelator,
@@ -93,6 +94,21 @@ export interface AcpAgentRegistryOptions {
93
94
  * transports without a context provider (e.g. HTTP) have no entry here.
94
95
  */
95
96
  contextSpawns?: Record<string, ContextSpawnFactory | undefined>
97
+ /**
98
+ * Per-agent resolved bind-mount list. Threaded into the AcpClient's spawn
99
+ * spec; honoured by the docker runtime, ignored by the local runtime.
100
+ */
101
+ mounts?: Record<string, AcpMount[]>
102
+ /**
103
+ * Per-agent list of host directories to `mkdir -p` before the first
104
+ * `runtime.spawn` for that agent. Subset of mount entries with `create: true`.
105
+ */
106
+ mkdirOnSpawn?: Record<string, string[]>
107
+ /**
108
+ * Per-agent override for the spawn-spec `cwd`. Set to e.g. `/workspace`
109
+ * when the workspace mount is active; falls back to `agent.workdir`.
110
+ */
111
+ cwd?: Record<string, string>
96
112
  }
97
113
 
98
114
  export type ContextSpawnFactory = (
@@ -148,6 +164,22 @@ export class AcpAgentRegistry implements AcpRegistry {
148
164
  return this.opts.image?.[name]
149
165
  }
150
166
 
167
+ resolveSpawnMounts(name: string): AcpMount[] {
168
+ return this.opts.mounts?.[name] ?? []
169
+ }
170
+
171
+ resolveSpawnCwd(name: string): string {
172
+ return (
173
+ this.opts.cwd?.[name] ??
174
+ this.opts.agents[name]?.workdir ??
175
+ process.cwd()
176
+ )
177
+ }
178
+
179
+ agentNames(): string[] {
180
+ return Object.keys(this.opts.agents)
181
+ }
182
+
151
183
  getApprovalTimeoutMs(name: string): number {
152
184
  return this.opts.agents[name]?.approval_timeout_ms ?? 0
153
185
  }
@@ -199,14 +231,18 @@ export class AcpAgentRegistry implements AcpRegistry {
199
231
  const cfg = this.opts.agents[name]
200
232
  if (!cfg.acp) throw new Error(`agents.${name}: missing acp block`)
201
233
  const spawn = resolveAcpAgentSpec(cfg.acp)
234
+ for (const dir of this.opts.mkdirOnSpawn?.[name] ?? []) {
235
+ mkdirSync(dir, { recursive: true })
236
+ }
202
237
  const client = new AcpClient({
203
238
  agent: {
204
239
  id: name,
205
240
  command: spawn.command,
206
241
  args: spawn.args,
207
242
  env: this.opts.env?.[name],
208
- cwd: cfg.workdir,
243
+ cwd: this.resolveSpawnCwd(name),
209
244
  image: this.opts.image?.[name],
245
+ mounts: this.resolveSpawnMounts(name),
210
246
  },
211
247
  agentDataDir: this.opts.agentsDir ? join(this.opts.agentsDir, name) : undefined,
212
248
  runtime: this.opts.runtime,
@@ -401,7 +401,7 @@ agents:
401
401
  expect(t.user_namespace).toBe('@.*:localhost')
402
402
  }
403
403
  expect(config.agents.architect!.matrix?.user_id).toBe('@architect:localhost')
404
- expect(config.agents.architect!.matrix?.rooms).toEqual(['!r1:localhost'])
404
+ expect(config.agents.architect!.matrix?.rooms).toEqual([{ alias: '!r1:localhost' }])
405
405
  expect(config.agents.architect!.matrix?.trigger).toBe('mention')
406
406
  })
407
407
 
@@ -649,8 +649,8 @@ agents:
649
649
  - '#docs'
650
650
  `)
651
651
  expect(config.agents.docs!.matrix?.rooms).toEqual([
652
- '#welcome:localhost',
653
- '#docs:localhost',
652
+ { alias: '#welcome:localhost' },
653
+ { alias: '#docs:localhost' },
654
654
  ])
655
655
  })
656
656
 
@@ -668,7 +668,7 @@ agents:
668
668
  rooms:
669
669
  - '!abc'
670
670
  `)
671
- expect(config.agents.docs!.matrix?.rooms).toEqual(['!abc:localhost'])
671
+ expect(config.agents.docs!.matrix?.rooms).toEqual([{ alias: '!abc:localhost' }])
672
672
  })
673
673
 
674
674
  it('leaves fully-qualified user_id and rooms untouched (mixed forms in one binding)', () => {
@@ -689,9 +689,9 @@ agents:
689
689
  `)
690
690
  expect(config.agents.docs!.matrix?.user_id).toBe('@docs:localhost')
691
691
  expect(config.agents.docs!.matrix?.rooms).toEqual([
692
- '#welcome:localhost',
693
- '#docs:localhost',
694
- '!r1:localhost',
692
+ { alias: '#welcome:localhost' },
693
+ { alias: '#docs:localhost' },
694
+ { alias: '!r1:localhost' },
695
695
  ])
696
696
  })
697
697
 
@@ -728,7 +728,86 @@ agents:
728
728
  rooms:
729
729
  - 'welcome'
730
730
  `),
731
- ).toThrow(/rooms\[\] must start with '#' or '!'/)
731
+ ).toThrow(/must start with '#' or '!'/)
732
+ })
733
+ })
734
+
735
+ describe('agent matrix.rooms power_level binding', () => {
736
+ it('accepts bare-alias strings (default PL, no powerLevel field)', () => {
737
+ const cfg = loadZooidConfig(`
738
+ runtime: local
739
+ ${MATRIX_TRANSPORT.trimStart()}
740
+ agents:
741
+ bot:
742
+ workdir: ./bot
743
+ acp: { preset: claude }
744
+ matrix:
745
+ transport: matrix-local
746
+ user_id: '@bot:localhost'
747
+ rooms: ['#general']
748
+ trigger: mention
749
+ `)
750
+ expect(cfg.agents.bot!.matrix?.rooms).toEqual([{ alias: '#general:localhost' }])
751
+ })
752
+
753
+ it('accepts { alias, power_level } object entries and normalizes them', () => {
754
+ const cfg = loadZooidConfig(`
755
+ runtime: local
756
+ ${MATRIX_TRANSPORT.trimStart()}
757
+ agents:
758
+ mod:
759
+ workdir: ./mod
760
+ acp: { preset: claude }
761
+ matrix:
762
+ transport: matrix-local
763
+ user_id: '@mod:localhost'
764
+ rooms:
765
+ - '#general'
766
+ - { alias: '#chat', power_level: 50 }
767
+ trigger: mention
768
+ `)
769
+ expect(cfg.agents.mod!.matrix?.rooms).toEqual([
770
+ { alias: '#general:localhost' },
771
+ { alias: '#chat:localhost', powerLevel: 50 },
772
+ ])
773
+ })
774
+
775
+ it('rejects an object entry without a string alias', () => {
776
+ expect(() =>
777
+ loadZooidConfig(`
778
+ runtime: local
779
+ ${MATRIX_TRANSPORT.trimStart()}
780
+ agents:
781
+ mod:
782
+ workdir: ./mod
783
+ acp: { preset: claude }
784
+ matrix:
785
+ transport: matrix-local
786
+ user_id: '@mod:localhost'
787
+ rooms:
788
+ - { power_level: 50 }
789
+ trigger: mention
790
+ `),
791
+ ).toThrow(/alias/)
792
+ })
793
+
794
+ it('rejects a non-integer power_level', () => {
795
+ expect(() =>
796
+ loadZooidConfig(`
797
+ runtime: local
798
+ ${MATRIX_TRANSPORT.trimStart()}
799
+ agents:
800
+ mod:
801
+ workdir: ./mod
802
+ acp: { preset: claude }
803
+ matrix:
804
+ transport: matrix-local
805
+ user_id: '@mod:localhost'
806
+ rooms:
807
+ - { alias: '#chat', power_level: 'high' }
808
+ trigger: mention
809
+ `),
810
+ ).toThrow(/power_level/)
732
811
  })
733
812
  })
734
813
 
@@ -1280,7 +1359,7 @@ agents:
1280
1359
  expect(cfg.agents.echo.workdir).toBe('./agents/echo')
1281
1360
  expect(cfg.agents.echo.matrix?.transport).toBe('matrix')
1282
1361
  expect(cfg.agents.echo.matrix?.user_id).toBe('@echo:localhost')
1283
- expect(cfg.agents.echo.matrix?.rooms).toEqual(['#welcome:localhost'])
1362
+ expect(cfg.agents.echo.matrix?.rooms).toEqual([{ alias: '#welcome:localhost' }])
1284
1363
 
1285
1364
  expect(cfg.agents.docs.workdir).toBe('./agents/docs')
1286
1365
  expect(cfg.agents.docs.matrix?.user_id).toBe('@docs:localhost')