opencode-tbot 0.1.33 → 0.1.35

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.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../src/infra/utils/redact.ts","../src/infra/logger/index.ts","../src/repositories/pending-action.repo.ts","../src/repositories/permission-approval.repo.ts","../src/repositories/session.repo.ts","../src/infra/utils/markdown-text.ts","../src/services/opencode/opencode.client.ts","../src/services/storage/bot-state.ts","../src/services/storage/json-state-store.ts","../src/services/telegram/telegram.client.ts","../src/services/session-activity/foreground-session-tracker.ts","../src/use-cases/abort-prompt.usecase.ts","../src/use-cases/session-creation.ts","../src/use-cases/create-session.usecase.ts","../src/use-cases/get-health.usecase.ts","../src/use-cases/get-path.usecase.ts","../src/use-cases/get-status.usecase.ts","../src/use-cases/agent-selection.ts","../src/use-cases/binding-update.ts","../src/use-cases/list-agents.usecase.ts","../src/use-cases/list-lsp.usecase.ts","../src/use-cases/list-mcp.usecase.ts","../src/use-cases/list-models.usecase.ts","../src/use-cases/list-sessions.usecase.ts","../src/use-cases/rename-session.usecase.ts","../src/use-cases/send-prompt.usecase.ts","../src/use-cases/switch-agent.usecase.ts","../src/use-cases/switch-model.usecase.ts","../src/use-cases/switch-session.usecase.ts","../src/use-cases/upload-file.usecase.ts","../src/app/container.ts","../src/app/bootstrap.ts","../src/services/permission/telegram-approval.ts","../src/app/plugin-events.ts","../src/bot/copy.ts","../src/bot/commands/command-list.ts","../src/bot/commands/sync-commands.ts","../src/bot/logger-context.ts","../src/bot/presenters/error.presenter.ts","../src/bot/error-boundary.ts","../src/bot/i18n.ts","../src/bot/presenters/keyboard.presenter.ts","../src/bot/presenters/message.presenter.ts","../src/bot/commands/agents.ts","../src/bot/sessions-menu.ts","../src/bot/session-rename.ts","../src/bot/commands/cancel.ts","../src/bot/commands/language.ts","../src/bot/commands/models.ts","../src/bot/commands/new.ts","../src/services/telegram/telegram-format.ts","../src/bot/commands/status.ts","../src/bot/commands/sessions.ts","../src/bot/presenters/static.presenter.ts","../src/bot/commands/start.ts","../src/bot/handlers/callback.handler.ts","../src/bot/handlers/prompt.handler.ts","../src/bot/handlers/file.handler.ts","../src/bot/handlers/message.handler.ts","../src/bot/handlers/voice.handler.ts","../src/bot/middlewares/auth.ts","../src/bot/middlewares/logging.ts","../src/bot/index.ts","../src/app/runtime.ts","../src/plugin.ts"],"sourcesContent":["const REDACTED = \"[REDACTED]\";\nconst DEFAULT_PREVIEW_LENGTH = 160;\nconst TELEGRAM_TOKEN_PATTERN = /\\b\\d{6,}:[A-Za-z0-9_-]{20,}\\b/g;\nconst BEARER_TOKEN_PATTERN = /\\bBearer\\s+[A-Za-z0-9._~+/-]+=*\\b/gi;\nconst NAMED_SECRET_PATTERN = /\\b(api[_\\s-]?key|token|secret|password)\\b(\\s*[:=]\\s*)([^\\s,;]+)/gi;\nconst API_KEY_LIKE_PATTERN = /\\b(?:sk|pk)_[A-Za-z0-9_-]{10,}\\b/g;\n\nexport function redactSensitiveText(input: string): string {\n return input\n .replace(BEARER_TOKEN_PATTERN, `Bearer ${REDACTED}`)\n .replace(TELEGRAM_TOKEN_PATTERN, REDACTED)\n .replace(NAMED_SECRET_PATTERN, (_, name: string, separator: string) => `${name}${separator}${REDACTED}`)\n .replace(API_KEY_LIKE_PATTERN, REDACTED);\n}\n\nexport function createRedactedPreview(input: string, maxLength = DEFAULT_PREVIEW_LENGTH): string {\n const redacted = redactSensitiveText(input).replace(/\\s+/g, \" \").trim();\n\n if (redacted.length <= maxLength) {\n return redacted;\n }\n\n return `${redacted.slice(0, Math.max(0, maxLength - 3))}...`;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir, readdir, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { redactSensitiveText } from \"../utils/redact.js\";\n\nexport type AppLogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\nexport type LogComponent =\n | \"app\"\n | \"runtime\"\n | \"telegram\"\n | \"opencode\"\n | \"prompt\"\n | \"plugin-event\"\n | \"storage\"\n | \"bot\";\nexport type LogEventName = string;\n\nexport interface StructuredLogError {\n data?: unknown;\n message: string;\n name: string;\n stack?: string;\n}\n\nexport interface StructuredLogEvent {\n ts: string;\n level: AppLogLevel;\n service: string;\n component: LogComponent | string;\n event: LogEventName;\n message: string;\n runtimeId: string | null;\n operationId: string | null;\n correlationId: string | null;\n worktree?: string;\n chatId?: number;\n sessionId?: string;\n projectId?: string;\n requestId?: string;\n updateId?: number;\n command?: string;\n callbackData?: string;\n durationMs?: number;\n attempt?: number;\n status?: string;\n sizeBytes?: number;\n error?: StructuredLogError;\n [key: string]: unknown;\n}\n\nexport interface LoggerContext {\n attempt?: number;\n callbackData?: string;\n chatId?: number;\n command?: string;\n component?: LogComponent | string;\n correlationId?: string | null;\n durationMs?: number;\n error?: StructuredLogError;\n event?: LogEventName;\n operationId?: string | null;\n projectId?: string;\n requestId?: string;\n runtimeId?: string | null;\n sessionId?: string;\n sizeBytes?: number;\n status?: string;\n updateId?: number;\n worktree?: string;\n}\n\nexport interface AppLogger {\n debug(input?: unknown, message?: string): void;\n info(input?: unknown, message?: string): void;\n warn(input?: unknown, message?: string): void;\n error(input?: unknown, message?: string): void;\n child(context: LoggerContext): AppLogger;\n flush(): Promise<void>;\n}\n\nexport interface LogSink {\n flush?(): Promise<void>;\n write(event: StructuredLogEvent): Promise<void>;\n}\n\nexport interface FileLogSinkOptions {\n dir: string;\n maxFiles?: number;\n maxTotalBytes?: number;\n runtimeId: string;\n}\n\ninterface OpenCodeAppLogClientLike {\n app: {\n log(input: {\n body?: {\n service: string;\n level: AppLogLevel;\n message: string;\n extra?: Record<string, unknown>;\n };\n service?: string;\n level?: AppLogLevel;\n message?: string;\n extra?: Record<string, unknown>;\n responseStyle?: \"data\" | \"fields\";\n throwOnError?: boolean;\n }, options?: {\n responseStyle?: \"data\" | \"fields\";\n throwOnError?: boolean;\n }): Promise<unknown>;\n };\n}\n\ninterface LoggerSinkOptions {\n file?: boolean;\n host?: boolean;\n}\n\ninterface CreateOpenCodeAppLoggerOptions {\n file?: {\n dir: string;\n retention?: {\n maxFiles?: number;\n maxTotalBytes?: number;\n };\n };\n level?: string | null;\n runtimeId?: string;\n service?: string;\n sinks?: LoggerSinkOptions;\n worktree?: string;\n}\n\ninterface PendingLogEvent {\n context: LoggerContext;\n input?: unknown;\n level: AppLogLevel;\n message?: string;\n}\n\nconst DEFAULT_COMPONENT: LogComponent = \"app\";\nconst DEFAULT_EVENT = \"log\";\nconst DEFAULT_SERVICE_NAME = \"opencode-tbot\";\nconst DEFAULT_MAX_LOG_FILES = 30;\nconst DEFAULT_MAX_TOTAL_LOG_BYTES = 314_572_800;\nconst CONTENT_OMITTED = \"[OMITTED]\";\nconst REDACTED = \"[REDACTED]\";\nconst LEVEL_PRIORITY: Record<AppLogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\nconst RESERVED_EVENT_FIELDS = new Set([\n \"attempt\",\n \"callbackData\",\n \"chatId\",\n \"command\",\n \"component\",\n \"correlationId\",\n \"durationMs\",\n \"error\",\n \"event\",\n \"operationId\",\n \"projectId\",\n \"requestId\",\n \"runtimeId\",\n \"sessionId\",\n \"sizeBytes\",\n \"status\",\n \"updateId\",\n \"worktree\",\n]);\n\nexport function createOpenCodeAppLogger(\n client: OpenCodeAppLogClientLike,\n options: CreateOpenCodeAppLoggerOptions = {},\n): AppLogger {\n const service = normalizeServiceName(options.service);\n const minimumLevel = normalizeLogLevel(options.level);\n const runtimeId = normalizeString(options.runtimeId) ?? randomUUID();\n const boundRootContext: LoggerContext = {\n component: DEFAULT_COMPONENT,\n runtimeId,\n ...(options.worktree ? { worktree: options.worktree } : {}),\n };\n const sinks = createSinks(client, {\n file: {\n dir: options.file?.dir,\n maxFiles: options.file?.retention?.maxFiles,\n maxTotalBytes: options.file?.retention?.maxTotalBytes,\n },\n runtimeId,\n service,\n sinks: options.sinks,\n });\n let queue = Promise.resolve();\n\n const enqueue = (event: PendingLogEvent) => {\n if (LEVEL_PRIORITY[event.level] < LEVEL_PRIORITY[minimumLevel]) {\n return;\n }\n\n const structuredEvent = buildStructuredLogEvent(\n event.level,\n event.input,\n event.message,\n service,\n event.context,\n );\n\n queue = queue\n .catch(() => undefined)\n .then(async () => {\n await Promise.allSettled(\n sinks.map((sink) => sink.write(structuredEvent)),\n );\n });\n };\n\n const createLogger = (context: LoggerContext): AppLogger => ({\n debug(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"debug\",\n message,\n });\n },\n info(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"info\",\n message,\n });\n },\n warn(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"warn\",\n message,\n });\n },\n error(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"error\",\n message,\n });\n },\n child(childContext: LoggerContext) {\n return createLogger({\n ...context,\n ...removeUndefinedFields(childContext),\n });\n },\n async flush() {\n await queue.catch(() => undefined);\n await Promise.allSettled(\n sinks.map(async (sink) => {\n await sink.flush?.();\n }),\n );\n },\n });\n\n return createLogger(boundRootContext);\n}\n\nexport function createOperationId(prefix = \"op\"): string {\n return `${prefix}-${randomUUID()}`;\n}\n\nexport function logTelegramUpdate(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"telegram\",\n ...input,\n },\n message,\n );\n}\n\nexport function logPromptLifecycle(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"prompt\",\n ...input,\n },\n message,\n );\n}\n\nexport function logOpenCodeRequest(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"opencode\",\n ...input,\n },\n message,\n );\n}\n\nexport function logPluginEvent(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"plugin-event\",\n ...input,\n },\n message,\n );\n}\n\nfunction createSinks(\n client: OpenCodeAppLogClientLike,\n options: {\n file?: {\n dir?: string;\n maxFiles?: number;\n maxTotalBytes?: number;\n };\n runtimeId: string;\n service: string;\n sinks?: LoggerSinkOptions;\n },\n): LogSink[] {\n const sinkOptions = options.sinks ?? {};\n const sinks: LogSink[] = [];\n\n if (sinkOptions.host !== false) {\n sinks.push(createHostSink(client, options.service));\n }\n\n if (sinkOptions.file !== false && options.file?.dir) {\n sinks.push(createJsonlFileSink({\n dir: options.file.dir,\n maxFiles: options.file.maxFiles,\n maxTotalBytes: options.file.maxTotalBytes,\n runtimeId: options.runtimeId,\n }));\n }\n\n return sinks;\n}\n\nfunction createHostSink(client: OpenCodeAppLogClientLike, service: string): LogSink {\n return {\n async write(event) {\n const payload = {\n service,\n level: event.level,\n message: event.message,\n extra: buildHostLogExtra(event),\n };\n\n if (client.app.log.length >= 2) {\n await client.app.log(payload, {\n responseStyle: \"data\",\n throwOnError: true,\n });\n return;\n }\n\n await client.app.log({\n body: payload,\n responseStyle: \"data\",\n throwOnError: true,\n });\n },\n };\n}\n\nfunction createJsonlFileSink(options: FileLogSinkOptions): LogSink {\n const maxFiles = options.maxFiles ?? DEFAULT_MAX_LOG_FILES;\n const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_TOTAL_LOG_BYTES;\n const runtimeSegment = sanitizeFileSegment(options.runtimeId);\n const timestampSegment = new Date().toISOString().replace(/:/gu, \"-\");\n const filePath = join(\n options.dir,\n `${timestampSegment}.${process.pid}.${runtimeSegment}.jsonl`,\n );\n let initialized = false;\n let writeCount = 0;\n\n const initialize = async () => {\n if (initialized) {\n return;\n }\n\n await mkdir(options.dir, { recursive: true });\n await cleanupLogDirectory(options.dir, maxFiles, maxTotalBytes);\n initialized = true;\n };\n\n return {\n async write(event) {\n await initialize();\n await appendFile(filePath, `${JSON.stringify(event)}\\n`, \"utf8\");\n writeCount += 1;\n\n if (writeCount === 1 || writeCount % 100 === 0) {\n await cleanupLogDirectory(options.dir, maxFiles, maxTotalBytes);\n }\n },\n };\n}\n\nasync function cleanupLogDirectory(\n directory: string,\n maxFiles: number,\n maxTotalBytes: number,\n): Promise<void> {\n let entries: Array<{ path: string; size: number; time: number }> = [];\n\n try {\n const names = await readdir(directory);\n\n entries = await Promise.all(\n names\n .filter((name) => name.endsWith(\".jsonl\"))\n .map(async (name) => {\n const entryPath = join(directory, name);\n const entryStat = await stat(entryPath);\n\n return {\n path: entryPath,\n size: entryStat.size,\n time: entryStat.mtimeMs,\n };\n }),\n );\n } catch {\n return;\n }\n\n entries.sort((left, right) => right.time - left.time);\n\n let totalBytes = 0;\n const retained: Array<{ path: string; size: number; time: number }> = [];\n const deleted: Array<{ path: string; size: number; time: number }> = [];\n\n for (const entry of entries) {\n const canKeepByCount = retained.length < maxFiles;\n const canKeepBySize = retained.length === 0 || totalBytes + entry.size <= maxTotalBytes;\n\n if (canKeepByCount && canKeepBySize) {\n retained.push(entry);\n totalBytes += entry.size;\n continue;\n }\n\n deleted.push(entry);\n }\n\n await Promise.allSettled(\n deleted.map(async (entry) => {\n await unlink(entry.path);\n }),\n );\n}\n\nfunction buildStructuredLogEvent(\n level: AppLogLevel,\n input: unknown,\n message: string | undefined,\n service: string,\n boundContext: LoggerContext,\n): StructuredLogEvent {\n const extracted = extractContextAndExtra(input);\n const context: LoggerContext = {\n ...removeUndefinedFields(boundContext),\n ...removeUndefinedFields(extracted.context),\n };\n const resolvedMessage = normalizeLogMessage(input, message);\n\n return {\n ts: new Date().toISOString(),\n level,\n service,\n component: normalizeComponent(context.component),\n event: normalizeEventName(context.event),\n message: redactSensitiveText(resolvedMessage),\n runtimeId: context.runtimeId ?? null,\n operationId: context.operationId ?? null,\n correlationId: resolveCorrelationId(context),\n ...(context.worktree ? { worktree: redactSensitiveText(context.worktree) } : {}),\n ...(typeof context.chatId === \"number\" ? { chatId: context.chatId } : {}),\n ...(context.sessionId ? { sessionId: context.sessionId } : {}),\n ...(context.projectId ? { projectId: context.projectId } : {}),\n ...(context.requestId ? { requestId: context.requestId } : {}),\n ...(typeof context.updateId === \"number\" ? { updateId: context.updateId } : {}),\n ...(context.command ? { command: context.command } : {}),\n ...(context.callbackData ? { callbackData: context.callbackData } : {}),\n ...(typeof context.durationMs === \"number\" ? { durationMs: context.durationMs } : {}),\n ...(typeof context.attempt === \"number\" ? { attempt: context.attempt } : {}),\n ...(context.status ? { status: context.status } : {}),\n ...(typeof context.sizeBytes === \"number\" ? { sizeBytes: context.sizeBytes } : {}),\n ...(context.error ? { error: context.error } : {}),\n ...removeUndefinedFields(extracted.extra),\n };\n}\n\nfunction buildHostLogExtra(event: StructuredLogEvent): Record<string, unknown> {\n const {\n service: _service,\n level: _level,\n message: _message,\n ...rest\n } = event;\n\n return rest;\n}\n\nfunction extractContextAndExtra(input: unknown): {\n context: LoggerContext;\n extra: Record<string, unknown>;\n} {\n if (input instanceof Error) {\n return {\n context: {\n error: serializeError(input),\n },\n extra: {},\n };\n }\n\n if (Array.isArray(input)) {\n return {\n context: {},\n extra: {\n items: input.map((item) => sanitizeValue(item)),\n },\n };\n }\n\n if (input === null || input === undefined) {\n return {\n context: {},\n extra: {},\n };\n }\n\n if (typeof input === \"string\") {\n return {\n context: {},\n extra: {},\n };\n }\n\n if (typeof input !== \"object\") {\n return {\n context: {},\n extra: {\n value: sanitizeValue(input),\n },\n };\n }\n\n const record = input as Record<string, unknown>;\n const context: LoggerContext = {};\n const extra: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(record)) {\n if (RESERVED_EVENT_FIELDS.has(key)) {\n assignReservedField(context, key, value);\n continue;\n }\n\n extra[key] = sanitizeFieldValue(key, value);\n }\n\n return {\n context,\n extra,\n };\n}\n\nfunction assignReservedField(context: LoggerContext, key: string, value: unknown): void {\n switch (key) {\n case \"attempt\":\n case \"durationMs\":\n case \"sizeBytes\":\n if (typeof value === \"number\") {\n context[key] = value;\n }\n return;\n case \"chatId\":\n case \"updateId\":\n if (typeof value === \"number\") {\n context[key] = value;\n }\n return;\n case \"callbackData\":\n case \"command\":\n case \"component\":\n case \"event\":\n case \"projectId\":\n case \"requestId\":\n case \"sessionId\":\n case \"status\":\n case \"worktree\":\n if (typeof value === \"string\" && value.trim().length > 0) {\n context[key] = redactSensitiveText(value.trim()) as never;\n }\n return;\n case \"correlationId\":\n case \"operationId\":\n case \"runtimeId\":\n if (typeof value === \"string\" && value.trim().length > 0) {\n context[key] = value.trim();\n } else if (value === null) {\n context[key] = null;\n }\n return;\n case \"error\":\n if (value instanceof Error) {\n context.error = serializeError(value);\n } else if (isPlainObject(value)) {\n context.error = normalizeStructuredLogErrorRecord(value);\n }\n return;\n default:\n return;\n }\n}\n\nfunction normalizeLogMessage(input: unknown, message?: string): string {\n if (typeof input === \"string\") {\n const normalizedInput = input.trim();\n\n return normalizedInput.length > 0\n ? normalizedInput\n : \"log\";\n }\n\n if (message && message.trim().length > 0) {\n return message.trim();\n }\n\n if (input instanceof Error) {\n return input.message.trim() || input.name;\n }\n\n return \"log\";\n}\n\nfunction normalizeServiceName(value: string | undefined): string {\n const normalized = value?.trim();\n\n return normalized && normalized.length > 0\n ? normalized\n : DEFAULT_SERVICE_NAME;\n}\n\nfunction normalizeLogLevel(value: string | null | undefined): AppLogLevel {\n switch (value?.trim().toLowerCase()) {\n case \"debug\":\n return \"debug\";\n case \"warn\":\n return \"warn\";\n case \"error\":\n return \"error\";\n default:\n return \"info\";\n }\n}\n\nfunction normalizeComponent(value: string | undefined): string {\n const normalized = value?.trim();\n\n return normalized && normalized.length > 0\n ? normalized\n : DEFAULT_COMPONENT;\n}\n\nfunction normalizeEventName(value: string | undefined): string {\n const normalized = value?.trim();\n\n return normalized && normalized.length > 0\n ? normalized\n : DEFAULT_EVENT;\n}\n\nfunction resolveCorrelationId(context: LoggerContext): string | null {\n if (context.correlationId) {\n return context.correlationId;\n }\n\n if (typeof context.updateId === \"number\") {\n return String(context.updateId);\n }\n\n return context.operationId ?? null;\n}\n\nfunction serializeError(error: Error): StructuredLogError {\n return {\n name: error.name,\n message: redactSensitiveText(error.message),\n ...(error.stack ? { stack: redactSensitiveText(error.stack) } : {}),\n ...(\"data\" in error && error.data && typeof error.data === \"object\"\n ? { data: sanitizeValue(error.data) }\n : {}),\n };\n}\n\nfunction sanitizePlainObject(value: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n sanitizeFieldValue(key, entryValue),\n ]),\n );\n}\n\nfunction sanitizeFieldValue(key: string, value: unknown): unknown {\n if (isSensitiveKey(key)) {\n return redactSensitiveFieldValue(value);\n }\n\n if (isUrlLikeKey(key)) {\n return summarizeUrlValue(value);\n }\n\n if (isTextContentKey(key)) {\n return summarizeTextValue(value);\n }\n\n if (isAttachmentCollectionKey(key)) {\n return summarizeAttachmentCollection(value);\n }\n\n return sanitizeValue(value);\n}\n\nfunction sanitizeValue(value: unknown): unknown {\n if (value instanceof Error) {\n return serializeError(value);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => sanitizeValue(entry));\n }\n\n if (typeof value === \"string\") {\n return redactSensitiveText(value);\n }\n\n if (!value || typeof value !== \"object\") {\n return value;\n }\n\n return sanitizePlainObject(value as Record<string, unknown>);\n}\n\nfunction summarizeTextValue(value: unknown): unknown {\n if (typeof value === \"string\") {\n return {\n omitted: CONTENT_OMITTED,\n length: value.length,\n };\n }\n\n if (Array.isArray(value)) {\n return {\n omitted: CONTENT_OMITTED,\n count: value.length,\n };\n }\n\n if (value && typeof value === \"object\") {\n return {\n omitted: CONTENT_OMITTED,\n kind: \"object\",\n };\n }\n\n return value;\n}\n\nfunction summarizeUrlValue(value: unknown): unknown {\n if (typeof value === \"string\" && value.trim().length > 0) {\n return {\n omitted: CONTENT_OMITTED,\n kind: \"url\",\n };\n }\n\n return sanitizeValue(value);\n}\n\nfunction summarizeAttachmentCollection(value: unknown): unknown {\n if (!Array.isArray(value)) {\n return summarizeTextValue(value);\n }\n\n return {\n count: value.length,\n items: value.map((entry) => summarizeAttachmentValue(entry)),\n };\n}\n\nfunction summarizeAttachmentValue(value: unknown): unknown {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return summarizeTextValue(value);\n }\n\n const record = value as Record<string, unknown>;\n\n return removeUndefinedFields({\n filename: normalizeString(record.filename) ?? normalizeString(record.fileName) ?? undefined,\n mime: normalizeString(record.mime) ?? normalizeString(record.mimeType) ?? undefined,\n sizeBytes: pickNumericValue(record, [\"sizeBytes\", \"size\", \"fileSize\"]),\n hasCaption: pickStringValue(record, [\"caption\"]) !== null,\n textLength: pickStringValue(record, [\"text\", \"prompt\"])?.length,\n type: normalizeString(record.type) ?? undefined,\n });\n}\n\nfunction isSensitiveKey(key: string): boolean {\n return /token|secret|api[-_]?key|authorization|password|cookie/iu.test(key);\n}\n\nfunction isTextContentKey(key: string): boolean {\n return /(^|[-_])(text|prompt|caption|body|markdown|content|messageText|fallbackText|input|raw)$/iu.test(key)\n || /bodyMd|bodyText|messageText|fallbackText/iu.test(key);\n}\n\nfunction isUrlLikeKey(key: string): boolean {\n return /(^|[-_])(url|uri|href|filePath|downloadPath|downloadUrl|fileUrl)$/iu.test(key);\n}\n\nfunction isAttachmentCollectionKey(key: string): boolean {\n return /(^|[-_])(files|parts|attachments)$/iu.test(key);\n}\n\nfunction redactSensitiveFieldValue(value: unknown): unknown {\n if (typeof value === \"string\" && value.trim().length > 0) {\n return REDACTED;\n }\n\n if (Array.isArray(value)) {\n return value.map(() => REDACTED);\n }\n\n if (value && typeof value === \"object\") {\n return REDACTED;\n }\n\n return value;\n}\n\nfunction removeUndefinedFields<TRecord extends object>(record: TRecord): TRecord {\n return Object.fromEntries(\n Object.entries(record).filter(([, value]) => value !== undefined),\n ) as TRecord;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction normalizeString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim().length > 0\n ? redactSensitiveText(value.trim())\n : null;\n}\n\nfunction pickNumericValue(record: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = record[key];\n\n if (typeof value === \"number\") {\n return value;\n }\n }\n\n return undefined;\n}\n\nfunction pickStringValue(record: Record<string, unknown>, keys: string[]): string | null {\n for (const key of keys) {\n const value = record[key];\n\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n }\n\n return null;\n}\n\nfunction sanitizeFileSegment(value: string): string {\n return value.replace(/[^a-z0-9._-]+/giu, \"_\");\n}\n\nfunction normalizeStructuredLogErrorRecord(value: Record<string, unknown>): StructuredLogError {\n return {\n name: normalizeString(value.name) ?? \"Error\",\n message: normalizeString(value.message) ?? \"Unknown error\",\n ...(typeof value.stack === \"string\" ? { stack: redactSensitiveText(value.stack) } : {}),\n ...(value.data !== undefined ? { data: sanitizeValue(value.data) } : {}),\n };\n}\n","import type { PendingChatAction } from \"../domain/pending-action/pending-action.entity.js\";\nimport type { PendingActionRepository } from \"../domain/pending-action/pending-action.repository.js\";\nimport type { OpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport type { JsonStateStore } from \"../services/storage/json-state-store.js\";\n\nexport class InMemoryPendingActionRepository implements PendingActionRepository {\n private readonly actionsByChatId = new Map<number, PendingChatAction>();\n\n async getByChatId(chatId: number): Promise<PendingChatAction | null> {\n return this.actionsByChatId.get(chatId) ?? null;\n }\n\n async set(action: PendingChatAction): Promise<void> {\n this.actionsByChatId.set(action.chatId, action);\n }\n\n async clear(chatId: number): Promise<void> {\n this.actionsByChatId.delete(chatId);\n }\n}\n\nexport class FilePendingActionRepository implements PendingActionRepository {\n constructor(private readonly store: JsonStateStore<OpencodeTbotState>) { }\n\n async getByChatId(chatId: number): Promise<PendingChatAction | null> {\n const state = await this.store.read();\n\n return state.pendingActions[String(chatId)] ?? null;\n }\n\n async set(action: PendingChatAction): Promise<void> {\n await this.store.update((state) => {\n state.pendingActions[String(action.chatId)] = action;\n });\n }\n\n async clear(chatId: number): Promise<void> {\n await this.store.update((state) => {\n delete state.pendingActions[String(chatId)];\n });\n }\n}\n","import type { PendingPermissionApproval } from \"../domain/permission/approval.entity.js\";\nimport type { PermissionApprovalRepository } from \"../domain/permission/approval.repository.js\";\nimport type { OpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport type { JsonStateStore } from \"../services/storage/json-state-store.js\";\n\nfunction buildApprovalKey(requestId: string, chatId: number): string {\n return `${requestId}:${chatId}`;\n}\n\nexport class InMemoryPermissionApprovalRepository implements PermissionApprovalRepository {\n private readonly approvalsByKey = new Map<string, PendingPermissionApproval>();\n\n async listByRequestId(requestId: string): Promise<PendingPermissionApproval[]> {\n return [...this.approvalsByKey.values()].filter((approval) => approval.requestId === requestId);\n }\n\n async set(approval: PendingPermissionApproval): Promise<void> {\n this.approvalsByKey.set(buildApprovalKey(approval.requestId, approval.chatId), approval);\n }\n}\n\nexport class FilePermissionApprovalRepository implements PermissionApprovalRepository {\n constructor(private readonly store: JsonStateStore<OpencodeTbotState>) { }\n\n async listByRequestId(requestId: string): Promise<PendingPermissionApproval[]> {\n const state = await this.store.read();\n\n return Object.values(state.pendingPermissions).filter((approval) => approval.requestId === requestId);\n }\n\n async set(approval: PendingPermissionApproval): Promise<void> {\n await this.store.update((state) => {\n state.pendingPermissions[buildApprovalKey(approval.requestId, approval.chatId)] = approval;\n });\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { OpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport type { JsonStateStore } from \"../services/storage/json-state-store.js\";\n\nexport class InMemorySessionRepository implements SessionRepository {\n private readonly sessionsByChatId = new Map<number, ChatSessionBinding>();\n\n async getByChatId(chatId: number): Promise<ChatSessionBinding | null> {\n return this.sessionsByChatId.get(chatId) ?? null;\n }\n\n async listBySessionId(sessionId: string): Promise<ChatSessionBinding[]> {\n return [...this.sessionsByChatId.values()].filter((binding) => binding.sessionId === sessionId);\n }\n\n async setCurrent(binding: ChatSessionBinding): Promise<void> {\n this.sessionsByChatId.set(binding.chatId, binding);\n }\n\n async touch(chatId: number): Promise<void> {\n const binding = this.sessionsByChatId.get(chatId);\n\n if (!binding) {\n return;\n }\n\n this.sessionsByChatId.set(chatId, {\n ...binding,\n updatedAt: new Date().toISOString(),\n });\n }\n}\n\nexport class FileSessionRepository implements SessionRepository {\n constructor(private readonly store: JsonStateStore<OpencodeTbotState>) { }\n\n async getByChatId(chatId: number): Promise<ChatSessionBinding | null> {\n const state = await this.store.read();\n\n return state.sessions[String(chatId)] ?? null;\n }\n\n async listBySessionId(sessionId: string): Promise<ChatSessionBinding[]> {\n const state = await this.store.read();\n\n return Object.values(state.sessions).filter((binding) => binding.sessionId === sessionId);\n }\n\n async setCurrent(binding: ChatSessionBinding): Promise<void> {\n await this.store.update((state) => {\n state.sessions[String(binding.chatId)] = binding;\n });\n }\n\n async touch(chatId: number): Promise<void> {\n await this.store.update((state) => {\n const current = state.sessions[String(chatId)];\n\n if (!current) {\n return;\n }\n\n state.sessions[String(chatId)] = {\n ...current,\n updatedAt: new Date().toISOString(),\n };\n });\n }\n}\n","const HTML_TAG_PATTERN = /<\\/?[A-Za-z][^>]*>/g;\n\nexport function stripMarkdownToPlainText(markdown: string): string {\n const normalizedMarkdown = preprocessMarkdownForPlainText(markdown);\n const lines = normalizedMarkdown.split(\"\\n\");\n const rendered: string[] = [];\n\n for (let index = 0; index < lines.length; index += 1) {\n const tableBlock = consumeMarkdownTable(lines, index);\n\n if (tableBlock) {\n rendered.push(renderTableAsPlainText(tableBlock.rows));\n index = tableBlock.nextIndex - 1;\n continue;\n }\n\n rendered.push(lines[index] ?? \"\");\n }\n\n return rendered\n .join(\"\\n\")\n .replace(/```[A-Za-z0-9_-]*\\n?/g, \"\")\n .replace(/```/g, \"\")\n .replace(/^#{1,6}\\s+/gm, \"\")\n .replace(/^\\s*>\\s?/gm, \"\")\n .replace(/^(\\s*)[-+*]\\s+/gm, \"$1- \")\n .replace(/^(\\s*)(\\d+)[.)]\\s+/gm, \"$1$2. \")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1 ($2)\")\n .replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\")\n .replace(/(\\*|_)(.*?)\\1/g, \"$2\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(HTML_TAG_PATTERN, \"\")\n .trim();\n}\n\ninterface ConsumedTable {\n nextIndex: number;\n rows: string[][];\n}\n\nfunction preprocessMarkdownForPlainText(markdown: string): string {\n const normalizedMarkdown = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalizedMarkdown.split(\"\\n\");\n const processed: string[] = [];\n let activeFence: \"markdown\" | \"plain\" | null = null;\n\n for (const line of lines) {\n const fenceMatch = line.match(/^```([A-Za-z0-9_-]+)?\\s*$/);\n\n if (fenceMatch) {\n const language = (fenceMatch[1] ?? \"\").toLowerCase();\n\n if (activeFence === \"markdown\") {\n activeFence = null;\n continue;\n }\n\n if (activeFence === \"plain\") {\n processed.push(line);\n activeFence = null;\n continue;\n }\n\n if (language === \"md\" || language === \"markdown\") {\n activeFence = \"markdown\";\n continue;\n }\n\n activeFence = \"plain\";\n processed.push(line);\n continue;\n }\n\n processed.push(line);\n }\n\n return processed.join(\"\\n\");\n}\n\nfunction consumeMarkdownTable(lines: string[], startIndex: number): ConsumedTable | null {\n if (startIndex + 1 >= lines.length) {\n return null;\n }\n\n const headerCells = parseMarkdownTableRow(lines[startIndex] ?? \"\");\n const separatorCells = parseMarkdownTableSeparator(lines[startIndex + 1] ?? \"\");\n\n if (!headerCells || !separatorCells || headerCells.length !== separatorCells.length) {\n return null;\n }\n\n const rows = [headerCells];\n let index = startIndex + 2;\n\n while (index < lines.length) {\n const rowCells = parseMarkdownTableRow(lines[index] ?? \"\");\n\n if (!rowCells || rowCells.length !== headerCells.length) {\n break;\n }\n\n rows.push(rowCells);\n index += 1;\n }\n\n return {\n rows,\n nextIndex: index,\n };\n}\n\nfunction parseMarkdownTableRow(line: string): string[] | null {\n const trimmed = line.trim();\n\n if (!trimmed.includes(\"|\")) {\n return null;\n }\n\n const cells = splitMarkdownTableCells(trimmed)\n .map((cell) => normalizeTableCell(cell));\n\n return cells.length >= 2 ? cells : null;\n}\n\nfunction parseMarkdownTableSeparator(line: string): string[] | null {\n const cells = splitMarkdownTableCells(line.trim());\n\n if (cells.length < 2) {\n return null;\n }\n\n return cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()))\n ? cells\n : null;\n}\n\nfunction splitMarkdownTableCells(line: string): string[] {\n const content = line\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\");\n const cells: string[] = [];\n let current = \"\";\n let escaped = false;\n\n for (const char of content) {\n if (escaped) {\n current += char;\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n escaped = true;\n current += char;\n continue;\n }\n\n if (char === \"|\") {\n cells.push(current);\n current = \"\";\n continue;\n }\n\n current += char;\n }\n\n cells.push(current);\n return cells;\n}\n\nfunction normalizeTableCell(cell: string): string {\n return cell\n .trim()\n .replace(/\\\\\\|/g, \"|\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1 ($2)\")\n .replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\")\n .replace(/(\\*|_)(.*?)\\1/g, \"$2\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(HTML_TAG_PATTERN, \"\");\n}\n\nfunction renderTableAsPlainText(rows: string[][]): string {\n return buildAlignedTableLines(rows).join(\"\\n\");\n}\n\nfunction buildAlignedTableLines(rows: string[][]): string[] {\n const columnWidths = calculateTableColumnWidths(rows);\n const header = formatTableRow(rows[0] ?? [], columnWidths);\n const separator = columnWidths.map((width) => \"-\".repeat(Math.max(3, width))).join(\"-+-\");\n const body = rows.slice(1).map((row) => formatTableRow(row, columnWidths));\n\n return [header, separator, ...body];\n}\n\nfunction calculateTableColumnWidths(rows: string[][]): number[] {\n return (rows[0] ?? []).map((_, columnIndex) =>\n rows.reduce((maxWidth, row) => Math.max(maxWidth, getDisplayWidth(row[columnIndex] ?? \"\")), 0),\n );\n}\n\nfunction formatTableRow(row: string[], columnWidths: number[]): string {\n return row\n .map((cell, index) => padDisplayWidth(cell, columnWidths[index] ?? 0))\n .join(\" | \");\n}\n\nfunction padDisplayWidth(value: string, targetWidth: number): string {\n const padding = Math.max(0, targetWidth - getDisplayWidth(value));\n\n return `${value}${\" \".repeat(padding)}`;\n}\n\nfunction getDisplayWidth(value: string): number {\n let width = 0;\n\n for (const char of value) {\n width += isWideCharacter(char.codePointAt(0) ?? 0) ? 2 : 1;\n }\n\n return width;\n}\n\nfunction isWideCharacter(codePoint: number): boolean {\n return codePoint >= 0x1100 && (\n codePoint <= 0x115f ||\n codePoint === 0x2329 ||\n codePoint === 0x232a ||\n (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||\n (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||\n (codePoint >= 0xf900 && codePoint <= 0xfaff) ||\n (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||\n (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||\n (codePoint >= 0xff00 && codePoint <= 0xff60) ||\n (codePoint >= 0xffe0 && codePoint <= 0xffe6)\n );\n}\n","import {\n createOpencodeClient,\n type OpencodeClient,\n} from \"@opencode-ai/sdk\";\nimport type {\n Agent,\n Config,\n LspStatus,\n McpStatus,\n Model,\n OutputFormat,\n Part,\n Path,\n Provider,\n Project,\n Session,\n SessionStatus,\n} from \"@opencode-ai/sdk/v2/client\";\nimport { stripMarkdownToPlainText } from \"../../infra/utils/markdown-text.js\";\n\nexport interface OpenCodeClientOptions {\n baseUrl: string;\n apiKey?: string;\n}\n\nexport interface OpenCodePromptTimeoutPolicy {\n pollRequestTimeoutMs: number;\n recoveryInactivityTimeoutMs: number;\n waitTimeoutMs: number;\n}\n\nexport function buildOpenCodeSdkConfig(options: OpenCodeClientOptions) {\n const apiKey = options.apiKey?.trim();\n\n return {\n baseUrl: options.baseUrl,\n ...(apiKey ? { auth: apiKey } : {}),\n };\n}\n\nexport interface PromptSessionInput {\n sessionId: string;\n prompt?: string | null;\n agent?: string | null;\n format?: OpenCodeTextOutputFormat;\n signal?: AbortSignal;\n model?: {\n providerID: string;\n modelID: string;\n };\n variant?: string | null;\n files?: PromptSessionFilePartInput[];\n}\n\nexport interface PromptSessionFilePartInput {\n filename?: string;\n mime: string;\n url: string;\n}\n\nexport interface PromptSessionTokenMetrics {\n total: number | null;\n input: number | null;\n output: number | null;\n reasoning: number | null;\n cacheRead: number | null;\n cacheWrite: number | null;\n}\n\nexport interface PromptSessionMetrics {\n durationMs: number | null;\n tokens: PromptSessionTokenMetrics;\n}\n\nexport interface PromptSessionResult {\n assistantError: OpenCodeAssistantError | null;\n bodyMd: string | null;\n fallbackText: string;\n info: OpenCodeAssistantMessage | null;\n metrics: PromptSessionMetrics;\n parts: Part[];\n structured: unknown;\n}\n\nexport type OpenCodeProject = Project;\nexport type OpenCodeSession = Session;\nexport type OpenCodeModel = Model;\nexport type OpenCodeProvider = Provider;\nexport type OpenCodeConfig = Config;\nexport type OpenCodeAgent = Agent;\nexport type OpenCodeLspStatus = LspStatus;\nexport type OpenCodePath = Path;\nexport type OpenCodeMcpStatus = McpStatus;\nexport type OpenCodeSessionStatus = SessionStatus;\nexport interface OpenCodePermissionRequest {\n always: string[];\n id: string;\n metadata: Record<string, unknown>;\n patterns: string[];\n permission: string;\n sessionID: string;\n}\nexport interface OpenCodeHealth {\n healthy: boolean;\n version: string;\n}\n\nexport interface OpenCodeConfiguredModel {\n id: string;\n providerID: string;\n providerName: string;\n name: string;\n qualifiedId: string;\n reasoning: boolean;\n variants: Record<string, Record<string, unknown>>;\n}\nexport type OpenCodeTextOutputFormat = Extract<OutputFormat, { type: \"text\" }>;\n\ntype RawSdkRequestOptions = {\n responseStyle?: \"data\" | \"fields\";\n signal?: AbortSignal;\n throwOnError?: boolean;\n url: string;\n};\n\ntype RawSdkRequestClient = {\n get?(options: RawSdkRequestOptions): Promise<unknown>;\n};\n\ntype OpenCodeSdkPermissionScopeLike = {\n list?(parameters?: unknown, options?: Record<string, unknown>): Promise<unknown>;\n reply?(parameters?: unknown, options?: Record<string, unknown>): Promise<unknown>;\n};\n\ntype OpenCodeSdkScopedClientLike = Pick<OpencodeClient, \"app\" | \"config\" | \"global\" | \"lsp\" | \"mcp\" | \"path\" | \"project\" | \"session\"> & {\n permission?: OpenCodeSdkPermissionScopeLike;\n};\n\ntype OpenCodeSdkPermissionReplyClientLike = {\n postSessionIdPermissionsPermissionId?(options: Record<string, unknown>): Promise<unknown>;\n};\n\nexport type OpenCodeSdkClientLike = OpenCodeSdkScopedClientLike & OpenCodeSdkPermissionReplyClientLike;\n\ntype OpenCodeSdkClientWithRawRequestClient = OpenCodeSdkClientLike & {\n _client?: RawSdkRequestClient;\n client?: RawSdkRequestClient;\n};\ntype MaybeWrappedResponse<T> = T | { data: T };\ntype ScopedSdkScope = \"app\" | \"config\" | \"global\" | \"lsp\" | \"mcp\" | \"path\" | \"permission\" | \"project\" | \"session\";\ntype ScopedSdkInvocationInput = {\n legacyParameters?: unknown;\n parameters?: Record<string, unknown>;\n signal?: AbortSignal;\n};\ntype OpenCodeProviderCatalog = {\n providers: OpenCodeProvider[];\n default: Record<string, string>;\n};\ntype OpenCodeProviderAvailability = Map<string, Set<string> | null>;\ntype OpenCodeProviderConfig = NonNullable<OpenCodeConfig[\"provider\"]>[string];\ntype OpenCodeModelConfig = NonNullable<OpenCodeProviderConfig[\"models\"]>[string];\ntype OpenCodePromptResponse = {\n info: unknown;\n parts?: Part[] | null;\n};\n\nexport type OpenCodePromptTimeoutStage =\n | \"capture-known-messages\"\n | \"send-prompt\"\n | \"poll-message\"\n | \"poll-messages\"\n | \"poll-status\"\n | \"final-scan\";\n\nexport interface OpenCodePromptTimeoutErrorData {\n elapsedMs: number;\n message?: string;\n messageId?: string;\n sessionId: string;\n stage: OpenCodePromptTimeoutStage;\n timeoutMs: number;\n}\n\nexport class OpenCodePromptTimeoutError extends Error {\n readonly data: OpenCodePromptTimeoutErrorData;\n\n constructor(data: OpenCodePromptTimeoutErrorData) {\n super(data.message ?? \"OpenCode prompt timed out.\");\n this.name = \"OpenCodePromptTimeoutError\";\n this.data = data;\n }\n}\n\nexport class OpenCodeMessageAbortedError extends Error {\n readonly data?: {\n message?: string;\n };\n\n constructor(message = \"Request was aborted.\") {\n super(message);\n this.name = \"MessageAbortedError\";\n this.data = {\n message,\n };\n }\n}\n\nexport function createMessageAbortedError(message = \"Request was aborted.\"): OpenCodeMessageAbortedError {\n return new OpenCodeMessageAbortedError(message);\n}\n\nexport interface OpenCodeAssistantError {\n data?: Record<string, unknown>;\n name: string;\n [key: string]: unknown;\n}\n\nexport interface OpenCodeAssistantMessage {\n agent?: string;\n cost?: number;\n error?: OpenCodeAssistantError;\n finish?: string;\n id?: string;\n mode?: string;\n modelID?: string;\n parentID?: string;\n path?: {\n cwd?: string;\n root?: string;\n };\n providerID?: string;\n role?: \"assistant\";\n sessionID?: string;\n summary?: boolean;\n time?: {\n completed?: number;\n created?: number;\n };\n tokens?: {\n cache?: {\n read?: number;\n write?: number;\n };\n input?: number;\n output?: number;\n reasoning?: number;\n total?: number;\n };\n variant?: string;\n}\n\nconst EMPTY_RESPONSE_TEXT = \"OpenCode returned empty response.\";\nconst PROMPT_MESSAGE_POLL_INITIAL_DELAYS_MS = [0, 100, 250, 500, 1000];\nconst PROMPT_MESSAGE_POLL_INTERVAL_MS = 2000;\nconst PROMPT_MESSAGE_POLL_LIMIT = 20;\nconst PROMPT_LOG_SERVICE = \"opencode-tbot\";\nconst DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY: OpenCodePromptTimeoutPolicy = {\n pollRequestTimeoutMs: 15_000,\n recoveryInactivityTimeoutMs: 120_000,\n waitTimeoutMs: 1_800_000,\n};\nconst SDK_OPTIONS = {\n responseStyle: \"data\" as const,\n throwOnError: true as const,\n};\nconst TEXT_OUTPUT_FORMAT: OpenCodeTextOutputFormat = {\n type: \"text\",\n};\n\nexport interface OpenCodeClientLike {\n readonly client?: OpenCodeSdkClientLike;\n abortSession(sessionId: string): Promise<boolean>;\n deleteSession(sessionId: string): Promise<boolean>;\n forkSession(sessionId: string, messageId?: string): Promise<OpenCodeSession>;\n getHealth(): Promise<OpenCodeHealth>;\n getPath(): Promise<OpenCodePath>;\n listLspStatuses(directory?: string): Promise<OpenCodeLspStatus[]>;\n listMcpStatuses(directory?: string): Promise<Record<string, OpenCodeMcpStatus>>;\n getSessionStatuses(): Promise<Record<string, OpenCodeSessionStatus>>;\n listProjects(): Promise<OpenCodeProject[]>;\n listSessions(): Promise<OpenCodeSession[]>;\n getCurrentProject(): Promise<OpenCodeProject>;\n createSessionForDirectory(directory: string, title?: string): Promise<OpenCodeSession>;\n renameSession(sessionId: string, title: string): Promise<OpenCodeSession>;\n listAgents(): Promise<OpenCodeAgent[]>;\n listPendingPermissions(directory?: string): Promise<OpenCodePermissionRequest[]>;\n replyToPermission(\n requestId: string,\n reply: \"once\" | \"always\" | \"reject\",\n message?: string,\n sessionId?: string,\n ): Promise<boolean>;\n listConfiguredPlugins?(): Promise<string[]>;\n listModels(): Promise<OpenCodeConfiguredModel[]>;\n promptSession(input: PromptSessionInput): Promise<PromptSessionResult>;\n}\n\nexport class OpenCodeClient implements OpenCodeClientLike {\n readonly client: OpenCodeSdkClientLike;\n private readonly fetchFn: typeof fetch;\n private promptTimeoutPolicy: OpenCodePromptTimeoutPolicy;\n private modelCache: {\n expiresAt: number;\n promise: Promise<OpenCodeConfiguredModel[]> | null;\n value: OpenCodeConfiguredModel[] | null;\n } = {\n expiresAt: 0,\n promise: null,\n value: null,\n };\n\n constructor(\n options?: OpenCodeClientOptions,\n client?: OpenCodeSdkClientLike,\n fetchFn: typeof fetch = fetch,\n promptTimeoutPolicy: Partial<OpenCodePromptTimeoutPolicy> = {},\n ) {\n if (!options && !client) {\n throw new Error(\"OpenCodeClient requires either base URL options or an injected SDK client.\");\n }\n\n this.client = client ?? createOpencodeClient(buildOpenCodeSdkConfig(options as OpenCodeClientOptions));\n this.fetchFn = fetchFn;\n this.promptTimeoutPolicy = resolvePromptTimeoutPolicy(promptTimeoutPolicy);\n }\n\n configurePromptTimeoutPolicy(\n promptTimeoutPolicy: Partial<OpenCodePromptTimeoutPolicy>,\n ): void {\n this.promptTimeoutPolicy = resolvePromptTimeoutPolicy({\n ...this.promptTimeoutPolicy,\n ...promptTimeoutPolicy,\n });\n }\n\n private async callScopedSdkMethod<T>(\n scope: ScopedSdkScope,\n method: string,\n input: ScopedSdkInvocationInput,\n ): Promise<T> {\n const target = this.client[scope] as unknown as Record<string, unknown> | undefined;\n const handler = target?.[method];\n\n if (typeof handler !== \"function\") {\n throw new Error(`OpenCode SDK client does not expose a compatible ${scope}.${method} method.`);\n }\n\n const options = {\n ...SDK_OPTIONS,\n ...(input.signal ? { signal: input.signal } : {}),\n };\n const response = handler.length >= 2\n ? await (handler as (parameters: unknown, requestOptions: Record<string, unknown>) => Promise<MaybeWrappedResponse<T>>).call(\n target,\n input.legacyParameters,\n options,\n )\n : await (handler as (requestOptions: Record<string, unknown>) => Promise<MaybeWrappedResponse<T>>).call(\n target,\n input.parameters === undefined\n ? options\n : {\n ...input.parameters,\n ...options,\n },\n );\n\n return unwrapSdkData(response);\n }\n\n async getHealth(): Promise<OpenCodeHealth> {\n try {\n return await this.callScopedSdkMethod<OpenCodeHealth>(\"global\", \"health\", {});\n } catch (error) {\n if (!isMissingScopedSdkMethodError(error, \"global\", \"health\")) {\n throw error;\n }\n\n return this.callRawSdkGet<OpenCodeHealth>(\"/global/health\");\n }\n }\n\n async abortSession(sessionId: string): Promise<boolean> {\n return this.callScopedSdkMethod<boolean>(\"session\", \"abort\", {\n legacyParameters: {\n sessionID: sessionId,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n },\n });\n }\n\n async deleteSession(sessionId: string): Promise<boolean> {\n return this.callScopedSdkMethod<boolean>(\"session\", \"delete\", {\n legacyParameters: {\n sessionID: sessionId,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n },\n });\n }\n\n async forkSession(sessionId: string, messageId?: string): Promise<OpenCodeSession> {\n return this.callScopedSdkMethod<OpenCodeSession>(\"session\", \"fork\", {\n legacyParameters: {\n sessionID: sessionId,\n ...(messageId?.trim()\n ? { messageID: messageId.trim() }\n : {}),\n },\n parameters: {\n path: {\n id: sessionId,\n },\n ...(\n messageId?.trim()\n ? {\n body: {\n messageID: messageId.trim(),\n },\n }\n : {}\n ),\n },\n });\n }\n\n async getPath(): Promise<OpenCodePath> {\n return this.callScopedSdkMethod<OpenCodePath>(\"path\", \"get\", {});\n }\n\n async listLspStatuses(directory?: string): Promise<OpenCodeLspStatus[]> {\n return this.callScopedSdkMethod<OpenCodeLspStatus[]>(\"lsp\", \"status\", {\n legacyParameters: directory\n ? { directory }\n : undefined,\n parameters: directory\n ? {\n query: {\n directory,\n },\n }\n : undefined,\n });\n }\n\n async listMcpStatuses(directory?: string): Promise<Record<string, OpenCodeMcpStatus>> {\n return this.callScopedSdkMethod<Record<string, OpenCodeMcpStatus>>(\"mcp\", \"status\", {\n legacyParameters: directory\n ? { directory }\n : undefined,\n parameters: directory\n ? {\n query: {\n directory,\n },\n }\n : undefined,\n });\n }\n\n async getSessionStatuses(): Promise<Record<string, OpenCodeSessionStatus>> {\n return this.loadSessionStatuses();\n }\n\n async listProjects(): Promise<OpenCodeProject[]> {\n return this.callScopedSdkMethod<OpenCodeProject[]>(\"project\", \"list\", {});\n }\n\n async listSessions(): Promise<OpenCodeSession[]> {\n return this.callScopedSdkMethod<OpenCodeSession[]>(\"session\", \"list\", {});\n }\n\n async getCurrentProject(): Promise<OpenCodeProject> {\n return this.callScopedSdkMethod<OpenCodeProject>(\"project\", \"current\", {});\n }\n\n async createSessionForDirectory(directory: string, title?: string): Promise<OpenCodeSession> {\n return this.callScopedSdkMethod<OpenCodeSession>(\"session\", \"create\", {\n legacyParameters: title ? { directory, title } : { directory },\n parameters: {\n query: {\n directory,\n },\n ...(title\n ? {\n body: {\n title,\n },\n }\n : {}),\n },\n });\n }\n\n async renameSession(sessionId: string, title: string): Promise<OpenCodeSession> {\n return this.callScopedSdkMethod<OpenCodeSession>(\"session\", \"update\", {\n legacyParameters: {\n sessionID: sessionId,\n title,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n body: {\n title,\n },\n },\n });\n }\n\n async listAgents(): Promise<OpenCodeAgent[]> {\n return this.callScopedSdkMethod<OpenCodeAgent[]>(\"app\", \"agents\", {});\n }\n\n async listPendingPermissions(directory?: string): Promise<OpenCodePermissionRequest[]> {\n const permissions = await this.callScopedSdkMethod<unknown[]>(\"permission\", \"list\", {\n legacyParameters: directory\n ? { directory }\n : undefined,\n parameters: directory\n ? {\n query: {\n directory,\n },\n }\n : undefined,\n });\n\n return permissions.map(normalizePermissionRequest).filter((permission): permission is OpenCodePermissionRequest => !!permission);\n }\n\n async replyToPermission(\n requestId: string,\n reply: \"once\" | \"always\" | \"reject\",\n message?: string,\n sessionId?: string,\n ): Promise<boolean> {\n const normalizedMessage = message?.trim();\n const rootPermissionHandler = this.client.postSessionIdPermissionsPermissionId;\n\n if (sessionId && typeof rootPermissionHandler === \"function\") {\n return unwrapSdkData(await rootPermissionHandler.call(this.client, {\n ...SDK_OPTIONS,\n body: {\n response: reply,\n ...(normalizedMessage\n ? { message: normalizedMessage }\n : {}),\n },\n path: {\n id: sessionId,\n permissionID: requestId,\n },\n }) as MaybeWrappedResponse<boolean>);\n }\n\n return this.callScopedSdkMethod<boolean>(\"permission\", \"reply\", {\n legacyParameters: {\n requestID: requestId,\n reply,\n ...(normalizedMessage\n ? { message: normalizedMessage }\n : {}),\n },\n parameters: sessionId\n ? {\n body: {\n response: reply,\n ...(normalizedMessage\n ? { message: normalizedMessage }\n : {}),\n },\n path: {\n id: sessionId,\n permissionID: requestId,\n },\n }\n : undefined,\n });\n }\n\n async listModels(): Promise<OpenCodeConfiguredModel[]> {\n const now = Date.now();\n\n if (this.modelCache.value && this.modelCache.expiresAt > now) {\n return this.modelCache.value;\n }\n\n if (this.modelCache.promise) {\n return this.modelCache.promise;\n }\n\n const refreshPromise = this.loadModels().finally(() => {\n if (this.modelCache.promise === refreshPromise) {\n this.modelCache.promise = null;\n }\n });\n\n this.modelCache.promise = refreshPromise;\n\n return refreshPromise;\n }\n\n async listConfiguredPlugins(): Promise<string[]> {\n const config = await this.loadConfig();\n\n return normalizeConfiguredPluginSpecs(config.plugin);\n }\n\n async promptSession(input: PromptSessionInput): Promise<PromptSessionResult> {\n const startedAt = Date.now();\n const promptText = input.prompt?.trim() ?? \"\";\n const parts = [\n ...(promptText\n ? [{\n type: \"text\" as const,\n text: promptText,\n }]\n : []),\n ...((input.files ?? []).map((file) => ({\n type: \"file\" as const,\n filename: file.filename,\n mime: file.mime,\n url: file.url,\n }))),\n ];\n\n if (parts.length === 0) {\n throw new Error(\"Prompt requires text or file attachments.\");\n }\n\n throwIfAborted(input.signal);\n\n const knownMessageIds = await this.captureKnownMessageIds(input.sessionId, input.signal);\n await this.sendPromptRequest(input, parts);\n const resolvedData = await this.resolvePromptResponse(\n input,\n null,\n knownMessageIds,\n startedAt,\n );\n const finishedAt = Date.now();\n\n return buildPromptSessionResult(resolvedData, {\n emptyResponseText: EMPTY_RESPONSE_TEXT,\n finishedAt,\n startedAt,\n });\n }\n\n private async resolvePromptResponse(\n input: PromptSessionInput,\n data: OpenCodePromptResponse | null,\n knownMessageIds: Set<string>,\n startedAt: number,\n ): Promise<OpenCodePromptResponse> {\n if (data && shouldReturnPromptResponseImmediately(data)) {\n return data;\n }\n\n const messageId = data ? extractMessageId(data.info) : null;\n const candidateOptions: PromptResponseCandidateOptions = {\n initialMessageId: messageId,\n initialParentId: data ? toAssistantMessage(data.info)?.parentID ?? null : null,\n knownMessageIds,\n requestStartedAt: resolvePromptCandidateStartTime(startedAt, data),\n };\n let bestCandidate = selectPromptResponseCandidate(\n data ? [data] : [],\n candidateOptions,\n );\n let lastProgressAt = Date.now();\n let lastStatus: OpenCodeSessionStatus | null = null;\n const deadlineAt = startedAt + this.promptTimeoutPolicy.waitTimeoutMs;\n let idleStatusSeen = false;\n let attempt = 0;\n\n while (true) {\n throwIfAborted(input.signal);\n\n const remainingWaitMs = deadlineAt - Date.now();\n const remainingInactivityMs = this.promptTimeoutPolicy.recoveryInactivityTimeoutMs - (Date.now() - lastProgressAt);\n\n if (remainingWaitMs <= 0 || remainingInactivityMs <= 0) {\n break;\n }\n\n const delayMs = getPromptMessagePollDelayMs(attempt);\n attempt += 1;\n\n if (delayMs > 0) {\n const remainingMs = Math.min(remainingWaitMs, remainingInactivityMs);\n\n if (remainingMs <= 0) {\n break;\n }\n\n await delay(Math.min(delayMs, remainingMs), input.signal);\n }\n\n if (messageId) {\n const next = await this.fetchPromptMessage(input.sessionId, messageId, input.signal);\n\n if (next) {\n const nextCandidate = selectPromptResponseCandidate(\n [bestCandidate, next],\n candidateOptions,\n );\n\n if (nextCandidate) {\n if (didPromptResponseAdvance(bestCandidate, nextCandidate)) {\n lastProgressAt = Date.now();\n idleStatusSeen = false;\n }\n\n bestCandidate = nextCandidate;\n }\n\n if (\n bestCandidate\n && isPromptResponseForCurrentRequest(bestCandidate, candidateOptions)\n && shouldReturnPromptResponseImmediately(bestCandidate)\n ) {\n return bestCandidate;\n }\n }\n }\n\n const latest = await this.findLatestPromptResponse(\n input.sessionId,\n candidateOptions,\n \"poll-messages\",\n input.signal,\n );\n\n if (latest) {\n const nextCandidate = selectPromptResponseCandidate(\n [bestCandidate, latest],\n candidateOptions,\n );\n\n if (nextCandidate) {\n if (didPromptResponseAdvance(bestCandidate, nextCandidate)) {\n lastProgressAt = Date.now();\n idleStatusSeen = false;\n }\n\n bestCandidate = nextCandidate;\n }\n\n if (\n bestCandidate\n && isPromptResponseForCurrentRequest(bestCandidate, candidateOptions)\n && shouldReturnPromptResponseImmediately(bestCandidate)\n ) {\n return bestCandidate;\n }\n }\n\n const status = await this.fetchPromptSessionStatus(input.sessionId, input.signal);\n\n lastStatus = status;\n\n if (status?.type === \"busy\" || status?.type === \"retry\") {\n lastProgressAt = Date.now();\n idleStatusSeen = false;\n } else if (status?.type === \"idle\") {\n if (idleStatusSeen) {\n break;\n }\n\n idleStatusSeen = true;\n }\n\n if (\n bestCandidate\n && isPromptResponseForCurrentRequest(bestCandidate, candidateOptions)\n && isCompletedEmptyPromptResponse(bestCandidate)\n && status?.type !== \"busy\"\n && status?.type !== \"retry\"\n ) {\n break;\n }\n\n if (Date.now() >= deadlineAt) {\n break;\n }\n }\n\n const latest = await this.findLatestPromptResponse(\n input.sessionId,\n candidateOptions,\n \"final-scan\",\n input.signal,\n );\n\n const resolved = selectPromptResponseCandidate(\n [bestCandidate, latest],\n candidateOptions,\n );\n const requestScopedResolved = resolved && isPromptResponseForCurrentRequest(resolved, candidateOptions)\n ? resolved\n : null;\n\n if (\n lastStatus?.type === \"idle\"\n && (!requestScopedResolved || shouldPollPromptMessage(requestScopedResolved))\n ) {\n throw createMessageAbortedError();\n }\n\n if (!requestScopedResolved || shouldPollPromptMessage(requestScopedResolved)) {\n const timeoutReason = Date.now() >= deadlineAt\n ? \"max-wait\"\n : \"recovery-inactivity\";\n const timeoutMs = timeoutReason === \"max-wait\"\n ? this.promptTimeoutPolicy.waitTimeoutMs\n : this.promptTimeoutPolicy.recoveryInactivityTimeoutMs;\n const error = createOpenCodePromptTimeoutError({\n sessionId: input.sessionId,\n stage: \"final-scan\",\n timeoutMs,\n messageId: messageId ?? undefined,\n });\n this.logPromptRequest(\"warn\", {\n lastProgressAt,\n messageId: messageId ?? undefined,\n sessionId: input.sessionId,\n stage: \"final-scan\",\n timeoutMs,\n timeoutReason,\n }, \"OpenCode prompt recovery timed out\");\n throw error;\n }\n\n return requestScopedResolved;\n }\n\n private async fetchPromptMessage(\n sessionId: string,\n messageId: string,\n signal?: AbortSignal,\n ): Promise<OpenCodePromptResponse | null> {\n try {\n return await this.runPromptRequestWithTimeout(\n {\n sessionId,\n stage: \"poll-message\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n messageId,\n },\n async (requestSignal) => {\n return normalizePromptResponse(await this.callScopedSdkMethod<OpenCodePromptResponse>(\"session\", \"message\", {\n legacyParameters: {\n sessionID: sessionId,\n messageID: messageId,\n },\n parameters: {\n path: {\n id: sessionId,\n messageID: messageId,\n },\n },\n signal: requestSignal,\n }));\n },\n signal,\n );\n } catch (error) {\n if (isPromptRequestAbort(error)) {\n throw error;\n }\n\n this.logPromptRequestFailure(error, {\n sessionId,\n stage: \"poll-message\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n messageId,\n });\n return null;\n }\n }\n\n private async captureKnownMessageIds(sessionId: string, signal?: AbortSignal): Promise<Set<string>> {\n const messages = await this.fetchRecentPromptMessages(sessionId, \"capture-known-messages\", signal);\n\n if (!messages) {\n return new Set();\n }\n\n return new Set(\n messages\n .map((message) => extractMessageId(message.info))\n .filter((id): id is string => typeof id === \"string\" && id.length > 0),\n );\n }\n\n private async fetchRecentPromptMessages(\n sessionId: string,\n stage: Extract<OpenCodePromptTimeoutStage, \"capture-known-messages\" | \"poll-messages\" | \"final-scan\">,\n signal?: AbortSignal,\n ): Promise<OpenCodePromptResponse[] | null> {\n try {\n return await this.runPromptRequestWithTimeout(\n {\n sessionId,\n stage,\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n },\n async (requestSignal) => {\n return normalizePromptResponses(await this.callScopedSdkMethod<OpenCodePromptResponse[]>(\"session\", \"messages\", {\n legacyParameters: {\n sessionID: sessionId,\n limit: PROMPT_MESSAGE_POLL_LIMIT,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n query: {\n limit: PROMPT_MESSAGE_POLL_LIMIT,\n },\n },\n signal: requestSignal,\n }));\n },\n signal,\n );\n } catch (error) {\n if (isPromptRequestAbort(error)) {\n throw error;\n }\n\n this.logPromptRequestFailure(error, {\n sessionId,\n stage,\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n });\n return null;\n }\n }\n\n private async fetchPromptSessionStatus(sessionId: string, signal?: AbortSignal): Promise<OpenCodeSessionStatus | null> {\n try {\n const statuses = await this.runPromptRequestWithTimeout(\n {\n sessionId,\n stage: \"poll-status\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n },\n async (requestSignal) => this.loadSessionStatuses(requestSignal),\n signal,\n );\n\n return statuses[sessionId] ?? null;\n } catch (error) {\n if (isPromptRequestAbort(error)) {\n throw error;\n }\n\n this.logPromptRequestFailure(error, {\n sessionId,\n stage: \"poll-status\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n });\n return null;\n }\n }\n\n private async findLatestPromptResponse(\n sessionId: string,\n options: PromptResponseCandidateOptions,\n stage: Extract<OpenCodePromptTimeoutStage, \"poll-messages\" | \"final-scan\">,\n signal?: AbortSignal,\n ): Promise<OpenCodePromptResponse | null> {\n const messages = await this.fetchRecentPromptMessages(sessionId, stage, signal);\n\n if (!messages || messages.length === 0) {\n return null;\n }\n\n return selectPromptResponseCandidate(messages, options);\n }\n\n private async loadModels(): Promise<OpenCodeConfiguredModel[]> {\n const [config, providerCatalog] = await Promise.all([\n this.loadConfig(),\n this.loadProviderCatalog(),\n ]);\n const providerAvailability = await resolveProviderAvailability(config, this.fetchFn);\n const models = buildSelectableModels(\n config,\n providerCatalog.providers,\n providerAvailability,\n );\n\n this.modelCache = {\n expiresAt: Date.now() + 60_000,\n promise: null,\n value: models,\n };\n\n return models;\n }\n\n private async loadConfig(): Promise<OpenCodeConfig> {\n return this.callScopedSdkMethod<OpenCodeConfig>(\"config\", \"get\", {});\n }\n\n private async loadProviderCatalog(): Promise<OpenCodeProviderCatalog> {\n return this.callScopedSdkMethod<OpenCodeProviderCatalog>(\"config\", \"providers\", {});\n }\n\n private async sendPromptRequest(\n input: PromptSessionInput,\n parts: Array<\n | { type: \"text\"; text: string }\n | { type: \"file\"; filename?: string; mime: string; url: string }\n >,\n ): Promise<void> {\n const format = input.format ?? TEXT_OUTPUT_FORMAT;\n const requestBody = {\n ...(input.agent ? { agent: input.agent } : {}),\n format,\n ...(input.model ? { model: input.model } : {}),\n ...(input.variant ? { variant: input.variant } : {}),\n parts,\n };\n const legacyRequestParameters = {\n sessionID: input.sessionId,\n ...requestBody,\n };\n const requestParameters = {\n body: requestBody,\n path: {\n id: input.sessionId,\n },\n };\n\n try {\n if (typeof this.client.session?.promptAsync === \"function\") {\n await this.runPromptRequestWithTimeout(\n {\n sessionId: input.sessionId,\n stage: \"send-prompt\",\n timeoutMs: this.promptTimeoutPolicy.waitTimeoutMs,\n },\n async (signal) => {\n await this.callScopedSdkMethod<void>(\"session\", \"promptAsync\", {\n legacyParameters: legacyRequestParameters,\n parameters: requestParameters,\n signal,\n });\n },\n input.signal,\n );\n\n return;\n }\n } catch (error) {\n this.logPromptRequestFailure(error, {\n sessionId: input.sessionId,\n stage: \"send-prompt\",\n timeoutMs: this.promptTimeoutPolicy.waitTimeoutMs,\n });\n throw error;\n }\n\n throw new Error(\"OpenCode SDK client does not expose session.promptAsync().\");\n }\n\n private async loadSessionStatuses(\n signal?: AbortSignal,\n ): Promise<Record<string, OpenCodeSessionStatus>> {\n return this.callScopedSdkMethod<Record<string, OpenCodeSessionStatus>>(\"session\", \"status\", {\n signal,\n });\n }\n\n private async callRawSdkGet<T>(\n url: string,\n signal?: AbortSignal,\n ): Promise<T> {\n const rawClient = getRawSdkRequestClient(this.client);\n\n if (typeof rawClient?.get !== \"function\") {\n throw new Error(`OpenCode SDK client does not expose a compatible raw GET endpoint for ${url}.`);\n }\n\n const response = await rawClient.get({\n ...SDK_OPTIONS,\n ...(signal ? { signal } : {}),\n url,\n }) as MaybeWrappedResponse<T>;\n\n return unwrapSdkData(response);\n }\n\n private async runPromptRequestWithTimeout<T>(\n input: {\n messageId?: string | null;\n sessionId: string;\n stage: OpenCodePromptTimeoutStage;\n timeoutMs: number;\n },\n operation: (signal: AbortSignal) => Promise<T>,\n signal?: AbortSignal,\n ): Promise<T> {\n const startedAt = Date.now();\n const controller = new AbortController();\n const requestSignal = signal\n ? AbortSignal.any([signal, controller.signal])\n : controller.signal;\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n let removeAbortListener = () => undefined;\n\n const abortPromise = signal\n ? new Promise<never>((_, reject) => {\n const onAbort = () => {\n reject(normalizeAbortReason(signal.reason));\n };\n\n if (signal.aborted) {\n onAbort();\n return;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n removeAbortListener = () => {\n signal.removeEventListener(\"abort\", onAbort);\n };\n })\n : null;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n reject(createOpenCodePromptTimeoutError({\n sessionId: input.sessionId,\n stage: input.stage,\n timeoutMs: input.timeoutMs,\n messageId: input.messageId ?? undefined,\n elapsedMs: Date.now() - startedAt,\n }));\n controller.abort();\n }, input.timeoutMs);\n });\n\n try {\n return await Promise.race([\n operation(requestSignal),\n timeoutPromise,\n ...(abortPromise ? [abortPromise] : []),\n ]);\n } finally {\n if (timeoutHandle !== null) {\n clearTimeout(timeoutHandle);\n }\n\n removeAbortListener();\n }\n }\n\n private logPromptRequestFailure(\n error: unknown,\n input: {\n messageId?: string | null;\n sessionId: string;\n stage: OpenCodePromptTimeoutStage;\n timeoutMs: number;\n },\n ) {\n if (error instanceof OpenCodePromptTimeoutError) {\n this.logPromptRequest(\"warn\", {\n endpointKind: resolvePromptEndpointKind(error.data.stage),\n elapsedMs: error.data.elapsedMs,\n messageId: error.data.messageId,\n sessionId: error.data.sessionId,\n stage: error.data.stage,\n timeoutMs: error.data.timeoutMs,\n }, \"OpenCode prompt request timed out\");\n return;\n }\n\n this.logPromptRequest(\"warn\", {\n endpointKind: resolvePromptEndpointKind(input.stage),\n error,\n messageId: input.messageId ?? undefined,\n sessionId: input.sessionId,\n stage: input.stage,\n timeoutMs: input.timeoutMs,\n }, \"OpenCode prompt request failed\");\n }\n\n private logPromptRequest(\n level: \"warn\" | \"error\" | \"info\",\n extra: Record<string, unknown>,\n message: string,\n ) {\n const log = this.client.app?.log;\n\n if (typeof log !== \"function\") {\n return;\n }\n\n const payload = {\n service: PROMPT_LOG_SERVICE,\n level,\n message,\n extra,\n };\n\n void (log.length >= 2\n ? (log as (body: Record<string, unknown>, options: Record<string, unknown>) => Promise<unknown>).call(\n this.client.app,\n payload,\n SDK_OPTIONS,\n )\n : (log as (options: Record<string, unknown>) => Promise<unknown>).call(this.client.app, {\n body: payload,\n ...SDK_OPTIONS,\n })\n ).catch(() => undefined);\n }\n}\n\nexport function createOpenCodeClientFromSdkClient(\n client: OpenCodeSdkClientLike,\n fetchFn: typeof fetch = fetch,\n promptTimeoutPolicy: Partial<OpenCodePromptTimeoutPolicy> = {},\n): OpenCodeClientLike {\n return new OpenCodeClient(undefined, client, fetchFn, promptTimeoutPolicy);\n}\n\nfunction buildSelectableModels(\n config: OpenCodeConfig,\n providers: OpenCodeProvider[],\n providerAvailability: OpenCodeProviderAvailability = new Map(),\n): OpenCodeConfiguredModel[] {\n const configuredProviders = config.provider ?? {};\n const providersById = new Map(providers.map((provider) => [provider.id, provider]));\n const models = new Map<string, OpenCodeConfiguredModel>();\n\n for (const [providerId, providerConfig] of Object.entries(configuredProviders)) {\n const configuredModels = providerConfig.models ?? {};\n\n for (const [configuredModelKey, modelConfig] of Object.entries(configuredModels)) {\n const model = buildConfiguredModel(\n providerId,\n providerConfig,\n configuredModelKey,\n modelConfig,\n providersById.get(providerId),\n providerAvailability.get(providerId) ?? null,\n );\n\n if (model) {\n models.set(model.qualifiedId, model);\n }\n }\n }\n\n for (const provider of providers) {\n for (const model of buildCatalogProviderModels(provider, providerAvailability.get(provider.id) ?? null)) {\n if (!models.has(model.qualifiedId)) {\n models.set(model.qualifiedId, model);\n }\n }\n }\n\n return [...models.values()];\n}\n\nfunction buildConfiguredModel(\n providerId: string,\n providerConfig: OpenCodeProviderConfig,\n configuredModelKey: string,\n modelConfig: OpenCodeModelConfig,\n providerCatalog: OpenCodeProvider | undefined,\n availableModelIds: Set<string> | null,\n): OpenCodeConfiguredModel | null {\n const modelId = modelConfig.id ?? configuredModelKey;\n const catalogModel = providerCatalog?.models[modelId];\n\n if (!isTextModel(modelConfig, catalogModel)) {\n return null;\n }\n\n if (!isModelAvailable(modelId, availableModelIds)) {\n return null;\n }\n\n return {\n id: modelId,\n providerID: providerId,\n providerName: resolveProviderDisplayName(providerId, providerConfig, providerCatalog),\n name: modelConfig.name ?? catalogModel?.name ?? modelId,\n qualifiedId: `${providerId}/${modelId}`,\n reasoning: modelConfig.reasoning ?? catalogModel?.capabilities.reasoning ?? false,\n variants: normalizeVariants(modelConfig.variants ?? catalogModel?.variants),\n };\n}\n\nfunction buildCatalogProviderModels(\n provider: OpenCodeProvider,\n availableModelIds: Set<string> | null,\n): OpenCodeConfiguredModel[] {\n return Object.values(provider.models)\n .filter((model) => isCatalogTextModel(model) && isModelAvailable(model.id, availableModelIds))\n .map((model) => ({\n id: model.id,\n providerID: provider.id,\n providerName: provider.name,\n name: model.name,\n qualifiedId: `${provider.id}/${model.id}`,\n reasoning: model.capabilities.reasoning,\n variants: normalizeVariants(model.variants),\n }));\n}\n\nfunction isTextModel(modelConfig: OpenCodeModelConfig, catalogModel: OpenCodeModel | undefined): boolean {\n if (modelConfig.modalities) {\n return modelConfig.modalities.input.includes(\"text\") && modelConfig.modalities.output.includes(\"text\");\n }\n\n if (catalogModel) {\n return catalogModel.capabilities.input.text && catalogModel.capabilities.output.text;\n }\n\n return true;\n}\n\nfunction isCatalogTextModel(catalogModel: OpenCodeModel): boolean {\n return catalogModel.capabilities.input.text && catalogModel.capabilities.output.text;\n}\n\nfunction isModelAvailable(modelId: string, availableModelIds: Set<string> | null): boolean {\n return availableModelIds === null || availableModelIds.has(modelId);\n}\n\nfunction resolveProviderDisplayName(\n providerId: string,\n providerConfig: OpenCodeProviderConfig,\n providerCatalog: OpenCodeProvider | undefined,\n): string {\n if (providerConfig.name) {\n return providerConfig.name;\n }\n\n const configuredBaseUrl = extractConfiguredBaseUrl(providerConfig);\n\n if (configuredBaseUrl) {\n const host = safeParseUrlHost(configuredBaseUrl);\n const label = providerCatalog?.name ?? providerId;\n\n return host ? `${label} (${host})` : label;\n }\n\n return providerCatalog?.name ?? providerId;\n}\n\nfunction extractConfiguredBaseUrl(providerConfig: OpenCodeProviderConfig): string | null {\n const options = providerConfig.options;\n\n if (!options || typeof options !== \"object\") {\n return null;\n }\n\n const baseUrl = \"baseURL\" in options ? options.baseURL : null;\n\n return typeof baseUrl === \"string\" && baseUrl.trim().length > 0\n ? baseUrl.trim()\n : null;\n}\n\nfunction safeParseUrlHost(value: string): string | null {\n try {\n return new URL(value).host || null;\n } catch {\n return null;\n }\n}\n\nfunction normalizeVariants(\n variants: OpenCodeModelConfig[\"variants\"] | OpenCodeModel[\"variants\"] | undefined,\n): Record<string, Record<string, unknown>> {\n if (!variants) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(variants)\n .filter(([, config]) => !config?.disabled)\n .map(([variant, config]) => {\n const normalized = Object.fromEntries(\n Object.entries(config).filter(([key]) => key !== \"disabled\"),\n );\n\n return [variant, normalized];\n }),\n );\n}\n\nfunction extractTextFromParts(parts: Part[] | null | undefined): string {\n if (!Array.isArray(parts)) {\n return \"\";\n }\n\n return parts\n .filter((part): part is Extract<Part, { type: \"text\"; text: string }> => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim();\n}\n\nfunction buildPromptSessionResult(\n data: OpenCodePromptResponse,\n options: {\n emptyResponseText: string;\n finishedAt: number;\n startedAt: number;\n },\n): PromptSessionResult {\n const assistantInfo = toAssistantMessage(data.info);\n const responseParts = Array.isArray(data.parts) ? data.parts : [];\n const bodyMd = extractTextFromParts(responseParts) || null;\n const fallbackText = bodyMd\n ? stripMarkdownToPlainText(bodyMd) || bodyMd\n : options.emptyResponseText;\n\n return {\n assistantError: assistantInfo?.error ?? null,\n bodyMd,\n fallbackText,\n info: assistantInfo,\n metrics: extractPromptMetrics(assistantInfo, options.startedAt, options.finishedAt),\n parts: responseParts,\n structured: null,\n };\n}\n\nfunction shouldPollPromptMessage(\n data: OpenCodePromptResponse,\n): boolean {\n const assistantInfo = toAssistantMessage(data.info);\n const responseParts = Array.isArray(data.parts) ? data.parts : [];\n const hasText = extractTextFromParts(responseParts).length > 0;\n const hasAssistantError = !!assistantInfo?.error;\n const isCompleted = isAssistantMessageCompleted(assistantInfo);\n\n return !hasText && !hasAssistantError && !isCompleted;\n}\n\nfunction shouldReturnPromptResponseImmediately(\n data: OpenCodePromptResponse,\n): boolean {\n return !shouldPollPromptMessage(data)\n && !isCompletedEmptyPromptResponse(data);\n}\n\nfunction isPromptResponseUsable(\n data: OpenCodePromptResponse,\n): boolean {\n return !shouldPollPromptMessage(data)\n && !isCompletedEmptyPromptResponse(data);\n}\n\nfunction normalizePromptResponse(response: OpenCodePromptResponse | null | undefined): OpenCodePromptResponse {\n return {\n info: isPlainRecord(response?.info) ? response.info : null,\n parts: normalizePromptParts(response?.parts),\n };\n}\n\nfunction normalizePromptResponses(\n responses: OpenCodePromptResponse[] | null | undefined,\n): OpenCodePromptResponse[] | null {\n if (!Array.isArray(responses)) {\n return null;\n }\n\n return responses.map((response) => normalizePromptResponse(response));\n}\n\nfunction normalizePromptParts(parts: Part[] | null | undefined): Part[] {\n return Array.isArray(parts) ? parts : [];\n}\n\nfunction toAssistantMessage(message: unknown): OpenCodeAssistantMessage | null {\n if (!message || typeof message !== \"object\") {\n return null;\n }\n\n if (\"role\" in message && message.role !== \"assistant\") {\n return null;\n }\n\n const normalized: OpenCodeAssistantMessage = {};\n\n if (\"agent\" in message && typeof message.agent === \"string\" && message.agent.trim().length > 0) {\n normalized.agent = message.agent;\n }\n\n if (\"cost\" in message && typeof message.cost === \"number\" && Number.isFinite(message.cost)) {\n normalized.cost = message.cost;\n }\n\n const error = normalizeAssistantError(\"error\" in message ? message.error : undefined);\n\n if (error) {\n normalized.error = error;\n }\n\n if (\"finish\" in message && typeof message.finish === \"string\" && message.finish.trim().length > 0) {\n normalized.finish = message.finish;\n }\n\n if (\"id\" in message && typeof message.id === \"string\" && message.id.trim().length > 0) {\n normalized.id = message.id;\n }\n\n if (\"mode\" in message && typeof message.mode === \"string\" && message.mode.trim().length > 0) {\n normalized.mode = message.mode;\n }\n\n if (\"modelID\" in message && typeof message.modelID === \"string\" && message.modelID.trim().length > 0) {\n normalized.modelID = message.modelID;\n }\n\n if (\"parentID\" in message && typeof message.parentID === \"string\" && message.parentID.trim().length > 0) {\n normalized.parentID = message.parentID;\n }\n\n if (\"path\" in message && isPlainRecord(message.path)) {\n normalized.path = {\n ...(typeof message.path.cwd === \"string\" && message.path.cwd.trim().length > 0\n ? { cwd: message.path.cwd }\n : {}),\n ...(typeof message.path.root === \"string\" && message.path.root.trim().length > 0\n ? { root: message.path.root }\n : {}),\n };\n }\n\n if (\"providerID\" in message && typeof message.providerID === \"string\" && message.providerID.trim().length > 0) {\n normalized.providerID = message.providerID;\n }\n\n if (\"role\" in message && message.role === \"assistant\") {\n normalized.role = \"assistant\";\n }\n\n if (\"sessionID\" in message && typeof message.sessionID === \"string\" && message.sessionID.trim().length > 0) {\n normalized.sessionID = message.sessionID;\n }\n\n if (\"summary\" in message && typeof message.summary === \"boolean\") {\n normalized.summary = message.summary;\n }\n\n if (\"time\" in message && isPlainRecord(message.time)) {\n normalized.time = {\n ...(typeof message.time.created === \"number\" && Number.isFinite(message.time.created)\n ? { created: message.time.created }\n : {}),\n ...(typeof message.time.completed === \"number\" && Number.isFinite(message.time.completed)\n ? { completed: message.time.completed }\n : {}),\n };\n }\n\n if (\"tokens\" in message && isPlainRecord(message.tokens)) {\n normalized.tokens = {\n ...(typeof message.tokens.input === \"number\" && Number.isFinite(message.tokens.input)\n ? { input: message.tokens.input }\n : {}),\n ...(typeof message.tokens.output === \"number\" && Number.isFinite(message.tokens.output)\n ? { output: message.tokens.output }\n : {}),\n ...(typeof message.tokens.reasoning === \"number\" && Number.isFinite(message.tokens.reasoning)\n ? { reasoning: message.tokens.reasoning }\n : {}),\n ...(typeof message.tokens.total === \"number\" && Number.isFinite(message.tokens.total)\n ? { total: message.tokens.total }\n : {}),\n ...(isPlainRecord(message.tokens.cache)\n ? {\n cache: {\n ...(typeof message.tokens.cache.read === \"number\" && Number.isFinite(message.tokens.cache.read)\n ? { read: message.tokens.cache.read }\n : {}),\n ...(typeof message.tokens.cache.write === \"number\" && Number.isFinite(message.tokens.cache.write)\n ? { write: message.tokens.cache.write }\n : {}),\n },\n }\n : {}),\n };\n }\n\n if (\"variant\" in message && typeof message.variant === \"string\" && message.variant.trim().length > 0) {\n normalized.variant = message.variant;\n }\n\n return normalized;\n}\n\nfunction extractMessageId(message: unknown): string | null {\n if (!isPlainRecord(message)) {\n return null;\n }\n\n return typeof message.id === \"string\" && message.id.trim().length > 0\n ? message.id\n : null;\n}\n\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const handle = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(handle);\n signal?.removeEventListener(\"abort\", onAbort);\n reject(normalizeAbortReason(signal?.reason));\n };\n\n if (signal?.aborted) {\n onAbort();\n return;\n }\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction didPromptResponseAdvance(\n previous: OpenCodePromptResponse | null,\n next: OpenCodePromptResponse,\n): boolean {\n return getPromptResponseProgressSignature(previous)\n !== getPromptResponseProgressSignature(next);\n}\n\nfunction createOpenCodePromptTimeoutError(\n input: Omit<OpenCodePromptTimeoutErrorData, \"elapsedMs\" | \"message\"> & {\n elapsedMs?: number;\n message?: string;\n },\n): OpenCodePromptTimeoutError {\n return new OpenCodePromptTimeoutError({\n ...input,\n elapsedMs: input.elapsedMs ?? input.timeoutMs,\n message: input.message ?? \"The OpenCode host did not finish this request in time.\",\n });\n}\n\nfunction resolvePromptEndpointKind(stage: OpenCodePromptTimeoutStage): \"message\" | \"messages\" | \"prompt\" | \"status\" {\n switch (stage) {\n case \"capture-known-messages\":\n case \"poll-messages\":\n case \"final-scan\":\n return \"messages\";\n case \"poll-message\":\n return \"message\";\n case \"poll-status\":\n return \"status\";\n case \"send-prompt\":\n default:\n return \"prompt\";\n }\n}\n\nfunction getPromptMessagePollDelayMs(attempt: number): number {\n return PROMPT_MESSAGE_POLL_INITIAL_DELAYS_MS[attempt] ?? PROMPT_MESSAGE_POLL_INTERVAL_MS;\n}\n\nfunction extractPromptMetrics(\n info: OpenCodeAssistantMessage | null | undefined,\n startedAt: number,\n finishedAt: number,\n): PromptSessionMetrics {\n const createdAt = typeof info?.time?.created === \"number\" && Number.isFinite(info.time.created)\n ? info.time.created\n : null;\n const completedAt = typeof info?.time?.completed === \"number\" && Number.isFinite(info.time.completed)\n ? info.time.completed\n : null;\n const completedDuration = createdAt !== null && completedAt !== null\n ? completedAt - createdAt\n : null;\n const durationMs = completedDuration !== null && completedDuration >= 0\n ? completedDuration\n : Math.max(0, finishedAt - startedAt);\n\n return {\n durationMs,\n tokens: extractTokenMetrics(info),\n };\n}\n\nfunction extractTokenMetrics(info: OpenCodeAssistantMessage | null | undefined): PromptSessionTokenMetrics {\n if (!info?.tokens) {\n return {\n total: null,\n input: null,\n output: null,\n reasoning: null,\n cacheRead: null,\n cacheWrite: null,\n };\n }\n\n const input = coerceFiniteNumber(info.tokens.input);\n const output = coerceFiniteNumber(info.tokens.output);\n const reasoning = coerceFiniteNumber(info.tokens.reasoning);\n const cacheRead = coerceFiniteNumber(info.tokens.cache?.read);\n const cacheWrite = coerceFiniteNumber(info.tokens.cache?.write);\n const total = coerceFiniteNumber(info.tokens.total);\n const fallbackTotal = sumTokenMetrics(input, output, cacheRead, cacheWrite);\n\n return {\n total: total ?? fallbackTotal,\n input,\n output,\n reasoning,\n cacheRead,\n cacheWrite,\n };\n}\n\nfunction coerceFiniteNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction sumTokenMetrics(...values: Array<number | null>): number | null {\n if (values.every((value) => value === null)) {\n return null;\n }\n\n const total = values.reduce<number>((sum, value) => sum + (value ?? 0), 0);\n\n return Number.isFinite(total) ? total : null;\n}\n\nfunction unwrapSdkData<T>(response: MaybeWrappedResponse<T>): T {\n if (response && typeof response === \"object\" && \"data\" in response) {\n return response.data;\n }\n\n return response;\n}\n\nfunction normalizePermissionRequest(permission: unknown): OpenCodePermissionRequest | null {\n if (!isPlainRecord(permission)) {\n return null;\n }\n\n const id = typeof permission.id === \"string\" && permission.id.trim().length > 0\n ? permission.id\n : null;\n const sessionID = typeof permission.sessionID === \"string\" && permission.sessionID.trim().length > 0\n ? permission.sessionID\n : null;\n const permissionName = typeof permission.permission === \"string\" && permission.permission.trim().length > 0\n ? permission.permission\n : typeof permission.type === \"string\" && permission.type.trim().length > 0\n ? permission.type\n : null;\n\n if (!id || !sessionID || !permissionName) {\n return null;\n }\n\n return {\n always: Array.isArray(permission.always)\n ? permission.always.filter((value): value is string => typeof value === \"string\")\n : [],\n id,\n metadata: isPlainRecord(permission.metadata)\n ? permission.metadata\n : {},\n patterns: normalizePermissionPatterns(permission),\n permission: permissionName,\n sessionID,\n };\n}\n\nfunction normalizeConfiguredPluginSpecs(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n const normalizedPlugins: string[] = [];\n const seenPlugins = new Set<string>();\n\n for (const item of value) {\n if (typeof item !== \"string\") {\n continue;\n }\n\n const normalizedItem = item.trim();\n\n if (normalizedItem.length === 0 || seenPlugins.has(normalizedItem)) {\n continue;\n }\n\n seenPlugins.add(normalizedItem);\n normalizedPlugins.push(normalizedItem);\n }\n\n return normalizedPlugins;\n}\n\nfunction normalizePermissionPatterns(permission: Record<string, unknown>): string[] {\n if (Array.isArray(permission.patterns)) {\n return permission.patterns.filter((value): value is string => typeof value === \"string\");\n }\n\n if (typeof permission.pattern === \"string\" && permission.pattern.trim().length > 0) {\n return [permission.pattern];\n }\n\n if (Array.isArray(permission.pattern)) {\n return permission.pattern.filter((value): value is string => typeof value === \"string\");\n }\n\n return [];\n}\n\nfunction getRawSdkRequestClient(client: OpenCodeSdkClientLike): RawSdkRequestClient | null {\n const compatibleClient = client as OpenCodeSdkClientWithRawRequestClient;\n\n return compatibleClient.client ?? compatibleClient._client ?? null;\n}\n\nfunction isMissingScopedSdkMethodError(\n error: unknown,\n scope: string,\n method: string,\n): error is Error {\n return error instanceof Error\n && error.message === `OpenCode SDK client does not expose a compatible ${scope}.${method} method.`;\n}\n\nfunction resolvePromptTimeoutPolicy(\n input: Partial<OpenCodePromptTimeoutPolicy>,\n): OpenCodePromptTimeoutPolicy {\n return {\n pollRequestTimeoutMs: input.pollRequestTimeoutMs ?? DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY.pollRequestTimeoutMs,\n recoveryInactivityTimeoutMs: input.recoveryInactivityTimeoutMs ?? DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY.recoveryInactivityTimeoutMs,\n waitTimeoutMs: input.waitTimeoutMs ?? DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY.waitTimeoutMs,\n };\n}\n\nfunction normalizeAssistantError(value: unknown): OpenCodeAssistantError | undefined {\n if (!isPlainRecord(value) || typeof value.name !== \"string\" || value.name.trim().length === 0) {\n return undefined;\n }\n\n return {\n ...value,\n name: value.name,\n ...(isPlainRecord(value.data)\n ? { data: value.data }\n : {}),\n } as OpenCodeAssistantError;\n}\n\nfunction isAssistantMessageCompleted(\n message: OpenCodeAssistantMessage | null | undefined,\n): boolean {\n return !!message?.error\n || typeof message?.time?.completed === \"number\"\n || (typeof message?.finish === \"string\" && message.finish.trim().length > 0);\n}\n\nfunction isCompletedEmptyPromptResponse(\n data: OpenCodePromptResponse,\n): boolean {\n const assistantInfo = toAssistantMessage(data.info);\n const responseParts = Array.isArray(data.parts) ? data.parts : [];\n const hasText = extractTextFromParts(responseParts).length > 0;\n\n return isAssistantMessageCompleted(assistantInfo)\n && !assistantInfo?.error\n && !hasText;\n}\n\ntype PromptResponseCandidateOptions = {\n initialMessageId: string | null;\n initialParentId: string | null;\n knownMessageIds: Set<string>;\n requestStartedAt: number | null;\n};\n\nfunction selectPromptResponseCandidate(\n candidates: Array<OpenCodePromptResponse | null | undefined>,\n options: PromptResponseCandidateOptions,\n): OpenCodePromptResponse | null {\n const availableCandidates = candidates\n .filter((candidate): candidate is OpenCodePromptResponse => !!candidate)\n .filter((candidate) => toAssistantMessage(candidate.info) !== null);\n\n if (availableCandidates.length === 0) {\n return null;\n }\n\n return [...availableCandidates].sort((left, right) =>\n comparePromptResponseCandidates(left, right, options)\n )[0] ?? null;\n}\n\nfunction comparePromptResponseCandidates(\n left: OpenCodePromptResponse,\n right: OpenCodePromptResponse,\n options: PromptResponseCandidateOptions,\n): number {\n const leftRank = getPromptResponseCandidateRank(left, options);\n const rightRank = getPromptResponseCandidateRank(right, options);\n\n return Number(rightRank.isInitial) - Number(leftRank.isInitial)\n || Number(rightRank.sharesParent) - Number(leftRank.sharesParent)\n || Number(rightRank.isNewSinceRequestStart) - Number(leftRank.isNewSinceRequestStart)\n || Number(rightRank.isUsable) - Number(leftRank.isUsable)\n || rightRank.createdAt - leftRank.createdAt;\n}\n\nfunction getPromptResponseCandidateRank(\n message: OpenCodePromptResponse,\n options: PromptResponseCandidateOptions,\n): {\n createdAt: number;\n isInitial: boolean;\n isNewSinceRequestStart: boolean;\n isUsable: boolean;\n sharesParent: boolean;\n} {\n const assistant = toAssistantMessage(message.info);\n const id = assistant?.id ?? null;\n const createdAt = typeof assistant?.time?.created === \"number\" && Number.isFinite(assistant.time.created)\n ? assistant.time.created\n : 0;\n\n return {\n createdAt,\n isInitial: !!id && id === options.initialMessageId,\n isNewSinceRequestStart: isPromptResponseNewSinceRequestStart(\n id,\n createdAt,\n options.knownMessageIds,\n options.requestStartedAt,\n ),\n isUsable: isPromptResponseUsable(message),\n sharesParent: !!assistant?.parentID && assistant.parentID === options.initialParentId,\n };\n}\n\nfunction resolvePromptCandidateStartTime(\n startedAt: number,\n initialMessage: OpenCodePromptResponse | null,\n): number | null {\n if (!initialMessage) {\n return startedAt;\n }\n\n const initialCreatedAt = coerceFiniteNumber(toAssistantMessage(initialMessage.info)?.time?.created);\n\n if (initialCreatedAt === null) {\n return startedAt;\n }\n\n return areComparablePromptTimestamps(startedAt, initialCreatedAt)\n ? startedAt\n : initialCreatedAt;\n}\n\nfunction getPromptResponseProgressSignature(\n response: OpenCodePromptResponse | null,\n): string {\n if (!response) {\n return \"null\";\n }\n\n const assistant = toAssistantMessage(response.info);\n const responseParts = Array.isArray(response.parts) ? response.parts : [];\n\n return JSON.stringify({\n assistantError: assistant?.error?.name ?? null,\n bodyMd: extractTextFromParts(responseParts) || null,\n completedAt: assistant?.time?.completed ?? null,\n finish: assistant?.finish ?? null,\n id: assistant?.id ?? null,\n partCount: responseParts.length,\n text: extractTextFromParts(responseParts),\n });\n}\n\nfunction isPromptResponseNewSinceRequestStart(\n messageId: string | null,\n createdAt: number,\n knownMessageIds: Set<string>,\n requestStartedAt: number | null,\n): boolean {\n if (!messageId || knownMessageIds.has(messageId)) {\n return false;\n }\n\n if (requestStartedAt === null) {\n return true;\n }\n\n return createdAt >= requestStartedAt;\n}\n\nfunction isPromptResponseForCurrentRequest(\n response: OpenCodePromptResponse,\n options: PromptResponseCandidateOptions,\n): boolean {\n const rank = getPromptResponseCandidateRank(response, options);\n\n return rank.isInitial || rank.sharesParent || rank.isNewSinceRequestStart;\n}\n\nfunction areComparablePromptTimestamps(left: number, right: number): boolean {\n const epochThresholdMs = 1_000_000_000_000;\n\n return left >= epochThresholdMs && right >= epochThresholdMs;\n}\n\nfunction isPromptRequestAbort(error: unknown): boolean {\n return error instanceof OpenCodeMessageAbortedError\n || (error instanceof Error && error.name === \"AbortError\")\n || isNamedAbortError(error);\n}\n\nfunction isNamedAbortError(error: unknown): error is { name: \"MessageAbortedError\" } {\n return !!error\n && typeof error === \"object\"\n && \"name\" in error\n && (error as { name?: unknown }).name === \"MessageAbortedError\";\n}\n\nfunction normalizeAbortReason(reason: unknown): unknown {\n if (reason instanceof Error || isNamedAbortError(reason)) {\n return reason;\n }\n\n return createMessageAbortedError();\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) {\n return;\n }\n\n throw normalizeAbortReason(signal.reason);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, any> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nasync function resolveProviderAvailability(\n config: OpenCodeConfig,\n fetchFn: typeof fetch,\n): Promise<OpenCodeProviderAvailability> {\n const configuredProviders = Object.entries(config.provider ?? {});\n const availabilityEntries = await Promise.all(\n configuredProviders.map(async ([providerId, providerConfig]) => [\n providerId,\n await fetchProviderAvailableModelIds(providerConfig, fetchFn),\n ] as const),\n );\n\n return new Map(availabilityEntries);\n}\n\nasync function fetchProviderAvailableModelIds(\n providerConfig: OpenCodeProviderConfig,\n fetchFn: typeof fetch,\n): Promise<Set<string> | null> {\n const baseUrl = extractConfiguredBaseUrl(providerConfig);\n const apiKey = extractConfiguredApiKey(providerConfig);\n\n if (!baseUrl || !apiKey) {\n return null;\n }\n\n try {\n const response = await fetchFn(\n buildModelsEndpointUrl(baseUrl),\n {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n Accept: \"application/json\",\n },\n signal: AbortSignal.timeout(10_000),\n },\n );\n\n if (!response.ok) {\n return null;\n }\n\n const payload = await response.json();\n const modelIds = extractModelIdsFromPayload(payload);\n\n return modelIds ? new Set(modelIds) : null;\n } catch {\n return null;\n }\n}\n\nfunction extractConfiguredApiKey(providerConfig: OpenCodeProviderConfig): string | null {\n const options = providerConfig.options;\n\n if (!options || typeof options !== \"object\") {\n return null;\n }\n\n const apiKey = \"apiKey\" in options ? options.apiKey : null;\n\n return typeof apiKey === \"string\" && apiKey.trim().length > 0\n ? apiKey.trim()\n : null;\n}\n\nfunction buildModelsEndpointUrl(baseUrl: string): string {\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n\n return new URL(\"models\", normalizedBaseUrl).toString();\n}\n\nfunction extractModelIdsFromPayload(payload: unknown): string[] | null {\n if (Array.isArray(payload)) {\n return payload\n .map(extractModelId)\n .filter((id): id is string => !!id);\n }\n\n if (payload && typeof payload === \"object\" && \"data\" in payload && Array.isArray(payload.data)) {\n return payload.data\n .map(extractModelId)\n .filter((id): id is string => !!id);\n }\n\n return null;\n}\n\nfunction extractModelId(value: unknown): string | null {\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n\n if (value && typeof value === \"object\" && \"id\" in value) {\n const id = (value as { id?: unknown }).id;\n\n return typeof id === \"string\" && id.trim().length > 0\n ? id.trim()\n : null;\n }\n\n return null;\n}\n","import type { PendingChatAction } from \"../../domain/pending-action/pending-action.entity.js\";\nimport type { PendingPermissionApproval } from \"../../domain/permission/approval.entity.js\";\nimport type { ChatSessionBinding } from \"../../domain/session/session.entity.js\";\n\nexport interface OpencodeTbotState {\n version: 1;\n sessions: Record<string, ChatSessionBinding>;\n pendingActions: Record<string, PendingChatAction>;\n pendingPermissions: Record<string, PendingPermissionApproval>;\n}\n\nexport function createDefaultOpencodeTbotState(): OpencodeTbotState {\n return {\n version: 1,\n sessions: {},\n pendingActions: {},\n pendingPermissions: {},\n };\n}\n","import { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nexport interface JsonStateStoreOptions<TState> {\n createDefaultState: () => TState;\n filePath: string;\n}\n\nexport class JsonStateStore<TState> {\n private readonly createDefaultState: () => TState;\n private readonly filePath: string;\n private statePromise: Promise<TState> | null = null;\n private writeQueue = Promise.resolve();\n\n constructor(options: JsonStateStoreOptions<TState>) {\n this.createDefaultState = options.createDefaultState;\n this.filePath = options.filePath;\n }\n\n async read(): Promise<TState> {\n const state = await this.loadState();\n\n return cloneState(state);\n }\n\n async update(mutator: (state: TState) => void): Promise<TState> {\n const nextStatePromise = this.writeQueue.then(async () => {\n const state = await this.loadState();\n const draft = cloneState(state);\n\n mutator(draft);\n await writeStateFile(this.filePath, draft);\n this.statePromise = Promise.resolve(draft);\n\n return cloneState(draft);\n });\n\n this.writeQueue = nextStatePromise.then(() => undefined, () => undefined);\n\n return nextStatePromise;\n }\n\n private async loadState(): Promise<TState> {\n if (!this.statePromise) {\n this.statePromise = readStateFile(this.filePath, this.createDefaultState);\n }\n\n return this.statePromise;\n }\n}\n\nasync function readStateFile<TState>(\n filePath: string,\n createDefaultState: () => TState,\n): Promise<TState> {\n try {\n const content = await readFile(filePath, \"utf8\");\n\n return JSON.parse(content) as TState;\n } catch (error) {\n if (isMissingFileError(error)) {\n return createDefaultState();\n }\n\n throw error;\n }\n}\n\nasync function writeStateFile<TState>(filePath: string, state: TState): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n\n const temporaryFilePath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n const serialized = `${JSON.stringify(state, null, 2)}\\n`;\n\n await writeFile(temporaryFilePath, serialized, \"utf8\");\n await rename(temporaryFilePath, filePath);\n}\n\nfunction cloneState<TState>(state: TState): TState {\n return JSON.parse(JSON.stringify(state)) as TState;\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n","export interface DownloadTelegramFileInput {\n filePath: string;\n}\n\nexport interface DownloadTelegramFileResult {\n data: Uint8Array;\n mimeType: string | null;\n}\n\nexport interface TelegramFileClientLike {\n downloadFile(input: DownloadTelegramFileInput): Promise<DownloadTelegramFileResult>;\n}\n\nexport interface TelegramFileClientOptions {\n baseUrl?: string;\n apiRoot?: string;\n botToken: string;\n}\n\nexport class TelegramFileDownloadError extends Error {\n readonly data: { message: string };\n\n constructor(message: string) {\n super(message);\n this.name = \"TelegramFileDownloadError\";\n this.data = { message };\n }\n}\n\nexport class TelegramFileClient implements TelegramFileClientLike {\n private readonly baseUrl: string;\n private readonly fetchFn: typeof fetch;\n\n constructor(options: TelegramFileClientOptions, fetchFn: typeof fetch = fetch) {\n this.baseUrl = options.baseUrl ?? buildTelegramFileApiRoot(options.apiRoot, options.botToken);\n this.fetchFn = fetchFn;\n }\n\n async downloadFile(input: DownloadTelegramFileInput): Promise<DownloadTelegramFileResult> {\n const filePath = input.filePath.trim();\n\n if (!filePath) {\n throw new TelegramFileDownloadError(\"Telegram did not provide a downloadable file path.\");\n }\n\n let response: Response;\n\n try {\n response = await this.fetchFn(new URL(filePath, this.baseUrl));\n } catch (error) {\n throw new TelegramFileDownloadError(extractErrorMessage(error) ?? \"Failed to download the Telegram file.\");\n }\n\n if (!response.ok) {\n throw new TelegramFileDownloadError(await buildDownloadFailureMessage(response));\n }\n\n const data = new Uint8Array(await response.arrayBuffer());\n\n if (data.byteLength === 0) {\n throw new TelegramFileDownloadError(\"Telegram returned an empty file.\");\n }\n\n return {\n data,\n mimeType: response.headers.get(\"content-type\"),\n };\n }\n}\n\nexport function buildTelegramFileApiRoot(apiRoot: string | undefined, botToken: string): string {\n const normalizedApiRoot = (apiRoot ?? \"https://api.telegram.org\").trim().replace(/\\/+$/u, \"\");\n\n return `${normalizedApiRoot}/file/bot${botToken}/`;\n}\n\nasync function buildDownloadFailureMessage(response: Response): Promise<string> {\n const responseText = await safeReadResponseText(response);\n const normalizedText = responseText?.trim();\n\n return normalizedText\n ? `Telegram file download failed with status ${response.status}: ${normalizedText}`\n : `Telegram file download failed with status ${response.status}.`;\n}\n\nasync function safeReadResponseText(response: Response): Promise<string | null> {\n try {\n const text = await response.text();\n\n return text.trim().length > 0 ? text : null;\n } catch {\n return null;\n }\n}\n\nfunction extractErrorMessage(error: unknown): string | null {\n return error instanceof Error && error.message.trim().length > 0\n ? error.message.trim()\n : null;\n}\n","import { createMessageAbortedError } from \"../opencode/opencode.client.js\";\n\nexport interface ForegroundSessionLease {\n readonly signal: AbortSignal;\n attachSession(sessionId: string): void;\n dispose(): void;\n}\n\nexport interface ForegroundSessionTrackerLike {\n acquire(chatId: number): ForegroundSessionLease | null;\n abort(chatId: number, reason?: unknown): boolean;\n begin(chatId: number, sessionId: string): () => void;\n clear(sessionId: string): boolean;\n fail(sessionId: string, error: unknown): boolean;\n getActiveSessionId(chatId: number): string | null;\n hasActiveRequest(chatId: number): boolean;\n isForeground(sessionId: string): boolean;\n listChatIds(sessionId: string): number[];\n}\n\ninterface ForegroundRequestState {\n chatId: number;\n controller: AbortController;\n sessionId: string | null;\n}\n\nexport class ForegroundSessionTracker implements ForegroundSessionTrackerLike {\n private readonly requests = new Map<number, ForegroundRequestState>();\n private readonly sessionChats = new Map<string, Set<number>>();\n\n acquire(chatId: number): ForegroundSessionLease | null {\n if (this.requests.has(chatId)) {\n return null;\n }\n\n const state: ForegroundRequestState = {\n chatId,\n controller: new AbortController(),\n sessionId: null,\n };\n\n this.requests.set(chatId, state);\n\n return {\n signal: state.controller.signal,\n attachSession: (sessionId: string) => {\n this.attachSession(chatId, sessionId);\n },\n dispose: () => {\n this.release(chatId);\n },\n };\n }\n\n abort(chatId: number, reason: unknown = createMessageAbortedError()): boolean {\n const state = this.requests.get(chatId);\n\n if (!state) {\n return false;\n }\n\n if (!state.controller.signal.aborted) {\n state.controller.abort(reason);\n }\n\n return true;\n }\n\n begin(chatId: number, sessionId: string): () => void {\n const lease = this.acquire(chatId);\n\n if (!lease) {\n return () => undefined;\n }\n\n lease.attachSession(sessionId);\n return () => {\n lease.dispose();\n };\n }\n\n clear(sessionId: string): boolean {\n const chatIds = this.listChatIds(sessionId);\n\n if (chatIds.length === 0) {\n return false;\n }\n\n for (const chatId of chatIds) {\n const state = this.requests.get(chatId);\n\n if (state?.sessionId === sessionId) {\n state.sessionId = null;\n }\n }\n\n this.sessionChats.delete(sessionId);\n return true;\n }\n\n fail(sessionId: string, error: unknown): boolean {\n const chatIds = this.listChatIds(sessionId);\n\n if (chatIds.length === 0) {\n return false;\n }\n\n this.clear(sessionId);\n\n for (const chatId of chatIds) {\n this.abort(chatId, error);\n }\n\n return true;\n }\n\n getActiveSessionId(chatId: number): string | null {\n return this.requests.get(chatId)?.sessionId ?? null;\n }\n\n hasActiveRequest(chatId: number): boolean {\n return this.requests.has(chatId);\n }\n\n isForeground(sessionId: string): boolean {\n return this.sessionChats.has(sessionId);\n }\n\n listChatIds(sessionId: string): number[] {\n return [...(this.sessionChats.get(sessionId) ?? new Set<number>())];\n }\n\n private attachSession(chatId: number, sessionId: string): void {\n const normalizedSessionId = sessionId.trim();\n const state = this.requests.get(chatId);\n\n if (!state || normalizedSessionId.length === 0) {\n return;\n }\n\n if (state.sessionId === normalizedSessionId) {\n return;\n }\n\n if (state.sessionId) {\n this.detachChatFromSession(chatId, state.sessionId);\n }\n\n state.sessionId = normalizedSessionId;\n\n const chatIds = this.sessionChats.get(normalizedSessionId) ?? new Set<number>();\n\n chatIds.add(chatId);\n this.sessionChats.set(normalizedSessionId, chatIds);\n }\n\n private release(chatId: number): void {\n const state = this.requests.get(chatId);\n\n if (!state) {\n return;\n }\n\n if (state.sessionId) {\n this.detachChatFromSession(chatId, state.sessionId);\n }\n\n this.requests.delete(chatId);\n }\n\n private detachChatFromSession(chatId: number, sessionId: string): void {\n const chatIds = this.sessionChats.get(sessionId);\n\n if (!chatIds) {\n return;\n }\n\n chatIds.delete(chatId);\n\n if (chatIds.size === 0) {\n this.sessionChats.delete(sessionId);\n return;\n }\n\n this.sessionChats.set(sessionId, chatIds);\n }\n}\n\nexport const NOOP_FOREGROUND_SESSION_TRACKER: ForegroundSessionTrackerLike = {\n acquire() {\n return null;\n },\n abort() {\n return false;\n },\n begin() {\n return () => undefined;\n },\n clear() {\n return false;\n },\n fail() {\n return false;\n },\n getActiveSessionId() {\n return null;\n },\n hasActiveRequest() {\n return false;\n },\n isForeground() {\n return false;\n },\n listChatIds() {\n return [];\n },\n};\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport {\n createMessageAbortedError,\n type OpenCodeClientLike,\n type OpenCodeSessionStatus,\n} from \"../services/opencode/opencode.client.js\";\nimport {\n NOOP_FOREGROUND_SESSION_TRACKER,\n type ForegroundSessionTrackerLike,\n} from \"../services/session-activity/foreground-session-tracker.js\";\n\nexport interface AbortPromptResult {\n sessionId: string | null;\n status: \"aborted\" | \"no_session\" | \"not_running\";\n sessionStatus: OpenCodeSessionStatus | null;\n}\n\nexport class AbortPromptUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly foregroundSessionTracker: ForegroundSessionTrackerLike = NOOP_FOREGROUND_SESSION_TRACKER,\n ) { }\n\n async execute(input: { chatId: number }): Promise<AbortPromptResult> {\n const hasForegroundRequest = this.foregroundSessionTracker.hasActiveRequest(input.chatId);\n const activeSessionId = this.foregroundSessionTracker.getActiveSessionId(input.chatId);\n const binding = activeSessionId\n ? null\n : await this.sessionRepo.getByChatId(input.chatId);\n const sessionId = activeSessionId ?? binding?.sessionId ?? null;\n\n if (!hasForegroundRequest && !sessionId) {\n return {\n sessionId: null,\n status: \"no_session\",\n sessionStatus: null,\n };\n }\n\n const sessionStatuses = sessionId\n ? await this.opencodeClient.getSessionStatuses()\n : {};\n const sessionStatus = sessionId\n ? (sessionStatuses[sessionId] ?? null)\n : null;\n\n if (hasForegroundRequest) {\n if (sessionId && sessionStatus && sessionStatus.type !== \"idle\") {\n await this.opencodeClient.abortSession(sessionId);\n }\n\n this.foregroundSessionTracker.abort(\n input.chatId,\n createMessageAbortedError(),\n );\n\n return {\n sessionId,\n status: \"aborted\",\n sessionStatus,\n };\n }\n\n if (!sessionStatus || sessionStatus.type === \"idle\") {\n return {\n sessionId,\n status: \"not_running\",\n sessionStatus,\n };\n }\n\n if (!sessionId) {\n return {\n sessionId: null,\n status: \"not_running\",\n sessionStatus,\n };\n }\n\n const runningSessionId = sessionId;\n const aborted = await this.opencodeClient.abortSession(runningSessionId);\n\n return {\n sessionId: runningSessionId,\n status: aborted ? \"aborted\" : \"not_running\",\n sessionStatus,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeProject,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\n\ninterface CreateAndBindCurrentProjectSessionInput {\n chatId: number;\n title?: string | null;\n binding?: ChatSessionBinding | null;\n}\n\nexport interface CreateAndBindCurrentProjectSessionResult {\n binding: ChatSessionBinding;\n project: OpenCodeProject;\n session: OpenCodeSession;\n}\n\nexport async function createAndBindCurrentProjectSession(\n sessionRepo: SessionRepository,\n opencodeClient: OpenCodeClientLike,\n input: CreateAndBindCurrentProjectSessionInput,\n): Promise<CreateAndBindCurrentProjectSessionResult> {\n const binding = input.binding ?? await sessionRepo.getByChatId(input.chatId);\n const project = await opencodeClient.getCurrentProject();\n const title = normalizeOptionalText(input.title);\n const session = await opencodeClient.createSessionForDirectory(project.worktree, title ?? undefined);\n const nextBinding: ChatSessionBinding = {\n chatId: input.chatId,\n sessionId: session.id,\n projectId: session.projectID,\n directory: session.directory,\n agentName: binding?.agentName ?? null,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n };\n\n await sessionRepo.setCurrent(nextBinding);\n\n return {\n binding: nextBinding,\n project,\n session,\n };\n}\n\nfunction normalizeOptionalText(value: string | null | undefined): string | null {\n const normalized = value?.trim();\n\n return normalized ? normalized : null;\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\nimport { createAndBindCurrentProjectSession } from \"./session-creation.js\";\n\nexport interface CreateSessionResult {\n session: OpenCodeSession;\n}\n\nexport class CreateSessionUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; title?: string | null }): Promise<CreateSessionResult> {\n const binding = await this.sessionRepo.getByChatId(input.chatId);\n const result = await createAndBindCurrentProjectSession(\n this.sessionRepo,\n this.opencodeClient,\n {\n chatId: input.chatId,\n title: input.title,\n binding,\n },\n );\n\n this.logger.info(\n {\n chatId: input.chatId,\n sessionId: result.session.id,\n projectId: result.session.projectID,\n directory: result.session.directory,\n title: input.title?.trim() || null,\n },\n \"session created\",\n );\n\n return {\n session: result.session,\n };\n }\n}\n","import type {\n OpenCodeClientLike,\n OpenCodeHealth,\n} from \"../services/opencode/opencode.client.js\";\n\nexport class GetHealthUseCase {\n constructor(private readonly opencodeClient: OpenCodeClientLike) { }\n\n async execute(): Promise<OpenCodeHealth> {\n return this.opencodeClient.getHealth();\n }\n}\n","import type { OpenCodeClientLike, OpenCodePath } from \"../services/opencode/opencode.client.js\";\n\nexport class GetPathUseCase {\n constructor(private readonly opencodeClient: OpenCodeClientLike) { }\n\n async execute(): Promise<OpenCodePath> {\n return this.opencodeClient.getPath();\n }\n}\n","import { isAbsolute } from \"node:path\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeHealth,\n OpenCodePath,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\nimport type { GetHealthUseCase } from \"./get-health.usecase.js\";\nimport type { GetPathUseCase } from \"./get-path.usecase.js\";\nimport type { ListLspResult, ListLspUseCase } from \"./list-lsp.usecase.js\";\nimport type { ListMcpResult, ListMcpUseCase } from \"./list-mcp.usecase.js\";\nimport type { ListSessionsUseCase } from \"./list-sessions.usecase.js\";\n\nexport interface StatusSectionOk<TData> {\n data: TData;\n status: \"ok\";\n}\n\nexport interface StatusSectionError {\n error: unknown;\n status: \"error\";\n}\n\nexport type StatusSectionResult<TData> = StatusSectionOk<TData> | StatusSectionError;\n\nexport interface ConfiguredPluginsResult {\n plugins: string[];\n}\n\ninterface ConfiguredPluginReader {\n listConfiguredPlugins(): Promise<string[]>;\n}\n\nexport interface WorkspaceStatusResult {\n currentProject: string;\n currentSession: string | null;\n}\n\nexport interface GetStatusResult {\n health: StatusSectionResult<OpenCodeHealth>;\n lsp: StatusSectionResult<ListLspResult>;\n mcp: StatusSectionResult<ListMcpResult>;\n path: StatusSectionResult<OpenCodePath>;\n plugins: StatusSectionResult<ConfiguredPluginsResult>;\n workspace: StatusSectionResult<WorkspaceStatusResult>;\n}\n\nexport class GetStatusUseCase {\n constructor(\n private readonly getHealthUseCase: GetHealthUseCase,\n private readonly getPathUseCase: GetPathUseCase,\n private readonly listLspUseCase: ListLspUseCase,\n private readonly listMcpUseCase: ListMcpUseCase,\n private readonly listSessionsUseCase: ListSessionsUseCase,\n private readonly sessionRepo: SessionRepository,\n private readonly configuredPluginReader: ConfiguredPluginReader,\n ) { }\n\n async execute(input: { chatId: number }): Promise<GetStatusResult> {\n const [health, path, lsp, mcp, plugins] = await Promise.allSettled([\n this.getHealthUseCase.execute(),\n this.getPathUseCase.execute(),\n this.listLspUseCase.execute({ chatId: input.chatId }),\n this.listMcpUseCase.execute({ chatId: input.chatId }),\n this.configuredPluginReader.listConfiguredPlugins(),\n ]);\n const pathResult = mapSettledResult(path);\n const pluginResult = loadConfiguredPluginsResult(plugins);\n const workspace = await loadWorkspaceStatusResult(\n input.chatId,\n pathResult,\n this.listSessionsUseCase,\n this.sessionRepo,\n );\n\n return {\n health: mapSettledResult(health),\n path: pathResult,\n plugins: pluginResult,\n workspace,\n lsp: mapSettledResult(lsp),\n mcp: mapSettledResult(mcp),\n };\n }\n}\n\nfunction mapSettledResult<TData>(result: PromiseSettledResult<TData>): StatusSectionResult<TData> {\n if (result.status === \"fulfilled\") {\n return {\n data: result.value,\n status: \"ok\",\n };\n }\n\n return {\n error: result.reason,\n status: \"error\",\n };\n}\n\nfunction loadConfiguredPluginsResult(\n result: PromiseSettledResult<string[]>,\n): StatusSectionResult<ConfiguredPluginsResult> {\n if (result.status === \"rejected\") {\n return {\n error: result.reason,\n status: \"error\",\n };\n }\n\n return {\n data: {\n plugins: normalizeConfiguredPluginLabels(result.value),\n },\n status: \"ok\",\n };\n}\n\nasync function loadWorkspaceStatusResult(\n chatId: number,\n path: StatusSectionResult<OpenCodePath>,\n listSessionsUseCase: ListSessionsUseCase,\n sessionRepo: SessionRepository,\n): Promise<StatusSectionResult<WorkspaceStatusResult>> {\n if (path.status === \"error\") {\n return {\n error: path.error,\n status: \"error\",\n };\n }\n\n const binding = await sessionRepo.getByChatId(chatId);\n let currentProject = resolveWorkspaceProjectPath(path.data);\n let currentSession = binding?.sessionId ?? null;\n\n try {\n const sessions = await listSessionsUseCase.execute({ chatId });\n\n currentProject = resolveWorkspaceProjectPath(path.data, sessions.currentDirectory);\n currentSession = sessions.currentSessionId\n ? formatSessionStatusLabel(\n sessions.sessions.find((session) => session.id === sessions.currentSessionId) ?? null,\n sessions.currentSessionId,\n )\n : null;\n } catch {\n // Keep path/session binding fallbacks when session listing is unavailable.\n }\n\n return {\n data: {\n currentProject,\n currentSession,\n },\n status: \"ok\",\n };\n}\n\nfunction formatSessionStatusLabel(session: OpenCodeSession | null, fallbackId: string): string {\n if (!session) {\n return fallbackId;\n }\n\n const title = session.title.trim() || session.slug || session.id;\n\n return title === session.slug\n ? title\n : `${title} (${session.slug})`;\n}\n\nfunction resolveWorkspaceProjectPath(path: OpenCodePath, preferredPath?: string | null): string {\n const candidates = [\n preferredPath,\n path.worktree,\n path.directory,\n ];\n\n for (const candidate of candidates) {\n if (isUsableWorkspacePath(candidate)) {\n return candidate;\n }\n }\n\n return preferredPath ?? path.worktree ?? path.directory;\n}\n\nfunction isUsableWorkspacePath(value: string | null | undefined): value is string {\n if (typeof value !== \"string\") {\n return false;\n }\n\n const normalized = value.trim();\n\n return normalized.length > 0\n && normalized !== \"/\"\n && normalized !== \"\\\\\"\n && isAbsolute(normalized);\n}\n\nfunction normalizeConfiguredPluginLabels(plugins: string[]): string[] {\n const normalizedPlugins: string[] = [];\n const seenPlugins = new Set<string>();\n\n for (const plugin of plugins) {\n const normalizedPlugin = normalizeConfiguredPluginLabel(plugin);\n\n if (normalizedPlugin.length === 0 || seenPlugins.has(normalizedPlugin)) {\n continue;\n }\n\n seenPlugins.add(normalizedPlugin);\n normalizedPlugins.push(normalizedPlugin);\n }\n\n return normalizedPlugins;\n}\n\nfunction normalizeConfiguredPluginLabel(plugin: string): string {\n const normalizedPlugin = plugin.trim();\n const localPluginName = extractLocalPluginName(normalizedPlugin);\n\n return localPluginName\n ? `${localPluginName} (local plugin)`\n : normalizedPlugin;\n}\n\nfunction extractLocalPluginName(plugin: string): string | null {\n const filePath = parseFilePluginPath(plugin);\n\n if (!filePath) {\n return null;\n }\n\n const pathSegments = filePath.split(\"/\").filter((segment) => segment.length > 0);\n const fileName = pathSegments.at(-1);\n const parentDirectoryName = pathSegments.at(-2);\n\n if (!fileName || parentDirectoryName !== \"plugins\") {\n return null;\n }\n\n const pluginName = fileName.replace(/\\.(?:[cm]?js|[cm]?ts)$/iu, \"\");\n\n return pluginName.trim().length > 0\n ? pluginName.trim()\n : null;\n}\n\nfunction parseFilePluginPath(plugin: string): string | null {\n if (!plugin.startsWith(\"file://\")) {\n return null;\n }\n\n try {\n const fileUrl = new URL(plugin);\n\n if (fileUrl.protocol !== \"file:\") {\n return null;\n }\n\n const normalizedPath = decodeURIComponent(fileUrl.pathname)\n .replace(/^\\/([A-Za-z]:)/u, \"$1\")\n .replace(/\\\\/gu, \"/\");\n\n return normalizedPath.length > 0\n ? normalizedPath\n : null;\n } catch {\n return null;\n }\n}\n","import type { OpenCodeAgent } from \"../services/opencode/opencode.client.js\";\n\nexport const DEFAULT_AGENT_NAME = \"build\";\n\nexport function isSelectableAgent(agent: OpenCodeAgent): boolean {\n return !agent.hidden && agent.mode !== \"subagent\";\n}\n\nexport function getSelectableAgents(agents: OpenCodeAgent[]): OpenCodeAgent[] {\n return agents.filter((agent) => isSelectableAgent(agent));\n}\n\nexport function resolveSelectedAgent(\n agents: OpenCodeAgent[],\n requestedAgentName: string | null | undefined,\n): OpenCodeAgent | null {\n const visibleAgents = getSelectableAgents(agents);\n\n if (requestedAgentName) {\n const requestedAgent = visibleAgents.find((agent) => agent.name === requestedAgentName);\n\n if (requestedAgent) {\n return requestedAgent;\n }\n }\n\n return visibleAgents.find((agent) => agent.name === DEFAULT_AGENT_NAME) ?? null;\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\n\ntype MutableBindingFields = Omit<ChatSessionBinding, \"chatId\" | \"updatedAt\">;\n\nexport async function persistBindingUpdate(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n updates: Partial<MutableBindingFields>,\n): Promise<ChatSessionBinding> {\n const nextBinding: ChatSessionBinding = {\n ...binding,\n ...updates,\n updatedAt: new Date().toISOString(),\n };\n\n await sessionRepo.setCurrent(nextBinding);\n return nextBinding;\n}\n\nexport async function clearStoredAgentSelection(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n agentName: null,\n });\n}\n\nexport async function clearStoredModelSelection(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n modelProviderId: null,\n modelId: null,\n modelVariant: null,\n });\n}\n\nexport async function clearStoredModelVariant(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n modelVariant: null,\n });\n}\n\nexport async function clearStoredSessionContext(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n sessionId: null,\n projectId: null,\n directory: null,\n });\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeAgent,\n OpenCodeClientLike,\n} from \"../services/opencode/opencode.client.js\";\nimport { getSelectableAgents, resolveSelectedAgent } from \"./agent-selection.js\";\nimport { clearStoredAgentSelection } from \"./binding-update.js\";\n\nexport interface ListAgentsResult {\n agents: OpenCodeAgent[];\n currentAgentName: string | null;\n}\n\nexport class ListAgentsUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListAgentsResult> {\n let [binding, agents] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listAgents(),\n ]);\n const visibleAgents = getSelectableAgents(agents);\n const currentAgent = resolveSelectedAgent(visibleAgents, binding?.agentName);\n\n if (binding?.agentName && currentAgent?.name !== binding.agentName) {\n binding = await clearStoredAgentSelection(this.sessionRepo, binding);\n }\n\n return {\n agents: visibleAgents,\n currentAgentName: currentAgent?.name ?? null,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeLspStatus,\n OpenCodeProject,\n} from \"../services/opencode/opencode.client.js\";\nimport { clearStoredSessionContext } from \"./binding-update.js\";\n\nexport interface ListLspResult {\n currentDirectory: string;\n statuses: OpenCodeLspStatus[];\n}\n\nexport class ListLspUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListLspResult> {\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n\n if (binding?.projectId && binding.directory) {\n const projects = await this.opencodeClient.listProjects();\n\n if (!hasMatchingProject(projects, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n }\n\n const projectContext = binding?.projectId && binding.directory\n ? {\n projectId: binding.projectId,\n directory: binding.directory,\n }\n : await this.getCurrentProjectContext();\n const statuses = await this.opencodeClient.listLspStatuses(projectContext.directory);\n\n return {\n currentDirectory: projectContext.directory,\n statuses: [...statuses].sort(compareLspStatuses),\n };\n }\n\n private async getCurrentProjectContext() {\n const currentProject = await this.opencodeClient.getCurrentProject();\n\n return {\n projectId: currentProject.id,\n directory: currentProject.worktree,\n };\n }\n}\n\nfunction compareLspStatuses(left: OpenCodeLspStatus, right: OpenCodeLspStatus): number {\n return left.name.localeCompare(right.name)\n || left.root.localeCompare(right.root)\n || left.id.localeCompare(right.id);\n}\n\nfunction hasMatchingProject(projects: OpenCodeProject[], binding: ChatSessionBinding): boolean {\n return projects.some((project) =>\n project.id === binding.projectId && project.worktree === binding.directory,\n );\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeMcpStatus,\n OpenCodeProject,\n} from \"../services/opencode/opencode.client.js\";\nimport { clearStoredSessionContext } from \"./binding-update.js\";\n\nexport interface ListMcpEntry {\n name: string;\n status: OpenCodeMcpStatus;\n}\n\nexport interface ListMcpResult {\n currentDirectory: string;\n statuses: ListMcpEntry[];\n}\n\nexport class ListMcpUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListMcpResult> {\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n\n if (binding?.projectId && binding.directory) {\n const projects = await this.opencodeClient.listProjects();\n\n if (!hasMatchingProject(projects, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n }\n\n const projectContext = binding?.projectId && binding.directory\n ? {\n projectId: binding.projectId,\n directory: binding.directory,\n }\n : await this.getCurrentProjectContext();\n const statuses = await this.opencodeClient.listMcpStatuses(projectContext.directory);\n\n return {\n currentDirectory: projectContext.directory,\n statuses: Object.entries(statuses)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([name, status]) => ({ name, status })),\n };\n }\n\n private async getCurrentProjectContext() {\n const currentProject = await this.opencodeClient.getCurrentProject();\n\n return {\n projectId: currentProject.id,\n directory: currentProject.worktree,\n };\n }\n}\n\nfunction hasMatchingProject(projects: OpenCodeProject[], binding: ChatSessionBinding): boolean {\n return projects.some((project) =>\n project.id === binding.projectId && project.worktree === binding.directory,\n );\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeConfiguredModel,\n} from \"../services/opencode/opencode.client.js\";\nimport {\n clearStoredModelSelection,\n clearStoredModelVariant,\n} from \"./binding-update.js\";\n\nexport interface ListModelsResult {\n models: OpenCodeConfiguredModel[];\n currentModelProviderId: string | null;\n currentModelId: string | null;\n currentModelVariant: string | null;\n}\n\nexport class ListModelsUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListModelsResult> {\n let [binding, models] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listModels(),\n ]);\n\n if (binding?.modelProviderId && binding?.modelId) {\n const selectedModel = models.find((model) =>\n model.providerID === binding?.modelProviderId && model.id === binding?.modelId,\n );\n\n if (!selectedModel) {\n binding = await clearStoredModelSelection(this.sessionRepo, binding);\n } else if (binding.modelVariant && !(binding.modelVariant in selectedModel.variants)) {\n binding = await clearStoredModelVariant(this.sessionRepo, binding);\n }\n }\n\n return {\n models,\n currentModelProviderId: binding?.modelProviderId ?? null,\n currentModelId: binding?.modelId ?? null,\n currentModelVariant: binding?.modelVariant ?? null,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeProject,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\nimport { clearStoredSessionContext } from \"./binding-update.js\";\n\nexport interface ListSessionsResult {\n sessions: OpenCodeSession[];\n currentProjectId: string;\n currentDirectory: string;\n currentSessionId: string | null;\n}\n\nexport class ListSessionsUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListSessionsResult> {\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n const [sessions, projects] = await Promise.all([\n this.opencodeClient.listSessions(),\n binding?.projectId && binding.directory\n ? this.opencodeClient.listProjects()\n : Promise.resolve<OpenCodeProject[] | null>(null),\n ]);\n\n if (binding?.projectId && binding.directory && !hasMatchingProject(projects, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n\n if (binding?.sessionId && binding.projectId && !hasMatchingSession(sessions, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n\n const projectContext = binding?.projectId && binding.directory\n ? {\n projectId: binding.projectId,\n directory: binding.directory,\n }\n : await this.getCurrentProjectContext();\n\n return {\n sessions: sessions.filter((session) => session.projectID === projectContext.projectId),\n currentProjectId: projectContext.projectId,\n currentDirectory: projectContext.directory,\n currentSessionId: binding?.projectId === projectContext.projectId ? binding.sessionId : null,\n };\n }\n\n private async getCurrentProjectContext() {\n const currentProject = await this.opencodeClient.getCurrentProject();\n\n return {\n projectId: currentProject.id,\n directory: currentProject.worktree,\n };\n }\n}\n\nfunction hasMatchingProject(\n projects: OpenCodeProject[] | null,\n binding: ChatSessionBinding,\n): boolean {\n if (!projects) {\n return true;\n }\n\n return projects.some((project) =>\n project.id === binding.projectId && project.worktree === binding.directory,\n );\n}\n\nfunction hasMatchingSession(\n sessions: OpenCodeSession[],\n binding: ChatSessionBinding,\n): boolean {\n return sessions.some((session) =>\n session.id === binding.sessionId && session.projectID === binding.projectId,\n );\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type { OpenCodeClientLike, OpenCodeSession } from \"../services/opencode/opencode.client.js\";\n\nexport type RenameSessionResult =\n | {\n found: false;\n }\n | {\n found: true;\n session: OpenCodeSession;\n };\n\nexport class RenameSessionUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; sessionId: string; title: string }): Promise<RenameSessionResult> {\n const title = input.title.trim();\n\n if (!title) {\n throw new Error(\"Session title cannot be empty.\");\n }\n\n const [binding, sessions] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listSessions(),\n ]);\n const currentProjectId = binding?.projectId ?? (await this.opencodeClient.getCurrentProject()).id;\n const session = sessions.find((item) => item.id === input.sessionId && item.projectID === currentProjectId);\n\n if (!session) {\n return { found: false };\n }\n\n const renamedSession = await this.opencodeClient.renameSession(session.id, title);\n\n this.logger.info(\n {\n chatId: input.chatId,\n sessionId: renamedSession.id,\n projectId: renamedSession.projectID,\n title: renamedSession.title,\n },\n \"session renamed\",\n );\n\n return {\n found: true,\n session: renamedSession,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport {\n logOpenCodeRequest,\n logPromptLifecycle,\n type AppLogger,\n} from \"../infra/logger/index.js\";\nimport type {\n OpenCodeClientLike,\n PromptSessionFilePartInput,\n} from \"../services/opencode/opencode.client.js\";\nimport { resolveSelectedAgent } from \"./agent-selection.js\";\nimport {\n clearStoredAgentSelection,\n clearStoredModelSelection,\n clearStoredModelVariant,\n clearStoredSessionContext,\n} from \"./binding-update.js\";\nimport { createAndBindCurrentProjectSession } from \"./session-creation.js\";\n\ntype ActiveChatBinding = ChatSessionBinding & {\n directory: string;\n projectId: string;\n sessionId: string;\n};\n\nexport class SendPromptUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: {\n chatId: number;\n files?: PromptSessionFilePartInput[];\n onExecutionSession?: (sessionId: string) => void;\n signal?: AbortSignal;\n text?: string | null;\n }) {\n const files = input.files ?? [];\n const promptText = buildPromptText(input.text, files);\n\n if (!promptText && files.length === 0) {\n throw new Error(\"Prompt requires text or file attachments.\");\n }\n\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n\n if (binding?.projectId && binding.directory) {\n const projects = await this.opencodeClient.listProjects();\n const selectedProject = projects.find((project) =>\n project.id === binding?.projectId && project.worktree === binding.directory,\n );\n\n if (!selectedProject) {\n binding = await this.clearInvalidSessionContext(\n input.chatId,\n binding,\n \"saved project is no longer available\",\n );\n }\n }\n\n if (binding?.sessionId && binding.projectId) {\n const sessions = await this.opencodeClient.listSessions();\n const selectedSession = sessions.find((session) =>\n session.id === binding?.sessionId && session.projectID === binding.projectId,\n );\n\n if (!selectedSession) {\n binding = await this.clearInvalidSessionContext(\n input.chatId,\n binding,\n \"saved session is no longer available\",\n );\n }\n }\n\n if (!binding || !binding.sessionId || !binding.projectId || !binding.directory) {\n const createdSession = await createAndBindCurrentProjectSession(\n this.sessionRepo,\n this.opencodeClient,\n {\n chatId: input.chatId,\n binding,\n },\n );\n binding = createdSession.binding;\n logPromptLifecycle(\n this.logger,\n {\n chatId: input.chatId,\n event: \"prompt.session.created\",\n projectId: createdSession.session.projectID,\n sessionId: createdSession.session.id,\n directory: createdSession.session.directory,\n },\n \"session created\",\n );\n }\n\n if (binding?.modelProviderId && binding?.modelId) {\n const availableModels = await this.opencodeClient.listModels();\n const selectedModel = availableModels.find((model) =>\n model.providerID === binding?.modelProviderId && model.id === binding?.modelId,\n );\n\n if (!selectedModel) {\n binding = await clearStoredModelSelection(this.sessionRepo, binding);\n this.logger.warn?.(\n {\n chatId: input.chatId,\n event: \"prompt.model.unavailable\",\n },\n \"selected model is no longer available, falling back to OpenCode default\",\n );\n } else if (binding.modelVariant && !(binding.modelVariant in selectedModel.variants)) {\n binding = await clearStoredModelVariant(this.sessionRepo, binding);\n this.logger.warn?.(\n {\n chatId: input.chatId,\n event: \"prompt.model.variant_unavailable\",\n providerId: selectedModel.providerID,\n modelId: selectedModel.id,\n },\n \"selected model variant is no longer available, falling back to default variant\",\n );\n }\n }\n\n if (!binding || !binding.sessionId || !binding.projectId) {\n throw new Error(\"Failed to initialize chat session.\");\n }\n\n let activeBinding = binding as ActiveChatBinding;\n const shouldIsolateImageTurn = hasImageFiles(files);\n const model = activeBinding.modelProviderId && activeBinding.modelId\n ? {\n providerID: activeBinding.modelProviderId,\n modelID: activeBinding.modelId,\n }\n : null;\n const availableAgents = await this.opencodeClient.listAgents();\n const selectedAgent = resolveSelectedAgent(availableAgents, activeBinding.agentName);\n\n if (activeBinding.agentName && selectedAgent?.name !== activeBinding.agentName) {\n activeBinding = await clearStoredAgentSelection(this.sessionRepo, activeBinding) as ActiveChatBinding;\n this.logger.warn?.(\n {\n chatId: input.chatId,\n event: \"prompt.agent.unavailable\",\n },\n \"selected agent is no longer available, falling back to OpenCode default\",\n );\n }\n\n const temporarySessionId = shouldIsolateImageTurn\n ? await this.createTemporaryImageSession(input.chatId, activeBinding.sessionId)\n : null;\n const executionSessionId = temporarySessionId ?? activeBinding.sessionId;\n\n input.onExecutionSession?.(executionSessionId);\n let result;\n\n try {\n logOpenCodeRequest(this.logger, {\n chatId: input.chatId,\n event: \"opencode.prompt.submit\",\n projectId: activeBinding.projectId,\n sessionId: executionSessionId,\n fileCount: files.length,\n status: \"started\",\n }, \"submitting OpenCode prompt\");\n result = await this.opencodeClient.promptSession({\n sessionId: executionSessionId,\n prompt: promptText,\n ...(files.length > 0 ? { files } : {}),\n ...(selectedAgent ? { agent: selectedAgent.name } : {}),\n format: {\n type: \"text\",\n },\n ...(model ? { model } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n ...(activeBinding.modelVariant ? { variant: activeBinding.modelVariant } : {}),\n });\n logPromptLifecycle(this.logger, {\n chatId: input.chatId,\n event: \"prompt.completed\",\n projectId: activeBinding.projectId,\n sessionId: executionSessionId,\n status: \"completed\",\n }, \"prompt completed\");\n } finally {\n if (temporarySessionId) {\n await this.cleanupTemporaryImageSession(\n input.chatId,\n activeBinding.sessionId,\n temporarySessionId,\n );\n }\n }\n\n await this.sessionRepo.touch(input.chatId);\n\n return {\n assistantReply: result,\n sessionId: activeBinding.sessionId,\n projectId: activeBinding.projectId,\n };\n }\n\n private async clearInvalidSessionContext(\n chatId: number,\n binding: ChatSessionBinding,\n reason: string,\n ) {\n const nextBinding = await clearStoredSessionContext(this.sessionRepo, binding);\n this.logger.warn?.(\n {\n chatId,\n event: \"prompt.session.invalid_context\",\n },\n `${reason}, falling back to the current OpenCode project`,\n );\n\n return nextBinding;\n }\n\n private async createTemporaryImageSession(chatId: number, sessionId: string): Promise<string> {\n const temporarySession = await this.opencodeClient.forkSession(sessionId);\n\n if (!temporarySession.id || temporarySession.id === sessionId) {\n throw new Error(\"OpenCode did not return a distinct temporary session for the image turn.\");\n }\n\n logPromptLifecycle(\n this.logger,\n {\n chatId,\n event: \"prompt.temporary_session.created\",\n parentSessionId: sessionId,\n sessionId: temporarySession.id,\n },\n \"created temporary image session\",\n );\n\n return temporarySession.id;\n }\n\n private async cleanupTemporaryImageSession(\n chatId: number,\n parentSessionId: string,\n sessionId: string,\n ): Promise<void> {\n try {\n const deleted = await this.opencodeClient.deleteSession(sessionId);\n\n if (!deleted) {\n this.logger.warn?.(\n {\n chatId,\n event: \"prompt.temporary_session.cleanup_failed\",\n parentSessionId,\n sessionId,\n },\n \"failed to delete temporary image session\",\n );\n }\n } catch (error) {\n this.logger.warn?.(\n {\n error,\n chatId,\n event: \"prompt.temporary_session.cleanup_failed\",\n parentSessionId,\n sessionId,\n },\n \"failed to delete temporary image session\",\n );\n }\n }\n}\n\nfunction buildPromptText(\n text: string | null | undefined,\n files: PromptSessionFilePartInput[],\n): string {\n const trimmedText = text?.trim() ?? \"\";\n\n if (!files.some(isImageFile)) {\n return trimmedText;\n }\n\n const promptSections = [\n [\n \"System note for this turn:\",\n \"The user attached one or more images in this message and you can inspect those images directly.\",\n \"Ignore any earlier statements in this conversation claiming that you could not view images or attachments, because those may have come from a previous model or an earlier limitation.\",\n \"If an image is blurry or unreadable, say that it is blurry or unreadable instead of saying that you cannot view images.\",\n ].join(\" \"),\n ];\n\n if (trimmedText) {\n promptSections.push(trimmedText);\n }\n\n return promptSections.join(\"\\n\\n\");\n}\n\nfunction isImageFile(file: PromptSessionFilePartInput): boolean {\n return file.mime.trim().toLowerCase().startsWith(\"image/\");\n}\n\nfunction hasImageFiles(files: PromptSessionFilePartInput[]): boolean {\n return files.some(isImageFile);\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type {\n OpenCodeAgent,\n OpenCodeClientLike,\n} from \"../services/opencode/opencode.client.js\";\nimport { isSelectableAgent } from \"./agent-selection.js\";\n\nexport type SwitchAgentResult =\n | {\n found: false;\n }\n | {\n found: true;\n agent: OpenCodeAgent;\n };\n\nexport class SwitchAgentUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; agentName: string }): Promise<SwitchAgentResult> {\n const [binding, agents] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listAgents(),\n ]);\n const agent = agents.find((item) => item.name === input.agentName && isSelectableAgent(item));\n\n if (!agent) {\n return { found: false };\n }\n\n await this.sessionRepo.setCurrent({\n chatId: input.chatId,\n sessionId: binding?.sessionId ?? null,\n projectId: binding?.projectId ?? null,\n directory: binding?.directory ?? null,\n agentName: agent.name,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n });\n\n this.logger.info(\n {\n chatId: input.chatId,\n agentName: agent.name,\n },\n \"agent switched\",\n );\n\n return {\n found: true,\n agent,\n };\n }\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeConfiguredModel,\n} from \"../services/opencode/opencode.client.js\";\n\nexport type SwitchModelResult =\n | {\n found: false;\n }\n | {\n found: true;\n model: OpenCodeConfiguredModel;\n variant: string | null;\n };\n\nexport class SwitchModelUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: {\n chatId: number;\n providerId: string;\n modelId: string;\n variant?: string | null;\n }): Promise<SwitchModelResult> {\n const [binding, models] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listModels(),\n ]);\n const model = models.find((item) =>\n item.providerID === input.providerId && item.id === input.modelId,\n );\n\n if (!model) {\n return { found: false };\n }\n\n const variant = input.variant ?? null;\n\n if (variant && !(variant in model.variants)) {\n return { found: false };\n }\n\n await this.sessionRepo.setCurrent({\n chatId: input.chatId,\n sessionId: binding?.sessionId ?? null,\n projectId: binding?.projectId ?? null,\n directory: binding?.directory ?? null,\n agentName: binding?.agentName ?? null,\n modelProviderId: model.providerID,\n modelId: model.id,\n modelVariant: variant,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n });\n\n this.logger.info(\n {\n chatId: input.chatId,\n providerId: model.providerID,\n modelId: model.id,\n variant,\n },\n \"model switched\",\n );\n\n return {\n found: true,\n model,\n variant,\n };\n }\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type { OpenCodeClientLike, OpenCodeSession } from \"../services/opencode/opencode.client.js\";\n\nexport type SwitchSessionResult =\n | {\n found: false;\n }\n | {\n found: true;\n session: OpenCodeSession;\n };\n\nexport class SwitchSessionUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; sessionId: string }): Promise<SwitchSessionResult> {\n const [binding, sessions] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listSessions(),\n ]);\n const currentProjectId = binding?.projectId ?? (await this.opencodeClient.getCurrentProject()).id;\n const session = sessions.find((item) => item.id === input.sessionId && item.projectID === currentProjectId);\n\n if (!session) {\n return { found: false };\n }\n\n await this.sessionRepo.setCurrent({\n chatId: input.chatId,\n sessionId: session.id,\n projectId: session.projectID,\n directory: session.directory,\n agentName: binding?.agentName ?? null,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n });\n\n this.logger.info(\n {\n chatId: input.chatId,\n sessionId: session.id,\n projectId: session.projectID,\n directory: session.directory,\n },\n \"session switched\",\n );\n\n return {\n found: true,\n session,\n };\n }\n}\n","import type { PromptSessionFilePartInput } from \"../services/opencode/opencode.client.js\";\nimport {\n TelegramFileDownloadError,\n type TelegramFileClientLike,\n} from \"../services/telegram/telegram.client.js\";\n\nexport interface UploadFileInput {\n expectedType: \"image\";\n filePath: string;\n filename?: string | null;\n mimeType?: string | null;\n}\n\nexport class ImageFileDownloadError extends Error {\n readonly data: { message: string };\n\n constructor(message: string) {\n super(message);\n this.name = \"ImageFileDownloadError\";\n this.data = { message };\n }\n}\n\nexport class ImageMessageUnsupportedError extends Error {\n readonly data: { message: string };\n\n constructor(message: string) {\n super(message);\n this.name = \"ImageMessageUnsupportedError\";\n this.data = { message };\n }\n}\n\nexport class UploadFileUseCase {\n constructor(private readonly telegramFileClient: TelegramFileClientLike) { }\n\n async execute(input: UploadFileInput): Promise<PromptSessionFilePartInput> {\n if (input.expectedType !== \"image\") {\n throw new ImageMessageUnsupportedError(\"Only image uploads are supported.\");\n }\n\n let download;\n\n try {\n download = await this.telegramFileClient.downloadFile({\n filePath: input.filePath,\n });\n } catch (error) {\n if (error instanceof TelegramFileDownloadError) {\n throw new ImageFileDownloadError(error.message);\n }\n\n throw error;\n }\n\n const mimeType = normalizeMimeType(input.mimeType ?? download.mimeType);\n\n if (!mimeType.startsWith(\"image/\")) {\n throw new ImageMessageUnsupportedError(`Unsupported image MIME type: ${mimeType}`);\n }\n\n const filename = resolveFilename(input.filename, input.filePath, mimeType);\n\n return {\n filename,\n mime: mimeType,\n url: buildDataUrl(download.data, mimeType),\n };\n }\n}\n\nfunction buildDataUrl(data: Uint8Array, mimeType: string): string {\n const buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength);\n\n return `data:${mimeType};base64,${buffer.toString(\"base64\")}`;\n}\n\nfunction normalizeMimeType(value: string | null): string {\n const normalized = value?.trim().toLowerCase();\n\n return normalized && normalized.length > 0\n ? normalized\n : \"application/octet-stream\";\n}\n\nfunction resolveFilename(\n explicitFilename: string | null | undefined,\n filePath: string,\n mimeType: string,\n): string {\n const preferredFilename = explicitFilename?.trim();\n\n if (preferredFilename) {\n return preferredFilename;\n }\n\n const filePathFilename = filePath.split(\"/\").at(-1)?.trim();\n\n if (filePathFilename) {\n return filePathFilename;\n }\n\n return `telegram-upload${resolveExtension(mimeType)}`;\n}\n\nfunction resolveExtension(mimeType: string): string {\n switch (mimeType) {\n case \"image/jpeg\":\n return \".jpg\";\n case \"image/png\":\n return \".png\";\n case \"image/webp\":\n return \".webp\";\n case \"image/gif\":\n return \".gif\";\n default:\n return \"\";\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { BotDependencies } from \"../bot/types.js\";\nimport type { PermissionApprovalRepository } from \"../domain/permission/approval.repository.js\";\nimport { createOpenCodeAppLogger } from \"../infra/logger/index.js\";\nimport { FilePendingActionRepository } from \"../repositories/pending-action.repo.js\";\nimport { FilePermissionApprovalRepository } from \"../repositories/permission-approval.repo.js\";\nimport { FileSessionRepository } from \"../repositories/session.repo.js\";\nimport {\n createOpenCodeClientFromSdkClient,\n type OpenCodeClientLike,\n type OpenCodeSdkClientLike,\n} from \"../services/opencode/opencode.client.js\";\nimport { createDefaultOpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport { JsonStateStore } from \"../services/storage/json-state-store.js\";\nimport { TelegramFileClient } from \"../services/telegram/telegram.client.js\";\nimport { ForegroundSessionTracker } from \"../services/session-activity/foreground-session-tracker.js\";\nimport { AbortPromptUseCase } from \"../use-cases/abort-prompt.usecase.js\";\nimport { CreateSessionUseCase } from \"../use-cases/create-session.usecase.js\";\nimport { GetHealthUseCase } from \"../use-cases/get-health.usecase.js\";\nimport { GetPathUseCase } from \"../use-cases/get-path.usecase.js\";\nimport { GetStatusUseCase } from \"../use-cases/get-status.usecase.js\";\nimport { ListAgentsUseCase } from \"../use-cases/list-agents.usecase.js\";\nimport { ListLspUseCase } from \"../use-cases/list-lsp.usecase.js\";\nimport { ListMcpUseCase } from \"../use-cases/list-mcp.usecase.js\";\nimport { ListModelsUseCase } from \"../use-cases/list-models.usecase.js\";\nimport { ListSessionsUseCase } from \"../use-cases/list-sessions.usecase.js\";\nimport { RenameSessionUseCase } from \"../use-cases/rename-session.usecase.js\";\nimport { SendPromptUseCase } from \"../use-cases/send-prompt.usecase.js\";\nimport { SwitchAgentUseCase } from \"../use-cases/switch-agent.usecase.js\";\nimport { SwitchModelUseCase } from \"../use-cases/switch-model.usecase.js\";\nimport { SwitchSessionUseCase } from \"../use-cases/switch-session.usecase.js\";\nimport { UploadFileUseCase } from \"../use-cases/upload-file.usecase.js\";\nimport type { AppConfig } from \"./config.js\";\n\nexport interface AppContainer extends BotDependencies {\n opencodeClient: OpenCodeClientLike;\n foregroundSessionTracker: ForegroundSessionTracker;\n permissionApprovalRepo: PermissionApprovalRepository;\n dispose(): Promise<void>;\n}\n\nexport function createAppContainer(\n config: AppConfig,\n client: OpenCodeSdkClientLike,\n): AppContainer {\n const runtimeId = randomUUID();\n const logger = createOpenCodeAppLogger(client, {\n file: {\n dir: config.loggingFileDir,\n retention: {\n maxFiles: config.loggingRetentionMaxFiles,\n maxTotalBytes: config.loggingRetentionMaxTotalBytes,\n },\n },\n level: config.loggingLevel,\n runtimeId,\n sinks: {\n file: config.loggingFileSinkEnabled,\n host: config.loggingHostSinkEnabled,\n },\n worktree: config.worktreePath,\n });\n\n return createContainer(\n config,\n createOpenCodeClientFromSdkClient(\n client,\n fetch,\n {\n waitTimeoutMs: config.promptWaitTimeoutMs,\n pollRequestTimeoutMs: config.promptPollRequestTimeoutMs,\n recoveryInactivityTimeoutMs: config.promptRecoveryInactivityTimeoutMs,\n },\n ),\n logger,\n );\n}\n\nfunction createContainer(\n config: AppConfig,\n opencodeClient: OpenCodeClientLike,\n logger: BotDependencies[\"logger\"],\n): AppContainer {\n const storageLogger = logger.child({ component: \"storage\" });\n const opencodeLogger = logger.child({ component: \"opencode\" });\n const promptLogger = logger.child({ component: \"prompt\" });\n const stateStore = new JsonStateStore({\n filePath: config.stateFilePath,\n createDefaultState: createDefaultOpencodeTbotState,\n });\n const pendingActionRepo = new FilePendingActionRepository(stateStore);\n const permissionApprovalRepo = new FilePermissionApprovalRepository(stateStore);\n const sessionRepo = new FileSessionRepository(stateStore);\n const foregroundSessionTracker = new ForegroundSessionTracker();\n const telegramFileClient = new TelegramFileClient({\n botToken: config.telegramBotToken,\n apiRoot: config.telegramApiRoot,\n });\n const uploadFileUseCase = new UploadFileUseCase(telegramFileClient);\n const abortPromptUseCase = new AbortPromptUseCase(\n sessionRepo,\n opencodeClient,\n foregroundSessionTracker,\n );\n const createSessionUseCase = new CreateSessionUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const getHealthUseCase = new GetHealthUseCase(opencodeClient);\n const getPathUseCase = new GetPathUseCase(opencodeClient);\n const listAgentsUseCase = new ListAgentsUseCase(sessionRepo, opencodeClient);\n const listLspUseCase = new ListLspUseCase(sessionRepo, opencodeClient);\n const listMcpUseCase = new ListMcpUseCase(sessionRepo, opencodeClient);\n const listSessionsUseCase = new ListSessionsUseCase(sessionRepo, opencodeClient);\n const getStatusUseCase = new GetStatusUseCase(\n getHealthUseCase,\n getPathUseCase,\n listLspUseCase,\n listMcpUseCase,\n listSessionsUseCase,\n sessionRepo,\n opencodeClient as {\n listConfiguredPlugins(): Promise<string[]>;\n },\n );\n const listModelsUseCase = new ListModelsUseCase(sessionRepo, opencodeClient);\n const renameSessionUseCase = new RenameSessionUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const sendPromptUseCase = new SendPromptUseCase(\n sessionRepo,\n opencodeClient,\n promptLogger,\n );\n const switchAgentUseCase = new SwitchAgentUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const switchModelUseCase = new SwitchModelUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const switchSessionUseCase = new SwitchSessionUseCase(sessionRepo, opencodeClient, opencodeLogger);\n let disposed = false;\n\n return {\n abortPromptUseCase,\n createSessionUseCase,\n getHealthUseCase,\n getPathUseCase,\n getStatusUseCase,\n listAgentsUseCase,\n listLspUseCase,\n listMcpUseCase,\n logger,\n listModelsUseCase,\n listSessionsUseCase,\n pendingActionRepo,\n renameSessionUseCase,\n sessionRepo,\n sendPromptUseCase,\n switchAgentUseCase,\n switchModelUseCase,\n switchSessionUseCase,\n telegramFileClient,\n uploadFileUseCase,\n opencodeClient,\n foregroundSessionTracker,\n permissionApprovalRepo,\n async dispose() {\n if (disposed) {\n return;\n }\n\n disposed = true;\n storageLogger.info(\n {\n event: \"storage.container.disposed\",\n filePath: config.stateFilePath,\n },\n \"disposing telegram bot container\",\n );\n await logger.flush();\n },\n };\n}\n","import {\n loadAppConfig,\n type LoadAppConfigOptions,\n type AppConfig,\n type PluginConfigSource,\n} from \"./config.js\";\nimport {\n createAppContainer,\n type AppContainer,\n} from \"./container.js\";\nimport type { OpenCodeSdkClientLike } from \"../services/opencode/opencode.client.js\";\n\nexport function bootstrapPluginApp(\n client: OpenCodeSdkClientLike,\n configSource: PluginConfigSource | undefined = {},\n options: LoadAppConfigOptions = {},\n): { config: AppConfig; container: AppContainer } {\n const config = loadAppConfig(configSource, options);\n\n return {\n config,\n container: createAppContainer(config, client),\n };\n}\n","import type { PermissionApprovalReply } from \"../../domain/permission/approval.entity.js\";\nimport type { PermissionApprovalCallbackData } from \"../../bot/types.js\";\nimport type { OpenCodePermissionRequest } from \"../opencode/opencode.client.js\";\n\nexport function buildPermissionApprovalMessage(\n request: OpenCodePermissionRequest,\n): string {\n const patterns = request.patterns.length > 0\n ? request.patterns.map((pattern) => `- ${pattern}`).join(\"\\n\")\n : \"- (none)\";\n\n return [\n \"*Permission Request*\",\n \"\",\n `Permission: \\`${escapeMarkdownV2(request.permission)}\\``,\n `Session: \\`${escapeMarkdownV2(request.sessionID)}\\``,\n \"\",\n \"Patterns:\",\n patterns,\n ].join(\"\\n\");\n}\n\nexport function buildPermissionApprovalResolvedMessage(\n requestId: string,\n reply: PermissionApprovalReply,\n): string {\n return [\n \"Permission request resolved.\",\n \"\",\n `Request: ${requestId}`,\n `Reply: ${reply}`,\n ].join(\"\\n\");\n}\n\nexport function buildPermissionApprovalKeyboard(requestId: string) {\n return {\n inline_keyboard: [[\n {\n text: \"Allow once\",\n callback_data: buildPermissionApprovalCallbackData(\"once\", requestId),\n },\n {\n text: \"Always allow\",\n callback_data: buildPermissionApprovalCallbackData(\"always\", requestId),\n },\n {\n text: \"Reject\",\n callback_data: buildPermissionApprovalCallbackData(\"reject\", requestId),\n },\n ]],\n };\n}\n\nexport function buildPermissionApprovalCallbackData(\n reply: PermissionApprovalReply,\n requestId: string,\n): PermissionApprovalCallbackData {\n return `permission:${reply}:${requestId}`;\n}\n\nexport function parsePermissionApprovalCallbackData(data: string): {\n reply: PermissionApprovalReply;\n requestId: string;\n} | null {\n if (!data.startsWith(\"permission:\")) {\n return null;\n }\n\n const [, reply, requestId] = data.split(\":\", 3);\n\n if (!requestId || !isPermissionApprovalReply(reply)) {\n return null;\n }\n\n return {\n reply,\n requestId,\n };\n}\n\nfunction isPermissionApprovalReply(value: string): value is PermissionApprovalReply {\n return value === \"once\" || value === \"always\" || value === \"reject\";\n}\n\nfunction escapeMarkdownV2(value: string): string {\n return value.replaceAll(/([_*\\[\\]()~`>#+\\-=|{}.!\\\\])/g, \"\\\\$1\");\n}\n","import type { Event as OpenCodeEvent } from \"@opencode-ai/sdk\";\nimport type { PendingPermissionApproval, PermissionApprovalReply } from \"../domain/permission/approval.entity.js\";\nimport { logPluginEvent } from \"../infra/logger/index.js\";\nimport type { OpenCodePermissionRequest } from \"../services/opencode/opencode.client.js\";\nimport {\n buildPermissionApprovalKeyboard,\n buildPermissionApprovalMessage,\n buildPermissionApprovalResolvedMessage,\n} from \"../services/permission/telegram-approval.js\";\nimport type { TelegramBotRuntime } from \"./runtime.js\";\n\ntype OpenCodePluginEvent = OpenCodeEvent | {\n properties?: unknown;\n type: string;\n};\n\ninterface NormalizedPermissionReplyEvent {\n reply: PermissionApprovalReply;\n requestId: string;\n sessionId: string;\n}\n\ninterface NormalizedSessionErrorEvent {\n error: unknown;\n sessionId: string;\n}\n\ninterface NormalizedSessionIdleEvent {\n sessionId: string;\n}\n\ninterface NormalizedSessionStatusEvent extends NormalizedSessionIdleEvent {\n statusType: string;\n}\n\nexport async function handleTelegramBotPluginEvent(\n runtime: TelegramBotRuntime,\n event: OpenCodePluginEvent,\n): Promise<void> {\n switch (event.type) {\n case \"permission.asked\":\n case \"permission.updated\": {\n const request = normalizePermissionRequestEvent(event.properties);\n\n if (request) {\n await handlePermissionAsked(runtime, request);\n }\n return;\n }\n case \"permission.replied\": {\n const replyEvent = normalizePermissionReplyEvent(event.properties);\n\n if (replyEvent) {\n await handlePermissionReplied(runtime, replyEvent);\n }\n return;\n }\n case \"session.error\": {\n const sessionError = normalizeSessionErrorEvent(event.properties);\n\n if (sessionError) {\n await handleSessionError(runtime, sessionError);\n }\n return;\n }\n case \"session.idle\": {\n const sessionIdle = normalizeSessionIdleEvent(event.properties);\n\n if (sessionIdle) {\n await handleSessionIdle(runtime, sessionIdle);\n }\n return;\n }\n case \"session.status\": {\n const sessionStatus = normalizeSessionStatusEvent(event.properties);\n\n if (sessionStatus) {\n await handleSessionStatus(runtime, sessionStatus);\n }\n return;\n }\n default:\n return;\n }\n}\n\nasync function handlePermissionAsked(\n runtime: TelegramBotRuntime,\n request: OpenCodePermissionRequest,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n requestId: request.id,\n sessionId: request.sessionID,\n });\n const bindings = await runtime.container.sessionRepo.listBySessionId(request.sessionID);\n const chatIds = new Set([\n ...bindings.map((binding) => binding.chatId),\n ...runtime.container.foregroundSessionTracker.listChatIds(request.sessionID),\n ]);\n const approvals = await runtime.container.permissionApprovalRepo.listByRequestId(request.id);\n const approvedChatIds = new Set(approvals.map((approval) => approval.chatId));\n\n for (const chatId of chatIds) {\n if (approvedChatIds.has(chatId)) {\n continue;\n }\n\n try {\n const message = await runtime.bot.api.sendMessage(\n chatId,\n buildPermissionApprovalMessage(request),\n {\n parse_mode: \"MarkdownV2\",\n reply_markup: buildPermissionApprovalKeyboard(request.id),\n },\n );\n\n await runtime.container.permissionApprovalRepo.set({\n requestId: request.id,\n sessionId: request.sessionID,\n chatId,\n messageId: message.message_id,\n status: \"pending\",\n updatedAt: new Date().toISOString(),\n });\n } catch (error) {\n logger.error(\n {\n error,\n chatId,\n event: \"plugin-event.permission.ask.delivery_failed\",\n requestId: request.id,\n },\n \"failed to deliver permission request to Telegram\",\n );\n }\n }\n}\n\nasync function handlePermissionReplied(\n runtime: TelegramBotRuntime,\n event: NormalizedPermissionReplyEvent,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n event: \"plugin-event.permission.replied\",\n requestId: event.requestId,\n sessionId: event.sessionId,\n });\n const approvals = await runtime.container.permissionApprovalRepo.listByRequestId(event.requestId);\n\n await Promise.all(\n approvals.map(async (approval) => {\n try {\n await runtime.bot.api.editMessageText(\n approval.chatId,\n approval.messageId,\n buildPermissionApprovalResolvedMessage(event.requestId, event.reply),\n );\n } catch (error) {\n logger.warn(\n {\n error,\n chatId: approval.chatId,\n event: \"plugin-event.permission.reply_message_failed\",\n },\n \"failed to update Telegram permission message\",\n );\n }\n\n await runtime.container.permissionApprovalRepo.set(toResolvedApproval(approval, event.reply));\n }),\n );\n}\n\nasync function handleSessionError(\n runtime: TelegramBotRuntime,\n event: NormalizedSessionErrorEvent,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n sessionId: event.sessionId,\n });\n const wasForeground = runtime.container.foregroundSessionTracker.fail(\n event.sessionId,\n normalizeForegroundSessionError(event.error),\n );\n\n if (wasForeground) {\n logger.warn(\n {\n error: event.error,\n event: \"plugin-event.session.error.foreground_suppressed\",\n },\n \"session error suppressed for foreground Telegram session\",\n );\n return;\n }\n\n const message = extractSessionErrorMessage(event.error) ?? \"Unknown session error.\";\n\n await notifyBoundChats(runtime, event.sessionId, `Session failed.\\n\\nSession: ${event.sessionId}\\nError: ${message}`);\n}\n\nasync function handleSessionIdle(\n runtime: TelegramBotRuntime,\n event: NormalizedSessionIdleEvent,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n sessionId: event.sessionId,\n });\n const wasForeground = runtime.container.foregroundSessionTracker.clear(event.sessionId);\n\n if (wasForeground) {\n logPluginEvent(\n logger,\n {\n event: \"plugin-event.session.idle.foreground_suppressed\",\n },\n \"session idle notification suppressed for foreground Telegram session\",\n );\n }\n}\n\nasync function handleSessionStatus(\n runtime: TelegramBotRuntime,\n event: NormalizedSessionStatusEvent,\n): Promise<void> {\n if (event.statusType !== \"idle\") {\n return;\n }\n\n await handleSessionIdle(runtime, event);\n}\n\nasync function notifyBoundChats(\n runtime: TelegramBotRuntime,\n sessionId: string,\n text: string,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n sessionId,\n });\n const bindings = await runtime.container.sessionRepo.listBySessionId(sessionId);\n const chatIds = [...new Set(bindings.map((binding) => binding.chatId))];\n\n await Promise.all(\n chatIds.map(async (chatId) => {\n try {\n await runtime.bot.api.sendMessage(chatId, text);\n } catch (error) {\n logger.warn(\n {\n error,\n chatId,\n event: \"plugin-event.session.notify_failed\",\n },\n \"failed to notify Telegram chat about session event\",\n );\n }\n }),\n );\n}\n\nfunction toResolvedApproval(\n approval: PendingPermissionApproval,\n reply: PermissionApprovalReply,\n): PendingPermissionApproval {\n return {\n ...approval,\n status: reply,\n updatedAt: new Date().toISOString(),\n };\n}\n\nfunction normalizePermissionRequestEvent(properties: unknown): OpenCodePermissionRequest | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const id = asNonEmptyString(properties.id);\n const sessionID = asNonEmptyString(properties.sessionID);\n const permission = asNonEmptyString(properties.permission) ?? asNonEmptyString(properties.type);\n\n if (!id || !sessionID || !permission) {\n return null;\n }\n\n return {\n always: Array.isArray(properties.always)\n ? properties.always.filter((value): value is string => typeof value === \"string\")\n : [],\n id,\n metadata: isPlainRecord(properties.metadata)\n ? properties.metadata\n : {},\n patterns: normalizePermissionPatterns(properties),\n permission,\n sessionID,\n };\n}\n\nfunction normalizePermissionReplyEvent(properties: unknown): NormalizedPermissionReplyEvent | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const requestId = asNonEmptyString(properties.requestID) ?? asNonEmptyString(properties.permissionID);\n const reply = normalizePermissionReply(\n asNonEmptyString(properties.reply) ?? asNonEmptyString(properties.response),\n );\n const sessionId = asNonEmptyString(properties.sessionID);\n\n if (!requestId || !reply || !sessionId) {\n return null;\n }\n\n return {\n reply,\n requestId,\n sessionId,\n };\n}\n\nfunction normalizeSessionErrorEvent(properties: unknown): NormalizedSessionErrorEvent | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const sessionId = asNonEmptyString(properties.sessionID);\n\n if (!sessionId) {\n return null;\n }\n\n return {\n error: properties.error,\n sessionId,\n };\n}\n\nfunction normalizeSessionIdleEvent(properties: unknown): NormalizedSessionIdleEvent | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const sessionId = asNonEmptyString(properties.sessionID);\n\n return sessionId\n ? { sessionId }\n : null;\n}\n\nfunction normalizeSessionStatusEvent(properties: unknown): NormalizedSessionStatusEvent | null {\n if (!isPlainRecord(properties) || !isPlainRecord(properties.status)) {\n return null;\n }\n\n const sessionId = asNonEmptyString(properties.sessionID);\n const statusType = asNonEmptyString(properties.status.type);\n\n if (!sessionId || !statusType) {\n return null;\n }\n\n return {\n sessionId,\n statusType,\n };\n}\n\nfunction normalizePermissionPatterns(properties: Record<string, unknown>): string[] {\n if (Array.isArray(properties.patterns)) {\n return properties.patterns.filter((value): value is string => typeof value === \"string\");\n }\n\n if (typeof properties.pattern === \"string\" && properties.pattern.trim().length > 0) {\n return [properties.pattern];\n }\n\n if (Array.isArray(properties.pattern)) {\n return properties.pattern.filter((value): value is string => typeof value === \"string\");\n }\n\n return [];\n}\n\nfunction normalizePermissionReply(value: string | null): PermissionApprovalReply | null {\n if (value === \"once\" || value === \"always\" || value === \"reject\") {\n return value;\n }\n\n return null;\n}\n\nfunction extractSessionErrorMessage(error: unknown): string | null {\n if (error instanceof Error && error.message.trim().length > 0) {\n return error.message.trim();\n }\n\n if (!isPlainRecord(error)) {\n return null;\n }\n\n if (isPlainRecord(error.data) && typeof error.data.message === \"string\" && error.data.message.trim().length > 0) {\n return error.data.message.trim();\n }\n\n return asNonEmptyString(error.name);\n}\n\nfunction normalizeForegroundSessionError(error: unknown): Error {\n if (error instanceof Error) {\n return error;\n }\n\n if (isPlainRecord(error) && typeof error.name === \"string\" && error.name.trim().length > 0) {\n const normalized = new Error(extractSessionErrorMessage(error) ?? \"Unknown session error.\") as Error & {\n data?: Record<string, unknown>;\n };\n\n normalized.name = error.name.trim();\n\n if (isPlainRecord(error.data)) {\n normalized.data = error.data;\n }\n\n return normalized;\n }\n\n return new Error(\"Unknown session error.\");\n}\n\nfunction asNonEmptyString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim().length > 0\n ? value.trim()\n : null;\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, any> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","export type BotLanguage = \"en\" | \"zh-CN\" | \"ja\";\n\nexport interface BotCopy {\n locale: BotLanguage;\n commands: {\n start: string;\n status: string;\n new: string;\n agents: string;\n sessions: string;\n cancel: string;\n model: string;\n language: string;\n };\n start: {\n lines: string[];\n };\n systemStatus: {\n title: string;\n };\n common: {\n notSelected: string;\n openCodeDefault: string;\n previousPage: string;\n nextPage: string;\n page(currentPage: number, totalPages: number): string;\n };\n status: {\n processing: string;\n alreadyProcessing: string;\n };\n prompt: {\n emptyResponse: string;\n };\n replyMetrics: {\n durationLabel: string;\n tokensLabel: string;\n totalLabel: string;\n inputLabel: string;\n outputLabel: string;\n reasoningLabel: string;\n cacheReadLabel: string;\n cacheWriteLabel: string;\n notAvailable: string;\n };\n abort: {\n noSession: string;\n notRunning: string;\n aborted: string;\n };\n errors: {\n unexpected: string;\n providerAuth: string;\n requestAborted: string;\n promptTimeout: string;\n structuredOutput: string;\n voiceUnsupported: string;\n imageDownload: string;\n imageUnsupported: string;\n outputLength: string;\n contextOverflow: string;\n providerRequest: string;\n notFound: string;\n badRequest: string;\n causeLabel: string;\n retryableLabel: string;\n statusCodeLabel: string;\n };\n health: {\n title: string;\n status(healthy: boolean): string;\n version(version: string): string;\n };\n path: {\n title: string;\n home(path: string): string;\n state(path: string): string;\n config(path: string): string;\n worktree(path: string): string;\n directory(path: string): string;\n };\n sessions: {\n none: string;\n title: string;\n actionTitle: string;\n chooseAction: string;\n currentProject(worktree: string): string;\n currentSession(session: string): string;\n selectedSession(session: string): string;\n switched: string;\n created: string;\n renamed: string;\n renameCancelled: string;\n renameEmpty: string;\n renameExpired: string;\n renamePendingInput: string;\n renamePrompt(session: string): string;\n switchAction: string;\n renameAction: string;\n backToList: string;\n expired: string;\n };\n lsp: {\n none: string;\n title: string;\n currentProject(worktree: string): string;\n connected: string;\n error: string;\n };\n mcp: {\n none: string;\n title: string;\n currentProject(worktree: string): string;\n connected: string;\n disabled: string;\n needsAuth: string;\n failed(error: string): string;\n needsClientRegistration(error: string): string;\n };\n agents: {\n none: string;\n title: string;\n current(agent: string): string;\n switched: string;\n expired: string;\n };\n models: {\n none: string;\n title: string;\n configuredOnly: string;\n current(model: string): string;\n switched: string;\n currentReasoningLevel(variant: string): string;\n reasoningLevel(variant: string): string;\n noReasoningLevels: string;\n reasoningLevelsTitle: string;\n model(model: string): string;\n modelNumber(modelIndex: number): string;\n expired: string;\n reasoningLevelExpired: string;\n defaultReasoningLevel: string;\n };\n language: {\n title: string;\n choose: string;\n current(label: string): string;\n switched: string;\n expired: string;\n labels: Record<BotLanguage, string>;\n };\n}\n\nexport const DEFAULT_BOT_LANGUAGE: BotLanguage = \"en\";\nexport const SUPPORTED_BOT_LANGUAGES: readonly BotLanguage[] = [\"en\", \"zh-CN\", \"ja\"];\n\nconst EN_BOT_COPY: BotCopy = {\n locale: \"en\",\n commands: {\n start: \"Show welcome and quick start\",\n status: \"Show system status\",\n new: \"Create a new session\",\n agents: \"Show and switch agents\",\n sessions: \"Show and switch sessions\",\n cancel: \"Cancel rename or abort running request\",\n model: \"Show and switch models\",\n language: \"Show and switch language\",\n },\n start: {\n lines: [\n \"# Welcome to opencode-tbot\",\n \"\",\n \"Talk to your OpenCode server from Telegram.\",\n \"\",\n \"## Quick start\",\n \"1. Run `/status` to confirm the server is ready.\",\n \"2. Run `/new [title]` to create a fresh session.\",\n \"\",\n \"Send a text or image message directly.\",\n ],\n },\n systemStatus: {\n title: \"System Status\",\n },\n common: {\n notSelected: \"Not selected\",\n openCodeDefault: \"Not selected (using OpenCode default)\",\n previousPage: \"Previous\",\n nextPage: \"Next\",\n page(currentPage: number, totalPages: number) {\n return `Page ${currentPage}/${totalPages}`;\n },\n },\n status: {\n processing: \"Processing...\",\n alreadyProcessing: \"Another request is still running. Wait for it to finish before sending a new prompt.\",\n },\n prompt: {\n emptyResponse: \"OpenCode returned empty response.\",\n },\n replyMetrics: {\n durationLabel: \"Duration\",\n tokensLabel: \"Tokens\",\n totalLabel: \"total\",\n inputLabel: \"input\",\n outputLabel: \"output\",\n reasoningLabel: \"reasoning\",\n cacheReadLabel: \"cache.read\",\n cacheWriteLabel: \"cache.write\",\n notAvailable: \"n/a\",\n },\n abort: {\n noSession: \"No active session is bound to this chat yet.\",\n notRunning: \"No request is currently running for the current session.\",\n aborted: \"Abort signal sent to the current session.\",\n },\n errors: {\n unexpected: \"Unexpected error.\",\n providerAuth: \"Provider authentication failed.\",\n requestAborted: \"Request was aborted.\",\n promptTimeout: \"OpenCode request timed out.\",\n structuredOutput: \"Structured output validation failed.\",\n voiceUnsupported: \"Voice messages are not supported. Send text or an image instead.\",\n imageDownload: \"Failed to download the Telegram image file.\",\n imageUnsupported: \"Image file is too large or unsupported.\",\n outputLength: \"Reply hit the model output limit.\",\n contextOverflow: \"Conversation exceeded the model context window.\",\n providerRequest: \"Provider request failed.\",\n notFound: \"Requested resource was not found.\",\n badRequest: \"Request was rejected by OpenCode.\",\n causeLabel: \"Cause\",\n retryableLabel: \"retryable\",\n statusCodeLabel: \"status\",\n },\n health: {\n title: \"Server Health\",\n status(healthy: boolean) {\n return `Status: ${healthy ? \"healthy\" : \"unhealthy\"}`;\n },\n version(version: string) {\n return `Version: ${version}`;\n },\n },\n path: {\n title: \"Current Paths\",\n home(path: string) {\n return `Home: ${path}`;\n },\n state(path: string) {\n return `State: ${path}`;\n },\n config(path: string) {\n return `Config: ${path}`;\n },\n worktree(path: string) {\n return `Worktree: ${path}`;\n },\n directory(path: string) {\n return `Current working directory: ${path}`;\n },\n },\n sessions: {\n none: \"No sessions available in the current project.\",\n title: \"Session List\",\n actionTitle: \"Session Actions\",\n chooseAction: \"Choose an action for this session.\",\n currentProject(worktree: string) {\n return `Current project: ${worktree}`;\n },\n currentSession(session: string) {\n return `Current session: ${session}`;\n },\n selectedSession(session: string) {\n return `Selected session: ${session}`;\n },\n switched: \"Session switched.\",\n created: \"Session created.\",\n renamed: \"Session renamed.\",\n renameCancelled: \"Session rename cancelled.\",\n renameEmpty: \"Session name cannot be empty. Send a new name or /cancel.\",\n renameExpired: \"The session is no longer available. Run /sessions again.\",\n renamePendingInput: \"Waiting for the new session name. Send plain text or /cancel.\",\n renamePrompt(session: string) {\n return [\n `Rename session: ${session}`,\n \"Send the new session name as your next text message.\",\n \"Send /cancel to cancel.\",\n ].join(\"\\n\");\n },\n switchAction: \"Switch\",\n renameAction: \"Rename\",\n backToList: \"Back to list\",\n expired: \"The session is no longer available. Run /sessions again.\",\n },\n lsp: {\n none: \"No LSP servers detected for the current project.\",\n title: \"LSP Servers\",\n currentProject(worktree: string) {\n return `Current project: ${worktree}`;\n },\n connected: \"connected\",\n error: \"error\",\n },\n mcp: {\n none: \"No MCP servers configured for the current project.\",\n title: \"MCP Servers\",\n currentProject(worktree: string) {\n return `Current project: ${worktree}`;\n },\n connected: \"connected\",\n disabled: \"disabled\",\n needsAuth: \"needs auth\",\n failed(error: string) {\n return `failed: ${error}`;\n },\n needsClientRegistration(error: string) {\n return `needs client registration: ${error}`;\n },\n },\n agents: {\n none: \"No agents available.\",\n title: \"Agent List\",\n current(agent: string) {\n return `Current agent: ${agent}`;\n },\n switched: \"Agent switched.\",\n expired: \"The agent is no longer available. Run /agents again.\",\n },\n models: {\n none: \"No models available.\",\n title: \"Model List\",\n configuredOnly: \"Only models currently available in OpenCode and connected providers are shown.\",\n current(model: string) {\n return `Current model: ${model}`;\n },\n switched: \"Model switched.\",\n currentReasoningLevel(variant: string) {\n return `Current reasoning level: ${variant}`;\n },\n reasoningLevel(variant: string) {\n return `Reasoning level: ${variant}`;\n },\n noReasoningLevels: \"This model has no selectable reasoning levels.\",\n reasoningLevelsTitle: \"Reasoning Levels\",\n model(model: string) {\n return `Model: ${model}`;\n },\n modelNumber(modelIndex: number) {\n return `Model number: ${modelIndex}`;\n },\n expired: \"The model is no longer available. Run /model again.\",\n reasoningLevelExpired: \"The reasoning level is no longer available. Run /model again.\",\n defaultReasoningLevel: \"default\",\n },\n language: {\n title: \"Language\",\n choose: \"Choose the display language for bot menus and replies.\",\n current(label: string) {\n return `Current language: ${label}`;\n },\n switched: \"Language switched.\",\n expired: \"The language option is no longer available. Run /language again.\",\n labels: {\n en: \"English\",\n \"zh-CN\": \"简体中文\",\n ja: \"日本語\",\n },\n },\n};\n\nconst ZH_CN_BOT_COPY: BotCopy = {\n locale: \"zh-CN\",\n commands: {\n start: \"查看欢迎信息与快速开始\",\n status: \"查看系统状态\",\n new: \"新建会话\",\n agents: \"查看并切换 Agent\",\n sessions: \"查看并切换会话\",\n cancel: \"取消重命名或中止当前请求\",\n model: \"查看并切换模型\",\n language: \"查看并切换语言\",\n },\n start: {\n lines: [\n \"# 欢迎使用 opencode-tbot\",\n \"\",\n \"通过 Telegram 直接和 OpenCode 服务对话。\",\n \"\",\n \"## 快速开始\",\n \"1. 先运行 `/status` 确认服务状态正常。\",\n \"2. 运行 `/new [title]` 创建一个新会话。\",\n \"\",\n \"直接发送文本或图片消息即可。\",\n ],\n },\n systemStatus: {\n title: \"系统状态\",\n },\n common: {\n notSelected: \"未选择\",\n openCodeDefault: \"未选择(使用 OpenCode 默认值)\",\n previousPage: \"上一页\",\n nextPage: \"下一页\",\n page(currentPage: number, totalPages: number) {\n return `第 ${currentPage}/${totalPages} 页`;\n },\n },\n status: {\n processing: \"处理中...\",\n alreadyProcessing: \"另一个请求仍在运行。请等待其完成后再发送新的提示词。\",\n },\n prompt: {\n emptyResponse: \"OpenCode 返回了空响应。\",\n },\n replyMetrics: {\n durationLabel: \"耗时\",\n tokensLabel: \"令牌数\",\n totalLabel: \"总计\",\n inputLabel: \"输入\",\n outputLabel: \"输出\",\n reasoningLabel: \"推理\",\n cacheReadLabel: \"缓存读取\",\n cacheWriteLabel: \"缓存写入\",\n notAvailable: \"不可用\",\n },\n abort: {\n noSession: \"当前聊天还没有绑定活动会话。\",\n notRunning: \"当前会话没有正在运行的请求。\",\n aborted: \"已向当前会话发送中止信号。\",\n },\n errors: {\n unexpected: \"发生未知错误。\",\n providerAuth: \"Provider 认证失败。\",\n requestAborted: \"请求已中止。\",\n promptTimeout: \"OpenCode 响应超时。\",\n structuredOutput: \"结构化输出校验失败。\",\n voiceUnsupported: \"暂不支持语音消息,请改发文本或图片。\",\n imageDownload: \"下载 Telegram 图片文件失败。\",\n imageUnsupported: \"图片文件过大或不受支持。\",\n outputLength: \"回复触发了模型输出长度上限。\",\n contextOverflow: \"会话已超过模型上下文窗口。\",\n providerRequest: \"Provider 请求失败。\",\n notFound: \"请求的资源不存在。\",\n badRequest: \"OpenCode 拒绝了该请求。\",\n causeLabel: \"原因\",\n retryableLabel: \"可重试\",\n statusCodeLabel: \"状态码\",\n },\n health: {\n title: \"服务健康状态\",\n status(healthy: boolean) {\n return `状态: ${healthy ? \"健康\" : \"异常\"}`;\n },\n version(version: string) {\n return `版本: ${version}`;\n },\n },\n path: {\n title: \"当前路径\",\n home(path: string) {\n return `主目录: ${path}`;\n },\n state(path: string) {\n return `状态目录: ${path}`;\n },\n config(path: string) {\n return `配置文件: ${path}`;\n },\n worktree(path: string) {\n return `工作树: ${path}`;\n },\n directory(path: string) {\n return `当前工作目录: ${path}`;\n },\n },\n sessions: {\n none: \"当前项目下没有可用会话。\",\n title: \"会话列表\",\n actionTitle: \"会话操作\",\n chooseAction: \"请选择该会话的操作。\",\n currentProject(worktree: string) {\n return `当前项目: ${worktree}`;\n },\n currentSession(session: string) {\n return `当前会话: ${session}`;\n },\n selectedSession(session: string) {\n return `已选会话: ${session}`;\n },\n switched: \"会话已切换。\",\n created: \"会话已创建。\",\n renamed: \"会话已重命名。\",\n renameCancelled: \"已取消会话重命名。\",\n renameEmpty: \"会话名称不能为空。请重新发送名称或发送 /cancel。\",\n renameExpired: \"该会话已不可用。请重新运行 /sessions。\",\n renamePendingInput: \"当前正在等待新的会话名称。请发送纯文本或 /cancel。\",\n renamePrompt(session: string) {\n return [\n `重命名会话: ${session}`,\n \"请发送新的会话名称。\",\n \"发送 /cancel 取消。\",\n ].join(\"\\n\");\n },\n switchAction: \"切换\",\n renameAction: \"重命名\",\n backToList: \"返回列表\",\n expired: \"该会话已不可用。请重新运行 /sessions。\",\n },\n lsp: {\n none: \"当前项目未检测到 LSP。\",\n title: \"LSP 服务\",\n currentProject(worktree: string) {\n return `当前项目: ${worktree}`;\n },\n connected: \"已连接\",\n error: \"异常\",\n },\n mcp: {\n none: \"当前项目未配置 MCP。\",\n title: \"MCP 服务\",\n currentProject(worktree: string) {\n return `当前项目: ${worktree}`;\n },\n connected: \"已连接\",\n disabled: \"已禁用\",\n needsAuth: \"需要认证\",\n failed(error: string) {\n return `失败: ${error}`;\n },\n needsClientRegistration(error: string) {\n return `需要客户端注册: ${error}`;\n },\n },\n agents: {\n none: \"没有可用 Agent。\",\n title: \"Agent 列表\",\n current(agent: string) {\n return `当前 Agent: ${agent}`;\n },\n switched: \"Agent 已切换。\",\n expired: \"该 Agent 已不可用。请重新运行 /agents。\",\n },\n models: {\n none: \"没有可用模型。\",\n title: \"模型列表\",\n configuredOnly: \"仅显示当前在 OpenCode 和已连接 provider 中实际可用的模型。\",\n current(model: string) {\n return `当前模型: ${model}`;\n },\n switched: \"模型已切换。\",\n currentReasoningLevel(variant: string) {\n return `当前推理级别: ${variant}`;\n },\n reasoningLevel(variant: string) {\n return `推理级别: ${variant}`;\n },\n noReasoningLevels: \"该模型没有可选的推理级别。\",\n reasoningLevelsTitle: \"推理级别\",\n model(model: string) {\n return `模型: ${model}`;\n },\n modelNumber(modelIndex: number) {\n return `模型编号: ${modelIndex}`;\n },\n expired: \"该模型已不可用。请重新运行 /model。\",\n reasoningLevelExpired: \"该推理级别已不可用。请重新运行 /model。\",\n defaultReasoningLevel: \"默认\",\n },\n language: {\n title: \"语言\",\n choose: \"选择 Bot 菜单和回复的显示语言。\",\n current(label: string) {\n return `当前语言: ${label}`;\n },\n switched: \"语言已切换。\",\n expired: \"该语言选项已不可用。请重新运行 /language。\",\n labels: {\n en: \"English\",\n \"zh-CN\": \"简体中文\",\n ja: \"日本語\",\n },\n },\n};\n\nconst JA_BOT_COPY: BotCopy = {\n locale: \"ja\",\n commands: {\n start: \"ようこそとクイックスタートを表示\",\n status: \"システム状態を表示\",\n new: \"新しいセッションを作成\",\n agents: \"エージェントを表示して切り替え\",\n sessions: \"セッションを表示して切り替え\",\n cancel: \"名前変更を取り消すか実行中のリクエストを中止\",\n model: \"モデルを表示して切り替え\",\n language: \"言語を表示して切り替え\",\n },\n start: {\n lines: [\n \"# opencode-tbot へようこそ\",\n \"\",\n \"Telegram から OpenCode サーバーとやり取りできます。\",\n \"\",\n \"## クイックスタート\",\n \"1. `/status` を実行してサーバーの準備完了を確認します。\",\n \"2. `/new [title]` を実行して新しいセッションを作成します。\",\n \"\",\n \"そのままテキストまたは画像メッセージを送信できます。\",\n ],\n },\n systemStatus: {\n title: \"システム状態\",\n },\n common: {\n notSelected: \"未選択\",\n openCodeDefault: \"未選択(OpenCode のデフォルトを使用)\",\n previousPage: \"前へ\",\n nextPage: \"次へ\",\n page(currentPage: number, totalPages: number) {\n return `ページ ${currentPage}/${totalPages}`;\n },\n },\n status: {\n processing: \"処理中...\",\n alreadyProcessing: \"別のリクエストがまだ実行中です。完了するまで新しいプロンプトを送信しないでください。\",\n },\n prompt: {\n emptyResponse: \"OpenCode から空の応答が返されました。\",\n },\n replyMetrics: {\n durationLabel: \"所要時間\",\n tokensLabel: \"トークン\",\n totalLabel: \"合計\",\n inputLabel: \"入力\",\n outputLabel: \"出力\",\n reasoningLabel: \"推論\",\n cacheReadLabel: \"キャッシュ読込\",\n cacheWriteLabel: \"キャッシュ書込\",\n notAvailable: \"該当なし\",\n },\n abort: {\n noSession: \"このチャットにはまだアクティブなセッションが紐付いていません。\",\n notRunning: \"現在のセッションで実行中のリクエストはありません。\",\n aborted: \"現在のセッションに中止シグナルを送信しました。\",\n },\n errors: {\n unexpected: \"予期しないエラーが発生しました。\",\n providerAuth: \"Provider の認証に失敗しました。\",\n requestAborted: \"リクエストは中止されました。\",\n promptTimeout: \"OpenCode リクエストがタイムアウトしました。\",\n structuredOutput: \"構造化出力の検証に失敗しました。\",\n voiceUnsupported: \"音声メッセージには対応していません。代わりにテキストまたは画像を送信してください。\",\n imageDownload: \"Telegram の画像ファイルをダウンロードできませんでした。\",\n imageUnsupported: \"画像ファイルが大きすぎるか、サポートされていません。\",\n outputLength: \"返信がモデルの出力上限に達しました。\",\n contextOverflow: \"会話がモデルのコンテキスト上限を超えました。\",\n providerRequest: \"Provider へのリクエストに失敗しました。\",\n notFound: \"要求されたリソースが見つかりませんでした。\",\n badRequest: \"リクエストは OpenCode に拒否されました。\",\n causeLabel: \"原因\",\n retryableLabel: \"再試行可能\",\n statusCodeLabel: \"ステータス\",\n },\n health: {\n title: \"サーバー状態\",\n status(healthy: boolean) {\n return `状態: ${healthy ? \"正常\" : \"異常\"}`;\n },\n version(version: string) {\n return `バージョン: ${version}`;\n },\n },\n path: {\n title: \"現在のパス\",\n home(path: string) {\n return `ホーム: ${path}`;\n },\n state(path: string) {\n return `状態: ${path}`;\n },\n config(path: string) {\n return `設定: ${path}`;\n },\n worktree(path: string) {\n return `ワークツリー: ${path}`;\n },\n directory(path: string) {\n return `現在の作業ディレクトリ: ${path}`;\n },\n },\n sessions: {\n none: \"現在のプロジェクトで利用できるセッションはありません。\",\n title: \"セッション一覧\",\n actionTitle: \"セッション操作\",\n chooseAction: \"このセッションに対する操作を選択してください。\",\n currentProject(worktree: string) {\n return `現在のプロジェクト: ${worktree}`;\n },\n currentSession(session: string) {\n return `現在のセッション: ${session}`;\n },\n selectedSession(session: string) {\n return `選択中のセッション: ${session}`;\n },\n switched: \"セッションを切り替えました。\",\n created: \"セッションを作成しました。\",\n renamed: \"セッション名を変更しました。\",\n renameCancelled: \"セッション名の変更を取り消しました。\",\n renameEmpty: \"セッション名は空にできません。新しい名前を送信するか /cancel を実行してください。\",\n renameExpired: \"このセッションはもう利用できません。/sessions を再実行してください。\",\n renamePendingInput: \"新しいセッション名の入力待ちです。プレーンテキストを送るか /cancel を実行してください。\",\n renamePrompt(session: string) {\n return [\n `セッション名を変更: ${session}`,\n \"次のテキストメッセージで新しいセッション名を送信してください。\",\n \"/cancel で取り消します。\",\n ].join(\"\\n\");\n },\n switchAction: \"切り替え\",\n renameAction: \"名前変更\",\n backToList: \"一覧に戻る\",\n expired: \"このセッションはもう利用できません。/sessions を再実行してください。\",\n },\n lsp: {\n none: \"現在のプロジェクトで LSP サーバーは検出されませんでした。\",\n title: \"LSP サーバー\",\n currentProject(worktree: string) {\n return `現在のプロジェクト: ${worktree}`;\n },\n connected: \"接続済み\",\n error: \"エラー\",\n },\n mcp: {\n none: \"現在のプロジェクトで MCP サーバーは設定されていません。\",\n title: \"MCP サーバー\",\n currentProject(worktree: string) {\n return `現在のプロジェクト: ${worktree}`;\n },\n connected: \"接続済み\",\n disabled: \"無効\",\n needsAuth: \"認証が必要\",\n failed(error: string) {\n return `失敗: ${error}`;\n },\n needsClientRegistration(error: string) {\n return `クライアント登録が必要: ${error}`;\n },\n },\n agents: {\n none: \"利用可能なエージェントはありません。\",\n title: \"エージェント一覧\",\n current(agent: string) {\n return `現在のエージェント: ${agent}`;\n },\n switched: \"エージェントを切り替えました。\",\n expired: \"このエージェントはもう利用できません。/agents を再実行してください。\",\n },\n models: {\n none: \"利用可能なモデルはありません。\",\n title: \"モデル一覧\",\n configuredOnly: \"OpenCode と接続済み provider で現在利用可能なモデルのみ表示します。\",\n current(model: string) {\n return `現在のモデル: ${model}`;\n },\n switched: \"モデルを切り替えました。\",\n currentReasoningLevel(variant: string) {\n return `現在の推論レベル: ${variant}`;\n },\n reasoningLevel(variant: string) {\n return `推論レベル: ${variant}`;\n },\n noReasoningLevels: \"このモデルには選択可能な推論レベルがありません。\",\n reasoningLevelsTitle: \"推論レベル\",\n model(model: string) {\n return `モデル: ${model}`;\n },\n modelNumber(modelIndex: number) {\n return `モデル番号: ${modelIndex}`;\n },\n expired: \"このモデルはもう利用できません。/model を再実行してください。\",\n reasoningLevelExpired: \"この推論レベルはもう利用できません。/model を再実行してください。\",\n defaultReasoningLevel: \"デフォルト\",\n },\n language: {\n title: \"言語\",\n choose: \"Bot のメニューと返信に使う表示言語を選択してください。\",\n current(label: string) {\n return `現在の言語: ${label}`;\n },\n switched: \"言語を切り替えました。\",\n expired: \"この言語オプションはもう利用できません。/language を再実行してください。\",\n labels: {\n en: \"English\",\n \"zh-CN\": \"简体中文\",\n ja: \"日本語\",\n },\n },\n};\n\nexport const BOT_COPY = EN_BOT_COPY;\n\nexport function isBotLanguage(value: string): value is BotLanguage {\n return SUPPORTED_BOT_LANGUAGES.includes(value as BotLanguage);\n}\n\nexport function normalizeBotLanguage(value: string | null | undefined): BotLanguage {\n if (!value) {\n return DEFAULT_BOT_LANGUAGE;\n }\n\n const normalized = value.trim().toLowerCase();\n\n if (normalized === \"zh-cn\" || normalized === \"zh-hans\" || normalized === \"zh\") {\n return \"zh-CN\";\n }\n\n if (normalized === \"ja\" || normalized === \"ja-jp\" || normalized === \"ja_jp\") {\n return \"ja\";\n }\n\n return \"en\";\n}\n\nexport function getBotCopy(language: BotLanguage | null | undefined = DEFAULT_BOT_LANGUAGE): BotCopy {\n const normalized = normalizeBotLanguage(language);\n\n if (normalized === \"zh-CN\") {\n return ZH_CN_BOT_COPY;\n }\n\n if (normalized === \"ja\") {\n return JA_BOT_COPY;\n }\n\n return EN_BOT_COPY;\n}\n\nexport function getLanguageLabel(language: BotLanguage, copy: BotCopy = BOT_COPY): string {\n return copy.language.labels[language];\n}\n","import type { BotCommand } from \"grammy/types\";\nimport { getBotCopy, type BotLanguage } from \"../copy.js\";\n\nexport function getTelegramCommands(language: BotLanguage = \"en\"): BotCommand[] {\n const copy = getBotCopy(language);\n\n return [\n {\n command: \"start\",\n description: copy.commands.start,\n },\n {\n command: \"status\",\n description: copy.commands.status,\n },\n {\n command: \"new\",\n description: copy.commands.new,\n },\n {\n command: \"agents\",\n description: copy.commands.agents,\n },\n {\n command: \"sessions\",\n description: copy.commands.sessions,\n },\n {\n command: \"cancel\",\n description: copy.commands.cancel,\n },\n {\n command: \"model\",\n description: copy.commands.model,\n },\n {\n command: \"language\",\n description: copy.commands.language,\n },\n ];\n}\n\nexport const TELEGRAM_COMMANDS: BotCommand[] = getTelegramCommands();\n","import type { Bot } from \"grammy\";\nimport type { BotCommandScope } from \"grammy/types\";\nimport type { AppLogger } from \"../../infra/logger/index.js\";\nimport { type BotLanguage } from \"../copy.js\";\nimport { getTelegramCommands, TELEGRAM_COMMANDS } from \"./command-list.js\";\n\nexport const TELEGRAM_COMMAND_SYNC_SCOPES: ReadonlyArray<BotCommandScope> = [\n { type: \"default\" },\n { type: \"all_private_chats\" },\n];\n\nexport async function syncTelegramCommands(bot: Bot, logger: AppLogger): Promise<void> {\n await Promise.all(\n TELEGRAM_COMMAND_SYNC_SCOPES.map((scope) =>\n bot.api.setMyCommands(TELEGRAM_COMMANDS, { scope }),\n ),\n );\n\n logger.info(\n {\n component: \"runtime\",\n commands: TELEGRAM_COMMANDS.map((command) => command.command),\n event: \"runtime.commands.synced\",\n scopes: TELEGRAM_COMMAND_SYNC_SCOPES.map((scope) => scope.type),\n },\n \"telegram commands synced\",\n );\n}\n\nexport async function syncTelegramCommandsForChat(\n api: Pick<Bot[\"api\"], \"setMyCommands\">,\n chatId: number,\n language: BotLanguage,\n): Promise<void> {\n await api.setMyCommands(\n getTelegramCommands(language),\n {\n scope: {\n type: \"chat\",\n chat_id: chatId,\n },\n },\n );\n}\n","import type { AppLogger, LogComponent, LoggerContext } from \"../infra/logger/index.js\";\nimport type { BotDependencies } from \"./types.js\";\n\ninterface TelegramLogContextLike {\n callbackQuery?: { data?: string | null };\n chat?: { id?: number };\n message?: { text?: string | null };\n msg?: { text?: string | null } | null;\n update?: { update_id?: number };\n}\n\nexport function buildTelegramLoggerContext(\n ctx: TelegramLogContextLike,\n component: LogComponent = \"telegram\",\n): LoggerContext {\n const updateId = typeof ctx.update?.update_id === \"number\"\n ? ctx.update.update_id\n : undefined;\n const messageText = resolveMessageText(ctx);\n const command = extractTelegramCommand(messageText);\n const callbackData = normalizeTelegramString(ctx.callbackQuery?.data);\n const operationId = typeof updateId === \"number\"\n ? `telegram-${updateId}`\n : null;\n\n return {\n component,\n ...(typeof ctx.chat?.id === \"number\" ? { chatId: ctx.chat.id } : {}),\n ...(typeof updateId === \"number\" ? { updateId } : {}),\n ...(command ? { command } : {}),\n ...(callbackData ? { callbackData } : {}),\n correlationId: typeof updateId === \"number\"\n ? String(updateId)\n : operationId,\n operationId,\n };\n}\n\nexport function scopeLoggerToTelegramContext(\n logger: AppLogger,\n ctx: TelegramLogContextLike,\n component: LogComponent = \"telegram\",\n): AppLogger {\n return logger.child(buildTelegramLoggerContext(ctx, component));\n}\n\nexport function scopeDependenciesToTelegramContext<TDependencies extends BotDependencies>(\n dependencies: TDependencies,\n ctx: TelegramLogContextLike,\n component: LogComponent = \"telegram\",\n): TDependencies {\n return {\n ...dependencies,\n logger: scopeLoggerToTelegramContext(dependencies.logger, ctx, component),\n };\n}\n\nfunction resolveMessageText(ctx: TelegramLogContextLike): string | null {\n return normalizeTelegramString(ctx.message?.text)\n ?? normalizeTelegramString(ctx.msg?.text);\n}\n\nfunction extractTelegramCommand(value: string | null): string | null {\n if (!value || !value.startsWith(\"/\")) {\n return null;\n }\n\n const token = value.split(/\\s+/u, 1)[0]?.trim();\n\n if (!token) {\n return null;\n }\n\n return token.replace(/^\\/+/u, \"\").split(\"@\", 1)[0] ?? null;\n}\n\nfunction normalizeTelegramString(value: string | null | undefined): string | null {\n return typeof value === \"string\" && value.trim().length > 0\n ? value.trim()\n : null;\n}\n","import { BOT_COPY, type BotCopy } from \"../copy.js\";\n\ninterface PresentedError {\n cause: string | null;\n message: string;\n}\n\nexport function presentError(error: unknown, copy: BotCopy = BOT_COPY): string {\n const presented = normalizeError(error, copy);\n\n return presented.cause\n ? `${presented.message}\\n${copy.errors.causeLabel}: ${presented.cause}`\n : presented.message;\n}\n\nfunction normalizeError(error: unknown, copy: BotCopy): PresentedError {\n if (isNamedError(error, \"ProviderAuthError\")) {\n return {\n message: copy.errors.providerAuth,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"MessageAbortedError\")) {\n return {\n message: copy.errors.requestAborted,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"OpenCodePromptTimeoutError\")) {\n return {\n message: copy.errors.promptTimeout,\n cause: null,\n };\n }\n\n if (isNamedError(error, \"StructuredOutputError\")) {\n return {\n message: copy.errors.structuredOutput,\n cause: joinNonEmptyParts([\n extractMessage(error.data),\n extractRetries(error.data),\n ]),\n };\n }\n\n if (isNamedError(error, \"ImageFileDownloadError\")) {\n return {\n message: copy.errors.imageDownload,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"ImageMessageUnsupportedError\")) {\n return {\n message: copy.errors.imageUnsupported,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"MessageOutputLengthError\")) {\n return {\n message: copy.errors.outputLength,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"ContextOverflowError\")) {\n return {\n message: copy.errors.contextOverflow,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"APIError\")) {\n return {\n message: copy.errors.providerRequest,\n cause: joinNonEmptyParts([\n extractMessage(error.data),\n extractStatusCode(error.data, copy),\n extractRetryable(error.data, copy),\n ]),\n };\n }\n\n if (isNamedError(error, \"NotFoundError\")) {\n return {\n message: copy.errors.notFound,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isBadRequestError(error)) {\n return {\n message: copy.errors.badRequest,\n cause: extractBadRequestCause(error),\n };\n }\n\n if (error instanceof Error) {\n return {\n message: error.name === \"AbortError\" ? copy.errors.requestAborted : copy.errors.unexpected,\n cause: error.message || null,\n };\n }\n\n return {\n message: copy.errors.unexpected,\n cause: extractMessage(error) ?? stringifyUnknown(error),\n };\n}\n\nfunction isBadRequestError(error: unknown): error is { data?: unknown; errors?: unknown[]; success: false } {\n return !!error\n && typeof error === \"object\"\n && \"success\" in error\n && (error as { success?: unknown }).success === false;\n}\n\nfunction isNamedError<TName extends string>(\n error: unknown,\n name: TName,\n): error is { data?: unknown; name: TName } {\n return !!error\n && typeof error === \"object\"\n && \"name\" in error\n && (error as { name?: unknown }).name === name;\n}\n\nfunction extractBadRequestCause(error: { data?: unknown; errors?: unknown[] }): string | null {\n const directMessage = extractMessage(error.data);\n\n if (directMessage) {\n return directMessage;\n }\n\n const firstValidationError = Array.isArray(error.errors) && error.errors.length > 0\n ? stringifyUnknown(error.errors[0])\n : null;\n\n return firstValidationError;\n}\n\nfunction extractMessage(value: unknown): string | null {\n if (!value) {\n return null;\n }\n\n if (typeof value === \"string\") {\n return value.trim() || null;\n }\n\n if (typeof value === \"object\" && \"message\" in value) {\n const message = (value as { message?: unknown }).message;\n\n return typeof message === \"string\" && message.trim().length > 0\n ? message.trim()\n : null;\n }\n\n return null;\n}\n\nfunction extractRetries(value: unknown): string | null {\n if (!value || typeof value !== \"object\" || !(\"retries\" in value)) {\n return null;\n }\n\n const retries = (value as { retries?: unknown }).retries;\n\n return typeof retries === \"number\" && Number.isFinite(retries)\n ? `retries: ${Math.round(retries)}`\n : null;\n}\n\nfunction extractRetryable(value: unknown, copy: BotCopy): string | null {\n if (!value || typeof value !== \"object\" || !(\"isRetryable\" in value)) {\n return null;\n }\n\n const isRetryable = (value as { isRetryable?: unknown }).isRetryable;\n\n return typeof isRetryable === \"boolean\"\n ? `${copy.errors.retryableLabel}: ${isRetryable ? \"yes\" : \"no\"}`\n : null;\n}\n\nfunction extractStatusCode(value: unknown, copy: BotCopy): string | null {\n if (!value || typeof value !== \"object\" || !(\"statusCode\" in value)) {\n return null;\n }\n\n const statusCode = (value as { statusCode?: unknown }).statusCode;\n\n return typeof statusCode === \"number\" && Number.isFinite(statusCode)\n ? `${copy.errors.statusCodeLabel}: ${Math.round(statusCode)}`\n : null;\n}\n\nfunction joinNonEmptyParts(parts: Array<string | null | undefined>): string | null {\n const filtered = parts\n .map((part) => part?.trim())\n .filter((part): part is string => !!part);\n\n return filtered.length > 0 ? filtered.join(\" | \") : null;\n}\n\nfunction stringifyUnknown(value: unknown): string | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === \"string\") {\n return value.trim() || null;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n try {\n const text = JSON.stringify(value);\n\n return text && text !== \"{}\" ? text : null;\n } catch {\n return null;\n }\n}\n","import type { AppLogger } from \"../infra/logger/index.js\";\nimport { buildTelegramLoggerContext } from \"./logger-context.js\";\nimport { BOT_COPY } from \"./copy.js\";\nimport { presentError } from \"./presenters/error.presenter.js\";\n\nexport function extractTelegramUpdateContext(\n ctx: object,\n): {\n callbackData?: string;\n chatId?: number;\n command?: string;\n correlationId?: string | null;\n operationId?: string | null;\n updateId?: number;\n} {\n return buildTelegramLoggerContext({\n callbackQuery: {\n data: getNestedString(ctx, [\"callbackQuery\", \"data\"]),\n },\n chat: {\n id: getNestedNumber(ctx, [\"chat\", \"id\"]) ?? undefined,\n },\n message: {\n text: getNestedString(ctx, [\"message\", \"text\"]),\n },\n update: {\n update_id: getNestedNumber(ctx, [\"update\", \"update_id\"]) ?? undefined,\n },\n });\n}\n\nexport async function replyWithDefaultTelegramError(\n ctx: object,\n logger: AppLogger,\n error: unknown,\n): Promise<void> {\n const text = presentError(error, BOT_COPY);\n const editMessageText = getFunction(ctx, \"editMessageText\");\n const reply = getFunction(ctx, \"reply\");\n const callbackData = getNestedString(ctx, [\"callbackQuery\", \"data\"]);\n\n try {\n if (typeof callbackData === \"string\" && editMessageText) {\n await editMessageText.call(ctx, text);\n return;\n }\n\n if (reply) {\n await reply.call(ctx, text);\n }\n } catch (replyError) {\n logger.warn?.(\n {\n ...extractTelegramUpdateContext(ctx),\n error: replyError,\n },\n \"failed to deliver fallback Telegram error message\",\n );\n }\n}\n\nfunction getFunction(value: object, key: string): ((...args: unknown[]) => Promise<unknown>) | null {\n if (!(key in value)) {\n return null;\n }\n\n const candidate = (value as Record<string, unknown>)[key];\n\n return typeof candidate === \"function\"\n ? candidate as (...args: unknown[]) => Promise<unknown>\n : null;\n}\n\nfunction getNestedNumber(value: object, path: string[]): number | null {\n const candidate = getNestedValue(value, path);\n\n return typeof candidate === \"number\" ? candidate : null;\n}\n\nfunction getNestedString(value: object, path: string[]): string | null {\n const candidate = getNestedValue(value, path);\n\n return typeof candidate === \"string\" ? candidate : null;\n}\n\nfunction getNestedValue(value: object, path: string[]): unknown {\n let current: unknown = value;\n\n for (const segment of path) {\n if (!current || typeof current !== \"object\" || !(segment in current)) {\n return null;\n }\n\n current = (current as Record<string, unknown>)[segment];\n }\n\n return current;\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport {\n BOT_COPY,\n DEFAULT_BOT_LANGUAGE,\n getBotCopy,\n normalizeBotLanguage,\n type BotCopy,\n type BotLanguage,\n} from \"./copy.js\";\n\nexport async function getChatLanguage(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n): Promise<BotLanguage> {\n if (!chatId) {\n return DEFAULT_BOT_LANGUAGE;\n }\n\n const binding = await sessionRepo.getByChatId(chatId);\n\n return normalizeBotLanguage(binding?.language);\n}\n\nexport async function getChatCopy(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n): Promise<BotCopy> {\n return getBotCopy(await getChatLanguage(sessionRepo, chatId));\n}\n\nexport async function getSafeChatLanguage(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n logger?: Pick<AppLogger, \"warn\">,\n): Promise<BotLanguage> {\n try {\n return await getChatLanguage(sessionRepo, chatId);\n } catch (error) {\n logger?.warn?.(\n {\n error,\n chatId: chatId ?? undefined,\n },\n \"failed to resolve Telegram chat language; falling back to the default locale\",\n );\n return DEFAULT_BOT_LANGUAGE;\n }\n}\n\nexport async function getSafeChatCopy(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n logger?: Pick<AppLogger, \"warn\">,\n): Promise<BotCopy> {\n try {\n return getBotCopy(await getSafeChatLanguage(sessionRepo, chatId, logger));\n } catch (error) {\n logger?.warn?.(\n {\n error,\n chatId: chatId ?? undefined,\n },\n \"failed to resolve Telegram copy; falling back to the default locale\",\n );\n return BOT_COPY;\n }\n}\n\nexport async function setChatLanguage(\n sessionRepo: SessionRepository,\n chatId: number,\n language: BotLanguage,\n): Promise<void> {\n const binding = await sessionRepo.getByChatId(chatId);\n\n await sessionRepo.setCurrent({\n chatId,\n sessionId: binding?.sessionId ?? null,\n projectId: binding?.projectId ?? null,\n directory: binding?.directory ?? null,\n agentName: binding?.agentName ?? null,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language,\n updatedAt: new Date().toISOString(),\n });\n}\n","import { InlineKeyboard } from \"grammy\";\nimport {\n BOT_COPY,\n getLanguageLabel,\n SUPPORTED_BOT_LANGUAGES,\n type BotCopy,\n type BotLanguage,\n} from \"../copy.js\";\nimport type {\n OpenCodeAgent,\n OpenCodeConfiguredModel,\n OpenCodeSession,\n} from \"../../services/opencode/opencode.client.js\";\n\nexport const MODELS_PAGE_SIZE = 10;\nexport const AGENTS_PAGE_SIZE = 10;\nexport const SESSIONS_PAGE_SIZE = 10;\nconst NUMBERED_BUTTONS_PER_ROW = 5;\n\nexport interface ModelsPage {\n items: OpenCodeConfiguredModel[];\n page: number;\n startIndex: number;\n totalPages: number;\n}\n\nexport interface AgentsPage {\n items: OpenCodeAgent[];\n page: number;\n startIndex: number;\n totalPages: number;\n}\n\nexport interface SessionsPage {\n items: OpenCodeSession[];\n page: number;\n startIndex: number;\n totalPages: number;\n}\n\nexport function buildModelsKeyboard(\n models: OpenCodeConfiguredModel[],\n requestedPage: number,\n copy: BotCopy = BOT_COPY,\n) {\n const page = getModelsPage(models, requestedPage);\n const keyboard = buildNumberedKeyboard(\n page.items,\n page.startIndex,\n (_, index) => `model:pick:${page.startIndex + index + 1}`,\n );\n\n appendPaginationButtons(keyboard, page.page, page.totalPages, \"model:page\", copy);\n\n return { keyboard, page };\n}\n\nexport function buildAgentsKeyboard(\n agents: OpenCodeAgent[],\n requestedPage: number,\n copy: BotCopy = BOT_COPY,\n) {\n const page = getAgentsPage(agents, requestedPage);\n const keyboard = buildNumberedKeyboard(\n page.items,\n page.startIndex,\n (_, index) => `agents:select:${page.startIndex + index + 1}`,\n );\n\n appendPaginationButtons(keyboard, page.page, page.totalPages, \"agents:page\", copy);\n\n return { keyboard, page };\n}\n\nexport function buildSessionsKeyboard(\n sessions: OpenCodeSession[],\n requestedPage: number,\n copy: BotCopy = BOT_COPY,\n) {\n const page = getSessionsPage(sessions, requestedPage);\n const keyboard = buildNumberedKeyboard(\n page.items,\n page.startIndex,\n (session) => `sessions:pick:${page.page}:${session.id}`,\n );\n\n appendPaginationButtons(keyboard, page.page, page.totalPages, \"sessions:page\", copy);\n\n return { keyboard, page };\n}\n\nexport function buildSessionActionKeyboard(\n sessionId: string,\n page: number,\n copy: BotCopy = BOT_COPY,\n) {\n return new InlineKeyboard()\n .text(copy.sessions.switchAction, `sessions:switch:${page}:${sessionId}`)\n .text(copy.sessions.renameAction, `sessions:rename:${page}:${sessionId}`)\n .row()\n .text(copy.sessions.backToList, `sessions:back:${page}`);\n}\n\nexport function buildModelVariantsKeyboard(variants: string[], modelIndex: number) {\n return buildNumberedKeyboard(\n variants,\n 0,\n (_, index) => `model:variant:${modelIndex}:${index + 1}`,\n );\n}\n\nexport function buildLanguageKeyboard(currentLanguage: BotLanguage, copy: BotCopy = BOT_COPY) {\n const keyboard = new InlineKeyboard();\n\n SUPPORTED_BOT_LANGUAGES.forEach((language, index) => {\n const label = currentLanguage === language\n ? `[${getLanguageLabel(language, copy)}]`\n : getLanguageLabel(language, copy);\n\n keyboard.text(label, `language:select:${language}`);\n\n if (index !== SUPPORTED_BOT_LANGUAGES.length - 1) {\n keyboard.row();\n }\n });\n\n return keyboard;\n}\n\nexport function getModelsPage(models: OpenCodeConfiguredModel[], requestedPage: number): ModelsPage {\n return getPagedItems(models, requestedPage, MODELS_PAGE_SIZE);\n}\n\nexport function getAgentsPage(agents: OpenCodeAgent[], requestedPage: number): AgentsPage {\n return getPagedItems(agents, requestedPage, AGENTS_PAGE_SIZE);\n}\n\nexport function getSessionsPage(sessions: OpenCodeSession[], requestedPage: number): SessionsPage {\n return getPagedItems(sessions, requestedPage, SESSIONS_PAGE_SIZE);\n}\n\nfunction buildNumberedKeyboard<T>(\n items: T[],\n startIndex: number,\n buildCallbackData: (item: T, index: number) => string,\n) {\n const keyboard = new InlineKeyboard();\n\n items.forEach((item, index) => {\n const displayIndex = startIndex + index + 1;\n\n keyboard.text(`${displayIndex}`, buildCallbackData(item, index));\n\n if (\n index !== items.length - 1\n && (index + 1) % NUMBERED_BUTTONS_PER_ROW === 0\n ) {\n keyboard.row();\n }\n });\n\n return keyboard;\n}\n\nfunction appendPaginationButtons(\n keyboard: InlineKeyboard,\n page: number,\n totalPages: number,\n prefix: \"agents:page\" | \"sessions:page\" | \"model:page\",\n copy: BotCopy,\n) {\n if (totalPages <= 1) {\n return;\n }\n\n if (page > 0) {\n keyboard.text(copy.common.previousPage, `${prefix}:${page - 1}`);\n }\n\n if (page < totalPages - 1) {\n keyboard.text(copy.common.nextPage, `${prefix}:${page + 1}`);\n }\n}\n\nfunction getPagedItems<T>(items: T[], requestedPage: number, pageSize: number) {\n const totalPages = Math.max(1, Math.ceil(items.length / pageSize));\n const page = clampPage(requestedPage, totalPages);\n const startIndex = page * pageSize;\n\n return {\n items: items.slice(startIndex, startIndex + pageSize),\n page,\n startIndex,\n totalPages,\n };\n}\n\nfunction clampPage(page: number, totalPages: number): number {\n if (!Number.isInteger(page) || page < 0) {\n return 0;\n }\n\n return Math.min(page, totalPages - 1);\n}\n","import type {\n OpenCodeAgent,\n OpenCodeConfiguredModel,\n OpenCodeHealth,\n OpenCodeLspStatus,\n OpenCodeMcpStatus,\n OpenCodePath,\n OpenCodeSession,\n} from \"../../services/opencode/opencode.client.js\";\nimport { OPENCODE_TBOT_VERSION } from \"../../app/package-info.js\";\nimport type { GetStatusResult } from \"../../use-cases/get-status.usecase.js\";\nimport {\n BOT_COPY,\n getLanguageLabel,\n type BotCopy,\n type BotLanguage,\n} from \"../copy.js\";\nimport { presentError } from \"./error.presenter.js\";\nimport {\n getAgentsPage,\n getModelsPage,\n getSessionsPage,\n} from \"./keyboard.presenter.js\";\n\ninterface ModelsMessageInput {\n currentModelId: string | null;\n currentModelProviderId: string | null;\n currentModelVariant: string | null;\n models: OpenCodeConfiguredModel[];\n page: number;\n}\n\ninterface AgentsMessageInput {\n agents: OpenCodeAgent[];\n currentAgentName: string | null;\n page: number;\n}\n\ninterface SessionsMessageInput {\n currentDirectory: string;\n currentSessionId: string | null;\n page: number;\n sessions: OpenCodeSession[];\n}\n\ninterface McpMessageInput {\n currentDirectory: string;\n statuses: Array<{\n name: string;\n status: OpenCodeMcpStatus;\n }>;\n}\n\ninterface LspMessageInput {\n currentDirectory: string;\n statuses: OpenCodeLspStatus[];\n}\n\ninterface StatusLayoutCopy {\n connectivityLabel: string;\n currentProjectLabel: string;\n currentSessionLabel: string;\n defaultSessionValue: string;\n detailsLabel: string;\n errorStatus: string;\n lspTitle: string;\n mcpFailedStatus: string;\n mcpNotesLabel: string;\n mcpRegistrationRequiredStatus: string;\n mcpTitle: string;\n noPluginsMessage: string;\n noneStatus: string;\n openCodeVersionLabel: string;\n overviewTitle: string;\n pluginsTitle: string;\n statusLabel: string;\n tbotVersionLabel: string;\n workspaceTitle: string;\n}\n\ninterface StatusDetailLine {\n codeValue?: boolean;\n label: string;\n value: string;\n}\n\nconst VARIANT_ORDER = [\"minimal\", \"none\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\nexport function presentHealthMessage(health: OpenCodeHealth, copy: BotCopy = BOT_COPY): string {\n return [\n copy.health.title,\n copy.health.status(health.healthy),\n copy.health.version(health.version),\n ].join(\"\\n\");\n}\n\nexport function presentPathMessage(path: OpenCodePath, copy: BotCopy = BOT_COPY): string {\n return copy.path.directory(path.directory);\n}\n\nexport function presentStatusMessage(input: GetStatusResult, copy: BotCopy = BOT_COPY): string {\n const layout = getStatusLayoutCopy(copy);\n const sections = [\n presentStatusPlainSection(layout.overviewTitle, presentStatusPlainOverviewLines(input, copy, layout)),\n presentStatusPlainSection(layout.workspaceTitle, presentStatusPlainWorkspaceLines(input, copy, layout)),\n presentStatusPlainSection(layout.pluginsTitle, presentStatusPlainPluginLines(input, copy, layout)),\n presentStatusPlainSection(layout.mcpTitle, presentStatusPlainMcpLines(input, copy, layout)),\n presentStatusPlainSection(layout.lspTitle, presentStatusPlainLspLines(input, copy, layout)),\n ];\n\n return presentStatusSections(sections);\n}\n\nexport function presentStatusMarkdownMessage(input: GetStatusResult, copy: BotCopy = BOT_COPY): string {\n const layout = getStatusLayoutCopy(copy);\n const sections = [\n presentStatusMarkdownSection(layout.overviewTitle, presentStatusMarkdownOverviewLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.workspaceTitle, presentStatusMarkdownWorkspaceLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.pluginsTitle, presentStatusMarkdownPluginLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.mcpTitle, presentStatusMarkdownMcpLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.lspTitle, presentStatusMarkdownLspLines(input, copy, layout)),\n ];\n\n return presentStatusSections(sections);\n}\n\nexport function presentMcpMessage(input: McpMessageInput, copy: BotCopy = BOT_COPY): string {\n const lines = [\n copy.mcp.title,\n copy.mcp.currentProject(input.currentDirectory),\n \"\",\n ];\n\n if (input.statuses.length === 0) {\n lines.push(copy.mcp.none);\n return lines.join(\"\\n\");\n }\n\n lines.push(...input.statuses.map(({ name, status }) => `${name}: ${formatMcpStatus(status, copy)}`));\n\n return lines.join(\"\\n\");\n}\n\nexport function presentLspMessage(input: LspMessageInput, copy: BotCopy = BOT_COPY): string {\n const lines = [\n copy.lsp.title,\n copy.lsp.currentProject(input.currentDirectory),\n \"\",\n ];\n\n if (input.statuses.length === 0) {\n lines.push(copy.lsp.none);\n return lines.join(\"\\n\");\n }\n\n lines.push(...input.statuses.map((status) => `${status.name}: ${formatLspStatus(status, copy)}`));\n\n return lines.join(\"\\n\");\n}\n\nfunction presentStatusSections(sections: string[]): string {\n return sections.flatMap((section, index) => index === 0 ? [section] : [\"\", section]).join(\"\\n\");\n}\n\nfunction presentStatusPlainSection(title: string, lines: string[]): string {\n return [\n title,\n ...lines,\n ].join(\"\\n\");\n}\n\nfunction presentStatusMarkdownSection(title: string, lines: string[]): string {\n return [\n `## ${title}`,\n ...lines,\n ].join(\"\\n\");\n}\n\nfunction presentStatusPlainOverviewLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const lines = [\n presentPlainStatusBullet(\n layout.connectivityLabel,\n input.health.status === \"error\"\n ? layout.errorStatus\n : formatHealthBadge(input.health.data.healthy, layout),\n ),\n ];\n\n if (input.health.status === \"error\") {\n return [\n ...lines,\n ...presentStatusPlainErrorDetailLines(input.health.error, copy, layout),\n presentPlainStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n }\n\n return [\n ...lines,\n presentPlainStatusBullet(layout.openCodeVersionLabel, input.health.data.version),\n presentPlainStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n}\n\nfunction presentStatusMarkdownOverviewLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const lines = [\n presentMarkdownStatusBullet(\n layout.connectivityLabel,\n input.health.status === \"error\"\n ? layout.errorStatus\n : formatHealthBadge(input.health.data.healthy, layout),\n ),\n ];\n\n if (input.health.status === \"error\") {\n return [\n ...lines,\n ...presentStatusMarkdownErrorDetailLines(input.health.error, copy, layout),\n presentMarkdownStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n }\n\n return [\n ...lines,\n presentMarkdownStatusBullet(layout.openCodeVersionLabel, input.health.data.version),\n presentMarkdownStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n}\n\nfunction presentStatusPlainWorkspaceLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.workspace.status === \"error\") {\n return presentStatusPlainErrorLines(input.workspace.error, copy, layout);\n }\n\n return [\n presentPlainStatusBullet(layout.currentProjectLabel, input.workspace.data.currentProject),\n presentPlainStatusBullet(layout.currentSessionLabel, input.workspace.data.currentSession ?? layout.defaultSessionValue),\n ];\n}\n\nfunction presentStatusMarkdownWorkspaceLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.workspace.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.workspace.error, copy, layout);\n }\n\n return [\n presentMarkdownStatusBullet(layout.currentProjectLabel, input.workspace.data.currentProject, {\n codeValue: true,\n }),\n presentMarkdownStatusBullet(layout.currentSessionLabel, input.workspace.data.currentSession ?? layout.defaultSessionValue),\n ];\n}\n\nfunction presentStatusPlainPluginLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.plugins.status === \"error\") {\n return presentStatusPlainErrorLines(input.plugins.error, copy, layout);\n }\n\n if (input.plugins.data.plugins.length === 0) {\n return [\n ...presentPlainEmptyStatusLines(layout.noPluginsMessage, layout),\n ];\n }\n\n return input.plugins.data.plugins.map((plugin) => `- ${plugin}`);\n}\n\nfunction presentStatusMarkdownPluginLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.plugins.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.plugins.error, copy, layout);\n }\n\n if (input.plugins.data.plugins.length === 0) {\n return [\n ...presentMarkdownEmptyStatusLines(layout.noPluginsMessage, layout),\n ];\n }\n\n return input.plugins.data.plugins.map((plugin) => `- \\`${plugin}\\``);\n}\n\nfunction presentStatusPlainLspLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.lsp.status === \"error\") {\n return presentStatusPlainErrorLines(input.lsp.error, copy, layout);\n }\n\n if (input.lsp.data.statuses.length === 0) {\n return presentPlainEmptyStatusLines(copy.lsp.none, layout);\n }\n\n return input.lsp.data.statuses.flatMap((status) => presentPlainStatusGroup(status.name, [\n {\n label: layout.statusLabel,\n value: formatLspStatusBadge(status),\n },\n ]));\n}\n\nfunction presentStatusMarkdownLspLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.lsp.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.lsp.error, copy, layout);\n }\n\n if (input.lsp.data.statuses.length === 0) {\n return presentMarkdownEmptyStatusLines(copy.lsp.none, layout);\n }\n\n return input.lsp.data.statuses.flatMap((status) => presentMarkdownStatusGroup(status.name, [\n {\n label: layout.statusLabel,\n value: formatLspStatusBadge(status),\n },\n ]));\n}\n\nfunction presentStatusPlainMcpLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.mcp.status === \"error\") {\n return presentStatusPlainErrorLines(input.mcp.error, copy, layout);\n }\n\n if (input.mcp.data.statuses.length === 0) {\n return presentPlainEmptyStatusLines(copy.mcp.none, layout);\n }\n\n return input.mcp.data.statuses.flatMap(({ name, status }) =>\n presentPlainStatusGroup(name, getMcpStatusDetailLines(status, copy, layout)),\n );\n}\n\nfunction presentStatusMarkdownMcpLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.mcp.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.mcp.error, copy, layout);\n }\n\n if (input.mcp.data.statuses.length === 0) {\n return presentMarkdownEmptyStatusLines(copy.mcp.none, layout);\n }\n\n return input.mcp.data.statuses.flatMap(({ name, status }) =>\n presentMarkdownStatusGroup(name, getMcpStatusDetailLines(status, copy, layout), {\n codeName: true,\n }),\n );\n}\n\nfunction presentStatusPlainErrorLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n return [\n presentPlainStatusBullet(layout.statusLabel, layout.errorStatus),\n ...presentStatusPlainErrorDetailLines(error, copy, layout),\n ];\n}\n\nfunction presentStatusPlainErrorDetailLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const detailLines = splitStatusLines(presentError(error, copy));\n\n return detailLines.map((line) => presentPlainStatusBullet(layout.detailsLabel, line));\n}\n\nfunction presentStatusMarkdownErrorLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n return [\n presentMarkdownStatusBullet(layout.statusLabel, layout.errorStatus),\n ...presentStatusMarkdownErrorDetailLines(error, copy, layout),\n ];\n}\n\nfunction presentStatusMarkdownErrorDetailLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const detailLines = splitStatusLines(presentError(error, copy));\n\n return detailLines.map((line) => presentMarkdownStatusBullet(layout.detailsLabel, line));\n}\n\nfunction presentPlainEmptyStatusLines(message: string, layout: StatusLayoutCopy): string[] {\n return [\n presentPlainStatusBullet(layout.statusLabel, layout.noneStatus),\n presentPlainStatusBullet(layout.detailsLabel, message),\n ];\n}\n\nfunction presentMarkdownEmptyStatusLines(message: string, layout: StatusLayoutCopy): string[] {\n return [\n presentMarkdownStatusBullet(layout.statusLabel, layout.noneStatus),\n presentMarkdownStatusBullet(layout.detailsLabel, message),\n ];\n}\n\nfunction presentPlainStatusGroup(name: string, details: StatusDetailLine[]): string[] {\n return [\n `- ${normalizeStatusInlineValue(name)}`,\n ...details.map((detail) => ` - ${detail.label}: ${formatStatusValue(detail.value)}`),\n ];\n}\n\nfunction presentMarkdownStatusGroup(\n name: string,\n details: StatusDetailLine[],\n options: {\n codeName?: boolean;\n } = {},\n): string[] {\n const renderedName = options.codeName\n ? `\\`${normalizeStatusInlineValue(name)}\\``\n : `**${normalizeStatusInlineValue(name)}**`;\n\n return [\n `- ${renderedName}`,\n ...details.map((detail) => detail.codeValue\n ? ` - **${detail.label}:** \\`${formatStatusValue(detail.value)}\\``\n : ` - **${detail.label}:** ${formatStatusValue(detail.value)}`),\n ];\n}\n\nfunction presentPlainStatusBullet(label: string, value: string): string {\n return `- ${label}: ${formatStatusValue(value)}`;\n}\n\nfunction presentMarkdownStatusBullet(\n label: string,\n value: string,\n options: {\n codeValue?: boolean;\n } = {},\n): string {\n return options.codeValue\n ? `- **${label}:** \\`${formatStatusValue(value)}\\``\n : `- **${label}:** ${formatStatusValue(value)}`;\n}\n\nfunction splitStatusLines(text: string): string[] {\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n}\n\nfunction formatHealthBadge(healthy: boolean, layout: StatusLayoutCopy): string {\n return healthy ? \"\\uD83D\\uDFE2\" : layout.errorStatus;\n}\n\nfunction formatLspStatusBadge(status: OpenCodeLspStatus): string {\n switch (status.status) {\n case \"connected\":\n return \"\\uD83D\\uDFE2\";\n case \"error\":\n return \"\\uD83D\\uDD34\";\n }\n\n const exhaustiveStatus: never = status.status;\n\n return exhaustiveStatus;\n}\n\nfunction formatMcpStatusBadge(status: OpenCodeMcpStatus, layout: StatusLayoutCopy): string {\n switch (status.status) {\n case \"connected\":\n return \"\\uD83D\\uDFE2\";\n case \"disabled\":\n return \"\\u26AA\";\n case \"needs_auth\":\n return \"\\uD83D\\uDFE1\";\n case \"failed\":\n return layout.mcpFailedStatus;\n case \"needs_client_registration\":\n return layout.mcpRegistrationRequiredStatus;\n }\n\n const exhaustiveStatus: never = status;\n\n return exhaustiveStatus;\n}\n\nfunction getMcpStatusDetailLines(\n status: OpenCodeMcpStatus,\n copy: BotCopy,\n layout: StatusLayoutCopy,\n): StatusDetailLine[] {\n const notes = formatMcpStatusNotes(status, copy, layout);\n\n return notes\n ? [\n {\n label: layout.statusLabel,\n value: formatMcpStatusBadge(status, layout),\n },\n {\n label: layout.mcpNotesLabel,\n value: notes,\n },\n ]\n : [\n {\n label: layout.statusLabel,\n value: formatMcpStatusBadge(status, layout),\n },\n ];\n}\n\nfunction formatMcpStatusNotes(status: OpenCodeMcpStatus, copy: BotCopy, layout: StatusLayoutCopy): string | null {\n switch (status.status) {\n case \"connected\":\n return null;\n case \"disabled\":\n return null;\n case \"needs_auth\":\n return copy.mcp.needsAuth;\n case \"failed\":\n return status.error;\n case \"needs_client_registration\":\n return status.error;\n }\n\n const exhaustiveStatus: never = status;\n\n return exhaustiveStatus;\n}\n\nfunction formatStatusValue(value: string): string {\n const normalized = value\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .join(\" / \");\n\n return normalized.length > 0 ? normalized : \"-\";\n}\n\nfunction normalizeStatusInlineValue(value: string): string {\n return formatStatusValue(value);\n}\n\nfunction getStatusLayoutCopy(copy: BotCopy): StatusLayoutCopy {\n if (copy.locale === \"en\") {\n return {\n connectivityLabel: \"Connectivity\",\n currentProjectLabel: \"Current Project\",\n currentSessionLabel: \"Current Session\",\n defaultSessionValue: \"OpenCode Default\",\n detailsLabel: \"Details\",\n errorStatus: \"\\uD83D\\uDD34\",\n lspTitle: \"\\uD83E\\uDDE0 LSP\",\n mcpFailedStatus: \"\\uD83D\\uDD34\",\n mcpNotesLabel: \"Notes\",\n mcpRegistrationRequiredStatus: \"\\uD83D\\uDFE1\",\n mcpTitle: \"\\uD83D\\uDD0C MCP\",\n noPluginsMessage: \"No plugins detected in the current OpenCode setup.\",\n noneStatus: \"\\u26AA\",\n openCodeVersionLabel: \"OpenCode Version\",\n overviewTitle: \"\\uD83D\\uDDA5\\uFE0F Overview\",\n pluginsTitle: \"\\uD83E\\uDDE9 Plugins\",\n statusLabel: \"Status\",\n tbotVersionLabel: \"opencode-tbot Version\",\n workspaceTitle: \"\\uD83D\\uDCC1 Workspace\",\n };\n }\n\n if (copy.locale === \"ja\") {\n return {\n connectivityLabel: \"接続性\",\n currentProjectLabel: \"現在のプロジェクト\",\n currentSessionLabel: \"現在のセッション\",\n defaultSessionValue: \"OpenCode のデフォルト\",\n detailsLabel: \"詳細\",\n errorStatus: \"\\uD83D\\uDD34\",\n lspTitle: \"\\uD83E\\uDDE0 LSP\",\n mcpFailedStatus: \"\\uD83D\\uDD34\",\n mcpNotesLabel: \"補足\",\n mcpRegistrationRequiredStatus: \"\\uD83D\\uDFE1\",\n mcpTitle: \"\\uD83D\\uDD0C MCP\",\n noPluginsMessage: \"現在の OpenCode 構成ではプラグインが検出されていません。\",\n noneStatus: \"\\u26AA\",\n openCodeVersionLabel: \"OpenCode バージョン\",\n overviewTitle: \"\\uD83D\\uDDA5\\uFE0F 概要\",\n pluginsTitle: \"\\uD83E\\uDDE9 プラグイン\",\n statusLabel: \"状態\",\n tbotVersionLabel: \"opencode-tbot バージョン\",\n workspaceTitle: \"\\uD83D\\uDCC1 ワークスペース\",\n };\n }\n\n return {\n connectivityLabel: \"\\u8FDE\\u901A\\u6027\",\n currentProjectLabel: \"\\u5F53\\u524D\\u9879\\u76EE\",\n currentSessionLabel: \"\\u5F53\\u524D\\u4F1A\\u8BDD\",\n defaultSessionValue: \"OpenCode \\u9ED8\\u8BA4\",\n detailsLabel: \"\\u8BE6\\u60C5\",\n errorStatus: \"\\uD83D\\uDD34\",\n lspTitle: \"\\uD83E\\uDDE0 LSP\",\n mcpFailedStatus: \"\\uD83D\\uDD34\",\n mcpNotesLabel: \"\\u8BF4\\u660E\",\n mcpRegistrationRequiredStatus: \"\\uD83D\\uDFE1\",\n mcpTitle: \"\\uD83D\\uDD0C MCP\",\n noPluginsMessage: \"\\u5F53\\u524D OpenCode \\u73AF\\u5883\\u4E2D\\u672A\\u68C0\\u6D4B\\u5230\\u63D2\\u4EF6\\u3002\",\n noneStatus: \"\\u26AA\",\n openCodeVersionLabel: \"OpenCode\\u7248\\u672C\",\n overviewTitle: \"\\uD83D\\uDDA5\\uFE0F \\u6982\\u89C8\",\n pluginsTitle: \"\\uD83E\\uDDE9 \\u63D2\\u4EF6\",\n statusLabel: \"\\u72B6\\u6001\",\n tbotVersionLabel: \"opencode-tbot\\u7248\\u672C\",\n workspaceTitle: \"\\uD83D\\uDCC1 \\u5DE5\\u4F5C\\u533A\",\n };\n}\n\nexport function presentSessionsMessage(input: SessionsMessageInput, copy: BotCopy = BOT_COPY): string {\n if (input.sessions.length === 0) {\n return copy.sessions.none;\n }\n\n const page = getSessionsPage(input.sessions, input.page);\n const currentSession = input.currentSessionId\n ? input.sessions.find((session) => session.id === input.currentSessionId) ?? null\n : null;\n const lines = [\n copy.sessions.title,\n copy.sessions.currentProject(input.currentDirectory),\n copy.sessions.currentSession(currentSession ? formatSessionLabel(currentSession) : copy.common.notSelected),\n copy.common.page(page.page + 1, page.totalPages),\n \"\",\n ...page.items.map((session, index) => `${page.startIndex + index + 1}. ${formatSessionLabel(session)}`),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentSessionSwitchMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return [\n copy.sessions.switched,\n copy.sessions.currentSession(formatSessionLabel(session)),\n ].join(\"\\n\");\n}\n\nexport function presentSessionCreatedMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return [\n copy.sessions.created,\n copy.sessions.currentSession(formatSessionLabel(session)),\n ].join(\"\\n\");\n}\n\nexport function presentSessionActionsMessage(\n input: { currentDirectory: string; session: OpenCodeSession },\n copy: BotCopy = BOT_COPY,\n): string {\n return [\n copy.sessions.actionTitle,\n copy.sessions.currentProject(input.currentDirectory),\n copy.sessions.selectedSession(formatSessionLabel(input.session)),\n \"\",\n copy.sessions.chooseAction,\n ].join(\"\\n\");\n}\n\nexport function presentSessionRenamePromptMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return copy.sessions.renamePrompt(formatSessionLabel(session));\n}\n\nexport function presentSessionRenamedMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return [\n copy.sessions.renamed,\n copy.sessions.currentSession(formatSessionLabel(session)),\n ].join(\"\\n\");\n}\n\nexport function presentAgentsMessage(input: AgentsMessageInput, copy: BotCopy = BOT_COPY): string {\n if (input.agents.length === 0) {\n return copy.agents.none;\n }\n\n const page = getAgentsPage(input.agents, input.page);\n const currentAgent = input.currentAgentName\n ? input.agents.find((agent) => agent.name === input.currentAgentName) ?? null\n : null;\n const lines = [\n copy.agents.title,\n copy.agents.current(currentAgent ? formatAgentLabel(currentAgent) : copy.common.openCodeDefault),\n copy.common.page(page.page + 1, page.totalPages),\n \"\",\n ...page.items.map((agent, index) => `${page.startIndex + index + 1}. ${formatAgentLabel(agent)}`),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentAgentSwitchMessage(agent: OpenCodeAgent, copy: BotCopy = BOT_COPY): string {\n return [\n copy.agents.switched,\n copy.agents.current(formatAgentLabel(agent)),\n ].join(\"\\n\");\n}\n\nexport function presentModelsMessage(input: ModelsMessageInput, copy: BotCopy = BOT_COPY): string {\n if (input.models.length === 0) {\n return copy.models.none;\n }\n\n const page = getModelsPage(input.models, input.page);\n const currentModel = input.currentModelId && input.currentModelProviderId\n ? input.models.find((model) =>\n model.id === input.currentModelId && model.providerID === input.currentModelProviderId,\n ) ?? null\n : null;\n const currentModelLine = currentModel\n ? formatModelSelection(currentModel, input.currentModelVariant, copy)\n : copy.common.openCodeDefault;\n const lines = [\n copy.models.title,\n copy.models.configuredOnly,\n copy.models.current(currentModelLine),\n copy.common.page(page.page + 1, page.totalPages),\n \"\",\n ...page.items.map((model, index) => formatModelListLine(model, page.startIndex + index + 1)),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentModelVariantsMessage(\n model: OpenCodeConfiguredModel,\n modelIndex: number,\n copy: BotCopy = BOT_COPY,\n): string {\n const variants = getModelVariants(model);\n\n if (variants.length === 0) {\n return [\n copy.models.noReasoningLevels,\n copy.models.model(formatModelLabel(model)),\n ].join(\"\\n\");\n }\n\n const lines = [\n copy.models.reasoningLevelsTitle,\n copy.models.model(formatModelLabel(model)),\n copy.models.modelNumber(modelIndex),\n \"\",\n ...variants.map((variant, index) => `${index + 1}. ${variant}`),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentModelSwitchMessage(\n model: OpenCodeConfiguredModel,\n variant: string | null,\n copy: BotCopy = BOT_COPY,\n): string {\n return [\n copy.models.switched,\n copy.models.current(formatModelLabel(model)),\n copy.models.currentReasoningLevel(variant ?? copy.models.defaultReasoningLevel),\n ].join(\"\\n\");\n}\n\nexport function presentLanguageMessage(currentLanguage: BotLanguage, copy: BotCopy = BOT_COPY): string {\n return [\n copy.language.title,\n copy.language.current(getLanguageLabel(currentLanguage, copy)),\n \"\",\n copy.language.choose,\n ].join(\"\\n\");\n}\n\nexport function presentLanguageSwitchMessage(currentLanguage: BotLanguage, copy: BotCopy = BOT_COPY): string {\n return [\n copy.language.switched,\n copy.language.current(getLanguageLabel(currentLanguage, copy)),\n ].join(\"\\n\");\n}\n\nexport function getModelVariants(model: OpenCodeConfiguredModel): string[] {\n return Object.keys(model.variants)\n .sort((left, right) => compareVariantNames(left, right));\n}\n\nfunction compareVariantNames(left: string, right: string): number {\n const leftIndex = VARIANT_ORDER.indexOf(left);\n const rightIndex = VARIANT_ORDER.indexOf(right);\n\n if (leftIndex === -1 && rightIndex === -1) {\n return left.localeCompare(right);\n }\n\n if (leftIndex === -1) {\n return 1;\n }\n\n if (rightIndex === -1) {\n return -1;\n }\n\n return leftIndex - rightIndex;\n}\n\nfunction formatAgentLabel(agent: OpenCodeAgent): string {\n return agent.name;\n}\n\nfunction formatModelListLine(model: OpenCodeConfiguredModel, displayIndex: number): string {\n return `${displayIndex}. ${formatModelLabel(model)}`;\n}\n\nfunction formatModelSelection(\n model: OpenCodeConfiguredModel,\n variant: string | null,\n copy: BotCopy,\n): string {\n return `${formatModelLabel(model)} | ${copy.models.reasoningLevel(variant ?? copy.models.defaultReasoningLevel)}`;\n}\n\nfunction formatModelLabel(model: OpenCodeConfiguredModel): string {\n return `${model.providerName} / ${model.name}`;\n}\n\nfunction formatSessionLabel(session: OpenCodeSession): string {\n const title = session.title.trim() || session.slug || session.id;\n\n return title === session.slug\n ? title\n : `${title} [${session.slug}]`;\n}\n\nfunction formatMcpStatus(status: OpenCodeMcpStatus, copy: BotCopy): string {\n switch (status.status) {\n case \"connected\":\n return copy.mcp.connected;\n case \"disabled\":\n return copy.mcp.disabled;\n case \"needs_auth\":\n return copy.mcp.needsAuth;\n case \"failed\":\n return copy.mcp.failed(status.error);\n case \"needs_client_registration\":\n return copy.mcp.needsClientRegistration(status.error);\n }\n\n const exhaustiveStatus: never = status;\n\n return exhaustiveStatus;\n}\n\nfunction formatLspStatus(status: OpenCodeLspStatus, copy: BotCopy): string {\n switch (status.status) {\n case \"connected\":\n return copy.lsp.connected;\n case \"error\":\n return copy.lsp.error;\n }\n\n const exhaustiveStatus: never = status.status;\n\n return exhaustiveStatus;\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { buildAgentsKeyboard } from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentAgentsMessage } from \"../presenters/message.presenter.js\";\n\ninterface AgentsCommandContext {\n chat: { id: number };\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleAgentsCommand(ctx: AgentsCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n const result = await dependencies.listAgentsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.agents.length === 0) {\n await ctx.reply(copy.agents.none);\n return;\n }\n\n const { keyboard, page } = buildAgentsKeyboard(result.agents, 0, copy);\n\n await ctx.reply(\n presentAgentsMessage({\n agents: result.agents,\n currentAgentName: result.currentAgentName,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to list agents\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerAgentsCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command([\"agents\", \"agent\"], async (ctx) => {\n await handleAgentsCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { OpenCodeSession } from \"../services/opencode/opencode.client.js\";\nimport { getSafeChatCopy } from \"./i18n.js\";\nimport {\n buildSessionActionKeyboard,\n buildSessionsKeyboard,\n} from \"./presenters/keyboard.presenter.js\";\nimport {\n presentSessionActionsMessage,\n presentSessionsMessage,\n} from \"./presenters/message.presenter.js\";\nimport type { BotDependencies } from \"./types.js\";\n\ninterface SessionsMessageApi {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n}\n\ninterface SessionsListView {\n copy: Awaited<ReturnType<typeof getSafeChatCopy>>;\n currentDirectory: string;\n currentSessionId: string | null;\n keyboard?: unknown;\n page: number;\n sessions: OpenCodeSession[];\n text: string;\n}\n\nexport async function buildSessionsListView(\n chatId: number,\n requestedPage: number,\n dependencies: BotDependencies,\n): Promise<SessionsListView> {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, chatId, dependencies.logger);\n const result = await dependencies.listSessionsUseCase.execute({\n chatId,\n });\n\n if (result.sessions.length === 0) {\n return {\n copy,\n currentDirectory: result.currentDirectory,\n currentSessionId: result.currentSessionId,\n page: 0,\n sessions: [],\n text: copy.sessions.none,\n };\n }\n\n const { keyboard, page } = buildSessionsKeyboard(result.sessions, requestedPage, copy);\n\n return {\n copy,\n currentDirectory: result.currentDirectory,\n currentSessionId: result.currentSessionId,\n keyboard,\n page: page.page,\n sessions: result.sessions,\n text: presentSessionsMessage({\n currentDirectory: result.currentDirectory,\n currentSessionId: result.currentSessionId,\n page: page.page,\n sessions: result.sessions,\n }, copy),\n };\n}\n\nexport async function buildSessionActionView(\n chatId: number,\n requestedPage: number,\n sessionId: string,\n dependencies: BotDependencies,\n) {\n const listView = await buildSessionsListView(chatId, requestedPage, dependencies);\n const session = listView.sessions.find((item) => item.id === sessionId);\n\n if (!session) {\n return {\n copy: listView.copy,\n found: false as const,\n };\n }\n\n return {\n copy: listView.copy,\n found: true as const,\n keyboard: buildSessionActionKeyboard(session.id, listView.page, listView.copy),\n page: listView.page,\n session,\n text: presentSessionActionsMessage({\n currentDirectory: listView.currentDirectory,\n session,\n }, listView.copy),\n };\n}\n\nexport async function restoreSessionsListMessage(\n api: SessionsMessageApi,\n chatId: number,\n messageId: number,\n requestedPage: number,\n dependencies: BotDependencies,\n) {\n const listView = await buildSessionsListView(chatId, requestedPage, dependencies);\n\n if (listView.keyboard) {\n await api.editMessageText(chatId, messageId, listView.text, {\n reply_markup: listView.keyboard,\n });\n } else {\n await api.editMessageText(chatId, messageId, listView.text);\n }\n\n return listView;\n}\n","import type { PendingChatAction, SessionRenamePendingAction } from \"../domain/pending-action/pending-action.entity.js\";\nimport { getSafeChatCopy } from \"./i18n.js\";\nimport { restoreSessionsListMessage } from \"./sessions-menu.js\";\nimport { presentError } from \"./presenters/error.presenter.js\";\nimport { presentSessionRenamedMessage } from \"./presenters/message.presenter.js\";\nimport type { BotDependencies } from \"./types.js\";\n\ninterface SessionRenameApi {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n}\n\ninterface SessionRenameReplyContext {\n api: SessionRenameApi;\n chat: { id: number };\n reply(text: string): Promise<unknown>;\n}\n\ninterface SessionRenameTextContext extends SessionRenameReplyContext {\n message: { text?: string };\n}\n\nexport async function getPendingSessionRenameAction(\n dependencies: BotDependencies,\n chatId: number,\n): Promise<SessionRenamePendingAction | null> {\n const action = await dependencies.pendingActionRepo.getByChatId(chatId);\n\n return isSessionRenamePendingAction(action) ? action : null;\n}\n\nexport async function replyIfSessionRenamePending(\n ctx: Pick<SessionRenameReplyContext, \"chat\" | \"reply\">,\n dependencies: BotDependencies,\n): Promise<boolean> {\n const pendingAction = await getPendingSessionRenameAction(dependencies, ctx.chat.id);\n\n if (!pendingAction) {\n return false;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n await ctx.reply(copy.sessions.renamePendingInput);\n\n return true;\n}\n\nexport async function handlePendingSessionRenameText(\n ctx: SessionRenameTextContext,\n dependencies: BotDependencies,\n): Promise<boolean> {\n const pendingAction = await getPendingSessionRenameAction(dependencies, ctx.chat.id);\n\n if (!pendingAction) {\n return false;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n const title = ctx.message.text?.trim() ?? \"\";\n\n if (title.startsWith(\"/\")) {\n await ctx.reply(copy.sessions.renamePendingInput);\n return true;\n }\n\n if (!title) {\n await ctx.reply(copy.sessions.renameEmpty);\n return true;\n }\n\n try {\n const result = await dependencies.renameSessionUseCase.execute({\n chatId: ctx.chat.id,\n sessionId: pendingAction.sessionId,\n title,\n });\n\n await dependencies.pendingActionRepo.clear(ctx.chat.id);\n\n await bestEffortRestoreSessionsList(ctx.api, pendingAction, dependencies);\n\n if (!result.found) {\n await ctx.reply(copy.sessions.renameExpired);\n return true;\n }\n\n await ctx.reply(presentSessionRenamedMessage(result.session, copy));\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to rename session\");\n await ctx.reply(presentError(error, copy));\n }\n\n return true;\n}\n\nexport async function cancelPendingSessionRename(\n ctx: SessionRenameReplyContext,\n dependencies: BotDependencies,\n): Promise<boolean> {\n const pendingAction = await getPendingSessionRenameAction(dependencies, ctx.chat.id);\n\n if (!pendingAction) {\n return false;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n await dependencies.pendingActionRepo.clear(ctx.chat.id);\n await bestEffortRestoreSessionsList(ctx.api, pendingAction, dependencies);\n await ctx.reply(copy.sessions.renameCancelled);\n\n return true;\n}\n\nasync function bestEffortRestoreSessionsList(\n api: SessionRenameApi,\n pendingAction: SessionRenamePendingAction,\n dependencies: BotDependencies,\n) {\n try {\n await restoreSessionsListMessage(\n api,\n pendingAction.chatId,\n pendingAction.menuMessageId,\n pendingAction.returnPage,\n dependencies,\n );\n } catch (error) {\n dependencies.logger.warn?.({ error }, \"failed to restore sessions list message\");\n }\n}\n\nfunction isSessionRenamePendingAction(action: PendingChatAction | null): action is SessionRenamePendingAction {\n return action?.kind === \"session_rename\";\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { cancelPendingSessionRename } from \"../session-rename.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface CancelCommandContext {\n api: {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n };\n chat: { id: number };\n reply(text: string): Promise<unknown>;\n}\n\nexport async function handleCancelCommand(ctx: CancelCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (await cancelPendingSessionRename(ctx, dependencies)) {\n return;\n }\n\n const result = await dependencies.abortPromptUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.status === \"no_session\") {\n await ctx.reply(copy.abort.noSession);\n return;\n }\n\n if (result.status === \"not_running\") {\n await ctx.reply(copy.abort.notRunning);\n return;\n }\n\n await ctx.reply(copy.abort.aborted);\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to cancel current action\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerCancelCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"cancel\", async (ctx) => {\n await handleCancelCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { isBotLanguage } from \"../copy.js\";\nimport {\n getSafeChatCopy,\n getSafeChatLanguage,\n setChatLanguage,\n} from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { buildLanguageKeyboard } from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport {\n presentLanguageMessage,\n presentLanguageSwitchMessage,\n} from \"../presenters/message.presenter.js\";\nimport { syncTelegramCommandsForChat } from \"./sync-commands.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface LanguageCommandContext {\n chat: { id: number };\n api: Pick<Bot[\"api\"], \"setMyCommands\">;\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleLanguageCommand(ctx: LanguageCommandContext, dependencies: BotDependencies) {\n const language = await getSafeChatLanguage(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n await syncTelegramCommandsForChat(ctx.api, ctx.chat.id, language);\n await ctx.reply(\n presentLanguageMessage(language, copy),\n {\n reply_markup: buildLanguageKeyboard(language, copy),\n },\n );\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to show language options\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport async function switchLanguageForChat(\n api: Pick<Bot[\"api\"], \"setMyCommands\">,\n chatId: number,\n language: string,\n dependencies: BotDependencies,\n): Promise<\n | { found: false; copy: Awaited<ReturnType<typeof getSafeChatCopy>> }\n | {\n found: true;\n copy: Awaited<ReturnType<typeof getSafeChatCopy>>;\n language: Awaited<ReturnType<typeof getSafeChatLanguage>>;\n }\n> {\n const currentCopy = await getSafeChatCopy(dependencies.sessionRepo, chatId, dependencies.logger);\n\n if (!isBotLanguage(language)) {\n return {\n found: false,\n copy: currentCopy,\n };\n }\n\n await setChatLanguage(dependencies.sessionRepo, chatId, language);\n await syncTelegramCommandsForChat(api, chatId, language);\n\n return {\n found: true,\n copy: await getSafeChatCopy(dependencies.sessionRepo, chatId, dependencies.logger),\n language,\n };\n}\n\nexport async function presentLanguageSwitchForChat(\n chatId: number,\n api: Pick<Bot[\"api\"], \"setMyCommands\">,\n language: string,\n dependencies: BotDependencies,\n) {\n const result = await switchLanguageForChat(api, chatId, language, dependencies);\n\n if (!result.found) {\n return {\n found: false as const,\n copy: result.copy,\n text: result.copy.language.expired,\n keyboard: buildLanguageKeyboard(\n await getSafeChatLanguage(dependencies.sessionRepo, chatId, dependencies.logger),\n result.copy,\n ),\n };\n }\n\n return {\n found: true as const,\n copy: result.copy,\n text: presentLanguageSwitchMessage(result.language, result.copy),\n keyboard: buildLanguageKeyboard(result.language, result.copy),\n };\n}\n\nexport function registerLanguageCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"language\", async (ctx) => {\n await handleLanguageCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { buildModelsKeyboard } from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentModelsMessage } from \"../presenters/message.presenter.js\";\n\ninterface ModelsCommandContext {\n chat: { id: number };\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleModelsCommand(ctx: ModelsCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.models.length === 0) {\n await ctx.reply(copy.models.none);\n return;\n }\n\n const { keyboard, page } = buildModelsKeyboard(result.models, 0, copy);\n\n await ctx.reply(\n presentModelsMessage({\n currentModelId: result.currentModelId,\n currentModelProviderId: result.currentModelProviderId,\n currentModelVariant: result.currentModelVariant,\n models: result.models,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to list models\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerModelsCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command([\"model\", \"models\"], async (ctx) => {\n await handleModelsCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentSessionCreatedMessage } from \"../presenters/message.presenter.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface NewCommandContext {\n chat: { id: number };\n message?: { text?: string };\n match?: string;\n reply(text: string): Promise<unknown>;\n}\n\nexport async function handleNewCommand(ctx: NewCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n const title = extractSessionTitle(ctx);\n const result = await dependencies.createSessionUseCase.execute({\n chatId: ctx.chat.id,\n title,\n });\n\n await ctx.reply(presentSessionCreatedMessage(result.session, copy));\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to create new session\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerNewCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"new\", async (ctx) => {\n await handleNewCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n\nfunction extractSessionTitle(ctx: NewCommandContext): string | null {\n if (typeof ctx.match === \"string\") {\n const title = ctx.match.trim();\n\n return title ? title : null;\n }\n\n const messageText = ctx.message?.text?.trim();\n\n if (!messageText) {\n return null;\n }\n\n const match = messageText.match(/^\\/new(?:@\\S+)?(?:\\s+([\\s\\S]*))?$/i);\n const title = match?.[1]?.trim();\n\n return title ? title : null;\n}\n","import { BOT_COPY, type BotCopy } from \"../../bot/copy.js\";\nimport { stripMarkdownToPlainText } from \"../../infra/utils/markdown-text.js\";\nimport type {\n PromptSessionMetrics,\n PromptSessionResult,\n} from \"../opencode/opencode.client.js\";\n\nconst MAX_TELEGRAM_MESSAGE_LENGTH = 4096;\nconst TRUNCATED_SUFFIX = \"...\";\nconst MARKDOWN_SPECIAL_CHARACTERS = /([_*\\[\\]()~`>#+\\-=|{}.!\\\\])/g;\nexport { stripMarkdownToPlainText } from \"../../infra/utils/markdown-text.js\";\n\nexport interface TelegramReplyPayload {\n options?: {\n parse_mode: \"MarkdownV2\";\n };\n text: string;\n}\n\nexport interface TelegramPromptReply {\n fallback: TelegramReplyPayload;\n preferred: TelegramReplyPayload;\n}\n\nexport interface TelegramStaticReply {\n fallback: TelegramReplyPayload;\n preferred: TelegramReplyPayload;\n}\n\nexport function buildTelegramPromptReply(\n result: PromptSessionResult,\n copy: BotCopy = BOT_COPY,\n): TelegramPromptReply {\n const renderedMarkdown = result.bodyMd ? renderMarkdownToTelegramMarkdownV2(result.bodyMd) : null;\n const footerPlain = formatPlainMetricsFooter(result.metrics, copy);\n const plainBody = normalizePlainBody(result, copy);\n const fallback = {\n text: joinBodyAndFooter(\n truncatePlainBody(plainBody, footerPlain),\n footerPlain,\n ),\n };\n\n if (!renderedMarkdown) {\n return {\n preferred: fallback,\n fallback,\n };\n }\n\n const footerMarkdown = formatMarkdownMetricsFooter(result.metrics, copy);\n const markdownText = joinBodyAndFooter(renderedMarkdown, footerMarkdown);\n\n if (markdownText.length > MAX_TELEGRAM_MESSAGE_LENGTH) {\n return {\n preferred: fallback,\n fallback,\n };\n }\n\n return {\n preferred: {\n text: markdownText,\n options: {\n parse_mode: \"MarkdownV2\",\n },\n },\n fallback,\n };\n}\n\nexport function buildTelegramStaticReply(markdown: string): TelegramStaticReply {\n const renderedMarkdown = renderMarkdownToTelegramMarkdownV2(markdown);\n const plainText = truncateStaticText(stripMarkdownToPlainText(markdown) || markdown.trim());\n const fallback = {\n text: plainText,\n };\n\n if (!renderedMarkdown || renderedMarkdown.length > MAX_TELEGRAM_MESSAGE_LENGTH) {\n return {\n preferred: fallback,\n fallback,\n };\n }\n\n return {\n preferred: {\n text: renderedMarkdown,\n options: {\n parse_mode: \"MarkdownV2\",\n },\n },\n fallback,\n };\n}\n\nexport function renderMarkdownToTelegramMarkdownV2(markdown: string): string | null {\n const normalizedMarkdown = preprocessMarkdownForTelegram(markdown).trim();\n\n if (!normalizedMarkdown) {\n return null;\n }\n\n const lines = normalizedMarkdown.split(\"\\n\");\n const rendered: string[] = [];\n let inCodeBlock = false;\n let codeBlockLanguage = \"\";\n\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index];\n const fenceMatch = line.match(/^```([A-Za-z0-9_-]+)?\\s*$/);\n\n if (fenceMatch) {\n if (inCodeBlock) {\n rendered.push(\"```\");\n inCodeBlock = false;\n codeBlockLanguage = \"\";\n } else {\n codeBlockLanguage = fenceMatch[1] ?? \"\";\n rendered.push(`\\`\\`\\`${codeBlockLanguage}`);\n inCodeBlock = true;\n }\n\n continue;\n }\n\n if (inCodeBlock) {\n rendered.push(escapeCodeContent(line));\n continue;\n }\n\n if (line.includes(\"![\")) {\n return null;\n }\n\n const tableBlock = consumeMarkdownTable(lines, index);\n\n if (tableBlock) {\n rendered.push(renderTableAsTelegramCodeBlock(tableBlock.rows));\n index = tableBlock.nextIndex - 1;\n continue;\n }\n\n if (/<[/A-Za-z][^>]*>/.test(line)) {\n return null;\n }\n\n if (!line.trim()) {\n rendered.push(\"\");\n continue;\n }\n\n const headingMatch = line.match(/^\\s{0,3}(#{1,6})\\s+(.+)$/);\n\n if (headingMatch) {\n rendered.push(`*${escapeMarkdownText(headingMatch[2].trim())}*`);\n continue;\n }\n\n const blockquoteMatch = line.match(/^\\s*>\\s?(.*)$/);\n\n if (blockquoteMatch) {\n const quote = renderInlineMarkdown(blockquoteMatch[1]);\n\n if (quote === null) {\n return null;\n }\n\n rendered.push(`>${quote ? ` ${quote}` : \"\"}`);\n continue;\n }\n\n const unorderedListMatch = line.match(/^(\\s*)[-+*]\\s+(.+)$/);\n\n if (unorderedListMatch) {\n const item = renderInlineMarkdown(unorderedListMatch[2]);\n\n if (item === null) {\n return null;\n }\n\n rendered.push(`${unorderedListMatch[1]}\\\\- ${item}`);\n continue;\n }\n\n const orderedListMatch = line.match(/^(\\s*)(\\d+)[.)]\\s+(.+)$/);\n\n if (orderedListMatch) {\n const item = renderInlineMarkdown(orderedListMatch[3]);\n\n if (item === null) {\n return null;\n }\n\n rendered.push(`${orderedListMatch[1]}${orderedListMatch[2]}\\\\. ${item}`);\n continue;\n }\n\n const paragraph = renderInlineMarkdown(line);\n\n if (paragraph === null) {\n return null;\n }\n\n rendered.push(paragraph);\n }\n\n if (inCodeBlock) {\n return null;\n }\n\n return rendered.join(\"\\n\");\n}\n\nfunction normalizePlainBody(\n result: PromptSessionResult,\n copy: BotCopy,\n): string {\n const fromStructured = result.bodyMd ? stripMarkdownToPlainText(result.bodyMd) : \"\";\n const fromFallback = result.fallbackText.trim();\n const body = fromStructured || fromFallback;\n\n return body.trim() || result.fallbackText || copy.prompt.emptyResponse;\n}\n\nfunction truncatePlainBody(body: string, footer: string): string {\n const reservedLength = footer.length + 2;\n const maxBodyLength = Math.max(0, MAX_TELEGRAM_MESSAGE_LENGTH - reservedLength);\n\n if (body.length <= maxBodyLength) {\n return body;\n }\n\n return `${body.slice(0, Math.max(0, maxBodyLength - TRUNCATED_SUFFIX.length))}${TRUNCATED_SUFFIX}`;\n}\n\nfunction truncateStaticText(text: string): string {\n if (text.length <= MAX_TELEGRAM_MESSAGE_LENGTH) {\n return text;\n }\n\n return `${text.slice(0, Math.max(0, MAX_TELEGRAM_MESSAGE_LENGTH - TRUNCATED_SUFFIX.length))}${TRUNCATED_SUFFIX}`;\n}\n\nfunction joinBodyAndFooter(body: string, footer: string): string {\n return `${body}\\n\\n${footer}`;\n}\n\nfunction preprocessMarkdownForTelegram(markdown: string): string {\n const normalizedMarkdown = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalizedMarkdown.split(\"\\n\");\n const processed: string[] = [];\n let activeFence: \"markdown\" | \"plain\" | null = null;\n\n for (const line of lines) {\n const fenceMatch = line.match(/^```([A-Za-z0-9_-]+)?\\s*$/);\n\n if (fenceMatch) {\n const language = (fenceMatch[1] ?? \"\").toLowerCase();\n\n if (activeFence === \"markdown\") {\n activeFence = null;\n continue;\n }\n\n if (activeFence === \"plain\") {\n processed.push(line);\n activeFence = null;\n continue;\n }\n\n if (language === \"md\" || language === \"markdown\") {\n activeFence = \"markdown\";\n continue;\n }\n\n activeFence = \"plain\";\n processed.push(line);\n continue;\n }\n\n processed.push(line);\n }\n\n return processed.join(\"\\n\");\n}\n\nfunction formatPlainMetricsFooter(metrics: PromptSessionMetrics, copy: BotCopy): string {\n return `${copy.replyMetrics.durationLabel}: ${formatDuration(metrics.durationMs, copy)} | ${copy.replyMetrics.tokensLabel}: ${formatMetricValue(metrics.tokens.total, copy)}`;\n}\n\nfunction formatMarkdownMetricsFooter(metrics: PromptSessionMetrics, copy: BotCopy): string {\n return escapeMarkdownText(formatPlainMetricsFooter(metrics, copy));\n}\n\nfunction formatDuration(durationMs: number | null, copy: BotCopy): string {\n if (durationMs === null || !Number.isFinite(durationMs)) {\n return copy.replyMetrics.notAvailable;\n }\n\n if (durationMs < 1000) {\n return `${Math.round(durationMs)} ms`;\n }\n\n return `${(durationMs / 1000).toFixed(1)} s`;\n}\n\nfunction formatMetricValue(value: number | null, copy: BotCopy): string {\n if (value === null || !Number.isFinite(value)) {\n return copy.replyMetrics.notAvailable;\n }\n\n return `${Math.round(value)}`;\n}\n\ninterface ConsumedTable {\n nextIndex: number;\n rows: string[][];\n}\n\nfunction consumeMarkdownTable(lines: string[], startIndex: number): ConsumedTable | null {\n if (startIndex + 1 >= lines.length) {\n return null;\n }\n\n const headerCells = parseMarkdownTableRow(lines[startIndex]);\n const separatorCells = parseMarkdownTableSeparator(lines[startIndex + 1]);\n\n if (!headerCells || !separatorCells || headerCells.length !== separatorCells.length) {\n return null;\n }\n\n const rows = [headerCells];\n let index = startIndex + 2;\n\n while (index < lines.length) {\n const rowCells = parseMarkdownTableRow(lines[index]);\n\n if (!rowCells || rowCells.length !== headerCells.length) {\n break;\n }\n\n rows.push(rowCells);\n index += 1;\n }\n\n return {\n rows,\n nextIndex: index,\n };\n}\n\nfunction parseMarkdownTableRow(line: string): string[] | null {\n const trimmed = line.trim();\n\n if (!trimmed.includes(\"|\")) {\n return null;\n }\n\n const cells = splitMarkdownTableCells(trimmed)\n .map((cell) => normalizeTableCell(cell));\n\n return cells.length >= 2 ? cells : null;\n}\n\nfunction parseMarkdownTableSeparator(line: string): string[] | null {\n const cells = splitMarkdownTableCells(line.trim());\n\n if (cells.length < 2) {\n return null;\n }\n\n return cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()))\n ? cells\n : null;\n}\n\nfunction splitMarkdownTableCells(line: string): string[] {\n const content = line\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\");\n const cells: string[] = [];\n let current = \"\";\n let escaped = false;\n\n for (const char of content) {\n if (escaped) {\n current += char;\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n escaped = true;\n current += char;\n continue;\n }\n\n if (char === \"|\") {\n cells.push(current);\n current = \"\";\n continue;\n }\n\n current += char;\n }\n\n cells.push(current);\n return cells;\n}\n\nfunction normalizeTableCell(cell: string): string {\n return cell\n .trim()\n .replace(/\\\\\\|/g, \"|\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1 ($2)\")\n .replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\")\n .replace(/(\\*|_)(.*?)\\1/g, \"$2\")\n .replace(/`([^`]+)`/g, \"$1\");\n}\n\nfunction renderTableAsTelegramCodeBlock(rows: string[][]): string {\n return [\n \"```\",\n ...buildAlignedTableLines(rows).map((line) => escapeCodeContent(line)),\n \"```\",\n ].join(\"\\n\");\n}\n\nfunction buildAlignedTableLines(rows: string[][]): string[] {\n const columnWidths = calculateTableColumnWidths(rows);\n const header = formatTableRow(rows[0], columnWidths);\n const separator = columnWidths.map((width) => \"-\".repeat(Math.max(3, width))).join(\"-+-\");\n const body = rows.slice(1).map((row) => formatTableRow(row, columnWidths));\n\n return [header, separator, ...body];\n}\n\nfunction calculateTableColumnWidths(rows: string[][]): number[] {\n return rows[0].map((_, columnIndex) =>\n rows.reduce((maxWidth, row) => Math.max(maxWidth, getDisplayWidth(row[columnIndex] ?? \"\")), 0),\n );\n}\n\nfunction formatTableRow(row: string[], columnWidths: number[]): string {\n return row\n .map((cell, index) => padDisplayWidth(cell, columnWidths[index] ?? 0))\n .join(\" | \");\n}\n\nfunction padDisplayWidth(value: string, targetWidth: number): string {\n const padding = Math.max(0, targetWidth - getDisplayWidth(value));\n\n return `${value}${\" \".repeat(padding)}`;\n}\n\nfunction getDisplayWidth(value: string): number {\n let width = 0;\n\n for (const char of value) {\n width += isWideCharacter(char.codePointAt(0) ?? 0) ? 2 : 1;\n }\n\n return width;\n}\n\nfunction isWideCharacter(codePoint: number): boolean {\n return codePoint >= 0x1100 && (\n codePoint <= 0x115f ||\n codePoint === 0x2329 ||\n codePoint === 0x232a ||\n (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||\n (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||\n (codePoint >= 0xf900 && codePoint <= 0xfaff) ||\n (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||\n (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||\n (codePoint >= 0xff00 && codePoint <= 0xff60) ||\n (codePoint >= 0xffe0 && codePoint <= 0xffe6)\n );\n}\n\nfunction renderInlineMarkdown(input: string): string | null {\n let output = \"\";\n let cursor = 0;\n\n while (cursor < input.length) {\n if (input.startsWith(\"![\", cursor)) {\n return null;\n }\n\n if (input.startsWith(\"**\", cursor) || input.startsWith(\"__\", cursor)) {\n const delimiter = input.slice(cursor, cursor + 2);\n const closingIndex = input.indexOf(delimiter, cursor + 2);\n\n if (closingIndex > cursor + 2) {\n output += `*${escapeMarkdownText(input.slice(cursor + 2, closingIndex))}*`;\n cursor = closingIndex + 2;\n continue;\n }\n }\n\n if (input[cursor] === \"*\" || input[cursor] === \"_\") {\n const delimiter = input[cursor];\n const closingIndex = input.indexOf(delimiter, cursor + 1);\n\n if (closingIndex > cursor + 1) {\n output += `_${escapeMarkdownText(input.slice(cursor + 1, closingIndex))}_`;\n cursor = closingIndex + 1;\n continue;\n }\n }\n\n if (input[cursor] === \"`\") {\n const closingIndex = input.indexOf(\"`\", cursor + 1);\n\n if (closingIndex === -1) {\n return null;\n }\n\n output += `\\`${escapeCodeContent(input.slice(cursor + 1, closingIndex))}\\``;\n cursor = closingIndex + 1;\n continue;\n }\n\n if (input[cursor] === \"[\") {\n const linkMatch = input.slice(cursor).match(/^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/);\n\n if (!linkMatch) {\n return null;\n }\n\n output += `[${escapeMarkdownText(linkMatch[1])}](${escapeLinkDestination(linkMatch[2])})`;\n cursor += linkMatch[0].length;\n continue;\n }\n\n output += escapeMarkdownText(input[cursor]);\n cursor += 1;\n }\n\n return output;\n}\n\nfunction escapeMarkdownText(text: string): string {\n return text.replace(MARKDOWN_SPECIAL_CHARACTERS, \"\\\\$1\");\n}\n\nfunction escapeCodeContent(text: string): string {\n return text\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/`/g, \"\\\\`\");\n}\n\nfunction escapeLinkDestination(url: string): string {\n return url\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\)/g, \"\\\\)\")\n .replace(/\\(/g, \"\\\\(\");\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport {\n presentStatusMarkdownMessage,\n presentStatusMessage,\n} from \"../presenters/message.presenter.js\";\nimport { renderMarkdownToTelegramMarkdownV2 } from \"../../services/telegram/telegram-format.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface StatusCommandContext {\n chat?: { id: number };\n reply(\n text: string,\n options?: {\n parse_mode: \"MarkdownV2\";\n },\n ): Promise<unknown>;\n}\n\nexport async function handleStatusCommand(ctx: StatusCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat?.id, dependencies.logger);\n\n try {\n const result = await dependencies.getStatusUseCase.execute({\n chatId: ctx.chat?.id ?? 0,\n });\n\n const renderedMarkdown = renderMarkdownToTelegramMarkdownV2(presentStatusMarkdownMessage(result, copy));\n\n if (renderedMarkdown) {\n await ctx.reply(renderedMarkdown, { parse_mode: \"MarkdownV2\" });\n return;\n }\n\n await ctx.reply(presentStatusMessage(result, copy));\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to fetch system status\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerStatusCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"status\", async (ctx) => {\n await handleStatusCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { buildSessionsListView } from \"../sessions-menu.js\";\n\ninterface SessionsCommandContext {\n chat: { id: number };\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleSessionsCommand(ctx: SessionsCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n await dependencies.pendingActionRepo.clear(ctx.chat.id);\n const view = await buildSessionsListView(ctx.chat.id, 0, dependencies);\n\n await ctx.reply(view.text, view.keyboard ? { reply_markup: view.keyboard } : undefined);\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to list sessions\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerSessionsCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"sessions\", async (ctx) => {\n await handleSessionsCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import { BOT_COPY, type BotCopy } from \"../copy.js\";\n\nexport function presentStartMarkdownMessage(copy: BotCopy = BOT_COPY): string {\n return copy.start.lines.join(\"\\n\");\n}\n","import type { Bot } from \"grammy\";\nimport { buildTelegramStaticReply } from \"../../services/telegram/telegram-format.js\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentStartMarkdownMessage } from \"../presenters/static.presenter.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface StartCommandContext {\n chat?: { id: number };\n reply(\n text: string,\n other?: {\n parse_mode: \"MarkdownV2\";\n },\n ): Promise<unknown>;\n}\n\nexport async function handleStartCommand(ctx: StartCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat?.id, dependencies.logger);\n const reply = buildTelegramStaticReply(presentStartMarkdownMessage(copy));\n\n try {\n await ctx.reply(reply.preferred.text, reply.preferred.options);\n } catch (error) {\n if (reply.preferred.options) {\n dependencies.logger.error({ error }, \"failed to send start markdown reply, falling back to plain text\");\n await ctx.reply(reply.fallback.text);\n return;\n }\n\n dependencies.logger.error({ error }, \"failed to show start message\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerStartCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"start\", async (ctx) => {\n await handleStartCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport type { PermissionApprovalRepository } from \"../../domain/permission/approval.repository.js\";\nimport {\n getSafeChatCopy,\n getSafeChatLanguage,\n} from \"../i18n.js\";\nimport { presentLanguageSwitchForChat } from \"../commands/language.js\";\nimport type {\n AgentsCallbackData,\n BotDependencies,\n LanguageCallbackData,\n ModelCallbackData,\n PermissionApprovalCallbackData,\n SessionsCallbackData,\n} from \"../types.js\";\nimport {\n buildAgentsKeyboard,\n buildLanguageKeyboard,\n buildModelsKeyboard,\n buildModelVariantsKeyboard,\n} from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport {\n getModelVariants,\n presentAgentsMessage,\n presentAgentSwitchMessage,\n presentLanguageMessage,\n presentModelsMessage,\n presentModelSwitchMessage,\n presentModelVariantsMessage,\n presentSessionRenamePromptMessage,\n presentSessionSwitchMessage,\n} from \"../presenters/message.presenter.js\";\nimport {\n buildSessionActionView,\n buildSessionsListView,\n} from \"../sessions-menu.js\";\nimport type { OpenCodeClientLike } from \"../../services/opencode/opencode.client.js\";\nimport {\n buildPermissionApprovalResolvedMessage,\n parsePermissionApprovalCallbackData,\n} from \"../../services/permission/telegram-approval.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\n\nconst AGENTS_PAGE_PREFIX = \"agents:page:\";\nconst AGENTS_SELECT_PREFIX = \"agents:select:\";\nconst SESSIONS_PAGE_PREFIX = \"sessions:page:\";\nconst SESSIONS_PICK_PREFIX = \"sessions:pick:\";\nconst SESSIONS_SWITCH_PREFIX = \"sessions:switch:\";\nconst SESSIONS_RENAME_PREFIX = \"sessions:rename:\";\nconst SESSIONS_BACK_PREFIX = \"sessions:back:\";\nconst MODEL_PAGE_PREFIX = \"model:page:\";\nconst MODEL_PICK_PREFIX = \"model:pick:\";\nconst MODEL_VARIANT_PREFIX = \"model:variant:\";\nconst LANGUAGE_SELECT_PREFIX = \"language:select:\";\nconst PERMISSION_PREFIX = \"permission:\";\n\ntype PermissionApprovalDependencies = BotDependencies & {\n opencodeClient: OpenCodeClientLike;\n permissionApprovalRepo: PermissionApprovalRepository;\n};\n\ninterface CallbackContext {\n chat?: { id: number };\n callbackQuery: { data: string; message?: { message_id: number } };\n answerCallbackQuery(): Promise<unknown>;\n editMessageText(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n api?: Pick<Bot[\"api\"], \"setMyCommands\">;\n}\n\nexport async function handleAgentsCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as AgentsCallbackData;\n\n if (!data.startsWith(\"agents:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (data.startsWith(AGENTS_PAGE_PREFIX)) {\n const requestedPage = Number(data.slice(AGENTS_PAGE_PREFIX.length));\n const result = await dependencies.listAgentsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.agents.length === 0) {\n await ctx.editMessageText(copy.agents.none);\n return;\n }\n\n const { keyboard, page } = buildAgentsKeyboard(result.agents, requestedPage, copy);\n\n await ctx.editMessageText(\n presentAgentsMessage({\n agents: result.agents,\n currentAgentName: result.currentAgentName,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n\n return;\n }\n\n if (data.startsWith(AGENTS_SELECT_PREFIX)) {\n const agentIndex = Number(data.slice(AGENTS_SELECT_PREFIX.length));\n const result = await dependencies.listAgentsUseCase.execute({\n chatId: ctx.chat.id,\n });\n const agent = result.agents[agentIndex - 1];\n\n if (!agent) {\n await ctx.editMessageText(copy.agents.expired);\n return;\n }\n\n const switchResult = await dependencies.switchAgentUseCase.execute({\n chatId: ctx.chat.id,\n agentName: agent.name,\n });\n\n if (!switchResult.found) {\n await ctx.editMessageText(copy.agents.expired);\n return;\n }\n\n await ctx.editMessageText(presentAgentSwitchMessage(switchResult.agent, copy));\n }\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle agent callback\");\n await ctx.editMessageText(presentError(error, copy));\n }\n}\n\nexport async function handleModelsCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as ModelCallbackData;\n\n if (!data.startsWith(\"model:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (data.startsWith(MODEL_PAGE_PREFIX)) {\n const requestedPage = Number(data.slice(MODEL_PAGE_PREFIX.length));\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.models.length === 0) {\n await ctx.editMessageText(copy.models.none);\n return;\n }\n\n const { keyboard, page } = buildModelsKeyboard(result.models, requestedPage, copy);\n\n await ctx.editMessageText(\n presentModelsMessage({\n currentModelId: result.currentModelId,\n currentModelProviderId: result.currentModelProviderId,\n currentModelVariant: result.currentModelVariant,\n models: result.models,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n\n return;\n }\n\n if (data.startsWith(MODEL_PICK_PREFIX)) {\n const modelIndex = Number(data.slice(MODEL_PICK_PREFIX.length));\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n const model = result.models[modelIndex - 1];\n\n if (!model) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n const variants = getModelVariants(model);\n\n if (variants.length === 0) {\n const switchResult = await dependencies.switchModelUseCase.execute({\n chatId: ctx.chat.id,\n providerId: model.providerID,\n modelId: model.id,\n });\n\n if (!switchResult.found) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n await ctx.editMessageText(presentModelSwitchMessage(switchResult.model, switchResult.variant, copy));\n return;\n }\n\n await ctx.editMessageText(\n presentModelVariantsMessage(model, modelIndex, copy),\n {\n reply_markup: buildModelVariantsKeyboard(variants, modelIndex),\n },\n );\n\n return;\n }\n\n if (data.startsWith(MODEL_VARIANT_PREFIX)) {\n const suffix = data.slice(MODEL_VARIANT_PREFIX.length);\n const [modelIndexRaw, variantIndexRaw] = suffix.split(\":\");\n const modelIndex = Number(modelIndexRaw);\n const variantIndex = Number(variantIndexRaw);\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n const model = result.models[modelIndex - 1];\n\n if (!model) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n const variants = getModelVariants(model);\n const variant = variants[variantIndex - 1];\n\n if (!variant) {\n await ctx.editMessageText(copy.models.reasoningLevelExpired);\n return;\n }\n\n const switchResult = await dependencies.switchModelUseCase.execute({\n chatId: ctx.chat.id,\n providerId: model.providerID,\n modelId: model.id,\n variant,\n });\n\n if (!switchResult.found) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n await ctx.editMessageText(presentModelSwitchMessage(switchResult.model, switchResult.variant, copy));\n }\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle model callback\");\n await ctx.editMessageText(presentError(error, copy));\n }\n}\n\nexport async function handleSessionsCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as SessionsCallbackData;\n\n if (!data.startsWith(\"sessions:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (data.startsWith(SESSIONS_PAGE_PREFIX)) {\n const requestedPage = Number(data.slice(SESSIONS_PAGE_PREFIX.length));\n const view = await buildSessionsListView(ctx.chat.id, requestedPage, dependencies);\n\n await ctx.editMessageText(view.text, view.keyboard ? { reply_markup: view.keyboard } : undefined);\n\n return;\n }\n\n if (data.startsWith(SESSIONS_BACK_PREFIX)) {\n const requestedPage = Number(data.slice(SESSIONS_BACK_PREFIX.length));\n const view = await buildSessionsListView(ctx.chat.id, requestedPage, dependencies);\n\n await ctx.editMessageText(view.text, view.keyboard ? { reply_markup: view.keyboard } : undefined);\n return;\n }\n\n if (data.startsWith(SESSIONS_PICK_PREFIX)) {\n const target = parseSessionActionTarget(data, SESSIONS_PICK_PREFIX);\n\n if (!target) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n const view = await buildSessionActionView(\n ctx.chat.id,\n target.page,\n target.sessionId,\n dependencies,\n );\n\n if (!view.found) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n await ctx.editMessageText(view.text, {\n reply_markup: view.keyboard,\n });\n return;\n }\n\n if (data.startsWith(SESSIONS_SWITCH_PREFIX)) {\n const target = parseSessionActionTarget(data, SESSIONS_SWITCH_PREFIX);\n\n if (!target) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n const result = await dependencies.switchSessionUseCase.execute({\n chatId: ctx.chat.id,\n sessionId: target.sessionId,\n });\n\n if (!result.found) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n await ctx.editMessageText(presentSessionSwitchMessage(result.session, copy));\n return;\n }\n\n if (data.startsWith(SESSIONS_RENAME_PREFIX)) {\n const target = parseSessionActionTarget(data, SESSIONS_RENAME_PREFIX);\n\n if (!target) {\n await ctx.editMessageText(copy.sessions.renameExpired);\n return;\n }\n\n const view = await buildSessionActionView(\n ctx.chat.id,\n target.page,\n target.sessionId,\n dependencies,\n );\n\n if (!view.found) {\n await ctx.editMessageText(copy.sessions.renameExpired);\n return;\n }\n\n const menuMessageId = ctx.callbackQuery.message?.message_id;\n\n if (typeof menuMessageId !== \"number\" || !Number.isInteger(menuMessageId)) {\n await ctx.editMessageText(copy.sessions.renameExpired);\n return;\n }\n\n await dependencies.pendingActionRepo.set({\n chatId: ctx.chat.id,\n kind: \"session_rename\",\n sessionId: view.session.id,\n menuMessageId,\n returnPage: view.page,\n updatedAt: new Date().toISOString(),\n });\n\n await ctx.editMessageText(presentSessionRenamePromptMessage(view.session, copy));\n }\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle session callback\");\n await ctx.editMessageText(presentError(error, copy));\n }\n}\n\nexport async function handleLanguageCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as LanguageCallbackData;\n\n if (!data.startsWith(\"language:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat || !ctx.api) {\n return;\n }\n\n const currentCopy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (!data.startsWith(LANGUAGE_SELECT_PREFIX)) {\n await ctx.editMessageText(\n presentLanguageMessage(\n await getSafeChatLanguage(dependencies.sessionRepo, ctx.chat.id, dependencies.logger),\n currentCopy,\n ),\n {\n reply_markup: buildLanguageKeyboard(\n await getSafeChatLanguage(dependencies.sessionRepo, ctx.chat.id, dependencies.logger),\n currentCopy,\n ),\n },\n );\n return;\n }\n\n const selectedLanguage = data.slice(LANGUAGE_SELECT_PREFIX.length);\n const result = await presentLanguageSwitchForChat(ctx.chat.id, ctx.api, selectedLanguage, dependencies);\n\n await ctx.editMessageText(result.text, {\n reply_markup: result.keyboard,\n });\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle language callback\");\n await ctx.editMessageText(presentError(error, currentCopy));\n }\n}\n\nexport async function handlePermissionApprovalCallback(\n ctx: CallbackContext,\n dependencies: PermissionApprovalDependencies,\n) {\n const data = ctx.callbackQuery.data as PermissionApprovalCallbackData;\n\n if (!data.startsWith(PERMISSION_PREFIX)) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const parsed = parsePermissionApprovalCallbackData(data);\n\n if (!parsed) {\n return;\n }\n\n try {\n const approvals = await dependencies.permissionApprovalRepo.listByRequestId(parsed.requestId);\n const approval = approvals.find((item) => item.chatId === ctx.chat?.id);\n\n await dependencies.opencodeClient.replyToPermission(\n parsed.requestId,\n parsed.reply,\n undefined,\n approval?.sessionId,\n );\n\n if (approval) {\n await dependencies.permissionApprovalRepo.set({\n ...approval,\n status: parsed.reply,\n updatedAt: new Date().toISOString(),\n });\n }\n\n await ctx.editMessageText(buildPermissionApprovalResolvedMessage(parsed.requestId, parsed.reply));\n } catch (error) {\n dependencies.logger.error({ error, requestId: parsed.requestId }, \"failed to reply to permission request\");\n await ctx.editMessageText(\"Failed to reply to the permission request.\");\n }\n}\n\nexport function registerCallbackHandler(bot: Pick<Bot, \"callbackQuery\">, dependencies: PermissionApprovalDependencies) {\n bot.callbackQuery(/^agents:/, async (ctx) => {\n await handleAgentsCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^sessions:/, async (ctx) => {\n await handleSessionsCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^model:/, async (ctx) => {\n await handleModelsCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^language:/, async (ctx) => {\n await handleLanguageCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^permission:/, async (ctx) => {\n await handlePermissionApprovalCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n\nfunction parseSessionActionTarget(data: string, prefix: string) {\n const suffix = data.slice(prefix.length);\n const separatorIndex = suffix.indexOf(\":\");\n\n if (separatorIndex === -1) {\n return null;\n }\n\n const page = Number(suffix.slice(0, separatorIndex));\n const sessionId = suffix.slice(separatorIndex + 1).trim();\n\n if (!Number.isInteger(page) || page < 0 || !sessionId) {\n return null;\n }\n\n return {\n page,\n sessionId,\n };\n}\n","import { getSafeChatCopy } from \"../i18n.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { buildTelegramPromptReply } from \"../../services/telegram/telegram-format.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport type { PromptSessionFilePartInput } from \"../../services/opencode/opencode.client.js\";\n\ninterface SentMessage {\n message_id: number;\n}\n\nexport interface PromptExecutionContext {\n chat: { id: number };\n api: {\n deleteMessage(chatId: number, messageId: number): Promise<unknown>;\n };\n reply(text: string, other?: { parse_mode?: \"MarkdownV2\" }): Promise<SentMessage>;\n}\n\nexport interface PromptExecutionInput {\n files?: PromptSessionFilePartInput[];\n text?: string | null;\n}\n\nexport async function executePromptRequest(\n ctx: PromptExecutionContext,\n dependencies: BotDependencies,\n resolvePrompt: () => Promise<PromptExecutionInput>,\n) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n const foregroundRequest = dependencies.foregroundSessionTracker.acquire(ctx.chat.id);\n\n if (!foregroundRequest) {\n await ctx.reply(copy.status.alreadyProcessing);\n return;\n }\n\n let processingMessage: SentMessage | null = null;\n let sentTerminalReply = false;\n\n try {\n processingMessage = await ctx.reply(copy.status.processing);\n\n const promptInput = await resolvePrompt();\n const result = await dependencies.sendPromptUseCase.execute({\n chatId: ctx.chat.id,\n files: promptInput.files,\n onExecutionSession: (sessionId: string) => {\n foregroundRequest.attachSession(sessionId);\n },\n signal: foregroundRequest.signal,\n text: promptInput.text,\n });\n const promptReply = normalizePromptReplyForDisplay(result.assistantReply, copy);\n const telegramReply = buildTelegramPromptReply(promptReply, copy);\n\n try {\n await ctx.reply(telegramReply.preferred.text, telegramReply.preferred.options);\n } catch (replyError) {\n dependencies.logger.warn?.(\n { error: replyError },\n \"failed to send preferred telegram reply, falling back to plain text\",\n );\n await ctx.reply(telegramReply.fallback.text, telegramReply.fallback.options);\n }\n sentTerminalReply = true;\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle prompt request\");\n await ctx.reply(presentError(error, copy));\n sentTerminalReply = true;\n } finally {\n foregroundRequest.dispose();\n if (processingMessage && sentTerminalReply) {\n try {\n await ctx.api.deleteMessage(ctx.chat.id, processingMessage.message_id);\n } catch (error) {\n dependencies.logger.warn?.({ error }, \"failed to delete processing message\");\n }\n }\n }\n}\n\nfunction normalizePromptReplyForDisplay(\n promptReply: Awaited<ReturnType<BotDependencies[\"sendPromptUseCase\"][\"execute\"]>>[\"assistantReply\"],\n copy: Awaited<ReturnType<typeof getSafeChatCopy>>,\n) {\n if (!promptReply.assistantError) {\n return promptReply;\n }\n\n return {\n ...promptReply,\n bodyMd: null,\n fallbackText: presentError(promptReply.assistantError, copy),\n };\n}\n","import type { Bot } from \"grammy\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { executePromptRequest, type PromptExecutionContext } from \"./prompt.handler.js\";\nimport { replyIfSessionRenamePending } from \"../session-rename.js\";\nimport { ImageMessageUnsupportedError } from \"../../use-cases/upload-file.usecase.js\";\n\nconst TELEGRAM_MAX_DOWNLOAD_BYTES = 20 * 1024 * 1024;\n\ninterface TelegramPhotoSize {\n file_id: string;\n file_size?: number;\n}\n\ninterface TelegramDocument {\n file_id: string;\n file_name?: string;\n file_size?: number;\n mime_type?: string;\n}\n\ninterface FileContext extends PromptExecutionContext {\n getFile(): Promise<{ file_path?: string }>;\n message: {\n caption?: string;\n document?: TelegramDocument;\n photo?: TelegramPhotoSize[];\n };\n}\n\nexport async function handleImageMessage(ctx: FileContext, dependencies: BotDependencies) {\n const image = resolveTelegramImage(ctx.message);\n\n if (!image) {\n return;\n }\n\n if (await replyIfSessionRenamePending(ctx, dependencies)) {\n return;\n }\n\n await executePromptRequest(ctx, dependencies, async () => {\n if (typeof image.fileSize === \"number\" && image.fileSize > TELEGRAM_MAX_DOWNLOAD_BYTES) {\n throw new ImageMessageUnsupportedError(\n `Image file size ${image.fileSize} exceeds the Telegram download limit of ${TELEGRAM_MAX_DOWNLOAD_BYTES} bytes.`,\n );\n }\n\n const file = await ctx.getFile();\n const filePath = file.file_path?.trim();\n\n if (!filePath) {\n throw new ImageMessageUnsupportedError(\"Telegram did not provide a downloadable image file path.\");\n }\n\n const promptFile = await dependencies.uploadFileUseCase.execute({\n expectedType: \"image\",\n filePath,\n filename: image.filename,\n mimeType: image.mimeType,\n });\n\n return {\n files: [promptFile],\n text: ctx.message.caption?.trim() || null,\n };\n });\n}\n\nexport function registerFileHandler(bot: Pick<Bot, \"on\">, dependencies: BotDependencies) {\n bot.on(\"message:photo\", async (ctx) => {\n await handleImageMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.on(\"message:document\", async (ctx) => {\n await handleImageMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n\nfunction resolveTelegramImage(message: FileContext[\"message\"]) {\n const document = message.document;\n\n if (document && isImageDocument(document)) {\n return {\n fileId: document.file_id,\n fileSize: document.file_size,\n filename: document.file_name ?? null,\n mimeType: document.mime_type ?? null,\n };\n }\n\n const photo = pickLargestPhoto(message.photo);\n\n if (!photo) {\n return null;\n }\n\n return {\n fileId: photo.file_id,\n fileSize: photo.file_size,\n filename: null,\n mimeType: \"image/jpeg\",\n };\n}\n\nfunction isImageDocument(document: TelegramDocument): boolean {\n const mimeType = document.mime_type?.trim().toLowerCase();\n const filename = document.file_name?.trim().toLowerCase() ?? \"\";\n\n return !!mimeType?.startsWith(\"image/\")\n || /\\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(filename);\n}\n\nfunction pickLargestPhoto(photos: TelegramPhotoSize[] | undefined): TelegramPhotoSize | null {\n if (!photos || photos.length === 0) {\n return null;\n }\n\n return photos.reduce<TelegramPhotoSize>((largest, current) => {\n const currentSize = current.file_size ?? 0;\n const largestSize = largest.file_size ?? 0;\n\n return currentSize >= largestSize ? current : largest;\n }, photos[0]);\n}\n","import type { Bot } from \"grammy\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { executePromptRequest, type PromptExecutionContext } from \"./prompt.handler.js\";\nimport { handlePendingSessionRenameText } from \"../session-rename.js\";\n\ninterface MessageContext extends PromptExecutionContext {\n api: PromptExecutionContext[\"api\"] & {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n };\n message: { text?: string };\n}\n\nexport async function handleTextMessage(ctx: MessageContext, dependencies: BotDependencies) {\n const text = ctx.message.text?.trim();\n\n if (await handlePendingSessionRenameText(ctx, dependencies)) return;\n if (!text) return;\n if (text.startsWith(\"/\")) return;\n await executePromptRequest(ctx, dependencies, async () => ({ text }));\n}\n\nexport function registerMessageHandler(bot: Pick<Bot, \"on\">, dependencies: BotDependencies) {\n bot.on(\"message:text\", async (ctx) => {\n await handleTextMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { replyIfSessionRenamePending } from \"../session-rename.js\";\n\ninterface VoiceContext {\n chat: { id: number };\n message: { voice?: unknown };\n reply(text: string): Promise<unknown>;\n}\n\nexport async function handleVoiceMessage(ctx: VoiceContext, dependencies: BotDependencies) {\n if (!ctx.message.voice) {\n return;\n }\n\n if (await replyIfSessionRenamePending(ctx, dependencies)) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n await ctx.reply(copy.errors.voiceUnsupported);\n}\n\nexport function registerVoiceHandler(bot: Pick<Bot, \"on\">, dependencies: BotDependencies) {\n bot.on(\"message:voice\", async (ctx) => {\n await handleVoiceMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { MiddlewareFn } from \"grammy\";\n\nexport function createAuthMiddleware(allowedChatIds: readonly number[]): MiddlewareFn {\n return async (ctx, next) => {\n if (allowedChatIds.length === 0) {\n return next();\n }\n\n const chatId = ctx.chat?.id;\n\n if (!chatId || !allowedChatIds.includes(chatId)) {\n await ctx.reply(\"Unauthorized chat.\");\n return;\n }\n\n return next();\n };\n}\n","import type { MiddlewareFn } from \"grammy\";\nimport {\n logTelegramUpdate,\n type AppLogger,\n} from \"../../infra/logger/index.js\";\nimport { buildTelegramLoggerContext } from \"../logger-context.js\";\n\ninterface LoggingContextLike {\n chat?: { id?: number };\n from?: { id?: number };\n msg?: { text?: string } | null;\n update: { update_id: number };\n}\n\nexport function buildIncomingUpdateLogFields(ctx: LoggingContextLike) {\n const messageText = ctx.msg && \"text\" in ctx.msg\n ? ctx.msg.text\n : undefined;\n const loggerContext = buildTelegramLoggerContext(ctx);\n\n return {\n ...loggerContext,\n event: \"telegram.update.received\",\n updateId: ctx.update.update_id,\n chatId: ctx.chat?.id,\n fromId: ctx.from?.id,\n hasText: typeof messageText === \"string\" && messageText.length > 0,\n textLength: typeof messageText === \"string\" ? messageText.length : 0,\n };\n}\n\nexport function createLoggingMiddleware(logger: Pick<AppLogger, \"info\">): MiddlewareFn {\n return async (ctx, next) => {\n logTelegramUpdate(logger as AppLogger, {\n ...buildIncomingUpdateLogFields(ctx),\n }, \"incoming update\");\n\n return next();\n };\n}\n","import type { Bot } from \"grammy\";\nimport type { PermissionApprovalRepository } from \"../domain/permission/approval.repository.js\";\nimport type { OpenCodeClientLike } from \"../services/opencode/opencode.client.js\";\nimport { registerAgentsCommand } from \"./commands/agents.js\";\nimport { registerCancelCommand } from \"./commands/cancel.js\";\nimport { registerLanguageCommand } from \"./commands/language.js\";\nimport { registerModelsCommand } from \"./commands/models.js\";\nimport { registerNewCommand } from \"./commands/new.js\";\nimport { registerStatusCommand } from \"./commands/status.js\";\nimport type { BotDependencies } from \"./types.js\";\nimport { registerSessionsCommand } from \"./commands/sessions.js\";\nimport { registerStartCommand } from \"./commands/start.js\";\nimport { registerCallbackHandler } from \"./handlers/callback.handler.js\";\nimport { registerFileHandler } from \"./handlers/file.handler.js\";\nimport { registerMessageHandler } from \"./handlers/message.handler.js\";\nimport { registerVoiceHandler } from \"./handlers/voice.handler.js\";\nimport { createAuthMiddleware } from \"./middlewares/auth.js\";\nimport { createLoggingMiddleware } from \"./middlewares/logging.js\";\nimport {\n extractTelegramUpdateContext,\n replyWithDefaultTelegramError,\n} from \"./error-boundary.js\";\nimport { scopeLoggerToTelegramContext } from \"./logger-context.js\";\n\nexport interface RegisterBotOptions {\n telegramAllowedChatIds: number[];\n}\n\nexport function registerBot(\n bot: Bot,\n container: BotDependencies & {\n opencodeClient: OpenCodeClientLike;\n permissionApprovalRepo: PermissionApprovalRepository;\n },\n options: RegisterBotOptions,\n) {\n bot.use(createLoggingMiddleware(container.logger));\n bot.use(createAuthMiddleware(options.telegramAllowedChatIds));\n\n const safeBot = bot.errorBoundary(async (error) => {\n const scopedLogger = scopeLoggerToTelegramContext(container.logger, error.ctx, \"telegram\");\n\n scopedLogger.error(\n {\n ...extractTelegramUpdateContext(error.ctx),\n event: \"telegram.middleware.failed\",\n error: error.error,\n },\n \"telegram middleware failed\",\n );\n await replyWithDefaultTelegramError(error.ctx, scopedLogger, error.error);\n });\n\n registerStartCommand(safeBot, container);\n registerStatusCommand(safeBot, container);\n registerNewCommand(safeBot, container);\n registerAgentsCommand(safeBot, container);\n registerSessionsCommand(safeBot, container);\n registerCancelCommand(safeBot, container);\n registerModelsCommand(safeBot, container);\n registerLanguageCommand(safeBot, container);\n registerCallbackHandler(safeBot, container);\n registerFileHandler(safeBot, container);\n registerMessageHandler(safeBot, container);\n registerVoiceHandler(safeBot, container);\n}\n","import { run } from \"@grammyjs/runner\";\nimport { Bot, GrammyError, HttpError } from \"grammy\";\nimport { syncTelegramCommands } from \"../bot/commands/sync-commands.js\";\nimport { extractTelegramUpdateContext } from \"../bot/error-boundary.js\";\nimport { registerBot } from \"../bot/index.js\";\nimport type { AppConfig } from \"./config.js\";\nimport type { AppContainer } from \"./container.js\";\n\nexport interface StartTelegramBotRuntimeInput {\n botFactory?: (token: string, options: ConstructorParameters<typeof Bot>[1]) => Bot;\n config: AppConfig;\n container: AppContainer;\n registerBotHandlers?: typeof registerBot;\n runBot?: typeof run;\n syncCommands?: boolean;\n syncCommandsHandler?: typeof syncTelegramCommands;\n}\n\nexport interface TelegramBotRuntime {\n bot: Bot;\n container: AppContainer;\n stop(): void;\n dispose(): Promise<void>;\n}\n\ninterface TelegramBotRuntimeRegistry {\n activeByKey: Map<string, Promise<TelegramBotRuntime>>;\n}\n\nconst TELEGRAM_RUNNER_OPTIONS = {\n runner: {\n fetch: {\n timeout: 30,\n },\n maxRetryTime: 15 * 60 * 1000,\n retryInterval: \"exponential\" as const,\n silent: true,\n },\n};\n\nexport async function startTelegramBotRuntime(\n input: StartTelegramBotRuntimeInput,\n): Promise<TelegramBotRuntime> {\n const runtimeKey = buildTelegramRuntimeKey(input.config);\n const registry = getTelegramBotRuntimeRegistry();\n const existingRuntime = registry.activeByKey.get(runtimeKey);\n const runtimeLogger = input.container.logger.child({\n component: \"runtime\",\n });\n\n if (existingRuntime) {\n runtimeLogger.warn(\n {\n event: \"runtime.reused\",\n runtimeKey,\n telegramApiRoot: input.config.telegramApiRoot,\n },\n \"telegram runtime already active in this process; reusing the existing runner\",\n );\n await input.container.dispose();\n return existingRuntime;\n }\n\n const runtimePromise = startTelegramBotRuntimeInternal(\n input,\n runtimeKey,\n () => {\n if (registry.activeByKey.get(runtimeKey) === runtimePromise) {\n registry.activeByKey.delete(runtimeKey);\n }\n },\n ).catch((error) => {\n if (registry.activeByKey.get(runtimeKey) === runtimePromise) {\n registry.activeByKey.delete(runtimeKey);\n }\n\n throw error;\n });\n\n registry.activeByKey.set(runtimeKey, runtimePromise);\n\n return runtimePromise;\n}\n\nasync function startTelegramBotRuntimeInternal(\n input: StartTelegramBotRuntimeInput,\n runtimeKey: string,\n releaseRuntime: () => void,\n): Promise<TelegramBotRuntime> {\n const botFactory = input.botFactory ?? ((token, options) => new Bot(token, options));\n const bot = botFactory(input.config.telegramBotToken, {\n client: {\n apiRoot: input.config.telegramApiRoot,\n },\n });\n const runtimeLogger = input.container.logger.child({\n component: \"runtime\",\n });\n\n wrapTelegramGetUpdates(bot, input.container);\n const registerBotHandlers = input.registerBotHandlers ?? registerBot;\n registerBotHandlers(bot, input.container, {\n telegramAllowedChatIds: input.config.telegramAllowedChatIds,\n });\n\n bot.catch((error) => {\n const metadata = extractTelegramUpdateContext(error.ctx);\n const telegramLogger = input.container.logger.child({\n component: \"telegram\",\n ...metadata,\n });\n\n if (error.error instanceof GrammyError) {\n telegramLogger.error(\n {\n event: \"telegram.api.error\",\n errorCode: error.error.error_code,\n description: error.error.description,\n method: error.error.method,\n parameters: error.error.parameters,\n payload: error.error.payload,\n },\n \"telegram bot api request failed\",\n );\n return;\n }\n\n if (error.error instanceof HttpError) {\n telegramLogger.error(\n {\n event: \"telegram.http.error\",\n error: error.error.error,\n message: error.error.message,\n },\n \"telegram bot network request failed\",\n );\n return;\n }\n\n telegramLogger.error(\n {\n event: \"telegram.update.failed\",\n error: error.error,\n },\n \"telegram bot update failed\",\n );\n });\n\n runtimeLogger.info(\n {\n event: \"runtime.polling.starting\",\n runtimeKey,\n },\n \"telegram bot polling starting\",\n );\n const runBot = input.runBot ?? run;\n const runner = runBot(bot, TELEGRAM_RUNNER_OPTIONS);\n let stopped = false;\n let disposed = false;\n\n if (input.syncCommands ?? true) {\n const syncCommandsHandler = input.syncCommandsHandler ?? syncTelegramCommands;\n\n void syncCommandsHandler(bot, input.container.logger).catch((error) => {\n runtimeLogger.warn(\n {\n event: \"runtime.commands.sync_failed\",\n error,\n runtimeKey,\n },\n \"failed to sync telegram commands; polling continues without command registration updates\",\n );\n });\n }\n\n let stopPromise: Promise<void> | null = null;\n const requestStop = async () => {\n if (stopped) {\n return;\n }\n\n stopped = true;\n stopPromise = runner.stop().catch((error) => {\n runtimeLogger.warn(\n {\n event: \"runtime.stop.failed\",\n error,\n runtimeKey,\n },\n \"failed to stop telegram runner cleanly\",\n );\n });\n\n await stopPromise;\n };\n const stop = () => {\n void requestStop();\n };\n const dispose = async () => {\n if (disposed) {\n return;\n }\n\n disposed = true;\n try {\n await requestStop();\n await input.container.dispose();\n } finally {\n releaseRuntime();\n }\n };\n\n return {\n bot,\n container: input.container,\n stop,\n dispose,\n };\n}\n\nfunction wrapTelegramGetUpdates(bot: Bot, container: AppContainer): void {\n const originalGetUpdates = bot.api.getUpdates.bind(bot.api);\n const runtimeLogger = container.logger.child({\n component: \"runtime\",\n });\n\n bot.api.getUpdates = async (options, signal) => {\n const requestOptions = options ?? {\n limit: 100,\n offset: 0,\n timeout: 30,\n };\n\n try {\n return await originalGetUpdates(requestOptions, signal);\n } catch (error) {\n runtimeLogger.warn(\n {\n event: \"runtime.telegram.get_updates_failed\",\n error,\n limit: requestOptions.limit,\n offset: requestOptions.offset,\n timeout: requestOptions.timeout,\n },\n \"telegram getUpdates failed\",\n );\n throw error;\n }\n };\n}\n\nfunction buildTelegramRuntimeKey(config: AppConfig): string {\n return `${config.telegramApiRoot}::${config.telegramBotToken}`;\n}\n\nfunction getTelegramBotRuntimeRegistry(): TelegramBotRuntimeRegistry {\n const globalScope = globalThis as typeof globalThis & {\n __opencodeTbotTelegramRuntimeRegistry__?: TelegramBotRuntimeRegistry;\n };\n\n globalScope.__opencodeTbotTelegramRuntimeRegistry__ ??= {\n activeByKey: new Map(),\n };\n\n return globalScope.__opencodeTbotTelegramRuntimeRegistry__;\n}\n\nexport function resetTelegramBotRuntimeRegistryForTests(): void {\n const globalScope = globalThis as typeof globalThis & {\n __opencodeTbotTelegramRuntimeRegistry__?: TelegramBotRuntimeRegistry;\n };\n\n globalScope.__opencodeTbotTelegramRuntimeRegistry__ = {\n activeByKey: new Map(),\n };\n}\n","import type { Hooks, Plugin, PluginInput } from \"@opencode-ai/plugin\";\nimport { bootstrapPluginApp } from \"./app/bootstrap.js\";\nimport { handleTelegramBotPluginEvent } from \"./app/plugin-events.js\";\nimport {\n preparePluginConfiguration,\n type PreparedPluginConfiguration,\n} from \"./app/plugin-config.js\";\nimport {\n startTelegramBotRuntime,\n type StartTelegramBotRuntimeInput,\n type TelegramBotRuntime,\n} from \"./app/runtime.js\";\nimport type { PluginConfigSource } from \"./app/config.js\";\nimport type { OpenCodeSdkClientLike } from \"./services/opencode/opencode.client.js\";\n\nexport interface OpenCodePluginContextLike {\n client: OpenCodeSdkClientLike;\n directory?: string;\n worktree?: string;\n}\n\nexport interface EnsureTelegramBotPluginRuntimeOptions {\n context: OpenCodePluginContextLike;\n config?: PluginConfigSource;\n bootstrapApp?: typeof bootstrapPluginApp;\n prepareConfiguration?: (input: {\n cwd: string;\n config?: PluginConfigSource;\n }) => Promise<PreparedPluginConfiguration>;\n startRuntime?: (input: StartTelegramBotRuntimeInput) => Promise<TelegramBotRuntime>;\n}\n\ninterface TelegramBotPluginRuntimeState {\n cwd: string;\n runtime: TelegramBotRuntime | null;\n runtimePromise: Promise<TelegramBotRuntime>;\n}\n\ninterface TelegramBotPluginRuntimeStateHolder {\n state: TelegramBotPluginRuntimeState | null;\n}\n\nexport async function ensureTelegramBotPluginRuntime(\n options: EnsureTelegramBotPluginRuntimeOptions,\n): Promise<TelegramBotRuntime> {\n const runtimeStateHolder = getTelegramBotPluginRuntimeStateHolder();\n const cwd = resolvePluginRuntimeCwd(options.context);\n\n if (runtimeStateHolder.state && runtimeStateHolder.state.cwd !== cwd) {\n const activeState = runtimeStateHolder.state;\n runtimeStateHolder.state = null;\n await disposeTelegramBotPluginRuntimeState(activeState);\n }\n\n if (!runtimeStateHolder.state) {\n const runtimePromise = startPluginRuntime(options, cwd)\n .then((runtime) => {\n if (runtimeStateHolder.state?.runtimePromise === runtimePromise) {\n runtimeStateHolder.state.runtime = runtime;\n }\n\n return runtime;\n })\n .catch((error) => {\n if (runtimeStateHolder.state?.runtimePromise === runtimePromise) {\n runtimeStateHolder.state = null;\n }\n\n throw error;\n });\n\n runtimeStateHolder.state = {\n cwd,\n runtime: null,\n runtimePromise,\n };\n }\n\n return runtimeStateHolder.state.runtimePromise;\n}\n\nexport const TelegramBotPlugin: Plugin = async (context) => {\n const runtime = await ensureTelegramBotPluginRuntime({\n context: context as unknown as OpenCodePluginContextLike,\n });\n\n return createHooks(runtime);\n};\n\nexport async function resetTelegramBotPluginRuntimeForTests() {\n const runtimeStateHolder = getTelegramBotPluginRuntimeStateHolder();\n\n if (!runtimeStateHolder.state) {\n return;\n }\n\n const activeState = runtimeStateHolder.state;\n runtimeStateHolder.state = null;\n await disposeTelegramBotPluginRuntimeState(activeState);\n}\n\nexport default TelegramBotPlugin;\n\nasync function startPluginRuntime(\n options: EnsureTelegramBotPluginRuntimeOptions,\n cwd: string,\n): Promise<TelegramBotRuntime> {\n const bootstrapApp = options.bootstrapApp ?? bootstrapPluginApp;\n const prepareConfiguration = options.prepareConfiguration ?? preparePluginConfiguration;\n const startRuntime = options.startRuntime ?? startTelegramBotRuntime;\n const preparedConfiguration = await prepareConfiguration({\n cwd,\n config: options.config,\n });\n const { config, container } = bootstrapApp(\n options.context.client,\n preparedConfiguration.config,\n { cwd: preparedConfiguration.cwd },\n );\n\n try {\n if (preparedConfiguration.ignoredProjectConfigFilePath) {\n container.logger.child({ component: \"runtime\" }).warn(\n {\n cwd: preparedConfiguration.cwd,\n event: \"runtime.config.legacy_worktree_ignored\",\n ignoredProjectConfigFilePath: preparedConfiguration.ignoredProjectConfigFilePath,\n globalConfigFilePath: preparedConfiguration.globalConfigFilePath,\n },\n \"legacy worktree plugin config is ignored; migrate settings to the global opencode-tbot config\",\n );\n }\n\n const runtime = await startRuntime({ config, container });\n\n container.logger.child({ component: \"runtime\" }).info(\n {\n cwd: preparedConfiguration.cwd,\n event: \"runtime.plugin.started\",\n globalConfigFilePath: preparedConfiguration.globalConfigFilePath,\n ignoredProjectConfigFilePath: preparedConfiguration.ignoredProjectConfigFilePath,\n configFilePath: preparedConfiguration.configFilePath,\n mode: \"plugin\",\n },\n \"telegram bot plugin runtime started\",\n );\n\n return runtime;\n } catch (error) {\n await container.dispose();\n throw error;\n }\n}\n\nfunction resolvePluginRuntimeCwd(context: OpenCodePluginContextLike): string {\n return context.worktree ?? context.directory ?? process.cwd();\n}\n\nasync function disposeTelegramBotPluginRuntimeState(\n state: TelegramBotPluginRuntimeState,\n): Promise<void> {\n const runtime = state.runtime ?? await state.runtimePromise.catch(() => null);\n\n await runtime?.dispose();\n}\n\nfunction createHooks(runtime: TelegramBotRuntime): Hooks {\n return {\n async event({ event }) {\n await handleTelegramBotPluginEvent(runtime, event);\n },\n async \"permission.ask\"(input, output) {\n const bindings = await runtime.container.sessionRepo.listBySessionId(input.sessionID);\n const foregroundChatIds = runtime.container.foregroundSessionTracker.listChatIds(input.sessionID);\n\n if (bindings.length > 0 || foregroundChatIds.length > 0) {\n output.status = \"ask\";\n }\n },\n };\n}\n\nfunction getTelegramBotPluginRuntimeStateHolder(): TelegramBotPluginRuntimeStateHolder {\n const globalScope = globalThis as typeof globalThis & {\n __opencodeTbotPluginRuntimeState__?: TelegramBotPluginRuntimeStateHolder;\n };\n\n globalScope.__opencodeTbotPluginRuntimeState__ ??= {\n state: null,\n };\n\n return globalScope.__opencodeTbotPluginRuntimeState__;\n}\n"],"mappings":";;;;;;;;AAAA,IAAM,aAAW;AAEjB,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAE7B,SAAgB,oBAAoB,OAAuB;AACvD,QAAO,MACF,QAAQ,sBAAsB,UAAU,aAAW,CACnD,QAAQ,wBAAwB,WAAS,CACzC,QAAQ,uBAAuB,GAAG,MAAc,cAAsB,GAAG,OAAO,YAAY,aAAW,CACvG,QAAQ,sBAAsB,WAAS;;;;ACiIhD,IAAM,oBAAkC;AACxC,IAAM,gBAAgB;AACtB,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAC9B,IAAM,8BAA8B;AACpC,IAAM,kBAAkB;AACxB,IAAM,WAAW;AACjB,IAAM,iBAA8C;CAChD,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACV;AACD,IAAM,wBAAwB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACH,CAAC;AAEF,SAAgB,wBACZ,QACA,UAA0C,EAAE,EACnC;CACT,MAAM,UAAU,qBAAqB,QAAQ,QAAQ;CACrD,MAAM,eAAe,kBAAkB,QAAQ,MAAM;CACrD,MAAM,YAAY,gBAAgB,QAAQ,UAAU,IAAI,YAAY;CACpE,MAAM,mBAAkC;EACpC,WAAW;EACX;EACA,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,UAAU,GAAG,EAAE;EAC7D;CACD,MAAM,QAAQ,YAAY,QAAQ;EAC9B,MAAM;GACF,KAAK,QAAQ,MAAM;GACnB,UAAU,QAAQ,MAAM,WAAW;GACnC,eAAe,QAAQ,MAAM,WAAW;GAC3C;EACD;EACA;EACA,OAAO,QAAQ;EAClB,CAAC;CACF,IAAI,QAAQ,QAAQ,SAAS;CAE7B,MAAM,WAAW,UAA2B;AACxC,MAAI,eAAe,MAAM,SAAS,eAAe,cAC7C;EAGJ,MAAM,kBAAkB,wBACpB,MAAM,OACN,MAAM,OACN,MAAM,SACN,SACA,MAAM,QACT;AAED,UAAQ,MACH,YAAY,KAAA,EAAU,CACtB,KAAK,YAAY;AACd,SAAM,QAAQ,WACV,MAAM,KAAK,SAAS,KAAK,MAAM,gBAAgB,CAAC,CACnD;IACH;;CAGV,MAAM,gBAAgB,aAAuC;EACzD,MAAM,OAAiB,SAAkB;AACrC,WAAQ;IACJ;IACA;IACA,OAAO;IACP;IACH,CAAC;;EAEN,KAAK,OAAiB,SAAkB;AACpC,WAAQ;IACJ;IACA;IACA,OAAO;IACP;IACH,CAAC;;EAEN,KAAK,OAAiB,SAAkB;AACpC,WAAQ;IACJ;IACA;IACA,OAAO;IACP;IACH,CAAC;;EAEN,MAAM,OAAiB,SAAkB;AACrC,WAAQ;IACJ;IACA;IACA,OAAO;IACP;IACH,CAAC;;EAEN,MAAM,cAA6B;AAC/B,UAAO,aAAa;IAChB,GAAG;IACH,GAAG,sBAAsB,aAAa;IACzC,CAAC;;EAEN,MAAM,QAAQ;AACV,SAAM,MAAM,YAAY,KAAA,EAAU;AAClC,SAAM,QAAQ,WACV,MAAM,IAAI,OAAO,SAAS;AACtB,UAAM,KAAK,SAAS;KACtB,CACL;;EAER;AAED,QAAO,aAAa,iBAAiB;;AAOzC,SAAgB,kBACZ,QACA,OACA,SACI;AACJ,QAAO,KACH;EACI,WAAW;EACX,GAAG;EACN,EACD,QACH;;AAGL,SAAgB,mBACZ,QACA,OACA,SACI;AACJ,QAAO,KACH;EACI,WAAW;EACX,GAAG;EACN,EACD,QACH;;AAGL,SAAgB,mBACZ,QACA,OACA,SACI;AACJ,QAAO,KACH;EACI,WAAW;EACX,GAAG;EACN,EACD,QACH;;AAGL,SAAgB,eACZ,QACA,OACA,SACI;AACJ,QAAO,KACH;EACI,WAAW;EACX,GAAG;EACN,EACD,QACH;;AAGL,SAAS,YACL,QACA,SAUS;CACT,MAAM,cAAc,QAAQ,SAAS,EAAE;CACvC,MAAM,QAAmB,EAAE;AAE3B,KAAI,YAAY,SAAS,MACrB,OAAM,KAAK,eAAe,QAAQ,QAAQ,QAAQ,CAAC;AAGvD,KAAI,YAAY,SAAS,SAAS,QAAQ,MAAM,IAC5C,OAAM,KAAK,oBAAoB;EAC3B,KAAK,QAAQ,KAAK;EAClB,UAAU,QAAQ,KAAK;EACvB,eAAe,QAAQ,KAAK;EAC5B,WAAW,QAAQ;EACtB,CAAC,CAAC;AAGP,QAAO;;AAGX,SAAS,eAAe,QAAkC,SAA0B;AAChF,QAAO,EACH,MAAM,MAAM,OAAO;EACf,MAAM,UAAU;GACZ;GACA,OAAO,MAAM;GACb,SAAS,MAAM;GACf,OAAO,kBAAkB,MAAM;GAClC;AAED,MAAI,OAAO,IAAI,IAAI,UAAU,GAAG;AAC5B,SAAM,OAAO,IAAI,IAAI,SAAS;IAC1B,eAAe;IACf,cAAc;IACjB,CAAC;AACF;;AAGJ,QAAM,OAAO,IAAI,IAAI;GACjB,MAAM;GACN,eAAe;GACf,cAAc;GACjB,CAAC;IAET;;AAGL,SAAS,oBAAoB,SAAsC;CAC/D,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,iBAAiB,oBAAoB,QAAQ,UAAU;CAC7D,MAAM,oCAAmB,IAAI,MAAM,EAAC,aAAa,CAAC,QAAQ,OAAO,IAAI;CACrE,MAAM,WAAW,KACb,QAAQ,KACR,GAAG,iBAAiB,GAAG,QAAQ,IAAI,GAAG,eAAe,QACxD;CACD,IAAI,cAAc;CAClB,IAAI,aAAa;CAEjB,MAAM,aAAa,YAAY;AAC3B,MAAI,YACA;AAGJ,QAAM,MAAM,QAAQ,KAAK,EAAE,WAAW,MAAM,CAAC;AAC7C,QAAM,oBAAoB,QAAQ,KAAK,UAAU,cAAc;AAC/D,gBAAc;;AAGlB,QAAO,EACH,MAAM,MAAM,OAAO;AACf,QAAM,YAAY;AAClB,QAAM,WAAW,UAAU,GAAG,KAAK,UAAU,MAAM,CAAC,KAAK,OAAO;AAChE,gBAAc;AAEd,MAAI,eAAe,KAAK,aAAa,QAAQ,EACzC,OAAM,oBAAoB,QAAQ,KAAK,UAAU,cAAc;IAG1E;;AAGL,eAAe,oBACX,WACA,UACA,eACa;CACb,IAAI,UAA+D,EAAE;AAErE,KAAI;EACA,MAAM,QAAQ,MAAM,QAAQ,UAAU;AAEtC,YAAU,MAAM,QAAQ,IACpB,MACK,QAAQ,SAAS,KAAK,SAAS,SAAS,CAAC,CACzC,IAAI,OAAO,SAAS;GACjB,MAAM,YAAY,KAAK,WAAW,KAAK;GACvC,MAAM,YAAY,MAAM,KAAK,UAAU;AAEvC,UAAO;IACH,MAAM;IACN,MAAM,UAAU;IAChB,MAAM,UAAU;IACnB;IACH,CACT;SACG;AACJ;;AAGJ,SAAQ,MAAM,MAAM,UAAU,MAAM,OAAO,KAAK,KAAK;CAErD,IAAI,aAAa;CACjB,MAAM,WAAgE,EAAE;CACxE,MAAM,UAA+D,EAAE;AAEvE,MAAK,MAAM,SAAS,SAAS;EACzB,MAAM,iBAAiB,SAAS,SAAS;EACzC,MAAM,gBAAgB,SAAS,WAAW,KAAK,aAAa,MAAM,QAAQ;AAE1E,MAAI,kBAAkB,eAAe;AACjC,YAAS,KAAK,MAAM;AACpB,iBAAc,MAAM;AACpB;;AAGJ,UAAQ,KAAK,MAAM;;AAGvB,OAAM,QAAQ,WACV,QAAQ,IAAI,OAAO,UAAU;AACzB,QAAM,OAAO,MAAM,KAAK;GAC1B,CACL;;AAGL,SAAS,wBACL,OACA,OACA,SACA,SACA,cACkB;CAClB,MAAM,YAAY,uBAAuB,MAAM;CAC/C,MAAM,UAAyB;EAC3B,GAAG,sBAAsB,aAAa;EACtC,GAAG,sBAAsB,UAAU,QAAQ;EAC9C;CACD,MAAM,kBAAkB,oBAAoB,OAAO,QAAQ;AAE3D,QAAO;EACH,qBAAI,IAAI,MAAM,EAAC,aAAa;EAC5B;EACA;EACA,WAAW,mBAAmB,QAAQ,UAAU;EAChD,OAAO,mBAAmB,QAAQ,MAAM;EACxC,SAAS,oBAAoB,gBAAgB;EAC7C,WAAW,QAAQ,aAAa;EAChC,aAAa,QAAQ,eAAe;EACpC,eAAe,qBAAqB,QAAQ;EAC5C,GAAI,QAAQ,WAAW,EAAE,UAAU,oBAAoB,QAAQ,SAAS,EAAE,GAAG,EAAE;EAC/E,GAAI,OAAO,QAAQ,WAAW,WAAW,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;EACxE,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC7D,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC7D,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC7D,GAAI,OAAO,QAAQ,aAAa,WAAW,EAAE,UAAU,QAAQ,UAAU,GAAG,EAAE;EAC9E,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;EACvD,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,cAAc,GAAG,EAAE;EACtE,GAAI,OAAO,QAAQ,eAAe,WAAW,EAAE,YAAY,QAAQ,YAAY,GAAG,EAAE;EACpF,GAAI,OAAO,QAAQ,YAAY,WAAW,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;EAC3E,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;EACpD,GAAI,OAAO,QAAQ,cAAc,WAAW,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EACjF,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,EAAE;EACjD,GAAG,sBAAsB,UAAU,MAAM;EAC5C;;AAGL,SAAS,kBAAkB,OAAoD;CAC3E,MAAM,EACF,SAAS,UACT,OAAO,QACP,SAAS,UACT,GAAG,SACH;AAEJ,QAAO;;AAGX,SAAS,uBAAuB,OAG9B;AACE,KAAI,iBAAiB,MACjB,QAAO;EACH,SAAS,EACL,OAAO,eAAe,MAAM,EAC/B;EACD,OAAO,EAAE;EACZ;AAGL,KAAI,MAAM,QAAQ,MAAM,CACpB,QAAO;EACH,SAAS,EAAE;EACX,OAAO,EACH,OAAO,MAAM,KAAK,SAAS,cAAc,KAAK,CAAC,EAClD;EACJ;AAGL,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC5B,QAAO;EACH,SAAS,EAAE;EACX,OAAO,EAAE;EACZ;AAGL,KAAI,OAAO,UAAU,SACjB,QAAO;EACH,SAAS,EAAE;EACX,OAAO,EAAE;EACZ;AAGL,KAAI,OAAO,UAAU,SACjB,QAAO;EACH,SAAS,EAAE;EACX,OAAO,EACH,OAAO,cAAc,MAAM,EAC9B;EACJ;CAGL,MAAM,SAAS;CACf,MAAM,UAAyB,EAAE;CACjC,MAAM,QAAiC,EAAE;AAEzC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;AAC/C,MAAI,sBAAsB,IAAI,IAAI,EAAE;AAChC,uBAAoB,SAAS,KAAK,MAAM;AACxC;;AAGJ,QAAM,OAAO,mBAAmB,KAAK,MAAM;;AAG/C,QAAO;EACH;EACA;EACH;;AAGL,SAAS,oBAAoB,SAAwB,KAAa,OAAsB;AACpF,SAAQ,KAAR;EACI,KAAK;EACL,KAAK;EACL,KAAK;AACD,OAAI,OAAO,UAAU,SACjB,SAAQ,OAAO;AAEnB;EACJ,KAAK;EACL,KAAK;AACD,OAAI,OAAO,UAAU,SACjB,SAAQ,OAAO;AAEnB;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;AACD,OAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACnD,SAAQ,OAAO,oBAAoB,MAAM,MAAM,CAAC;AAEpD;EACJ,KAAK;EACL,KAAK;EACL,KAAK;AACD,OAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACnD,SAAQ,OAAO,MAAM,MAAM;YACpB,UAAU,KACjB,SAAQ,OAAO;AAEnB;EACJ,KAAK;AACD,OAAI,iBAAiB,MACjB,SAAQ,QAAQ,eAAe,MAAM;YAC9B,cAAc,MAAM,CAC3B,SAAQ,QAAQ,kCAAkC,MAAM;AAE5D;EACJ,QACI;;;AAIZ,SAAS,oBAAoB,OAAgB,SAA0B;AACnE,KAAI,OAAO,UAAU,UAAU;EAC3B,MAAM,kBAAkB,MAAM,MAAM;AAEpC,SAAO,gBAAgB,SAAS,IAC1B,kBACA;;AAGV,KAAI,WAAW,QAAQ,MAAM,CAAC,SAAS,EACnC,QAAO,QAAQ,MAAM;AAGzB,KAAI,iBAAiB,MACjB,QAAO,MAAM,QAAQ,MAAM,IAAI,MAAM;AAGzC,QAAO;;AAGX,SAAS,qBAAqB,OAAmC;CAC7D,MAAM,aAAa,OAAO,MAAM;AAEhC,QAAO,cAAc,WAAW,SAAS,IACnC,aACA;;AAGV,SAAS,kBAAkB,OAA+C;AACtE,SAAQ,OAAO,MAAM,CAAC,aAAa,EAAnC;EACI,KAAK,QACD,QAAO;EACX,KAAK,OACD,QAAO;EACX,KAAK,QACD,QAAO;EACX,QACI,QAAO;;;AAInB,SAAS,mBAAmB,OAAmC;CAC3D,MAAM,aAAa,OAAO,MAAM;AAEhC,QAAO,cAAc,WAAW,SAAS,IACnC,aACA;;AAGV,SAAS,mBAAmB,OAAmC;CAC3D,MAAM,aAAa,OAAO,MAAM;AAEhC,QAAO,cAAc,WAAW,SAAS,IACnC,aACA;;AAGV,SAAS,qBAAqB,SAAuC;AACjE,KAAI,QAAQ,cACR,QAAO,QAAQ;AAGnB,KAAI,OAAO,QAAQ,aAAa,SAC5B,QAAO,OAAO,QAAQ,SAAS;AAGnC,QAAO,QAAQ,eAAe;;AAGlC,SAAS,eAAe,OAAkC;AACtD,QAAO;EACH,MAAM,MAAM;EACZ,SAAS,oBAAoB,MAAM,QAAQ;EAC3C,GAAI,MAAM,QAAQ,EAAE,OAAO,oBAAoB,MAAM,MAAM,EAAE,GAAG,EAAE;EAClE,GAAI,UAAU,SAAS,MAAM,QAAQ,OAAO,MAAM,SAAS,WACrD,EAAE,MAAM,cAAc,MAAM,KAAK,EAAE,GACnC,EAAE;EACX;;AAGL,SAAS,oBAAoB,OAAyD;AAClF,QAAO,OAAO,YACV,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,gBAAgB,CAC7C,KACA,mBAAmB,KAAK,WAAW,CACtC,CAAC,CACL;;AAGL,SAAS,mBAAmB,KAAa,OAAyB;AAC9D,KAAI,eAAe,IAAI,CACnB,QAAO,0BAA0B,MAAM;AAG3C,KAAI,aAAa,IAAI,CACjB,QAAO,kBAAkB,MAAM;AAGnC,KAAI,iBAAiB,IAAI,CACrB,QAAO,mBAAmB,MAAM;AAGpC,KAAI,0BAA0B,IAAI,CAC9B,QAAO,8BAA8B,MAAM;AAG/C,QAAO,cAAc,MAAM;;AAG/B,SAAS,cAAc,OAAyB;AAC5C,KAAI,iBAAiB,MACjB,QAAO,eAAe,MAAM;AAGhC,KAAI,MAAM,QAAQ,MAAM,CACpB,QAAO,MAAM,KAAK,UAAU,cAAc,MAAM,CAAC;AAGrD,KAAI,OAAO,UAAU,SACjB,QAAO,oBAAoB,MAAM;AAGrC,KAAI,CAAC,SAAS,OAAO,UAAU,SAC3B,QAAO;AAGX,QAAO,oBAAoB,MAAiC;;AAGhE,SAAS,mBAAmB,OAAyB;AACjD,KAAI,OAAO,UAAU,SACjB,QAAO;EACH,SAAS;EACT,QAAQ,MAAM;EACjB;AAGL,KAAI,MAAM,QAAQ,MAAM,CACpB,QAAO;EACH,SAAS;EACT,OAAO,MAAM;EAChB;AAGL,KAAI,SAAS,OAAO,UAAU,SAC1B,QAAO;EACH,SAAS;EACT,MAAM;EACT;AAGL,QAAO;;AAGX,SAAS,kBAAkB,OAAyB;AAChD,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACnD,QAAO;EACH,SAAS;EACT,MAAM;EACT;AAGL,QAAO,cAAc,MAAM;;AAG/B,SAAS,8BAA8B,OAAyB;AAC5D,KAAI,CAAC,MAAM,QAAQ,MAAM,CACrB,QAAO,mBAAmB,MAAM;AAGpC,QAAO;EACH,OAAO,MAAM;EACb,OAAO,MAAM,KAAK,UAAU,yBAAyB,MAAM,CAAC;EAC/D;;AAGL,SAAS,yBAAyB,OAAyB;AACvD,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,MAAM,CAC3D,QAAO,mBAAmB,MAAM;CAGpC,MAAM,SAAS;AAEf,QAAO,sBAAsB;EACzB,UAAU,gBAAgB,OAAO,SAAS,IAAI,gBAAgB,OAAO,SAAS,IAAI,KAAA;EAClF,MAAM,gBAAgB,OAAO,KAAK,IAAI,gBAAgB,OAAO,SAAS,IAAI,KAAA;EAC1E,WAAW,iBAAiB,QAAQ;GAAC;GAAa;GAAQ;GAAW,CAAC;EACtE,YAAY,gBAAgB,QAAQ,CAAC,UAAU,CAAC,KAAK;EACrD,YAAY,gBAAgB,QAAQ,CAAC,QAAQ,SAAS,CAAC,EAAE;EACzD,MAAM,gBAAgB,OAAO,KAAK,IAAI,KAAA;EACzC,CAAC;;AAGN,SAAS,eAAe,KAAsB;AAC1C,QAAO,2DAA2D,KAAK,IAAI;;AAG/E,SAAS,iBAAiB,KAAsB;AAC5C,QAAO,4FAA4F,KAAK,IAAI,IACrG,6CAA6C,KAAK,IAAI;;AAGjE,SAAS,aAAa,KAAsB;AACxC,QAAO,sEAAsE,KAAK,IAAI;;AAG1F,SAAS,0BAA0B,KAAsB;AACrD,QAAO,uCAAuC,KAAK,IAAI;;AAG3D,SAAS,0BAA0B,OAAyB;AACxD,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACnD,QAAO;AAGX,KAAI,MAAM,QAAQ,MAAM,CACpB,QAAO,MAAM,UAAU,SAAS;AAGpC,KAAI,SAAS,OAAO,UAAU,SAC1B,QAAO;AAGX,QAAO;;AAGX,SAAS,sBAA8C,QAA0B;AAC7E,QAAO,OAAO,YACV,OAAO,QAAQ,OAAO,CAAC,QAAQ,GAAG,WAAW,UAAU,KAAA,EAAU,CACpE;;AAGL,SAAS,cAAc,OAAkD;AACrE,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;AAG/E,SAAS,gBAAgB,OAA+B;AACpD,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,IACpD,oBAAoB,MAAM,MAAM,CAAC,GACjC;;AAGV,SAAS,iBAAiB,QAAiC,MAAoC;AAC3F,MAAK,MAAM,OAAO,MAAM;EACpB,MAAM,QAAQ,OAAO;AAErB,MAAI,OAAO,UAAU,SACjB,QAAO;;;AAOnB,SAAS,gBAAgB,QAAiC,MAA+B;AACrF,MAAK,MAAM,OAAO,MAAM;EACpB,MAAM,QAAQ,OAAO;AAErB,MAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACnD,QAAO,MAAM,MAAM;;AAI3B,QAAO;;AAGX,SAAS,oBAAoB,OAAuB;AAChD,QAAO,MAAM,QAAQ,oBAAoB,IAAI;;AAGjD,SAAS,kCAAkC,OAAoD;AAC3F,QAAO;EACH,MAAM,gBAAgB,MAAM,KAAK,IAAI;EACrC,SAAS,gBAAgB,MAAM,QAAQ,IAAI;EAC3C,GAAI,OAAO,MAAM,UAAU,WAAW,EAAE,OAAO,oBAAoB,MAAM,MAAM,EAAE,GAAG,EAAE;EACtF,GAAI,MAAM,SAAS,KAAA,IAAY,EAAE,MAAM,cAAc,MAAM,KAAK,EAAE,GAAG,EAAE;EAC1E;;;;ACr4BL,IAAa,8BAAb,MAA4E;CACxE,YAAY,OAA2D;AAA1C,OAAA,QAAA;;CAE7B,MAAM,YAAY,QAAmD;AAGjE,UAFc,MAAM,KAAK,MAAM,MAAM,EAExB,eAAe,OAAO,OAAO,KAAK;;CAGnD,MAAM,IAAI,QAA0C;AAChD,QAAM,KAAK,MAAM,QAAQ,UAAU;AAC/B,SAAM,eAAe,OAAO,OAAO,OAAO,IAAI;IAChD;;CAGN,MAAM,MAAM,QAA+B;AACvC,QAAM,KAAK,MAAM,QAAQ,UAAU;AAC/B,UAAO,MAAM,eAAe,OAAO,OAAO;IAC5C;;;;;AClCV,SAAS,iBAAiB,WAAmB,QAAwB;AACjE,QAAO,GAAG,UAAU,GAAG;;AAe3B,IAAa,mCAAb,MAAsF;CAClF,YAAY,OAA2D;AAA1C,OAAA,QAAA;;CAE7B,MAAM,gBAAgB,WAAyD;EAC3E,MAAM,QAAQ,MAAM,KAAK,MAAM,MAAM;AAErC,SAAO,OAAO,OAAO,MAAM,mBAAmB,CAAC,QAAQ,aAAa,SAAS,cAAc,UAAU;;CAGzG,MAAM,IAAI,UAAoD;AAC1D,QAAM,KAAK,MAAM,QAAQ,UAAU;AAC/B,SAAM,mBAAmB,iBAAiB,SAAS,WAAW,SAAS,OAAO,IAAI;IACpF;;;;;ACCV,IAAa,wBAAb,MAAgE;CAC5D,YAAY,OAA2D;AAA1C,OAAA,QAAA;;CAE7B,MAAM,YAAY,QAAoD;AAGlE,UAFc,MAAM,KAAK,MAAM,MAAM,EAExB,SAAS,OAAO,OAAO,KAAK;;CAG7C,MAAM,gBAAgB,WAAkD;EACpE,MAAM,QAAQ,MAAM,KAAK,MAAM,MAAM;AAErC,SAAO,OAAO,OAAO,MAAM,SAAS,CAAC,QAAQ,YAAY,QAAQ,cAAc,UAAU;;CAG7F,MAAM,WAAW,SAA4C;AACzD,QAAM,KAAK,MAAM,QAAQ,UAAU;AAC/B,SAAM,SAAS,OAAO,QAAQ,OAAO,IAAI;IAC3C;;CAGN,MAAM,MAAM,QAA+B;AACvC,QAAM,KAAK,MAAM,QAAQ,UAAU;GAC/B,MAAM,UAAU,MAAM,SAAS,OAAO,OAAO;AAE7C,OAAI,CAAC,QACD;AAGJ,SAAM,SAAS,OAAO,OAAO,IAAI;IAC7B,GAAG;IACH,4BAAW,IAAI,MAAM,EAAC,aAAa;IACtC;IACH;;;;;ACnEV,IAAM,mBAAmB;AAEzB,SAAgB,yBAAyB,UAA0B;CAE/D,MAAM,QADqB,+BAA+B,SAAS,CAClC,MAAM,KAAK;CAC5C,MAAM,WAAqB,EAAE;AAE7B,MAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;EAClD,MAAM,aAAa,uBAAqB,OAAO,MAAM;AAErD,MAAI,YAAY;AACZ,YAAS,KAAK,uBAAuB,WAAW,KAAK,CAAC;AACtD,WAAQ,WAAW,YAAY;AAC/B;;AAGJ,WAAS,KAAK,MAAM,UAAU,GAAG;;AAGrC,QAAO,SACF,KAAK,KAAK,CACV,QAAQ,yBAAyB,GAAG,CACpC,QAAQ,QAAQ,GAAG,CACnB,QAAQ,gBAAgB,GAAG,CAC3B,QAAQ,cAAc,GAAG,CACzB,QAAQ,oBAAoB,OAAO,CACnC,QAAQ,wBAAwB,SAAS,CACzC,QAAQ,4BAA4B,UAAU,CAC9C,QAAQ,qBAAqB,KAAK,CAClC,QAAQ,kBAAkB,KAAK,CAC/B,QAAQ,cAAc,KAAK,CAC3B,QAAQ,kBAAkB,GAAG,CAC7B,MAAM;;AAQf,SAAS,+BAA+B,UAA0B;CAE9D,MAAM,QADqB,SAAS,QAAQ,UAAU,KAAK,CAC1B,MAAM,KAAK;CAC5C,MAAM,YAAsB,EAAE;CAC9B,IAAI,cAA2C;AAE/C,MAAK,MAAM,QAAQ,OAAO;EACtB,MAAM,aAAa,KAAK,MAAM,4BAA4B;AAE1D,MAAI,YAAY;GACZ,MAAM,YAAY,WAAW,MAAM,IAAI,aAAa;AAEpD,OAAI,gBAAgB,YAAY;AAC5B,kBAAc;AACd;;AAGJ,OAAI,gBAAgB,SAAS;AACzB,cAAU,KAAK,KAAK;AACpB,kBAAc;AACd;;AAGJ,OAAI,aAAa,QAAQ,aAAa,YAAY;AAC9C,kBAAc;AACd;;AAGJ,iBAAc;AACd,aAAU,KAAK,KAAK;AACpB;;AAGJ,YAAU,KAAK,KAAK;;AAGxB,QAAO,UAAU,KAAK,KAAK;;AAG/B,SAAS,uBAAqB,OAAiB,YAA0C;AACrF,KAAI,aAAa,KAAK,MAAM,OACxB,QAAO;CAGX,MAAM,cAAc,wBAAsB,MAAM,eAAe,GAAG;CAClE,MAAM,iBAAiB,8BAA4B,MAAM,aAAa,MAAM,GAAG;AAE/E,KAAI,CAAC,eAAe,CAAC,kBAAkB,YAAY,WAAW,eAAe,OACzE,QAAO;CAGX,MAAM,OAAO,CAAC,YAAY;CAC1B,IAAI,QAAQ,aAAa;AAEzB,QAAO,QAAQ,MAAM,QAAQ;EACzB,MAAM,WAAW,wBAAsB,MAAM,UAAU,GAAG;AAE1D,MAAI,CAAC,YAAY,SAAS,WAAW,YAAY,OAC7C;AAGJ,OAAK,KAAK,SAAS;AACnB,WAAS;;AAGb,QAAO;EACH;EACA,WAAW;EACd;;AAGL,SAAS,wBAAsB,MAA+B;CAC1D,MAAM,UAAU,KAAK,MAAM;AAE3B,KAAI,CAAC,QAAQ,SAAS,IAAI,CACtB,QAAO;CAGX,MAAM,QAAQ,0BAAwB,QAAQ,CACzC,KAAK,SAAS,qBAAmB,KAAK,CAAC;AAE5C,QAAO,MAAM,UAAU,IAAI,QAAQ;;AAGvC,SAAS,8BAA4B,MAA+B;CAChE,MAAM,QAAQ,0BAAwB,KAAK,MAAM,CAAC;AAElD,KAAI,MAAM,SAAS,EACf,QAAO;AAGX,QAAO,MAAM,OAAO,SAAS,cAAc,KAAK,KAAK,MAAM,CAAC,CAAC,GACvD,QACA;;AAGV,SAAS,0BAAwB,MAAwB;CACrD,MAAM,UAAU,KACX,QAAQ,OAAO,GAAG,CAClB,QAAQ,OAAO,GAAG;CACvB,MAAM,QAAkB,EAAE;CAC1B,IAAI,UAAU;CACd,IAAI,UAAU;AAEd,MAAK,MAAM,QAAQ,SAAS;AACxB,MAAI,SAAS;AACT,cAAW;AACX,aAAU;AACV;;AAGJ,MAAI,SAAS,MAAM;AACf,aAAU;AACV,cAAW;AACX;;AAGJ,MAAI,SAAS,KAAK;AACd,SAAM,KAAK,QAAQ;AACnB,aAAU;AACV;;AAGJ,aAAW;;AAGf,OAAM,KAAK,QAAQ;AACnB,QAAO;;AAGX,SAAS,qBAAmB,MAAsB;AAC9C,QAAO,KACF,MAAM,CACN,QAAQ,SAAS,IAAI,CACrB,QAAQ,4BAA4B,UAAU,CAC9C,QAAQ,qBAAqB,KAAK,CAClC,QAAQ,kBAAkB,KAAK,CAC/B,QAAQ,cAAc,KAAK,CAC3B,QAAQ,kBAAkB,GAAG;;AAGtC,SAAS,uBAAuB,MAA0B;AACtD,QAAO,yBAAuB,KAAK,CAAC,KAAK,KAAK;;AAGlD,SAAS,yBAAuB,MAA4B;CACxD,MAAM,eAAe,6BAA2B,KAAK;AAKrD,QAAO;EAJQ,iBAAe,KAAK,MAAM,EAAE,EAAE,aAAa;EACxC,aAAa,KAAK,UAAU,IAAI,OAAO,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;EAG9D,GAFd,KAAK,MAAM,EAAE,CAAC,KAAK,QAAQ,iBAAe,KAAK,aAAa,CAAC;EAEvC;;AAGvC,SAAS,6BAA2B,MAA4B;AAC5D,SAAQ,KAAK,MAAM,EAAE,EAAE,KAAK,GAAG,gBAC3B,KAAK,QAAQ,UAAU,QAAQ,KAAK,IAAI,UAAU,kBAAgB,IAAI,gBAAgB,GAAG,CAAC,EAAE,EAAE,CACjG;;AAGL,SAAS,iBAAe,KAAe,cAAgC;AACnE,QAAO,IACF,KAAK,MAAM,UAAU,kBAAgB,MAAM,aAAa,UAAU,EAAE,CAAC,CACrE,KAAK,MAAM;;AAGpB,SAAS,kBAAgB,OAAe,aAA6B;CACjE,MAAM,UAAU,KAAK,IAAI,GAAG,cAAc,kBAAgB,MAAM,CAAC;AAEjE,QAAO,GAAG,QAAQ,IAAI,OAAO,QAAQ;;AAGzC,SAAS,kBAAgB,OAAuB;CAC5C,IAAI,QAAQ;AAEZ,MAAK,MAAM,QAAQ,MACf,UAAS,kBAAgB,KAAK,YAAY,EAAE,IAAI,EAAE,GAAG,IAAI;AAG7D,QAAO;;AAGX,SAAS,kBAAgB,WAA4B;AACjD,QAAO,aAAa,SAChB,aAAa,QACb,cAAc,QACd,cAAc,QACb,aAAa,SAAU,aAAa,SAAU,cAAc,SAC5D,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa;;;;AC1M7C,SAAgB,uBAAuB,SAAgC;CACnE,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,QAAO;EACH,SAAS,QAAQ;EACjB,GAAI,SAAS,EAAE,MAAM,QAAQ,GAAG,EAAE;EACrC;;AAmJL,IAAa,6BAAb,cAAgD,MAAM;CAClD;CAEA,YAAY,MAAsC;AAC9C,QAAM,KAAK,WAAW,6BAA6B;AACnD,OAAK,OAAO;AACZ,OAAK,OAAO;;;AAIpB,IAAa,8BAAb,cAAiD,MAAM;CACnD;CAIA,YAAY,UAAU,wBAAwB;AAC1C,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO,EACR,SACH;;;AAIT,SAAgB,0BAA0B,UAAU,wBAAqD;AACrG,QAAO,IAAI,4BAA4B,QAAQ;;AA2CnD,IAAM,sBAAsB;AAC5B,IAAM,wCAAwC;CAAC;CAAG;CAAK;CAAK;CAAK;CAAK;AACtE,IAAM,kCAAkC;AACxC,IAAM,4BAA4B;AAClC,IAAM,qBAAqB;AAC3B,IAAM,yCAAsE;CACxE,sBAAsB;CACtB,6BAA6B;CAC7B,eAAe;CAClB;AACD,IAAM,cAAc;CAChB,eAAe;CACf,cAAc;CACjB;AACD,IAAM,qBAA+C,EACjD,MAAM,QACT;AA8BD,IAAa,iBAAb,MAA0D;CACtD;CACA;CACA;CACA,aAII;EACI,WAAW;EACX,SAAS;EACT,OAAO;EACV;CAEL,YACI,SACA,QACA,UAAwB,OACxB,sBAA4D,EAAE,EAChE;AACE,MAAI,CAAC,WAAW,CAAC,OACb,OAAM,IAAI,MAAM,6EAA6E;AAGjG,OAAK,SAAS,UAAU,qBAAqB,uBAAuB,QAAiC,CAAC;AACtG,OAAK,UAAU;AACf,OAAK,sBAAsB,2BAA2B,oBAAoB;;CAG9E,6BACI,qBACI;AACJ,OAAK,sBAAsB,2BAA2B;GAClD,GAAG,KAAK;GACR,GAAG;GACN,CAAC;;CAGN,MAAc,oBACV,OACA,QACA,OACU;EACV,MAAM,SAAS,KAAK,OAAO;EAC3B,MAAM,UAAU,SAAS;AAEzB,MAAI,OAAO,YAAY,WACnB,OAAM,IAAI,MAAM,oDAAoD,MAAM,GAAG,OAAO,UAAU;EAGlG,MAAM,UAAU;GACZ,GAAG;GACH,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,QAAQ,GAAG,EAAE;GACnD;AAiBD,SAAO,cAhBU,QAAQ,UAAU,IAC7B,MAAO,QAA+G,KACpH,QACA,MAAM,kBACN,QACH,GACC,MAAO,QAA0F,KAC/F,QACA,MAAM,eAAe,KAAA,IACf,UACA;GACE,GAAG,MAAM;GACT,GAAG;GACN,CACR,CAEyB;;CAGlC,MAAM,YAAqC;AACvC,MAAI;AACA,UAAO,MAAM,KAAK,oBAAoC,UAAU,UAAU,EAAE,CAAC;WACxE,OAAO;AACZ,OAAI,CAAC,8BAA8B,OAAO,UAAU,SAAS,CACzD,OAAM;AAGV,UAAO,KAAK,cAA8B,iBAAiB;;;CAInE,MAAM,aAAa,WAAqC;AACpD,SAAO,KAAK,oBAA6B,WAAW,SAAS;GACzD,kBAAkB,EACd,WAAW,WACd;GACD,YAAY,EACR,MAAM,EACF,IAAI,WACP,EACJ;GACJ,CAAC;;CAGN,MAAM,cAAc,WAAqC;AACrD,SAAO,KAAK,oBAA6B,WAAW,UAAU;GAC1D,kBAAkB,EACd,WAAW,WACd;GACD,YAAY,EACR,MAAM,EACF,IAAI,WACP,EACJ;GACJ,CAAC;;CAGN,MAAM,YAAY,WAAmB,WAA8C;AAC/E,SAAO,KAAK,oBAAqC,WAAW,QAAQ;GAChE,kBAAkB;IACd,WAAW;IACX,GAAI,WAAW,MAAM,GACf,EAAE,WAAW,UAAU,MAAM,EAAE,GAC/B,EAAE;IACX;GACD,YAAY;IACR,MAAM,EACF,IAAI,WACP;IACD,GACI,WAAW,MAAM,GACX,EACE,MAAM,EACF,WAAW,UAAU,MAAM,EAC9B,EACJ,GACC,EAAE;IAEf;GACJ,CAAC;;CAGN,MAAM,UAAiC;AACnC,SAAO,KAAK,oBAAkC,QAAQ,OAAO,EAAE,CAAC;;CAGpE,MAAM,gBAAgB,WAAkD;AACpE,SAAO,KAAK,oBAAyC,OAAO,UAAU;GAClE,kBAAkB,YACZ,EAAE,WAAW,GACb,KAAA;GACN,YAAY,YACN,EACE,OAAO,EACH,WACH,EACJ,GACC,KAAA;GACT,CAAC;;CAGN,MAAM,gBAAgB,WAAgE;AAClF,SAAO,KAAK,oBAAuD,OAAO,UAAU;GAChF,kBAAkB,YACZ,EAAE,WAAW,GACb,KAAA;GACN,YAAY,YACN,EACE,OAAO,EACH,WACH,EACJ,GACC,KAAA;GACT,CAAC;;CAGN,MAAM,qBAAqE;AACvE,SAAO,KAAK,qBAAqB;;CAGrC,MAAM,eAA2C;AAC7C,SAAO,KAAK,oBAAuC,WAAW,QAAQ,EAAE,CAAC;;CAG7E,MAAM,eAA2C;AAC7C,SAAO,KAAK,oBAAuC,WAAW,QAAQ,EAAE,CAAC;;CAG7E,MAAM,oBAA8C;AAChD,SAAO,KAAK,oBAAqC,WAAW,WAAW,EAAE,CAAC;;CAG9E,MAAM,0BAA0B,WAAmB,OAA0C;AACzF,SAAO,KAAK,oBAAqC,WAAW,UAAU;GAClE,kBAAkB,QAAQ;IAAE;IAAW;IAAO,GAAG,EAAE,WAAW;GAC9D,YAAY;IACR,OAAO,EACH,WACH;IACD,GAAI,QACE,EACE,MAAM,EACF,OACH,EACJ,GACC,EAAE;IACX;GACJ,CAAC;;CAGN,MAAM,cAAc,WAAmB,OAAyC;AAC5E,SAAO,KAAK,oBAAqC,WAAW,UAAU;GAClE,kBAAkB;IACd,WAAW;IACX;IACH;GACD,YAAY;IACR,MAAM,EACF,IAAI,WACP;IACD,MAAM,EACF,OACH;IACJ;GACJ,CAAC;;CAGN,MAAM,aAAuC;AACzC,SAAO,KAAK,oBAAqC,OAAO,UAAU,EAAE,CAAC;;CAGzE,MAAM,uBAAuB,WAA0D;AAcnF,UAboB,MAAM,KAAK,oBAA+B,cAAc,QAAQ;GAChF,kBAAkB,YACZ,EAAE,WAAW,GACb,KAAA;GACN,YAAY,YACN,EACE,OAAO,EACH,WACH,EACJ,GACC,KAAA;GACT,CAAC,EAEiB,IAAI,2BAA2B,CAAC,QAAQ,eAAwD,CAAC,CAAC,WAAW;;CAGpI,MAAM,kBACF,WACA,OACA,SACA,WACgB;EAChB,MAAM,oBAAoB,SAAS,MAAM;EACzC,MAAM,wBAAwB,KAAK,OAAO;AAE1C,MAAI,aAAa,OAAO,0BAA0B,WAC9C,QAAO,cAAc,MAAM,sBAAsB,KAAK,KAAK,QAAQ;GAC/D,GAAG;GACH,MAAM;IACF,UAAU;IACV,GAAI,oBACE,EAAE,SAAS,mBAAmB,GAC9B,EAAE;IACX;GACD,MAAM;IACF,IAAI;IACJ,cAAc;IACjB;GACJ,CAAC,CAAkC;AAGxC,SAAO,KAAK,oBAA6B,cAAc,SAAS;GAC5D,kBAAkB;IACd,WAAW;IACX;IACA,GAAI,oBACE,EAAE,SAAS,mBAAmB,GAC9B,EAAE;IACX;GACD,YAAY,YACN;IACE,MAAM;KACF,UAAU;KACV,GAAI,oBACE,EAAE,SAAS,mBAAmB,GAC9B,EAAE;KACX;IACD,MAAM;KACF,IAAI;KACJ,cAAc;KACjB;IACJ,GACC,KAAA;GACT,CAAC;;CAGN,MAAM,aAAiD;EACnD,MAAM,MAAM,KAAK,KAAK;AAEtB,MAAI,KAAK,WAAW,SAAS,KAAK,WAAW,YAAY,IACrD,QAAO,KAAK,WAAW;AAG3B,MAAI,KAAK,WAAW,QAChB,QAAO,KAAK,WAAW;EAG3B,MAAM,iBAAiB,KAAK,YAAY,CAAC,cAAc;AACnD,OAAI,KAAK,WAAW,YAAY,eAC5B,MAAK,WAAW,UAAU;IAEhC;AAEF,OAAK,WAAW,UAAU;AAE1B,SAAO;;CAGX,MAAM,wBAA2C;AAG7C,SAAO,gCAFQ,MAAM,KAAK,YAAY,EAEO,OAAO;;CAGxD,MAAM,cAAc,OAAyD;EACzE,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,aAAa,MAAM,QAAQ,MAAM,IAAI;EAC3C,MAAM,QAAQ,CACV,GAAI,aACE,CAAC;GACC,MAAM;GACN,MAAM;GACT,CAAC,GACA,EAAE,EACR,IAAK,MAAM,SAAS,EAAE,EAAE,KAAK,UAAU;GACnC,MAAM;GACN,UAAU,KAAK;GACf,MAAM,KAAK;GACX,KAAK,KAAK;GACb,EAAE,CACN;AAED,MAAI,MAAM,WAAW,EACjB,OAAM,IAAI,MAAM,4CAA4C;AAGhE,iBAAe,MAAM,OAAO;EAE5B,MAAM,kBAAkB,MAAM,KAAK,uBAAuB,MAAM,WAAW,MAAM,OAAO;AACxF,QAAM,KAAK,kBAAkB,OAAO,MAAM;AAS1C,SAAO,yBARc,MAAM,KAAK,sBAC5B,OACA,MACA,iBACA,UACH,EAG6C;GAC1C,mBAAmB;GACnB,YAJe,KAAK,KAAK;GAKzB;GACH,CAAC;;CAGN,MAAc,sBACV,OACA,MACA,iBACA,WAC+B;AAC/B,MAAI,QAAQ,sCAAsC,KAAK,CACnD,QAAO;EAGX,MAAM,YAAY,OAAO,iBAAiB,KAAK,KAAK,GAAG;EACvD,MAAM,mBAAmD;GACrD,kBAAkB;GAClB,iBAAiB,OAAO,mBAAmB,KAAK,KAAK,EAAE,YAAY,OAAO;GAC1E;GACA,kBAAkB,gCAAgC,WAAW,KAAK;GACrE;EACD,IAAI,gBAAgB,8BAChB,OAAO,CAAC,KAAK,GAAG,EAAE,EAClB,iBACH;EACD,IAAI,iBAAiB,KAAK,KAAK;EAC/B,IAAI,aAA2C;EAC/C,MAAM,aAAa,YAAY,KAAK,oBAAoB;EACxD,IAAI,iBAAiB;EACrB,IAAI,UAAU;AAEd,SAAO,MAAM;AACT,kBAAe,MAAM,OAAO;GAE5B,MAAM,kBAAkB,aAAa,KAAK,KAAK;GAC/C,MAAM,wBAAwB,KAAK,oBAAoB,+BAA+B,KAAK,KAAK,GAAG;AAEnG,OAAI,mBAAmB,KAAK,yBAAyB,EACjD;GAGJ,MAAM,UAAU,4BAA4B,QAAQ;AACpD,cAAW;AAEX,OAAI,UAAU,GAAG;IACb,MAAM,cAAc,KAAK,IAAI,iBAAiB,sBAAsB;AAEpE,QAAI,eAAe,EACf;AAGJ,UAAM,MAAM,KAAK,IAAI,SAAS,YAAY,EAAE,MAAM,OAAO;;AAG7D,OAAI,WAAW;IACX,MAAM,OAAO,MAAM,KAAK,mBAAmB,MAAM,WAAW,WAAW,MAAM,OAAO;AAEpF,QAAI,MAAM;KACN,MAAM,gBAAgB,8BAClB,CAAC,eAAe,KAAK,EACrB,iBACH;AAED,SAAI,eAAe;AACf,UAAI,yBAAyB,eAAe,cAAc,EAAE;AACxD,wBAAiB,KAAK,KAAK;AAC3B,wBAAiB;;AAGrB,sBAAgB;;AAGpB,SACI,iBACG,kCAAkC,eAAe,iBAAiB,IAClE,sCAAsC,cAAc,CAEvD,QAAO;;;GAKnB,MAAM,SAAS,MAAM,KAAK,yBACtB,MAAM,WACN,kBACA,iBACA,MAAM,OACT;AAED,OAAI,QAAQ;IACR,MAAM,gBAAgB,8BAClB,CAAC,eAAe,OAAO,EACvB,iBACH;AAED,QAAI,eAAe;AACf,SAAI,yBAAyB,eAAe,cAAc,EAAE;AACxD,uBAAiB,KAAK,KAAK;AAC3B,uBAAiB;;AAGrB,qBAAgB;;AAGpB,QACI,iBACG,kCAAkC,eAAe,iBAAiB,IAClE,sCAAsC,cAAc,CAEvD,QAAO;;GAIf,MAAM,SAAS,MAAM,KAAK,yBAAyB,MAAM,WAAW,MAAM,OAAO;AAEjF,gBAAa;AAEb,OAAI,QAAQ,SAAS,UAAU,QAAQ,SAAS,SAAS;AACrD,qBAAiB,KAAK,KAAK;AAC3B,qBAAiB;cACV,QAAQ,SAAS,QAAQ;AAChC,QAAI,eACA;AAGJ,qBAAiB;;AAGrB,OACI,iBACG,kCAAkC,eAAe,iBAAiB,IAClE,+BAA+B,cAAc,IAC7C,QAAQ,SAAS,UACjB,QAAQ,SAAS,QAEpB;AAGJ,OAAI,KAAK,KAAK,IAAI,WACd;;EAIR,MAAM,SAAS,MAAM,KAAK,yBACtB,MAAM,WACN,kBACA,cACA,MAAM,OACT;EAED,MAAM,WAAW,8BACb,CAAC,eAAe,OAAO,EACvB,iBACH;EACD,MAAM,wBAAwB,YAAY,kCAAkC,UAAU,iBAAiB,GACjG,WACA;AAEN,MACI,YAAY,SAAS,WACjB,CAAC,yBAAyB,wBAAwB,sBAAsB,EAE5E,OAAM,2BAA2B;AAGrC,MAAI,CAAC,yBAAyB,wBAAwB,sBAAsB,EAAE;GAC1E,MAAM,gBAAgB,KAAK,KAAK,IAAI,aAC9B,aACA;GACN,MAAM,YAAY,kBAAkB,aAC9B,KAAK,oBAAoB,gBACzB,KAAK,oBAAoB;GAC/B,MAAM,QAAQ,iCAAiC;IAC3C,WAAW,MAAM;IACjB,OAAO;IACP;IACA,WAAW,aAAa,KAAA;IAC3B,CAAC;AACF,QAAK,iBAAiB,QAAQ;IAC1B;IACA,WAAW,aAAa,KAAA;IACxB,WAAW,MAAM;IACjB,OAAO;IACP;IACA;IACH,EAAE,qCAAqC;AACxC,SAAM;;AAGV,SAAO;;CAGX,MAAc,mBACV,WACA,WACA,QACsC;AACtC,MAAI;AACA,UAAO,MAAM,KAAK,4BACd;IACI;IACA,OAAO;IACP,WAAW,KAAK,oBAAoB;IACpC;IACH,EACD,OAAO,kBAAkB;AACrB,WAAO,wBAAwB,MAAM,KAAK,oBAA4C,WAAW,WAAW;KACxG,kBAAkB;MACd,WAAW;MACX,WAAW;MACd;KACD,YAAY,EACR,MAAM;MACF,IAAI;MACJ,WAAW;MACd,EACJ;KACD,QAAQ;KACX,CAAC,CAAC;MAEP,OACH;WACI,OAAO;AACZ,OAAI,qBAAqB,MAAM,CAC3B,OAAM;AAGV,QAAK,wBAAwB,OAAO;IAChC;IACA,OAAO;IACP,WAAW,KAAK,oBAAoB;IACpC;IACH,CAAC;AACF,UAAO;;;CAIf,MAAc,uBAAuB,WAAmB,QAA4C;EAChG,MAAM,WAAW,MAAM,KAAK,0BAA0B,WAAW,0BAA0B,OAAO;AAElG,MAAI,CAAC,SACD,wBAAO,IAAI,KAAK;AAGpB,SAAO,IAAI,IACP,SACK,KAAK,YAAY,iBAAiB,QAAQ,KAAK,CAAC,CAChD,QAAQ,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,EAAE,CAC7E;;CAGL,MAAc,0BACV,WACA,OACA,QACwC;AACxC,MAAI;AACA,UAAO,MAAM,KAAK,4BACd;IACI;IACA;IACA,WAAW,KAAK,oBAAoB;IACvC,EACD,OAAO,kBAAkB;AACrB,WAAO,yBAAyB,MAAM,KAAK,oBAA8C,WAAW,YAAY;KAC5G,kBAAkB;MACd,WAAW;MACX,OAAO;MACV;KACD,YAAY;MACR,MAAM,EACF,IAAI,WACP;MACD,OAAO,EACH,OAAO,2BACV;MACJ;KACD,QAAQ;KACX,CAAC,CAAC;MAEP,OACH;WACI,OAAO;AACZ,OAAI,qBAAqB,MAAM,CAC3B,OAAM;AAGV,QAAK,wBAAwB,OAAO;IAChC;IACA;IACA,WAAW,KAAK,oBAAoB;IACvC,CAAC;AACF,UAAO;;;CAIf,MAAc,yBAAyB,WAAmB,QAA6D;AACnH,MAAI;AAWA,WAViB,MAAM,KAAK,4BACxB;IACI;IACA,OAAO;IACP,WAAW,KAAK,oBAAoB;IACvC,EACD,OAAO,kBAAkB,KAAK,oBAAoB,cAAc,EAChE,OACH,EAEe,cAAc;WACzB,OAAO;AACZ,OAAI,qBAAqB,MAAM,CAC3B,OAAM;AAGV,QAAK,wBAAwB,OAAO;IAChC;IACA,OAAO;IACP,WAAW,KAAK,oBAAoB;IACvC,CAAC;AACF,UAAO;;;CAIf,MAAc,yBACV,WACA,SACA,OACA,QACsC;EACtC,MAAM,WAAW,MAAM,KAAK,0BAA0B,WAAW,OAAO,OAAO;AAE/E,MAAI,CAAC,YAAY,SAAS,WAAW,EACjC,QAAO;AAGX,SAAO,8BAA8B,UAAU,QAAQ;;CAG3D,MAAc,aAAiD;EAC3D,MAAM,CAAC,QAAQ,mBAAmB,MAAM,QAAQ,IAAI,CAChD,KAAK,YAAY,EACjB,KAAK,qBAAqB,CAC7B,CAAC;EACF,MAAM,uBAAuB,MAAM,4BAA4B,QAAQ,KAAK,QAAQ;EACpF,MAAM,SAAS,sBACX,QACA,gBAAgB,WAChB,qBACH;AAED,OAAK,aAAa;GACd,WAAW,KAAK,KAAK,GAAG;GACxB,SAAS;GACT,OAAO;GACV;AAED,SAAO;;CAGX,MAAc,aAAsC;AAChD,SAAO,KAAK,oBAAoC,UAAU,OAAO,EAAE,CAAC;;CAGxE,MAAc,sBAAwD;AAClE,SAAO,KAAK,oBAA6C,UAAU,aAAa,EAAE,CAAC;;CAGvF,MAAc,kBACV,OACA,OAIa;EACb,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,cAAc;GAChB,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,OAAO,GAAG,EAAE;GAC7C;GACA,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,OAAO,GAAG,EAAE;GAC7C,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,SAAS,GAAG,EAAE;GACnD;GACH;EACD,MAAM,0BAA0B;GAC5B,WAAW,MAAM;GACjB,GAAG;GACN;EACD,MAAM,oBAAoB;GACtB,MAAM;GACN,MAAM,EACF,IAAI,MAAM,WACb;GACJ;AAED,MAAI;AACA,OAAI,OAAO,KAAK,OAAO,SAAS,gBAAgB,YAAY;AACxD,UAAM,KAAK,4BACP;KACI,WAAW,MAAM;KACjB,OAAO;KACP,WAAW,KAAK,oBAAoB;KACvC,EACD,OAAO,WAAW;AACd,WAAM,KAAK,oBAA0B,WAAW,eAAe;MAC3D,kBAAkB;MAClB,YAAY;MACZ;MACH,CAAC;OAEN,MAAM,OACT;AAED;;WAEC,OAAO;AACZ,QAAK,wBAAwB,OAAO;IAChC,WAAW,MAAM;IACjB,OAAO;IACP,WAAW,KAAK,oBAAoB;IACvC,CAAC;AACF,SAAM;;AAGV,QAAM,IAAI,MAAM,6DAA6D;;CAGjF,MAAc,oBACV,QAC8C;AAC9C,SAAO,KAAK,oBAA2D,WAAW,UAAU,EACxF,QACH,CAAC;;CAGN,MAAc,cACV,KACA,QACU;EACV,MAAM,YAAY,uBAAuB,KAAK,OAAO;AAErD,MAAI,OAAO,WAAW,QAAQ,WAC1B,OAAM,IAAI,MAAM,yEAAyE,IAAI,GAAG;AASpG,SAAO,cANU,MAAM,UAAU,IAAI;GACjC,GAAG;GACH,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;GAC5B;GACH,CAAC,CAE4B;;CAGlC,MAAc,4BACV,OAMA,WACA,QACU;EACV,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,gBAAgB,SAChB,YAAY,IAAI,CAAC,QAAQ,WAAW,OAAO,CAAC,GAC5C,WAAW;EACjB,IAAI,gBAAsD;EAC1D,IAAI,4BAA4B,KAAA;EAEhC,MAAM,eAAe,SACf,IAAI,SAAgB,GAAG,WAAW;GAChC,MAAM,gBAAgB;AAClB,WAAO,qBAAqB,OAAO,OAAO,CAAC;;AAG/C,OAAI,OAAO,SAAS;AAChB,aAAS;AACT;;AAGJ,UAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;AACzD,+BAA4B;AACxB,WAAO,oBAAoB,SAAS,QAAQ;;IAElD,GACA;EACN,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;AACrD,mBAAgB,iBAAiB;AAC7B,WAAO,iCAAiC;KACpC,WAAW,MAAM;KACjB,OAAO,MAAM;KACb,WAAW,MAAM;KACjB,WAAW,MAAM,aAAa,KAAA;KAC9B,WAAW,KAAK,KAAK,GAAG;KAC3B,CAAC,CAAC;AACH,eAAW,OAAO;MACnB,MAAM,UAAU;IACrB;AAEF,MAAI;AACA,UAAO,MAAM,QAAQ,KAAK;IACtB,UAAU,cAAc;IACxB;IACA,GAAI,eAAe,CAAC,aAAa,GAAG,EAAE;IACzC,CAAC;YACI;AACN,OAAI,kBAAkB,KAClB,cAAa,cAAc;AAG/B,wBAAqB;;;CAI7B,wBACI,OACA,OAMF;AACE,MAAI,iBAAiB,4BAA4B;AAC7C,QAAK,iBAAiB,QAAQ;IAC1B,cAAc,0BAA0B,MAAM,KAAK,MAAM;IACzD,WAAW,MAAM,KAAK;IACtB,WAAW,MAAM,KAAK;IACtB,WAAW,MAAM,KAAK;IACtB,OAAO,MAAM,KAAK;IAClB,WAAW,MAAM,KAAK;IACzB,EAAE,oCAAoC;AACvC;;AAGJ,OAAK,iBAAiB,QAAQ;GAC1B,cAAc,0BAA0B,MAAM,MAAM;GACpD;GACA,WAAW,MAAM,aAAa,KAAA;GAC9B,WAAW,MAAM;GACjB,OAAO,MAAM;GACb,WAAW,MAAM;GACpB,EAAE,iCAAiC;;CAGxC,iBACI,OACA,OACA,SACF;EACE,MAAM,MAAM,KAAK,OAAO,KAAK;AAE7B,MAAI,OAAO,QAAQ,WACf;EAGJ,MAAM,UAAU;GACZ,SAAS;GACT;GACA;GACA;GACH;AAED,GAAM,IAAI,UAAU,IACb,IAA8F,KAC7F,KAAK,OAAO,KACZ,SACA,YACH,GACE,IAA+D,KAAK,KAAK,OAAO,KAAK;GACpF,MAAM;GACN,GAAG;GACN,CAAC,EACJ,YAAY,KAAA,EAAU;;;AAIhC,SAAgB,kCACZ,QACA,UAAwB,OACxB,sBAA4D,EAAE,EAC5C;AAClB,QAAO,IAAI,eAAe,KAAA,GAAW,QAAQ,SAAS,oBAAoB;;AAG9E,SAAS,sBACL,QACA,WACA,uCAAqD,IAAI,KAAK,EACrC;CACzB,MAAM,sBAAsB,OAAO,YAAY,EAAE;CACjD,MAAM,gBAAgB,IAAI,IAAI,UAAU,KAAK,aAAa,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;CACnF,MAAM,yBAAS,IAAI,KAAsC;AAEzD,MAAK,MAAM,CAAC,YAAY,mBAAmB,OAAO,QAAQ,oBAAoB,EAAE;EAC5E,MAAM,mBAAmB,eAAe,UAAU,EAAE;AAEpD,OAAK,MAAM,CAAC,oBAAoB,gBAAgB,OAAO,QAAQ,iBAAiB,EAAE;GAC9E,MAAM,QAAQ,qBACV,YACA,gBACA,oBACA,aACA,cAAc,IAAI,WAAW,EAC7B,qBAAqB,IAAI,WAAW,IAAI,KAC3C;AAED,OAAI,MACA,QAAO,IAAI,MAAM,aAAa,MAAM;;;AAKhD,MAAK,MAAM,YAAY,UACnB,MAAK,MAAM,SAAS,2BAA2B,UAAU,qBAAqB,IAAI,SAAS,GAAG,IAAI,KAAK,CACnG,KAAI,CAAC,OAAO,IAAI,MAAM,YAAY,CAC9B,QAAO,IAAI,MAAM,aAAa,MAAM;AAKhD,QAAO,CAAC,GAAG,OAAO,QAAQ,CAAC;;AAG/B,SAAS,qBACL,YACA,gBACA,oBACA,aACA,iBACA,mBAC8B;CAC9B,MAAM,UAAU,YAAY,MAAM;CAClC,MAAM,eAAe,iBAAiB,OAAO;AAE7C,KAAI,CAAC,YAAY,aAAa,aAAa,CACvC,QAAO;AAGX,KAAI,CAAC,iBAAiB,SAAS,kBAAkB,CAC7C,QAAO;AAGX,QAAO;EACH,IAAI;EACJ,YAAY;EACZ,cAAc,2BAA2B,YAAY,gBAAgB,gBAAgB;EACrF,MAAM,YAAY,QAAQ,cAAc,QAAQ;EAChD,aAAa,GAAG,WAAW,GAAG;EAC9B,WAAW,YAAY,aAAa,cAAc,aAAa,aAAa;EAC5E,UAAU,kBAAkB,YAAY,YAAY,cAAc,SAAS;EAC9E;;AAGL,SAAS,2BACL,UACA,mBACyB;AACzB,QAAO,OAAO,OAAO,SAAS,OAAO,CAChC,QAAQ,UAAU,mBAAmB,MAAM,IAAI,iBAAiB,MAAM,IAAI,kBAAkB,CAAC,CAC7F,KAAK,WAAW;EACb,IAAI,MAAM;EACV,YAAY,SAAS;EACrB,cAAc,SAAS;EACvB,MAAM,MAAM;EACZ,aAAa,GAAG,SAAS,GAAG,GAAG,MAAM;EACrC,WAAW,MAAM,aAAa;EAC9B,UAAU,kBAAkB,MAAM,SAAS;EAC9C,EAAE;;AAGX,SAAS,YAAY,aAAkC,cAAkD;AACrG,KAAI,YAAY,WACZ,QAAO,YAAY,WAAW,MAAM,SAAS,OAAO,IAAI,YAAY,WAAW,OAAO,SAAS,OAAO;AAG1G,KAAI,aACA,QAAO,aAAa,aAAa,MAAM,QAAQ,aAAa,aAAa,OAAO;AAGpF,QAAO;;AAGX,SAAS,mBAAmB,cAAsC;AAC9D,QAAO,aAAa,aAAa,MAAM,QAAQ,aAAa,aAAa,OAAO;;AAGpF,SAAS,iBAAiB,SAAiB,mBAAgD;AACvF,QAAO,sBAAsB,QAAQ,kBAAkB,IAAI,QAAQ;;AAGvE,SAAS,2BACL,YACA,gBACA,iBACM;AACN,KAAI,eAAe,KACf,QAAO,eAAe;CAG1B,MAAM,oBAAoB,yBAAyB,eAAe;AAElE,KAAI,mBAAmB;EACnB,MAAM,OAAO,iBAAiB,kBAAkB;EAChD,MAAM,QAAQ,iBAAiB,QAAQ;AAEvC,SAAO,OAAO,GAAG,MAAM,IAAI,KAAK,KAAK;;AAGzC,QAAO,iBAAiB,QAAQ;;AAGpC,SAAS,yBAAyB,gBAAuD;CACrF,MAAM,UAAU,eAAe;AAE/B,KAAI,CAAC,WAAW,OAAO,YAAY,SAC/B,QAAO;CAGX,MAAM,UAAU,aAAa,UAAU,QAAQ,UAAU;AAEzD,QAAO,OAAO,YAAY,YAAY,QAAQ,MAAM,CAAC,SAAS,IACxD,QAAQ,MAAM,GACd;;AAGV,SAAS,iBAAiB,OAA8B;AACpD,KAAI;AACA,SAAO,IAAI,IAAI,MAAM,CAAC,QAAQ;SAC1B;AACJ,SAAO;;;AAIf,SAAS,kBACL,UACuC;AACvC,KAAI,CAAC,SACD,QAAO,EAAE;AAGb,QAAO,OAAO,YACV,OAAO,QAAQ,SAAS,CACnB,QAAQ,GAAG,YAAY,CAAC,QAAQ,SAAS,CACzC,KAAK,CAAC,SAAS,YAAY;AAKxB,SAAO,CAAC,SAJW,OAAO,YACtB,OAAO,QAAQ,OAAO,CAAC,QAAQ,CAAC,SAAS,QAAQ,WAAW,CAC/D,CAE2B;GAC9B,CACT;;AAGL,SAAS,qBAAqB,OAA0C;AACpE,KAAI,CAAC,MAAM,QAAQ,MAAM,CACrB,QAAO;AAGX,QAAO,MACF,QAAQ,SAAgE,KAAK,SAAS,OAAO,CAC7F,KAAK,SAAS,KAAK,KAAK,CACxB,KAAK,GAAG,CACR,MAAM;;AAGf,SAAS,yBACL,MACA,SAKmB;CACnB,MAAM,gBAAgB,mBAAmB,KAAK,KAAK;CACnD,MAAM,gBAAgB,MAAM,QAAQ,KAAK,MAAM,GAAG,KAAK,QAAQ,EAAE;CACjE,MAAM,SAAS,qBAAqB,cAAc,IAAI;CACtD,MAAM,eAAe,SACf,yBAAyB,OAAO,IAAI,SACpC,QAAQ;AAEd,QAAO;EACH,gBAAgB,eAAe,SAAS;EACxC;EACA;EACA,MAAM;EACN,SAAS,qBAAqB,eAAe,QAAQ,WAAW,QAAQ,WAAW;EACnF,OAAO;EACP,YAAY;EACf;;AAGL,SAAS,wBACL,MACO;CACP,MAAM,gBAAgB,mBAAmB,KAAK,KAAK;CAEnD,MAAM,UAAU,qBADM,MAAM,QAAQ,KAAK,MAAM,GAAG,KAAK,QAAQ,EAAE,CACd,CAAC,SAAS;CAC7D,MAAM,oBAAoB,CAAC,CAAC,eAAe;CAC3C,MAAM,cAAc,4BAA4B,cAAc;AAE9D,QAAO,CAAC,WAAW,CAAC,qBAAqB,CAAC;;AAG9C,SAAS,sCACL,MACO;AACP,QAAO,CAAC,wBAAwB,KAAK,IAC9B,CAAC,+BAA+B,KAAK;;AAGhD,SAAS,uBACL,MACO;AACP,QAAO,CAAC,wBAAwB,KAAK,IAC9B,CAAC,+BAA+B,KAAK;;AAGhD,SAAS,wBAAwB,UAA6E;AAC1G,QAAO;EACH,MAAM,gBAAc,UAAU,KAAK,GAAG,SAAS,OAAO;EACtD,OAAO,qBAAqB,UAAU,MAAM;EAC/C;;AAGL,SAAS,yBACL,WAC+B;AAC/B,KAAI,CAAC,MAAM,QAAQ,UAAU,CACzB,QAAO;AAGX,QAAO,UAAU,KAAK,aAAa,wBAAwB,SAAS,CAAC;;AAGzE,SAAS,qBAAqB,OAA0C;AACpE,QAAO,MAAM,QAAQ,MAAM,GAAG,QAAQ,EAAE;;AAG5C,SAAS,mBAAmB,SAAmD;AAC3E,KAAI,CAAC,WAAW,OAAO,YAAY,SAC/B,QAAO;AAGX,KAAI,UAAU,WAAW,QAAQ,SAAS,YACtC,QAAO;CAGX,MAAM,aAAuC,EAAE;AAE/C,KAAI,WAAW,WAAW,OAAO,QAAQ,UAAU,YAAY,QAAQ,MAAM,MAAM,CAAC,SAAS,EACzF,YAAW,QAAQ,QAAQ;AAG/B,KAAI,UAAU,WAAW,OAAO,QAAQ,SAAS,YAAY,OAAO,SAAS,QAAQ,KAAK,CACtF,YAAW,OAAO,QAAQ;CAG9B,MAAM,QAAQ,wBAAwB,WAAW,UAAU,QAAQ,QAAQ,KAAA,EAAU;AAErF,KAAI,MACA,YAAW,QAAQ;AAGvB,KAAI,YAAY,WAAW,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,MAAM,CAAC,SAAS,EAC5F,YAAW,SAAS,QAAQ;AAGhC,KAAI,QAAQ,WAAW,OAAO,QAAQ,OAAO,YAAY,QAAQ,GAAG,MAAM,CAAC,SAAS,EAChF,YAAW,KAAK,QAAQ;AAG5B,KAAI,UAAU,WAAW,OAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK,MAAM,CAAC,SAAS,EACtF,YAAW,OAAO,QAAQ;AAG9B,KAAI,aAAa,WAAW,OAAO,QAAQ,YAAY,YAAY,QAAQ,QAAQ,MAAM,CAAC,SAAS,EAC/F,YAAW,UAAU,QAAQ;AAGjC,KAAI,cAAc,WAAW,OAAO,QAAQ,aAAa,YAAY,QAAQ,SAAS,MAAM,CAAC,SAAS,EAClG,YAAW,WAAW,QAAQ;AAGlC,KAAI,UAAU,WAAW,gBAAc,QAAQ,KAAK,CAChD,YAAW,OAAO;EACd,GAAI,OAAO,QAAQ,KAAK,QAAQ,YAAY,QAAQ,KAAK,IAAI,MAAM,CAAC,SAAS,IACvE,EAAE,KAAK,QAAQ,KAAK,KAAK,GACzB,EAAE;EACR,GAAI,OAAO,QAAQ,KAAK,SAAS,YAAY,QAAQ,KAAK,KAAK,MAAM,CAAC,SAAS,IACzE,EAAE,MAAM,QAAQ,KAAK,MAAM,GAC3B,EAAE;EACX;AAGL,KAAI,gBAAgB,WAAW,OAAO,QAAQ,eAAe,YAAY,QAAQ,WAAW,MAAM,CAAC,SAAS,EACxG,YAAW,aAAa,QAAQ;AAGpC,KAAI,UAAU,WAAW,QAAQ,SAAS,YACtC,YAAW,OAAO;AAGtB,KAAI,eAAe,WAAW,OAAO,QAAQ,cAAc,YAAY,QAAQ,UAAU,MAAM,CAAC,SAAS,EACrG,YAAW,YAAY,QAAQ;AAGnC,KAAI,aAAa,WAAW,OAAO,QAAQ,YAAY,UACnD,YAAW,UAAU,QAAQ;AAGjC,KAAI,UAAU,WAAW,gBAAc,QAAQ,KAAK,CAChD,YAAW,OAAO;EACd,GAAI,OAAO,QAAQ,KAAK,YAAY,YAAY,OAAO,SAAS,QAAQ,KAAK,QAAQ,GAC/E,EAAE,SAAS,QAAQ,KAAK,SAAS,GACjC,EAAE;EACR,GAAI,OAAO,QAAQ,KAAK,cAAc,YAAY,OAAO,SAAS,QAAQ,KAAK,UAAU,GACnF,EAAE,WAAW,QAAQ,KAAK,WAAW,GACrC,EAAE;EACX;AAGL,KAAI,YAAY,WAAW,gBAAc,QAAQ,OAAO,CACpD,YAAW,SAAS;EAChB,GAAI,OAAO,QAAQ,OAAO,UAAU,YAAY,OAAO,SAAS,QAAQ,OAAO,MAAM,GAC/E,EAAE,OAAO,QAAQ,OAAO,OAAO,GAC/B,EAAE;EACR,GAAI,OAAO,QAAQ,OAAO,WAAW,YAAY,OAAO,SAAS,QAAQ,OAAO,OAAO,GACjF,EAAE,QAAQ,QAAQ,OAAO,QAAQ,GACjC,EAAE;EACR,GAAI,OAAO,QAAQ,OAAO,cAAc,YAAY,OAAO,SAAS,QAAQ,OAAO,UAAU,GACvF,EAAE,WAAW,QAAQ,OAAO,WAAW,GACvC,EAAE;EACR,GAAI,OAAO,QAAQ,OAAO,UAAU,YAAY,OAAO,SAAS,QAAQ,OAAO,MAAM,GAC/E,EAAE,OAAO,QAAQ,OAAO,OAAO,GAC/B,EAAE;EACR,GAAI,gBAAc,QAAQ,OAAO,MAAM,GACjC,EACE,OAAO;GACH,GAAI,OAAO,QAAQ,OAAO,MAAM,SAAS,YAAY,OAAO,SAAS,QAAQ,OAAO,MAAM,KAAK,GACzF,EAAE,MAAM,QAAQ,OAAO,MAAM,MAAM,GACnC,EAAE;GACR,GAAI,OAAO,QAAQ,OAAO,MAAM,UAAU,YAAY,OAAO,SAAS,QAAQ,OAAO,MAAM,MAAM,GAC3F,EAAE,OAAO,QAAQ,OAAO,MAAM,OAAO,GACrC,EAAE;GACX,EACJ,GACC,EAAE;EACX;AAGL,KAAI,aAAa,WAAW,OAAO,QAAQ,YAAY,YAAY,QAAQ,QAAQ,MAAM,CAAC,SAAS,EAC/F,YAAW,UAAU,QAAQ;AAGjC,QAAO;;AAGX,SAAS,iBAAiB,SAAiC;AACvD,KAAI,CAAC,gBAAc,QAAQ,CACvB,QAAO;AAGX,QAAO,OAAO,QAAQ,OAAO,YAAY,QAAQ,GAAG,MAAM,CAAC,SAAS,IAC9D,QAAQ,KACR;;AAGV,SAAS,MAAM,IAAY,QAAqC;AAC5D,QAAO,IAAI,SAAS,SAAS,WAAW;EACpC,MAAM,SAAS,iBAAiB;AAC5B,WAAQ,oBAAoB,SAAS,QAAQ;AAC7C,YAAS;KACV,GAAG;EACN,MAAM,gBAAgB;AAClB,gBAAa,OAAO;AACpB,WAAQ,oBAAoB,SAAS,QAAQ;AAC7C,UAAO,qBAAqB,QAAQ,OAAO,CAAC;;AAGhD,MAAI,QAAQ,SAAS;AACjB,YAAS;AACT;;AAGJ,UAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;GAC5D;;AAGN,SAAS,yBACL,UACA,MACO;AACP,QAAO,mCAAmC,SAAS,KAC3C,mCAAmC,KAAK;;AAGpD,SAAS,iCACL,OAI0B;AAC1B,QAAO,IAAI,2BAA2B;EAClC,GAAG;EACH,WAAW,MAAM,aAAa,MAAM;EACpC,SAAS,MAAM,WAAW;EAC7B,CAAC;;AAGN,SAAS,0BAA0B,OAAiF;AAChH,SAAQ,OAAR;EACI,KAAK;EACL,KAAK;EACL,KAAK,aACD,QAAO;EACX,KAAK,eACD,QAAO;EACX,KAAK,cACD,QAAO;EAEX,QACI,QAAO;;;AAInB,SAAS,4BAA4B,SAAyB;AAC1D,QAAO,sCAAsC,YAAY;;AAG7D,SAAS,qBACL,MACA,WACA,YACoB;CACpB,MAAM,YAAY,OAAO,MAAM,MAAM,YAAY,YAAY,OAAO,SAAS,KAAK,KAAK,QAAQ,GACzF,KAAK,KAAK,UACV;CACN,MAAM,cAAc,OAAO,MAAM,MAAM,cAAc,YAAY,OAAO,SAAS,KAAK,KAAK,UAAU,GAC/F,KAAK,KAAK,YACV;CACN,MAAM,oBAAoB,cAAc,QAAQ,gBAAgB,OAC1D,cAAc,YACd;AAKN,QAAO;EACH,YALe,sBAAsB,QAAQ,qBAAqB,IAChE,oBACA,KAAK,IAAI,GAAG,aAAa,UAAU;EAIrC,QAAQ,oBAAoB,KAAK;EACpC;;AAGL,SAAS,oBAAoB,MAA8E;AACvG,KAAI,CAAC,MAAM,OACP,QAAO;EACH,OAAO;EACP,OAAO;EACP,QAAQ;EACR,WAAW;EACX,WAAW;EACX,YAAY;EACf;CAGL,MAAM,QAAQ,mBAAmB,KAAK,OAAO,MAAM;CACnD,MAAM,SAAS,mBAAmB,KAAK,OAAO,OAAO;CACrD,MAAM,YAAY,mBAAmB,KAAK,OAAO,UAAU;CAC3D,MAAM,YAAY,mBAAmB,KAAK,OAAO,OAAO,KAAK;CAC7D,MAAM,aAAa,mBAAmB,KAAK,OAAO,OAAO,MAAM;CAC/D,MAAM,QAAQ,mBAAmB,KAAK,OAAO,MAAM;CACnD,MAAM,gBAAgB,gBAAgB,OAAO,QAAQ,WAAW,WAAW;AAE3E,QAAO;EACH,OAAO,SAAS;EAChB;EACA;EACA;EACA;EACA;EACH;;AAGL,SAAS,mBAAmB,OAA+B;AACvD,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,GAAG,QAAQ;;AAGzE,SAAS,gBAAgB,GAAG,QAA6C;AACrE,KAAI,OAAO,OAAO,UAAU,UAAU,KAAK,CACvC,QAAO;CAGX,MAAM,QAAQ,OAAO,QAAgB,KAAK,UAAU,OAAO,SAAS,IAAI,EAAE;AAE1E,QAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;;AAG5C,SAAS,cAAiB,UAAsC;AAC5D,KAAI,YAAY,OAAO,aAAa,YAAY,UAAU,SACtD,QAAO,SAAS;AAGpB,QAAO;;AAGX,SAAS,2BAA2B,YAAuD;AACvF,KAAI,CAAC,gBAAc,WAAW,CAC1B,QAAO;CAGX,MAAM,KAAK,OAAO,WAAW,OAAO,YAAY,WAAW,GAAG,MAAM,CAAC,SAAS,IACxE,WAAW,KACX;CACN,MAAM,YAAY,OAAO,WAAW,cAAc,YAAY,WAAW,UAAU,MAAM,CAAC,SAAS,IAC7F,WAAW,YACX;CACN,MAAM,iBAAiB,OAAO,WAAW,eAAe,YAAY,WAAW,WAAW,MAAM,CAAC,SAAS,IACpG,WAAW,aACX,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,MAAM,CAAC,SAAS,IACnE,WAAW,OACX;AAEV,KAAI,CAAC,MAAM,CAAC,aAAa,CAAC,eACtB,QAAO;AAGX,QAAO;EACH,QAAQ,MAAM,QAAQ,WAAW,OAAO,GAClC,WAAW,OAAO,QAAQ,UAA2B,OAAO,UAAU,SAAS,GAC/E,EAAE;EACR;EACA,UAAU,gBAAc,WAAW,SAAS,GACtC,WAAW,WACX,EAAE;EACR,UAAU,8BAA4B,WAAW;EACjD,YAAY;EACZ;EACH;;AAGL,SAAS,+BAA+B,OAA0B;AAC9D,KAAI,CAAC,MAAM,QAAQ,MAAM,CACrB,QAAO,EAAE;CAGb,MAAM,oBAA8B,EAAE;CACtC,MAAM,8BAAc,IAAI,KAAa;AAErC,MAAK,MAAM,QAAQ,OAAO;AACtB,MAAI,OAAO,SAAS,SAChB;EAGJ,MAAM,iBAAiB,KAAK,MAAM;AAElC,MAAI,eAAe,WAAW,KAAK,YAAY,IAAI,eAAe,CAC9D;AAGJ,cAAY,IAAI,eAAe;AAC/B,oBAAkB,KAAK,eAAe;;AAG1C,QAAO;;AAGX,SAAS,8BAA4B,YAA+C;AAChF,KAAI,MAAM,QAAQ,WAAW,SAAS,CAClC,QAAO,WAAW,SAAS,QAAQ,UAA2B,OAAO,UAAU,SAAS;AAG5F,KAAI,OAAO,WAAW,YAAY,YAAY,WAAW,QAAQ,MAAM,CAAC,SAAS,EAC7E,QAAO,CAAC,WAAW,QAAQ;AAG/B,KAAI,MAAM,QAAQ,WAAW,QAAQ,CACjC,QAAO,WAAW,QAAQ,QAAQ,UAA2B,OAAO,UAAU,SAAS;AAG3F,QAAO,EAAE;;AAGb,SAAS,uBAAuB,QAA2D;CACvF,MAAM,mBAAmB;AAEzB,QAAO,iBAAiB,UAAU,iBAAiB,WAAW;;AAGlE,SAAS,8BACL,OACA,OACA,QACc;AACd,QAAO,iBAAiB,SACjB,MAAM,YAAY,oDAAoD,MAAM,GAAG,OAAO;;AAGjG,SAAS,2BACL,OAC2B;AAC3B,QAAO;EACH,sBAAsB,MAAM,wBAAwB,uCAAuC;EAC3F,6BAA6B,MAAM,+BAA+B,uCAAuC;EACzG,eAAe,MAAM,iBAAiB,uCAAuC;EAChF;;AAGL,SAAS,wBAAwB,OAAoD;AACjF,KAAI,CAAC,gBAAc,MAAM,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,MAAM,CAAC,WAAW,EACxF;AAGJ,QAAO;EACH,GAAG;EACH,MAAM,MAAM;EACZ,GAAI,gBAAc,MAAM,KAAK,GACvB,EAAE,MAAM,MAAM,MAAM,GACpB,EAAE;EACX;;AAGL,SAAS,4BACL,SACO;AACP,QAAO,CAAC,CAAC,SAAS,SACX,OAAO,SAAS,MAAM,cAAc,YACnC,OAAO,SAAS,WAAW,YAAY,QAAQ,OAAO,MAAM,CAAC,SAAS;;AAGlF,SAAS,+BACL,MACO;CACP,MAAM,gBAAgB,mBAAmB,KAAK,KAAK;CAEnD,MAAM,UAAU,qBADM,MAAM,QAAQ,KAAK,MAAM,GAAG,KAAK,QAAQ,EAAE,CACd,CAAC,SAAS;AAE7D,QAAO,4BAA4B,cAAc,IAC1C,CAAC,eAAe,SAChB,CAAC;;AAUZ,SAAS,8BACL,YACA,SAC6B;CAC7B,MAAM,sBAAsB,WACvB,QAAQ,cAAmD,CAAC,CAAC,UAAU,CACvE,QAAQ,cAAc,mBAAmB,UAAU,KAAK,KAAK,KAAK;AAEvE,KAAI,oBAAoB,WAAW,EAC/B,QAAO;AAGX,QAAO,CAAC,GAAG,oBAAoB,CAAC,MAAM,MAAM,UACxC,gCAAgC,MAAM,OAAO,QAAQ,CACxD,CAAC,MAAM;;AAGZ,SAAS,gCACL,MACA,OACA,SACM;CACN,MAAM,WAAW,+BAA+B,MAAM,QAAQ;CAC9D,MAAM,YAAY,+BAA+B,OAAO,QAAQ;AAEhE,QAAO,OAAO,UAAU,UAAU,GAAG,OAAO,SAAS,UAAU,IACxD,OAAO,UAAU,aAAa,GAAG,OAAO,SAAS,aAAa,IAC9D,OAAO,UAAU,uBAAuB,GAAG,OAAO,SAAS,uBAAuB,IAClF,OAAO,UAAU,SAAS,GAAG,OAAO,SAAS,SAAS,IACtD,UAAU,YAAY,SAAS;;AAG1C,SAAS,+BACL,SACA,SAOF;CACE,MAAM,YAAY,mBAAmB,QAAQ,KAAK;CAClD,MAAM,KAAK,WAAW,MAAM;CAC5B,MAAM,YAAY,OAAO,WAAW,MAAM,YAAY,YAAY,OAAO,SAAS,UAAU,KAAK,QAAQ,GACnG,UAAU,KAAK,UACf;AAEN,QAAO;EACH;EACA,WAAW,CAAC,CAAC,MAAM,OAAO,QAAQ;EAClC,wBAAwB,qCACpB,IACA,WACA,QAAQ,iBACR,QAAQ,iBACX;EACD,UAAU,uBAAuB,QAAQ;EACzC,cAAc,CAAC,CAAC,WAAW,YAAY,UAAU,aAAa,QAAQ;EACzE;;AAGL,SAAS,gCACL,WACA,gBACa;AACb,KAAI,CAAC,eACD,QAAO;CAGX,MAAM,mBAAmB,mBAAmB,mBAAmB,eAAe,KAAK,EAAE,MAAM,QAAQ;AAEnG,KAAI,qBAAqB,KACrB,QAAO;AAGX,QAAO,8BAA8B,WAAW,iBAAiB,GAC3D,YACA;;AAGV,SAAS,mCACL,UACM;AACN,KAAI,CAAC,SACD,QAAO;CAGX,MAAM,YAAY,mBAAmB,SAAS,KAAK;CACnD,MAAM,gBAAgB,MAAM,QAAQ,SAAS,MAAM,GAAG,SAAS,QAAQ,EAAE;AAEzE,QAAO,KAAK,UAAU;EAClB,gBAAgB,WAAW,OAAO,QAAQ;EAC1C,QAAQ,qBAAqB,cAAc,IAAI;EAC/C,aAAa,WAAW,MAAM,aAAa;EAC3C,QAAQ,WAAW,UAAU;EAC7B,IAAI,WAAW,MAAM;EACrB,WAAW,cAAc;EACzB,MAAM,qBAAqB,cAAc;EAC5C,CAAC;;AAGN,SAAS,qCACL,WACA,WACA,iBACA,kBACO;AACP,KAAI,CAAC,aAAa,gBAAgB,IAAI,UAAU,CAC5C,QAAO;AAGX,KAAI,qBAAqB,KACrB,QAAO;AAGX,QAAO,aAAa;;AAGxB,SAAS,kCACL,UACA,SACO;CACP,MAAM,OAAO,+BAA+B,UAAU,QAAQ;AAE9D,QAAO,KAAK,aAAa,KAAK,gBAAgB,KAAK;;AAGvD,SAAS,8BAA8B,MAAc,OAAwB;CACzE,MAAM,mBAAmB;AAEzB,QAAO,QAAQ,oBAAoB,SAAS;;AAGhD,SAAS,qBAAqB,OAAyB;AACnD,QAAO,iBAAiB,+BAChB,iBAAiB,SAAS,MAAM,SAAS,gBAC1C,kBAAkB,MAAM;;AAGnC,SAAS,kBAAkB,OAA0D;AACjF,QAAO,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,UAAU,SACT,MAA6B,SAAS;;AAGlD,SAAS,qBAAqB,QAA0B;AACpD,KAAI,kBAAkB,SAAS,kBAAkB,OAAO,CACpD,QAAO;AAGX,QAAO,2BAA2B;;AAGtC,SAAS,eAAe,QAA4B;AAChD,KAAI,CAAC,QAAQ,QACT;AAGJ,OAAM,qBAAqB,OAAO,OAAO;;AAG7C,SAAS,gBAAc,OAA8C;AACjE,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;AAG/E,eAAe,4BACX,QACA,SACqC;CACrC,MAAM,sBAAsB,OAAO,QAAQ,OAAO,YAAY,EAAE,CAAC;CACjE,MAAM,sBAAsB,MAAM,QAAQ,IACtC,oBAAoB,IAAI,OAAO,CAAC,YAAY,oBAAoB,CAC5D,YACA,MAAM,+BAA+B,gBAAgB,QAAQ,CAChE,CAAU,CACd;AAED,QAAO,IAAI,IAAI,oBAAoB;;AAGvC,eAAe,+BACX,gBACA,SAC2B;CAC3B,MAAM,UAAU,yBAAyB,eAAe;CACxD,MAAM,SAAS,wBAAwB,eAAe;AAEtD,KAAI,CAAC,WAAW,CAAC,OACb,QAAO;AAGX,KAAI;EACA,MAAM,WAAW,MAAM,QACnB,uBAAuB,QAAQ,EAC/B;GACI,SAAS;IACL,eAAe,UAAU;IACzB,QAAQ;IACX;GACD,QAAQ,YAAY,QAAQ,IAAO;GACtC,CACJ;AAED,MAAI,CAAC,SAAS,GACV,QAAO;EAIX,MAAM,WAAW,2BADD,MAAM,SAAS,MAAM,CACe;AAEpD,SAAO,WAAW,IAAI,IAAI,SAAS,GAAG;SAClC;AACJ,SAAO;;;AAIf,SAAS,wBAAwB,gBAAuD;CACpF,MAAM,UAAU,eAAe;AAE/B,KAAI,CAAC,WAAW,OAAO,YAAY,SAC/B,QAAO;CAGX,MAAM,SAAS,YAAY,UAAU,QAAQ,SAAS;AAEtD,QAAO,OAAO,WAAW,YAAY,OAAO,MAAM,CAAC,SAAS,IACtD,OAAO,MAAM,GACb;;AAGV,SAAS,uBAAuB,SAAyB;CACrD,MAAM,oBAAoB,QAAQ,SAAS,IAAI,GAAG,UAAU,GAAG,QAAQ;AAEvE,QAAO,IAAI,IAAI,UAAU,kBAAkB,CAAC,UAAU;;AAG1D,SAAS,2BAA2B,SAAmC;AACnE,KAAI,MAAM,QAAQ,QAAQ,CACtB,QAAO,QACF,IAAI,eAAe,CACnB,QAAQ,OAAqB,CAAC,CAAC,GAAG;AAG3C,KAAI,WAAW,OAAO,YAAY,YAAY,UAAU,WAAW,MAAM,QAAQ,QAAQ,KAAK,CAC1F,QAAO,QAAQ,KACV,IAAI,eAAe,CACnB,QAAQ,OAAqB,CAAC,CAAC,GAAG;AAG3C,QAAO;;AAGX,SAAS,eAAe,OAA+B;AACnD,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACnD,QAAO,MAAM,MAAM;AAGvB,KAAI,SAAS,OAAO,UAAU,YAAY,QAAQ,OAAO;EACrD,MAAM,KAAM,MAA2B;AAEvC,SAAO,OAAO,OAAO,YAAY,GAAG,MAAM,CAAC,SAAS,IAC9C,GAAG,MAAM,GACT;;AAGV,QAAO;;;;ACjnEX,SAAgB,iCAAoD;AAChE,QAAO;EACH,SAAS;EACT,UAAU,EAAE;EACZ,gBAAgB,EAAE;EAClB,oBAAoB,EAAE;EACzB;;;;ACRL,IAAa,iBAAb,MAAoC;CAChC;CACA;CACA,eAA+C;CAC/C,aAAqB,QAAQ,SAAS;CAEtC,YAAY,SAAwC;AAChD,OAAK,qBAAqB,QAAQ;AAClC,OAAK,WAAW,QAAQ;;CAG5B,MAAM,OAAwB;AAG1B,SAAO,WAFO,MAAM,KAAK,WAAW,CAEZ;;CAG5B,MAAM,OAAO,SAAmD;EAC5D,MAAM,mBAAmB,KAAK,WAAW,KAAK,YAAY;GAEtD,MAAM,QAAQ,WADA,MAAM,KAAK,WAAW,CACL;AAE/B,WAAQ,MAAM;AACd,SAAM,eAAe,KAAK,UAAU,MAAM;AAC1C,QAAK,eAAe,QAAQ,QAAQ,MAAM;AAE1C,UAAO,WAAW,MAAM;IAC1B;AAEF,OAAK,aAAa,iBAAiB,WAAW,KAAA,SAAiB,KAAA,EAAU;AAEzE,SAAO;;CAGX,MAAc,YAA6B;AACvC,MAAI,CAAC,KAAK,aACN,MAAK,eAAe,cAAc,KAAK,UAAU,KAAK,mBAAmB;AAG7E,SAAO,KAAK;;;AAIpB,eAAe,cACX,UACA,oBACe;AACf,KAAI;EACA,MAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAEhD,SAAO,KAAK,MAAM,QAAQ;UACrB,OAAO;AACZ,MAAI,mBAAmB,MAAM,CACzB,QAAO,oBAAoB;AAG/B,QAAM;;;AAId,eAAe,eAAuB,UAAkB,OAA8B;AAClF,OAAM,MAAM,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;CAEnD,MAAM,oBAAoB,GAAG,SAAS,GAAG,QAAQ,IAAI,GAAG,YAAY,CAAC;AAGrE,OAAM,UAAU,mBAFG,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC,KAEN,OAAO;AACtD,OAAM,OAAO,mBAAmB,SAAS;;AAG7C,SAAS,WAAmB,OAAuB;AAC/C,QAAO,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;;AAG5C,SAAS,mBAAmB,OAAgD;AACxE,QAAO,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS;;;;ACjEvE,IAAa,4BAAb,cAA+C,MAAM;CACjD;CAEA,YAAY,SAAiB;AACzB,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO,EAAE,SAAS;;;AAI/B,IAAa,qBAAb,MAAkE;CAC9D;CACA;CAEA,YAAY,SAAoC,UAAwB,OAAO;AAC3E,OAAK,UAAU,QAAQ,WAAW,yBAAyB,QAAQ,SAAS,QAAQ,SAAS;AAC7F,OAAK,UAAU;;CAGnB,MAAM,aAAa,OAAuE;EACtF,MAAM,WAAW,MAAM,SAAS,MAAM;AAEtC,MAAI,CAAC,SACD,OAAM,IAAI,0BAA0B,qDAAqD;EAG7F,IAAI;AAEJ,MAAI;AACA,cAAW,MAAM,KAAK,QAAQ,IAAI,IAAI,UAAU,KAAK,QAAQ,CAAC;WACzD,OAAO;AACZ,SAAM,IAAI,0BAA0B,oBAAoB,MAAM,IAAI,wCAAwC;;AAG9G,MAAI,CAAC,SAAS,GACV,OAAM,IAAI,0BAA0B,MAAM,4BAA4B,SAAS,CAAC;EAGpF,MAAM,OAAO,IAAI,WAAW,MAAM,SAAS,aAAa,CAAC;AAEzD,MAAI,KAAK,eAAe,EACpB,OAAM,IAAI,0BAA0B,mCAAmC;AAG3E,SAAO;GACH;GACA,UAAU,SAAS,QAAQ,IAAI,eAAe;GACjD;;;AAIT,SAAgB,yBAAyB,SAA6B,UAA0B;AAG5F,QAAO,IAFoB,WAAW,4BAA4B,MAAM,CAAC,QAAQ,SAAS,GAAG,CAEjE,WAAW,SAAS;;AAGpD,eAAe,4BAA4B,UAAqC;CAE5E,MAAM,kBADe,MAAM,qBAAqB,SAAS,GACpB,MAAM;AAE3C,QAAO,iBACD,6CAA6C,SAAS,OAAO,IAAI,mBACjE,6CAA6C,SAAS,OAAO;;AAGvE,eAAe,qBAAqB,UAA4C;AAC5E,KAAI;EACA,MAAM,OAAO,MAAM,SAAS,MAAM;AAElC,SAAO,KAAK,MAAM,CAAC,SAAS,IAAI,OAAO;SACnC;AACJ,SAAO;;;AAIf,SAAS,oBAAoB,OAA+B;AACxD,QAAO,iBAAiB,SAAS,MAAM,QAAQ,MAAM,CAAC,SAAS,IACzD,MAAM,QAAQ,MAAM,GACpB;;;;ACxEV,IAAa,2BAAb,MAA8E;CAC1E,2BAA4B,IAAI,KAAqC;CACrE,+BAAgC,IAAI,KAA0B;CAE9D,QAAQ,QAA+C;AACnD,MAAI,KAAK,SAAS,IAAI,OAAO,CACzB,QAAO;EAGX,MAAM,QAAgC;GAClC;GACA,YAAY,IAAI,iBAAiB;GACjC,WAAW;GACd;AAED,OAAK,SAAS,IAAI,QAAQ,MAAM;AAEhC,SAAO;GACH,QAAQ,MAAM,WAAW;GACzB,gBAAgB,cAAsB;AAClC,SAAK,cAAc,QAAQ,UAAU;;GAEzC,eAAe;AACX,SAAK,QAAQ,OAAO;;GAE3B;;CAGL,MAAM,QAAgB,SAAkB,2BAA2B,EAAW;EAC1E,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO;AAEvC,MAAI,CAAC,MACD,QAAO;AAGX,MAAI,CAAC,MAAM,WAAW,OAAO,QACzB,OAAM,WAAW,MAAM,OAAO;AAGlC,SAAO;;CAGX,MAAM,QAAgB,WAA+B;EACjD,MAAM,QAAQ,KAAK,QAAQ,OAAO;AAElC,MAAI,CAAC,MACD,cAAa,KAAA;AAGjB,QAAM,cAAc,UAAU;AAC9B,eAAa;AACT,SAAM,SAAS;;;CAIvB,MAAM,WAA4B;EAC9B,MAAM,UAAU,KAAK,YAAY,UAAU;AAE3C,MAAI,QAAQ,WAAW,EACnB,QAAO;AAGX,OAAK,MAAM,UAAU,SAAS;GAC1B,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO;AAEvC,OAAI,OAAO,cAAc,UACrB,OAAM,YAAY;;AAI1B,OAAK,aAAa,OAAO,UAAU;AACnC,SAAO;;CAGX,KAAK,WAAmB,OAAyB;EAC7C,MAAM,UAAU,KAAK,YAAY,UAAU;AAE3C,MAAI,QAAQ,WAAW,EACnB,QAAO;AAGX,OAAK,MAAM,UAAU;AAErB,OAAK,MAAM,UAAU,QACjB,MAAK,MAAM,QAAQ,MAAM;AAG7B,SAAO;;CAGX,mBAAmB,QAA+B;AAC9C,SAAO,KAAK,SAAS,IAAI,OAAO,EAAE,aAAa;;CAGnD,iBAAiB,QAAyB;AACtC,SAAO,KAAK,SAAS,IAAI,OAAO;;CAGpC,aAAa,WAA4B;AACrC,SAAO,KAAK,aAAa,IAAI,UAAU;;CAG3C,YAAY,WAA6B;AACrC,SAAO,CAAC,GAAI,KAAK,aAAa,IAAI,UAAU,oBAAI,IAAI,KAAa,CAAE;;CAGvE,cAAsB,QAAgB,WAAyB;EAC3D,MAAM,sBAAsB,UAAU,MAAM;EAC5C,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO;AAEvC,MAAI,CAAC,SAAS,oBAAoB,WAAW,EACzC;AAGJ,MAAI,MAAM,cAAc,oBACpB;AAGJ,MAAI,MAAM,UACN,MAAK,sBAAsB,QAAQ,MAAM,UAAU;AAGvD,QAAM,YAAY;EAElB,MAAM,UAAU,KAAK,aAAa,IAAI,oBAAoB,oBAAI,IAAI,KAAa;AAE/E,UAAQ,IAAI,OAAO;AACnB,OAAK,aAAa,IAAI,qBAAqB,QAAQ;;CAGvD,QAAgB,QAAsB;EAClC,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO;AAEvC,MAAI,CAAC,MACD;AAGJ,MAAI,MAAM,UACN,MAAK,sBAAsB,QAAQ,MAAM,UAAU;AAGvD,OAAK,SAAS,OAAO,OAAO;;CAGhC,sBAA8B,QAAgB,WAAyB;EACnE,MAAM,UAAU,KAAK,aAAa,IAAI,UAAU;AAEhD,MAAI,CAAC,QACD;AAGJ,UAAQ,OAAO,OAAO;AAEtB,MAAI,QAAQ,SAAS,GAAG;AACpB,QAAK,aAAa,OAAO,UAAU;AACnC;;AAGJ,OAAK,aAAa,IAAI,WAAW,QAAQ;;;AAIjD,IAAa,kCAAgE;CACzE,UAAU;AACN,SAAO;;CAEX,QAAQ;AACJ,SAAO;;CAEX,QAAQ;AACJ,eAAa,KAAA;;CAEjB,QAAQ;AACJ,SAAO;;CAEX,OAAO;AACH,SAAO;;CAEX,qBAAqB;AACjB,SAAO;;CAEX,mBAAmB;AACf,SAAO;;CAEX,eAAe;AACX,SAAO;;CAEX,cAAc;AACV,SAAO,EAAE;;CAEhB;;;ACvMD,IAAa,qBAAb,MAAgC;CAC5B,YACI,aACA,gBACA,2BAA0E,iCAC5E;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,2BAAA;;CAGrB,MAAM,QAAQ,OAAuD;EACjE,MAAM,uBAAuB,KAAK,yBAAyB,iBAAiB,MAAM,OAAO;EACzF,MAAM,kBAAkB,KAAK,yBAAyB,mBAAmB,MAAM,OAAO;EACtF,MAAM,UAAU,kBACV,OACA,MAAM,KAAK,YAAY,YAAY,MAAM,OAAO;EACtD,MAAM,YAAY,mBAAmB,SAAS,aAAa;AAE3D,MAAI,CAAC,wBAAwB,CAAC,UAC1B,QAAO;GACH,WAAW;GACX,QAAQ;GACR,eAAe;GAClB;EAGL,MAAM,kBAAkB,YAClB,MAAM,KAAK,eAAe,oBAAoB,GAC9C,EAAE;EACR,MAAM,gBAAgB,YACf,gBAAgB,cAAc,OAC/B;AAEN,MAAI,sBAAsB;AACtB,OAAI,aAAa,iBAAiB,cAAc,SAAS,OACrD,OAAM,KAAK,eAAe,aAAa,UAAU;AAGrD,QAAK,yBAAyB,MAC1B,MAAM,QACN,2BAA2B,CAC9B;AAED,UAAO;IACH;IACA,QAAQ;IACR;IACH;;AAGL,MAAI,CAAC,iBAAiB,cAAc,SAAS,OACzC,QAAO;GACH;GACA,QAAQ;GACR;GACH;AAGL,MAAI,CAAC,UACD,QAAO;GACH,WAAW;GACX,QAAQ;GACR;GACH;EAGL,MAAM,mBAAmB;AAGzB,SAAO;GACH,WAAW;GACX,QAJY,MAAM,KAAK,eAAe,aAAa,iBAAiB,GAIlD,YAAY;GAC9B;GACH;;;;;ACnET,eAAsB,mCAClB,aACA,gBACA,OACiD;CACjD,MAAM,UAAU,MAAM,WAAW,MAAM,YAAY,YAAY,MAAM,OAAO;CAC5E,MAAM,UAAU,MAAM,eAAe,mBAAmB;CACxD,MAAM,QAAQ,sBAAsB,MAAM,MAAM;CAChD,MAAM,UAAU,MAAM,eAAe,0BAA0B,QAAQ,UAAU,SAAS,KAAA,EAAU;CACpG,MAAM,cAAkC;EACpC,QAAQ,MAAM;EACd,WAAW,QAAQ;EACnB,WAAW,QAAQ;EACnB,WAAW,QAAQ;EACnB,WAAW,SAAS,aAAa;EACjC,iBAAiB,SAAS,mBAAmB;EAC7C,SAAS,SAAS,WAAW;EAC7B,cAAc,SAAS,gBAAgB;EACvC,UAAU,SAAS,YAAY;EAC/B,4BAAW,IAAI,MAAM,EAAC,aAAa;EACtC;AAED,OAAM,YAAY,WAAW,YAAY;AAEzC,QAAO;EACH,SAAS;EACT;EACA;EACH;;AAGL,SAAS,sBAAsB,OAAiD;CAC5E,MAAM,aAAa,OAAO,MAAM;AAEhC,QAAO,aAAa,aAAa;;;;AC1CrC,IAAa,uBAAb,MAAkC;CAC9B,YACI,aACA,gBACA,QACF;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,SAAA;;CAGrB,MAAM,QAAQ,OAAgF;EAC1F,MAAM,UAAU,MAAM,KAAK,YAAY,YAAY,MAAM,OAAO;EAChE,MAAM,SAAS,MAAM,mCACjB,KAAK,aACL,KAAK,gBACL;GACI,QAAQ,MAAM;GACd,OAAO,MAAM;GACb;GACH,CACJ;AAED,OAAK,OAAO,KACR;GACI,QAAQ,MAAM;GACd,WAAW,OAAO,QAAQ;GAC1B,WAAW,OAAO,QAAQ;GAC1B,WAAW,OAAO,QAAQ;GAC1B,OAAO,MAAM,OAAO,MAAM,IAAI;GACjC,EACD,kBACH;AAED,SAAO,EACH,SAAS,OAAO,SACnB;;;;;ACvCT,IAAa,mBAAb,MAA8B;CAC1B,YAAY,gBAAqD;AAApC,OAAA,iBAAA;;CAE7B,MAAM,UAAmC;AACrC,SAAO,KAAK,eAAe,WAAW;;;;;ACP9C,IAAa,iBAAb,MAA4B;CACxB,YAAY,gBAAqD;AAApC,OAAA,iBAAA;;CAE7B,MAAM,UAAiC;AACnC,SAAO,KAAK,eAAe,SAAS;;;;;ACyC5C,IAAa,mBAAb,MAA8B;CAC1B,YACI,kBACA,gBACA,gBACA,gBACA,qBACA,aACA,wBACF;AAPmB,OAAA,mBAAA;AACA,OAAA,iBAAA;AACA,OAAA,iBAAA;AACA,OAAA,iBAAA;AACA,OAAA,sBAAA;AACA,OAAA,cAAA;AACA,OAAA,yBAAA;;CAGrB,MAAM,QAAQ,OAAqD;EAC/D,MAAM,CAAC,QAAQ,MAAM,KAAK,KAAK,WAAW,MAAM,QAAQ,WAAW;GAC/D,KAAK,iBAAiB,SAAS;GAC/B,KAAK,eAAe,SAAS;GAC7B,KAAK,eAAe,QAAQ,EAAE,QAAQ,MAAM,QAAQ,CAAC;GACrD,KAAK,eAAe,QAAQ,EAAE,QAAQ,MAAM,QAAQ,CAAC;GACrD,KAAK,uBAAuB,uBAAuB;GACtD,CAAC;EACF,MAAM,aAAa,iBAAiB,KAAK;EACzC,MAAM,eAAe,4BAA4B,QAAQ;EACzD,MAAM,YAAY,MAAM,0BACpB,MAAM,QACN,YACA,KAAK,qBACL,KAAK,YACR;AAED,SAAO;GACH,QAAQ,iBAAiB,OAAO;GAChC,MAAM;GACN,SAAS;GACT;GACA,KAAK,iBAAiB,IAAI;GAC1B,KAAK,iBAAiB,IAAI;GAC7B;;;AAIT,SAAS,iBAAwB,QAAiE;AAC9F,KAAI,OAAO,WAAW,YAClB,QAAO;EACH,MAAM,OAAO;EACb,QAAQ;EACX;AAGL,QAAO;EACH,OAAO,OAAO;EACd,QAAQ;EACX;;AAGL,SAAS,4BACL,QAC4C;AAC5C,KAAI,OAAO,WAAW,WAClB,QAAO;EACH,OAAO,OAAO;EACd,QAAQ;EACX;AAGL,QAAO;EACH,MAAM,EACF,SAAS,gCAAgC,OAAO,MAAM,EACzD;EACD,QAAQ;EACX;;AAGL,eAAe,0BACX,QACA,MACA,qBACA,aACmD;AACnD,KAAI,KAAK,WAAW,QAChB,QAAO;EACH,OAAO,KAAK;EACZ,QAAQ;EACX;CAGL,MAAM,UAAU,MAAM,YAAY,YAAY,OAAO;CACrD,IAAI,iBAAiB,4BAA4B,KAAK,KAAK;CAC3D,IAAI,iBAAiB,SAAS,aAAa;AAE3C,KAAI;EACA,MAAM,WAAW,MAAM,oBAAoB,QAAQ,EAAE,QAAQ,CAAC;AAE9D,mBAAiB,4BAA4B,KAAK,MAAM,SAAS,iBAAiB;AAClF,mBAAiB,SAAS,mBACpB,yBACE,SAAS,SAAS,MAAM,YAAY,QAAQ,OAAO,SAAS,iBAAiB,IAAI,MACjF,SAAS,iBACZ,GACC;SACF;AAIR,QAAO;EACH,MAAM;GACF;GACA;GACH;EACD,QAAQ;EACX;;AAGL,SAAS,yBAAyB,SAAiC,YAA4B;AAC3F,KAAI,CAAC,QACD,QAAO;CAGX,MAAM,QAAQ,QAAQ,MAAM,MAAM,IAAI,QAAQ,QAAQ,QAAQ;AAE9D,QAAO,UAAU,QAAQ,OACnB,QACA,GAAG,MAAM,IAAI,QAAQ,KAAK;;AAGpC,SAAS,4BAA4B,MAAoB,eAAuC;CAC5F,MAAM,aAAa;EACf;EACA,KAAK;EACL,KAAK;EACR;AAED,MAAK,MAAM,aAAa,WACpB,KAAI,sBAAsB,UAAU,CAChC,QAAO;AAIf,QAAO,iBAAiB,KAAK,YAAY,KAAK;;AAGlD,SAAS,sBAAsB,OAAmD;AAC9E,KAAI,OAAO,UAAU,SACjB,QAAO;CAGX,MAAM,aAAa,MAAM,MAAM;AAE/B,QAAO,WAAW,SAAS,KACpB,eAAe,OACf,eAAe,QACf,WAAW,WAAW;;AAGjC,SAAS,gCAAgC,SAA6B;CAClE,MAAM,oBAA8B,EAAE;CACtC,MAAM,8BAAc,IAAI,KAAa;AAErC,MAAK,MAAM,UAAU,SAAS;EAC1B,MAAM,mBAAmB,+BAA+B,OAAO;AAE/D,MAAI,iBAAiB,WAAW,KAAK,YAAY,IAAI,iBAAiB,CAClE;AAGJ,cAAY,IAAI,iBAAiB;AACjC,oBAAkB,KAAK,iBAAiB;;AAG5C,QAAO;;AAGX,SAAS,+BAA+B,QAAwB;CAC5D,MAAM,mBAAmB,OAAO,MAAM;CACtC,MAAM,kBAAkB,uBAAuB,iBAAiB;AAEhE,QAAO,kBACD,GAAG,gBAAgB,mBACnB;;AAGV,SAAS,uBAAuB,QAA+B;CAC3D,MAAM,WAAW,oBAAoB,OAAO;AAE5C,KAAI,CAAC,SACD,QAAO;CAGX,MAAM,eAAe,SAAS,MAAM,IAAI,CAAC,QAAQ,YAAY,QAAQ,SAAS,EAAE;CAChF,MAAM,WAAW,aAAa,GAAG,GAAG;CACpC,MAAM,sBAAsB,aAAa,GAAG,GAAG;AAE/C,KAAI,CAAC,YAAY,wBAAwB,UACrC,QAAO;CAGX,MAAM,aAAa,SAAS,QAAQ,4BAA4B,GAAG;AAEnE,QAAO,WAAW,MAAM,CAAC,SAAS,IAC5B,WAAW,MAAM,GACjB;;AAGV,SAAS,oBAAoB,QAA+B;AACxD,KAAI,CAAC,OAAO,WAAW,UAAU,CAC7B,QAAO;AAGX,KAAI;EACA,MAAM,UAAU,IAAI,IAAI,OAAO;AAE/B,MAAI,QAAQ,aAAa,QACrB,QAAO;EAGX,MAAM,iBAAiB,mBAAmB,QAAQ,SAAS,CACtD,QAAQ,mBAAmB,KAAK,CAChC,QAAQ,QAAQ,IAAI;AAEzB,SAAO,eAAe,SAAS,IACzB,iBACA;SACF;AACJ,SAAO;;;ACxQf,SAAgB,kBAAkB,OAA+B;AAC7D,QAAO,CAAC,MAAM,UAAU,MAAM,SAAS;;AAG3C,SAAgB,oBAAoB,QAA0C;AAC1E,QAAO,OAAO,QAAQ,UAAU,kBAAkB,MAAM,CAAC;;AAG7D,SAAgB,qBACZ,QACA,oBACoB;CACpB,MAAM,gBAAgB,oBAAoB,OAAO;AAEjD,KAAI,oBAAoB;EACpB,MAAM,iBAAiB,cAAc,MAAM,UAAU,MAAM,SAAS,mBAAmB;AAEvF,MAAI,eACA,QAAO;;AAIf,QAAO,cAAc,MAAM,UAAU,MAAM,SAAA,QAA4B,IAAI;;;;ACrB/E,eAAsB,qBAClB,aACA,SACA,SAC2B;CAC3B,MAAM,cAAkC;EACpC,GAAG;EACH,GAAG;EACH,4BAAW,IAAI,MAAM,EAAC,aAAa;EACtC;AAED,OAAM,YAAY,WAAW,YAAY;AACzC,QAAO;;AAGX,eAAsB,0BAClB,aACA,SAC2B;AAC3B,QAAO,qBAAqB,aAAa,SAAS,EAC9C,WAAW,MACd,CAAC;;AAGN,eAAsB,0BAClB,aACA,SAC2B;AAC3B,QAAO,qBAAqB,aAAa,SAAS;EAC9C,iBAAiB;EACjB,SAAS;EACT,cAAc;EACjB,CAAC;;AAGN,eAAsB,wBAClB,aACA,SAC2B;AAC3B,QAAO,qBAAqB,aAAa,SAAS,EAC9C,cAAc,MACjB,CAAC;;AAGN,eAAsB,0BAClB,aACA,SAC2B;AAC3B,QAAO,qBAAqB,aAAa,SAAS;EAC9C,WAAW;EACX,WAAW;EACX,WAAW;EACd,CAAC;;;;AC5CN,IAAa,oBAAb,MAA+B;CAC3B,YACI,aACA,gBACF;AAFmB,OAAA,cAAA;AACA,OAAA,iBAAA;;CAGrB,MAAM,QAAQ,OAAsD;EAChE,IAAI,CAAC,SAAS,UAAU,MAAM,QAAQ,IAAI,CACtC,KAAK,YAAY,YAAY,MAAM,OAAO,EAC1C,KAAK,eAAe,YAAY,CACnC,CAAC;EACF,MAAM,gBAAgB,oBAAoB,OAAO;EACjD,MAAM,eAAe,qBAAqB,eAAe,SAAS,UAAU;AAE5E,MAAI,SAAS,aAAa,cAAc,SAAS,QAAQ,UACrD,WAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;AAGxE,SAAO;GACH,QAAQ;GACR,kBAAkB,cAAc,QAAQ;GAC3C;;;;;ACpBT,IAAa,iBAAb,MAA4B;CACxB,YACI,aACA,gBACF;AAFmB,OAAA,cAAA;AACA,OAAA,iBAAA;;CAGrB,MAAM,QAAQ,OAAmD;EAC7D,IAAI,UAAU,MAAM,KAAK,YAAY,YAAY,MAAM,OAAO;AAE9D,MAAI,SAAS,aAAa,QAAQ;OAG1B,CAAC,qBAFY,MAAM,KAAK,eAAe,cAAc,EAEvB,QAAQ,CACtC,WAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;;EAI5E,MAAM,iBAAiB,SAAS,aAAa,QAAQ,YAC/C;GACE,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACtB,GACC,MAAM,KAAK,0BAA0B;EAC3C,MAAM,WAAW,MAAM,KAAK,eAAe,gBAAgB,eAAe,UAAU;AAEpF,SAAO;GACH,kBAAkB,eAAe;GACjC,UAAU,CAAC,GAAG,SAAS,CAAC,KAAK,mBAAmB;GACnD;;CAGL,MAAc,2BAA2B;EACrC,MAAM,iBAAiB,MAAM,KAAK,eAAe,mBAAmB;AAEpE,SAAO;GACH,WAAW,eAAe;GAC1B,WAAW,eAAe;GAC7B;;;AAIT,SAAS,mBAAmB,MAAyB,OAAkC;AACnF,QAAO,KAAK,KAAK,cAAc,MAAM,KAAK,IACnC,KAAK,KAAK,cAAc,MAAM,KAAK,IACnC,KAAK,GAAG,cAAc,MAAM,GAAG;;AAG1C,SAAS,qBAAmB,UAA6B,SAAsC;AAC3F,QAAO,SAAS,MAAM,YAClB,QAAQ,OAAO,QAAQ,aAAa,QAAQ,aAAa,QAAQ,UACpE;;;;AC7CL,IAAa,iBAAb,MAA4B;CACxB,YACI,aACA,gBACF;AAFmB,OAAA,cAAA;AACA,OAAA,iBAAA;;CAGrB,MAAM,QAAQ,OAAmD;EAC7D,IAAI,UAAU,MAAM,KAAK,YAAY,YAAY,MAAM,OAAO;AAE9D,MAAI,SAAS,aAAa,QAAQ;OAG1B,CAAC,qBAFY,MAAM,KAAK,eAAe,cAAc,EAEvB,QAAQ,CACtC,WAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;;EAI5E,MAAM,iBAAiB,SAAS,aAAa,QAAQ,YAC/C;GACE,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACtB,GACC,MAAM,KAAK,0BAA0B;EAC3C,MAAM,WAAW,MAAM,KAAK,eAAe,gBAAgB,eAAe,UAAU;AAEpF,SAAO;GACH,kBAAkB,eAAe;GACjC,UAAU,OAAO,QAAQ,SAAS,CAC7B,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,cAAc,MAAM,CAAC,CACpD,KAAK,CAAC,MAAM,aAAa;IAAE;IAAM;IAAQ,EAAE;GACnD;;CAGL,MAAc,2BAA2B;EACrC,MAAM,iBAAiB,MAAM,KAAK,eAAe,mBAAmB;AAEpE,SAAO;GACH,WAAW,eAAe;GAC1B,WAAW,eAAe;GAC7B;;;AAIT,SAAS,qBAAmB,UAA6B,SAAsC;AAC3F,QAAO,SAAS,MAAM,YAClB,QAAQ,OAAO,QAAQ,aAAa,QAAQ,aAAa,QAAQ,UACpE;;;;AChDL,IAAa,oBAAb,MAA+B;CAC3B,YACI,aACA,gBACF;AAFmB,OAAA,cAAA;AACA,OAAA,iBAAA;;CAGrB,MAAM,QAAQ,OAAsD;EAChE,IAAI,CAAC,SAAS,UAAU,MAAM,QAAQ,IAAI,CACtC,KAAK,YAAY,YAAY,MAAM,OAAO,EAC1C,KAAK,eAAe,YAAY,CACnC,CAAC;AAEF,MAAI,SAAS,mBAAmB,SAAS,SAAS;GAC9C,MAAM,gBAAgB,OAAO,MAAM,UAC/B,MAAM,eAAe,SAAS,mBAAmB,MAAM,OAAO,SAAS,QAC1E;AAED,OAAI,CAAC,cACD,WAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;YAC7D,QAAQ,gBAAgB,EAAE,QAAQ,gBAAgB,cAAc,UACvE,WAAU,MAAM,wBAAwB,KAAK,aAAa,QAAQ;;AAI1E,SAAO;GACH;GACA,wBAAwB,SAAS,mBAAmB;GACpD,gBAAgB,SAAS,WAAW;GACpC,qBAAqB,SAAS,gBAAgB;GACjD;;;;;AC9BT,IAAa,sBAAb,MAAiC;CAC7B,YACI,aACA,gBACF;AAFmB,OAAA,cAAA;AACA,OAAA,iBAAA;;CAGrB,MAAM,QAAQ,OAAwD;EAClE,IAAI,UAAU,MAAM,KAAK,YAAY,YAAY,MAAM,OAAO;EAC9D,MAAM,CAAC,UAAU,YAAY,MAAM,QAAQ,IAAI,CAC3C,KAAK,eAAe,cAAc,EAClC,SAAS,aAAa,QAAQ,YACxB,KAAK,eAAe,cAAc,GAClC,QAAQ,QAAkC,KAAK,CACxD,CAAC;AAEF,MAAI,SAAS,aAAa,QAAQ,aAAa,CAAC,mBAAmB,UAAU,QAAQ,CACjF,WAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;AAGxE,MAAI,SAAS,aAAa,QAAQ,aAAa,CAAC,mBAAmB,UAAU,QAAQ,CACjF,WAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;EAGxE,MAAM,iBAAiB,SAAS,aAAa,QAAQ,YAC/C;GACE,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACtB,GACC,MAAM,KAAK,0BAA0B;AAE3C,SAAO;GACH,UAAU,SAAS,QAAQ,YAAY,QAAQ,cAAc,eAAe,UAAU;GACtF,kBAAkB,eAAe;GACjC,kBAAkB,eAAe;GACjC,kBAAkB,SAAS,cAAc,eAAe,YAAY,QAAQ,YAAY;GAC3F;;CAGL,MAAc,2BAA2B;EACrC,MAAM,iBAAiB,MAAM,KAAK,eAAe,mBAAmB;AAEpE,SAAO;GACH,WAAW,eAAe;GAC1B,WAAW,eAAe;GAC7B;;;AAIT,SAAS,mBACL,UACA,SACO;AACP,KAAI,CAAC,SACD,QAAO;AAGX,QAAO,SAAS,MAAM,YAClB,QAAQ,OAAO,QAAQ,aAAa,QAAQ,aAAa,QAAQ,UACpE;;AAGL,SAAS,mBACL,UACA,SACO;AACP,QAAO,SAAS,MAAM,YAClB,QAAQ,OAAO,QAAQ,aAAa,QAAQ,cAAc,QAAQ,UACrE;;;;ACtEL,IAAa,uBAAb,MAAkC;CAC9B,YACI,aACA,gBACA,QACF;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,SAAA;;CAGrB,MAAM,QAAQ,OAA2F;EACrG,MAAM,QAAQ,MAAM,MAAM,MAAM;AAEhC,MAAI,CAAC,MACD,OAAM,IAAI,MAAM,iCAAiC;EAGrD,MAAM,CAAC,SAAS,YAAY,MAAM,QAAQ,IAAI,CAC1C,KAAK,YAAY,YAAY,MAAM,OAAO,EAC1C,KAAK,eAAe,cAAc,CACrC,CAAC;EACF,MAAM,mBAAmB,SAAS,cAAc,MAAM,KAAK,eAAe,mBAAmB,EAAE;EAC/F,MAAM,UAAU,SAAS,MAAM,SAAS,KAAK,OAAO,MAAM,aAAa,KAAK,cAAc,iBAAiB;AAE3G,MAAI,CAAC,QACD,QAAO,EAAE,OAAO,OAAO;EAG3B,MAAM,iBAAiB,MAAM,KAAK,eAAe,cAAc,QAAQ,IAAI,MAAM;AAEjF,OAAK,OAAO,KACR;GACI,QAAQ,MAAM;GACd,WAAW,eAAe;GAC1B,WAAW,eAAe;GAC1B,OAAO,eAAe;GACzB,EACD,kBACH;AAED,SAAO;GACH,OAAO;GACP,SAAS;GACZ;;;;;AC3BT,IAAa,oBAAb,MAA+B;CAC3B,YACI,aACA,gBACA,QACF;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,SAAA;;CAGrB,MAAM,QAAQ,OAMX;EACC,MAAM,QAAQ,MAAM,SAAS,EAAE;EAC/B,MAAM,aAAa,gBAAgB,MAAM,MAAM,MAAM;AAErD,MAAI,CAAC,cAAc,MAAM,WAAW,EAChC,OAAM,IAAI,MAAM,4CAA4C;EAGhE,IAAI,UAAU,MAAM,KAAK,YAAY,YAAY,MAAM,OAAO;AAE9D,MAAI,SAAS,aAAa,QAAQ;OAM1B,EALa,MAAM,KAAK,eAAe,cAAc,EACxB,MAAM,YACnC,QAAQ,OAAO,SAAS,aAAa,QAAQ,aAAa,QAAQ,UACrE,CAGG,WAAU,MAAM,KAAK,2BACjB,MAAM,QACN,SACA,uCACH;;AAIT,MAAI,SAAS,aAAa,QAAQ;OAM1B,EALa,MAAM,KAAK,eAAe,cAAc,EACxB,MAAM,YACnC,QAAQ,OAAO,SAAS,aAAa,QAAQ,cAAc,QAAQ,UACtE,CAGG,WAAU,MAAM,KAAK,2BACjB,MAAM,QACN,SACA,uCACH;;AAIT,MAAI,CAAC,WAAW,CAAC,QAAQ,aAAa,CAAC,QAAQ,aAAa,CAAC,QAAQ,WAAW;GAC5E,MAAM,iBAAiB,MAAM,mCACzB,KAAK,aACL,KAAK,gBACL;IACI,QAAQ,MAAM;IACd;IACH,CACJ;AACD,aAAU,eAAe;AACzB,sBACI,KAAK,QACL;IACI,QAAQ,MAAM;IACd,OAAO;IACP,WAAW,eAAe,QAAQ;IAClC,WAAW,eAAe,QAAQ;IAClC,WAAW,eAAe,QAAQ;IACrC,EACD,kBACH;;AAGL,MAAI,SAAS,mBAAmB,SAAS,SAAS;GAE9C,MAAM,iBADkB,MAAM,KAAK,eAAe,YAAY,EACxB,MAAM,UACxC,MAAM,eAAe,SAAS,mBAAmB,MAAM,OAAO,SAAS,QAC1E;AAED,OAAI,CAAC,eAAe;AAChB,cAAU,MAAM,0BAA0B,KAAK,aAAa,QAAQ;AACpE,SAAK,OAAO,OACR;KACI,QAAQ,MAAM;KACd,OAAO;KACV,EACD,0EACH;cACM,QAAQ,gBAAgB,EAAE,QAAQ,gBAAgB,cAAc,WAAW;AAClF,cAAU,MAAM,wBAAwB,KAAK,aAAa,QAAQ;AAClE,SAAK,OAAO,OACR;KACI,QAAQ,MAAM;KACd,OAAO;KACP,YAAY,cAAc;KAC1B,SAAS,cAAc;KAC1B,EACD,iFACH;;;AAIT,MAAI,CAAC,WAAW,CAAC,QAAQ,aAAa,CAAC,QAAQ,UAC3C,OAAM,IAAI,MAAM,qCAAqC;EAGzD,IAAI,gBAAgB;EACpB,MAAM,yBAAyB,cAAc,MAAM;EACnD,MAAM,QAAQ,cAAc,mBAAmB,cAAc,UACvD;GACE,YAAY,cAAc;GAC1B,SAAS,cAAc;GAC1B,GACC;EAEN,MAAM,gBAAgB,qBADE,MAAM,KAAK,eAAe,YAAY,EACF,cAAc,UAAU;AAEpF,MAAI,cAAc,aAAa,eAAe,SAAS,cAAc,WAAW;AAC5E,mBAAgB,MAAM,0BAA0B,KAAK,aAAa,cAAc;AAChF,QAAK,OAAO,OACR;IACI,QAAQ,MAAM;IACd,OAAO;IACV,EACD,0EACH;;EAGL,MAAM,qBAAqB,yBACrB,MAAM,KAAK,4BAA4B,MAAM,QAAQ,cAAc,UAAU,GAC7E;EACN,MAAM,qBAAqB,sBAAsB,cAAc;AAE/D,QAAM,qBAAqB,mBAAmB;EAC9C,IAAI;AAEJ,MAAI;AACA,sBAAmB,KAAK,QAAQ;IAC5B,QAAQ,MAAM;IACd,OAAO;IACP,WAAW,cAAc;IACzB,WAAW;IACX,WAAW,MAAM;IACjB,QAAQ;IACX,EAAE,6BAA6B;AAChC,YAAS,MAAM,KAAK,eAAe,cAAc;IAC7C,WAAW;IACX,QAAQ;IACR,GAAI,MAAM,SAAS,IAAI,EAAE,OAAO,GAAG,EAAE;IACrC,GAAI,gBAAgB,EAAE,OAAO,cAAc,MAAM,GAAG,EAAE;IACtD,QAAQ,EACJ,MAAM,QACT;IACD,GAAI,QAAQ,EAAE,OAAO,GAAG,EAAE;IAC1B,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,QAAQ,GAAG,EAAE;IAChD,GAAI,cAAc,eAAe,EAAE,SAAS,cAAc,cAAc,GAAG,EAAE;IAChF,CAAC;AACF,sBAAmB,KAAK,QAAQ;IAC5B,QAAQ,MAAM;IACd,OAAO;IACP,WAAW,cAAc;IACzB,WAAW;IACX,QAAQ;IACX,EAAE,mBAAmB;YAChB;AACN,OAAI,mBACA,OAAM,KAAK,6BACP,MAAM,QACN,cAAc,WACd,mBACH;;AAIT,QAAM,KAAK,YAAY,MAAM,MAAM,OAAO;AAE1C,SAAO;GACH,gBAAgB;GAChB,WAAW,cAAc;GACzB,WAAW,cAAc;GAC5B;;CAGL,MAAc,2BACV,QACA,SACA,QACF;EACE,MAAM,cAAc,MAAM,0BAA0B,KAAK,aAAa,QAAQ;AAC9E,OAAK,OAAO,OACR;GACI;GACA,OAAO;GACV,EACD,GAAG,OAAO,gDACb;AAED,SAAO;;CAGX,MAAc,4BAA4B,QAAgB,WAAoC;EAC1F,MAAM,mBAAmB,MAAM,KAAK,eAAe,YAAY,UAAU;AAEzE,MAAI,CAAC,iBAAiB,MAAM,iBAAiB,OAAO,UAChD,OAAM,IAAI,MAAM,2EAA2E;AAG/F,qBACI,KAAK,QACL;GACI;GACA,OAAO;GACP,iBAAiB;GACjB,WAAW,iBAAiB;GAC/B,EACD,kCACH;AAED,SAAO,iBAAiB;;CAG5B,MAAc,6BACV,QACA,iBACA,WACa;AACb,MAAI;AAGA,OAAI,CAFY,MAAM,KAAK,eAAe,cAAc,UAAU,CAG9D,MAAK,OAAO,OACR;IACI;IACA,OAAO;IACP;IACA;IACH,EACD,2CACH;WAEA,OAAO;AACZ,QAAK,OAAO,OACR;IACI;IACA;IACA,OAAO;IACP;IACA;IACH,EACD,2CACH;;;;AAKb,SAAS,gBACL,MACA,OACM;CACN,MAAM,cAAc,MAAM,MAAM,IAAI;AAEpC,KAAI,CAAC,MAAM,KAAK,YAAY,CACxB,QAAO;CAGX,MAAM,iBAAiB,CACnB;EACI;EACA;EACA;EACA;EACH,CAAC,KAAK,IAAI,CACd;AAED,KAAI,YACA,gBAAe,KAAK,YAAY;AAGpC,QAAO,eAAe,KAAK,OAAO;;AAGtC,SAAS,YAAY,MAA2C;AAC5D,QAAO,KAAK,KAAK,MAAM,CAAC,aAAa,CAAC,WAAW,SAAS;;AAG9D,SAAS,cAAc,OAA8C;AACjE,QAAO,MAAM,KAAK,YAAY;;;;AC1SlC,IAAa,qBAAb,MAAgC;CAC5B,YACI,aACA,gBACA,QACF;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,SAAA;;CAGrB,MAAM,QAAQ,OAA0E;EACpF,MAAM,CAAC,SAAS,UAAU,MAAM,QAAQ,IAAI,CACxC,KAAK,YAAY,YAAY,MAAM,OAAO,EAC1C,KAAK,eAAe,YAAY,CACnC,CAAC;EACF,MAAM,QAAQ,OAAO,MAAM,SAAS,KAAK,SAAS,MAAM,aAAa,kBAAkB,KAAK,CAAC;AAE7F,MAAI,CAAC,MACD,QAAO,EAAE,OAAO,OAAO;AAG3B,QAAM,KAAK,YAAY,WAAW;GAC9B,QAAQ,MAAM;GACd,WAAW,SAAS,aAAa;GACjC,WAAW,SAAS,aAAa;GACjC,WAAW,SAAS,aAAa;GACjC,WAAW,MAAM;GACjB,iBAAiB,SAAS,mBAAmB;GAC7C,SAAS,SAAS,WAAW;GAC7B,cAAc,SAAS,gBAAgB;GACvC,UAAU,SAAS,YAAY;GAC/B,4BAAW,IAAI,MAAM,EAAC,aAAa;GACtC,CAAC;AAEF,OAAK,OAAO,KACR;GACI,QAAQ,MAAM;GACd,WAAW,MAAM;GACpB,EACD,iBACH;AAED,SAAO;GACH,OAAO;GACP;GACH;;;;;AC1CT,IAAa,qBAAb,MAAgC;CAC5B,YACI,aACA,gBACA,QACF;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,SAAA;;CAGrB,MAAM,QAAQ,OAKiB;EAC3B,MAAM,CAAC,SAAS,UAAU,MAAM,QAAQ,IAAI,CACxC,KAAK,YAAY,YAAY,MAAM,OAAO,EAC1C,KAAK,eAAe,YAAY,CACnC,CAAC;EACF,MAAM,QAAQ,OAAO,MAAM,SACvB,KAAK,eAAe,MAAM,cAAc,KAAK,OAAO,MAAM,QAC7D;AAED,MAAI,CAAC,MACD,QAAO,EAAE,OAAO,OAAO;EAG3B,MAAM,UAAU,MAAM,WAAW;AAEjC,MAAI,WAAW,EAAE,WAAW,MAAM,UAC9B,QAAO,EAAE,OAAO,OAAO;AAG3B,QAAM,KAAK,YAAY,WAAW;GAC9B,QAAQ,MAAM;GACd,WAAW,SAAS,aAAa;GACjC,WAAW,SAAS,aAAa;GACjC,WAAW,SAAS,aAAa;GACjC,WAAW,SAAS,aAAa;GACjC,iBAAiB,MAAM;GACvB,SAAS,MAAM;GACf,cAAc;GACd,UAAU,SAAS,YAAY;GAC/B,4BAAW,IAAI,MAAM,EAAC,aAAa;GACtC,CAAC;AAEF,OAAK,OAAO,KACR;GACI,QAAQ,MAAM;GACd,YAAY,MAAM;GAClB,SAAS,MAAM;GACf;GACH,EACD,iBACH;AAED,SAAO;GACH,OAAO;GACP;GACA;GACH;;;;;AC9DT,IAAa,uBAAb,MAAkC;CAC9B,YACI,aACA,gBACA,QACF;AAHmB,OAAA,cAAA;AACA,OAAA,iBAAA;AACA,OAAA,SAAA;;CAGrB,MAAM,QAAQ,OAA4E;EACtF,MAAM,CAAC,SAAS,YAAY,MAAM,QAAQ,IAAI,CAC1C,KAAK,YAAY,YAAY,MAAM,OAAO,EAC1C,KAAK,eAAe,cAAc,CACrC,CAAC;EACF,MAAM,mBAAmB,SAAS,cAAc,MAAM,KAAK,eAAe,mBAAmB,EAAE;EAC/F,MAAM,UAAU,SAAS,MAAM,SAAS,KAAK,OAAO,MAAM,aAAa,KAAK,cAAc,iBAAiB;AAE3G,MAAI,CAAC,QACD,QAAO,EAAE,OAAO,OAAO;AAG3B,QAAM,KAAK,YAAY,WAAW;GAC9B,QAAQ,MAAM;GACd,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACnB,WAAW,SAAS,aAAa;GACjC,iBAAiB,SAAS,mBAAmB;GAC7C,SAAS,SAAS,WAAW;GAC7B,cAAc,SAAS,gBAAgB;GACvC,UAAU,SAAS,YAAY;GAC/B,4BAAW,IAAI,MAAM,EAAC,aAAa;GACtC,CAAC;AAEF,OAAK,OAAO,KACR;GACI,QAAQ,MAAM;GACd,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACtB,EACD,mBACH;AAED,SAAO;GACH,OAAO;GACP;GACH;;;;;AC7CT,IAAa,yBAAb,cAA4C,MAAM;CAC9C;CAEA,YAAY,SAAiB;AACzB,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO,EAAE,SAAS;;;AAI/B,IAAa,+BAAb,cAAkD,MAAM;CACpD;CAEA,YAAY,SAAiB;AACzB,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO,EAAE,SAAS;;;AAI/B,IAAa,oBAAb,MAA+B;CAC3B,YAAY,oBAA6D;AAA5C,OAAA,qBAAA;;CAE7B,MAAM,QAAQ,OAA6D;AACvE,MAAI,MAAM,iBAAiB,QACvB,OAAM,IAAI,6BAA6B,oCAAoC;EAG/E,IAAI;AAEJ,MAAI;AACA,cAAW,MAAM,KAAK,mBAAmB,aAAa,EAClD,UAAU,MAAM,UACnB,CAAC;WACG,OAAO;AACZ,OAAI,iBAAiB,0BACjB,OAAM,IAAI,uBAAuB,MAAM,QAAQ;AAGnD,SAAM;;EAGV,MAAM,WAAW,kBAAkB,MAAM,YAAY,SAAS,SAAS;AAEvE,MAAI,CAAC,SAAS,WAAW,SAAS,CAC9B,OAAM,IAAI,6BAA6B,gCAAgC,WAAW;AAKtF,SAAO;GACH,UAHa,gBAAgB,MAAM,UAAU,MAAM,UAAU,SAAS;GAItE,MAAM;GACN,KAAK,aAAa,SAAS,MAAM,SAAS;GAC7C;;;AAIT,SAAS,aAAa,MAAkB,UAA0B;AAG9D,QAAO,QAAQ,SAAS,UAFT,OAAO,KAAK,KAAK,QAAQ,KAAK,YAAY,KAAK,WAAW,CAEhC,SAAS,SAAS;;AAG/D,SAAS,kBAAkB,OAA8B;CACrD,MAAM,aAAa,OAAO,MAAM,CAAC,aAAa;AAE9C,QAAO,cAAc,WAAW,SAAS,IACnC,aACA;;AAGV,SAAS,gBACL,kBACA,UACA,UACM;CACN,MAAM,oBAAoB,kBAAkB,MAAM;AAElD,KAAI,kBACA,QAAO;CAGX,MAAM,mBAAmB,SAAS,MAAM,IAAI,CAAC,GAAG,GAAG,EAAE,MAAM;AAE3D,KAAI,iBACA,QAAO;AAGX,QAAO,kBAAkB,iBAAiB,SAAS;;AAGvD,SAAS,iBAAiB,UAA0B;AAChD,SAAQ,UAAR;EACI,KAAK,aACD,QAAO;EACX,KAAK,YACD,QAAO;EACX,KAAK,aACD,QAAO;EACX,KAAK,YACD,QAAO;EACX,QACI,QAAO;;;;;AC3EnB,SAAgB,mBACZ,QACA,QACY;CACZ,MAAM,YAAY,YAAY;CAC9B,MAAM,SAAS,wBAAwB,QAAQ;EAC3C,MAAM;GACF,KAAK,OAAO;GACZ,WAAW;IACP,UAAU,OAAO;IACjB,eAAe,OAAO;IACzB;GACJ;EACD,OAAO,OAAO;EACd;EACA,OAAO;GACH,MAAM,OAAO;GACb,MAAM,OAAO;GAChB;EACD,UAAU,OAAO;EACpB,CAAC;AAEF,QAAO,gBACH,QACA,kCACI,QACA,OACA;EACI,eAAe,OAAO;EACtB,sBAAsB,OAAO;EAC7B,6BAA6B,OAAO;EACvC,CACJ,EACD,OACH;;AAGL,SAAS,gBACL,QACA,gBACA,QACY;CACZ,MAAM,gBAAgB,OAAO,MAAM,EAAE,WAAW,WAAW,CAAC;CAC5D,MAAM,iBAAiB,OAAO,MAAM,EAAE,WAAW,YAAY,CAAC;CAC9D,MAAM,eAAe,OAAO,MAAM,EAAE,WAAW,UAAU,CAAC;CAC1D,MAAM,aAAa,IAAI,eAAe;EAClC,UAAU,OAAO;EACjB,oBAAoB;EACvB,CAAC;CACF,MAAM,oBAAoB,IAAI,4BAA4B,WAAW;CACrE,MAAM,yBAAyB,IAAI,iCAAiC,WAAW;CAC/E,MAAM,cAAc,IAAI,sBAAsB,WAAW;CACzD,MAAM,2BAA2B,IAAI,0BAA0B;CAC/D,MAAM,qBAAqB,IAAI,mBAAmB;EAC9C,UAAU,OAAO;EACjB,SAAS,OAAO;EACnB,CAAC;CACF,MAAM,oBAAoB,IAAI,kBAAkB,mBAAmB;CACnE,MAAM,qBAAqB,IAAI,mBAC3B,aACA,gBACA,yBACH;CACD,MAAM,uBAAuB,IAAI,qBAAqB,aAAa,gBAAgB,eAAe;CAClG,MAAM,mBAAmB,IAAI,iBAAiB,eAAe;CAC7D,MAAM,iBAAiB,IAAI,eAAe,eAAe;CACzD,MAAM,oBAAoB,IAAI,kBAAkB,aAAa,eAAe;CAC5E,MAAM,iBAAiB,IAAI,eAAe,aAAa,eAAe;CACtE,MAAM,iBAAiB,IAAI,eAAe,aAAa,eAAe;CACtE,MAAM,sBAAsB,IAAI,oBAAoB,aAAa,eAAe;CAChF,MAAM,mBAAmB,IAAI,iBACzB,kBACA,gBACA,gBACA,gBACA,qBACA,aACA,eAGH;CACD,MAAM,oBAAoB,IAAI,kBAAkB,aAAa,eAAe;CAC5E,MAAM,uBAAuB,IAAI,qBAAqB,aAAa,gBAAgB,eAAe;CAClG,MAAM,oBAAoB,IAAI,kBAC1B,aACA,gBACA,aACH;CACD,MAAM,qBAAqB,IAAI,mBAAmB,aAAa,gBAAgB,eAAe;CAC9F,MAAM,qBAAqB,IAAI,mBAAmB,aAAa,gBAAgB,eAAe;CAC9F,MAAM,uBAAuB,IAAI,qBAAqB,aAAa,gBAAgB,eAAe;CAClG,IAAI,WAAW;AAEf,QAAO;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAM,UAAU;AACZ,OAAI,SACA;AAGJ,cAAW;AACX,iBAAc,KACV;IACI,OAAO;IACP,UAAU,OAAO;IACpB,EACD,mCACH;AACD,SAAM,OAAO,OAAO;;EAE3B;;;;ACjKL,SAAgB,mBACZ,QACA,eAA+C,EAAE,EACjD,UAAgC,EAAE,EACY;CAC9C,MAAM,SAAS,cAAc,cAAc,QAAQ;AAEnD,QAAO;EACH;EACA,WAAW,mBAAmB,QAAQ,OAAO;EAChD;;;;AClBL,SAAgB,+BACZ,SACM;CACN,MAAM,WAAW,QAAQ,SAAS,SAAS,IACrC,QAAQ,SAAS,KAAK,YAAY,KAAK,UAAU,CAAC,KAAK,KAAK,GAC5D;AAEN,QAAO;EACH;EACA;EACA,iBAAiB,iBAAiB,QAAQ,WAAW,CAAC;EACtD,cAAc,iBAAiB,QAAQ,UAAU,CAAC;EAClD;EACA;EACA;EACH,CAAC,KAAK,KAAK;;AAGhB,SAAgB,uCACZ,WACA,OACM;AACN,QAAO;EACH;EACA;EACA,YAAY;EACZ,UAAU;EACb,CAAC,KAAK,KAAK;;AAGhB,SAAgB,gCAAgC,WAAmB;AAC/D,QAAO,EACH,iBAAiB,CAAC;EACd;GACI,MAAM;GACN,eAAe,oCAAoC,QAAQ,UAAU;GACxE;EACD;GACI,MAAM;GACN,eAAe,oCAAoC,UAAU,UAAU;GAC1E;EACD;GACI,MAAM;GACN,eAAe,oCAAoC,UAAU,UAAU;GAC1E;EACJ,CAAC,EACL;;AAGL,SAAgB,oCACZ,OACA,WAC8B;AAC9B,QAAO,cAAc,MAAM,GAAG;;AAGlC,SAAgB,oCAAoC,MAG3C;AACL,KAAI,CAAC,KAAK,WAAW,cAAc,CAC/B,QAAO;CAGX,MAAM,GAAG,OAAO,aAAa,KAAK,MAAM,KAAK,EAAE;AAE/C,KAAI,CAAC,aAAa,CAAC,0BAA0B,MAAM,CAC/C,QAAO;AAGX,QAAO;EACH;EACA;EACH;;AAGL,SAAS,0BAA0B,OAAiD;AAChF,QAAO,UAAU,UAAU,UAAU,YAAY,UAAU;;AAG/D,SAAS,iBAAiB,OAAuB;AAC7C,QAAO,MAAM,WAAW,gCAAgC,OAAO;;;;AClDnE,eAAsB,6BAClB,SACA,OACa;AACb,SAAQ,MAAM,MAAd;EACI,KAAK;EACL,KAAK,sBAAsB;GACvB,MAAM,UAAU,gCAAgC,MAAM,WAAW;AAEjE,OAAI,QACA,OAAM,sBAAsB,SAAS,QAAQ;AAEjD;;EAEJ,KAAK,sBAAsB;GACvB,MAAM,aAAa,8BAA8B,MAAM,WAAW;AAElE,OAAI,WACA,OAAM,wBAAwB,SAAS,WAAW;AAEtD;;EAEJ,KAAK,iBAAiB;GAClB,MAAM,eAAe,2BAA2B,MAAM,WAAW;AAEjE,OAAI,aACA,OAAM,mBAAmB,SAAS,aAAa;AAEnD;;EAEJ,KAAK,gBAAgB;GACjB,MAAM,cAAc,0BAA0B,MAAM,WAAW;AAE/D,OAAI,YACA,OAAM,kBAAkB,SAAS,YAAY;AAEjD;;EAEJ,KAAK,kBAAkB;GACnB,MAAM,gBAAgB,4BAA4B,MAAM,WAAW;AAEnE,OAAI,cACA,OAAM,oBAAoB,SAAS,cAAc;AAErD;;EAEJ,QACI;;;AAIZ,eAAe,sBACX,SACA,SACa;CACb,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM;EAC1C,WAAW;EACX,WAAW,QAAQ;EACnB,WAAW,QAAQ;EACtB,CAAC;CACF,MAAM,WAAW,MAAM,QAAQ,UAAU,YAAY,gBAAgB,QAAQ,UAAU;CACvF,MAAM,UAAU,IAAI,IAAI,CACpB,GAAG,SAAS,KAAK,YAAY,QAAQ,OAAO,EAC5C,GAAG,QAAQ,UAAU,yBAAyB,YAAY,QAAQ,UAAU,CAC/E,CAAC;CACF,MAAM,YAAY,MAAM,QAAQ,UAAU,uBAAuB,gBAAgB,QAAQ,GAAG;CAC5F,MAAM,kBAAkB,IAAI,IAAI,UAAU,KAAK,aAAa,SAAS,OAAO,CAAC;AAE7E,MAAK,MAAM,UAAU,SAAS;AAC1B,MAAI,gBAAgB,IAAI,OAAO,CAC3B;AAGJ,MAAI;GACA,MAAM,UAAU,MAAM,QAAQ,IAAI,IAAI,YAClC,QACA,+BAA+B,QAAQ,EACvC;IACI,YAAY;IACZ,cAAc,gCAAgC,QAAQ,GAAG;IAC5D,CACJ;AAED,SAAM,QAAQ,UAAU,uBAAuB,IAAI;IAC/C,WAAW,QAAQ;IACnB,WAAW,QAAQ;IACnB;IACA,WAAW,QAAQ;IACnB,QAAQ;IACR,4BAAW,IAAI,MAAM,EAAC,aAAa;IACtC,CAAC;WACG,OAAO;AACZ,UAAO,MACH;IACI;IACA;IACA,OAAO;IACP,WAAW,QAAQ;IACtB,EACD,mDACH;;;;AAKb,eAAe,wBACX,SACA,OACa;CACb,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM;EAC1C,WAAW;EACX,OAAO;EACP,WAAW,MAAM;EACjB,WAAW,MAAM;EACpB,CAAC;CACF,MAAM,YAAY,MAAM,QAAQ,UAAU,uBAAuB,gBAAgB,MAAM,UAAU;AAEjG,OAAM,QAAQ,IACV,UAAU,IAAI,OAAO,aAAa;AAC9B,MAAI;AACA,SAAM,QAAQ,IAAI,IAAI,gBAClB,SAAS,QACT,SAAS,WACT,uCAAuC,MAAM,WAAW,MAAM,MAAM,CACvE;WACI,OAAO;AACZ,UAAO,KACH;IACI;IACA,QAAQ,SAAS;IACjB,OAAO;IACV,EACD,+CACH;;AAGL,QAAM,QAAQ,UAAU,uBAAuB,IAAI,mBAAmB,UAAU,MAAM,MAAM,CAAC;GAC/F,CACL;;AAGL,eAAe,mBACX,SACA,OACa;CACb,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM;EAC1C,WAAW;EACX,WAAW,MAAM;EACpB,CAAC;AAMF,KALsB,QAAQ,UAAU,yBAAyB,KAC7D,MAAM,WACN,gCAAgC,MAAM,MAAM,CAC/C,EAEkB;AACf,SAAO,KACH;GACI,OAAO,MAAM;GACb,OAAO;GACV,EACD,2DACH;AACD;;CAGJ,MAAM,UAAU,2BAA2B,MAAM,MAAM,IAAI;AAE3D,OAAM,iBAAiB,SAAS,MAAM,WAAW,+BAA+B,MAAM,UAAU,WAAW,UAAU;;AAGzH,eAAe,kBACX,SACA,OACa;CACb,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM;EAC1C,WAAW;EACX,WAAW,MAAM;EACpB,CAAC;AAGF,KAFsB,QAAQ,UAAU,yBAAyB,MAAM,MAAM,UAAU,CAGnF,gBACI,QACA,EACI,OAAO,mDACV,EACD,uEACH;;AAIT,eAAe,oBACX,SACA,OACa;AACb,KAAI,MAAM,eAAe,OACrB;AAGJ,OAAM,kBAAkB,SAAS,MAAM;;AAG3C,eAAe,iBACX,SACA,WACA,MACa;CACb,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM;EAC1C,WAAW;EACX;EACH,CAAC;CACF,MAAM,WAAW,MAAM,QAAQ,UAAU,YAAY,gBAAgB,UAAU;CAC/E,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,SAAS,KAAK,YAAY,QAAQ,OAAO,CAAC,CAAC;AAEvE,OAAM,QAAQ,IACV,QAAQ,IAAI,OAAO,WAAW;AAC1B,MAAI;AACA,SAAM,QAAQ,IAAI,IAAI,YAAY,QAAQ,KAAK;WAC1C,OAAO;AACZ,UAAO,KACH;IACI;IACA;IACA,OAAO;IACV,EACD,qDACH;;GAEP,CACL;;AAGL,SAAS,mBACL,UACA,OACyB;AACzB,QAAO;EACH,GAAG;EACH,QAAQ;EACR,4BAAW,IAAI,MAAM,EAAC,aAAa;EACtC;;AAGL,SAAS,gCAAgC,YAAuD;AAC5F,KAAI,CAAC,cAAc,WAAW,CAC1B,QAAO;CAGX,MAAM,KAAK,iBAAiB,WAAW,GAAG;CAC1C,MAAM,YAAY,iBAAiB,WAAW,UAAU;CACxD,MAAM,aAAa,iBAAiB,WAAW,WAAW,IAAI,iBAAiB,WAAW,KAAK;AAE/F,KAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WACtB,QAAO;AAGX,QAAO;EACH,QAAQ,MAAM,QAAQ,WAAW,OAAO,GAClC,WAAW,OAAO,QAAQ,UAA2B,OAAO,UAAU,SAAS,GAC/E,EAAE;EACR;EACA,UAAU,cAAc,WAAW,SAAS,GACtC,WAAW,WACX,EAAE;EACR,UAAU,4BAA4B,WAAW;EACjD;EACA;EACH;;AAGL,SAAS,8BAA8B,YAA4D;AAC/F,KAAI,CAAC,cAAc,WAAW,CAC1B,QAAO;CAGX,MAAM,YAAY,iBAAiB,WAAW,UAAU,IAAI,iBAAiB,WAAW,aAAa;CACrG,MAAM,QAAQ,yBACV,iBAAiB,WAAW,MAAM,IAAI,iBAAiB,WAAW,SAAS,CAC9E;CACD,MAAM,YAAY,iBAAiB,WAAW,UAAU;AAExD,KAAI,CAAC,aAAa,CAAC,SAAS,CAAC,UACzB,QAAO;AAGX,QAAO;EACH;EACA;EACA;EACH;;AAGL,SAAS,2BAA2B,YAAyD;AACzF,KAAI,CAAC,cAAc,WAAW,CAC1B,QAAO;CAGX,MAAM,YAAY,iBAAiB,WAAW,UAAU;AAExD,KAAI,CAAC,UACD,QAAO;AAGX,QAAO;EACH,OAAO,WAAW;EAClB;EACH;;AAGL,SAAS,0BAA0B,YAAwD;AACvF,KAAI,CAAC,cAAc,WAAW,CAC1B,QAAO;CAGX,MAAM,YAAY,iBAAiB,WAAW,UAAU;AAExD,QAAO,YACD,EAAE,WAAW,GACb;;AAGV,SAAS,4BAA4B,YAA0D;AAC3F,KAAI,CAAC,cAAc,WAAW,IAAI,CAAC,cAAc,WAAW,OAAO,CAC/D,QAAO;CAGX,MAAM,YAAY,iBAAiB,WAAW,UAAU;CACxD,MAAM,aAAa,iBAAiB,WAAW,OAAO,KAAK;AAE3D,KAAI,CAAC,aAAa,CAAC,WACf,QAAO;AAGX,QAAO;EACH;EACA;EACH;;AAGL,SAAS,4BAA4B,YAA+C;AAChF,KAAI,MAAM,QAAQ,WAAW,SAAS,CAClC,QAAO,WAAW,SAAS,QAAQ,UAA2B,OAAO,UAAU,SAAS;AAG5F,KAAI,OAAO,WAAW,YAAY,YAAY,WAAW,QAAQ,MAAM,CAAC,SAAS,EAC7E,QAAO,CAAC,WAAW,QAAQ;AAG/B,KAAI,MAAM,QAAQ,WAAW,QAAQ,CACjC,QAAO,WAAW,QAAQ,QAAQ,UAA2B,OAAO,UAAU,SAAS;AAG3F,QAAO,EAAE;;AAGb,SAAS,yBAAyB,OAAsD;AACpF,KAAI,UAAU,UAAU,UAAU,YAAY,UAAU,SACpD,QAAO;AAGX,QAAO;;AAGX,SAAS,2BAA2B,OAA+B;AAC/D,KAAI,iBAAiB,SAAS,MAAM,QAAQ,MAAM,CAAC,SAAS,EACxD,QAAO,MAAM,QAAQ,MAAM;AAG/B,KAAI,CAAC,cAAc,MAAM,CACrB,QAAO;AAGX,KAAI,cAAc,MAAM,KAAK,IAAI,OAAO,MAAM,KAAK,YAAY,YAAY,MAAM,KAAK,QAAQ,MAAM,CAAC,SAAS,EAC1G,QAAO,MAAM,KAAK,QAAQ,MAAM;AAGpC,QAAO,iBAAiB,MAAM,KAAK;;AAGvC,SAAS,gCAAgC,OAAuB;AAC5D,KAAI,iBAAiB,MACjB,QAAO;AAGX,KAAI,cAAc,MAAM,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,MAAM,CAAC,SAAS,GAAG;EACxF,MAAM,aAAa,IAAI,MAAM,2BAA2B,MAAM,IAAI,yBAAyB;AAI3F,aAAW,OAAO,MAAM,KAAK,MAAM;AAEnC,MAAI,cAAc,MAAM,KAAK,CACzB,YAAW,OAAO,MAAM;AAG5B,SAAO;;AAGX,wBAAO,IAAI,MAAM,yBAAyB;;AAG9C,SAAS,iBAAiB,OAA+B;AACrD,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,IACpD,MAAM,MAAM,GACZ;;AAGV,SAAS,cAAc,OAA8C;AACjE,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;AClS/E,IAAa,0BAAkD;CAAC;CAAM;CAAS;CAAK;AAEpF,IAAM,cAAuB;CACzB,QAAQ;CACR,UAAU;EACN,OAAO;EACP,QAAQ;EACR,KAAK;EACL,QAAQ;EACR,UAAU;EACV,QAAQ;EACR,OAAO;EACP,UAAU;EACb;CACD,OAAO,EACH,OAAO;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACH,EACJ;CACD,cAAc,EACV,OAAO,iBACV;CACD,QAAQ;EACJ,aAAa;EACb,iBAAiB;EACjB,cAAc;EACd,UAAU;EACV,KAAK,aAAqB,YAAoB;AAC1C,UAAO,QAAQ,YAAY,GAAG;;EAErC;CACD,QAAQ;EACJ,YAAY;EACZ,mBAAmB;EACtB;CACD,QAAQ,EACJ,eAAe,qCAClB;CACD,cAAc;EACV,eAAe;EACf,aAAa;EACb,YAAY;EACZ,YAAY;EACZ,aAAa;EACb,gBAAgB;EAChB,gBAAgB;EAChB,iBAAiB;EACjB,cAAc;EACjB;CACD,OAAO;EACH,WAAW;EACX,YAAY;EACZ,SAAS;EACZ;CACD,QAAQ;EACJ,YAAY;EACZ,cAAc;EACd,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,kBAAkB;EAClB,eAAe;EACf,kBAAkB;EAClB,cAAc;EACd,iBAAiB;EACjB,iBAAiB;EACjB,UAAU;EACV,YAAY;EACZ,YAAY;EACZ,gBAAgB;EAChB,iBAAiB;EACpB;CACD,QAAQ;EACJ,OAAO;EACP,OAAO,SAAkB;AACrB,UAAO,WAAW,UAAU,YAAY;;EAE5C,QAAQ,SAAiB;AACrB,UAAO,YAAY;;EAE1B;CACD,MAAM;EACF,OAAO;EACP,KAAK,MAAc;AACf,UAAO,SAAS;;EAEpB,MAAM,MAAc;AAChB,UAAO,UAAU;;EAErB,OAAO,MAAc;AACjB,UAAO,WAAW;;EAEtB,SAAS,MAAc;AACnB,UAAO,aAAa;;EAExB,UAAU,MAAc;AACpB,UAAO,8BAA8B;;EAE5C;CACD,UAAU;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,cAAc;EACd,eAAe,UAAkB;AAC7B,UAAO,oBAAoB;;EAE/B,eAAe,SAAiB;AAC5B,UAAO,oBAAoB;;EAE/B,gBAAgB,SAAiB;AAC7B,UAAO,qBAAqB;;EAEhC,UAAU;EACV,SAAS;EACT,SAAS;EACT,iBAAiB;EACjB,aAAa;EACb,eAAe;EACf,oBAAoB;EACpB,aAAa,SAAiB;AAC1B,UAAO;IACH,mBAAmB;IACnB;IACA;IACH,CAAC,KAAK,KAAK;;EAEhB,cAAc;EACd,cAAc;EACd,YAAY;EACZ,SAAS;EACZ;CACD,KAAK;EACD,MAAM;EACN,OAAO;EACP,eAAe,UAAkB;AAC7B,UAAO,oBAAoB;;EAE/B,WAAW;EACX,OAAO;EACV;CACD,KAAK;EACD,MAAM;EACN,OAAO;EACP,eAAe,UAAkB;AAC7B,UAAO,oBAAoB;;EAE/B,WAAW;EACX,UAAU;EACV,WAAW;EACX,OAAO,OAAe;AAClB,UAAO,WAAW;;EAEtB,wBAAwB,OAAe;AACnC,UAAO,8BAA8B;;EAE5C;CACD,QAAQ;EACJ,MAAM;EACN,OAAO;EACP,QAAQ,OAAe;AACnB,UAAO,kBAAkB;;EAE7B,UAAU;EACV,SAAS;EACZ;CACD,QAAQ;EACJ,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,QAAQ,OAAe;AACnB,UAAO,kBAAkB;;EAE7B,UAAU;EACV,sBAAsB,SAAiB;AACnC,UAAO,4BAA4B;;EAEvC,eAAe,SAAiB;AAC5B,UAAO,oBAAoB;;EAE/B,mBAAmB;EACnB,sBAAsB;EACtB,MAAM,OAAe;AACjB,UAAO,UAAU;;EAErB,YAAY,YAAoB;AAC5B,UAAO,iBAAiB;;EAE5B,SAAS;EACT,uBAAuB;EACvB,uBAAuB;EAC1B;CACD,UAAU;EACN,OAAO;EACP,QAAQ;EACR,QAAQ,OAAe;AACnB,UAAO,qBAAqB;;EAEhC,UAAU;EACV,SAAS;EACT,QAAQ;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;GACP;EACJ;CACJ;AAED,IAAM,iBAA0B;CAC5B,QAAQ;CACR,UAAU;EACN,OAAO;EACP,QAAQ;EACR,KAAK;EACL,QAAQ;EACR,UAAU;EACV,QAAQ;EACR,OAAO;EACP,UAAU;EACb;CACD,OAAO,EACH,OAAO;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACH,EACJ;CACD,cAAc,EACV,OAAO,QACV;CACD,QAAQ;EACJ,aAAa;EACb,iBAAiB;EACjB,cAAc;EACd,UAAU;EACV,KAAK,aAAqB,YAAoB;AAC1C,UAAO,KAAK,YAAY,GAAG,WAAW;;EAE7C;CACD,QAAQ;EACJ,YAAY;EACZ,mBAAmB;EACtB;CACD,QAAQ,EACJ,eAAe,oBAClB;CACD,cAAc;EACV,eAAe;EACf,aAAa;EACb,YAAY;EACZ,YAAY;EACZ,aAAa;EACb,gBAAgB;EAChB,gBAAgB;EAChB,iBAAiB;EACjB,cAAc;EACjB;CACD,OAAO;EACH,WAAW;EACX,YAAY;EACZ,SAAS;EACZ;CACD,QAAQ;EACJ,YAAY;EACZ,cAAc;EACd,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,kBAAkB;EAClB,eAAe;EACf,kBAAkB;EAClB,cAAc;EACd,iBAAiB;EACjB,iBAAiB;EACjB,UAAU;EACV,YAAY;EACZ,YAAY;EACZ,gBAAgB;EAChB,iBAAiB;EACpB;CACD,QAAQ;EACJ,OAAO;EACP,OAAO,SAAkB;AACrB,UAAO,OAAO,UAAU,OAAO;;EAEnC,QAAQ,SAAiB;AACrB,UAAO,OAAO;;EAErB;CACD,MAAM;EACF,OAAO;EACP,KAAK,MAAc;AACf,UAAO,QAAQ;;EAEnB,MAAM,MAAc;AAChB,UAAO,SAAS;;EAEpB,OAAO,MAAc;AACjB,UAAO,SAAS;;EAEpB,SAAS,MAAc;AACnB,UAAO,QAAQ;;EAEnB,UAAU,MAAc;AACpB,UAAO,WAAW;;EAEzB;CACD,UAAU;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,cAAc;EACd,eAAe,UAAkB;AAC7B,UAAO,SAAS;;EAEpB,eAAe,SAAiB;AAC5B,UAAO,SAAS;;EAEpB,gBAAgB,SAAiB;AAC7B,UAAO,SAAS;;EAEpB,UAAU;EACV,SAAS;EACT,SAAS;EACT,iBAAiB;EACjB,aAAa;EACb,eAAe;EACf,oBAAoB;EACpB,aAAa,SAAiB;AAC1B,UAAO;IACH,UAAU;IACV;IACA;IACH,CAAC,KAAK,KAAK;;EAEhB,cAAc;EACd,cAAc;EACd,YAAY;EACZ,SAAS;EACZ;CACD,KAAK;EACD,MAAM;EACN,OAAO;EACP,eAAe,UAAkB;AAC7B,UAAO,SAAS;;EAEpB,WAAW;EACX,OAAO;EACV;CACD,KAAK;EACD,MAAM;EACN,OAAO;EACP,eAAe,UAAkB;AAC7B,UAAO,SAAS;;EAEpB,WAAW;EACX,UAAU;EACV,WAAW;EACX,OAAO,OAAe;AAClB,UAAO,OAAO;;EAElB,wBAAwB,OAAe;AACnC,UAAO,YAAY;;EAE1B;CACD,QAAQ;EACJ,MAAM;EACN,OAAO;EACP,QAAQ,OAAe;AACnB,UAAO,aAAa;;EAExB,UAAU;EACV,SAAS;EACZ;CACD,QAAQ;EACJ,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,QAAQ,OAAe;AACnB,UAAO,SAAS;;EAEpB,UAAU;EACV,sBAAsB,SAAiB;AACnC,UAAO,WAAW;;EAEtB,eAAe,SAAiB;AAC5B,UAAO,SAAS;;EAEpB,mBAAmB;EACnB,sBAAsB;EACtB,MAAM,OAAe;AACjB,UAAO,OAAO;;EAElB,YAAY,YAAoB;AAC5B,UAAO,SAAS;;EAEpB,SAAS;EACT,uBAAuB;EACvB,uBAAuB;EAC1B;CACD,UAAU;EACN,OAAO;EACP,QAAQ;EACR,QAAQ,OAAe;AACnB,UAAO,SAAS;;EAEpB,UAAU;EACV,SAAS;EACT,QAAQ;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;GACP;EACJ;CACJ;AAED,IAAM,cAAuB;CACzB,QAAQ;CACR,UAAU;EACN,OAAO;EACP,QAAQ;EACR,KAAK;EACL,QAAQ;EACR,UAAU;EACV,QAAQ;EACR,OAAO;EACP,UAAU;EACb;CACD,OAAO,EACH,OAAO;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACH,EACJ;CACD,cAAc,EACV,OAAO,UACV;CACD,QAAQ;EACJ,aAAa;EACb,iBAAiB;EACjB,cAAc;EACd,UAAU;EACV,KAAK,aAAqB,YAAoB;AAC1C,UAAO,OAAO,YAAY,GAAG;;EAEpC;CACD,QAAQ;EACJ,YAAY;EACZ,mBAAmB;EACtB;CACD,QAAQ,EACJ,eAAe,2BAClB;CACD,cAAc;EACV,eAAe;EACf,aAAa;EACb,YAAY;EACZ,YAAY;EACZ,aAAa;EACb,gBAAgB;EAChB,gBAAgB;EAChB,iBAAiB;EACjB,cAAc;EACjB;CACD,OAAO;EACH,WAAW;EACX,YAAY;EACZ,SAAS;EACZ;CACD,QAAQ;EACJ,YAAY;EACZ,cAAc;EACd,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,kBAAkB;EAClB,eAAe;EACf,kBAAkB;EAClB,cAAc;EACd,iBAAiB;EACjB,iBAAiB;EACjB,UAAU;EACV,YAAY;EACZ,YAAY;EACZ,gBAAgB;EAChB,iBAAiB;EACpB;CACD,QAAQ;EACJ,OAAO;EACP,OAAO,SAAkB;AACrB,UAAO,OAAO,UAAU,OAAO;;EAEnC,QAAQ,SAAiB;AACrB,UAAO,UAAU;;EAExB;CACD,MAAM;EACF,OAAO;EACP,KAAK,MAAc;AACf,UAAO,QAAQ;;EAEnB,MAAM,MAAc;AAChB,UAAO,OAAO;;EAElB,OAAO,MAAc;AACjB,UAAO,OAAO;;EAElB,SAAS,MAAc;AACnB,UAAO,WAAW;;EAEtB,UAAU,MAAc;AACpB,UAAO,gBAAgB;;EAE9B;CACD,UAAU;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,cAAc;EACd,eAAe,UAAkB;AAC7B,UAAO,cAAc;;EAEzB,eAAe,SAAiB;AAC5B,UAAO,aAAa;;EAExB,gBAAgB,SAAiB;AAC7B,UAAO,cAAc;;EAEzB,UAAU;EACV,SAAS;EACT,SAAS;EACT,iBAAiB;EACjB,aAAa;EACb,eAAe;EACf,oBAAoB;EACpB,aAAa,SAAiB;AAC1B,UAAO;IACH,cAAc;IACd;IACA;IACH,CAAC,KAAK,KAAK;;EAEhB,cAAc;EACd,cAAc;EACd,YAAY;EACZ,SAAS;EACZ;CACD,KAAK;EACD,MAAM;EACN,OAAO;EACP,eAAe,UAAkB;AAC7B,UAAO,cAAc;;EAEzB,WAAW;EACX,OAAO;EACV;CACD,KAAK;EACD,MAAM;EACN,OAAO;EACP,eAAe,UAAkB;AAC7B,UAAO,cAAc;;EAEzB,WAAW;EACX,UAAU;EACV,WAAW;EACX,OAAO,OAAe;AAClB,UAAO,OAAO;;EAElB,wBAAwB,OAAe;AACnC,UAAO,gBAAgB;;EAE9B;CACD,QAAQ;EACJ,MAAM;EACN,OAAO;EACP,QAAQ,OAAe;AACnB,UAAO,cAAc;;EAEzB,UAAU;EACV,SAAS;EACZ;CACD,QAAQ;EACJ,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,QAAQ,OAAe;AACnB,UAAO,WAAW;;EAEtB,UAAU;EACV,sBAAsB,SAAiB;AACnC,UAAO,aAAa;;EAExB,eAAe,SAAiB;AAC5B,UAAO,UAAU;;EAErB,mBAAmB;EACnB,sBAAsB;EACtB,MAAM,OAAe;AACjB,UAAO,QAAQ;;EAEnB,YAAY,YAAoB;AAC5B,UAAO,UAAU;;EAErB,SAAS;EACT,uBAAuB;EACvB,uBAAuB;EAC1B;CACD,UAAU;EACN,OAAO;EACP,QAAQ;EACR,QAAQ,OAAe;AACnB,UAAO,UAAU;;EAErB,UAAU;EACV,SAAS;EACT,QAAQ;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;GACP;EACJ;CACJ;AAED,IAAa,WAAW;AAExB,SAAgB,cAAc,OAAqC;AAC/D,QAAO,wBAAwB,SAAS,MAAqB;;AAGjE,SAAgB,qBAAqB,OAA+C;AAChF,KAAI,CAAC,MACD,QAAA;CAGJ,MAAM,aAAa,MAAM,MAAM,CAAC,aAAa;AAE7C,KAAI,eAAe,WAAW,eAAe,aAAa,eAAe,KACrE,QAAO;AAGX,KAAI,eAAe,QAAQ,eAAe,WAAW,eAAe,QAChE,QAAO;AAGX,QAAO;;AAGX,SAAgB,WAAW,WAAA,MAA0E;CACjG,MAAM,aAAa,qBAAqB,SAAS;AAEjD,KAAI,eAAe,QACf,QAAO;AAGX,KAAI,eAAe,KACf,QAAO;AAGX,QAAO;;AAGX,SAAgB,iBAAiB,UAAuB,OAAgB,UAAkB;AACtF,QAAO,KAAK,SAAS,OAAO;;;;ACj0BhC,SAAgB,oBAAoB,WAAwB,MAAoB;CAC5E,MAAM,OAAO,WAAW,SAAS;AAEjC,QAAO;EACH;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACD;GACI,SAAS;GACT,aAAa,KAAK,SAAS;GAC9B;EACJ;;AAGL,IAAa,oBAAkC,qBAAqB;;;ACpCpE,IAAa,+BAA+D,CACxE,EAAE,MAAM,WAAW,EACnB,EAAE,MAAM,qBAAqB,CAChC;AAED,eAAsB,qBAAqB,KAAU,QAAkC;AACnF,OAAM,QAAQ,IACV,6BAA6B,KAAK,UAC9B,IAAI,IAAI,cAAc,mBAAmB,EAAE,OAAO,CAAC,CACtD,CACJ;AAED,QAAO,KACH;EACI,WAAW;EACX,UAAU,kBAAkB,KAAK,YAAY,QAAQ,QAAQ;EAC7D,OAAO;EACP,QAAQ,6BAA6B,KAAK,UAAU,MAAM,KAAK;EAClE,EACD,2BACH;;AAGL,eAAsB,4BAClB,KACA,QACA,UACa;AACb,OAAM,IAAI,cACN,oBAAoB,SAAS,EAC7B,EACI,OAAO;EACH,MAAM;EACN,SAAS;EACZ,EACJ,CACJ;;;;AC/BL,SAAgB,2BACZ,KACA,YAA0B,YACb;CACb,MAAM,WAAW,OAAO,IAAI,QAAQ,cAAc,WAC5C,IAAI,OAAO,YACX,KAAA;CAEN,MAAM,UAAU,uBADI,mBAAmB,IAAI,CACQ;CACnD,MAAM,eAAe,wBAAwB,IAAI,eAAe,KAAK;CACrE,MAAM,cAAc,OAAO,aAAa,WAClC,YAAY,aACZ;AAEN,QAAO;EACH;EACA,GAAI,OAAO,IAAI,MAAM,OAAO,WAAW,EAAE,QAAQ,IAAI,KAAK,IAAI,GAAG,EAAE;EACnE,GAAI,OAAO,aAAa,WAAW,EAAE,UAAU,GAAG,EAAE;EACpD,GAAI,UAAU,EAAE,SAAS,GAAG,EAAE;EAC9B,GAAI,eAAe,EAAE,cAAc,GAAG,EAAE;EACxC,eAAe,OAAO,aAAa,WAC7B,OAAO,SAAS,GAChB;EACN;EACH;;AAGL,SAAgB,6BACZ,QACA,KACA,YAA0B,YACjB;AACT,QAAO,OAAO,MAAM,2BAA2B,KAAK,UAAU,CAAC;;AAGnE,SAAgB,mCACZ,cACA,KACA,YAA0B,YACb;AACb,QAAO;EACH,GAAG;EACH,QAAQ,6BAA6B,aAAa,QAAQ,KAAK,UAAU;EAC5E;;AAGL,SAAS,mBAAmB,KAA4C;AACpE,QAAO,wBAAwB,IAAI,SAAS,KAAK,IAC1C,wBAAwB,IAAI,KAAK,KAAK;;AAGjD,SAAS,uBAAuB,OAAqC;AACjE,KAAI,CAAC,SAAS,CAAC,MAAM,WAAW,IAAI,CAChC,QAAO;CAGX,MAAM,QAAQ,MAAM,MAAM,QAAQ,EAAE,CAAC,IAAI,MAAM;AAE/C,KAAI,CAAC,MACD,QAAO;AAGX,QAAO,MAAM,QAAQ,SAAS,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;;AAG1D,SAAS,wBAAwB,OAAiD;AAC9E,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,IACpD,MAAM,MAAM,GACZ;;;;ACxEV,SAAgB,aAAa,OAAgB,OAAgB,UAAkB;CAC3E,MAAM,YAAY,eAAe,OAAO,KAAK;AAE7C,QAAO,UAAU,QACX,GAAG,UAAU,QAAQ,IAAI,KAAK,OAAO,WAAW,IAAI,UAAU,UAC9D,UAAU;;AAGpB,SAAS,eAAe,OAAgB,MAA+B;AACnE,KAAI,aAAa,OAAO,oBAAoB,CACxC,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,aAAa,OAAO,sBAAsB,CAC1C,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,aAAa,OAAO,6BAA6B,CACjD,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO;EACV;AAGL,KAAI,aAAa,OAAO,wBAAwB,CAC5C,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,kBAAkB,CACrB,eAAe,MAAM,KAAK,EAC1B,eAAe,MAAM,KAAK,CAC7B,CAAC;EACL;AAGL,KAAI,aAAa,OAAO,yBAAyB,CAC7C,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,aAAa,OAAO,+BAA+B,CACnD,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,aAAa,OAAO,2BAA2B,CAC/C,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,aAAa,OAAO,uBAAuB,CAC3C,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,aAAa,OAAO,WAAW,CAC/B,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,kBAAkB;GACrB,eAAe,MAAM,KAAK;GAC1B,kBAAkB,MAAM,MAAM,KAAK;GACnC,iBAAiB,MAAM,MAAM,KAAK;GACrC,CAAC;EACL;AAGL,KAAI,aAAa,OAAO,gBAAgB,CACpC,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,KAAK,IAAI;EACxC;AAGL,KAAI,kBAAkB,MAAM,CACxB,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,uBAAuB,MAAM;EACvC;AAGL,KAAI,iBAAiB,MACjB,QAAO;EACH,SAAS,MAAM,SAAS,eAAe,KAAK,OAAO,iBAAiB,KAAK,OAAO;EAChF,OAAO,MAAM,WAAW;EAC3B;AAGL,QAAO;EACH,SAAS,KAAK,OAAO;EACrB,OAAO,eAAe,MAAM,IAAI,iBAAiB,MAAM;EAC1D;;AAGL,SAAS,kBAAkB,OAAiF;AACxG,QAAO,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,aAAa,SACZ,MAAgC,YAAY;;AAGxD,SAAS,aACL,OACA,MACwC;AACxC,QAAO,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,UAAU,SACT,MAA6B,SAAS;;AAGlD,SAAS,uBAAuB,OAA8D;CAC1F,MAAM,gBAAgB,eAAe,MAAM,KAAK;AAEhD,KAAI,cACA,QAAO;AAOX,QAJ6B,MAAM,QAAQ,MAAM,OAAO,IAAI,MAAM,OAAO,SAAS,IAC5E,iBAAiB,MAAM,OAAO,GAAG,GACjC;;AAKV,SAAS,eAAe,OAA+B;AACnD,KAAI,CAAC,MACD,QAAO;AAGX,KAAI,OAAO,UAAU,SACjB,QAAO,MAAM,MAAM,IAAI;AAG3B,KAAI,OAAO,UAAU,YAAY,aAAa,OAAO;EACjD,MAAM,UAAW,MAAgC;AAEjD,SAAO,OAAO,YAAY,YAAY,QAAQ,MAAM,CAAC,SAAS,IACxD,QAAQ,MAAM,GACd;;AAGV,QAAO;;AAGX,SAAS,eAAe,OAA+B;AACnD,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,EAAE,aAAa,OACtD,QAAO;CAGX,MAAM,UAAW,MAAgC;AAEjD,QAAO,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,GACxD,YAAY,KAAK,MAAM,QAAQ,KAC/B;;AAGV,SAAS,iBAAiB,OAAgB,MAA8B;AACpE,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,EAAE,iBAAiB,OAC1D,QAAO;CAGX,MAAM,cAAe,MAAoC;AAEzD,QAAO,OAAO,gBAAgB,YACxB,GAAG,KAAK,OAAO,eAAe,IAAI,cAAc,QAAQ,SACxD;;AAGV,SAAS,kBAAkB,OAAgB,MAA8B;AACrE,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,EAAE,gBAAgB,OACzD,QAAO;CAGX,MAAM,aAAc,MAAmC;AAEvD,QAAO,OAAO,eAAe,YAAY,OAAO,SAAS,WAAW,GAC9D,GAAG,KAAK,OAAO,gBAAgB,IAAI,KAAK,MAAM,WAAW,KACzD;;AAGV,SAAS,kBAAkB,OAAwD;CAC/E,MAAM,WAAW,MACZ,KAAK,SAAS,MAAM,MAAM,CAAC,CAC3B,QAAQ,SAAyB,CAAC,CAAC,KAAK;AAE7C,QAAO,SAAS,SAAS,IAAI,SAAS,KAAK,MAAM,GAAG;;AAGxD,SAAS,iBAAiB,OAA+B;AACrD,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC5B,QAAO;AAGX,KAAI,OAAO,UAAU,SACjB,QAAO,MAAM,MAAM,IAAI;AAG3B,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAC9C,QAAO,OAAO,MAAM;AAGxB,KAAI;EACA,MAAM,OAAO,KAAK,UAAU,MAAM;AAElC,SAAO,QAAQ,SAAS,OAAO,OAAO;SAClC;AACJ,SAAO;;;;;AC7Nf,SAAgB,6BACZ,KAQF;AACE,QAAO,2BAA2B;EAC9B,eAAe,EACX,MAAM,gBAAgB,KAAK,CAAC,iBAAiB,OAAO,CAAC,EACxD;EACD,MAAM,EACF,IAAI,gBAAgB,KAAK,CAAC,QAAQ,KAAK,CAAC,IAAI,KAAA,GAC/C;EACD,SAAS,EACL,MAAM,gBAAgB,KAAK,CAAC,WAAW,OAAO,CAAC,EAClD;EACD,QAAQ,EACJ,WAAW,gBAAgB,KAAK,CAAC,UAAU,YAAY,CAAC,IAAI,KAAA,GAC/D;EACJ,CAAC;;AAGN,eAAsB,8BAClB,KACA,QACA,OACa;CACb,MAAM,OAAO,aAAa,OAAO,SAAS;CAC1C,MAAM,kBAAkB,YAAY,KAAK,kBAAkB;CAC3D,MAAM,QAAQ,YAAY,KAAK,QAAQ;CACvC,MAAM,eAAe,gBAAgB,KAAK,CAAC,iBAAiB,OAAO,CAAC;AAEpE,KAAI;AACA,MAAI,OAAO,iBAAiB,YAAY,iBAAiB;AACrD,SAAM,gBAAgB,KAAK,KAAK,KAAK;AACrC;;AAGJ,MAAI,MACA,OAAM,MAAM,KAAK,KAAK,KAAK;UAE1B,YAAY;AACjB,SAAO,OACH;GACI,GAAG,6BAA6B,IAAI;GACpC,OAAO;GACV,EACD,oDACH;;;AAIT,SAAS,YAAY,OAAe,KAAgE;AAChG,KAAI,EAAE,OAAO,OACT,QAAO;CAGX,MAAM,YAAa,MAAkC;AAErD,QAAO,OAAO,cAAc,aACtB,YACA;;AAGV,SAAS,gBAAgB,OAAe,MAA+B;CACnE,MAAM,YAAY,eAAe,OAAO,KAAK;AAE7C,QAAO,OAAO,cAAc,WAAW,YAAY;;AAGvD,SAAS,gBAAgB,OAAe,MAA+B;CACnE,MAAM,YAAY,eAAe,OAAO,KAAK;AAE7C,QAAO,OAAO,cAAc,WAAW,YAAY;;AAGvD,SAAS,eAAe,OAAe,MAAyB;CAC5D,IAAI,UAAmB;AAEvB,MAAK,MAAM,WAAW,MAAM;AACxB,MAAI,CAAC,WAAW,OAAO,YAAY,YAAY,EAAE,WAAW,SACxD,QAAO;AAGX,YAAW,QAAoC;;AAGnD,QAAO;;;;ACrFX,eAAsB,gBAClB,aACA,QACoB;AACpB,KAAI,CAAC,OACD,QAAA;AAKJ,QAAO,sBAFS,MAAM,YAAY,YAAY,OAAO,GAEhB,SAAS;;AAUlD,eAAsB,oBAClB,aACA,QACA,QACoB;AACpB,KAAI;AACA,SAAO,MAAM,gBAAgB,aAAa,OAAO;UAC5C,OAAO;AACZ,UAAQ,OACJ;GACI;GACA,QAAQ,UAAU,KAAA;GACrB,EACD,+EACH;AACD,SAAA;;;AAIR,eAAsB,gBAClB,aACA,QACA,QACgB;AAChB,KAAI;AACA,SAAO,WAAW,MAAM,oBAAoB,aAAa,QAAQ,OAAO,CAAC;UACpE,OAAO;AACZ,UAAQ,OACJ;GACI;GACA,QAAQ,UAAU,KAAA;GACrB,EACD,sEACH;AACD,SAAO;;;AAIf,eAAsB,gBAClB,aACA,QACA,UACa;CACb,MAAM,UAAU,MAAM,YAAY,YAAY,OAAO;AAErD,OAAM,YAAY,WAAW;EACzB;EACA,WAAW,SAAS,aAAa;EACjC,WAAW,SAAS,aAAa;EACjC,WAAW,SAAS,aAAa;EACjC,WAAW,SAAS,aAAa;EACjC,iBAAiB,SAAS,mBAAmB;EAC7C,SAAS,SAAS,WAAW;EAC7B,cAAc,SAAS,gBAAgB;EACvC;EACA,4BAAW,IAAI,MAAM,EAAC,aAAa;EACtC,CAAC;;ACtEN,IAAM,2BAA2B;AAuBjC,SAAgB,oBACZ,QACA,eACA,OAAgB,UAClB;CACE,MAAM,OAAO,cAAc,QAAQ,cAAc;CACjD,MAAM,WAAW,sBACb,KAAK,OACL,KAAK,aACJ,GAAG,UAAU,cAAc,KAAK,aAAa,QAAQ,IACzD;AAED,yBAAwB,UAAU,KAAK,MAAM,KAAK,YAAY,cAAc,KAAK;AAEjF,QAAO;EAAE;EAAU;EAAM;;AAG7B,SAAgB,oBACZ,QACA,eACA,OAAgB,UAClB;CACE,MAAM,OAAO,cAAc,QAAQ,cAAc;CACjD,MAAM,WAAW,sBACb,KAAK,OACL,KAAK,aACJ,GAAG,UAAU,iBAAiB,KAAK,aAAa,QAAQ,IAC5D;AAED,yBAAwB,UAAU,KAAK,MAAM,KAAK,YAAY,eAAe,KAAK;AAElF,QAAO;EAAE;EAAU;EAAM;;AAG7B,SAAgB,sBACZ,UACA,eACA,OAAgB,UAClB;CACE,MAAM,OAAO,gBAAgB,UAAU,cAAc;CACrD,MAAM,WAAW,sBACb,KAAK,OACL,KAAK,aACJ,YAAY,iBAAiB,KAAK,KAAK,GAAG,QAAQ,KACtD;AAED,yBAAwB,UAAU,KAAK,MAAM,KAAK,YAAY,iBAAiB,KAAK;AAEpF,QAAO;EAAE;EAAU;EAAM;;AAG7B,SAAgB,2BACZ,WACA,MACA,OAAgB,UAClB;AACE,QAAO,IAAI,gBAAgB,CACtB,KAAK,KAAK,SAAS,cAAc,mBAAmB,KAAK,GAAG,YAAY,CACxE,KAAK,KAAK,SAAS,cAAc,mBAAmB,KAAK,GAAG,YAAY,CACxE,KAAK,CACL,KAAK,KAAK,SAAS,YAAY,iBAAiB,OAAO;;AAGhE,SAAgB,2BAA2B,UAAoB,YAAoB;AAC/E,QAAO,sBACH,UACA,IACC,GAAG,UAAU,iBAAiB,WAAW,GAAG,QAAQ,IACxD;;AAGL,SAAgB,sBAAsB,iBAA8B,OAAgB,UAAU;CAC1F,MAAM,WAAW,IAAI,gBAAgB;AAErC,yBAAwB,SAAS,UAAU,UAAU;EACjD,MAAM,QAAQ,oBAAoB,WAC5B,IAAI,iBAAiB,UAAU,KAAK,CAAC,KACrC,iBAAiB,UAAU,KAAK;AAEtC,WAAS,KAAK,OAAO,mBAAmB,WAAW;AAEnD,MAAI,UAAU,wBAAwB,SAAS,EAC3C,UAAS,KAAK;GAEpB;AAEF,QAAO;;AAGX,SAAgB,cAAc,QAAmC,eAAmC;AAChG,QAAO,cAAc,QAAQ,eAAA,GAAgC;;AAGjE,SAAgB,cAAc,QAAyB,eAAmC;AACtF,QAAO,cAAc,QAAQ,eAAA,GAAgC;;AAGjE,SAAgB,gBAAgB,UAA6B,eAAqC;AAC9F,QAAO,cAAc,UAAU,eAAA,GAAkC;;AAGrE,SAAS,sBACL,OACA,YACA,mBACF;CACE,MAAM,WAAW,IAAI,gBAAgB;AAErC,OAAM,SAAS,MAAM,UAAU;EAC3B,MAAM,eAAe,aAAa,QAAQ;AAE1C,WAAS,KAAK,GAAG,gBAAgB,kBAAkB,MAAM,MAAM,CAAC;AAEhE,MACI,UAAU,MAAM,SAAS,MACrB,QAAQ,KAAK,6BAA6B,EAE9C,UAAS,KAAK;GAEpB;AAEF,QAAO;;AAGX,SAAS,wBACL,UACA,MACA,YACA,QACA,MACF;AACE,KAAI,cAAc,EACd;AAGJ,KAAI,OAAO,EACP,UAAS,KAAK,KAAK,OAAO,cAAc,GAAG,OAAO,GAAG,OAAO,IAAI;AAGpE,KAAI,OAAO,aAAa,EACpB,UAAS,KAAK,KAAK,OAAO,UAAU,GAAG,OAAO,GAAG,OAAO,IAAI;;AAIpE,SAAS,cAAiB,OAAY,eAAuB,UAAkB;CAC3E,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,SAAS,SAAS,CAAC;CAClE,MAAM,OAAO,UAAU,eAAe,WAAW;CACjD,MAAM,aAAa,OAAO;AAE1B,QAAO;EACH,OAAO,MAAM,MAAM,YAAY,aAAa,SAAS;EACrD;EACA;EACA;EACH;;AAGL,SAAS,UAAU,MAAc,YAA4B;AACzD,KAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,EAClC,QAAO;AAGX,QAAO,KAAK,IAAI,MAAM,aAAa,EAAE;;;;ACpHzC,IAAM,gBAAgB;CAAC;CAAW;CAAQ;CAAO;CAAU;CAAQ;CAAS;CAAM;AAclF,SAAgB,qBAAqB,OAAwB,OAAgB,UAAkB;CAC3F,MAAM,SAAS,oBAAoB,KAAK;AASxC,QAAO,sBARU;EACb,0BAA0B,OAAO,eAAe,gCAAgC,OAAO,MAAM,OAAO,CAAC;EACrG,0BAA0B,OAAO,gBAAgB,iCAAiC,OAAO,MAAM,OAAO,CAAC;EACvG,0BAA0B,OAAO,cAAc,8BAA8B,OAAO,MAAM,OAAO,CAAC;EAClG,0BAA0B,OAAO,UAAU,2BAA2B,OAAO,MAAM,OAAO,CAAC;EAC3F,0BAA0B,OAAO,UAAU,2BAA2B,OAAO,MAAM,OAAO,CAAC;EAC9F,CAEqC;;AAG1C,SAAgB,6BAA6B,OAAwB,OAAgB,UAAkB;CACnG,MAAM,SAAS,oBAAoB,KAAK;AASxC,QAAO,sBARU;EACb,6BAA6B,OAAO,eAAe,mCAAmC,OAAO,MAAM,OAAO,CAAC;EAC3G,6BAA6B,OAAO,gBAAgB,oCAAoC,OAAO,MAAM,OAAO,CAAC;EAC7G,6BAA6B,OAAO,cAAc,iCAAiC,OAAO,MAAM,OAAO,CAAC;EACxG,6BAA6B,OAAO,UAAU,8BAA8B,OAAO,MAAM,OAAO,CAAC;EACjG,6BAA6B,OAAO,UAAU,8BAA8B,OAAO,MAAM,OAAO,CAAC;EACpG,CAEqC;;AAqC1C,SAAS,sBAAsB,UAA4B;AACvD,QAAO,SAAS,SAAS,SAAS,UAAU,UAAU,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,KAAK,KAAK;;AAGnG,SAAS,0BAA0B,OAAe,OAAyB;AACvE,QAAO,CACH,OACA,GAAG,MACN,CAAC,KAAK,KAAK;;AAGhB,SAAS,6BAA6B,OAAe,OAAyB;AAC1E,QAAO,CACH,MAAM,SACN,GAAG,MACN,CAAC,KAAK,KAAK;;AAGhB,SAAS,gCAAgC,OAAwB,MAAe,QAAoC;CAChH,MAAM,QAAQ,CACV,yBACI,OAAO,mBACP,MAAM,OAAO,WAAW,UAClB,OAAO,cACP,kBAAkB,MAAM,OAAO,KAAK,SAAS,OAAO,CAC7D,CACJ;AAED,KAAI,MAAM,OAAO,WAAW,QACxB,QAAO;EACH,GAAG;EACH,GAAG,mCAAmC,MAAM,OAAO,OAAO,MAAM,OAAO;EACvE,yBAAyB,OAAO,kBAAkB,sBAAsB;EAC3E;AAGL,QAAO;EACH,GAAG;EACH,yBAAyB,OAAO,sBAAsB,MAAM,OAAO,KAAK,QAAQ;EAChF,yBAAyB,OAAO,kBAAkB,sBAAsB;EAC3E;;AAGL,SAAS,mCAAmC,OAAwB,MAAe,QAAoC;CACnH,MAAM,QAAQ,CACV,4BACI,OAAO,mBACP,MAAM,OAAO,WAAW,UAClB,OAAO,cACP,kBAAkB,MAAM,OAAO,KAAK,SAAS,OAAO,CAC7D,CACJ;AAED,KAAI,MAAM,OAAO,WAAW,QACxB,QAAO;EACH,GAAG;EACH,GAAG,sCAAsC,MAAM,OAAO,OAAO,MAAM,OAAO;EAC1E,4BAA4B,OAAO,kBAAkB,sBAAsB;EAC9E;AAGL,QAAO;EACH,GAAG;EACH,4BAA4B,OAAO,sBAAsB,MAAM,OAAO,KAAK,QAAQ;EACnF,4BAA4B,OAAO,kBAAkB,sBAAsB;EAC9E;;AAGL,SAAS,iCAAiC,OAAwB,MAAe,QAAoC;AACjH,KAAI,MAAM,UAAU,WAAW,QAC3B,QAAO,6BAA6B,MAAM,UAAU,OAAO,MAAM,OAAO;AAG5E,QAAO,CACH,yBAAyB,OAAO,qBAAqB,MAAM,UAAU,KAAK,eAAe,EACzF,yBAAyB,OAAO,qBAAqB,MAAM,UAAU,KAAK,kBAAkB,OAAO,oBAAoB,CAC1H;;AAGL,SAAS,oCAAoC,OAAwB,MAAe,QAAoC;AACpH,KAAI,MAAM,UAAU,WAAW,QAC3B,QAAO,gCAAgC,MAAM,UAAU,OAAO,MAAM,OAAO;AAG/E,QAAO,CACH,4BAA4B,OAAO,qBAAqB,MAAM,UAAU,KAAK,gBAAgB,EACzF,WAAW,MACd,CAAC,EACF,4BAA4B,OAAO,qBAAqB,MAAM,UAAU,KAAK,kBAAkB,OAAO,oBAAoB,CAC7H;;AAGL,SAAS,8BAA8B,OAAwB,MAAe,QAAoC;AAC9G,KAAI,MAAM,QAAQ,WAAW,QACzB,QAAO,6BAA6B,MAAM,QAAQ,OAAO,MAAM,OAAO;AAG1E,KAAI,MAAM,QAAQ,KAAK,QAAQ,WAAW,EACtC,QAAO,CACH,GAAG,6BAA6B,OAAO,kBAAkB,OAAO,CACnE;AAGL,QAAO,MAAM,QAAQ,KAAK,QAAQ,KAAK,WAAW,KAAK,SAAS;;AAGpE,SAAS,iCAAiC,OAAwB,MAAe,QAAoC;AACjH,KAAI,MAAM,QAAQ,WAAW,QACzB,QAAO,gCAAgC,MAAM,QAAQ,OAAO,MAAM,OAAO;AAG7E,KAAI,MAAM,QAAQ,KAAK,QAAQ,WAAW,EACtC,QAAO,CACH,GAAG,gCAAgC,OAAO,kBAAkB,OAAO,CACtE;AAGL,QAAO,MAAM,QAAQ,KAAK,QAAQ,KAAK,WAAW,OAAO,OAAO,IAAI;;AAGxE,SAAS,2BAA2B,OAAwB,MAAe,QAAoC;AAC3G,KAAI,MAAM,IAAI,WAAW,QACrB,QAAO,6BAA6B,MAAM,IAAI,OAAO,MAAM,OAAO;AAGtE,KAAI,MAAM,IAAI,KAAK,SAAS,WAAW,EACnC,QAAO,6BAA6B,KAAK,IAAI,MAAM,OAAO;AAG9D,QAAO,MAAM,IAAI,KAAK,SAAS,SAAS,WAAW,wBAAwB,OAAO,MAAM,CACpF;EACI,OAAO,OAAO;EACd,OAAO,qBAAqB,OAAO;EACtC,CACJ,CAAC,CAAC;;AAGP,SAAS,8BAA8B,OAAwB,MAAe,QAAoC;AAC9G,KAAI,MAAM,IAAI,WAAW,QACrB,QAAO,gCAAgC,MAAM,IAAI,OAAO,MAAM,OAAO;AAGzE,KAAI,MAAM,IAAI,KAAK,SAAS,WAAW,EACnC,QAAO,gCAAgC,KAAK,IAAI,MAAM,OAAO;AAGjE,QAAO,MAAM,IAAI,KAAK,SAAS,SAAS,WAAW,2BAA2B,OAAO,MAAM,CACvF;EACI,OAAO,OAAO;EACd,OAAO,qBAAqB,OAAO;EACtC,CACJ,CAAC,CAAC;;AAGP,SAAS,2BAA2B,OAAwB,MAAe,QAAoC;AAC3G,KAAI,MAAM,IAAI,WAAW,QACrB,QAAO,6BAA6B,MAAM,IAAI,OAAO,MAAM,OAAO;AAGtE,KAAI,MAAM,IAAI,KAAK,SAAS,WAAW,EACnC,QAAO,6BAA6B,KAAK,IAAI,MAAM,OAAO;AAG9D,QAAO,MAAM,IAAI,KAAK,SAAS,SAAS,EAAE,MAAM,aAC5C,wBAAwB,MAAM,wBAAwB,QAAQ,MAAM,OAAO,CAAC,CAC/E;;AAGL,SAAS,8BAA8B,OAAwB,MAAe,QAAoC;AAC9G,KAAI,MAAM,IAAI,WAAW,QACrB,QAAO,gCAAgC,MAAM,IAAI,OAAO,MAAM,OAAO;AAGzE,KAAI,MAAM,IAAI,KAAK,SAAS,WAAW,EACnC,QAAO,gCAAgC,KAAK,IAAI,MAAM,OAAO;AAGjE,QAAO,MAAM,IAAI,KAAK,SAAS,SAAS,EAAE,MAAM,aAC5C,2BAA2B,MAAM,wBAAwB,QAAQ,MAAM,OAAO,EAAE,EAC5E,UAAU,MACb,CAAC,CACL;;AAGL,SAAS,6BAA6B,OAAgB,MAAe,QAAoC;AACrG,QAAO,CACH,yBAAyB,OAAO,aAAa,OAAO,YAAY,EAChE,GAAG,mCAAmC,OAAO,MAAM,OAAO,CAC7D;;AAGL,SAAS,mCAAmC,OAAgB,MAAe,QAAoC;AAG3G,QAFoB,iBAAiB,aAAa,OAAO,KAAK,CAAC,CAE5C,KAAK,SAAS,yBAAyB,OAAO,cAAc,KAAK,CAAC;;AAGzF,SAAS,gCAAgC,OAAgB,MAAe,QAAoC;AACxG,QAAO,CACH,4BAA4B,OAAO,aAAa,OAAO,YAAY,EACnE,GAAG,sCAAsC,OAAO,MAAM,OAAO,CAChE;;AAGL,SAAS,sCAAsC,OAAgB,MAAe,QAAoC;AAG9G,QAFoB,iBAAiB,aAAa,OAAO,KAAK,CAAC,CAE5C,KAAK,SAAS,4BAA4B,OAAO,cAAc,KAAK,CAAC;;AAG5F,SAAS,6BAA6B,SAAiB,QAAoC;AACvF,QAAO,CACH,yBAAyB,OAAO,aAAa,OAAO,WAAW,EAC/D,yBAAyB,OAAO,cAAc,QAAQ,CACzD;;AAGL,SAAS,gCAAgC,SAAiB,QAAoC;AAC1F,QAAO,CACH,4BAA4B,OAAO,aAAa,OAAO,WAAW,EAClE,4BAA4B,OAAO,cAAc,QAAQ,CAC5D;;AAGL,SAAS,wBAAwB,MAAc,SAAuC;AAClF,QAAO,CACH,KAAK,2BAA2B,KAAK,IACrC,GAAG,QAAQ,KAAK,WAAW,OAAO,OAAO,MAAM,IAAI,kBAAkB,OAAO,MAAM,GAAG,CACxF;;AAGL,SAAS,2BACL,MACA,SACA,UAEI,EAAE,EACE;AAKR,QAAO,CACH,KALiB,QAAQ,WACvB,KAAK,2BAA2B,KAAK,CAAC,MACtC,KAAK,2BAA2B,KAAK,CAAC,OAIxC,GAAG,QAAQ,KAAK,WAAW,OAAO,YAC5B,SAAS,OAAO,MAAM,QAAQ,kBAAkB,OAAO,MAAM,CAAC,MAC9D,SAAS,OAAO,MAAM,MAAM,kBAAkB,OAAO,MAAM,GAAG,CACvE;;AAGL,SAAS,yBAAyB,OAAe,OAAuB;AACpE,QAAO,KAAK,MAAM,IAAI,kBAAkB,MAAM;;AAGlD,SAAS,4BACL,OACA,OACA,UAEI,EAAE,EACA;AACN,QAAO,QAAQ,YACT,OAAO,MAAM,QAAQ,kBAAkB,MAAM,CAAC,MAC9C,OAAO,MAAM,MAAM,kBAAkB,MAAM;;AAGrD,SAAS,iBAAiB,MAAwB;AAC9C,QAAO,KACF,MAAM,KAAK,CACX,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,QAAQ,SAAS,KAAK,SAAS,EAAE;;AAG1C,SAAS,kBAAkB,SAAkB,QAAkC;AAC3E,QAAO,UAAU,OAAiB,OAAO;;AAG7C,SAAS,qBAAqB,QAAmC;AAC7D,SAAQ,OAAO,QAAf;EACI,KAAK,YACD,QAAO;EACX,KAAK,QACD,QAAO;;AAKf,QAFgC,OAAO;;AAK3C,SAAS,qBAAqB,QAA2B,QAAkC;AACvF,SAAQ,OAAO,QAAf;EACI,KAAK,YACD,QAAO;EACX,KAAK,WACD,QAAO;EACX,KAAK,aACD,QAAO;EACX,KAAK,SACD,QAAO,OAAO;EAClB,KAAK,4BACD,QAAO,OAAO;;AAKtB,QAFgC;;AAKpC,SAAS,wBACL,QACA,MACA,QACkB;CAClB,MAAM,QAAQ,qBAAqB,QAAQ,MAAM,OAAO;AAExD,QAAO,QACD,CACE;EACI,OAAO,OAAO;EACd,OAAO,qBAAqB,QAAQ,OAAO;EAC9C,EACD;EACI,OAAO,OAAO;EACd,OAAO;EACV,CACJ,GACC,CACE;EACI,OAAO,OAAO;EACd,OAAO,qBAAqB,QAAQ,OAAO;EAC9C,CACJ;;AAGT,SAAS,qBAAqB,QAA2B,MAAe,QAAyC;AAC7G,SAAQ,OAAO,QAAf;EACI,KAAK,YACD,QAAO;EACX,KAAK,WACD,QAAO;EACX,KAAK,aACD,QAAO,KAAK,IAAI;EACpB,KAAK,SACD,QAAO,OAAO;EAClB,KAAK,4BACD,QAAO,OAAO;;AAKtB,QAFgC;;AAKpC,SAAS,kBAAkB,OAAuB;CAC9C,MAAM,aAAa,MACd,QAAQ,UAAU,KAAK,CACvB,MAAM,KAAK,CACX,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,QAAQ,SAAS,KAAK,SAAS,EAAE,CACjC,KAAK,MAAM;AAEhB,QAAO,WAAW,SAAS,IAAI,aAAa;;AAGhD,SAAS,2BAA2B,OAAuB;AACvD,QAAO,kBAAkB,MAAM;;AAGnC,SAAS,oBAAoB,MAAiC;AAC1D,KAAI,KAAK,WAAW,KAChB,QAAO;EACH,mBAAmB;EACnB,qBAAqB;EACrB,qBAAqB;EACrB,qBAAqB;EACrB,cAAc;EACd,aAAa;EACb,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,+BAA+B;EAC/B,UAAU;EACV,kBAAkB;EAClB,YAAY;EACZ,sBAAsB;EACtB,eAAe;EACf,cAAc;EACd,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EACnB;AAGL,KAAI,KAAK,WAAW,KAChB,QAAO;EACH,mBAAmB;EACnB,qBAAqB;EACrB,qBAAqB;EACrB,qBAAqB;EACrB,cAAc;EACd,aAAa;EACb,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,+BAA+B;EAC/B,UAAU;EACV,kBAAkB;EAClB,YAAY;EACZ,sBAAsB;EACtB,eAAe;EACf,cAAc;EACd,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EACnB;AAGL,QAAO;EACH,mBAAmB;EACnB,qBAAqB;EACrB,qBAAqB;EACrB,qBAAqB;EACrB,cAAc;EACd,aAAa;EACb,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,+BAA+B;EAC/B,UAAU;EACV,kBAAkB;EAClB,YAAY;EACZ,sBAAsB;EACtB,eAAe;EACf,cAAc;EACd,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EACnB;;AAGL,SAAgB,uBAAuB,OAA6B,OAAgB,UAAkB;AAClG,KAAI,MAAM,SAAS,WAAW,EAC1B,QAAO,KAAK,SAAS;CAGzB,MAAM,OAAO,gBAAgB,MAAM,UAAU,MAAM,KAAK;CACxD,MAAM,iBAAiB,MAAM,mBACvB,MAAM,SAAS,MAAM,YAAY,QAAQ,OAAO,MAAM,iBAAiB,IAAI,OAC3E;AAUN,QATc;EACV,KAAK,SAAS;EACd,KAAK,SAAS,eAAe,MAAM,iBAAiB;EACpD,KAAK,SAAS,eAAe,iBAAiB,mBAAmB,eAAe,GAAG,KAAK,OAAO,YAAY;EAC3G,KAAK,OAAO,KAAK,KAAK,OAAO,GAAG,KAAK,WAAW;EAChD;EACA,GAAG,KAAK,MAAM,KAAK,SAAS,UAAU,GAAG,KAAK,aAAa,QAAQ,EAAE,IAAI,mBAAmB,QAAQ,GAAG;EAC1G,CAEY,KAAK,KAAK;;AAG3B,SAAgB,4BAA4B,SAA0B,OAAgB,UAAkB;AACpG,QAAO,CACH,KAAK,SAAS,UACd,KAAK,SAAS,eAAe,mBAAmB,QAAQ,CAAC,CAC5D,CAAC,KAAK,KAAK;;AAGhB,SAAgB,6BAA6B,SAA0B,OAAgB,UAAkB;AACrG,QAAO,CACH,KAAK,SAAS,SACd,KAAK,SAAS,eAAe,mBAAmB,QAAQ,CAAC,CAC5D,CAAC,KAAK,KAAK;;AAGhB,SAAgB,6BACZ,OACA,OAAgB,UACV;AACN,QAAO;EACH,KAAK,SAAS;EACd,KAAK,SAAS,eAAe,MAAM,iBAAiB;EACpD,KAAK,SAAS,gBAAgB,mBAAmB,MAAM,QAAQ,CAAC;EAChE;EACA,KAAK,SAAS;EACjB,CAAC,KAAK,KAAK;;AAGhB,SAAgB,kCAAkC,SAA0B,OAAgB,UAAkB;AAC1G,QAAO,KAAK,SAAS,aAAa,mBAAmB,QAAQ,CAAC;;AAGlE,SAAgB,6BAA6B,SAA0B,OAAgB,UAAkB;AACrG,QAAO,CACH,KAAK,SAAS,SACd,KAAK,SAAS,eAAe,mBAAmB,QAAQ,CAAC,CAC5D,CAAC,KAAK,KAAK;;AAGhB,SAAgB,qBAAqB,OAA2B,OAAgB,UAAkB;AAC9F,KAAI,MAAM,OAAO,WAAW,EACxB,QAAO,KAAK,OAAO;CAGvB,MAAM,OAAO,cAAc,MAAM,QAAQ,MAAM,KAAK;CACpD,MAAM,eAAe,MAAM,mBACrB,MAAM,OAAO,MAAM,UAAU,MAAM,SAAS,MAAM,iBAAiB,IAAI,OACvE;AASN,QARc;EACV,KAAK,OAAO;EACZ,KAAK,OAAO,QAAQ,eAAe,iBAAiB,aAAa,GAAG,KAAK,OAAO,gBAAgB;EAChG,KAAK,OAAO,KAAK,KAAK,OAAO,GAAG,KAAK,WAAW;EAChD;EACA,GAAG,KAAK,MAAM,KAAK,OAAO,UAAU,GAAG,KAAK,aAAa,QAAQ,EAAE,IAAI,iBAAiB,MAAM,GAAG;EACpG,CAEY,KAAK,KAAK;;AAG3B,SAAgB,0BAA0B,OAAsB,OAAgB,UAAkB;AAC9F,QAAO,CACH,KAAK,OAAO,UACZ,KAAK,OAAO,QAAQ,iBAAiB,MAAM,CAAC,CAC/C,CAAC,KAAK,KAAK;;AAGhB,SAAgB,qBAAqB,OAA2B,OAAgB,UAAkB;AAC9F,KAAI,MAAM,OAAO,WAAW,EACxB,QAAO,KAAK,OAAO;CAGvB,MAAM,OAAO,cAAc,MAAM,QAAQ,MAAM,KAAK;CACpD,MAAM,eAAe,MAAM,kBAAkB,MAAM,yBAC7C,MAAM,OAAO,MAAM,UACjB,MAAM,OAAO,MAAM,kBAAkB,MAAM,eAAe,MAAM,uBACnE,IAAI,OACH;CACN,MAAM,mBAAmB,eACnB,qBAAqB,cAAc,MAAM,qBAAqB,KAAK,GACnE,KAAK,OAAO;AAUlB,QATc;EACV,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,OAAO,QAAQ,iBAAiB;EACrC,KAAK,OAAO,KAAK,KAAK,OAAO,GAAG,KAAK,WAAW;EAChD;EACA,GAAG,KAAK,MAAM,KAAK,OAAO,UAAU,oBAAoB,OAAO,KAAK,aAAa,QAAQ,EAAE,CAAC;EAC/F,CAEY,KAAK,KAAK;;AAG3B,SAAgB,4BACZ,OACA,YACA,OAAgB,UACV;CACN,MAAM,WAAW,iBAAiB,MAAM;AAExC,KAAI,SAAS,WAAW,EACpB,QAAO,CACH,KAAK,OAAO,mBACZ,KAAK,OAAO,MAAM,iBAAiB,MAAM,CAAC,CAC7C,CAAC,KAAK,KAAK;AAWhB,QARc;EACV,KAAK,OAAO;EACZ,KAAK,OAAO,MAAM,iBAAiB,MAAM,CAAC;EAC1C,KAAK,OAAO,YAAY,WAAW;EACnC;EACA,GAAG,SAAS,KAAK,SAAS,UAAU,GAAG,QAAQ,EAAE,IAAI,UAAU;EAClE,CAEY,KAAK,KAAK;;AAG3B,SAAgB,0BACZ,OACA,SACA,OAAgB,UACV;AACN,QAAO;EACH,KAAK,OAAO;EACZ,KAAK,OAAO,QAAQ,iBAAiB,MAAM,CAAC;EAC5C,KAAK,OAAO,sBAAsB,WAAW,KAAK,OAAO,sBAAsB;EAClF,CAAC,KAAK,KAAK;;AAGhB,SAAgB,uBAAuB,iBAA8B,OAAgB,UAAkB;AACnG,QAAO;EACH,KAAK,SAAS;EACd,KAAK,SAAS,QAAQ,iBAAiB,iBAAiB,KAAK,CAAC;EAC9D;EACA,KAAK,SAAS;EACjB,CAAC,KAAK,KAAK;;AAGhB,SAAgB,6BAA6B,iBAA8B,OAAgB,UAAkB;AACzG,QAAO,CACH,KAAK,SAAS,UACd,KAAK,SAAS,QAAQ,iBAAiB,iBAAiB,KAAK,CAAC,CACjE,CAAC,KAAK,KAAK;;AAGhB,SAAgB,iBAAiB,OAA0C;AACvE,QAAO,OAAO,KAAK,MAAM,SAAS,CAC7B,MAAM,MAAM,UAAU,oBAAoB,MAAM,MAAM,CAAC;;AAGhE,SAAS,oBAAoB,MAAc,OAAuB;CAC9D,MAAM,YAAY,cAAc,QAAQ,KAAK;CAC7C,MAAM,aAAa,cAAc,QAAQ,MAAM;AAE/C,KAAI,cAAc,MAAM,eAAe,GACnC,QAAO,KAAK,cAAc,MAAM;AAGpC,KAAI,cAAc,GACd,QAAO;AAGX,KAAI,eAAe,GACf,QAAO;AAGX,QAAO,YAAY;;AAGvB,SAAS,iBAAiB,OAA8B;AACpD,QAAO,MAAM;;AAGjB,SAAS,oBAAoB,OAAgC,cAA8B;AACvF,QAAO,GAAG,aAAa,IAAI,iBAAiB,MAAM;;AAGtD,SAAS,qBACL,OACA,SACA,MACM;AACN,QAAO,GAAG,iBAAiB,MAAM,CAAC,KAAK,KAAK,OAAO,eAAe,WAAW,KAAK,OAAO,sBAAsB;;AAGnH,SAAS,iBAAiB,OAAwC;AAC9D,QAAO,GAAG,MAAM,aAAa,KAAK,MAAM;;AAG5C,SAAS,mBAAmB,SAAkC;CAC1D,MAAM,QAAQ,QAAQ,MAAM,MAAM,IAAI,QAAQ,QAAQ,QAAQ;AAE9D,QAAO,UAAU,QAAQ,OACnB,QACA,GAAG,MAAM,IAAI,QAAQ,KAAK;;;;AClyBpC,eAAsB,oBAAoB,KAA2B,cAA+B;CAChG,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;EACA,MAAM,SAAS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC;AAEF,MAAI,OAAO,OAAO,WAAW,GAAG;AAC5B,SAAM,IAAI,MAAM,KAAK,OAAO,KAAK;AACjC;;EAGJ,MAAM,EAAE,UAAU,SAAS,oBAAoB,OAAO,QAAQ,GAAG,KAAK;AAEtE,QAAM,IAAI,MACN,qBAAqB;GACjB,QAAQ,OAAO;GACf,kBAAkB,OAAO;GACzB,MAAM,KAAK;GACd,EAAE,KAAK,EACR,EACI,cAAc,UACjB,CACJ;UACI,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,wBAAwB;AAC7D,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,sBAAsB,KAA2B,cAA+B;AAC5F,KAAI,QAAQ,CAAC,UAAU,QAAQ,EAAE,OAAO,QAAQ;AAC5C,QAAM,oBAAoB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACnG;;;;AChBN,eAAsB,sBAClB,QACA,eACA,cACyB;CACzB,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,QAAQ,aAAa,OAAO;CACzF,MAAM,SAAS,MAAM,aAAa,oBAAoB,QAAQ,EAC1D,QACH,CAAC;AAEF,KAAI,OAAO,SAAS,WAAW,EAC3B,QAAO;EACH;EACA,kBAAkB,OAAO;EACzB,kBAAkB,OAAO;EACzB,MAAM;EACN,UAAU,EAAE;EACZ,MAAM,KAAK,SAAS;EACvB;CAGL,MAAM,EAAE,UAAU,SAAS,sBAAsB,OAAO,UAAU,eAAe,KAAK;AAEtF,QAAO;EACH;EACA,kBAAkB,OAAO;EACzB,kBAAkB,OAAO;EACzB;EACA,MAAM,KAAK;EACX,UAAU,OAAO;EACjB,MAAM,uBAAuB;GACzB,kBAAkB,OAAO;GACzB,kBAAkB,OAAO;GACzB,MAAM,KAAK;GACX,UAAU,OAAO;GACpB,EAAE,KAAK;EACX;;AAGL,eAAsB,uBAClB,QACA,eACA,WACA,cACF;CACE,MAAM,WAAW,MAAM,sBAAsB,QAAQ,eAAe,aAAa;CACjF,MAAM,UAAU,SAAS,SAAS,MAAM,SAAS,KAAK,OAAO,UAAU;AAEvE,KAAI,CAAC,QACD,QAAO;EACH,MAAM,SAAS;EACf,OAAO;EACV;AAGL,QAAO;EACH,MAAM,SAAS;EACf,OAAO;EACP,UAAU,2BAA2B,QAAQ,IAAI,SAAS,MAAM,SAAS,KAAK;EAC9E,MAAM,SAAS;EACf;EACA,MAAM,6BAA6B;GAC/B,kBAAkB,SAAS;GAC3B;GACH,EAAE,SAAS,KAAK;EACpB;;AAGL,eAAsB,2BAClB,KACA,QACA,WACA,eACA,cACF;CACE,MAAM,WAAW,MAAM,sBAAsB,QAAQ,eAAe,aAAa;AAEjF,KAAI,SAAS,SACT,OAAM,IAAI,gBAAgB,QAAQ,WAAW,SAAS,MAAM,EACxD,cAAc,SAAS,UAC1B,CAAC;KAEF,OAAM,IAAI,gBAAgB,QAAQ,WAAW,SAAS,KAAK;AAG/D,QAAO;;;;AC1FX,eAAsB,8BAClB,cACA,QAC0C;CAC1C,MAAM,SAAS,MAAM,aAAa,kBAAkB,YAAY,OAAO;AAEvE,QAAO,6BAA6B,OAAO,GAAG,SAAS;;AAG3D,eAAsB,4BAClB,KACA,cACgB;AAGhB,KAAI,CAFkB,MAAM,8BAA8B,cAAc,IAAI,KAAK,GAAG,CAGhF,QAAO;CAGX,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAC9F,OAAM,IAAI,MAAM,KAAK,SAAS,mBAAmB;AAEjD,QAAO;;AAGX,eAAsB,+BAClB,KACA,cACgB;CAChB,MAAM,gBAAgB,MAAM,8BAA8B,cAAc,IAAI,KAAK,GAAG;AAEpF,KAAI,CAAC,cACD,QAAO;CAGX,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;CAC9F,MAAM,QAAQ,IAAI,QAAQ,MAAM,MAAM,IAAI;AAE1C,KAAI,MAAM,WAAW,IAAI,EAAE;AACvB,QAAM,IAAI,MAAM,KAAK,SAAS,mBAAmB;AACjD,SAAO;;AAGX,KAAI,CAAC,OAAO;AACR,QAAM,IAAI,MAAM,KAAK,SAAS,YAAY;AAC1C,SAAO;;AAGX,KAAI;EACA,MAAM,SAAS,MAAM,aAAa,qBAAqB,QAAQ;GAC3D,QAAQ,IAAI,KAAK;GACjB,WAAW,cAAc;GACzB;GACH,CAAC;AAEF,QAAM,aAAa,kBAAkB,MAAM,IAAI,KAAK,GAAG;AAEvD,QAAM,8BAA8B,IAAI,KAAK,eAAe,aAAa;AAEzE,MAAI,CAAC,OAAO,OAAO;AACf,SAAM,IAAI,MAAM,KAAK,SAAS,cAAc;AAC5C,UAAO;;AAGX,QAAM,IAAI,MAAM,6BAA6B,OAAO,SAAS,KAAK,CAAC;UAC9D,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,2BAA2B;AAChE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;AAG9C,QAAO;;AAGX,eAAsB,2BAClB,KACA,cACgB;CAChB,MAAM,gBAAgB,MAAM,8BAA8B,cAAc,IAAI,KAAK,GAAG;AAEpF,KAAI,CAAC,cACD,QAAO;CAGX,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAC9F,OAAM,aAAa,kBAAkB,MAAM,IAAI,KAAK,GAAG;AACvD,OAAM,8BAA8B,IAAI,KAAK,eAAe,aAAa;AACzE,OAAM,IAAI,MAAM,KAAK,SAAS,gBAAgB;AAE9C,QAAO;;AAGX,eAAe,8BACX,KACA,eACA,cACF;AACE,KAAI;AACA,QAAM,2BACF,KACA,cAAc,QACd,cAAc,eACd,cAAc,YACd,aACH;UACI,OAAO;AACZ,eAAa,OAAO,OAAO,EAAE,OAAO,EAAE,0CAA0C;;;AAIxF,SAAS,6BAA6B,QAAwE;AAC1G,QAAO,QAAQ,SAAS;;;;ACpH5B,eAAsB,oBAAoB,KAA2B,cAA+B;CAChG,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;AACA,MAAI,MAAM,2BAA2B,KAAK,aAAa,CACnD;EAGJ,MAAM,SAAS,MAAM,aAAa,mBAAmB,QAAQ,EACzD,QAAQ,IAAI,KAAK,IACpB,CAAC;AAEF,MAAI,OAAO,WAAW,cAAc;AAChC,SAAM,IAAI,MAAM,KAAK,MAAM,UAAU;AACrC;;AAGJ,MAAI,OAAO,WAAW,eAAe;AACjC,SAAM,IAAI,MAAM,KAAK,MAAM,WAAW;AACtC;;AAGJ,QAAM,IAAI,MAAM,KAAK,MAAM,QAAQ;UAC9B,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,kCAAkC;AACvE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,sBAAsB,KAA2B,cAA+B;AAC5F,KAAI,QAAQ,UAAU,OAAO,QAAQ;AACjC,QAAM,oBAAoB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACnG;;;;AC7BN,eAAsB,sBAAsB,KAA6B,cAA+B;CACpG,MAAM,WAAW,MAAM,oBAAoB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;CACtG,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;AACA,QAAM,4BAA4B,IAAI,KAAK,IAAI,KAAK,IAAI,SAAS;AACjE,QAAM,IAAI,MACN,uBAAuB,UAAU,KAAK,EACtC,EACI,cAAc,sBAAsB,UAAU,KAAK,EACtD,CACJ;UACI,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,kCAAkC;AACvE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,eAAsB,sBAClB,KACA,QACA,UACA,cAQF;CACE,MAAM,cAAc,MAAM,gBAAgB,aAAa,aAAa,QAAQ,aAAa,OAAO;AAEhG,KAAI,CAAC,cAAc,SAAS,CACxB,QAAO;EACH,OAAO;EACP,MAAM;EACT;AAGL,OAAM,gBAAgB,aAAa,aAAa,QAAQ,SAAS;AACjE,OAAM,4BAA4B,KAAK,QAAQ,SAAS;AAExD,QAAO;EACH,OAAO;EACP,MAAM,MAAM,gBAAgB,aAAa,aAAa,QAAQ,aAAa,OAAO;EAClF;EACH;;AAGL,eAAsB,6BAClB,QACA,KACA,UACA,cACF;CACE,MAAM,SAAS,MAAM,sBAAsB,KAAK,QAAQ,UAAU,aAAa;AAE/E,KAAI,CAAC,OAAO,MACR,QAAO;EACH,OAAO;EACP,MAAM,OAAO;EACb,MAAM,OAAO,KAAK,SAAS;EAC3B,UAAU,sBACN,MAAM,oBAAoB,aAAa,aAAa,QAAQ,aAAa,OAAO,EAChF,OAAO,KACV;EACJ;AAGL,QAAO;EACH,OAAO;EACP,MAAM,OAAO;EACb,MAAM,6BAA6B,OAAO,UAAU,OAAO,KAAK;EAChE,UAAU,sBAAsB,OAAO,UAAU,OAAO,KAAK;EAChE;;AAGL,SAAgB,wBAAwB,KAA2B,cAA+B;AAC9F,KAAI,QAAQ,YAAY,OAAO,QAAQ;AACnC,QAAM,sBAAsB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACrG;;;;AC3FN,eAAsB,oBAAoB,KAA2B,cAA+B;CAChG,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;EACA,MAAM,SAAS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC;AAEF,MAAI,OAAO,OAAO,WAAW,GAAG;AAC5B,SAAM,IAAI,MAAM,KAAK,OAAO,KAAK;AACjC;;EAGJ,MAAM,EAAE,UAAU,SAAS,oBAAoB,OAAO,QAAQ,GAAG,KAAK;AAEtE,QAAM,IAAI,MACN,qBAAqB;GACjB,gBAAgB,OAAO;GACvB,wBAAwB,OAAO;GAC/B,qBAAqB,OAAO;GAC5B,QAAQ,OAAO;GACf,MAAM,KAAK;GACd,EAAE,KAAK,EACR,EACI,cAAc,UACjB,CACJ;UACI,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,wBAAwB;AAC7D,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,sBAAsB,KAA2B,cAA+B;AAC5F,KAAI,QAAQ,CAAC,SAAS,SAAS,EAAE,OAAO,QAAQ;AAC5C,QAAM,oBAAoB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACnG;;;;ACnCN,eAAsB,iBAAiB,KAAwB,cAA+B;CAC1F,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;EACA,MAAM,QAAQ,oBAAoB,IAAI;EACtC,MAAM,SAAS,MAAM,aAAa,qBAAqB,QAAQ;GAC3D,QAAQ,IAAI,KAAK;GACjB;GACH,CAAC;AAEF,QAAM,IAAI,MAAM,6BAA6B,OAAO,SAAS,KAAK,CAAC;UAC9D,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,+BAA+B;AACpE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,mBAAmB,KAA2B,cAA+B;AACzF,KAAI,QAAQ,OAAO,OAAO,QAAQ;AAC9B,QAAM,iBAAiB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GAChG;;AAGN,SAAS,oBAAoB,KAAuC;AAChE,KAAI,OAAO,IAAI,UAAU,UAAU;EAC/B,MAAM,QAAQ,IAAI,MAAM,MAAM;AAE9B,SAAO,QAAQ,QAAQ;;CAG3B,MAAM,cAAc,IAAI,SAAS,MAAM,MAAM;AAE7C,KAAI,CAAC,YACD,QAAO;CAIX,MAAM,QADQ,YAAY,MAAM,qCAAqC,GAC/C,IAAI,MAAM;AAEhC,QAAO,QAAQ,QAAQ;;;;AC9C3B,IAAM,8BAA8B;AACpC,IAAM,mBAAmB;AACzB,IAAM,8BAA8B;AAoBpC,SAAgB,yBACZ,QACA,OAAgB,UACG;CACnB,MAAM,mBAAmB,OAAO,SAAS,mCAAmC,OAAO,OAAO,GAAG;CAC7F,MAAM,cAAc,yBAAyB,OAAO,SAAS,KAAK;CAElE,MAAM,WAAW,EACb,MAAM,kBACF,kBAHU,mBAAmB,QAAQ,KAAK,EAGb,YAAY,EACzC,YACH,EACJ;AAED,KAAI,CAAC,iBACD,QAAO;EACH,WAAW;EACX;EACH;CAIL,MAAM,eAAe,kBAAkB,kBADhB,4BAA4B,OAAO,SAAS,KAAK,CACA;AAExE,KAAI,aAAa,SAAS,4BACtB,QAAO;EACH,WAAW;EACX;EACH;AAGL,QAAO;EACH,WAAW;GACP,MAAM;GACN,SAAS,EACL,YAAY,cACf;GACJ;EACD;EACH;;AAGL,SAAgB,yBAAyB,UAAuC;CAC5E,MAAM,mBAAmB,mCAAmC,SAAS;CAErE,MAAM,WAAW,EACb,MAFc,mBAAmB,yBAAyB,SAAS,IAAI,SAAS,MAAM,CAAC,EAG1F;AAED,KAAI,CAAC,oBAAoB,iBAAiB,SAAS,4BAC/C,QAAO;EACH,WAAW;EACX;EACH;AAGL,QAAO;EACH,WAAW;GACP,MAAM;GACN,SAAS,EACL,YAAY,cACf;GACJ;EACD;EACH;;AAGL,SAAgB,mCAAmC,UAAiC;CAChF,MAAM,qBAAqB,8BAA8B,SAAS,CAAC,MAAM;AAEzE,KAAI,CAAC,mBACD,QAAO;CAGX,MAAM,QAAQ,mBAAmB,MAAM,KAAK;CAC5C,MAAM,WAAqB,EAAE;CAC7B,IAAI,cAAc;CAClB,IAAI,oBAAoB;AAExB,MAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;EAClD,MAAM,OAAO,MAAM;EACnB,MAAM,aAAa,KAAK,MAAM,4BAA4B;AAE1D,MAAI,YAAY;AACZ,OAAI,aAAa;AACb,aAAS,KAAK,MAAM;AACpB,kBAAc;AACd,wBAAoB;UACjB;AACH,wBAAoB,WAAW,MAAM;AACrC,aAAS,KAAK,SAAS,oBAAoB;AAC3C,kBAAc;;AAGlB;;AAGJ,MAAI,aAAa;AACb,YAAS,KAAK,kBAAkB,KAAK,CAAC;AACtC;;AAGJ,MAAI,KAAK,SAAS,KAAK,CACnB,QAAO;EAGX,MAAM,aAAa,qBAAqB,OAAO,MAAM;AAErD,MAAI,YAAY;AACZ,YAAS,KAAK,+BAA+B,WAAW,KAAK,CAAC;AAC9D,WAAQ,WAAW,YAAY;AAC/B;;AAGJ,MAAI,mBAAmB,KAAK,KAAK,CAC7B,QAAO;AAGX,MAAI,CAAC,KAAK,MAAM,EAAE;AACd,YAAS,KAAK,GAAG;AACjB;;EAGJ,MAAM,eAAe,KAAK,MAAM,2BAA2B;AAE3D,MAAI,cAAc;AACd,YAAS,KAAK,IAAI,mBAAmB,aAAa,GAAG,MAAM,CAAC,CAAC,GAAG;AAChE;;EAGJ,MAAM,kBAAkB,KAAK,MAAM,gBAAgB;AAEnD,MAAI,iBAAiB;GACjB,MAAM,QAAQ,qBAAqB,gBAAgB,GAAG;AAEtD,OAAI,UAAU,KACV,QAAO;AAGX,YAAS,KAAK,IAAI,QAAQ,IAAI,UAAU,KAAK;AAC7C;;EAGJ,MAAM,qBAAqB,KAAK,MAAM,sBAAsB;AAE5D,MAAI,oBAAoB;GACpB,MAAM,OAAO,qBAAqB,mBAAmB,GAAG;AAExD,OAAI,SAAS,KACT,QAAO;AAGX,YAAS,KAAK,GAAG,mBAAmB,GAAG,MAAM,OAAO;AACpD;;EAGJ,MAAM,mBAAmB,KAAK,MAAM,0BAA0B;AAE9D,MAAI,kBAAkB;GAClB,MAAM,OAAO,qBAAqB,iBAAiB,GAAG;AAEtD,OAAI,SAAS,KACT,QAAO;AAGX,YAAS,KAAK,GAAG,iBAAiB,KAAK,iBAAiB,GAAG,MAAM,OAAO;AACxE;;EAGJ,MAAM,YAAY,qBAAqB,KAAK;AAE5C,MAAI,cAAc,KACd,QAAO;AAGX,WAAS,KAAK,UAAU;;AAG5B,KAAI,YACA,QAAO;AAGX,QAAO,SAAS,KAAK,KAAK;;AAG9B,SAAS,mBACL,QACA,MACM;CACN,MAAM,iBAAiB,OAAO,SAAS,yBAAyB,OAAO,OAAO,GAAG;CACjF,MAAM,eAAe,OAAO,aAAa,MAAM;AAG/C,SAFa,kBAAkB,cAEnB,MAAM,IAAI,OAAO,gBAAgB,KAAK,OAAO;;AAG7D,SAAS,kBAAkB,MAAc,QAAwB;CAC7D,MAAM,iBAAiB,OAAO,SAAS;CACvC,MAAM,gBAAgB,KAAK,IAAI,GAAG,8BAA8B,eAAe;AAE/E,KAAI,KAAK,UAAU,cACf,QAAO;AAGX,QAAO,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,gBAAgB,EAAwB,CAAC,GAAG;;AAGpF,SAAS,mBAAmB,MAAsB;AAC9C,KAAI,KAAK,UAAU,4BACf,QAAO;AAGX,QAAO,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,8BAA8B,EAAwB,CAAC,GAAG;;AAGlG,SAAS,kBAAkB,MAAc,QAAwB;AAC7D,QAAO,GAAG,KAAK,MAAM;;AAGzB,SAAS,8BAA8B,UAA0B;CAE7D,MAAM,QADqB,SAAS,QAAQ,UAAU,KAAK,CAC1B,MAAM,KAAK;CAC5C,MAAM,YAAsB,EAAE;CAC9B,IAAI,cAA2C;AAE/C,MAAK,MAAM,QAAQ,OAAO;EACtB,MAAM,aAAa,KAAK,MAAM,4BAA4B;AAE1D,MAAI,YAAY;GACZ,MAAM,YAAY,WAAW,MAAM,IAAI,aAAa;AAEpD,OAAI,gBAAgB,YAAY;AAC5B,kBAAc;AACd;;AAGJ,OAAI,gBAAgB,SAAS;AACzB,cAAU,KAAK,KAAK;AACpB,kBAAc;AACd;;AAGJ,OAAI,aAAa,QAAQ,aAAa,YAAY;AAC9C,kBAAc;AACd;;AAGJ,iBAAc;AACd,aAAU,KAAK,KAAK;AACpB;;AAGJ,YAAU,KAAK,KAAK;;AAGxB,QAAO,UAAU,KAAK,KAAK;;AAG/B,SAAS,yBAAyB,SAA+B,MAAuB;AACpF,QAAO,GAAG,KAAK,aAAa,cAAc,IAAI,eAAe,QAAQ,YAAY,KAAK,CAAC,KAAK,KAAK,aAAa,YAAY,IAAI,kBAAkB,QAAQ,OAAO,OAAO,KAAK;;AAG/K,SAAS,4BAA4B,SAA+B,MAAuB;AACvF,QAAO,mBAAmB,yBAAyB,SAAS,KAAK,CAAC;;AAGtE,SAAS,eAAe,YAA2B,MAAuB;AACtE,KAAI,eAAe,QAAQ,CAAC,OAAO,SAAS,WAAW,CACnD,QAAO,KAAK,aAAa;AAG7B,KAAI,aAAa,IACb,QAAO,GAAG,KAAK,MAAM,WAAW,CAAC;AAGrC,QAAO,IAAI,aAAa,KAAM,QAAQ,EAAE,CAAC;;AAG7C,SAAS,kBAAkB,OAAsB,MAAuB;AACpE,KAAI,UAAU,QAAQ,CAAC,OAAO,SAAS,MAAM,CACzC,QAAO,KAAK,aAAa;AAG7B,QAAO,GAAG,KAAK,MAAM,MAAM;;AAQ/B,SAAS,qBAAqB,OAAiB,YAA0C;AACrF,KAAI,aAAa,KAAK,MAAM,OACxB,QAAO;CAGX,MAAM,cAAc,sBAAsB,MAAM,YAAY;CAC5D,MAAM,iBAAiB,4BAA4B,MAAM,aAAa,GAAG;AAEzE,KAAI,CAAC,eAAe,CAAC,kBAAkB,YAAY,WAAW,eAAe,OACzE,QAAO;CAGX,MAAM,OAAO,CAAC,YAAY;CAC1B,IAAI,QAAQ,aAAa;AAEzB,QAAO,QAAQ,MAAM,QAAQ;EACzB,MAAM,WAAW,sBAAsB,MAAM,OAAO;AAEpD,MAAI,CAAC,YAAY,SAAS,WAAW,YAAY,OAC7C;AAGJ,OAAK,KAAK,SAAS;AACnB,WAAS;;AAGb,QAAO;EACH;EACA,WAAW;EACd;;AAGL,SAAS,sBAAsB,MAA+B;CAC1D,MAAM,UAAU,KAAK,MAAM;AAE3B,KAAI,CAAC,QAAQ,SAAS,IAAI,CACtB,QAAO;CAGX,MAAM,QAAQ,wBAAwB,QAAQ,CACzC,KAAK,SAAS,mBAAmB,KAAK,CAAC;AAE5C,QAAO,MAAM,UAAU,IAAI,QAAQ;;AAGvC,SAAS,4BAA4B,MAA+B;CAChE,MAAM,QAAQ,wBAAwB,KAAK,MAAM,CAAC;AAElD,KAAI,MAAM,SAAS,EACf,QAAO;AAGX,QAAO,MAAM,OAAO,SAAS,cAAc,KAAK,KAAK,MAAM,CAAC,CAAC,GACvD,QACA;;AAGV,SAAS,wBAAwB,MAAwB;CACrD,MAAM,UAAU,KACX,QAAQ,OAAO,GAAG,CAClB,QAAQ,OAAO,GAAG;CACvB,MAAM,QAAkB,EAAE;CAC1B,IAAI,UAAU;CACd,IAAI,UAAU;AAEd,MAAK,MAAM,QAAQ,SAAS;AACxB,MAAI,SAAS;AACT,cAAW;AACX,aAAU;AACV;;AAGJ,MAAI,SAAS,MAAM;AACf,aAAU;AACV,cAAW;AACX;;AAGJ,MAAI,SAAS,KAAK;AACd,SAAM,KAAK,QAAQ;AACnB,aAAU;AACV;;AAGJ,aAAW;;AAGf,OAAM,KAAK,QAAQ;AACnB,QAAO;;AAGX,SAAS,mBAAmB,MAAsB;AAC9C,QAAO,KACF,MAAM,CACN,QAAQ,SAAS,IAAI,CACrB,QAAQ,4BAA4B,UAAU,CAC9C,QAAQ,qBAAqB,KAAK,CAClC,QAAQ,kBAAkB,KAAK,CAC/B,QAAQ,cAAc,KAAK;;AAGpC,SAAS,+BAA+B,MAA0B;AAC9D,QAAO;EACH;EACA,GAAG,uBAAuB,KAAK,CAAC,KAAK,SAAS,kBAAkB,KAAK,CAAC;EACtE;EACH,CAAC,KAAK,KAAK;;AAGhB,SAAS,uBAAuB,MAA4B;CACxD,MAAM,eAAe,2BAA2B,KAAK;AAKrD,QAAO;EAJQ,eAAe,KAAK,IAAI,aAAa;EAClC,aAAa,KAAK,UAAU,IAAI,OAAO,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;EAG9D,GAFd,KAAK,MAAM,EAAE,CAAC,KAAK,QAAQ,eAAe,KAAK,aAAa,CAAC;EAEvC;;AAGvC,SAAS,2BAA2B,MAA4B;AAC5D,QAAO,KAAK,GAAG,KAAK,GAAG,gBACnB,KAAK,QAAQ,UAAU,QAAQ,KAAK,IAAI,UAAU,gBAAgB,IAAI,gBAAgB,GAAG,CAAC,EAAE,EAAE,CACjG;;AAGL,SAAS,eAAe,KAAe,cAAgC;AACnE,QAAO,IACF,KAAK,MAAM,UAAU,gBAAgB,MAAM,aAAa,UAAU,EAAE,CAAC,CACrE,KAAK,MAAM;;AAGpB,SAAS,gBAAgB,OAAe,aAA6B;CACjE,MAAM,UAAU,KAAK,IAAI,GAAG,cAAc,gBAAgB,MAAM,CAAC;AAEjE,QAAO,GAAG,QAAQ,IAAI,OAAO,QAAQ;;AAGzC,SAAS,gBAAgB,OAAuB;CAC5C,IAAI,QAAQ;AAEZ,MAAK,MAAM,QAAQ,MACf,UAAS,gBAAgB,KAAK,YAAY,EAAE,IAAI,EAAE,GAAG,IAAI;AAG7D,QAAO;;AAGX,SAAS,gBAAgB,WAA4B;AACjD,QAAO,aAAa,SAChB,aAAa,QACb,cAAc,QACd,cAAc,QACb,aAAa,SAAU,aAAa,SAAU,cAAc,SAC5D,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa,SACpC,aAAa,SAAU,aAAa;;AAI7C,SAAS,qBAAqB,OAA8B;CACxD,IAAI,SAAS;CACb,IAAI,SAAS;AAEb,QAAO,SAAS,MAAM,QAAQ;AAC1B,MAAI,MAAM,WAAW,MAAM,OAAO,CAC9B,QAAO;AAGX,MAAI,MAAM,WAAW,MAAM,OAAO,IAAI,MAAM,WAAW,MAAM,OAAO,EAAE;GAClE,MAAM,YAAY,MAAM,MAAM,QAAQ,SAAS,EAAE;GACjD,MAAM,eAAe,MAAM,QAAQ,WAAW,SAAS,EAAE;AAEzD,OAAI,eAAe,SAAS,GAAG;AAC3B,cAAU,IAAI,mBAAmB,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC;AACxE,aAAS,eAAe;AACxB;;;AAIR,MAAI,MAAM,YAAY,OAAO,MAAM,YAAY,KAAK;GAChD,MAAM,YAAY,MAAM;GACxB,MAAM,eAAe,MAAM,QAAQ,WAAW,SAAS,EAAE;AAEzD,OAAI,eAAe,SAAS,GAAG;AAC3B,cAAU,IAAI,mBAAmB,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC;AACxE,aAAS,eAAe;AACxB;;;AAIR,MAAI,MAAM,YAAY,KAAK;GACvB,MAAM,eAAe,MAAM,QAAQ,KAAK,SAAS,EAAE;AAEnD,OAAI,iBAAiB,GACjB,QAAO;AAGX,aAAU,KAAK,kBAAkB,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC;AACxE,YAAS,eAAe;AACxB;;AAGJ,MAAI,MAAM,YAAY,KAAK;GACvB,MAAM,YAAY,MAAM,MAAM,OAAO,CAAC,MAAM,6BAA6B;AAEzE,OAAI,CAAC,UACD,QAAO;AAGX,aAAU,IAAI,mBAAmB,UAAU,GAAG,CAAC,IAAI,sBAAsB,UAAU,GAAG,CAAC;AACvF,aAAU,UAAU,GAAG;AACvB;;AAGJ,YAAU,mBAAmB,MAAM,QAAQ;AAC3C,YAAU;;AAGd,QAAO;;AAGX,SAAS,mBAAmB,MAAsB;AAC9C,QAAO,KAAK,QAAQ,6BAA6B,OAAO;;AAG5D,SAAS,kBAAkB,MAAsB;AAC7C,QAAO,KACF,QAAQ,OAAO,OAAO,CACtB,QAAQ,MAAM,MAAM;;AAG7B,SAAS,sBAAsB,KAAqB;AAChD,QAAO,IACF,QAAQ,OAAO,OAAO,CACtB,QAAQ,OAAO,MAAM,CACrB,QAAQ,OAAO,MAAM;;;;ACxhB9B,eAAsB,oBAAoB,KAA2B,cAA+B;CAChG,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,MAAM,IAAI,aAAa,OAAO;AAE/F,KAAI;EACA,MAAM,SAAS,MAAM,aAAa,iBAAiB,QAAQ,EACvD,QAAQ,IAAI,MAAM,MAAM,GAC3B,CAAC;EAEF,MAAM,mBAAmB,mCAAmC,6BAA6B,QAAQ,KAAK,CAAC;AAEvG,MAAI,kBAAkB;AAClB,SAAM,IAAI,MAAM,kBAAkB,EAAE,YAAY,cAAc,CAAC;AAC/D;;AAGJ,QAAM,IAAI,MAAM,qBAAqB,QAAQ,KAAK,CAAC;UAC9C,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,gCAAgC;AACrE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,sBAAsB,KAA2B,cAA+B;AAC5F,KAAI,QAAQ,UAAU,OAAO,QAAQ;AACjC,QAAM,oBAAoB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACnG;;;;AClCN,eAAsB,sBAAsB,KAA6B,cAA+B;CACpG,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;AACA,QAAM,aAAa,kBAAkB,MAAM,IAAI,KAAK,GAAG;EACvD,MAAM,OAAO,MAAM,sBAAsB,IAAI,KAAK,IAAI,GAAG,aAAa;AAEtE,QAAM,IAAI,MAAM,KAAK,MAAM,KAAK,WAAW,EAAE,cAAc,KAAK,UAAU,GAAG,KAAA,EAAU;UAClF,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,0BAA0B;AAC/D,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,wBAAwB,KAA2B,cAA+B;AAC9F,KAAI,QAAQ,YAAY,OAAO,QAAQ;AACnC,QAAM,sBAAsB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACrG;;;;AC3BN,SAAgB,4BAA4B,OAAgB,UAAkB;AAC1E,QAAO,KAAK,MAAM,MAAM,KAAK,KAAK;;;;ACetC,eAAsB,mBAAmB,KAA0B,cAA+B;CAC9F,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,MAAM,IAAI,aAAa,OAAO;CAC/F,MAAM,QAAQ,yBAAyB,4BAA4B,KAAK,CAAC;AAEzE,KAAI;AACA,QAAM,IAAI,MAAM,MAAM,UAAU,MAAM,MAAM,UAAU,QAAQ;UACzD,OAAO;AACZ,MAAI,MAAM,UAAU,SAAS;AACzB,gBAAa,OAAO,MAAM,EAAE,OAAO,EAAE,kEAAkE;AACvG,SAAM,IAAI,MAAM,MAAM,SAAS,KAAK;AACpC;;AAGJ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,+BAA+B;AACpE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;;;AAIlD,SAAgB,qBAAqB,KAA2B,cAA+B;AAC3F,KAAI,QAAQ,SAAS,OAAO,QAAQ;AAChC,QAAM,mBAAmB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GAClG;;;;ACKN,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAC/B,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAC/B,IAAM,oBAAoB;AAe1B,eAAsB,qBAAqB,KAAsB,cAA+B;CAC5F,MAAM,OAAO,IAAI,cAAc;AAE/B,KAAI,CAAC,KAAK,WAAW,UAAU,CAC3B;AAGJ,OAAM,IAAI,qBAAqB;AAE/B,KAAI,CAAC,IAAI,KACL;CAGJ,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;AACA,MAAI,KAAK,WAAW,mBAAmB,EAAE;GACrC,MAAM,gBAAgB,OAAO,KAAK,MAAM,GAA0B,CAAC;GACnE,MAAM,SAAS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC;AAEF,OAAI,OAAO,OAAO,WAAW,GAAG;AAC5B,UAAM,IAAI,gBAAgB,KAAK,OAAO,KAAK;AAC3C;;GAGJ,MAAM,EAAE,UAAU,SAAS,oBAAoB,OAAO,QAAQ,eAAe,KAAK;AAElF,SAAM,IAAI,gBACN,qBAAqB;IACjB,QAAQ,OAAO;IACf,kBAAkB,OAAO;IACzB,MAAM,KAAK;IACd,EAAE,KAAK,EACR,EACI,cAAc,UACjB,CACJ;AAED;;AAGJ,MAAI,KAAK,WAAW,qBAAqB,EAAE;GACvC,MAAM,aAAa,OAAO,KAAK,MAAM,GAA4B,CAAC;GAIlE,MAAM,SAHS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC,EACmB,OAAO,aAAa;AAEzC,OAAI,CAAC,OAAO;AACR,UAAM,IAAI,gBAAgB,KAAK,OAAO,QAAQ;AAC9C;;GAGJ,MAAM,eAAe,MAAM,aAAa,mBAAmB,QAAQ;IAC/D,QAAQ,IAAI,KAAK;IACjB,WAAW,MAAM;IACpB,CAAC;AAEF,OAAI,CAAC,aAAa,OAAO;AACrB,UAAM,IAAI,gBAAgB,KAAK,OAAO,QAAQ;AAC9C;;AAGJ,SAAM,IAAI,gBAAgB,0BAA0B,aAAa,OAAO,KAAK,CAAC;;UAE7E,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,kCAAkC;AACvE,QAAM,IAAI,gBAAgB,aAAa,OAAO,KAAK,CAAC;;;AAI5D,eAAsB,qBAAqB,KAAsB,cAA+B;CAC5F,MAAM,OAAO,IAAI,cAAc;AAE/B,KAAI,CAAC,KAAK,WAAW,SAAS,CAC1B;AAGJ,OAAM,IAAI,qBAAqB;AAE/B,KAAI,CAAC,IAAI,KACL;CAGJ,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;AACA,MAAI,KAAK,WAAW,kBAAkB,EAAE;GACpC,MAAM,gBAAgB,OAAO,KAAK,MAAM,GAAyB,CAAC;GAClE,MAAM,SAAS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC;AAEF,OAAI,OAAO,OAAO,WAAW,GAAG;AAC5B,UAAM,IAAI,gBAAgB,KAAK,OAAO,KAAK;AAC3C;;GAGJ,MAAM,EAAE,UAAU,SAAS,oBAAoB,OAAO,QAAQ,eAAe,KAAK;AAElF,SAAM,IAAI,gBACN,qBAAqB;IACjB,gBAAgB,OAAO;IACvB,wBAAwB,OAAO;IAC/B,qBAAqB,OAAO;IAC5B,QAAQ,OAAO;IACf,MAAM,KAAK;IACd,EAAE,KAAK,EACR,EACI,cAAc,UACjB,CACJ;AAED;;AAGJ,MAAI,KAAK,WAAW,kBAAkB,EAAE;GACpC,MAAM,aAAa,OAAO,KAAK,MAAM,GAAyB,CAAC;GAI/D,MAAM,SAHS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC,EACmB,OAAO,aAAa;AAEzC,OAAI,CAAC,OAAO;AACR,UAAM,IAAI,gBAAgB,KAAK,OAAO,QAAQ;AAC9C;;GAGJ,MAAM,WAAW,iBAAiB,MAAM;AAExC,OAAI,SAAS,WAAW,GAAG;IACvB,MAAM,eAAe,MAAM,aAAa,mBAAmB,QAAQ;KAC/D,QAAQ,IAAI,KAAK;KACjB,YAAY,MAAM;KAClB,SAAS,MAAM;KAClB,CAAC;AAEF,QAAI,CAAC,aAAa,OAAO;AACrB,WAAM,IAAI,gBAAgB,KAAK,OAAO,QAAQ;AAC9C;;AAGJ,UAAM,IAAI,gBAAgB,0BAA0B,aAAa,OAAO,aAAa,SAAS,KAAK,CAAC;AACpG;;AAGJ,SAAM,IAAI,gBACN,4BAA4B,OAAO,YAAY,KAAK,EACpD,EACI,cAAc,2BAA2B,UAAU,WAAW,EACjE,CACJ;AAED;;AAGJ,MAAI,KAAK,WAAW,qBAAqB,EAAE;GAEvC,MAAM,CAAC,eAAe,mBADP,KAAK,MAAM,GAA4B,CACN,MAAM,IAAI;GAC1D,MAAM,aAAa,OAAO,cAAc;GACxC,MAAM,eAAe,OAAO,gBAAgB;GAI5C,MAAM,SAHS,MAAM,aAAa,kBAAkB,QAAQ,EACxD,QAAQ,IAAI,KAAK,IACpB,CAAC,EACmB,OAAO,aAAa;AAEzC,OAAI,CAAC,OAAO;AACR,UAAM,IAAI,gBAAgB,KAAK,OAAO,QAAQ;AAC9C;;GAIJ,MAAM,UADW,iBAAiB,MAAM,CACf,eAAe;AAExC,OAAI,CAAC,SAAS;AACV,UAAM,IAAI,gBAAgB,KAAK,OAAO,sBAAsB;AAC5D;;GAGJ,MAAM,eAAe,MAAM,aAAa,mBAAmB,QAAQ;IAC/D,QAAQ,IAAI,KAAK;IACjB,YAAY,MAAM;IAClB,SAAS,MAAM;IACf;IACH,CAAC;AAEF,OAAI,CAAC,aAAa,OAAO;AACrB,UAAM,IAAI,gBAAgB,KAAK,OAAO,QAAQ;AAC9C;;AAGJ,SAAM,IAAI,gBAAgB,0BAA0B,aAAa,OAAO,aAAa,SAAS,KAAK,CAAC;;UAEnG,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,kCAAkC;AACvE,QAAM,IAAI,gBAAgB,aAAa,OAAO,KAAK,CAAC;;;AAI5D,eAAsB,uBAAuB,KAAsB,cAA+B;CAC9F,MAAM,OAAO,IAAI,cAAc;AAE/B,KAAI,CAAC,KAAK,WAAW,YAAY,CAC7B;AAGJ,OAAM,IAAI,qBAAqB;AAE/B,KAAI,CAAC,IAAI,KACL;CAGJ,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAE9F,KAAI;AACA,MAAI,KAAK,WAAW,qBAAqB,EAAE;GACvC,MAAM,gBAAgB,OAAO,KAAK,MAAM,GAA4B,CAAC;GACrE,MAAM,OAAO,MAAM,sBAAsB,IAAI,KAAK,IAAI,eAAe,aAAa;AAElF,SAAM,IAAI,gBAAgB,KAAK,MAAM,KAAK,WAAW,EAAE,cAAc,KAAK,UAAU,GAAG,KAAA,EAAU;AAEjG;;AAGJ,MAAI,KAAK,WAAW,qBAAqB,EAAE;GACvC,MAAM,gBAAgB,OAAO,KAAK,MAAM,GAA4B,CAAC;GACrE,MAAM,OAAO,MAAM,sBAAsB,IAAI,KAAK,IAAI,eAAe,aAAa;AAElF,SAAM,IAAI,gBAAgB,KAAK,MAAM,KAAK,WAAW,EAAE,cAAc,KAAK,UAAU,GAAG,KAAA,EAAU;AACjG;;AAGJ,MAAI,KAAK,WAAW,qBAAqB,EAAE;GACvC,MAAM,SAAS,yBAAyB,MAAM,qBAAqB;AAEnE,OAAI,CAAC,QAAQ;AACT,UAAM,IAAI,gBAAgB,KAAK,SAAS,QAAQ;AAChD;;GAGJ,MAAM,OAAO,MAAM,uBACf,IAAI,KAAK,IACT,OAAO,MACP,OAAO,WACP,aACH;AAED,OAAI,CAAC,KAAK,OAAO;AACb,UAAM,IAAI,gBAAgB,KAAK,SAAS,QAAQ;AAChD;;AAGJ,SAAM,IAAI,gBAAgB,KAAK,MAAM,EACjC,cAAc,KAAK,UACtB,CAAC;AACF;;AAGJ,MAAI,KAAK,WAAW,uBAAuB,EAAE;GACzC,MAAM,SAAS,yBAAyB,MAAM,uBAAuB;AAErE,OAAI,CAAC,QAAQ;AACT,UAAM,IAAI,gBAAgB,KAAK,SAAS,QAAQ;AAChD;;GAGJ,MAAM,SAAS,MAAM,aAAa,qBAAqB,QAAQ;IAC3D,QAAQ,IAAI,KAAK;IACjB,WAAW,OAAO;IACrB,CAAC;AAEF,OAAI,CAAC,OAAO,OAAO;AACf,UAAM,IAAI,gBAAgB,KAAK,SAAS,QAAQ;AAChD;;AAGJ,SAAM,IAAI,gBAAgB,4BAA4B,OAAO,SAAS,KAAK,CAAC;AAC5E;;AAGJ,MAAI,KAAK,WAAW,uBAAuB,EAAE;GACzC,MAAM,SAAS,yBAAyB,MAAM,uBAAuB;AAErE,OAAI,CAAC,QAAQ;AACT,UAAM,IAAI,gBAAgB,KAAK,SAAS,cAAc;AACtD;;GAGJ,MAAM,OAAO,MAAM,uBACf,IAAI,KAAK,IACT,OAAO,MACP,OAAO,WACP,aACH;AAED,OAAI,CAAC,KAAK,OAAO;AACb,UAAM,IAAI,gBAAgB,KAAK,SAAS,cAAc;AACtD;;GAGJ,MAAM,gBAAgB,IAAI,cAAc,SAAS;AAEjD,OAAI,OAAO,kBAAkB,YAAY,CAAC,OAAO,UAAU,cAAc,EAAE;AACvE,UAAM,IAAI,gBAAgB,KAAK,SAAS,cAAc;AACtD;;AAGJ,SAAM,aAAa,kBAAkB,IAAI;IACrC,QAAQ,IAAI,KAAK;IACjB,MAAM;IACN,WAAW,KAAK,QAAQ;IACxB;IACA,YAAY,KAAK;IACjB,4BAAW,IAAI,MAAM,EAAC,aAAa;IACtC,CAAC;AAEF,SAAM,IAAI,gBAAgB,kCAAkC,KAAK,SAAS,KAAK,CAAC;;UAE/E,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,oCAAoC;AACzE,QAAM,IAAI,gBAAgB,aAAa,OAAO,KAAK,CAAC;;;AAI5D,eAAsB,uBAAuB,KAAsB,cAA+B;CAC9F,MAAM,OAAO,IAAI,cAAc;AAE/B,KAAI,CAAC,KAAK,WAAW,YAAY,CAC7B;AAGJ,OAAM,IAAI,qBAAqB;AAE/B,KAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,IAClB;CAGJ,MAAM,cAAc,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAErG,KAAI;AACA,MAAI,CAAC,KAAK,WAAW,uBAAuB,EAAE;AAC1C,SAAM,IAAI,gBACN,uBACI,MAAM,oBAAoB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO,EACrF,YACH,EACD,EACI,cAAc,sBACV,MAAM,oBAAoB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO,EACrF,YACH,EACJ,CACJ;AACD;;EAGJ,MAAM,mBAAmB,KAAK,MAAM,GAA8B;EAClE,MAAM,SAAS,MAAM,6BAA6B,IAAI,KAAK,IAAI,IAAI,KAAK,kBAAkB,aAAa;AAEvG,QAAM,IAAI,gBAAgB,OAAO,MAAM,EACnC,cAAc,OAAO,UACxB,CAAC;UACG,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,qCAAqC;AAC1E,QAAM,IAAI,gBAAgB,aAAa,OAAO,YAAY,CAAC;;;AAInE,eAAsB,iCAClB,KACA,cACF;CACE,MAAM,OAAO,IAAI,cAAc;AAE/B,KAAI,CAAC,KAAK,WAAW,kBAAkB,CACnC;AAGJ,OAAM,IAAI,qBAAqB;AAE/B,KAAI,CAAC,IAAI,KACL;CAGJ,MAAM,SAAS,oCAAoC,KAAK;AAExD,KAAI,CAAC,OACD;AAGJ,KAAI;EAEA,MAAM,YADY,MAAM,aAAa,uBAAuB,gBAAgB,OAAO,UAAU,EAClE,MAAM,SAAS,KAAK,WAAW,IAAI,MAAM,GAAG;AAEvE,QAAM,aAAa,eAAe,kBAC9B,OAAO,WACP,OAAO,OACP,KAAA,GACA,UAAU,UACb;AAED,MAAI,SACA,OAAM,aAAa,uBAAuB,IAAI;GAC1C,GAAG;GACH,QAAQ,OAAO;GACf,4BAAW,IAAI,MAAM,EAAC,aAAa;GACtC,CAAC;AAGN,QAAM,IAAI,gBAAgB,uCAAuC,OAAO,WAAW,OAAO,MAAM,CAAC;UAC5F,OAAO;AACZ,eAAa,OAAO,MAAM;GAAE;GAAO,WAAW,OAAO;GAAW,EAAE,wCAAwC;AAC1G,QAAM,IAAI,gBAAgB,6CAA6C;;;AAI/E,SAAgB,wBAAwB,KAAiC,cAA8C;AACnH,KAAI,cAAc,YAAY,OAAO,QAAQ;AACzC,QAAM,qBAAqB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACpG;AAEF,KAAI,cAAc,cAAc,OAAO,QAAQ;AAC3C,QAAM,uBAAuB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACtG;AAEF,KAAI,cAAc,WAAW,OAAO,QAAQ;AACxC,QAAM,qBAAqB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACpG;AAEF,KAAI,cAAc,cAAc,OAAO,QAAQ;AAC3C,QAAM,uBAAuB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACtG;AAEF,KAAI,cAAc,gBAAgB,OAAO,QAAQ;AAC7C,QAAM,iCAAiC,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GAChH;;AAGN,SAAS,yBAAyB,MAAc,QAAgB;CAC5D,MAAM,SAAS,KAAK,MAAM,OAAO,OAAO;CACxC,MAAM,iBAAiB,OAAO,QAAQ,IAAI;AAE1C,KAAI,mBAAmB,GACnB,QAAO;CAGX,MAAM,OAAO,OAAO,OAAO,MAAM,GAAG,eAAe,CAAC;CACpD,MAAM,YAAY,OAAO,MAAM,iBAAiB,EAAE,CAAC,MAAM;AAEzD,KAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,CAAC,UACxC,QAAO;AAGX,QAAO;EACH;EACA;EACH;;;;ACzfL,eAAsB,qBAClB,KACA,cACA,eACF;CACE,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;CAC9F,MAAM,oBAAoB,aAAa,yBAAyB,QAAQ,IAAI,KAAK,GAAG;AAEpF,KAAI,CAAC,mBAAmB;AACpB,QAAM,IAAI,MAAM,KAAK,OAAO,kBAAkB;AAC9C;;CAGJ,IAAI,oBAAwC;CAC5C,IAAI,oBAAoB;AAExB,KAAI;AACA,sBAAoB,MAAM,IAAI,MAAM,KAAK,OAAO,WAAW;EAE3D,MAAM,cAAc,MAAM,eAAe;EAWzC,MAAM,gBAAgB,yBADF,gCATL,MAAM,aAAa,kBAAkB,QAAQ;GACxD,QAAQ,IAAI,KAAK;GACjB,OAAO,YAAY;GACnB,qBAAqB,cAAsB;AACvC,sBAAkB,cAAc,UAAU;;GAE9C,QAAQ,kBAAkB;GAC1B,MAAM,YAAY;GACrB,CAAC,EACwD,gBAAgB,KAAK,EACnB,KAAK;AAEjE,MAAI;AACA,SAAM,IAAI,MAAM,cAAc,UAAU,MAAM,cAAc,UAAU,QAAQ;WACzE,YAAY;AACjB,gBAAa,OAAO,OAChB,EAAE,OAAO,YAAY,EACrB,sEACH;AACD,SAAM,IAAI,MAAM,cAAc,SAAS,MAAM,cAAc,SAAS,QAAQ;;AAEhF,sBAAoB;UACf,OAAO;AACZ,eAAa,OAAO,MAAM,EAAE,OAAO,EAAE,kCAAkC;AACvE,QAAM,IAAI,MAAM,aAAa,OAAO,KAAK,CAAC;AAC1C,sBAAoB;WACd;AACN,oBAAkB,SAAS;AAC3B,MAAI,qBAAqB,kBACrB,KAAI;AACA,SAAM,IAAI,IAAI,cAAc,IAAI,KAAK,IAAI,kBAAkB,WAAW;WACjE,OAAO;AACZ,gBAAa,OAAO,OAAO,EAAE,OAAO,EAAE,sCAAsC;;;;AAM5F,SAAS,+BACL,aACA,MACF;AACE,KAAI,CAAC,YAAY,eACb,QAAO;AAGX,QAAO;EACH,GAAG;EACH,QAAQ;EACR,cAAc,aAAa,YAAY,gBAAgB,KAAK;EAC/D;;;;ACtFL,IAAM,8BAA8B,KAAK,OAAO;AAuBhD,eAAsB,mBAAmB,KAAkB,cAA+B;CACtF,MAAM,QAAQ,qBAAqB,IAAI,QAAQ;AAE/C,KAAI,CAAC,MACD;AAGJ,KAAI,MAAM,4BAA4B,KAAK,aAAa,CACpD;AAGJ,OAAM,qBAAqB,KAAK,cAAc,YAAY;AACtD,MAAI,OAAO,MAAM,aAAa,YAAY,MAAM,WAAW,4BACvD,OAAM,IAAI,6BACN,mBAAmB,MAAM,SAAS,0CAA0C,4BAA4B,SAC3G;EAIL,MAAM,YADO,MAAM,IAAI,SAAS,EACV,WAAW,MAAM;AAEvC,MAAI,CAAC,SACD,OAAM,IAAI,6BAA6B,2DAA2D;AAUtG,SAAO;GACH,OAAO,CARQ,MAAM,aAAa,kBAAkB,QAAQ;IAC5D,cAAc;IACd;IACA,UAAU,MAAM;IAChB,UAAU,MAAM;IACnB,CAAC,CAGqB;GACnB,MAAM,IAAI,QAAQ,SAAS,MAAM,IAAI;GACxC;GACH;;AAGN,SAAgB,oBAAoB,KAAsB,cAA+B;AACrF,KAAI,GAAG,iBAAiB,OAAO,QAAQ;AACnC,QAAM,mBAAmB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GAClG;AAEF,KAAI,GAAG,oBAAoB,OAAO,QAAQ;AACtC,QAAM,mBAAmB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GAClG;;AAGN,SAAS,qBAAqB,SAAiC;CAC3D,MAAM,WAAW,QAAQ;AAEzB,KAAI,YAAY,gBAAgB,SAAS,CACrC,QAAO;EACH,QAAQ,SAAS;EACjB,UAAU,SAAS;EACnB,UAAU,SAAS,aAAa;EAChC,UAAU,SAAS,aAAa;EACnC;CAGL,MAAM,QAAQ,iBAAiB,QAAQ,MAAM;AAE7C,KAAI,CAAC,MACD,QAAO;AAGX,QAAO;EACH,QAAQ,MAAM;EACd,UAAU,MAAM;EAChB,UAAU;EACV,UAAU;EACb;;AAGL,SAAS,gBAAgB,UAAqC;CAC1D,MAAM,WAAW,SAAS,WAAW,MAAM,CAAC,aAAa;CACzD,MAAM,WAAW,SAAS,WAAW,MAAM,CAAC,aAAa,IAAI;AAE7D,QAAO,CAAC,CAAC,UAAU,WAAW,SAAS,IAChC,mCAAmC,KAAK,SAAS;;AAG5D,SAAS,iBAAiB,QAAmE;AACzF,KAAI,CAAC,UAAU,OAAO,WAAW,EAC7B,QAAO;AAGX,QAAO,OAAO,QAA2B,SAAS,YAAY;AAI1D,UAHoB,QAAQ,aAAa,OACrB,QAAQ,aAAa,KAEL,UAAU;IAC/C,OAAO,GAAG;;;;ACzGjB,eAAsB,kBAAkB,KAAqB,cAA+B;CACxF,MAAM,OAAO,IAAI,QAAQ,MAAM,MAAM;AAErC,KAAI,MAAM,+BAA+B,KAAK,aAAa,CAAE;AAC7D,KAAI,CAAC,KAAM;AACX,KAAI,KAAK,WAAW,IAAI,CAAE;AAC1B,OAAM,qBAAqB,KAAK,cAAc,aAAa,EAAE,MAAM,EAAE;;AAGzE,SAAgB,uBAAuB,KAAsB,cAA+B;AACxF,KAAI,GAAG,gBAAgB,OAAO,QAAQ;AAClC,QAAM,kBAAkB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GACjG;;;;AClBN,eAAsB,mBAAmB,KAAmB,cAA+B;AACvF,KAAI,CAAC,IAAI,QAAQ,MACb;AAGJ,KAAI,MAAM,4BAA4B,KAAK,aAAa,CACpD;CAGJ,MAAM,OAAO,MAAM,gBAAgB,aAAa,aAAa,IAAI,KAAK,IAAI,aAAa,OAAO;AAC9F,OAAM,IAAI,MAAM,KAAK,OAAO,iBAAiB;;AAGjD,SAAgB,qBAAqB,KAAsB,cAA+B;AACtF,KAAI,GAAG,iBAAiB,OAAO,QAAQ;AACnC,QAAM,mBAAmB,KAAK,mCAAmC,cAAc,KAAK,WAAW,CAAC;GAClG;;;;AC1BN,SAAgB,qBAAqB,gBAAiD;AAClF,QAAO,OAAO,KAAK,SAAS;AACxB,MAAI,eAAe,WAAW,EAC1B,QAAO,MAAM;EAGjB,MAAM,SAAS,IAAI,MAAM;AAEzB,MAAI,CAAC,UAAU,CAAC,eAAe,SAAS,OAAO,EAAE;AAC7C,SAAM,IAAI,MAAM,qBAAqB;AACrC;;AAGJ,SAAO,MAAM;;;;;ACDrB,SAAgB,6BAA6B,KAAyB;CAClE,MAAM,cAAc,IAAI,OAAO,UAAU,IAAI,MACvC,IAAI,IAAI,OACR,KAAA;AAGN,QAAO;EACH,GAHkB,2BAA2B,IAAI;EAIjD,OAAO;EACP,UAAU,IAAI,OAAO;EACrB,QAAQ,IAAI,MAAM;EAClB,QAAQ,IAAI,MAAM;EAClB,SAAS,OAAO,gBAAgB,YAAY,YAAY,SAAS;EACjE,YAAY,OAAO,gBAAgB,WAAW,YAAY,SAAS;EACtE;;AAGL,SAAgB,wBAAwB,QAA+C;AACnF,QAAO,OAAO,KAAK,SAAS;AACxB,oBAAkB,QAAqB,EACnC,GAAG,6BAA6B,IAAI,EACvC,EAAE,kBAAkB;AAErB,SAAO,MAAM;;;;;ACTrB,SAAgB,YACZ,KACA,WAIA,SACF;AACE,KAAI,IAAI,wBAAwB,UAAU,OAAO,CAAC;AAClD,KAAI,IAAI,qBAAqB,QAAQ,uBAAuB,CAAC;CAE7D,MAAM,UAAU,IAAI,cAAc,OAAO,UAAU;EAC/C,MAAM,eAAe,6BAA6B,UAAU,QAAQ,MAAM,KAAK,WAAW;AAE1F,eAAa,MACT;GACI,GAAG,6BAA6B,MAAM,IAAI;GAC1C,OAAO;GACP,OAAO,MAAM;GAChB,EACD,6BACH;AACD,QAAM,8BAA8B,MAAM,KAAK,cAAc,MAAM,MAAM;GAC3E;AAEF,sBAAqB,SAAS,UAAU;AACxC,uBAAsB,SAAS,UAAU;AACzC,oBAAmB,SAAS,UAAU;AACtC,uBAAsB,SAAS,UAAU;AACzC,yBAAwB,SAAS,UAAU;AAC3C,uBAAsB,SAAS,UAAU;AACzC,uBAAsB,SAAS,UAAU;AACzC,yBAAwB,SAAS,UAAU;AAC3C,yBAAwB,SAAS,UAAU;AAC3C,qBAAoB,SAAS,UAAU;AACvC,wBAAuB,SAAS,UAAU;AAC1C,sBAAqB,SAAS,UAAU;;;;ACnC5C,IAAM,0BAA0B,EAC5B,QAAQ;CACJ,OAAO,EACH,SAAS,IACZ;CACD,cAAc,MAAU;CACxB,eAAe;CACf,QAAQ;CACX,EACJ;AAED,eAAsB,wBAClB,OAC2B;CAC3B,MAAM,aAAa,wBAAwB,MAAM,OAAO;CACxD,MAAM,WAAW,+BAA+B;CAChD,MAAM,kBAAkB,SAAS,YAAY,IAAI,WAAW;CAC5D,MAAM,gBAAgB,MAAM,UAAU,OAAO,MAAM,EAC/C,WAAW,WACd,CAAC;AAEF,KAAI,iBAAiB;AACjB,gBAAc,KACV;GACI,OAAO;GACP;GACA,iBAAiB,MAAM,OAAO;GACjC,EACD,+EACH;AACD,QAAM,MAAM,UAAU,SAAS;AAC/B,SAAO;;CAGX,MAAM,iBAAiB,gCACnB,OACA,kBACM;AACF,MAAI,SAAS,YAAY,IAAI,WAAW,KAAK,eACzC,UAAS,YAAY,OAAO,WAAW;GAGlD,CAAC,OAAO,UAAU;AACf,MAAI,SAAS,YAAY,IAAI,WAAW,KAAK,eACzC,UAAS,YAAY,OAAO,WAAW;AAG3C,QAAM;GACR;AAEF,UAAS,YAAY,IAAI,YAAY,eAAe;AAEpD,QAAO;;AAGX,eAAe,gCACX,OACA,YACA,gBAC2B;CAE3B,MAAM,OADa,MAAM,gBAAgB,OAAO,YAAY,IAAI,IAAI,OAAO,QAAQ,GAC5D,MAAM,OAAO,kBAAkB,EAClD,QAAQ,EACJ,SAAS,MAAM,OAAO,iBACzB,EACJ,CAAC;CACF,MAAM,gBAAgB,MAAM,UAAU,OAAO,MAAM,EAC/C,WAAW,WACd,CAAC;AAEF,wBAAuB,KAAK,MAAM,UAAU;AAE5C,EAD4B,MAAM,uBAAuB,aACrC,KAAK,MAAM,WAAW,EACtC,wBAAwB,MAAM,OAAO,wBACxC,CAAC;AAEF,KAAI,OAAO,UAAU;EACjB,MAAM,WAAW,6BAA6B,MAAM,IAAI;EACxD,MAAM,iBAAiB,MAAM,UAAU,OAAO,MAAM;GAChD,WAAW;GACX,GAAG;GACN,CAAC;AAEF,MAAI,MAAM,iBAAiB,aAAa;AACpC,kBAAe,MACX;IACI,OAAO;IACP,WAAW,MAAM,MAAM;IACvB,aAAa,MAAM,MAAM;IACzB,QAAQ,MAAM,MAAM;IACpB,YAAY,MAAM,MAAM;IACxB,SAAS,MAAM,MAAM;IACxB,EACD,kCACH;AACD;;AAGJ,MAAI,MAAM,iBAAiB,WAAW;AAClC,kBAAe,MACX;IACI,OAAO;IACP,OAAO,MAAM,MAAM;IACnB,SAAS,MAAM,MAAM;IACxB,EACD,sCACH;AACD;;AAGJ,iBAAe,MACX;GACI,OAAO;GACP,OAAO,MAAM;GAChB,EACD,6BACH;GACH;AAEF,eAAc,KACV;EACI,OAAO;EACP;EACH,EACD,gCACH;CAED,MAAM,UADS,MAAM,UAAU,KACT,KAAK,wBAAwB;CACnD,IAAI,UAAU;CACd,IAAI,WAAW;AAEf,KAAI,MAAM,gBAAgB,KAGtB,EAF4B,MAAM,uBAAuB,sBAEhC,KAAK,MAAM,UAAU,OAAO,CAAC,OAAO,UAAU;AACnE,gBAAc,KACV;GACI,OAAO;GACP;GACA;GACH,EACD,2FACH;GACH;CAGN,IAAI,cAAoC;CACxC,MAAM,cAAc,YAAY;AAC5B,MAAI,QACA;AAGJ,YAAU;AACV,gBAAc,OAAO,MAAM,CAAC,OAAO,UAAU;AACzC,iBAAc,KACV;IACI,OAAO;IACP;IACA;IACH,EACD,yCACH;IACH;AAEF,QAAM;;CAEV,MAAM,aAAa;AACV,eAAa;;CAEtB,MAAM,UAAU,YAAY;AACxB,MAAI,SACA;AAGJ,aAAW;AACX,MAAI;AACA,SAAM,aAAa;AACnB,SAAM,MAAM,UAAU,SAAS;YACzB;AACN,mBAAgB;;;AAIxB,QAAO;EACH;EACA,WAAW,MAAM;EACjB;EACA;EACH;;AAGL,SAAS,uBAAuB,KAAU,WAA+B;CACrE,MAAM,qBAAqB,IAAI,IAAI,WAAW,KAAK,IAAI,IAAI;CAC3D,MAAM,gBAAgB,UAAU,OAAO,MAAM,EACzC,WAAW,WACd,CAAC;AAEF,KAAI,IAAI,aAAa,OAAO,SAAS,WAAW;EAC5C,MAAM,iBAAiB,WAAW;GAC9B,OAAO;GACP,QAAQ;GACR,SAAS;GACZ;AAED,MAAI;AACA,UAAO,MAAM,mBAAmB,gBAAgB,OAAO;WAClD,OAAO;AACZ,iBAAc,KACV;IACI,OAAO;IACP;IACA,OAAO,eAAe;IACtB,QAAQ,eAAe;IACvB,SAAS,eAAe;IAC3B,EACD,6BACH;AACD,SAAM;;;;AAKlB,SAAS,wBAAwB,QAA2B;AACxD,QAAO,GAAG,OAAO,gBAAgB,IAAI,OAAO;;AAGhD,SAAS,gCAA4D;CACjE,MAAM,cAAc;AAIpB,aAAY,4CAA4C,EACpD,6BAAa,IAAI,KAAK,EACzB;AAED,QAAO,YAAY;;;;AC9NvB,eAAsB,+BAClB,SAC2B;CAC3B,MAAM,qBAAqB,wCAAwC;CACnE,MAAM,MAAM,wBAAwB,QAAQ,QAAQ;AAEpD,KAAI,mBAAmB,SAAS,mBAAmB,MAAM,QAAQ,KAAK;EAClE,MAAM,cAAc,mBAAmB;AACvC,qBAAmB,QAAQ;AAC3B,QAAM,qCAAqC,YAAY;;AAG3D,KAAI,CAAC,mBAAmB,OAAO;EAC3B,MAAM,iBAAiB,mBAAmB,SAAS,IAAI,CAClD,MAAM,YAAY;AACf,OAAI,mBAAmB,OAAO,mBAAmB,eAC7C,oBAAmB,MAAM,UAAU;AAGvC,UAAO;IACT,CACD,OAAO,UAAU;AACd,OAAI,mBAAmB,OAAO,mBAAmB,eAC7C,oBAAmB,QAAQ;AAG/B,SAAM;IACR;AAEN,qBAAmB,QAAQ;GACvB;GACA,SAAS;GACT;GACH;;AAGL,QAAO,mBAAmB,MAAM;;AAGpC,IAAa,oBAA4B,OAAO,YAAY;AAKxD,QAAO,YAJS,MAAM,+BAA+B,EACxC,SACZ,CAAC,CAEyB;;AAG/B,eAAsB,wCAAwC;CAC1D,MAAM,qBAAqB,wCAAwC;AAEnE,KAAI,CAAC,mBAAmB,MACpB;CAGJ,MAAM,cAAc,mBAAmB;AACvC,oBAAmB,QAAQ;AAC3B,OAAM,qCAAqC,YAAY;;AAK3D,eAAe,mBACX,SACA,KAC2B;CAC3B,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,uBAAuB,QAAQ,wBAAwB;CAC7D,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,wBAAwB,MAAM,qBAAqB;EACrD;EACA,QAAQ,QAAQ;EACnB,CAAC;CACF,MAAM,EAAE,QAAQ,cAAc,aAC1B,QAAQ,QAAQ,QAChB,sBAAsB,QACtB,EAAE,KAAK,sBAAsB,KAAK,CACrC;AAED,KAAI;AACA,MAAI,sBAAsB,6BACtB,WAAU,OAAO,MAAM,EAAE,WAAW,WAAW,CAAC,CAAC,KAC7C;GACI,KAAK,sBAAsB;GAC3B,OAAO;GACP,8BAA8B,sBAAsB;GACpD,sBAAsB,sBAAsB;GAC/C,EACD,gGACH;EAGL,MAAM,UAAU,MAAM,aAAa;GAAE;GAAQ;GAAW,CAAC;AAEzD,YAAU,OAAO,MAAM,EAAE,WAAW,WAAW,CAAC,CAAC,KAC7C;GACI,KAAK,sBAAsB;GAC3B,OAAO;GACP,sBAAsB,sBAAsB;GAC5C,8BAA8B,sBAAsB;GACpD,gBAAgB,sBAAsB;GACtC,MAAM;GACT,EACD,sCACH;AAED,SAAO;UACF,OAAO;AACZ,QAAM,UAAU,SAAS;AACzB,QAAM;;;AAId,SAAS,wBAAwB,SAA4C;AACzE,QAAO,QAAQ,YAAY,QAAQ,aAAa,QAAQ,KAAK;;AAGjE,eAAe,qCACX,OACa;AAGb,QAFgB,MAAM,WAAW,MAAM,MAAM,eAAe,YAAY,KAAK,GAE9D,SAAS;;AAG5B,SAAS,YAAY,SAAoC;AACrD,QAAO;EACH,MAAM,MAAM,EAAE,SAAS;AACnB,SAAM,6BAA6B,SAAS,MAAM;;EAEtD,MAAM,iBAAiB,OAAO,QAAQ;GAClC,MAAM,WAAW,MAAM,QAAQ,UAAU,YAAY,gBAAgB,MAAM,UAAU;GACrF,MAAM,oBAAoB,QAAQ,UAAU,yBAAyB,YAAY,MAAM,UAAU;AAEjG,OAAI,SAAS,SAAS,KAAK,kBAAkB,SAAS,EAClD,QAAO,SAAS;;EAG3B;;AAGL,SAAS,yCAA8E;CACnF,MAAM,cAAc;AAIpB,aAAY,uCAAuC,EAC/C,OAAO,MACV;AAED,QAAO,YAAY"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../src/infra/utils/redact.ts","../src/infra/logger/index.ts","../src/repositories/pending-action.repo.ts","../src/repositories/permission-approval.repo.ts","../src/repositories/session.repo.ts","../src/infra/utils/markdown-text.ts","../src/services/opencode/opencode.client.ts","../src/services/storage/bot-state.ts","../src/services/storage/json-state-store.ts","../src/services/telegram/telegram.client.ts","../src/services/session-activity/foreground-session-tracker.ts","../src/use-cases/abort-prompt.usecase.ts","../src/use-cases/session-creation.ts","../src/use-cases/create-session.usecase.ts","../src/use-cases/get-health.usecase.ts","../src/use-cases/get-path.usecase.ts","../src/use-cases/get-status.usecase.ts","../src/use-cases/agent-selection.ts","../src/use-cases/binding-update.ts","../src/use-cases/list-agents.usecase.ts","../src/use-cases/list-lsp.usecase.ts","../src/use-cases/list-mcp.usecase.ts","../src/use-cases/list-models.usecase.ts","../src/use-cases/list-sessions.usecase.ts","../src/use-cases/rename-session.usecase.ts","../src/use-cases/send-prompt.usecase.ts","../src/use-cases/switch-agent.usecase.ts","../src/use-cases/switch-model.usecase.ts","../src/use-cases/switch-session.usecase.ts","../src/use-cases/upload-file.usecase.ts","../src/app/container.ts","../src/app/bootstrap.ts","../src/services/permission/telegram-approval.ts","../src/app/plugin-events.ts","../src/bot/copy.ts","../src/bot/commands/command-list.ts","../src/bot/commands/sync-commands.ts","../src/bot/logger-context.ts","../src/bot/presenters/error.presenter.ts","../src/bot/error-boundary.ts","../src/bot/i18n.ts","../src/bot/presenters/keyboard.presenter.ts","../src/bot/presenters/message.presenter.ts","../src/bot/commands/agents.ts","../src/bot/sessions-menu.ts","../src/bot/session-rename.ts","../src/bot/commands/cancel.ts","../src/bot/commands/language.ts","../src/bot/commands/models.ts","../src/bot/commands/new.ts","../src/services/telegram/telegram-format.ts","../src/bot/commands/status.ts","../src/bot/commands/sessions.ts","../src/bot/presenters/static.presenter.ts","../src/bot/commands/start.ts","../src/bot/handlers/callback.handler.ts","../src/bot/handlers/prompt.handler.ts","../src/bot/handlers/file.handler.ts","../src/bot/handlers/message.handler.ts","../src/bot/handlers/voice.handler.ts","../src/bot/middlewares/auth.ts","../src/bot/middlewares/logging.ts","../src/bot/index.ts","../src/app/runtime.ts","../src/plugin.ts"],"sourcesContent":["const REDACTED = \"[REDACTED]\";\nconst DEFAULT_PREVIEW_LENGTH = 160;\nconst TELEGRAM_TOKEN_PATTERN = /\\b\\d{6,}:[A-Za-z0-9_-]{20,}\\b/g;\nconst BEARER_TOKEN_PATTERN = /\\bBearer\\s+[A-Za-z0-9._~+/-]+=*\\b/gi;\nconst NAMED_SECRET_PATTERN = /\\b(api[_\\s-]?key|token|secret|password)\\b(\\s*[:=]\\s*)([^\\s,;]+)/gi;\nconst API_KEY_LIKE_PATTERN = /\\b(?:sk|pk)_[A-Za-z0-9_-]{10,}\\b/g;\n\nexport function redactSensitiveText(input: string): string {\n return input\n .replace(BEARER_TOKEN_PATTERN, `Bearer ${REDACTED}`)\n .replace(TELEGRAM_TOKEN_PATTERN, REDACTED)\n .replace(NAMED_SECRET_PATTERN, (_, name: string, separator: string) => `${name}${separator}${REDACTED}`)\n .replace(API_KEY_LIKE_PATTERN, REDACTED);\n}\n\nexport function createRedactedPreview(input: string, maxLength = DEFAULT_PREVIEW_LENGTH): string {\n const redacted = redactSensitiveText(input).replace(/\\s+/g, \" \").trim();\n\n if (redacted.length <= maxLength) {\n return redacted;\n }\n\n return `${redacted.slice(0, Math.max(0, maxLength - 3))}...`;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir, readdir, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { redactSensitiveText } from \"../utils/redact.js\";\n\nexport type AppLogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\nexport type LogComponent =\n | \"app\"\n | \"runtime\"\n | \"telegram\"\n | \"opencode\"\n | \"prompt\"\n | \"plugin-event\"\n | \"storage\"\n | \"bot\";\nexport type LogEventName = string;\n\nexport interface StructuredLogError {\n data?: unknown;\n message: string;\n name: string;\n stack?: string;\n}\n\nexport interface StructuredLogEvent {\n ts: string;\n level: AppLogLevel;\n service: string;\n component: LogComponent | string;\n event: LogEventName;\n message: string;\n runtimeId: string | null;\n operationId: string | null;\n correlationId: string | null;\n worktree?: string;\n chatId?: number;\n sessionId?: string;\n projectId?: string;\n requestId?: string;\n updateId?: number;\n command?: string;\n callbackData?: string;\n durationMs?: number;\n attempt?: number;\n status?: string;\n sizeBytes?: number;\n error?: StructuredLogError;\n [key: string]: unknown;\n}\n\nexport interface LoggerContext {\n attempt?: number;\n callbackData?: string;\n chatId?: number;\n command?: string;\n component?: LogComponent | string;\n correlationId?: string | null;\n durationMs?: number;\n error?: StructuredLogError;\n event?: LogEventName;\n operationId?: string | null;\n projectId?: string;\n requestId?: string;\n runtimeId?: string | null;\n sessionId?: string;\n sizeBytes?: number;\n status?: string;\n updateId?: number;\n worktree?: string;\n}\n\nexport interface AppLogger {\n debug(input?: unknown, message?: string): void;\n info(input?: unknown, message?: string): void;\n warn(input?: unknown, message?: string): void;\n error(input?: unknown, message?: string): void;\n child(context: LoggerContext): AppLogger;\n flush(): Promise<void>;\n}\n\nexport interface LogSink {\n flush?(): Promise<void>;\n write(event: StructuredLogEvent): Promise<void>;\n}\n\nexport interface FileLogSinkOptions {\n dir: string;\n maxFiles?: number;\n maxTotalBytes?: number;\n runtimeId: string;\n}\n\ninterface OpenCodeAppLogClientLike {\n app: {\n log(input: {\n body?: {\n service: string;\n level: AppLogLevel;\n message: string;\n extra?: Record<string, unknown>;\n };\n service?: string;\n level?: AppLogLevel;\n message?: string;\n extra?: Record<string, unknown>;\n responseStyle?: \"data\" | \"fields\";\n throwOnError?: boolean;\n }, options?: {\n responseStyle?: \"data\" | \"fields\";\n throwOnError?: boolean;\n }): Promise<unknown>;\n };\n}\n\ninterface LoggerSinkOptions {\n file?: boolean;\n host?: boolean;\n}\n\ninterface CreateOpenCodeAppLoggerOptions {\n file?: {\n dir: string;\n retention?: {\n maxFiles?: number;\n maxTotalBytes?: number;\n };\n };\n level?: string | null;\n runtimeId?: string;\n service?: string;\n sinks?: LoggerSinkOptions;\n worktree?: string;\n}\n\ninterface PendingLogEvent {\n context: LoggerContext;\n input?: unknown;\n level: AppLogLevel;\n message?: string;\n}\n\nconst DEFAULT_COMPONENT: LogComponent = \"app\";\nconst DEFAULT_EVENT = \"log\";\nconst DEFAULT_SERVICE_NAME = \"opencode-tbot\";\nconst DEFAULT_MAX_LOG_FILES = 30;\nconst DEFAULT_MAX_TOTAL_LOG_BYTES = 314_572_800;\nconst CONTENT_OMITTED = \"[OMITTED]\";\nconst REDACTED = \"[REDACTED]\";\nconst LEVEL_PRIORITY: Record<AppLogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\nconst RESERVED_EVENT_FIELDS = new Set([\n \"attempt\",\n \"callbackData\",\n \"chatId\",\n \"command\",\n \"component\",\n \"correlationId\",\n \"durationMs\",\n \"error\",\n \"event\",\n \"operationId\",\n \"projectId\",\n \"requestId\",\n \"runtimeId\",\n \"sessionId\",\n \"sizeBytes\",\n \"status\",\n \"updateId\",\n \"worktree\",\n]);\n\nexport function createOpenCodeAppLogger(\n client: OpenCodeAppLogClientLike,\n options: CreateOpenCodeAppLoggerOptions = {},\n): AppLogger {\n const service = normalizeServiceName(options.service);\n const minimumLevel = normalizeLogLevel(options.level);\n const runtimeId = normalizeString(options.runtimeId) ?? randomUUID();\n const boundRootContext: LoggerContext = {\n component: DEFAULT_COMPONENT,\n runtimeId,\n ...(options.worktree ? { worktree: options.worktree } : {}),\n };\n const sinks = createSinks(client, {\n file: {\n dir: options.file?.dir,\n maxFiles: options.file?.retention?.maxFiles,\n maxTotalBytes: options.file?.retention?.maxTotalBytes,\n },\n runtimeId,\n service,\n sinks: options.sinks,\n });\n let queue = Promise.resolve();\n\n const enqueue = (event: PendingLogEvent) => {\n if (LEVEL_PRIORITY[event.level] < LEVEL_PRIORITY[minimumLevel]) {\n return;\n }\n\n const structuredEvent = buildStructuredLogEvent(\n event.level,\n event.input,\n event.message,\n service,\n event.context,\n );\n\n queue = queue\n .catch(() => undefined)\n .then(async () => {\n await Promise.allSettled(\n sinks.map((sink) => sink.write(structuredEvent)),\n );\n });\n };\n\n const createLogger = (context: LoggerContext): AppLogger => ({\n debug(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"debug\",\n message,\n });\n },\n info(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"info\",\n message,\n });\n },\n warn(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"warn\",\n message,\n });\n },\n error(input?: unknown, message?: string) {\n enqueue({\n context,\n input,\n level: \"error\",\n message,\n });\n },\n child(childContext: LoggerContext) {\n return createLogger({\n ...context,\n ...removeUndefinedFields(childContext),\n });\n },\n async flush() {\n await queue.catch(() => undefined);\n await Promise.allSettled(\n sinks.map(async (sink) => {\n await sink.flush?.();\n }),\n );\n },\n });\n\n return createLogger(boundRootContext);\n}\n\nexport function createOperationId(prefix = \"op\"): string {\n return `${prefix}-${randomUUID()}`;\n}\n\nexport function logTelegramUpdate(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"telegram\",\n ...input,\n },\n message,\n );\n}\n\nexport function logPromptLifecycle(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"prompt\",\n ...input,\n },\n message,\n );\n}\n\nexport function logOpenCodeRequest(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"opencode\",\n ...input,\n },\n message,\n );\n}\n\nexport function logPluginEvent(\n logger: AppLogger,\n input: LoggerContext & Record<string, unknown>,\n message: string,\n): void {\n logger.info(\n {\n component: \"plugin-event\",\n ...input,\n },\n message,\n );\n}\n\nfunction createSinks(\n client: OpenCodeAppLogClientLike,\n options: {\n file?: {\n dir?: string;\n maxFiles?: number;\n maxTotalBytes?: number;\n };\n runtimeId: string;\n service: string;\n sinks?: LoggerSinkOptions;\n },\n): LogSink[] {\n const sinkOptions = options.sinks ?? {};\n const sinks: LogSink[] = [];\n\n if (sinkOptions.host !== false) {\n sinks.push(createHostSink(client, options.service));\n }\n\n if (sinkOptions.file !== false && options.file?.dir) {\n sinks.push(createJsonlFileSink({\n dir: options.file.dir,\n maxFiles: options.file.maxFiles,\n maxTotalBytes: options.file.maxTotalBytes,\n runtimeId: options.runtimeId,\n }));\n }\n\n return sinks;\n}\n\nfunction createHostSink(client: OpenCodeAppLogClientLike, service: string): LogSink {\n return {\n async write(event) {\n const payload = {\n service,\n level: event.level,\n message: event.message,\n extra: buildHostLogExtra(event),\n };\n\n if (client.app.log.length >= 2) {\n await client.app.log(payload, {\n responseStyle: \"data\",\n throwOnError: true,\n });\n return;\n }\n\n await client.app.log({\n body: payload,\n responseStyle: \"data\",\n throwOnError: true,\n });\n },\n };\n}\n\nfunction createJsonlFileSink(options: FileLogSinkOptions): LogSink {\n const maxFiles = options.maxFiles ?? DEFAULT_MAX_LOG_FILES;\n const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_TOTAL_LOG_BYTES;\n const runtimeSegment = sanitizeFileSegment(options.runtimeId);\n const timestampSegment = new Date().toISOString().replace(/:/gu, \"-\");\n const filePath = join(\n options.dir,\n `${timestampSegment}.${process.pid}.${runtimeSegment}.jsonl`,\n );\n let initialized = false;\n let writeCount = 0;\n\n const initialize = async () => {\n if (initialized) {\n return;\n }\n\n await mkdir(options.dir, { recursive: true });\n await cleanupLogDirectory(options.dir, maxFiles, maxTotalBytes);\n initialized = true;\n };\n\n return {\n async write(event) {\n await initialize();\n await appendFile(filePath, `${JSON.stringify(event)}\\n`, \"utf8\");\n writeCount += 1;\n\n if (writeCount === 1 || writeCount % 100 === 0) {\n await cleanupLogDirectory(options.dir, maxFiles, maxTotalBytes);\n }\n },\n };\n}\n\nasync function cleanupLogDirectory(\n directory: string,\n maxFiles: number,\n maxTotalBytes: number,\n): Promise<void> {\n let entries: Array<{ path: string; size: number; time: number }> = [];\n\n try {\n const names = await readdir(directory);\n\n entries = await Promise.all(\n names\n .filter((name) => name.endsWith(\".jsonl\"))\n .map(async (name) => {\n const entryPath = join(directory, name);\n const entryStat = await stat(entryPath);\n\n return {\n path: entryPath,\n size: entryStat.size,\n time: entryStat.mtimeMs,\n };\n }),\n );\n } catch {\n return;\n }\n\n entries.sort((left, right) => right.time - left.time);\n\n let totalBytes = 0;\n const retained: Array<{ path: string; size: number; time: number }> = [];\n const deleted: Array<{ path: string; size: number; time: number }> = [];\n\n for (const entry of entries) {\n const canKeepByCount = retained.length < maxFiles;\n const canKeepBySize = retained.length === 0 || totalBytes + entry.size <= maxTotalBytes;\n\n if (canKeepByCount && canKeepBySize) {\n retained.push(entry);\n totalBytes += entry.size;\n continue;\n }\n\n deleted.push(entry);\n }\n\n await Promise.allSettled(\n deleted.map(async (entry) => {\n await unlink(entry.path);\n }),\n );\n}\n\nfunction buildStructuredLogEvent(\n level: AppLogLevel,\n input: unknown,\n message: string | undefined,\n service: string,\n boundContext: LoggerContext,\n): StructuredLogEvent {\n const extracted = extractContextAndExtra(input);\n const context: LoggerContext = {\n ...removeUndefinedFields(boundContext),\n ...removeUndefinedFields(extracted.context),\n };\n const resolvedMessage = normalizeLogMessage(input, message);\n\n return {\n ts: new Date().toISOString(),\n level,\n service,\n component: normalizeComponent(context.component),\n event: normalizeEventName(context.event),\n message: redactSensitiveText(resolvedMessage),\n runtimeId: context.runtimeId ?? null,\n operationId: context.operationId ?? null,\n correlationId: resolveCorrelationId(context),\n ...(context.worktree ? { worktree: redactSensitiveText(context.worktree) } : {}),\n ...(typeof context.chatId === \"number\" ? { chatId: context.chatId } : {}),\n ...(context.sessionId ? { sessionId: context.sessionId } : {}),\n ...(context.projectId ? { projectId: context.projectId } : {}),\n ...(context.requestId ? { requestId: context.requestId } : {}),\n ...(typeof context.updateId === \"number\" ? { updateId: context.updateId } : {}),\n ...(context.command ? { command: context.command } : {}),\n ...(context.callbackData ? { callbackData: context.callbackData } : {}),\n ...(typeof context.durationMs === \"number\" ? { durationMs: context.durationMs } : {}),\n ...(typeof context.attempt === \"number\" ? { attempt: context.attempt } : {}),\n ...(context.status ? { status: context.status } : {}),\n ...(typeof context.sizeBytes === \"number\" ? { sizeBytes: context.sizeBytes } : {}),\n ...(context.error ? { error: context.error } : {}),\n ...removeUndefinedFields(extracted.extra),\n };\n}\n\nfunction buildHostLogExtra(event: StructuredLogEvent): Record<string, unknown> {\n const {\n service: _service,\n level: _level,\n message: _message,\n ...rest\n } = event;\n\n return rest;\n}\n\nfunction extractContextAndExtra(input: unknown): {\n context: LoggerContext;\n extra: Record<string, unknown>;\n} {\n if (input instanceof Error) {\n return {\n context: {\n error: serializeError(input),\n },\n extra: {},\n };\n }\n\n if (Array.isArray(input)) {\n return {\n context: {},\n extra: {\n items: input.map((item) => sanitizeValue(item)),\n },\n };\n }\n\n if (input === null || input === undefined) {\n return {\n context: {},\n extra: {},\n };\n }\n\n if (typeof input === \"string\") {\n return {\n context: {},\n extra: {},\n };\n }\n\n if (typeof input !== \"object\") {\n return {\n context: {},\n extra: {\n value: sanitizeValue(input),\n },\n };\n }\n\n const record = input as Record<string, unknown>;\n const context: LoggerContext = {};\n const extra: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(record)) {\n if (RESERVED_EVENT_FIELDS.has(key)) {\n assignReservedField(context, key, value);\n continue;\n }\n\n extra[key] = sanitizeFieldValue(key, value);\n }\n\n return {\n context,\n extra,\n };\n}\n\nfunction assignReservedField(context: LoggerContext, key: string, value: unknown): void {\n switch (key) {\n case \"attempt\":\n case \"durationMs\":\n case \"sizeBytes\":\n if (typeof value === \"number\") {\n context[key] = value;\n }\n return;\n case \"chatId\":\n case \"updateId\":\n if (typeof value === \"number\") {\n context[key] = value;\n }\n return;\n case \"callbackData\":\n case \"command\":\n case \"component\":\n case \"event\":\n case \"projectId\":\n case \"requestId\":\n case \"sessionId\":\n case \"status\":\n case \"worktree\":\n if (typeof value === \"string\" && value.trim().length > 0) {\n context[key] = redactSensitiveText(value.trim()) as never;\n }\n return;\n case \"correlationId\":\n case \"operationId\":\n case \"runtimeId\":\n if (typeof value === \"string\" && value.trim().length > 0) {\n context[key] = value.trim();\n } else if (value === null) {\n context[key] = null;\n }\n return;\n case \"error\":\n if (value instanceof Error) {\n context.error = serializeError(value);\n } else if (isPlainObject(value)) {\n context.error = normalizeStructuredLogErrorRecord(value);\n }\n return;\n default:\n return;\n }\n}\n\nfunction normalizeLogMessage(input: unknown, message?: string): string {\n if (typeof input === \"string\") {\n const normalizedInput = input.trim();\n\n return normalizedInput.length > 0\n ? normalizedInput\n : \"log\";\n }\n\n if (message && message.trim().length > 0) {\n return message.trim();\n }\n\n if (input instanceof Error) {\n return input.message.trim() || input.name;\n }\n\n return \"log\";\n}\n\nfunction normalizeServiceName(value: string | undefined): string {\n const normalized = value?.trim();\n\n return normalized && normalized.length > 0\n ? normalized\n : DEFAULT_SERVICE_NAME;\n}\n\nfunction normalizeLogLevel(value: string | null | undefined): AppLogLevel {\n switch (value?.trim().toLowerCase()) {\n case \"debug\":\n return \"debug\";\n case \"warn\":\n return \"warn\";\n case \"error\":\n return \"error\";\n default:\n return \"info\";\n }\n}\n\nfunction normalizeComponent(value: string | undefined): string {\n const normalized = value?.trim();\n\n return normalized && normalized.length > 0\n ? normalized\n : DEFAULT_COMPONENT;\n}\n\nfunction normalizeEventName(value: string | undefined): string {\n const normalized = value?.trim();\n\n return normalized && normalized.length > 0\n ? normalized\n : DEFAULT_EVENT;\n}\n\nfunction resolveCorrelationId(context: LoggerContext): string | null {\n if (context.correlationId) {\n return context.correlationId;\n }\n\n if (typeof context.updateId === \"number\") {\n return String(context.updateId);\n }\n\n return context.operationId ?? null;\n}\n\nfunction serializeError(error: Error): StructuredLogError {\n return {\n name: error.name,\n message: redactSensitiveText(error.message),\n ...(error.stack ? { stack: redactSensitiveText(error.stack) } : {}),\n ...(\"data\" in error && error.data && typeof error.data === \"object\"\n ? { data: sanitizeValue(error.data) }\n : {}),\n };\n}\n\nfunction sanitizePlainObject(value: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n sanitizeFieldValue(key, entryValue),\n ]),\n );\n}\n\nfunction sanitizeFieldValue(key: string, value: unknown): unknown {\n if (isSensitiveKey(key)) {\n return redactSensitiveFieldValue(value);\n }\n\n if (isUrlLikeKey(key)) {\n return summarizeUrlValue(value);\n }\n\n if (isTextContentKey(key)) {\n return summarizeTextValue(value);\n }\n\n if (isAttachmentCollectionKey(key)) {\n return summarizeAttachmentCollection(value);\n }\n\n return sanitizeValue(value);\n}\n\nfunction sanitizeValue(value: unknown): unknown {\n if (value instanceof Error) {\n return serializeError(value);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => sanitizeValue(entry));\n }\n\n if (typeof value === \"string\") {\n return redactSensitiveText(value);\n }\n\n if (!value || typeof value !== \"object\") {\n return value;\n }\n\n return sanitizePlainObject(value as Record<string, unknown>);\n}\n\nfunction summarizeTextValue(value: unknown): unknown {\n if (typeof value === \"string\") {\n return {\n omitted: CONTENT_OMITTED,\n length: value.length,\n };\n }\n\n if (Array.isArray(value)) {\n return {\n omitted: CONTENT_OMITTED,\n count: value.length,\n };\n }\n\n if (value && typeof value === \"object\") {\n return {\n omitted: CONTENT_OMITTED,\n kind: \"object\",\n };\n }\n\n return value;\n}\n\nfunction summarizeUrlValue(value: unknown): unknown {\n if (typeof value === \"string\" && value.trim().length > 0) {\n return {\n omitted: CONTENT_OMITTED,\n kind: \"url\",\n };\n }\n\n return sanitizeValue(value);\n}\n\nfunction summarizeAttachmentCollection(value: unknown): unknown {\n if (!Array.isArray(value)) {\n return summarizeTextValue(value);\n }\n\n return {\n count: value.length,\n items: value.map((entry) => summarizeAttachmentValue(entry)),\n };\n}\n\nfunction summarizeAttachmentValue(value: unknown): unknown {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return summarizeTextValue(value);\n }\n\n const record = value as Record<string, unknown>;\n\n return removeUndefinedFields({\n filename: normalizeString(record.filename) ?? normalizeString(record.fileName) ?? undefined,\n mime: normalizeString(record.mime) ?? normalizeString(record.mimeType) ?? undefined,\n sizeBytes: pickNumericValue(record, [\"sizeBytes\", \"size\", \"fileSize\"]),\n hasCaption: pickStringValue(record, [\"caption\"]) !== null,\n textLength: pickStringValue(record, [\"text\", \"prompt\"])?.length,\n type: normalizeString(record.type) ?? undefined,\n });\n}\n\nfunction isSensitiveKey(key: string): boolean {\n return /token|secret|api[-_]?key|authorization|password|cookie/iu.test(key);\n}\n\nfunction isTextContentKey(key: string): boolean {\n return /(^|[-_])(text|prompt|caption|body|markdown|content|messageText|fallbackText|input|raw)$/iu.test(key)\n || /bodyMd|bodyText|messageText|fallbackText/iu.test(key);\n}\n\nfunction isUrlLikeKey(key: string): boolean {\n return /(^|[-_])(url|uri|href|filePath|downloadPath|downloadUrl|fileUrl)$/iu.test(key);\n}\n\nfunction isAttachmentCollectionKey(key: string): boolean {\n return /(^|[-_])(files|parts|attachments)$/iu.test(key);\n}\n\nfunction redactSensitiveFieldValue(value: unknown): unknown {\n if (typeof value === \"string\" && value.trim().length > 0) {\n return REDACTED;\n }\n\n if (Array.isArray(value)) {\n return value.map(() => REDACTED);\n }\n\n if (value && typeof value === \"object\") {\n return REDACTED;\n }\n\n return value;\n}\n\nfunction removeUndefinedFields<TRecord extends object>(record: TRecord): TRecord {\n return Object.fromEntries(\n Object.entries(record).filter(([, value]) => value !== undefined),\n ) as TRecord;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction normalizeString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim().length > 0\n ? redactSensitiveText(value.trim())\n : null;\n}\n\nfunction pickNumericValue(record: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = record[key];\n\n if (typeof value === \"number\") {\n return value;\n }\n }\n\n return undefined;\n}\n\nfunction pickStringValue(record: Record<string, unknown>, keys: string[]): string | null {\n for (const key of keys) {\n const value = record[key];\n\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n }\n\n return null;\n}\n\nfunction sanitizeFileSegment(value: string): string {\n return value.replace(/[^a-z0-9._-]+/giu, \"_\");\n}\n\nfunction normalizeStructuredLogErrorRecord(value: Record<string, unknown>): StructuredLogError {\n return {\n name: normalizeString(value.name) ?? \"Error\",\n message: normalizeString(value.message) ?? \"Unknown error\",\n ...(typeof value.stack === \"string\" ? { stack: redactSensitiveText(value.stack) } : {}),\n ...(value.data !== undefined ? { data: sanitizeValue(value.data) } : {}),\n };\n}\n","import type { PendingChatAction } from \"../domain/pending-action/pending-action.entity.js\";\nimport type { PendingActionRepository } from \"../domain/pending-action/pending-action.repository.js\";\nimport type { OpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport type { JsonStateStore } from \"../services/storage/json-state-store.js\";\n\nexport class InMemoryPendingActionRepository implements PendingActionRepository {\n private readonly actionsByChatId = new Map<number, PendingChatAction>();\n\n async getByChatId(chatId: number): Promise<PendingChatAction | null> {\n return this.actionsByChatId.get(chatId) ?? null;\n }\n\n async set(action: PendingChatAction): Promise<void> {\n this.actionsByChatId.set(action.chatId, action);\n }\n\n async clear(chatId: number): Promise<void> {\n this.actionsByChatId.delete(chatId);\n }\n}\n\nexport class FilePendingActionRepository implements PendingActionRepository {\n constructor(private readonly store: JsonStateStore<OpencodeTbotState>) { }\n\n async getByChatId(chatId: number): Promise<PendingChatAction | null> {\n const state = await this.store.read();\n\n return state.pendingActions[String(chatId)] ?? null;\n }\n\n async set(action: PendingChatAction): Promise<void> {\n await this.store.update((state) => {\n state.pendingActions[String(action.chatId)] = action;\n });\n }\n\n async clear(chatId: number): Promise<void> {\n await this.store.update((state) => {\n delete state.pendingActions[String(chatId)];\n });\n }\n}\n","import type { PendingPermissionApproval } from \"../domain/permission/approval.entity.js\";\nimport type { PermissionApprovalRepository } from \"../domain/permission/approval.repository.js\";\nimport type { OpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport type { JsonStateStore } from \"../services/storage/json-state-store.js\";\n\nfunction buildApprovalKey(requestId: string, chatId: number): string {\n return `${requestId}:${chatId}`;\n}\n\nexport class InMemoryPermissionApprovalRepository implements PermissionApprovalRepository {\n private readonly approvalsByKey = new Map<string, PendingPermissionApproval>();\n\n async listByRequestId(requestId: string): Promise<PendingPermissionApproval[]> {\n return [...this.approvalsByKey.values()].filter((approval) => approval.requestId === requestId);\n }\n\n async set(approval: PendingPermissionApproval): Promise<void> {\n this.approvalsByKey.set(buildApprovalKey(approval.requestId, approval.chatId), approval);\n }\n}\n\nexport class FilePermissionApprovalRepository implements PermissionApprovalRepository {\n constructor(private readonly store: JsonStateStore<OpencodeTbotState>) { }\n\n async listByRequestId(requestId: string): Promise<PendingPermissionApproval[]> {\n const state = await this.store.read();\n\n return Object.values(state.pendingPermissions).filter((approval) => approval.requestId === requestId);\n }\n\n async set(approval: PendingPermissionApproval): Promise<void> {\n await this.store.update((state) => {\n state.pendingPermissions[buildApprovalKey(approval.requestId, approval.chatId)] = approval;\n });\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { OpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport type { JsonStateStore } from \"../services/storage/json-state-store.js\";\n\nexport class InMemorySessionRepository implements SessionRepository {\n private readonly sessionsByChatId = new Map<number, ChatSessionBinding>();\n\n async getByChatId(chatId: number): Promise<ChatSessionBinding | null> {\n return this.sessionsByChatId.get(chatId) ?? null;\n }\n\n async listBySessionId(sessionId: string): Promise<ChatSessionBinding[]> {\n return [...this.sessionsByChatId.values()].filter((binding) => binding.sessionId === sessionId);\n }\n\n async setCurrent(binding: ChatSessionBinding): Promise<void> {\n this.sessionsByChatId.set(binding.chatId, binding);\n }\n\n async touch(chatId: number): Promise<void> {\n const binding = this.sessionsByChatId.get(chatId);\n\n if (!binding) {\n return;\n }\n\n this.sessionsByChatId.set(chatId, {\n ...binding,\n updatedAt: new Date().toISOString(),\n });\n }\n}\n\nexport class FileSessionRepository implements SessionRepository {\n constructor(private readonly store: JsonStateStore<OpencodeTbotState>) { }\n\n async getByChatId(chatId: number): Promise<ChatSessionBinding | null> {\n const state = await this.store.read();\n\n return state.sessions[String(chatId)] ?? null;\n }\n\n async listBySessionId(sessionId: string): Promise<ChatSessionBinding[]> {\n const state = await this.store.read();\n\n return Object.values(state.sessions).filter((binding) => binding.sessionId === sessionId);\n }\n\n async setCurrent(binding: ChatSessionBinding): Promise<void> {\n await this.store.update((state) => {\n state.sessions[String(binding.chatId)] = binding;\n });\n }\n\n async touch(chatId: number): Promise<void> {\n await this.store.update((state) => {\n const current = state.sessions[String(chatId)];\n\n if (!current) {\n return;\n }\n\n state.sessions[String(chatId)] = {\n ...current,\n updatedAt: new Date().toISOString(),\n };\n });\n }\n}\n","const HTML_TAG_PATTERN = /<\\/?[A-Za-z][^>]*>/g;\n\nexport function stripMarkdownToPlainText(markdown: string): string {\n const normalizedMarkdown = preprocessMarkdownForPlainText(markdown);\n const lines = normalizedMarkdown.split(\"\\n\");\n const rendered: string[] = [];\n\n for (let index = 0; index < lines.length; index += 1) {\n const tableBlock = consumeMarkdownTable(lines, index);\n\n if (tableBlock) {\n rendered.push(renderTableAsPlainText(tableBlock.rows));\n index = tableBlock.nextIndex - 1;\n continue;\n }\n\n rendered.push(lines[index] ?? \"\");\n }\n\n return rendered\n .join(\"\\n\")\n .replace(/```[A-Za-z0-9_-]*\\n?/g, \"\")\n .replace(/```/g, \"\")\n .replace(/^#{1,6}\\s+/gm, \"\")\n .replace(/^\\s*>\\s?/gm, \"\")\n .replace(/^(\\s*)[-+*]\\s+/gm, \"$1- \")\n .replace(/^(\\s*)(\\d+)[.)]\\s+/gm, \"$1$2. \")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1 ($2)\")\n .replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\")\n .replace(/(\\*|_)(.*?)\\1/g, \"$2\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(HTML_TAG_PATTERN, \"\")\n .trim();\n}\n\ninterface ConsumedTable {\n nextIndex: number;\n rows: string[][];\n}\n\nfunction preprocessMarkdownForPlainText(markdown: string): string {\n const normalizedMarkdown = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalizedMarkdown.split(\"\\n\");\n const processed: string[] = [];\n let activeFence: \"markdown\" | \"plain\" | null = null;\n\n for (const line of lines) {\n const fenceMatch = line.match(/^```([A-Za-z0-9_-]+)?\\s*$/);\n\n if (fenceMatch) {\n const language = (fenceMatch[1] ?? \"\").toLowerCase();\n\n if (activeFence === \"markdown\") {\n activeFence = null;\n continue;\n }\n\n if (activeFence === \"plain\") {\n processed.push(line);\n activeFence = null;\n continue;\n }\n\n if (language === \"md\" || language === \"markdown\") {\n activeFence = \"markdown\";\n continue;\n }\n\n activeFence = \"plain\";\n processed.push(line);\n continue;\n }\n\n processed.push(line);\n }\n\n return processed.join(\"\\n\");\n}\n\nfunction consumeMarkdownTable(lines: string[], startIndex: number): ConsumedTable | null {\n if (startIndex + 1 >= lines.length) {\n return null;\n }\n\n const headerCells = parseMarkdownTableRow(lines[startIndex] ?? \"\");\n const separatorCells = parseMarkdownTableSeparator(lines[startIndex + 1] ?? \"\");\n\n if (!headerCells || !separatorCells || headerCells.length !== separatorCells.length) {\n return null;\n }\n\n const rows = [headerCells];\n let index = startIndex + 2;\n\n while (index < lines.length) {\n const rowCells = parseMarkdownTableRow(lines[index] ?? \"\");\n\n if (!rowCells || rowCells.length !== headerCells.length) {\n break;\n }\n\n rows.push(rowCells);\n index += 1;\n }\n\n return {\n rows,\n nextIndex: index,\n };\n}\n\nfunction parseMarkdownTableRow(line: string): string[] | null {\n const trimmed = line.trim();\n\n if (!trimmed.includes(\"|\")) {\n return null;\n }\n\n const cells = splitMarkdownTableCells(trimmed)\n .map((cell) => normalizeTableCell(cell));\n\n return cells.length >= 2 ? cells : null;\n}\n\nfunction parseMarkdownTableSeparator(line: string): string[] | null {\n const cells = splitMarkdownTableCells(line.trim());\n\n if (cells.length < 2) {\n return null;\n }\n\n return cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()))\n ? cells\n : null;\n}\n\nfunction splitMarkdownTableCells(line: string): string[] {\n const content = line\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\");\n const cells: string[] = [];\n let current = \"\";\n let escaped = false;\n\n for (const char of content) {\n if (escaped) {\n current += char;\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n escaped = true;\n current += char;\n continue;\n }\n\n if (char === \"|\") {\n cells.push(current);\n current = \"\";\n continue;\n }\n\n current += char;\n }\n\n cells.push(current);\n return cells;\n}\n\nfunction normalizeTableCell(cell: string): string {\n return cell\n .trim()\n .replace(/\\\\\\|/g, \"|\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1 ($2)\")\n .replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\")\n .replace(/(\\*|_)(.*?)\\1/g, \"$2\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(HTML_TAG_PATTERN, \"\");\n}\n\nfunction renderTableAsPlainText(rows: string[][]): string {\n return buildAlignedTableLines(rows).join(\"\\n\");\n}\n\nfunction buildAlignedTableLines(rows: string[][]): string[] {\n const columnWidths = calculateTableColumnWidths(rows);\n const header = formatTableRow(rows[0] ?? [], columnWidths);\n const separator = columnWidths.map((width) => \"-\".repeat(Math.max(3, width))).join(\"-+-\");\n const body = rows.slice(1).map((row) => formatTableRow(row, columnWidths));\n\n return [header, separator, ...body];\n}\n\nfunction calculateTableColumnWidths(rows: string[][]): number[] {\n return (rows[0] ?? []).map((_, columnIndex) =>\n rows.reduce((maxWidth, row) => Math.max(maxWidth, getDisplayWidth(row[columnIndex] ?? \"\")), 0),\n );\n}\n\nfunction formatTableRow(row: string[], columnWidths: number[]): string {\n return row\n .map((cell, index) => padDisplayWidth(cell, columnWidths[index] ?? 0))\n .join(\" | \");\n}\n\nfunction padDisplayWidth(value: string, targetWidth: number): string {\n const padding = Math.max(0, targetWidth - getDisplayWidth(value));\n\n return `${value}${\" \".repeat(padding)}`;\n}\n\nfunction getDisplayWidth(value: string): number {\n let width = 0;\n\n for (const char of value) {\n width += isWideCharacter(char.codePointAt(0) ?? 0) ? 2 : 1;\n }\n\n return width;\n}\n\nfunction isWideCharacter(codePoint: number): boolean {\n return codePoint >= 0x1100 && (\n codePoint <= 0x115f ||\n codePoint === 0x2329 ||\n codePoint === 0x232a ||\n (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||\n (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||\n (codePoint >= 0xf900 && codePoint <= 0xfaff) ||\n (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||\n (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||\n (codePoint >= 0xff00 && codePoint <= 0xff60) ||\n (codePoint >= 0xffe0 && codePoint <= 0xffe6)\n );\n}\n","import {\n createOpencodeClient,\n type OpencodeClient,\n} from \"@opencode-ai/sdk\";\nimport type {\n Agent,\n Config,\n LspStatus,\n McpStatus,\n Model,\n OutputFormat,\n Part,\n Path,\n Provider,\n Project,\n Session,\n SessionStatus,\n} from \"@opencode-ai/sdk/v2/client\";\nimport { stripMarkdownToPlainText } from \"../../infra/utils/markdown-text.js\";\n\nexport interface OpenCodeClientOptions {\n baseUrl: string;\n apiKey?: string;\n}\n\nexport interface OpenCodePromptTimeoutPolicy {\n pollRequestTimeoutMs: number;\n recoveryInactivityTimeoutMs: number;\n waitTimeoutMs: number;\n}\n\nexport function buildOpenCodeSdkConfig(options: OpenCodeClientOptions) {\n const apiKey = options.apiKey?.trim();\n\n return {\n baseUrl: options.baseUrl,\n ...(apiKey ? { auth: apiKey } : {}),\n };\n}\n\nexport interface PromptSessionInput {\n sessionId: string;\n prompt?: string | null;\n agent?: string | null;\n format?: OpenCodeTextOutputFormat;\n signal?: AbortSignal;\n model?: {\n providerID: string;\n modelID: string;\n };\n variant?: string | null;\n files?: PromptSessionFilePartInput[];\n}\n\nexport interface PromptSessionFilePartInput {\n filename?: string;\n mime: string;\n url: string;\n}\n\nexport interface PromptSessionTokenMetrics {\n total: number | null;\n input: number | null;\n output: number | null;\n reasoning: number | null;\n cacheRead: number | null;\n cacheWrite: number | null;\n}\n\nexport interface PromptSessionMetrics {\n durationMs: number | null;\n tokens: PromptSessionTokenMetrics;\n}\n\nexport interface PromptSessionResult {\n assistantError: OpenCodeAssistantError | null;\n bodyMd: string | null;\n fallbackText: string;\n info: OpenCodeAssistantMessage | null;\n metrics: PromptSessionMetrics;\n parts: Part[];\n structured: unknown;\n}\n\nexport type OpenCodeProject = Project;\nexport type OpenCodeSession = Session;\nexport type OpenCodeModel = Model;\nexport type OpenCodeProvider = Provider;\nexport type OpenCodeConfig = Config;\nexport type OpenCodeAgent = Agent;\nexport type OpenCodeLspStatus = LspStatus;\nexport type OpenCodePath = Path;\nexport type OpenCodeMcpStatus = McpStatus;\nexport type OpenCodeSessionStatus = SessionStatus;\nexport interface OpenCodePermissionRequest {\n always: string[];\n id: string;\n metadata: Record<string, unknown>;\n patterns: string[];\n permission: string;\n sessionID: string;\n}\nexport interface OpenCodeHealth {\n healthy: boolean;\n version: string;\n}\n\nexport interface OpenCodeConfiguredModel {\n id: string;\n providerID: string;\n providerName: string;\n name: string;\n qualifiedId: string;\n reasoning: boolean;\n variants: Record<string, Record<string, unknown>>;\n}\nexport type OpenCodeTextOutputFormat = Extract<OutputFormat, { type: \"text\" }>;\n\ntype RawSdkRequestOptions = {\n responseStyle?: \"data\" | \"fields\";\n signal?: AbortSignal;\n throwOnError?: boolean;\n url: string;\n};\n\ntype RawSdkRequestClient = {\n get?(options: RawSdkRequestOptions): Promise<unknown>;\n};\n\ntype OpenCodeSdkPermissionScopeLike = {\n list?(parameters?: unknown, options?: Record<string, unknown>): Promise<unknown>;\n reply?(parameters?: unknown, options?: Record<string, unknown>): Promise<unknown>;\n};\n\ntype OpenCodeSdkScopedClientLike = Pick<OpencodeClient, \"app\" | \"config\" | \"global\" | \"lsp\" | \"mcp\" | \"path\" | \"project\" | \"session\"> & {\n permission?: OpenCodeSdkPermissionScopeLike;\n};\n\ntype OpenCodeSdkPermissionReplyClientLike = {\n postSessionIdPermissionsPermissionId?(options: Record<string, unknown>): Promise<unknown>;\n};\n\nexport type OpenCodeSdkClientLike = OpenCodeSdkScopedClientLike & OpenCodeSdkPermissionReplyClientLike;\n\ntype OpenCodeSdkClientWithRawRequestClient = OpenCodeSdkClientLike & {\n _client?: RawSdkRequestClient;\n client?: RawSdkRequestClient;\n};\ntype MaybeWrappedResponse<T> = T | { data: T };\ntype ScopedSdkScope = \"app\" | \"config\" | \"global\" | \"lsp\" | \"mcp\" | \"path\" | \"permission\" | \"project\" | \"session\";\ntype ScopedSdkInvocationInput = {\n legacyParameters?: unknown;\n parameters?: Record<string, unknown>;\n signal?: AbortSignal;\n};\ntype OpenCodeProviderCatalog = {\n providers: OpenCodeProvider[];\n default: Record<string, string>;\n};\ntype OpenCodeProviderAvailability = Map<string, Set<string> | null>;\ntype OpenCodeProviderConfig = NonNullable<OpenCodeConfig[\"provider\"]>[string];\ntype OpenCodeModelConfig = NonNullable<OpenCodeProviderConfig[\"models\"]>[string];\ntype OpenCodePromptResponse = {\n info: unknown;\n parts?: Part[] | null;\n};\n\nexport type OpenCodePromptTimeoutStage =\n | \"capture-known-messages\"\n | \"send-prompt\"\n | \"poll-message\"\n | \"poll-messages\"\n | \"poll-status\"\n | \"final-scan\";\n\nexport interface OpenCodePromptTimeoutErrorData {\n elapsedMs: number;\n message?: string;\n messageId?: string;\n sessionId: string;\n stage: OpenCodePromptTimeoutStage;\n timeoutMs: number;\n}\n\nexport class OpenCodePromptTimeoutError extends Error {\n readonly data: OpenCodePromptTimeoutErrorData;\n\n constructor(data: OpenCodePromptTimeoutErrorData) {\n super(data.message ?? \"OpenCode prompt timed out.\");\n this.name = \"OpenCodePromptTimeoutError\";\n this.data = data;\n }\n}\n\nexport class OpenCodeMessageAbortedError extends Error {\n readonly data?: {\n message?: string;\n };\n\n constructor(message = \"Request was aborted.\") {\n super(message);\n this.name = \"MessageAbortedError\";\n this.data = {\n message,\n };\n }\n}\n\nexport function createMessageAbortedError(message = \"Request was aborted.\"): OpenCodeMessageAbortedError {\n return new OpenCodeMessageAbortedError(message);\n}\n\nexport interface OpenCodeAssistantError {\n data?: Record<string, unknown>;\n name: string;\n [key: string]: unknown;\n}\n\nexport interface OpenCodeAssistantMessage {\n agent?: string;\n cost?: number;\n error?: OpenCodeAssistantError;\n finish?: string;\n id?: string;\n mode?: string;\n modelID?: string;\n parentID?: string;\n path?: {\n cwd?: string;\n root?: string;\n };\n providerID?: string;\n role?: \"assistant\";\n sessionID?: string;\n summary?: boolean;\n time?: {\n completed?: number;\n created?: number;\n };\n tokens?: {\n cache?: {\n read?: number;\n write?: number;\n };\n input?: number;\n output?: number;\n reasoning?: number;\n total?: number;\n };\n variant?: string;\n}\n\nconst EMPTY_RESPONSE_TEXT = \"OpenCode returned empty response.\";\nconst PROMPT_MESSAGE_POLL_INITIAL_DELAYS_MS = [0, 100, 250, 500, 1000];\nconst PROMPT_MESSAGE_POLL_INTERVAL_MS = 2000;\nconst PROMPT_MESSAGE_POLL_LIMIT = 20;\nconst PROMPT_LOG_SERVICE = \"opencode-tbot\";\nconst DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY: OpenCodePromptTimeoutPolicy = {\n pollRequestTimeoutMs: 15_000,\n recoveryInactivityTimeoutMs: 120_000,\n waitTimeoutMs: 1_800_000,\n};\nconst SDK_OPTIONS = {\n responseStyle: \"data\" as const,\n throwOnError: true as const,\n};\nconst TEXT_OUTPUT_FORMAT: OpenCodeTextOutputFormat = {\n type: \"text\",\n};\n\nexport interface OpenCodeClientLike {\n readonly client?: OpenCodeSdkClientLike;\n abortSession(sessionId: string): Promise<boolean>;\n deleteSession(sessionId: string): Promise<boolean>;\n forkSession(sessionId: string, messageId?: string): Promise<OpenCodeSession>;\n getHealth(): Promise<OpenCodeHealth>;\n getPath(): Promise<OpenCodePath>;\n listLspStatuses(directory?: string): Promise<OpenCodeLspStatus[]>;\n listMcpStatuses(directory?: string): Promise<Record<string, OpenCodeMcpStatus>>;\n getSessionStatuses(): Promise<Record<string, OpenCodeSessionStatus>>;\n listProjects(): Promise<OpenCodeProject[]>;\n listSessions(): Promise<OpenCodeSession[]>;\n getCurrentProject(): Promise<OpenCodeProject>;\n createSessionForDirectory(directory: string, title?: string): Promise<OpenCodeSession>;\n renameSession(sessionId: string, title: string): Promise<OpenCodeSession>;\n listAgents(): Promise<OpenCodeAgent[]>;\n listPendingPermissions(directory?: string): Promise<OpenCodePermissionRequest[]>;\n replyToPermission(\n requestId: string,\n reply: \"once\" | \"always\" | \"reject\",\n message?: string,\n sessionId?: string,\n ): Promise<boolean>;\n listConfiguredPlugins?(): Promise<string[]>;\n listModels(): Promise<OpenCodeConfiguredModel[]>;\n promptSession(input: PromptSessionInput): Promise<PromptSessionResult>;\n}\n\nexport class OpenCodeClient implements OpenCodeClientLike {\n readonly client: OpenCodeSdkClientLike;\n private readonly fetchFn: typeof fetch;\n private promptTimeoutPolicy: OpenCodePromptTimeoutPolicy;\n private modelCache: {\n expiresAt: number;\n promise: Promise<OpenCodeConfiguredModel[]> | null;\n value: OpenCodeConfiguredModel[] | null;\n } = {\n expiresAt: 0,\n promise: null,\n value: null,\n };\n\n constructor(\n options?: OpenCodeClientOptions,\n client?: OpenCodeSdkClientLike,\n fetchFn: typeof fetch = fetch,\n promptTimeoutPolicy: Partial<OpenCodePromptTimeoutPolicy> = {},\n ) {\n if (!options && !client) {\n throw new Error(\"OpenCodeClient requires either base URL options or an injected SDK client.\");\n }\n\n this.client = client ?? createOpencodeClient(buildOpenCodeSdkConfig(options as OpenCodeClientOptions));\n this.fetchFn = fetchFn;\n this.promptTimeoutPolicy = resolvePromptTimeoutPolicy(promptTimeoutPolicy);\n }\n\n configurePromptTimeoutPolicy(\n promptTimeoutPolicy: Partial<OpenCodePromptTimeoutPolicy>,\n ): void {\n this.promptTimeoutPolicy = resolvePromptTimeoutPolicy({\n ...this.promptTimeoutPolicy,\n ...promptTimeoutPolicy,\n });\n }\n\n private async callScopedSdkMethod<T>(\n scope: ScopedSdkScope,\n method: string,\n input: ScopedSdkInvocationInput,\n ): Promise<T> {\n const target = this.client[scope] as unknown as Record<string, unknown> | undefined;\n const handler = target?.[method];\n\n if (typeof handler !== \"function\") {\n throw new Error(`OpenCode SDK client does not expose a compatible ${scope}.${method} method.`);\n }\n\n const options = {\n ...SDK_OPTIONS,\n ...(input.signal ? { signal: input.signal } : {}),\n };\n const response = handler.length >= 2\n ? await (handler as (parameters: unknown, requestOptions: Record<string, unknown>) => Promise<MaybeWrappedResponse<T>>).call(\n target,\n input.legacyParameters,\n options,\n )\n : await (handler as (requestOptions: Record<string, unknown>) => Promise<MaybeWrappedResponse<T>>).call(\n target,\n input.parameters === undefined\n ? options\n : {\n ...input.parameters,\n ...options,\n },\n );\n\n return unwrapSdkData(response);\n }\n\n async getHealth(): Promise<OpenCodeHealth> {\n try {\n return await this.callScopedSdkMethod<OpenCodeHealth>(\"global\", \"health\", {});\n } catch (error) {\n if (!isMissingScopedSdkMethodError(error, \"global\", \"health\")) {\n throw error;\n }\n\n return this.callRawSdkGet<OpenCodeHealth>(\"/global/health\");\n }\n }\n\n async abortSession(sessionId: string): Promise<boolean> {\n return this.callScopedSdkMethod<boolean>(\"session\", \"abort\", {\n legacyParameters: {\n sessionID: sessionId,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n },\n });\n }\n\n async deleteSession(sessionId: string): Promise<boolean> {\n return this.callScopedSdkMethod<boolean>(\"session\", \"delete\", {\n legacyParameters: {\n sessionID: sessionId,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n },\n });\n }\n\n async forkSession(sessionId: string, messageId?: string): Promise<OpenCodeSession> {\n return this.callScopedSdkMethod<OpenCodeSession>(\"session\", \"fork\", {\n legacyParameters: {\n sessionID: sessionId,\n ...(messageId?.trim()\n ? { messageID: messageId.trim() }\n : {}),\n },\n parameters: {\n path: {\n id: sessionId,\n },\n ...(\n messageId?.trim()\n ? {\n body: {\n messageID: messageId.trim(),\n },\n }\n : {}\n ),\n },\n });\n }\n\n async getPath(): Promise<OpenCodePath> {\n return this.callScopedSdkMethod<OpenCodePath>(\"path\", \"get\", {});\n }\n\n async listLspStatuses(directory?: string): Promise<OpenCodeLspStatus[]> {\n return this.callScopedSdkMethod<OpenCodeLspStatus[]>(\"lsp\", \"status\", {\n legacyParameters: directory\n ? { directory }\n : undefined,\n parameters: directory\n ? {\n query: {\n directory,\n },\n }\n : undefined,\n });\n }\n\n async listMcpStatuses(directory?: string): Promise<Record<string, OpenCodeMcpStatus>> {\n return this.callScopedSdkMethod<Record<string, OpenCodeMcpStatus>>(\"mcp\", \"status\", {\n legacyParameters: directory\n ? { directory }\n : undefined,\n parameters: directory\n ? {\n query: {\n directory,\n },\n }\n : undefined,\n });\n }\n\n async getSessionStatuses(): Promise<Record<string, OpenCodeSessionStatus>> {\n return this.loadSessionStatuses();\n }\n\n async listProjects(): Promise<OpenCodeProject[]> {\n return this.callScopedSdkMethod<OpenCodeProject[]>(\"project\", \"list\", {});\n }\n\n async listSessions(): Promise<OpenCodeSession[]> {\n return this.callScopedSdkMethod<OpenCodeSession[]>(\"session\", \"list\", {});\n }\n\n async getCurrentProject(): Promise<OpenCodeProject> {\n return this.callScopedSdkMethod<OpenCodeProject>(\"project\", \"current\", {});\n }\n\n async createSessionForDirectory(directory: string, title?: string): Promise<OpenCodeSession> {\n return this.callScopedSdkMethod<OpenCodeSession>(\"session\", \"create\", {\n legacyParameters: title ? { directory, title } : { directory },\n parameters: {\n query: {\n directory,\n },\n ...(title\n ? {\n body: {\n title,\n },\n }\n : {}),\n },\n });\n }\n\n async renameSession(sessionId: string, title: string): Promise<OpenCodeSession> {\n return this.callScopedSdkMethod<OpenCodeSession>(\"session\", \"update\", {\n legacyParameters: {\n sessionID: sessionId,\n title,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n body: {\n title,\n },\n },\n });\n }\n\n async listAgents(): Promise<OpenCodeAgent[]> {\n return this.callScopedSdkMethod<OpenCodeAgent[]>(\"app\", \"agents\", {});\n }\n\n async listPendingPermissions(directory?: string): Promise<OpenCodePermissionRequest[]> {\n const permissions = await this.callScopedSdkMethod<unknown[]>(\"permission\", \"list\", {\n legacyParameters: directory\n ? { directory }\n : undefined,\n parameters: directory\n ? {\n query: {\n directory,\n },\n }\n : undefined,\n });\n\n return permissions.map(normalizePermissionRequest).filter((permission): permission is OpenCodePermissionRequest => !!permission);\n }\n\n async replyToPermission(\n requestId: string,\n reply: \"once\" | \"always\" | \"reject\",\n message?: string,\n sessionId?: string,\n ): Promise<boolean> {\n const normalizedMessage = message?.trim();\n const rootPermissionHandler = this.client.postSessionIdPermissionsPermissionId;\n\n if (sessionId && typeof rootPermissionHandler === \"function\") {\n return unwrapSdkData(await rootPermissionHandler.call(this.client, {\n ...SDK_OPTIONS,\n body: {\n response: reply,\n ...(normalizedMessage\n ? { message: normalizedMessage }\n : {}),\n },\n path: {\n id: sessionId,\n permissionID: requestId,\n },\n }) as MaybeWrappedResponse<boolean>);\n }\n\n return this.callScopedSdkMethod<boolean>(\"permission\", \"reply\", {\n legacyParameters: {\n requestID: requestId,\n reply,\n ...(normalizedMessage\n ? { message: normalizedMessage }\n : {}),\n },\n parameters: sessionId\n ? {\n body: {\n response: reply,\n ...(normalizedMessage\n ? { message: normalizedMessage }\n : {}),\n },\n path: {\n id: sessionId,\n permissionID: requestId,\n },\n }\n : undefined,\n });\n }\n\n async listModels(): Promise<OpenCodeConfiguredModel[]> {\n const now = Date.now();\n\n if (this.modelCache.value && this.modelCache.expiresAt > now) {\n return this.modelCache.value;\n }\n\n if (this.modelCache.promise) {\n return this.modelCache.promise;\n }\n\n const refreshPromise = this.loadModels().finally(() => {\n if (this.modelCache.promise === refreshPromise) {\n this.modelCache.promise = null;\n }\n });\n\n this.modelCache.promise = refreshPromise;\n\n return refreshPromise;\n }\n\n async listConfiguredPlugins(): Promise<string[]> {\n const config = await this.loadConfig();\n\n return normalizeConfiguredPluginSpecs(config.plugin);\n }\n\n async promptSession(input: PromptSessionInput): Promise<PromptSessionResult> {\n const startedAt = Date.now();\n const promptText = input.prompt?.trim() ?? \"\";\n const parts = [\n ...(promptText\n ? [{\n type: \"text\" as const,\n text: promptText,\n }]\n : []),\n ...((input.files ?? []).map((file) => ({\n type: \"file\" as const,\n filename: file.filename,\n mime: file.mime,\n url: file.url,\n }))),\n ];\n\n if (parts.length === 0) {\n throw new Error(\"Prompt requires text or file attachments.\");\n }\n\n throwIfAborted(input.signal);\n\n const knownMessageIds = await this.captureKnownMessageIds(input.sessionId, input.signal);\n await this.sendPromptRequest(input, parts);\n const resolvedData = await this.resolvePromptResponse(\n input,\n null,\n knownMessageIds,\n startedAt,\n );\n const finishedAt = Date.now();\n\n return buildPromptSessionResult(resolvedData, {\n emptyResponseText: EMPTY_RESPONSE_TEXT,\n finishedAt,\n startedAt,\n });\n }\n\n private async resolvePromptResponse(\n input: PromptSessionInput,\n data: OpenCodePromptResponse | null,\n knownMessageIds: Set<string>,\n startedAt: number,\n ): Promise<OpenCodePromptResponse> {\n if (data && shouldReturnPromptResponseImmediately(data)) {\n return data;\n }\n\n const messageId = data ? extractMessageId(data.info) : null;\n const candidateOptions: PromptResponseCandidateOptions = {\n initialMessageId: messageId,\n initialParentId: data ? toAssistantMessage(data.info)?.parentID ?? null : null,\n knownMessageIds,\n requestStartedAt: resolvePromptCandidateStartTime(startedAt, data),\n };\n let bestCandidate = selectPromptResponseCandidate(\n data ? [data] : [],\n candidateOptions,\n );\n let lastProgressAt = Date.now();\n let lastStatus: OpenCodeSessionStatus | null = null;\n const deadlineAt = startedAt + this.promptTimeoutPolicy.waitTimeoutMs;\n let idleStatusSeen = false;\n let attempt = 0;\n\n while (true) {\n throwIfAborted(input.signal);\n\n const remainingWaitMs = deadlineAt - Date.now();\n const remainingInactivityMs = this.promptTimeoutPolicy.recoveryInactivityTimeoutMs - (Date.now() - lastProgressAt);\n\n if (remainingWaitMs <= 0 || remainingInactivityMs <= 0) {\n break;\n }\n\n const delayMs = getPromptMessagePollDelayMs(attempt);\n attempt += 1;\n\n if (delayMs > 0) {\n const remainingMs = Math.min(remainingWaitMs, remainingInactivityMs);\n\n if (remainingMs <= 0) {\n break;\n }\n\n await delay(Math.min(delayMs, remainingMs), input.signal);\n }\n\n if (messageId) {\n const next = await this.fetchPromptMessage(input.sessionId, messageId, input.signal);\n\n if (next) {\n const nextCandidate = selectPromptResponseCandidate(\n [bestCandidate, next],\n candidateOptions,\n );\n\n if (nextCandidate) {\n if (didPromptResponseAdvance(bestCandidate, nextCandidate)) {\n lastProgressAt = Date.now();\n idleStatusSeen = false;\n }\n\n bestCandidate = nextCandidate;\n }\n\n if (\n bestCandidate\n && isPromptResponseForCurrentRequest(bestCandidate, candidateOptions)\n && shouldReturnPromptResponseImmediately(bestCandidate)\n ) {\n return bestCandidate;\n }\n }\n }\n\n const latest = await this.findLatestPromptResponse(\n input.sessionId,\n candidateOptions,\n \"poll-messages\",\n input.signal,\n );\n\n if (latest) {\n const nextCandidate = selectPromptResponseCandidate(\n [bestCandidate, latest],\n candidateOptions,\n );\n\n if (nextCandidate) {\n if (didPromptResponseAdvance(bestCandidate, nextCandidate)) {\n lastProgressAt = Date.now();\n idleStatusSeen = false;\n }\n\n bestCandidate = nextCandidate;\n }\n\n if (\n bestCandidate\n && isPromptResponseForCurrentRequest(bestCandidate, candidateOptions)\n && shouldReturnPromptResponseImmediately(bestCandidate)\n ) {\n return bestCandidate;\n }\n }\n\n const status = await this.fetchPromptSessionStatus(input.sessionId, input.signal);\n\n lastStatus = status;\n\n if (status?.type === \"busy\" || status?.type === \"retry\") {\n lastProgressAt = Date.now();\n idleStatusSeen = false;\n } else if (status?.type === \"idle\") {\n if (idleStatusSeen) {\n break;\n }\n\n idleStatusSeen = true;\n }\n\n if (\n bestCandidate\n && isPromptResponseForCurrentRequest(bestCandidate, candidateOptions)\n && isCompletedEmptyPromptResponse(bestCandidate)\n && status?.type !== \"busy\"\n && status?.type !== \"retry\"\n ) {\n break;\n }\n\n if (Date.now() >= deadlineAt) {\n break;\n }\n }\n\n const latest = await this.findLatestPromptResponse(\n input.sessionId,\n candidateOptions,\n \"final-scan\",\n input.signal,\n );\n\n const resolved = selectPromptResponseCandidate(\n [bestCandidate, latest],\n candidateOptions,\n );\n const requestScopedResolved = resolved && isPromptResponseForCurrentRequest(resolved, candidateOptions)\n ? resolved\n : null;\n\n if (\n lastStatus?.type === \"idle\"\n && (!requestScopedResolved || shouldPollPromptMessage(requestScopedResolved))\n ) {\n throw createMessageAbortedError();\n }\n\n if (!requestScopedResolved || shouldPollPromptMessage(requestScopedResolved)) {\n const timeoutReason = Date.now() >= deadlineAt\n ? \"max-wait\"\n : \"recovery-inactivity\";\n const timeoutMs = timeoutReason === \"max-wait\"\n ? this.promptTimeoutPolicy.waitTimeoutMs\n : this.promptTimeoutPolicy.recoveryInactivityTimeoutMs;\n const error = createOpenCodePromptTimeoutError({\n sessionId: input.sessionId,\n stage: \"final-scan\",\n timeoutMs,\n messageId: messageId ?? undefined,\n });\n this.logPromptRequest(\"warn\", {\n lastProgressAt,\n messageId: messageId ?? undefined,\n sessionId: input.sessionId,\n stage: \"final-scan\",\n timeoutMs,\n timeoutReason,\n }, \"OpenCode prompt recovery timed out\");\n throw error;\n }\n\n return requestScopedResolved;\n }\n\n private async fetchPromptMessage(\n sessionId: string,\n messageId: string,\n signal?: AbortSignal,\n ): Promise<OpenCodePromptResponse | null> {\n try {\n return await this.runPromptRequestWithTimeout(\n {\n sessionId,\n stage: \"poll-message\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n messageId,\n },\n async (requestSignal) => {\n return normalizePromptResponse(await this.callScopedSdkMethod<OpenCodePromptResponse>(\"session\", \"message\", {\n legacyParameters: {\n sessionID: sessionId,\n messageID: messageId,\n },\n parameters: {\n path: {\n id: sessionId,\n messageID: messageId,\n },\n },\n signal: requestSignal,\n }));\n },\n signal,\n );\n } catch (error) {\n if (isPromptRequestAbort(error)) {\n throw error;\n }\n\n this.logPromptRequestFailure(error, {\n sessionId,\n stage: \"poll-message\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n messageId,\n });\n return null;\n }\n }\n\n private async captureKnownMessageIds(sessionId: string, signal?: AbortSignal): Promise<Set<string>> {\n const messages = await this.fetchRecentPromptMessages(sessionId, \"capture-known-messages\", signal);\n\n if (!messages) {\n return new Set();\n }\n\n return new Set(\n messages\n .map((message) => extractMessageId(message.info))\n .filter((id): id is string => typeof id === \"string\" && id.length > 0),\n );\n }\n\n private async fetchRecentPromptMessages(\n sessionId: string,\n stage: Extract<OpenCodePromptTimeoutStage, \"capture-known-messages\" | \"poll-messages\" | \"final-scan\">,\n signal?: AbortSignal,\n ): Promise<OpenCodePromptResponse[] | null> {\n try {\n return await this.runPromptRequestWithTimeout(\n {\n sessionId,\n stage,\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n },\n async (requestSignal) => {\n return normalizePromptResponses(await this.callScopedSdkMethod<OpenCodePromptResponse[]>(\"session\", \"messages\", {\n legacyParameters: {\n sessionID: sessionId,\n limit: PROMPT_MESSAGE_POLL_LIMIT,\n },\n parameters: {\n path: {\n id: sessionId,\n },\n query: {\n limit: PROMPT_MESSAGE_POLL_LIMIT,\n },\n },\n signal: requestSignal,\n }));\n },\n signal,\n );\n } catch (error) {\n if (isPromptRequestAbort(error)) {\n throw error;\n }\n\n this.logPromptRequestFailure(error, {\n sessionId,\n stage,\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n });\n return null;\n }\n }\n\n private async fetchPromptSessionStatus(sessionId: string, signal?: AbortSignal): Promise<OpenCodeSessionStatus | null> {\n try {\n const statuses = await this.runPromptRequestWithTimeout(\n {\n sessionId,\n stage: \"poll-status\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n },\n async (requestSignal) => this.loadSessionStatuses(requestSignal),\n signal,\n );\n\n return statuses[sessionId] ?? null;\n } catch (error) {\n if (isPromptRequestAbort(error)) {\n throw error;\n }\n\n this.logPromptRequestFailure(error, {\n sessionId,\n stage: \"poll-status\",\n timeoutMs: this.promptTimeoutPolicy.pollRequestTimeoutMs,\n });\n return null;\n }\n }\n\n private async findLatestPromptResponse(\n sessionId: string,\n options: PromptResponseCandidateOptions,\n stage: Extract<OpenCodePromptTimeoutStage, \"poll-messages\" | \"final-scan\">,\n signal?: AbortSignal,\n ): Promise<OpenCodePromptResponse | null> {\n const messages = await this.fetchRecentPromptMessages(sessionId, stage, signal);\n\n if (!messages || messages.length === 0) {\n return null;\n }\n\n return selectPromptResponseCandidate(messages, options);\n }\n\n private async loadModels(): Promise<OpenCodeConfiguredModel[]> {\n const [config, providerCatalog] = await Promise.all([\n this.loadConfig(),\n this.loadProviderCatalog(),\n ]);\n const providerAvailability = await resolveProviderAvailability(config, this.fetchFn);\n const models = buildSelectableModels(\n config,\n providerCatalog.providers,\n providerAvailability,\n );\n\n this.modelCache = {\n expiresAt: Date.now() + 60_000,\n promise: null,\n value: models,\n };\n\n return models;\n }\n\n private async loadConfig(): Promise<OpenCodeConfig> {\n return this.callScopedSdkMethod<OpenCodeConfig>(\"config\", \"get\", {});\n }\n\n private async loadProviderCatalog(): Promise<OpenCodeProviderCatalog> {\n return this.callScopedSdkMethod<OpenCodeProviderCatalog>(\"config\", \"providers\", {});\n }\n\n private async sendPromptRequest(\n input: PromptSessionInput,\n parts: Array<\n | { type: \"text\"; text: string }\n | { type: \"file\"; filename?: string; mime: string; url: string }\n >,\n ): Promise<void> {\n const format = input.format ?? TEXT_OUTPUT_FORMAT;\n const requestBody = {\n ...(input.agent ? { agent: input.agent } : {}),\n format,\n ...(input.model ? { model: input.model } : {}),\n ...(input.variant ? { variant: input.variant } : {}),\n parts,\n };\n const legacyRequestParameters = {\n sessionID: input.sessionId,\n ...requestBody,\n };\n const requestParameters = {\n body: requestBody,\n path: {\n id: input.sessionId,\n },\n };\n\n try {\n if (typeof this.client.session?.promptAsync === \"function\") {\n await this.runPromptRequestWithTimeout(\n {\n sessionId: input.sessionId,\n stage: \"send-prompt\",\n timeoutMs: this.promptTimeoutPolicy.waitTimeoutMs,\n },\n async (signal) => {\n await this.callScopedSdkMethod<void>(\"session\", \"promptAsync\", {\n legacyParameters: legacyRequestParameters,\n parameters: requestParameters,\n signal,\n });\n },\n input.signal,\n );\n\n return;\n }\n } catch (error) {\n this.logPromptRequestFailure(error, {\n sessionId: input.sessionId,\n stage: \"send-prompt\",\n timeoutMs: this.promptTimeoutPolicy.waitTimeoutMs,\n });\n throw error;\n }\n\n throw new Error(\"OpenCode SDK client does not expose session.promptAsync().\");\n }\n\n private async loadSessionStatuses(\n signal?: AbortSignal,\n ): Promise<Record<string, OpenCodeSessionStatus>> {\n return this.callScopedSdkMethod<Record<string, OpenCodeSessionStatus>>(\"session\", \"status\", {\n signal,\n });\n }\n\n private async callRawSdkGet<T>(\n url: string,\n signal?: AbortSignal,\n ): Promise<T> {\n const rawClient = getRawSdkRequestClient(this.client);\n\n if (typeof rawClient?.get !== \"function\") {\n throw new Error(`OpenCode SDK client does not expose a compatible raw GET endpoint for ${url}.`);\n }\n\n const response = await rawClient.get({\n ...SDK_OPTIONS,\n ...(signal ? { signal } : {}),\n url,\n }) as MaybeWrappedResponse<T>;\n\n return unwrapSdkData(response);\n }\n\n private async runPromptRequestWithTimeout<T>(\n input: {\n messageId?: string | null;\n sessionId: string;\n stage: OpenCodePromptTimeoutStage;\n timeoutMs: number;\n },\n operation: (signal: AbortSignal) => Promise<T>,\n signal?: AbortSignal,\n ): Promise<T> {\n const startedAt = Date.now();\n const controller = new AbortController();\n const requestSignal = signal\n ? AbortSignal.any([signal, controller.signal])\n : controller.signal;\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n let removeAbortListener = () => undefined;\n\n const abortPromise = signal\n ? new Promise<never>((_, reject) => {\n const onAbort = () => {\n reject(normalizeAbortReason(signal.reason));\n };\n\n if (signal.aborted) {\n onAbort();\n return;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n removeAbortListener = () => {\n signal.removeEventListener(\"abort\", onAbort);\n };\n })\n : null;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n reject(createOpenCodePromptTimeoutError({\n sessionId: input.sessionId,\n stage: input.stage,\n timeoutMs: input.timeoutMs,\n messageId: input.messageId ?? undefined,\n elapsedMs: Date.now() - startedAt,\n }));\n controller.abort();\n }, input.timeoutMs);\n });\n\n try {\n return await Promise.race([\n operation(requestSignal),\n timeoutPromise,\n ...(abortPromise ? [abortPromise] : []),\n ]);\n } finally {\n if (timeoutHandle !== null) {\n clearTimeout(timeoutHandle);\n }\n\n removeAbortListener();\n }\n }\n\n private logPromptRequestFailure(\n error: unknown,\n input: {\n messageId?: string | null;\n sessionId: string;\n stage: OpenCodePromptTimeoutStage;\n timeoutMs: number;\n },\n ) {\n if (error instanceof OpenCodePromptTimeoutError) {\n this.logPromptRequest(\"warn\", {\n endpointKind: resolvePromptEndpointKind(error.data.stage),\n elapsedMs: error.data.elapsedMs,\n messageId: error.data.messageId,\n sessionId: error.data.sessionId,\n stage: error.data.stage,\n timeoutMs: error.data.timeoutMs,\n }, \"OpenCode prompt request timed out\");\n return;\n }\n\n this.logPromptRequest(\"warn\", {\n endpointKind: resolvePromptEndpointKind(input.stage),\n error,\n messageId: input.messageId ?? undefined,\n sessionId: input.sessionId,\n stage: input.stage,\n timeoutMs: input.timeoutMs,\n }, \"OpenCode prompt request failed\");\n }\n\n private logPromptRequest(\n level: \"warn\" | \"error\" | \"info\",\n extra: Record<string, unknown>,\n message: string,\n ) {\n const log = this.client.app?.log;\n\n if (typeof log !== \"function\") {\n return;\n }\n\n const payload = {\n service: PROMPT_LOG_SERVICE,\n level,\n message,\n extra,\n };\n\n void (log.length >= 2\n ? (log as (body: Record<string, unknown>, options: Record<string, unknown>) => Promise<unknown>).call(\n this.client.app,\n payload,\n SDK_OPTIONS,\n )\n : (log as (options: Record<string, unknown>) => Promise<unknown>).call(this.client.app, {\n body: payload,\n ...SDK_OPTIONS,\n })\n ).catch(() => undefined);\n }\n}\n\nexport function createOpenCodeClientFromSdkClient(\n client: OpenCodeSdkClientLike,\n fetchFn: typeof fetch = fetch,\n promptTimeoutPolicy: Partial<OpenCodePromptTimeoutPolicy> = {},\n): OpenCodeClientLike {\n return new OpenCodeClient(undefined, client, fetchFn, promptTimeoutPolicy);\n}\n\nfunction buildSelectableModels(\n config: OpenCodeConfig,\n providers: OpenCodeProvider[],\n providerAvailability: OpenCodeProviderAvailability = new Map(),\n): OpenCodeConfiguredModel[] {\n const configuredProviders = config.provider ?? {};\n const providersById = new Map(providers.map((provider) => [provider.id, provider]));\n const models = new Map<string, OpenCodeConfiguredModel>();\n\n for (const [providerId, providerConfig] of Object.entries(configuredProviders)) {\n const configuredModels = providerConfig.models ?? {};\n\n for (const [configuredModelKey, modelConfig] of Object.entries(configuredModels)) {\n const model = buildConfiguredModel(\n providerId,\n providerConfig,\n configuredModelKey,\n modelConfig,\n providersById.get(providerId),\n providerAvailability.get(providerId) ?? null,\n );\n\n if (model) {\n models.set(model.qualifiedId, model);\n }\n }\n }\n\n for (const provider of providers) {\n for (const model of buildCatalogProviderModels(provider, providerAvailability.get(provider.id) ?? null)) {\n if (!models.has(model.qualifiedId)) {\n models.set(model.qualifiedId, model);\n }\n }\n }\n\n return [...models.values()];\n}\n\nfunction buildConfiguredModel(\n providerId: string,\n providerConfig: OpenCodeProviderConfig,\n configuredModelKey: string,\n modelConfig: OpenCodeModelConfig,\n providerCatalog: OpenCodeProvider | undefined,\n availableModelIds: Set<string> | null,\n): OpenCodeConfiguredModel | null {\n const modelId = modelConfig.id ?? configuredModelKey;\n const catalogModel = providerCatalog?.models[modelId];\n\n if (!isTextModel(modelConfig, catalogModel)) {\n return null;\n }\n\n if (!isModelAvailable(modelId, availableModelIds)) {\n return null;\n }\n\n return {\n id: modelId,\n providerID: providerId,\n providerName: resolveProviderDisplayName(providerId, providerConfig, providerCatalog),\n name: modelConfig.name ?? catalogModel?.name ?? modelId,\n qualifiedId: `${providerId}/${modelId}`,\n reasoning: modelConfig.reasoning ?? catalogModel?.capabilities.reasoning ?? false,\n variants: normalizeVariants(modelConfig.variants ?? catalogModel?.variants),\n };\n}\n\nfunction buildCatalogProviderModels(\n provider: OpenCodeProvider,\n availableModelIds: Set<string> | null,\n): OpenCodeConfiguredModel[] {\n return Object.values(provider.models)\n .filter((model) => isCatalogTextModel(model) && isModelAvailable(model.id, availableModelIds))\n .map((model) => ({\n id: model.id,\n providerID: provider.id,\n providerName: provider.name,\n name: model.name,\n qualifiedId: `${provider.id}/${model.id}`,\n reasoning: model.capabilities.reasoning,\n variants: normalizeVariants(model.variants),\n }));\n}\n\nfunction isTextModel(modelConfig: OpenCodeModelConfig, catalogModel: OpenCodeModel | undefined): boolean {\n if (modelConfig.modalities) {\n return modelConfig.modalities.input.includes(\"text\") && modelConfig.modalities.output.includes(\"text\");\n }\n\n if (catalogModel) {\n return catalogModel.capabilities.input.text && catalogModel.capabilities.output.text;\n }\n\n return true;\n}\n\nfunction isCatalogTextModel(catalogModel: OpenCodeModel): boolean {\n return catalogModel.capabilities.input.text && catalogModel.capabilities.output.text;\n}\n\nfunction isModelAvailable(modelId: string, availableModelIds: Set<string> | null): boolean {\n return availableModelIds === null || availableModelIds.has(modelId);\n}\n\nfunction resolveProviderDisplayName(\n providerId: string,\n providerConfig: OpenCodeProviderConfig,\n providerCatalog: OpenCodeProvider | undefined,\n): string {\n if (providerConfig.name) {\n return providerConfig.name;\n }\n\n const configuredBaseUrl = extractConfiguredBaseUrl(providerConfig);\n\n if (configuredBaseUrl) {\n const host = safeParseUrlHost(configuredBaseUrl);\n const label = providerCatalog?.name ?? providerId;\n\n return host ? `${label} (${host})` : label;\n }\n\n return providerCatalog?.name ?? providerId;\n}\n\nfunction extractConfiguredBaseUrl(providerConfig: OpenCodeProviderConfig): string | null {\n const options = providerConfig.options;\n\n if (!options || typeof options !== \"object\") {\n return null;\n }\n\n const baseUrl = \"baseURL\" in options ? options.baseURL : null;\n\n return typeof baseUrl === \"string\" && baseUrl.trim().length > 0\n ? baseUrl.trim()\n : null;\n}\n\nfunction safeParseUrlHost(value: string): string | null {\n try {\n return new URL(value).host || null;\n } catch {\n return null;\n }\n}\n\nfunction normalizeVariants(\n variants: OpenCodeModelConfig[\"variants\"] | OpenCodeModel[\"variants\"] | undefined,\n): Record<string, Record<string, unknown>> {\n if (!variants) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(variants)\n .filter(([, config]) => !config?.disabled)\n .map(([variant, config]) => {\n const normalized = Object.fromEntries(\n Object.entries(config).filter(([key]) => key !== \"disabled\"),\n );\n\n return [variant, normalized];\n }),\n );\n}\n\nfunction extractTextFromParts(parts: Part[] | null | undefined): string {\n if (!Array.isArray(parts)) {\n return \"\";\n }\n\n return parts\n .filter((part): part is Extract<Part, { type: \"text\"; text: string }> => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim();\n}\n\nfunction buildPromptSessionResult(\n data: OpenCodePromptResponse,\n options: {\n emptyResponseText: string;\n finishedAt: number;\n startedAt: number;\n },\n): PromptSessionResult {\n const assistantInfo = toAssistantMessage(data.info);\n const responseParts = Array.isArray(data.parts) ? data.parts : [];\n const bodyMd = extractTextFromParts(responseParts) || null;\n const fallbackText = bodyMd\n ? stripMarkdownToPlainText(bodyMd) || bodyMd\n : options.emptyResponseText;\n\n return {\n assistantError: assistantInfo?.error ?? null,\n bodyMd,\n fallbackText,\n info: assistantInfo,\n metrics: extractPromptMetrics(assistantInfo, options.startedAt, options.finishedAt),\n parts: responseParts,\n structured: null,\n };\n}\n\nfunction shouldPollPromptMessage(\n data: OpenCodePromptResponse,\n): boolean {\n const assistantInfo = toAssistantMessage(data.info);\n const responseParts = Array.isArray(data.parts) ? data.parts : [];\n const hasText = extractTextFromParts(responseParts).length > 0;\n const hasAssistantError = !!assistantInfo?.error;\n const isCompleted = isAssistantMessageCompleted(assistantInfo);\n\n return !hasText && !hasAssistantError && !isCompleted;\n}\n\nfunction shouldReturnPromptResponseImmediately(\n data: OpenCodePromptResponse,\n): boolean {\n return !shouldPollPromptMessage(data)\n && !isCompletedEmptyPromptResponse(data);\n}\n\nfunction isPromptResponseUsable(\n data: OpenCodePromptResponse,\n): boolean {\n return !shouldPollPromptMessage(data)\n && !isCompletedEmptyPromptResponse(data);\n}\n\nfunction normalizePromptResponse(response: OpenCodePromptResponse | null | undefined): OpenCodePromptResponse {\n return {\n info: isPlainRecord(response?.info) ? response.info : null,\n parts: normalizePromptParts(response?.parts),\n };\n}\n\nfunction normalizePromptResponses(\n responses: OpenCodePromptResponse[] | null | undefined,\n): OpenCodePromptResponse[] | null {\n if (!Array.isArray(responses)) {\n return null;\n }\n\n return responses.map((response) => normalizePromptResponse(response));\n}\n\nfunction normalizePromptParts(parts: Part[] | null | undefined): Part[] {\n return Array.isArray(parts) ? parts : [];\n}\n\nfunction toAssistantMessage(message: unknown): OpenCodeAssistantMessage | null {\n if (!message || typeof message !== \"object\") {\n return null;\n }\n\n if (\"role\" in message && message.role !== \"assistant\") {\n return null;\n }\n\n const normalized: OpenCodeAssistantMessage = {};\n\n if (\"agent\" in message && typeof message.agent === \"string\" && message.agent.trim().length > 0) {\n normalized.agent = message.agent;\n }\n\n if (\"cost\" in message && typeof message.cost === \"number\" && Number.isFinite(message.cost)) {\n normalized.cost = message.cost;\n }\n\n const error = normalizeAssistantError(\"error\" in message ? message.error : undefined);\n\n if (error) {\n normalized.error = error;\n }\n\n if (\"finish\" in message && typeof message.finish === \"string\" && message.finish.trim().length > 0) {\n normalized.finish = message.finish;\n }\n\n if (\"id\" in message && typeof message.id === \"string\" && message.id.trim().length > 0) {\n normalized.id = message.id;\n }\n\n if (\"mode\" in message && typeof message.mode === \"string\" && message.mode.trim().length > 0) {\n normalized.mode = message.mode;\n }\n\n if (\"modelID\" in message && typeof message.modelID === \"string\" && message.modelID.trim().length > 0) {\n normalized.modelID = message.modelID;\n }\n\n if (\"parentID\" in message && typeof message.parentID === \"string\" && message.parentID.trim().length > 0) {\n normalized.parentID = message.parentID;\n }\n\n if (\"path\" in message && isPlainRecord(message.path)) {\n normalized.path = {\n ...(typeof message.path.cwd === \"string\" && message.path.cwd.trim().length > 0\n ? { cwd: message.path.cwd }\n : {}),\n ...(typeof message.path.root === \"string\" && message.path.root.trim().length > 0\n ? { root: message.path.root }\n : {}),\n };\n }\n\n if (\"providerID\" in message && typeof message.providerID === \"string\" && message.providerID.trim().length > 0) {\n normalized.providerID = message.providerID;\n }\n\n if (\"role\" in message && message.role === \"assistant\") {\n normalized.role = \"assistant\";\n }\n\n if (\"sessionID\" in message && typeof message.sessionID === \"string\" && message.sessionID.trim().length > 0) {\n normalized.sessionID = message.sessionID;\n }\n\n if (\"summary\" in message && typeof message.summary === \"boolean\") {\n normalized.summary = message.summary;\n }\n\n if (\"time\" in message && isPlainRecord(message.time)) {\n normalized.time = {\n ...(typeof message.time.created === \"number\" && Number.isFinite(message.time.created)\n ? { created: message.time.created }\n : {}),\n ...(typeof message.time.completed === \"number\" && Number.isFinite(message.time.completed)\n ? { completed: message.time.completed }\n : {}),\n };\n }\n\n if (\"tokens\" in message && isPlainRecord(message.tokens)) {\n normalized.tokens = {\n ...(typeof message.tokens.input === \"number\" && Number.isFinite(message.tokens.input)\n ? { input: message.tokens.input }\n : {}),\n ...(typeof message.tokens.output === \"number\" && Number.isFinite(message.tokens.output)\n ? { output: message.tokens.output }\n : {}),\n ...(typeof message.tokens.reasoning === \"number\" && Number.isFinite(message.tokens.reasoning)\n ? { reasoning: message.tokens.reasoning }\n : {}),\n ...(typeof message.tokens.total === \"number\" && Number.isFinite(message.tokens.total)\n ? { total: message.tokens.total }\n : {}),\n ...(isPlainRecord(message.tokens.cache)\n ? {\n cache: {\n ...(typeof message.tokens.cache.read === \"number\" && Number.isFinite(message.tokens.cache.read)\n ? { read: message.tokens.cache.read }\n : {}),\n ...(typeof message.tokens.cache.write === \"number\" && Number.isFinite(message.tokens.cache.write)\n ? { write: message.tokens.cache.write }\n : {}),\n },\n }\n : {}),\n };\n }\n\n if (\"variant\" in message && typeof message.variant === \"string\" && message.variant.trim().length > 0) {\n normalized.variant = message.variant;\n }\n\n return normalized;\n}\n\nfunction extractMessageId(message: unknown): string | null {\n if (!isPlainRecord(message)) {\n return null;\n }\n\n return typeof message.id === \"string\" && message.id.trim().length > 0\n ? message.id\n : null;\n}\n\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const handle = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(handle);\n signal?.removeEventListener(\"abort\", onAbort);\n reject(normalizeAbortReason(signal?.reason));\n };\n\n if (signal?.aborted) {\n onAbort();\n return;\n }\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction didPromptResponseAdvance(\n previous: OpenCodePromptResponse | null,\n next: OpenCodePromptResponse,\n): boolean {\n return getPromptResponseProgressSignature(previous)\n !== getPromptResponseProgressSignature(next);\n}\n\nfunction createOpenCodePromptTimeoutError(\n input: Omit<OpenCodePromptTimeoutErrorData, \"elapsedMs\" | \"message\"> & {\n elapsedMs?: number;\n message?: string;\n },\n): OpenCodePromptTimeoutError {\n return new OpenCodePromptTimeoutError({\n ...input,\n elapsedMs: input.elapsedMs ?? input.timeoutMs,\n message: input.message ?? \"The OpenCode host did not finish this request in time.\",\n });\n}\n\nfunction resolvePromptEndpointKind(stage: OpenCodePromptTimeoutStage): \"message\" | \"messages\" | \"prompt\" | \"status\" {\n switch (stage) {\n case \"capture-known-messages\":\n case \"poll-messages\":\n case \"final-scan\":\n return \"messages\";\n case \"poll-message\":\n return \"message\";\n case \"poll-status\":\n return \"status\";\n case \"send-prompt\":\n default:\n return \"prompt\";\n }\n}\n\nfunction getPromptMessagePollDelayMs(attempt: number): number {\n return PROMPT_MESSAGE_POLL_INITIAL_DELAYS_MS[attempt] ?? PROMPT_MESSAGE_POLL_INTERVAL_MS;\n}\n\nfunction extractPromptMetrics(\n info: OpenCodeAssistantMessage | null | undefined,\n startedAt: number,\n finishedAt: number,\n): PromptSessionMetrics {\n const createdAt = typeof info?.time?.created === \"number\" && Number.isFinite(info.time.created)\n ? info.time.created\n : null;\n const completedAt = typeof info?.time?.completed === \"number\" && Number.isFinite(info.time.completed)\n ? info.time.completed\n : null;\n const completedDuration = createdAt !== null && completedAt !== null\n ? completedAt - createdAt\n : null;\n const durationMs = completedDuration !== null && completedDuration >= 0\n ? completedDuration\n : Math.max(0, finishedAt - startedAt);\n\n return {\n durationMs,\n tokens: extractTokenMetrics(info),\n };\n}\n\nfunction extractTokenMetrics(info: OpenCodeAssistantMessage | null | undefined): PromptSessionTokenMetrics {\n if (!info?.tokens) {\n return {\n total: null,\n input: null,\n output: null,\n reasoning: null,\n cacheRead: null,\n cacheWrite: null,\n };\n }\n\n const input = coerceFiniteNumber(info.tokens.input);\n const output = coerceFiniteNumber(info.tokens.output);\n const reasoning = coerceFiniteNumber(info.tokens.reasoning);\n const cacheRead = coerceFiniteNumber(info.tokens.cache?.read);\n const cacheWrite = coerceFiniteNumber(info.tokens.cache?.write);\n const total = coerceFiniteNumber(info.tokens.total);\n const fallbackTotal = sumTokenMetrics(input, output, cacheRead, cacheWrite);\n\n return {\n total: total ?? fallbackTotal,\n input,\n output,\n reasoning,\n cacheRead,\n cacheWrite,\n };\n}\n\nfunction coerceFiniteNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction sumTokenMetrics(...values: Array<number | null>): number | null {\n if (values.every((value) => value === null)) {\n return null;\n }\n\n const total = values.reduce<number>((sum, value) => sum + (value ?? 0), 0);\n\n return Number.isFinite(total) ? total : null;\n}\n\nfunction unwrapSdkData<T>(response: MaybeWrappedResponse<T>): T {\n if (response && typeof response === \"object\" && \"data\" in response) {\n return response.data;\n }\n\n return response;\n}\n\nfunction normalizePermissionRequest(permission: unknown): OpenCodePermissionRequest | null {\n if (!isPlainRecord(permission)) {\n return null;\n }\n\n const id = typeof permission.id === \"string\" && permission.id.trim().length > 0\n ? permission.id\n : null;\n const sessionID = typeof permission.sessionID === \"string\" && permission.sessionID.trim().length > 0\n ? permission.sessionID\n : null;\n const permissionName = typeof permission.permission === \"string\" && permission.permission.trim().length > 0\n ? permission.permission\n : typeof permission.type === \"string\" && permission.type.trim().length > 0\n ? permission.type\n : null;\n\n if (!id || !sessionID || !permissionName) {\n return null;\n }\n\n return {\n always: Array.isArray(permission.always)\n ? permission.always.filter((value): value is string => typeof value === \"string\")\n : [],\n id,\n metadata: isPlainRecord(permission.metadata)\n ? permission.metadata\n : {},\n patterns: normalizePermissionPatterns(permission),\n permission: permissionName,\n sessionID,\n };\n}\n\nfunction normalizeConfiguredPluginSpecs(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n const normalizedPlugins: string[] = [];\n const seenPlugins = new Set<string>();\n\n for (const item of value) {\n if (typeof item !== \"string\") {\n continue;\n }\n\n const normalizedItem = item.trim();\n\n if (normalizedItem.length === 0 || seenPlugins.has(normalizedItem)) {\n continue;\n }\n\n seenPlugins.add(normalizedItem);\n normalizedPlugins.push(normalizedItem);\n }\n\n return normalizedPlugins;\n}\n\nfunction normalizePermissionPatterns(permission: Record<string, unknown>): string[] {\n if (Array.isArray(permission.patterns)) {\n return permission.patterns.filter((value): value is string => typeof value === \"string\");\n }\n\n if (typeof permission.pattern === \"string\" && permission.pattern.trim().length > 0) {\n return [permission.pattern];\n }\n\n if (Array.isArray(permission.pattern)) {\n return permission.pattern.filter((value): value is string => typeof value === \"string\");\n }\n\n return [];\n}\n\nfunction getRawSdkRequestClient(client: OpenCodeSdkClientLike): RawSdkRequestClient | null {\n const compatibleClient = client as OpenCodeSdkClientWithRawRequestClient;\n\n return compatibleClient.client ?? compatibleClient._client ?? null;\n}\n\nfunction isMissingScopedSdkMethodError(\n error: unknown,\n scope: string,\n method: string,\n): error is Error {\n return error instanceof Error\n && error.message === `OpenCode SDK client does not expose a compatible ${scope}.${method} method.`;\n}\n\nfunction resolvePromptTimeoutPolicy(\n input: Partial<OpenCodePromptTimeoutPolicy>,\n): OpenCodePromptTimeoutPolicy {\n return {\n pollRequestTimeoutMs: input.pollRequestTimeoutMs ?? DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY.pollRequestTimeoutMs,\n recoveryInactivityTimeoutMs: input.recoveryInactivityTimeoutMs ?? DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY.recoveryInactivityTimeoutMs,\n waitTimeoutMs: input.waitTimeoutMs ?? DEFAULT_OPENCODE_PROMPT_TIMEOUT_POLICY.waitTimeoutMs,\n };\n}\n\nfunction normalizeAssistantError(value: unknown): OpenCodeAssistantError | undefined {\n if (!isPlainRecord(value) || typeof value.name !== \"string\" || value.name.trim().length === 0) {\n return undefined;\n }\n\n return {\n ...value,\n name: value.name,\n ...(isPlainRecord(value.data)\n ? { data: value.data }\n : {}),\n } as OpenCodeAssistantError;\n}\n\nfunction isAssistantMessageCompleted(\n message: OpenCodeAssistantMessage | null | undefined,\n): boolean {\n return !!message?.error\n || typeof message?.time?.completed === \"number\"\n || (typeof message?.finish === \"string\" && message.finish.trim().length > 0);\n}\n\nfunction isCompletedEmptyPromptResponse(\n data: OpenCodePromptResponse,\n): boolean {\n const assistantInfo = toAssistantMessage(data.info);\n const responseParts = Array.isArray(data.parts) ? data.parts : [];\n const hasText = extractTextFromParts(responseParts).length > 0;\n\n return isAssistantMessageCompleted(assistantInfo)\n && !assistantInfo?.error\n && !hasText;\n}\n\ntype PromptResponseCandidateOptions = {\n initialMessageId: string | null;\n initialParentId: string | null;\n knownMessageIds: Set<string>;\n requestStartedAt: number | null;\n};\n\nfunction selectPromptResponseCandidate(\n candidates: Array<OpenCodePromptResponse | null | undefined>,\n options: PromptResponseCandidateOptions,\n): OpenCodePromptResponse | null {\n const availableCandidates = candidates\n .filter((candidate): candidate is OpenCodePromptResponse => !!candidate)\n .filter((candidate) => toAssistantMessage(candidate.info) !== null);\n\n if (availableCandidates.length === 0) {\n return null;\n }\n\n return [...availableCandidates].sort((left, right) =>\n comparePromptResponseCandidates(left, right, options)\n )[0] ?? null;\n}\n\nfunction comparePromptResponseCandidates(\n left: OpenCodePromptResponse,\n right: OpenCodePromptResponse,\n options: PromptResponseCandidateOptions,\n): number {\n const leftRank = getPromptResponseCandidateRank(left, options);\n const rightRank = getPromptResponseCandidateRank(right, options);\n\n return Number(rightRank.isInitial) - Number(leftRank.isInitial)\n || Number(rightRank.sharesParent) - Number(leftRank.sharesParent)\n || Number(rightRank.isNewSinceRequestStart) - Number(leftRank.isNewSinceRequestStart)\n || Number(rightRank.isUsable) - Number(leftRank.isUsable)\n || rightRank.createdAt - leftRank.createdAt;\n}\n\nfunction getPromptResponseCandidateRank(\n message: OpenCodePromptResponse,\n options: PromptResponseCandidateOptions,\n): {\n createdAt: number;\n isInitial: boolean;\n isNewSinceRequestStart: boolean;\n isUsable: boolean;\n sharesParent: boolean;\n} {\n const assistant = toAssistantMessage(message.info);\n const id = assistant?.id ?? null;\n const createdAt = typeof assistant?.time?.created === \"number\" && Number.isFinite(assistant.time.created)\n ? assistant.time.created\n : 0;\n\n return {\n createdAt,\n isInitial: !!id && id === options.initialMessageId,\n isNewSinceRequestStart: isPromptResponseNewSinceRequestStart(\n id,\n createdAt,\n options.knownMessageIds,\n options.requestStartedAt,\n ),\n isUsable: isPromptResponseUsable(message),\n sharesParent: !!assistant?.parentID && assistant.parentID === options.initialParentId,\n };\n}\n\nfunction resolvePromptCandidateStartTime(\n startedAt: number,\n initialMessage: OpenCodePromptResponse | null,\n): number | null {\n if (!initialMessage) {\n return startedAt;\n }\n\n const initialCreatedAt = coerceFiniteNumber(toAssistantMessage(initialMessage.info)?.time?.created);\n\n if (initialCreatedAt === null) {\n return startedAt;\n }\n\n return areComparablePromptTimestamps(startedAt, initialCreatedAt)\n ? startedAt\n : initialCreatedAt;\n}\n\nfunction getPromptResponseProgressSignature(\n response: OpenCodePromptResponse | null,\n): string {\n if (!response) {\n return \"null\";\n }\n\n const assistant = toAssistantMessage(response.info);\n const responseParts = Array.isArray(response.parts) ? response.parts : [];\n\n return JSON.stringify({\n assistantError: assistant?.error?.name ?? null,\n bodyMd: extractTextFromParts(responseParts) || null,\n completedAt: assistant?.time?.completed ?? null,\n finish: assistant?.finish ?? null,\n id: assistant?.id ?? null,\n partCount: responseParts.length,\n text: extractTextFromParts(responseParts),\n });\n}\n\nfunction isPromptResponseNewSinceRequestStart(\n messageId: string | null,\n createdAt: number,\n knownMessageIds: Set<string>,\n requestStartedAt: number | null,\n): boolean {\n if (!messageId || knownMessageIds.has(messageId)) {\n return false;\n }\n\n if (requestStartedAt === null) {\n return true;\n }\n\n return createdAt >= requestStartedAt;\n}\n\nfunction isPromptResponseForCurrentRequest(\n response: OpenCodePromptResponse,\n options: PromptResponseCandidateOptions,\n): boolean {\n const rank = getPromptResponseCandidateRank(response, options);\n\n return rank.isInitial || rank.sharesParent || rank.isNewSinceRequestStart;\n}\n\nfunction areComparablePromptTimestamps(left: number, right: number): boolean {\n const epochThresholdMs = 1_000_000_000_000;\n\n return left >= epochThresholdMs && right >= epochThresholdMs;\n}\n\nfunction isPromptRequestAbort(error: unknown): boolean {\n return error instanceof OpenCodeMessageAbortedError\n || (error instanceof Error && error.name === \"AbortError\")\n || isNamedAbortError(error);\n}\n\nfunction isNamedAbortError(error: unknown): error is { name: \"MessageAbortedError\" } {\n return !!error\n && typeof error === \"object\"\n && \"name\" in error\n && (error as { name?: unknown }).name === \"MessageAbortedError\";\n}\n\nfunction normalizeAbortReason(reason: unknown): unknown {\n if (reason instanceof Error || isNamedAbortError(reason)) {\n return reason;\n }\n\n return createMessageAbortedError();\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) {\n return;\n }\n\n throw normalizeAbortReason(signal.reason);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, any> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nasync function resolveProviderAvailability(\n config: OpenCodeConfig,\n fetchFn: typeof fetch,\n): Promise<OpenCodeProviderAvailability> {\n const configuredProviders = Object.entries(config.provider ?? {});\n const availabilityEntries = await Promise.all(\n configuredProviders.map(async ([providerId, providerConfig]) => [\n providerId,\n await fetchProviderAvailableModelIds(providerConfig, fetchFn),\n ] as const),\n );\n\n return new Map(availabilityEntries);\n}\n\nasync function fetchProviderAvailableModelIds(\n providerConfig: OpenCodeProviderConfig,\n fetchFn: typeof fetch,\n): Promise<Set<string> | null> {\n const baseUrl = extractConfiguredBaseUrl(providerConfig);\n const apiKey = extractConfiguredApiKey(providerConfig);\n\n if (!baseUrl || !apiKey) {\n return null;\n }\n\n try {\n const response = await fetchFn(\n buildModelsEndpointUrl(baseUrl),\n {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n Accept: \"application/json\",\n },\n signal: AbortSignal.timeout(10_000),\n },\n );\n\n if (!response.ok) {\n return null;\n }\n\n const payload = await response.json();\n const modelIds = extractModelIdsFromPayload(payload);\n\n return modelIds ? new Set(modelIds) : null;\n } catch {\n return null;\n }\n}\n\nfunction extractConfiguredApiKey(providerConfig: OpenCodeProviderConfig): string | null {\n const options = providerConfig.options;\n\n if (!options || typeof options !== \"object\") {\n return null;\n }\n\n const apiKey = \"apiKey\" in options ? options.apiKey : null;\n\n return typeof apiKey === \"string\" && apiKey.trim().length > 0\n ? apiKey.trim()\n : null;\n}\n\nfunction buildModelsEndpointUrl(baseUrl: string): string {\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n\n return new URL(\"models\", normalizedBaseUrl).toString();\n}\n\nfunction extractModelIdsFromPayload(payload: unknown): string[] | null {\n if (Array.isArray(payload)) {\n return payload\n .map(extractModelId)\n .filter((id): id is string => !!id);\n }\n\n if (payload && typeof payload === \"object\" && \"data\" in payload && Array.isArray(payload.data)) {\n return payload.data\n .map(extractModelId)\n .filter((id): id is string => !!id);\n }\n\n return null;\n}\n\nfunction extractModelId(value: unknown): string | null {\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n\n if (value && typeof value === \"object\" && \"id\" in value) {\n const id = (value as { id?: unknown }).id;\n\n return typeof id === \"string\" && id.trim().length > 0\n ? id.trim()\n : null;\n }\n\n return null;\n}\n","import type { PendingChatAction } from \"../../domain/pending-action/pending-action.entity.js\";\nimport type { PendingPermissionApproval } from \"../../domain/permission/approval.entity.js\";\nimport type { ChatSessionBinding } from \"../../domain/session/session.entity.js\";\n\nexport interface OpencodeTbotState {\n version: 1;\n sessions: Record<string, ChatSessionBinding>;\n pendingActions: Record<string, PendingChatAction>;\n pendingPermissions: Record<string, PendingPermissionApproval>;\n}\n\nexport function createDefaultOpencodeTbotState(): OpencodeTbotState {\n return {\n version: 1,\n sessions: {},\n pendingActions: {},\n pendingPermissions: {},\n };\n}\n","import { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nexport interface JsonStateStoreOptions<TState> {\n createDefaultState: () => TState;\n filePath: string;\n}\n\nexport class JsonStateStore<TState> {\n private readonly createDefaultState: () => TState;\n private readonly filePath: string;\n private statePromise: Promise<TState> | null = null;\n private writeQueue = Promise.resolve();\n\n constructor(options: JsonStateStoreOptions<TState>) {\n this.createDefaultState = options.createDefaultState;\n this.filePath = options.filePath;\n }\n\n async read(): Promise<TState> {\n const state = await this.loadState();\n\n return cloneState(state);\n }\n\n async update(mutator: (state: TState) => void): Promise<TState> {\n const nextStatePromise = this.writeQueue.then(async () => {\n const state = await this.loadState();\n const draft = cloneState(state);\n\n mutator(draft);\n await writeStateFile(this.filePath, draft);\n this.statePromise = Promise.resolve(draft);\n\n return cloneState(draft);\n });\n\n this.writeQueue = nextStatePromise.then(() => undefined, () => undefined);\n\n return nextStatePromise;\n }\n\n private async loadState(): Promise<TState> {\n if (!this.statePromise) {\n this.statePromise = readStateFile(this.filePath, this.createDefaultState);\n }\n\n return this.statePromise;\n }\n}\n\nasync function readStateFile<TState>(\n filePath: string,\n createDefaultState: () => TState,\n): Promise<TState> {\n try {\n const content = await readFile(filePath, \"utf8\");\n\n return JSON.parse(content) as TState;\n } catch (error) {\n if (isMissingFileError(error)) {\n return createDefaultState();\n }\n\n throw error;\n }\n}\n\nasync function writeStateFile<TState>(filePath: string, state: TState): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n\n const temporaryFilePath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n const serialized = `${JSON.stringify(state, null, 2)}\\n`;\n\n await writeFile(temporaryFilePath, serialized, \"utf8\");\n await rename(temporaryFilePath, filePath);\n}\n\nfunction cloneState<TState>(state: TState): TState {\n return JSON.parse(JSON.stringify(state)) as TState;\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n","export interface DownloadTelegramFileInput {\n filePath: string;\n}\n\nexport interface DownloadTelegramFileResult {\n data: Uint8Array;\n mimeType: string | null;\n}\n\nexport interface TelegramFileClientLike {\n downloadFile(input: DownloadTelegramFileInput): Promise<DownloadTelegramFileResult>;\n}\n\nexport interface TelegramFileClientOptions {\n baseUrl?: string;\n apiRoot?: string;\n botToken: string;\n}\n\nexport class TelegramFileDownloadError extends Error {\n readonly data: { message: string };\n\n constructor(message: string) {\n super(message);\n this.name = \"TelegramFileDownloadError\";\n this.data = { message };\n }\n}\n\nexport class TelegramFileClient implements TelegramFileClientLike {\n private readonly baseUrl: string;\n private readonly fetchFn: typeof fetch;\n\n constructor(options: TelegramFileClientOptions, fetchFn: typeof fetch = fetch) {\n this.baseUrl = options.baseUrl ?? buildTelegramFileApiRoot(options.apiRoot, options.botToken);\n this.fetchFn = fetchFn;\n }\n\n async downloadFile(input: DownloadTelegramFileInput): Promise<DownloadTelegramFileResult> {\n const filePath = input.filePath.trim();\n\n if (!filePath) {\n throw new TelegramFileDownloadError(\"Telegram did not provide a downloadable file path.\");\n }\n\n let response: Response;\n\n try {\n response = await this.fetchFn(new URL(filePath, this.baseUrl));\n } catch (error) {\n throw new TelegramFileDownloadError(extractErrorMessage(error) ?? \"Failed to download the Telegram file.\");\n }\n\n if (!response.ok) {\n throw new TelegramFileDownloadError(await buildDownloadFailureMessage(response));\n }\n\n const data = new Uint8Array(await response.arrayBuffer());\n\n if (data.byteLength === 0) {\n throw new TelegramFileDownloadError(\"Telegram returned an empty file.\");\n }\n\n return {\n data,\n mimeType: response.headers.get(\"content-type\"),\n };\n }\n}\n\nexport function buildTelegramFileApiRoot(apiRoot: string | undefined, botToken: string): string {\n const normalizedApiRoot = (apiRoot ?? \"https://api.telegram.org\").trim().replace(/\\/+$/u, \"\");\n\n return `${normalizedApiRoot}/file/bot${botToken}/`;\n}\n\nasync function buildDownloadFailureMessage(response: Response): Promise<string> {\n const responseText = await safeReadResponseText(response);\n const normalizedText = responseText?.trim();\n\n return normalizedText\n ? `Telegram file download failed with status ${response.status}: ${normalizedText}`\n : `Telegram file download failed with status ${response.status}.`;\n}\n\nasync function safeReadResponseText(response: Response): Promise<string | null> {\n try {\n const text = await response.text();\n\n return text.trim().length > 0 ? text : null;\n } catch {\n return null;\n }\n}\n\nfunction extractErrorMessage(error: unknown): string | null {\n return error instanceof Error && error.message.trim().length > 0\n ? error.message.trim()\n : null;\n}\n","import { createMessageAbortedError } from \"../opencode/opencode.client.js\";\n\nexport interface ForegroundSessionLease {\n readonly signal: AbortSignal;\n attachSession(sessionId: string): void;\n dispose(): void;\n}\n\nexport interface ForegroundSessionTrackerLike {\n acquire(chatId: number): ForegroundSessionLease | null;\n abort(chatId: number, reason?: unknown): boolean;\n begin(chatId: number, sessionId: string): () => void;\n clear(sessionId: string): boolean;\n fail(sessionId: string, error: unknown): boolean;\n getActiveSessionId(chatId: number): string | null;\n hasActiveRequest(chatId: number): boolean;\n isForeground(sessionId: string): boolean;\n listChatIds(sessionId: string): number[];\n}\n\ninterface ForegroundRequestState {\n chatId: number;\n controller: AbortController;\n sessionId: string | null;\n}\n\nexport class ForegroundSessionTracker implements ForegroundSessionTrackerLike {\n private readonly requests = new Map<number, ForegroundRequestState>();\n private readonly sessionChats = new Map<string, Set<number>>();\n\n acquire(chatId: number): ForegroundSessionLease | null {\n if (this.requests.has(chatId)) {\n return null;\n }\n\n const state: ForegroundRequestState = {\n chatId,\n controller: new AbortController(),\n sessionId: null,\n };\n\n this.requests.set(chatId, state);\n\n return {\n signal: state.controller.signal,\n attachSession: (sessionId: string) => {\n this.attachSession(chatId, sessionId);\n },\n dispose: () => {\n this.release(chatId);\n },\n };\n }\n\n abort(chatId: number, reason: unknown = createMessageAbortedError()): boolean {\n const state = this.requests.get(chatId);\n\n if (!state) {\n return false;\n }\n\n if (!state.controller.signal.aborted) {\n state.controller.abort(reason);\n }\n\n return true;\n }\n\n begin(chatId: number, sessionId: string): () => void {\n const lease = this.acquire(chatId);\n\n if (!lease) {\n return () => undefined;\n }\n\n lease.attachSession(sessionId);\n return () => {\n lease.dispose();\n };\n }\n\n clear(sessionId: string): boolean {\n const chatIds = this.listChatIds(sessionId);\n\n if (chatIds.length === 0) {\n return false;\n }\n\n for (const chatId of chatIds) {\n const state = this.requests.get(chatId);\n\n if (state?.sessionId === sessionId) {\n state.sessionId = null;\n }\n }\n\n this.sessionChats.delete(sessionId);\n return true;\n }\n\n fail(sessionId: string, error: unknown): boolean {\n const chatIds = this.listChatIds(sessionId);\n\n if (chatIds.length === 0) {\n return false;\n }\n\n this.clear(sessionId);\n\n for (const chatId of chatIds) {\n this.abort(chatId, error);\n }\n\n return true;\n }\n\n getActiveSessionId(chatId: number): string | null {\n return this.requests.get(chatId)?.sessionId ?? null;\n }\n\n hasActiveRequest(chatId: number): boolean {\n return this.requests.has(chatId);\n }\n\n isForeground(sessionId: string): boolean {\n return this.sessionChats.has(sessionId);\n }\n\n listChatIds(sessionId: string): number[] {\n return [...(this.sessionChats.get(sessionId) ?? new Set<number>())];\n }\n\n private attachSession(chatId: number, sessionId: string): void {\n const normalizedSessionId = sessionId.trim();\n const state = this.requests.get(chatId);\n\n if (!state || normalizedSessionId.length === 0) {\n return;\n }\n\n if (state.sessionId === normalizedSessionId) {\n return;\n }\n\n if (state.sessionId) {\n this.detachChatFromSession(chatId, state.sessionId);\n }\n\n state.sessionId = normalizedSessionId;\n\n const chatIds = this.sessionChats.get(normalizedSessionId) ?? new Set<number>();\n\n chatIds.add(chatId);\n this.sessionChats.set(normalizedSessionId, chatIds);\n }\n\n private release(chatId: number): void {\n const state = this.requests.get(chatId);\n\n if (!state) {\n return;\n }\n\n if (state.sessionId) {\n this.detachChatFromSession(chatId, state.sessionId);\n }\n\n this.requests.delete(chatId);\n }\n\n private detachChatFromSession(chatId: number, sessionId: string): void {\n const chatIds = this.sessionChats.get(sessionId);\n\n if (!chatIds) {\n return;\n }\n\n chatIds.delete(chatId);\n\n if (chatIds.size === 0) {\n this.sessionChats.delete(sessionId);\n return;\n }\n\n this.sessionChats.set(sessionId, chatIds);\n }\n}\n\nexport const NOOP_FOREGROUND_SESSION_TRACKER: ForegroundSessionTrackerLike = {\n acquire() {\n return null;\n },\n abort() {\n return false;\n },\n begin() {\n return () => undefined;\n },\n clear() {\n return false;\n },\n fail() {\n return false;\n },\n getActiveSessionId() {\n return null;\n },\n hasActiveRequest() {\n return false;\n },\n isForeground() {\n return false;\n },\n listChatIds() {\n return [];\n },\n};\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport {\n createMessageAbortedError,\n type OpenCodeClientLike,\n type OpenCodeSessionStatus,\n} from \"../services/opencode/opencode.client.js\";\nimport {\n NOOP_FOREGROUND_SESSION_TRACKER,\n type ForegroundSessionTrackerLike,\n} from \"../services/session-activity/foreground-session-tracker.js\";\n\nexport interface AbortPromptResult {\n sessionId: string | null;\n status: \"aborted\" | \"no_session\" | \"not_running\";\n sessionStatus: OpenCodeSessionStatus | null;\n}\n\nexport class AbortPromptUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly foregroundSessionTracker: ForegroundSessionTrackerLike = NOOP_FOREGROUND_SESSION_TRACKER,\n ) { }\n\n async execute(input: { chatId: number }): Promise<AbortPromptResult> {\n const hasForegroundRequest = this.foregroundSessionTracker.hasActiveRequest(input.chatId);\n const activeSessionId = this.foregroundSessionTracker.getActiveSessionId(input.chatId);\n const binding = activeSessionId\n ? null\n : await this.sessionRepo.getByChatId(input.chatId);\n const sessionId = activeSessionId ?? binding?.sessionId ?? null;\n\n if (!hasForegroundRequest && !sessionId) {\n return {\n sessionId: null,\n status: \"no_session\",\n sessionStatus: null,\n };\n }\n\n const sessionStatuses = sessionId\n ? await this.opencodeClient.getSessionStatuses()\n : {};\n const sessionStatus = sessionId\n ? (sessionStatuses[sessionId] ?? null)\n : null;\n\n if (hasForegroundRequest) {\n if (sessionId && sessionStatus && sessionStatus.type !== \"idle\") {\n await this.opencodeClient.abortSession(sessionId);\n }\n\n this.foregroundSessionTracker.abort(\n input.chatId,\n createMessageAbortedError(),\n );\n\n return {\n sessionId,\n status: \"aborted\",\n sessionStatus,\n };\n }\n\n if (!sessionStatus || sessionStatus.type === \"idle\") {\n return {\n sessionId,\n status: \"not_running\",\n sessionStatus,\n };\n }\n\n if (!sessionId) {\n return {\n sessionId: null,\n status: \"not_running\",\n sessionStatus,\n };\n }\n\n const runningSessionId = sessionId;\n const aborted = await this.opencodeClient.abortSession(runningSessionId);\n\n return {\n sessionId: runningSessionId,\n status: aborted ? \"aborted\" : \"not_running\",\n sessionStatus,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeProject,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\n\ninterface CreateAndBindCurrentProjectSessionInput {\n chatId: number;\n title?: string | null;\n binding?: ChatSessionBinding | null;\n}\n\nexport interface CreateAndBindCurrentProjectSessionResult {\n binding: ChatSessionBinding;\n project: OpenCodeProject;\n session: OpenCodeSession;\n}\n\nexport async function createAndBindCurrentProjectSession(\n sessionRepo: SessionRepository,\n opencodeClient: OpenCodeClientLike,\n input: CreateAndBindCurrentProjectSessionInput,\n): Promise<CreateAndBindCurrentProjectSessionResult> {\n const binding = input.binding ?? await sessionRepo.getByChatId(input.chatId);\n const project = await opencodeClient.getCurrentProject();\n const title = normalizeOptionalText(input.title);\n const session = await opencodeClient.createSessionForDirectory(project.worktree, title ?? undefined);\n const nextBinding: ChatSessionBinding = {\n chatId: input.chatId,\n sessionId: session.id,\n projectId: session.projectID,\n directory: session.directory,\n agentName: binding?.agentName ?? null,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n };\n\n await sessionRepo.setCurrent(nextBinding);\n\n return {\n binding: nextBinding,\n project,\n session,\n };\n}\n\nfunction normalizeOptionalText(value: string | null | undefined): string | null {\n const normalized = value?.trim();\n\n return normalized ? normalized : null;\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\nimport { createAndBindCurrentProjectSession } from \"./session-creation.js\";\n\nexport interface CreateSessionResult {\n session: OpenCodeSession;\n}\n\nexport class CreateSessionUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; title?: string | null }): Promise<CreateSessionResult> {\n const binding = await this.sessionRepo.getByChatId(input.chatId);\n const result = await createAndBindCurrentProjectSession(\n this.sessionRepo,\n this.opencodeClient,\n {\n chatId: input.chatId,\n title: input.title,\n binding,\n },\n );\n\n this.logger.info(\n {\n chatId: input.chatId,\n sessionId: result.session.id,\n projectId: result.session.projectID,\n directory: result.session.directory,\n title: input.title?.trim() || null,\n },\n \"session created\",\n );\n\n return {\n session: result.session,\n };\n }\n}\n","import type {\n OpenCodeClientLike,\n OpenCodeHealth,\n} from \"../services/opencode/opencode.client.js\";\n\nexport class GetHealthUseCase {\n constructor(private readonly opencodeClient: OpenCodeClientLike) { }\n\n async execute(): Promise<OpenCodeHealth> {\n return this.opencodeClient.getHealth();\n }\n}\n","import type { OpenCodeClientLike, OpenCodePath } from \"../services/opencode/opencode.client.js\";\n\nexport class GetPathUseCase {\n constructor(private readonly opencodeClient: OpenCodeClientLike) { }\n\n async execute(): Promise<OpenCodePath> {\n return this.opencodeClient.getPath();\n }\n}\n","import { isAbsolute } from \"node:path\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeHealth,\n OpenCodePath,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\nimport type { GetHealthUseCase } from \"./get-health.usecase.js\";\nimport type { GetPathUseCase } from \"./get-path.usecase.js\";\nimport type { ListLspResult, ListLspUseCase } from \"./list-lsp.usecase.js\";\nimport type { ListMcpResult, ListMcpUseCase } from \"./list-mcp.usecase.js\";\nimport type { ListSessionsUseCase } from \"./list-sessions.usecase.js\";\n\nexport interface StatusSectionOk<TData> {\n data: TData;\n status: \"ok\";\n}\n\nexport interface StatusSectionError {\n error: unknown;\n status: \"error\";\n}\n\nexport type StatusSectionResult<TData> = StatusSectionOk<TData> | StatusSectionError;\n\nexport interface ConfiguredPluginsResult {\n plugins: string[];\n}\n\ninterface ConfiguredPluginReader {\n listConfiguredPlugins(): Promise<string[]>;\n}\n\nexport interface WorkspaceStatusResult {\n currentProject: string;\n currentSession: string | null;\n}\n\nexport interface GetStatusResult {\n health: StatusSectionResult<OpenCodeHealth>;\n lsp: StatusSectionResult<ListLspResult>;\n mcp: StatusSectionResult<ListMcpResult>;\n path: StatusSectionResult<OpenCodePath>;\n plugins: StatusSectionResult<ConfiguredPluginsResult>;\n workspace: StatusSectionResult<WorkspaceStatusResult>;\n}\n\nexport class GetStatusUseCase {\n constructor(\n private readonly getHealthUseCase: GetHealthUseCase,\n private readonly getPathUseCase: GetPathUseCase,\n private readonly listLspUseCase: ListLspUseCase,\n private readonly listMcpUseCase: ListMcpUseCase,\n private readonly listSessionsUseCase: ListSessionsUseCase,\n private readonly sessionRepo: SessionRepository,\n private readonly configuredPluginReader: ConfiguredPluginReader,\n ) { }\n\n async execute(input: { chatId: number }): Promise<GetStatusResult> {\n const [health, path, lsp, mcp, plugins] = await Promise.allSettled([\n this.getHealthUseCase.execute(),\n this.getPathUseCase.execute(),\n this.listLspUseCase.execute({ chatId: input.chatId }),\n this.listMcpUseCase.execute({ chatId: input.chatId }),\n this.configuredPluginReader.listConfiguredPlugins(),\n ]);\n const pathResult = mapSettledResult(path);\n const pluginResult = loadConfiguredPluginsResult(plugins);\n const workspace = await loadWorkspaceStatusResult(\n input.chatId,\n pathResult,\n this.listSessionsUseCase,\n this.sessionRepo,\n );\n\n return {\n health: mapSettledResult(health),\n path: pathResult,\n plugins: pluginResult,\n workspace,\n lsp: mapSettledResult(lsp),\n mcp: mapSettledResult(mcp),\n };\n }\n}\n\nfunction mapSettledResult<TData>(result: PromiseSettledResult<TData>): StatusSectionResult<TData> {\n if (result.status === \"fulfilled\") {\n return {\n data: result.value,\n status: \"ok\",\n };\n }\n\n return {\n error: result.reason,\n status: \"error\",\n };\n}\n\nfunction loadConfiguredPluginsResult(\n result: PromiseSettledResult<string[]>,\n): StatusSectionResult<ConfiguredPluginsResult> {\n if (result.status === \"rejected\") {\n return {\n error: result.reason,\n status: \"error\",\n };\n }\n\n return {\n data: {\n plugins: normalizeConfiguredPluginLabels(result.value),\n },\n status: \"ok\",\n };\n}\n\nasync function loadWorkspaceStatusResult(\n chatId: number,\n path: StatusSectionResult<OpenCodePath>,\n listSessionsUseCase: ListSessionsUseCase,\n sessionRepo: SessionRepository,\n): Promise<StatusSectionResult<WorkspaceStatusResult>> {\n if (path.status === \"error\") {\n return {\n error: path.error,\n status: \"error\",\n };\n }\n\n const binding = await sessionRepo.getByChatId(chatId);\n let currentProject = resolveWorkspaceProjectPath(path.data);\n let currentSession = binding?.sessionId ?? null;\n\n try {\n const sessions = await listSessionsUseCase.execute({ chatId });\n\n currentProject = resolveWorkspaceProjectPath(path.data, sessions.currentDirectory);\n currentSession = sessions.currentSessionId\n ? formatSessionStatusLabel(\n sessions.sessions.find((session) => session.id === sessions.currentSessionId) ?? null,\n sessions.currentSessionId,\n )\n : null;\n } catch {\n // Keep path/session binding fallbacks when session listing is unavailable.\n }\n\n return {\n data: {\n currentProject,\n currentSession,\n },\n status: \"ok\",\n };\n}\n\nfunction formatSessionStatusLabel(session: OpenCodeSession | null, fallbackId: string): string {\n if (!session) {\n return fallbackId;\n }\n\n const title = session.title.trim() || session.slug || session.id;\n\n return title === session.slug\n ? title\n : `${title} (${session.slug})`;\n}\n\nfunction resolveWorkspaceProjectPath(path: OpenCodePath, preferredPath?: string | null): string {\n const candidates = [\n preferredPath,\n path.worktree,\n path.directory,\n ];\n\n for (const candidate of candidates) {\n if (isUsableWorkspacePath(candidate)) {\n return candidate;\n }\n }\n\n return preferredPath ?? path.worktree ?? path.directory;\n}\n\nfunction isUsableWorkspacePath(value: string | null | undefined): value is string {\n if (typeof value !== \"string\") {\n return false;\n }\n\n const normalized = value.trim();\n\n return normalized.length > 0\n && normalized !== \"/\"\n && normalized !== \"\\\\\"\n && isAbsolute(normalized);\n}\n\nfunction normalizeConfiguredPluginLabels(plugins: string[]): string[] {\n const normalizedPlugins: string[] = [];\n const seenPlugins = new Set<string>();\n\n for (const plugin of plugins) {\n const normalizedPlugin = normalizeConfiguredPluginLabel(plugin);\n\n if (normalizedPlugin.length === 0 || seenPlugins.has(normalizedPlugin)) {\n continue;\n }\n\n seenPlugins.add(normalizedPlugin);\n normalizedPlugins.push(normalizedPlugin);\n }\n\n return normalizedPlugins;\n}\n\nfunction normalizeConfiguredPluginLabel(plugin: string): string {\n const normalizedPlugin = plugin.trim();\n const localPluginName = extractLocalPluginName(normalizedPlugin);\n\n return localPluginName\n ? `${localPluginName} (local plugin)`\n : normalizedPlugin;\n}\n\nfunction extractLocalPluginName(plugin: string): string | null {\n const filePath = parseFilePluginPath(plugin);\n\n if (!filePath) {\n return null;\n }\n\n const pathSegments = filePath.split(\"/\").filter((segment) => segment.length > 0);\n const fileName = pathSegments.at(-1);\n const parentDirectoryName = pathSegments.at(-2);\n\n if (!fileName || parentDirectoryName !== \"plugins\") {\n return null;\n }\n\n const pluginName = fileName.replace(/\\.(?:[cm]?js|[cm]?ts)$/iu, \"\");\n\n return pluginName.trim().length > 0\n ? pluginName.trim()\n : null;\n}\n\nfunction parseFilePluginPath(plugin: string): string | null {\n if (!plugin.startsWith(\"file://\")) {\n return null;\n }\n\n try {\n const fileUrl = new URL(plugin);\n\n if (fileUrl.protocol !== \"file:\") {\n return null;\n }\n\n const normalizedPath = decodeURIComponent(fileUrl.pathname)\n .replace(/^\\/([A-Za-z]:)/u, \"$1\")\n .replace(/\\\\/gu, \"/\");\n\n return normalizedPath.length > 0\n ? normalizedPath\n : null;\n } catch {\n return null;\n }\n}\n","import type { OpenCodeAgent } from \"../services/opencode/opencode.client.js\";\n\nexport const DEFAULT_AGENT_NAME = \"build\";\n\nexport function isSelectableAgent(agent: OpenCodeAgent): boolean {\n return !agent.hidden && agent.mode !== \"subagent\";\n}\n\nexport function getSelectableAgents(agents: OpenCodeAgent[]): OpenCodeAgent[] {\n return agents.filter((agent) => isSelectableAgent(agent));\n}\n\nexport function resolveSelectedAgent(\n agents: OpenCodeAgent[],\n requestedAgentName: string | null | undefined,\n): OpenCodeAgent | null {\n const visibleAgents = getSelectableAgents(agents);\n\n if (requestedAgentName) {\n const requestedAgent = visibleAgents.find((agent) => agent.name === requestedAgentName);\n\n if (requestedAgent) {\n return requestedAgent;\n }\n }\n\n return visibleAgents.find((agent) => agent.name === DEFAULT_AGENT_NAME) ?? null;\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\n\ntype MutableBindingFields = Omit<ChatSessionBinding, \"chatId\" | \"updatedAt\">;\n\nexport async function persistBindingUpdate(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n updates: Partial<MutableBindingFields>,\n): Promise<ChatSessionBinding> {\n const nextBinding: ChatSessionBinding = {\n ...binding,\n ...updates,\n updatedAt: new Date().toISOString(),\n };\n\n await sessionRepo.setCurrent(nextBinding);\n return nextBinding;\n}\n\nexport async function clearStoredAgentSelection(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n agentName: null,\n });\n}\n\nexport async function clearStoredModelSelection(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n modelProviderId: null,\n modelId: null,\n modelVariant: null,\n });\n}\n\nexport async function clearStoredModelVariant(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n modelVariant: null,\n });\n}\n\nexport async function clearStoredSessionContext(\n sessionRepo: SessionRepository,\n binding: ChatSessionBinding,\n): Promise<ChatSessionBinding> {\n return persistBindingUpdate(sessionRepo, binding, {\n sessionId: null,\n projectId: null,\n directory: null,\n });\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeAgent,\n OpenCodeClientLike,\n} from \"../services/opencode/opencode.client.js\";\nimport { getSelectableAgents, resolveSelectedAgent } from \"./agent-selection.js\";\nimport { clearStoredAgentSelection } from \"./binding-update.js\";\n\nexport interface ListAgentsResult {\n agents: OpenCodeAgent[];\n currentAgentName: string | null;\n}\n\nexport class ListAgentsUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListAgentsResult> {\n let [binding, agents] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listAgents(),\n ]);\n const visibleAgents = getSelectableAgents(agents);\n const currentAgent = resolveSelectedAgent(visibleAgents, binding?.agentName);\n\n if (binding?.agentName && currentAgent?.name !== binding.agentName) {\n binding = await clearStoredAgentSelection(this.sessionRepo, binding);\n }\n\n return {\n agents: visibleAgents,\n currentAgentName: currentAgent?.name ?? null,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeLspStatus,\n OpenCodeProject,\n} from \"../services/opencode/opencode.client.js\";\nimport { clearStoredSessionContext } from \"./binding-update.js\";\n\nexport interface ListLspResult {\n currentDirectory: string;\n statuses: OpenCodeLspStatus[];\n}\n\nexport class ListLspUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListLspResult> {\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n\n if (binding?.projectId && binding.directory) {\n const projects = await this.opencodeClient.listProjects();\n\n if (!hasMatchingProject(projects, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n }\n\n const projectContext = binding?.projectId && binding.directory\n ? {\n projectId: binding.projectId,\n directory: binding.directory,\n }\n : await this.getCurrentProjectContext();\n const statuses = await this.opencodeClient.listLspStatuses(projectContext.directory);\n\n return {\n currentDirectory: projectContext.directory,\n statuses: [...statuses].sort(compareLspStatuses),\n };\n }\n\n private async getCurrentProjectContext() {\n const currentProject = await this.opencodeClient.getCurrentProject();\n\n return {\n projectId: currentProject.id,\n directory: currentProject.worktree,\n };\n }\n}\n\nfunction compareLspStatuses(left: OpenCodeLspStatus, right: OpenCodeLspStatus): number {\n return left.name.localeCompare(right.name)\n || left.root.localeCompare(right.root)\n || left.id.localeCompare(right.id);\n}\n\nfunction hasMatchingProject(projects: OpenCodeProject[], binding: ChatSessionBinding): boolean {\n return projects.some((project) =>\n project.id === binding.projectId && project.worktree === binding.directory,\n );\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeMcpStatus,\n OpenCodeProject,\n} from \"../services/opencode/opencode.client.js\";\nimport { clearStoredSessionContext } from \"./binding-update.js\";\n\nexport interface ListMcpEntry {\n name: string;\n status: OpenCodeMcpStatus;\n}\n\nexport interface ListMcpResult {\n currentDirectory: string;\n statuses: ListMcpEntry[];\n}\n\nexport class ListMcpUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListMcpResult> {\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n\n if (binding?.projectId && binding.directory) {\n const projects = await this.opencodeClient.listProjects();\n\n if (!hasMatchingProject(projects, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n }\n\n const projectContext = binding?.projectId && binding.directory\n ? {\n projectId: binding.projectId,\n directory: binding.directory,\n }\n : await this.getCurrentProjectContext();\n const statuses = await this.opencodeClient.listMcpStatuses(projectContext.directory);\n\n return {\n currentDirectory: projectContext.directory,\n statuses: Object.entries(statuses)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([name, status]) => ({ name, status })),\n };\n }\n\n private async getCurrentProjectContext() {\n const currentProject = await this.opencodeClient.getCurrentProject();\n\n return {\n projectId: currentProject.id,\n directory: currentProject.worktree,\n };\n }\n}\n\nfunction hasMatchingProject(projects: OpenCodeProject[], binding: ChatSessionBinding): boolean {\n return projects.some((project) =>\n project.id === binding.projectId && project.worktree === binding.directory,\n );\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeConfiguredModel,\n} from \"../services/opencode/opencode.client.js\";\nimport {\n clearStoredModelSelection,\n clearStoredModelVariant,\n} from \"./binding-update.js\";\n\nexport interface ListModelsResult {\n models: OpenCodeConfiguredModel[];\n currentModelProviderId: string | null;\n currentModelId: string | null;\n currentModelVariant: string | null;\n}\n\nexport class ListModelsUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListModelsResult> {\n let [binding, models] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listModels(),\n ]);\n\n if (binding?.modelProviderId && binding?.modelId) {\n const selectedModel = models.find((model) =>\n model.providerID === binding?.modelProviderId && model.id === binding?.modelId,\n );\n\n if (!selectedModel) {\n binding = await clearStoredModelSelection(this.sessionRepo, binding);\n } else if (binding.modelVariant && !(binding.modelVariant in selectedModel.variants)) {\n binding = await clearStoredModelVariant(this.sessionRepo, binding);\n }\n }\n\n return {\n models,\n currentModelProviderId: binding?.modelProviderId ?? null,\n currentModelId: binding?.modelId ?? null,\n currentModelVariant: binding?.modelVariant ?? null,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeProject,\n OpenCodeSession,\n} from \"../services/opencode/opencode.client.js\";\nimport { clearStoredSessionContext } from \"./binding-update.js\";\n\nexport interface ListSessionsResult {\n sessions: OpenCodeSession[];\n currentProjectId: string;\n currentDirectory: string;\n currentSessionId: string | null;\n}\n\nexport class ListSessionsUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n ) { }\n\n async execute(input: { chatId: number }): Promise<ListSessionsResult> {\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n const [sessions, projects] = await Promise.all([\n this.opencodeClient.listSessions(),\n binding?.projectId && binding.directory\n ? this.opencodeClient.listProjects()\n : Promise.resolve<OpenCodeProject[] | null>(null),\n ]);\n\n if (binding?.projectId && binding.directory && !hasMatchingProject(projects, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n\n if (binding?.sessionId && binding.projectId && !hasMatchingSession(sessions, binding)) {\n binding = await clearStoredSessionContext(this.sessionRepo, binding);\n }\n\n const projectContext = binding?.projectId && binding.directory\n ? {\n projectId: binding.projectId,\n directory: binding.directory,\n }\n : await this.getCurrentProjectContext();\n\n return {\n sessions: sessions.filter((session) => session.projectID === projectContext.projectId),\n currentProjectId: projectContext.projectId,\n currentDirectory: projectContext.directory,\n currentSessionId: binding?.projectId === projectContext.projectId ? binding.sessionId : null,\n };\n }\n\n private async getCurrentProjectContext() {\n const currentProject = await this.opencodeClient.getCurrentProject();\n\n return {\n projectId: currentProject.id,\n directory: currentProject.worktree,\n };\n }\n}\n\nfunction hasMatchingProject(\n projects: OpenCodeProject[] | null,\n binding: ChatSessionBinding,\n): boolean {\n if (!projects) {\n return true;\n }\n\n return projects.some((project) =>\n project.id === binding.projectId && project.worktree === binding.directory,\n );\n}\n\nfunction hasMatchingSession(\n sessions: OpenCodeSession[],\n binding: ChatSessionBinding,\n): boolean {\n return sessions.some((session) =>\n session.id === binding.sessionId && session.projectID === binding.projectId,\n );\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type { OpenCodeClientLike, OpenCodeSession } from \"../services/opencode/opencode.client.js\";\n\nexport type RenameSessionResult =\n | {\n found: false;\n }\n | {\n found: true;\n session: OpenCodeSession;\n };\n\nexport class RenameSessionUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; sessionId: string; title: string }): Promise<RenameSessionResult> {\n const title = input.title.trim();\n\n if (!title) {\n throw new Error(\"Session title cannot be empty.\");\n }\n\n const [binding, sessions] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listSessions(),\n ]);\n const currentProjectId = binding?.projectId ?? (await this.opencodeClient.getCurrentProject()).id;\n const session = sessions.find((item) => item.id === input.sessionId && item.projectID === currentProjectId);\n\n if (!session) {\n return { found: false };\n }\n\n const renamedSession = await this.opencodeClient.renameSession(session.id, title);\n\n this.logger.info(\n {\n chatId: input.chatId,\n sessionId: renamedSession.id,\n projectId: renamedSession.projectID,\n title: renamedSession.title,\n },\n \"session renamed\",\n );\n\n return {\n found: true,\n session: renamedSession,\n };\n }\n}\n","import type { ChatSessionBinding } from \"../domain/session/session.entity.js\";\nimport type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport {\n logOpenCodeRequest,\n logPromptLifecycle,\n type AppLogger,\n} from \"../infra/logger/index.js\";\nimport type {\n OpenCodeClientLike,\n PromptSessionFilePartInput,\n} from \"../services/opencode/opencode.client.js\";\nimport { resolveSelectedAgent } from \"./agent-selection.js\";\nimport {\n clearStoredAgentSelection,\n clearStoredModelSelection,\n clearStoredModelVariant,\n clearStoredSessionContext,\n} from \"./binding-update.js\";\nimport { createAndBindCurrentProjectSession } from \"./session-creation.js\";\n\ntype ActiveChatBinding = ChatSessionBinding & {\n directory: string;\n projectId: string;\n sessionId: string;\n};\n\nexport class SendPromptUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: {\n chatId: number;\n files?: PromptSessionFilePartInput[];\n onExecutionSession?: (sessionId: string) => void;\n signal?: AbortSignal;\n text?: string | null;\n }) {\n const files = input.files ?? [];\n const promptText = buildPromptText(input.text, files);\n\n if (!promptText && files.length === 0) {\n throw new Error(\"Prompt requires text or file attachments.\");\n }\n\n let binding = await this.sessionRepo.getByChatId(input.chatId);\n\n if (binding?.projectId && binding.directory) {\n const projects = await this.opencodeClient.listProjects();\n const selectedProject = projects.find((project) =>\n project.id === binding?.projectId && project.worktree === binding.directory,\n );\n\n if (!selectedProject) {\n binding = await this.clearInvalidSessionContext(\n input.chatId,\n binding,\n \"saved project is no longer available\",\n );\n }\n }\n\n if (binding?.sessionId && binding.projectId) {\n const sessions = await this.opencodeClient.listSessions();\n const selectedSession = sessions.find((session) =>\n session.id === binding?.sessionId && session.projectID === binding.projectId,\n );\n\n if (!selectedSession) {\n binding = await this.clearInvalidSessionContext(\n input.chatId,\n binding,\n \"saved session is no longer available\",\n );\n }\n }\n\n if (!binding || !binding.sessionId || !binding.projectId || !binding.directory) {\n const createdSession = await createAndBindCurrentProjectSession(\n this.sessionRepo,\n this.opencodeClient,\n {\n chatId: input.chatId,\n binding,\n },\n );\n binding = createdSession.binding;\n logPromptLifecycle(\n this.logger,\n {\n chatId: input.chatId,\n event: \"prompt.session.created\",\n projectId: createdSession.session.projectID,\n sessionId: createdSession.session.id,\n directory: createdSession.session.directory,\n },\n \"session created\",\n );\n }\n\n if (binding?.modelProviderId && binding?.modelId) {\n const availableModels = await this.opencodeClient.listModels();\n const selectedModel = availableModels.find((model) =>\n model.providerID === binding?.modelProviderId && model.id === binding?.modelId,\n );\n\n if (!selectedModel) {\n binding = await clearStoredModelSelection(this.sessionRepo, binding);\n this.logger.warn?.(\n {\n chatId: input.chatId,\n event: \"prompt.model.unavailable\",\n },\n \"selected model is no longer available, falling back to OpenCode default\",\n );\n } else if (binding.modelVariant && !(binding.modelVariant in selectedModel.variants)) {\n binding = await clearStoredModelVariant(this.sessionRepo, binding);\n this.logger.warn?.(\n {\n chatId: input.chatId,\n event: \"prompt.model.variant_unavailable\",\n providerId: selectedModel.providerID,\n modelId: selectedModel.id,\n },\n \"selected model variant is no longer available, falling back to default variant\",\n );\n }\n }\n\n if (!binding || !binding.sessionId || !binding.projectId) {\n throw new Error(\"Failed to initialize chat session.\");\n }\n\n let activeBinding = binding as ActiveChatBinding;\n const shouldIsolateImageTurn = hasImageFiles(files);\n const model = activeBinding.modelProviderId && activeBinding.modelId\n ? {\n providerID: activeBinding.modelProviderId,\n modelID: activeBinding.modelId,\n }\n : null;\n const availableAgents = await this.opencodeClient.listAgents();\n const selectedAgent = resolveSelectedAgent(availableAgents, activeBinding.agentName);\n\n if (activeBinding.agentName && selectedAgent?.name !== activeBinding.agentName) {\n activeBinding = await clearStoredAgentSelection(this.sessionRepo, activeBinding) as ActiveChatBinding;\n this.logger.warn?.(\n {\n chatId: input.chatId,\n event: \"prompt.agent.unavailable\",\n },\n \"selected agent is no longer available, falling back to OpenCode default\",\n );\n }\n\n const temporarySessionId = shouldIsolateImageTurn\n ? await this.createTemporaryImageSession(input.chatId, activeBinding.sessionId)\n : null;\n const executionSessionId = temporarySessionId ?? activeBinding.sessionId;\n\n input.onExecutionSession?.(executionSessionId);\n let result;\n\n try {\n logOpenCodeRequest(this.logger, {\n chatId: input.chatId,\n event: \"opencode.prompt.submit\",\n projectId: activeBinding.projectId,\n sessionId: executionSessionId,\n fileCount: files.length,\n status: \"started\",\n }, \"submitting OpenCode prompt\");\n result = await this.opencodeClient.promptSession({\n sessionId: executionSessionId,\n prompt: promptText,\n ...(files.length > 0 ? { files } : {}),\n ...(selectedAgent ? { agent: selectedAgent.name } : {}),\n format: {\n type: \"text\",\n },\n ...(model ? { model } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n ...(activeBinding.modelVariant ? { variant: activeBinding.modelVariant } : {}),\n });\n logPromptLifecycle(this.logger, {\n chatId: input.chatId,\n event: \"prompt.completed\",\n projectId: activeBinding.projectId,\n sessionId: executionSessionId,\n status: \"completed\",\n }, \"prompt completed\");\n } finally {\n if (temporarySessionId) {\n await this.cleanupTemporaryImageSession(\n input.chatId,\n activeBinding.sessionId,\n temporarySessionId,\n );\n }\n }\n\n await this.sessionRepo.touch(input.chatId);\n\n return {\n assistantReply: result,\n sessionId: activeBinding.sessionId,\n projectId: activeBinding.projectId,\n };\n }\n\n private async clearInvalidSessionContext(\n chatId: number,\n binding: ChatSessionBinding,\n reason: string,\n ) {\n const nextBinding = await clearStoredSessionContext(this.sessionRepo, binding);\n this.logger.warn?.(\n {\n chatId,\n event: \"prompt.session.invalid_context\",\n },\n `${reason}, falling back to the current OpenCode project`,\n );\n\n return nextBinding;\n }\n\n private async createTemporaryImageSession(chatId: number, sessionId: string): Promise<string> {\n const temporarySession = await this.opencodeClient.forkSession(sessionId);\n\n if (!temporarySession.id || temporarySession.id === sessionId) {\n throw new Error(\"OpenCode did not return a distinct temporary session for the image turn.\");\n }\n\n logPromptLifecycle(\n this.logger,\n {\n chatId,\n event: \"prompt.temporary_session.created\",\n parentSessionId: sessionId,\n sessionId: temporarySession.id,\n },\n \"created temporary image session\",\n );\n\n return temporarySession.id;\n }\n\n private async cleanupTemporaryImageSession(\n chatId: number,\n parentSessionId: string,\n sessionId: string,\n ): Promise<void> {\n try {\n const deleted = await this.opencodeClient.deleteSession(sessionId);\n\n if (!deleted) {\n this.logger.warn?.(\n {\n chatId,\n event: \"prompt.temporary_session.cleanup_failed\",\n parentSessionId,\n sessionId,\n },\n \"failed to delete temporary image session\",\n );\n }\n } catch (error) {\n this.logger.warn?.(\n {\n error,\n chatId,\n event: \"prompt.temporary_session.cleanup_failed\",\n parentSessionId,\n sessionId,\n },\n \"failed to delete temporary image session\",\n );\n }\n }\n}\n\nfunction buildPromptText(\n text: string | null | undefined,\n files: PromptSessionFilePartInput[],\n): string {\n const trimmedText = text?.trim() ?? \"\";\n\n if (!files.some(isImageFile)) {\n return trimmedText;\n }\n\n const promptSections = [\n [\n \"System note for this turn:\",\n \"The user attached one or more images in this message and you can inspect those images directly.\",\n \"Ignore any earlier statements in this conversation claiming that you could not view images or attachments, because those may have come from a previous model or an earlier limitation.\",\n \"If an image is blurry or unreadable, say that it is blurry or unreadable instead of saying that you cannot view images.\",\n ].join(\" \"),\n ];\n\n if (trimmedText) {\n promptSections.push(trimmedText);\n }\n\n return promptSections.join(\"\\n\\n\");\n}\n\nfunction isImageFile(file: PromptSessionFilePartInput): boolean {\n return file.mime.trim().toLowerCase().startsWith(\"image/\");\n}\n\nfunction hasImageFiles(files: PromptSessionFilePartInput[]): boolean {\n return files.some(isImageFile);\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type {\n OpenCodeAgent,\n OpenCodeClientLike,\n} from \"../services/opencode/opencode.client.js\";\nimport { isSelectableAgent } from \"./agent-selection.js\";\n\nexport type SwitchAgentResult =\n | {\n found: false;\n }\n | {\n found: true;\n agent: OpenCodeAgent;\n };\n\nexport class SwitchAgentUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; agentName: string }): Promise<SwitchAgentResult> {\n const [binding, agents] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listAgents(),\n ]);\n const agent = agents.find((item) => item.name === input.agentName && isSelectableAgent(item));\n\n if (!agent) {\n return { found: false };\n }\n\n await this.sessionRepo.setCurrent({\n chatId: input.chatId,\n sessionId: binding?.sessionId ?? null,\n projectId: binding?.projectId ?? null,\n directory: binding?.directory ?? null,\n agentName: agent.name,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n });\n\n this.logger.info(\n {\n chatId: input.chatId,\n agentName: agent.name,\n },\n \"agent switched\",\n );\n\n return {\n found: true,\n agent,\n };\n }\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type {\n OpenCodeClientLike,\n OpenCodeConfiguredModel,\n} from \"../services/opencode/opencode.client.js\";\n\nexport type SwitchModelResult =\n | {\n found: false;\n }\n | {\n found: true;\n model: OpenCodeConfiguredModel;\n variant: string | null;\n };\n\nexport class SwitchModelUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: {\n chatId: number;\n providerId: string;\n modelId: string;\n variant?: string | null;\n }): Promise<SwitchModelResult> {\n const [binding, models] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listModels(),\n ]);\n const model = models.find((item) =>\n item.providerID === input.providerId && item.id === input.modelId,\n );\n\n if (!model) {\n return { found: false };\n }\n\n const variant = input.variant ?? null;\n\n if (variant && !(variant in model.variants)) {\n return { found: false };\n }\n\n await this.sessionRepo.setCurrent({\n chatId: input.chatId,\n sessionId: binding?.sessionId ?? null,\n projectId: binding?.projectId ?? null,\n directory: binding?.directory ?? null,\n agentName: binding?.agentName ?? null,\n modelProviderId: model.providerID,\n modelId: model.id,\n modelVariant: variant,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n });\n\n this.logger.info(\n {\n chatId: input.chatId,\n providerId: model.providerID,\n modelId: model.id,\n variant,\n },\n \"model switched\",\n );\n\n return {\n found: true,\n model,\n variant,\n };\n }\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport type { OpenCodeClientLike, OpenCodeSession } from \"../services/opencode/opencode.client.js\";\n\nexport type SwitchSessionResult =\n | {\n found: false;\n }\n | {\n found: true;\n session: OpenCodeSession;\n };\n\nexport class SwitchSessionUseCase {\n constructor(\n private readonly sessionRepo: SessionRepository,\n private readonly opencodeClient: OpenCodeClientLike,\n private readonly logger: AppLogger,\n ) { }\n\n async execute(input: { chatId: number; sessionId: string }): Promise<SwitchSessionResult> {\n const [binding, sessions] = await Promise.all([\n this.sessionRepo.getByChatId(input.chatId),\n this.opencodeClient.listSessions(),\n ]);\n const currentProjectId = binding?.projectId ?? (await this.opencodeClient.getCurrentProject()).id;\n const session = sessions.find((item) => item.id === input.sessionId && item.projectID === currentProjectId);\n\n if (!session) {\n return { found: false };\n }\n\n await this.sessionRepo.setCurrent({\n chatId: input.chatId,\n sessionId: session.id,\n projectId: session.projectID,\n directory: session.directory,\n agentName: binding?.agentName ?? null,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language: binding?.language ?? null,\n updatedAt: new Date().toISOString(),\n });\n\n this.logger.info(\n {\n chatId: input.chatId,\n sessionId: session.id,\n projectId: session.projectID,\n directory: session.directory,\n },\n \"session switched\",\n );\n\n return {\n found: true,\n session,\n };\n }\n}\n","import type { PromptSessionFilePartInput } from \"../services/opencode/opencode.client.js\";\nimport {\n TelegramFileDownloadError,\n type TelegramFileClientLike,\n} from \"../services/telegram/telegram.client.js\";\n\nexport interface UploadFileInput {\n expectedType: \"image\";\n filePath: string;\n filename?: string | null;\n mimeType?: string | null;\n}\n\nexport class ImageFileDownloadError extends Error {\n readonly data: { message: string };\n\n constructor(message: string) {\n super(message);\n this.name = \"ImageFileDownloadError\";\n this.data = { message };\n }\n}\n\nexport class ImageMessageUnsupportedError extends Error {\n readonly data: { message: string };\n\n constructor(message: string) {\n super(message);\n this.name = \"ImageMessageUnsupportedError\";\n this.data = { message };\n }\n}\n\nexport class UploadFileUseCase {\n constructor(private readonly telegramFileClient: TelegramFileClientLike) { }\n\n async execute(input: UploadFileInput): Promise<PromptSessionFilePartInput> {\n if (input.expectedType !== \"image\") {\n throw new ImageMessageUnsupportedError(\"Only image uploads are supported.\");\n }\n\n let download;\n\n try {\n download = await this.telegramFileClient.downloadFile({\n filePath: input.filePath,\n });\n } catch (error) {\n if (error instanceof TelegramFileDownloadError) {\n throw new ImageFileDownloadError(error.message);\n }\n\n throw error;\n }\n\n const mimeType = normalizeMimeType(input.mimeType ?? download.mimeType);\n\n if (!mimeType.startsWith(\"image/\")) {\n throw new ImageMessageUnsupportedError(`Unsupported image MIME type: ${mimeType}`);\n }\n\n const filename = resolveFilename(input.filename, input.filePath, mimeType);\n\n return {\n filename,\n mime: mimeType,\n url: buildDataUrl(download.data, mimeType),\n };\n }\n}\n\nfunction buildDataUrl(data: Uint8Array, mimeType: string): string {\n const buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength);\n\n return `data:${mimeType};base64,${buffer.toString(\"base64\")}`;\n}\n\nfunction normalizeMimeType(value: string | null): string {\n const normalized = value?.trim().toLowerCase();\n\n return normalized && normalized.length > 0\n ? normalized\n : \"application/octet-stream\";\n}\n\nfunction resolveFilename(\n explicitFilename: string | null | undefined,\n filePath: string,\n mimeType: string,\n): string {\n const preferredFilename = explicitFilename?.trim();\n\n if (preferredFilename) {\n return preferredFilename;\n }\n\n const filePathFilename = filePath.split(\"/\").at(-1)?.trim();\n\n if (filePathFilename) {\n return filePathFilename;\n }\n\n return `telegram-upload${resolveExtension(mimeType)}`;\n}\n\nfunction resolveExtension(mimeType: string): string {\n switch (mimeType) {\n case \"image/jpeg\":\n return \".jpg\";\n case \"image/png\":\n return \".png\";\n case \"image/webp\":\n return \".webp\";\n case \"image/gif\":\n return \".gif\";\n default:\n return \"\";\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { BotDependencies } from \"../bot/types.js\";\nimport type { PermissionApprovalRepository } from \"../domain/permission/approval.repository.js\";\nimport { createOpenCodeAppLogger } from \"../infra/logger/index.js\";\nimport { FilePendingActionRepository } from \"../repositories/pending-action.repo.js\";\nimport { FilePermissionApprovalRepository } from \"../repositories/permission-approval.repo.js\";\nimport { FileSessionRepository } from \"../repositories/session.repo.js\";\nimport {\n createOpenCodeClientFromSdkClient,\n type OpenCodeClientLike,\n type OpenCodeSdkClientLike,\n} from \"../services/opencode/opencode.client.js\";\nimport { createDefaultOpencodeTbotState } from \"../services/storage/bot-state.js\";\nimport { JsonStateStore } from \"../services/storage/json-state-store.js\";\nimport { TelegramFileClient } from \"../services/telegram/telegram.client.js\";\nimport { ForegroundSessionTracker } from \"../services/session-activity/foreground-session-tracker.js\";\nimport { AbortPromptUseCase } from \"../use-cases/abort-prompt.usecase.js\";\nimport { CreateSessionUseCase } from \"../use-cases/create-session.usecase.js\";\nimport { GetHealthUseCase } from \"../use-cases/get-health.usecase.js\";\nimport { GetPathUseCase } from \"../use-cases/get-path.usecase.js\";\nimport { GetStatusUseCase } from \"../use-cases/get-status.usecase.js\";\nimport { ListAgentsUseCase } from \"../use-cases/list-agents.usecase.js\";\nimport { ListLspUseCase } from \"../use-cases/list-lsp.usecase.js\";\nimport { ListMcpUseCase } from \"../use-cases/list-mcp.usecase.js\";\nimport { ListModelsUseCase } from \"../use-cases/list-models.usecase.js\";\nimport { ListSessionsUseCase } from \"../use-cases/list-sessions.usecase.js\";\nimport { RenameSessionUseCase } from \"../use-cases/rename-session.usecase.js\";\nimport { SendPromptUseCase } from \"../use-cases/send-prompt.usecase.js\";\nimport { SwitchAgentUseCase } from \"../use-cases/switch-agent.usecase.js\";\nimport { SwitchModelUseCase } from \"../use-cases/switch-model.usecase.js\";\nimport { SwitchSessionUseCase } from \"../use-cases/switch-session.usecase.js\";\nimport { UploadFileUseCase } from \"../use-cases/upload-file.usecase.js\";\nimport type { AppConfig } from \"./config.js\";\n\nexport interface AppContainer extends BotDependencies {\n opencodeClient: OpenCodeClientLike;\n foregroundSessionTracker: ForegroundSessionTracker;\n permissionApprovalRepo: PermissionApprovalRepository;\n dispose(): Promise<void>;\n}\n\nexport function createAppContainer(\n config: AppConfig,\n client: OpenCodeSdkClientLike,\n): AppContainer {\n const runtimeId = randomUUID();\n const logger = createOpenCodeAppLogger(client, {\n file: {\n dir: config.loggingFileDir,\n retention: {\n maxFiles: config.loggingRetentionMaxFiles,\n maxTotalBytes: config.loggingRetentionMaxTotalBytes,\n },\n },\n level: config.loggingLevel,\n runtimeId,\n sinks: {\n file: config.loggingFileSinkEnabled,\n host: config.loggingHostSinkEnabled,\n },\n worktree: config.worktreePath,\n });\n\n return createContainer(\n config,\n createOpenCodeClientFromSdkClient(\n client,\n fetch,\n {\n waitTimeoutMs: config.promptWaitTimeoutMs,\n pollRequestTimeoutMs: config.promptPollRequestTimeoutMs,\n recoveryInactivityTimeoutMs: config.promptRecoveryInactivityTimeoutMs,\n },\n ),\n logger,\n );\n}\n\nfunction createContainer(\n config: AppConfig,\n opencodeClient: OpenCodeClientLike,\n logger: BotDependencies[\"logger\"],\n): AppContainer {\n const storageLogger = logger.child({ component: \"storage\" });\n const opencodeLogger = logger.child({ component: \"opencode\" });\n const promptLogger = logger.child({ component: \"prompt\" });\n const stateStore = new JsonStateStore({\n filePath: config.stateFilePath,\n createDefaultState: createDefaultOpencodeTbotState,\n });\n const pendingActionRepo = new FilePendingActionRepository(stateStore);\n const permissionApprovalRepo = new FilePermissionApprovalRepository(stateStore);\n const sessionRepo = new FileSessionRepository(stateStore);\n const foregroundSessionTracker = new ForegroundSessionTracker();\n const telegramFileClient = new TelegramFileClient({\n botToken: config.telegramBotToken,\n apiRoot: config.telegramApiRoot,\n });\n const uploadFileUseCase = new UploadFileUseCase(telegramFileClient);\n const abortPromptUseCase = new AbortPromptUseCase(\n sessionRepo,\n opencodeClient,\n foregroundSessionTracker,\n );\n const createSessionUseCase = new CreateSessionUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const getHealthUseCase = new GetHealthUseCase(opencodeClient);\n const getPathUseCase = new GetPathUseCase(opencodeClient);\n const listAgentsUseCase = new ListAgentsUseCase(sessionRepo, opencodeClient);\n const listLspUseCase = new ListLspUseCase(sessionRepo, opencodeClient);\n const listMcpUseCase = new ListMcpUseCase(sessionRepo, opencodeClient);\n const listSessionsUseCase = new ListSessionsUseCase(sessionRepo, opencodeClient);\n const getStatusUseCase = new GetStatusUseCase(\n getHealthUseCase,\n getPathUseCase,\n listLspUseCase,\n listMcpUseCase,\n listSessionsUseCase,\n sessionRepo,\n opencodeClient as {\n listConfiguredPlugins(): Promise<string[]>;\n },\n );\n const listModelsUseCase = new ListModelsUseCase(sessionRepo, opencodeClient);\n const renameSessionUseCase = new RenameSessionUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const sendPromptUseCase = new SendPromptUseCase(\n sessionRepo,\n opencodeClient,\n promptLogger,\n );\n const switchAgentUseCase = new SwitchAgentUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const switchModelUseCase = new SwitchModelUseCase(sessionRepo, opencodeClient, opencodeLogger);\n const switchSessionUseCase = new SwitchSessionUseCase(sessionRepo, opencodeClient, opencodeLogger);\n let disposed = false;\n\n return {\n abortPromptUseCase,\n createSessionUseCase,\n getHealthUseCase,\n getPathUseCase,\n getStatusUseCase,\n listAgentsUseCase,\n listLspUseCase,\n listMcpUseCase,\n logger,\n listModelsUseCase,\n listSessionsUseCase,\n pendingActionRepo,\n renameSessionUseCase,\n sessionRepo,\n sendPromptUseCase,\n switchAgentUseCase,\n switchModelUseCase,\n switchSessionUseCase,\n telegramFileClient,\n uploadFileUseCase,\n opencodeClient,\n foregroundSessionTracker,\n permissionApprovalRepo,\n async dispose() {\n if (disposed) {\n return;\n }\n\n disposed = true;\n storageLogger.info(\n {\n event: \"storage.container.disposed\",\n filePath: config.stateFilePath,\n },\n \"disposing telegram bot container\",\n );\n await logger.flush();\n },\n };\n}\n","import {\n loadAppConfig,\n type LoadAppConfigOptions,\n type AppConfig,\n type PluginConfigSource,\n} from \"./config.js\";\nimport {\n createAppContainer,\n type AppContainer,\n} from \"./container.js\";\nimport type { OpenCodeSdkClientLike } from \"../services/opencode/opencode.client.js\";\n\nexport function bootstrapPluginApp(\n client: OpenCodeSdkClientLike,\n configSource: PluginConfigSource | undefined = {},\n options: LoadAppConfigOptions = {},\n): { config: AppConfig; container: AppContainer } {\n const config = loadAppConfig(configSource, options);\n\n return {\n config,\n container: createAppContainer(config, client),\n };\n}\n","import type { PermissionApprovalReply } from \"../../domain/permission/approval.entity.js\";\nimport type { PermissionApprovalCallbackData } from \"../../bot/types.js\";\nimport type { OpenCodePermissionRequest } from \"../opencode/opencode.client.js\";\n\nexport function buildPermissionApprovalMessage(\n request: OpenCodePermissionRequest,\n): string {\n const patterns = request.patterns.length > 0\n ? request.patterns.map((pattern) => `- ${pattern}`).join(\"\\n\")\n : \"- (none)\";\n\n return [\n \"*Permission Request*\",\n \"\",\n `Permission: \\`${escapeMarkdownV2(request.permission)}\\``,\n `Session: \\`${escapeMarkdownV2(request.sessionID)}\\``,\n \"\",\n \"Patterns:\",\n patterns,\n ].join(\"\\n\");\n}\n\nexport function buildPermissionApprovalResolvedMessage(\n requestId: string,\n reply: PermissionApprovalReply,\n): string {\n return [\n \"Permission request resolved.\",\n \"\",\n `Request: ${requestId}`,\n `Reply: ${reply}`,\n ].join(\"\\n\");\n}\n\nexport function buildPermissionApprovalKeyboard(requestId: string) {\n return {\n inline_keyboard: [[\n {\n text: \"Allow once\",\n callback_data: buildPermissionApprovalCallbackData(\"once\", requestId),\n },\n {\n text: \"Always allow\",\n callback_data: buildPermissionApprovalCallbackData(\"always\", requestId),\n },\n {\n text: \"Reject\",\n callback_data: buildPermissionApprovalCallbackData(\"reject\", requestId),\n },\n ]],\n };\n}\n\nexport function buildPermissionApprovalCallbackData(\n reply: PermissionApprovalReply,\n requestId: string,\n): PermissionApprovalCallbackData {\n return `permission:${reply}:${requestId}`;\n}\n\nexport function parsePermissionApprovalCallbackData(data: string): {\n reply: PermissionApprovalReply;\n requestId: string;\n} | null {\n if (!data.startsWith(\"permission:\")) {\n return null;\n }\n\n const [, reply, requestId] = data.split(\":\", 3);\n\n if (!requestId || !isPermissionApprovalReply(reply)) {\n return null;\n }\n\n return {\n reply,\n requestId,\n };\n}\n\nfunction isPermissionApprovalReply(value: string): value is PermissionApprovalReply {\n return value === \"once\" || value === \"always\" || value === \"reject\";\n}\n\nfunction escapeMarkdownV2(value: string): string {\n return value.replaceAll(/([_*\\[\\]()~`>#+\\-=|{}.!\\\\])/g, \"\\\\$1\");\n}\n","import type { Event as OpenCodeEvent } from \"@opencode-ai/sdk\";\nimport type { PendingPermissionApproval, PermissionApprovalReply } from \"../domain/permission/approval.entity.js\";\nimport { logPluginEvent } from \"../infra/logger/index.js\";\nimport type { OpenCodePermissionRequest } from \"../services/opencode/opencode.client.js\";\nimport {\n buildPermissionApprovalKeyboard,\n buildPermissionApprovalMessage,\n buildPermissionApprovalResolvedMessage,\n} from \"../services/permission/telegram-approval.js\";\nimport type { TelegramBotRuntime } from \"./runtime.js\";\n\ntype OpenCodePluginEvent = OpenCodeEvent | {\n properties?: unknown;\n type: string;\n};\n\ninterface NormalizedPermissionReplyEvent {\n reply: PermissionApprovalReply;\n requestId: string;\n sessionId: string;\n}\n\ninterface NormalizedSessionErrorEvent {\n error: unknown;\n sessionId: string;\n}\n\ninterface NormalizedSessionIdleEvent {\n sessionId: string;\n}\n\ninterface NormalizedSessionStatusEvent extends NormalizedSessionIdleEvent {\n statusType: string;\n}\n\nexport async function handleTelegramBotPluginEvent(\n runtime: TelegramBotRuntime,\n event: OpenCodePluginEvent,\n): Promise<void> {\n switch (event.type) {\n case \"permission.asked\":\n case \"permission.updated\": {\n const request = normalizePermissionRequestEvent(event.properties);\n\n if (request) {\n await handlePermissionAsked(runtime, request);\n }\n return;\n }\n case \"permission.replied\": {\n const replyEvent = normalizePermissionReplyEvent(event.properties);\n\n if (replyEvent) {\n await handlePermissionReplied(runtime, replyEvent);\n }\n return;\n }\n case \"session.error\": {\n const sessionError = normalizeSessionErrorEvent(event.properties);\n\n if (sessionError) {\n await handleSessionError(runtime, sessionError);\n }\n return;\n }\n case \"session.idle\": {\n const sessionIdle = normalizeSessionIdleEvent(event.properties);\n\n if (sessionIdle) {\n await handleSessionIdle(runtime, sessionIdle);\n }\n return;\n }\n case \"session.status\": {\n const sessionStatus = normalizeSessionStatusEvent(event.properties);\n\n if (sessionStatus) {\n await handleSessionStatus(runtime, sessionStatus);\n }\n return;\n }\n default:\n return;\n }\n}\n\nasync function handlePermissionAsked(\n runtime: TelegramBotRuntime,\n request: OpenCodePermissionRequest,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n requestId: request.id,\n sessionId: request.sessionID,\n });\n const bindings = await runtime.container.sessionRepo.listBySessionId(request.sessionID);\n const chatIds = new Set([\n ...bindings.map((binding) => binding.chatId),\n ...runtime.container.foregroundSessionTracker.listChatIds(request.sessionID),\n ]);\n const approvals = await runtime.container.permissionApprovalRepo.listByRequestId(request.id);\n const approvedChatIds = new Set(approvals.map((approval) => approval.chatId));\n\n for (const chatId of chatIds) {\n if (approvedChatIds.has(chatId)) {\n continue;\n }\n\n try {\n const message = await runtime.bot.api.sendMessage(\n chatId,\n buildPermissionApprovalMessage(request),\n {\n parse_mode: \"MarkdownV2\",\n reply_markup: buildPermissionApprovalKeyboard(request.id),\n },\n );\n\n await runtime.container.permissionApprovalRepo.set({\n requestId: request.id,\n sessionId: request.sessionID,\n chatId,\n messageId: message.message_id,\n status: \"pending\",\n updatedAt: new Date().toISOString(),\n });\n } catch (error) {\n logger.error(\n {\n error,\n chatId,\n event: \"plugin-event.permission.ask.delivery_failed\",\n requestId: request.id,\n },\n \"failed to deliver permission request to Telegram\",\n );\n }\n }\n}\n\nasync function handlePermissionReplied(\n runtime: TelegramBotRuntime,\n event: NormalizedPermissionReplyEvent,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n event: \"plugin-event.permission.replied\",\n requestId: event.requestId,\n sessionId: event.sessionId,\n });\n const approvals = await runtime.container.permissionApprovalRepo.listByRequestId(event.requestId);\n\n await Promise.all(\n approvals.map(async (approval) => {\n try {\n await runtime.bot.api.editMessageText(\n approval.chatId,\n approval.messageId,\n buildPermissionApprovalResolvedMessage(event.requestId, event.reply),\n );\n } catch (error) {\n logger.warn(\n {\n error,\n chatId: approval.chatId,\n event: \"plugin-event.permission.reply_message_failed\",\n },\n \"failed to update Telegram permission message\",\n );\n }\n\n await runtime.container.permissionApprovalRepo.set(toResolvedApproval(approval, event.reply));\n }),\n );\n}\n\nasync function handleSessionError(\n runtime: TelegramBotRuntime,\n event: NormalizedSessionErrorEvent,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n sessionId: event.sessionId,\n });\n const wasForeground = runtime.container.foregroundSessionTracker.fail(\n event.sessionId,\n normalizeForegroundSessionError(event.error),\n );\n\n if (wasForeground) {\n logger.warn(\n {\n error: event.error,\n event: \"plugin-event.session.error.foreground_suppressed\",\n },\n \"session error suppressed for foreground Telegram session\",\n );\n return;\n }\n\n const message = extractSessionErrorMessage(event.error) ?? \"Unknown session error.\";\n\n await notifyBoundChats(runtime, event.sessionId, `Session failed.\\n\\nSession: ${event.sessionId}\\nError: ${message}`);\n}\n\nasync function handleSessionIdle(\n runtime: TelegramBotRuntime,\n event: NormalizedSessionIdleEvent,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n sessionId: event.sessionId,\n });\n const wasForeground = runtime.container.foregroundSessionTracker.clear(event.sessionId);\n\n if (wasForeground) {\n logPluginEvent(\n logger,\n {\n event: \"plugin-event.session.idle.foreground_suppressed\",\n },\n \"session idle notification suppressed for foreground Telegram session\",\n );\n }\n}\n\nasync function handleSessionStatus(\n runtime: TelegramBotRuntime,\n event: NormalizedSessionStatusEvent,\n): Promise<void> {\n if (event.statusType !== \"idle\") {\n return;\n }\n\n await handleSessionIdle(runtime, event);\n}\n\nasync function notifyBoundChats(\n runtime: TelegramBotRuntime,\n sessionId: string,\n text: string,\n): Promise<void> {\n const logger = runtime.container.logger.child({\n component: \"plugin-event\",\n sessionId,\n });\n const bindings = await runtime.container.sessionRepo.listBySessionId(sessionId);\n const chatIds = [...new Set(bindings.map((binding) => binding.chatId))];\n\n await Promise.all(\n chatIds.map(async (chatId) => {\n try {\n await runtime.bot.api.sendMessage(chatId, text);\n } catch (error) {\n logger.warn(\n {\n error,\n chatId,\n event: \"plugin-event.session.notify_failed\",\n },\n \"failed to notify Telegram chat about session event\",\n );\n }\n }),\n );\n}\n\nfunction toResolvedApproval(\n approval: PendingPermissionApproval,\n reply: PermissionApprovalReply,\n): PendingPermissionApproval {\n return {\n ...approval,\n status: reply,\n updatedAt: new Date().toISOString(),\n };\n}\n\nfunction normalizePermissionRequestEvent(properties: unknown): OpenCodePermissionRequest | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const id = asNonEmptyString(properties.id);\n const sessionID = asNonEmptyString(properties.sessionID);\n const permission = asNonEmptyString(properties.permission) ?? asNonEmptyString(properties.type);\n\n if (!id || !sessionID || !permission) {\n return null;\n }\n\n return {\n always: Array.isArray(properties.always)\n ? properties.always.filter((value): value is string => typeof value === \"string\")\n : [],\n id,\n metadata: isPlainRecord(properties.metadata)\n ? properties.metadata\n : {},\n patterns: normalizePermissionPatterns(properties),\n permission,\n sessionID,\n };\n}\n\nfunction normalizePermissionReplyEvent(properties: unknown): NormalizedPermissionReplyEvent | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const requestId = asNonEmptyString(properties.requestID) ?? asNonEmptyString(properties.permissionID);\n const reply = normalizePermissionReply(\n asNonEmptyString(properties.reply) ?? asNonEmptyString(properties.response),\n );\n const sessionId = asNonEmptyString(properties.sessionID);\n\n if (!requestId || !reply || !sessionId) {\n return null;\n }\n\n return {\n reply,\n requestId,\n sessionId,\n };\n}\n\nfunction normalizeSessionErrorEvent(properties: unknown): NormalizedSessionErrorEvent | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const sessionId = asNonEmptyString(properties.sessionID);\n\n if (!sessionId) {\n return null;\n }\n\n return {\n error: properties.error,\n sessionId,\n };\n}\n\nfunction normalizeSessionIdleEvent(properties: unknown): NormalizedSessionIdleEvent | null {\n if (!isPlainRecord(properties)) {\n return null;\n }\n\n const sessionId = asNonEmptyString(properties.sessionID);\n\n return sessionId\n ? { sessionId }\n : null;\n}\n\nfunction normalizeSessionStatusEvent(properties: unknown): NormalizedSessionStatusEvent | null {\n if (!isPlainRecord(properties) || !isPlainRecord(properties.status)) {\n return null;\n }\n\n const sessionId = asNonEmptyString(properties.sessionID);\n const statusType = asNonEmptyString(properties.status.type);\n\n if (!sessionId || !statusType) {\n return null;\n }\n\n return {\n sessionId,\n statusType,\n };\n}\n\nfunction normalizePermissionPatterns(properties: Record<string, unknown>): string[] {\n if (Array.isArray(properties.patterns)) {\n return properties.patterns.filter((value): value is string => typeof value === \"string\");\n }\n\n if (typeof properties.pattern === \"string\" && properties.pattern.trim().length > 0) {\n return [properties.pattern];\n }\n\n if (Array.isArray(properties.pattern)) {\n return properties.pattern.filter((value): value is string => typeof value === \"string\");\n }\n\n return [];\n}\n\nfunction normalizePermissionReply(value: string | null): PermissionApprovalReply | null {\n if (value === \"once\" || value === \"always\" || value === \"reject\") {\n return value;\n }\n\n return null;\n}\n\nfunction extractSessionErrorMessage(error: unknown): string | null {\n if (error instanceof Error && error.message.trim().length > 0) {\n return error.message.trim();\n }\n\n if (!isPlainRecord(error)) {\n return null;\n }\n\n if (typeof error.message === \"string\" && error.message.trim().length > 0) {\n return error.message.trim();\n }\n\n if (isPlainRecord(error.data) && typeof error.data.message === \"string\" && error.data.message.trim().length > 0) {\n return error.data.message.trim();\n }\n\n return asNonEmptyString(error.name);\n}\n\nfunction normalizeForegroundSessionError(error: unknown): Error {\n if (error instanceof Error) {\n return error;\n }\n\n if (isPlainRecord(error)) {\n const normalized = new Error(extractSessionErrorMessage(error) ?? \"Unknown session error.\") as Error & {\n data?: Record<string, unknown>;\n };\n\n const normalizedName = asNonEmptyString(error.name);\n\n if (normalizedName) {\n normalized.name = normalizedName;\n }\n\n if (isPlainRecord(error.data)) {\n normalized.data = error.data;\n }\n\n return normalized;\n }\n\n return new Error(\"Unknown session error.\");\n}\n\nfunction asNonEmptyString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim().length > 0\n ? value.trim()\n : null;\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, any> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","export type BotLanguage = \"en\" | \"zh-CN\" | \"ja\";\n\nexport interface BotCopy {\n locale: BotLanguage;\n commands: {\n start: string;\n status: string;\n new: string;\n agents: string;\n sessions: string;\n cancel: string;\n model: string;\n language: string;\n };\n start: {\n lines: string[];\n };\n systemStatus: {\n title: string;\n };\n common: {\n notSelected: string;\n openCodeDefault: string;\n previousPage: string;\n nextPage: string;\n page(currentPage: number, totalPages: number): string;\n };\n status: {\n processing: string;\n alreadyProcessing: string;\n };\n prompt: {\n emptyResponse: string;\n };\n replyMetrics: {\n durationLabel: string;\n tokensLabel: string;\n totalLabel: string;\n inputLabel: string;\n outputLabel: string;\n reasoningLabel: string;\n cacheReadLabel: string;\n cacheWriteLabel: string;\n notAvailable: string;\n };\n abort: {\n noSession: string;\n notRunning: string;\n aborted: string;\n };\n errors: {\n unexpected: string;\n providerAuth: string;\n requestAborted: string;\n promptTimeout: string;\n structuredOutput: string;\n voiceUnsupported: string;\n imageDownload: string;\n imageUnsupported: string;\n outputLength: string;\n contextOverflow: string;\n providerRequest: string;\n notFound: string;\n badRequest: string;\n causeLabel: string;\n retryableLabel: string;\n statusCodeLabel: string;\n };\n health: {\n title: string;\n status(healthy: boolean): string;\n version(version: string): string;\n };\n path: {\n title: string;\n home(path: string): string;\n state(path: string): string;\n config(path: string): string;\n worktree(path: string): string;\n directory(path: string): string;\n };\n sessions: {\n none: string;\n title: string;\n actionTitle: string;\n chooseAction: string;\n currentProject(worktree: string): string;\n currentSession(session: string): string;\n selectedSession(session: string): string;\n switched: string;\n created: string;\n renamed: string;\n renameCancelled: string;\n renameEmpty: string;\n renameExpired: string;\n renamePendingInput: string;\n renamePrompt(session: string): string;\n switchAction: string;\n renameAction: string;\n backToList: string;\n expired: string;\n };\n lsp: {\n none: string;\n title: string;\n currentProject(worktree: string): string;\n connected: string;\n error: string;\n };\n mcp: {\n none: string;\n title: string;\n currentProject(worktree: string): string;\n connected: string;\n disabled: string;\n needsAuth: string;\n failed(error: string): string;\n needsClientRegistration(error: string): string;\n };\n agents: {\n none: string;\n title: string;\n current(agent: string): string;\n switched: string;\n expired: string;\n };\n models: {\n none: string;\n title: string;\n configuredOnly: string;\n current(model: string): string;\n switched: string;\n currentReasoningLevel(variant: string): string;\n reasoningLevel(variant: string): string;\n noReasoningLevels: string;\n reasoningLevelsTitle: string;\n model(model: string): string;\n modelNumber(modelIndex: number): string;\n expired: string;\n reasoningLevelExpired: string;\n defaultReasoningLevel: string;\n };\n language: {\n title: string;\n choose: string;\n current(label: string): string;\n switched: string;\n expired: string;\n labels: Record<BotLanguage, string>;\n };\n}\n\nexport const DEFAULT_BOT_LANGUAGE: BotLanguage = \"en\";\nexport const SUPPORTED_BOT_LANGUAGES: readonly BotLanguage[] = [\"en\", \"zh-CN\", \"ja\"];\n\nconst EN_BOT_COPY: BotCopy = {\n locale: \"en\",\n commands: {\n start: \"Show welcome and quick start\",\n status: \"Show system status\",\n new: \"Create a new session\",\n agents: \"Show and switch agents\",\n sessions: \"Show and switch sessions\",\n cancel: \"Cancel rename or abort running request\",\n model: \"Show and switch models\",\n language: \"Show and switch language\",\n },\n start: {\n lines: [\n \"# Welcome to opencode-tbot\",\n \"\",\n \"Talk to your OpenCode server from Telegram.\",\n \"\",\n \"## Quick start\",\n \"1. Run `/status` to confirm the server is ready.\",\n \"2. Run `/new [title]` to create a fresh session.\",\n \"\",\n \"Send a text or image message directly.\",\n ],\n },\n systemStatus: {\n title: \"System Status\",\n },\n common: {\n notSelected: \"Not selected\",\n openCodeDefault: \"Not selected (using OpenCode default)\",\n previousPage: \"Previous\",\n nextPage: \"Next\",\n page(currentPage: number, totalPages: number) {\n return `Page ${currentPage}/${totalPages}`;\n },\n },\n status: {\n processing: \"Processing...\",\n alreadyProcessing: \"Another request is still running. Wait for it to finish before sending a new prompt.\",\n },\n prompt: {\n emptyResponse: \"OpenCode returned empty response.\",\n },\n replyMetrics: {\n durationLabel: \"Duration\",\n tokensLabel: \"Tokens\",\n totalLabel: \"total\",\n inputLabel: \"input\",\n outputLabel: \"output\",\n reasoningLabel: \"reasoning\",\n cacheReadLabel: \"cache.read\",\n cacheWriteLabel: \"cache.write\",\n notAvailable: \"n/a\",\n },\n abort: {\n noSession: \"No active session is bound to this chat yet.\",\n notRunning: \"No request is currently running for the current session.\",\n aborted: \"Abort signal sent to the current session.\",\n },\n errors: {\n unexpected: \"Unexpected error.\",\n providerAuth: \"Provider authentication failed.\",\n requestAborted: \"Request was aborted.\",\n promptTimeout: \"OpenCode request timed out.\",\n structuredOutput: \"Structured output validation failed.\",\n voiceUnsupported: \"Voice messages are not supported. Send text or an image instead.\",\n imageDownload: \"Failed to download the Telegram image file.\",\n imageUnsupported: \"Image file is too large or unsupported.\",\n outputLength: \"Reply hit the model output limit.\",\n contextOverflow: \"Conversation exceeded the model context window.\",\n providerRequest: \"Provider request failed.\",\n notFound: \"Requested resource was not found.\",\n badRequest: \"Request was rejected by OpenCode.\",\n causeLabel: \"Cause\",\n retryableLabel: \"retryable\",\n statusCodeLabel: \"status\",\n },\n health: {\n title: \"Server Health\",\n status(healthy: boolean) {\n return `Status: ${healthy ? \"healthy\" : \"unhealthy\"}`;\n },\n version(version: string) {\n return `Version: ${version}`;\n },\n },\n path: {\n title: \"Current Paths\",\n home(path: string) {\n return `Home: ${path}`;\n },\n state(path: string) {\n return `State: ${path}`;\n },\n config(path: string) {\n return `Config: ${path}`;\n },\n worktree(path: string) {\n return `Worktree: ${path}`;\n },\n directory(path: string) {\n return `Current working directory: ${path}`;\n },\n },\n sessions: {\n none: \"No sessions available in the current project.\",\n title: \"Session List\",\n actionTitle: \"Session Actions\",\n chooseAction: \"Choose an action for this session.\",\n currentProject(worktree: string) {\n return `Current project: ${worktree}`;\n },\n currentSession(session: string) {\n return `Current session: ${session}`;\n },\n selectedSession(session: string) {\n return `Selected session: ${session}`;\n },\n switched: \"Session switched.\",\n created: \"Session created.\",\n renamed: \"Session renamed.\",\n renameCancelled: \"Session rename cancelled.\",\n renameEmpty: \"Session name cannot be empty. Send a new name or /cancel.\",\n renameExpired: \"The session is no longer available. Run /sessions again.\",\n renamePendingInput: \"Waiting for the new session name. Send plain text or /cancel.\",\n renamePrompt(session: string) {\n return [\n `Rename session: ${session}`,\n \"Send the new session name as your next text message.\",\n \"Send /cancel to cancel.\",\n ].join(\"\\n\");\n },\n switchAction: \"Switch\",\n renameAction: \"Rename\",\n backToList: \"Back to list\",\n expired: \"The session is no longer available. Run /sessions again.\",\n },\n lsp: {\n none: \"No LSP servers detected for the current project.\",\n title: \"LSP Servers\",\n currentProject(worktree: string) {\n return `Current project: ${worktree}`;\n },\n connected: \"connected\",\n error: \"error\",\n },\n mcp: {\n none: \"No MCP servers configured for the current project.\",\n title: \"MCP Servers\",\n currentProject(worktree: string) {\n return `Current project: ${worktree}`;\n },\n connected: \"connected\",\n disabled: \"disabled\",\n needsAuth: \"needs auth\",\n failed(error: string) {\n return `failed: ${error}`;\n },\n needsClientRegistration(error: string) {\n return `needs client registration: ${error}`;\n },\n },\n agents: {\n none: \"No agents available.\",\n title: \"Agent List\",\n current(agent: string) {\n return `Current agent: ${agent}`;\n },\n switched: \"Agent switched.\",\n expired: \"The agent is no longer available. Run /agents again.\",\n },\n models: {\n none: \"No models available.\",\n title: \"Model List\",\n configuredOnly: \"Only models currently available in OpenCode and connected providers are shown.\",\n current(model: string) {\n return `Current model: ${model}`;\n },\n switched: \"Model switched.\",\n currentReasoningLevel(variant: string) {\n return `Current reasoning level: ${variant}`;\n },\n reasoningLevel(variant: string) {\n return `Reasoning level: ${variant}`;\n },\n noReasoningLevels: \"This model has no selectable reasoning levels.\",\n reasoningLevelsTitle: \"Reasoning Levels\",\n model(model: string) {\n return `Model: ${model}`;\n },\n modelNumber(modelIndex: number) {\n return `Model number: ${modelIndex}`;\n },\n expired: \"The model is no longer available. Run /model again.\",\n reasoningLevelExpired: \"The reasoning level is no longer available. Run /model again.\",\n defaultReasoningLevel: \"default\",\n },\n language: {\n title: \"Language\",\n choose: \"Choose the display language for bot menus and replies.\",\n current(label: string) {\n return `Current language: ${label}`;\n },\n switched: \"Language switched.\",\n expired: \"The language option is no longer available. Run /language again.\",\n labels: {\n en: \"English\",\n \"zh-CN\": \"简体中文\",\n ja: \"日本語\",\n },\n },\n};\n\nconst ZH_CN_BOT_COPY: BotCopy = {\n locale: \"zh-CN\",\n commands: {\n start: \"查看欢迎信息与快速开始\",\n status: \"查看系统状态\",\n new: \"新建会话\",\n agents: \"查看并切换 Agent\",\n sessions: \"查看并切换会话\",\n cancel: \"取消重命名或中止当前请求\",\n model: \"查看并切换模型\",\n language: \"查看并切换语言\",\n },\n start: {\n lines: [\n \"# 欢迎使用 opencode-tbot\",\n \"\",\n \"通过 Telegram 直接和 OpenCode 服务对话。\",\n \"\",\n \"## 快速开始\",\n \"1. 先运行 `/status` 确认服务状态正常。\",\n \"2. 运行 `/new [title]` 创建一个新会话。\",\n \"\",\n \"直接发送文本或图片消息即可。\",\n ],\n },\n systemStatus: {\n title: \"系统状态\",\n },\n common: {\n notSelected: \"未选择\",\n openCodeDefault: \"未选择(使用 OpenCode 默认值)\",\n previousPage: \"上一页\",\n nextPage: \"下一页\",\n page(currentPage: number, totalPages: number) {\n return `第 ${currentPage}/${totalPages} 页`;\n },\n },\n status: {\n processing: \"处理中...\",\n alreadyProcessing: \"另一个请求仍在运行。请等待其完成后再发送新的提示词。\",\n },\n prompt: {\n emptyResponse: \"OpenCode 返回了空响应。\",\n },\n replyMetrics: {\n durationLabel: \"耗时\",\n tokensLabel: \"令牌数\",\n totalLabel: \"总计\",\n inputLabel: \"输入\",\n outputLabel: \"输出\",\n reasoningLabel: \"推理\",\n cacheReadLabel: \"缓存读取\",\n cacheWriteLabel: \"缓存写入\",\n notAvailable: \"不可用\",\n },\n abort: {\n noSession: \"当前聊天还没有绑定活动会话。\",\n notRunning: \"当前会话没有正在运行的请求。\",\n aborted: \"已向当前会话发送中止信号。\",\n },\n errors: {\n unexpected: \"发生未知错误。\",\n providerAuth: \"Provider 认证失败。\",\n requestAborted: \"请求已中止。\",\n promptTimeout: \"OpenCode 响应超时。\",\n structuredOutput: \"结构化输出校验失败。\",\n voiceUnsupported: \"暂不支持语音消息,请改发文本或图片。\",\n imageDownload: \"下载 Telegram 图片文件失败。\",\n imageUnsupported: \"图片文件过大或不受支持。\",\n outputLength: \"回复触发了模型输出长度上限。\",\n contextOverflow: \"会话已超过模型上下文窗口。\",\n providerRequest: \"Provider 请求失败。\",\n notFound: \"请求的资源不存在。\",\n badRequest: \"OpenCode 拒绝了该请求。\",\n causeLabel: \"原因\",\n retryableLabel: \"可重试\",\n statusCodeLabel: \"状态码\",\n },\n health: {\n title: \"服务健康状态\",\n status(healthy: boolean) {\n return `状态: ${healthy ? \"健康\" : \"异常\"}`;\n },\n version(version: string) {\n return `版本: ${version}`;\n },\n },\n path: {\n title: \"当前路径\",\n home(path: string) {\n return `主目录: ${path}`;\n },\n state(path: string) {\n return `状态目录: ${path}`;\n },\n config(path: string) {\n return `配置文件: ${path}`;\n },\n worktree(path: string) {\n return `工作树: ${path}`;\n },\n directory(path: string) {\n return `当前工作目录: ${path}`;\n },\n },\n sessions: {\n none: \"当前项目下没有可用会话。\",\n title: \"会话列表\",\n actionTitle: \"会话操作\",\n chooseAction: \"请选择该会话的操作。\",\n currentProject(worktree: string) {\n return `当前项目: ${worktree}`;\n },\n currentSession(session: string) {\n return `当前会话: ${session}`;\n },\n selectedSession(session: string) {\n return `已选会话: ${session}`;\n },\n switched: \"会话已切换。\",\n created: \"会话已创建。\",\n renamed: \"会话已重命名。\",\n renameCancelled: \"已取消会话重命名。\",\n renameEmpty: \"会话名称不能为空。请重新发送名称或发送 /cancel。\",\n renameExpired: \"该会话已不可用。请重新运行 /sessions。\",\n renamePendingInput: \"当前正在等待新的会话名称。请发送纯文本或 /cancel。\",\n renamePrompt(session: string) {\n return [\n `重命名会话: ${session}`,\n \"请发送新的会话名称。\",\n \"发送 /cancel 取消。\",\n ].join(\"\\n\");\n },\n switchAction: \"切换\",\n renameAction: \"重命名\",\n backToList: \"返回列表\",\n expired: \"该会话已不可用。请重新运行 /sessions。\",\n },\n lsp: {\n none: \"当前项目未检测到 LSP。\",\n title: \"LSP 服务\",\n currentProject(worktree: string) {\n return `当前项目: ${worktree}`;\n },\n connected: \"已连接\",\n error: \"异常\",\n },\n mcp: {\n none: \"当前项目未配置 MCP。\",\n title: \"MCP 服务\",\n currentProject(worktree: string) {\n return `当前项目: ${worktree}`;\n },\n connected: \"已连接\",\n disabled: \"已禁用\",\n needsAuth: \"需要认证\",\n failed(error: string) {\n return `失败: ${error}`;\n },\n needsClientRegistration(error: string) {\n return `需要客户端注册: ${error}`;\n },\n },\n agents: {\n none: \"没有可用 Agent。\",\n title: \"Agent 列表\",\n current(agent: string) {\n return `当前 Agent: ${agent}`;\n },\n switched: \"Agent 已切换。\",\n expired: \"该 Agent 已不可用。请重新运行 /agents。\",\n },\n models: {\n none: \"没有可用模型。\",\n title: \"模型列表\",\n configuredOnly: \"仅显示当前在 OpenCode 和已连接 provider 中实际可用的模型。\",\n current(model: string) {\n return `当前模型: ${model}`;\n },\n switched: \"模型已切换。\",\n currentReasoningLevel(variant: string) {\n return `当前推理级别: ${variant}`;\n },\n reasoningLevel(variant: string) {\n return `推理级别: ${variant}`;\n },\n noReasoningLevels: \"该模型没有可选的推理级别。\",\n reasoningLevelsTitle: \"推理级别\",\n model(model: string) {\n return `模型: ${model}`;\n },\n modelNumber(modelIndex: number) {\n return `模型编号: ${modelIndex}`;\n },\n expired: \"该模型已不可用。请重新运行 /model。\",\n reasoningLevelExpired: \"该推理级别已不可用。请重新运行 /model。\",\n defaultReasoningLevel: \"默认\",\n },\n language: {\n title: \"语言\",\n choose: \"选择 Bot 菜单和回复的显示语言。\",\n current(label: string) {\n return `当前语言: ${label}`;\n },\n switched: \"语言已切换。\",\n expired: \"该语言选项已不可用。请重新运行 /language。\",\n labels: {\n en: \"English\",\n \"zh-CN\": \"简体中文\",\n ja: \"日本語\",\n },\n },\n};\n\nconst JA_BOT_COPY: BotCopy = {\n locale: \"ja\",\n commands: {\n start: \"ようこそとクイックスタートを表示\",\n status: \"システム状態を表示\",\n new: \"新しいセッションを作成\",\n agents: \"エージェントを表示して切り替え\",\n sessions: \"セッションを表示して切り替え\",\n cancel: \"名前変更を取り消すか実行中のリクエストを中止\",\n model: \"モデルを表示して切り替え\",\n language: \"言語を表示して切り替え\",\n },\n start: {\n lines: [\n \"# opencode-tbot へようこそ\",\n \"\",\n \"Telegram から OpenCode サーバーとやり取りできます。\",\n \"\",\n \"## クイックスタート\",\n \"1. `/status` を実行してサーバーの準備完了を確認します。\",\n \"2. `/new [title]` を実行して新しいセッションを作成します。\",\n \"\",\n \"そのままテキストまたは画像メッセージを送信できます。\",\n ],\n },\n systemStatus: {\n title: \"システム状態\",\n },\n common: {\n notSelected: \"未選択\",\n openCodeDefault: \"未選択(OpenCode のデフォルトを使用)\",\n previousPage: \"前へ\",\n nextPage: \"次へ\",\n page(currentPage: number, totalPages: number) {\n return `ページ ${currentPage}/${totalPages}`;\n },\n },\n status: {\n processing: \"処理中...\",\n alreadyProcessing: \"別のリクエストがまだ実行中です。完了するまで新しいプロンプトを送信しないでください。\",\n },\n prompt: {\n emptyResponse: \"OpenCode から空の応答が返されました。\",\n },\n replyMetrics: {\n durationLabel: \"所要時間\",\n tokensLabel: \"トークン\",\n totalLabel: \"合計\",\n inputLabel: \"入力\",\n outputLabel: \"出力\",\n reasoningLabel: \"推論\",\n cacheReadLabel: \"キャッシュ読込\",\n cacheWriteLabel: \"キャッシュ書込\",\n notAvailable: \"該当なし\",\n },\n abort: {\n noSession: \"このチャットにはまだアクティブなセッションが紐付いていません。\",\n notRunning: \"現在のセッションで実行中のリクエストはありません。\",\n aborted: \"現在のセッションに中止シグナルを送信しました。\",\n },\n errors: {\n unexpected: \"予期しないエラーが発生しました。\",\n providerAuth: \"Provider の認証に失敗しました。\",\n requestAborted: \"リクエストは中止されました。\",\n promptTimeout: \"OpenCode リクエストがタイムアウトしました。\",\n structuredOutput: \"構造化出力の検証に失敗しました。\",\n voiceUnsupported: \"音声メッセージには対応していません。代わりにテキストまたは画像を送信してください。\",\n imageDownload: \"Telegram の画像ファイルをダウンロードできませんでした。\",\n imageUnsupported: \"画像ファイルが大きすぎるか、サポートされていません。\",\n outputLength: \"返信がモデルの出力上限に達しました。\",\n contextOverflow: \"会話がモデルのコンテキスト上限を超えました。\",\n providerRequest: \"Provider へのリクエストに失敗しました。\",\n notFound: \"要求されたリソースが見つかりませんでした。\",\n badRequest: \"リクエストは OpenCode に拒否されました。\",\n causeLabel: \"原因\",\n retryableLabel: \"再試行可能\",\n statusCodeLabel: \"ステータス\",\n },\n health: {\n title: \"サーバー状態\",\n status(healthy: boolean) {\n return `状態: ${healthy ? \"正常\" : \"異常\"}`;\n },\n version(version: string) {\n return `バージョン: ${version}`;\n },\n },\n path: {\n title: \"現在のパス\",\n home(path: string) {\n return `ホーム: ${path}`;\n },\n state(path: string) {\n return `状態: ${path}`;\n },\n config(path: string) {\n return `設定: ${path}`;\n },\n worktree(path: string) {\n return `ワークツリー: ${path}`;\n },\n directory(path: string) {\n return `現在の作業ディレクトリ: ${path}`;\n },\n },\n sessions: {\n none: \"現在のプロジェクトで利用できるセッションはありません。\",\n title: \"セッション一覧\",\n actionTitle: \"セッション操作\",\n chooseAction: \"このセッションに対する操作を選択してください。\",\n currentProject(worktree: string) {\n return `現在のプロジェクト: ${worktree}`;\n },\n currentSession(session: string) {\n return `現在のセッション: ${session}`;\n },\n selectedSession(session: string) {\n return `選択中のセッション: ${session}`;\n },\n switched: \"セッションを切り替えました。\",\n created: \"セッションを作成しました。\",\n renamed: \"セッション名を変更しました。\",\n renameCancelled: \"セッション名の変更を取り消しました。\",\n renameEmpty: \"セッション名は空にできません。新しい名前を送信するか /cancel を実行してください。\",\n renameExpired: \"このセッションはもう利用できません。/sessions を再実行してください。\",\n renamePendingInput: \"新しいセッション名の入力待ちです。プレーンテキストを送るか /cancel を実行してください。\",\n renamePrompt(session: string) {\n return [\n `セッション名を変更: ${session}`,\n \"次のテキストメッセージで新しいセッション名を送信してください。\",\n \"/cancel で取り消します。\",\n ].join(\"\\n\");\n },\n switchAction: \"切り替え\",\n renameAction: \"名前変更\",\n backToList: \"一覧に戻る\",\n expired: \"このセッションはもう利用できません。/sessions を再実行してください。\",\n },\n lsp: {\n none: \"現在のプロジェクトで LSP サーバーは検出されませんでした。\",\n title: \"LSP サーバー\",\n currentProject(worktree: string) {\n return `現在のプロジェクト: ${worktree}`;\n },\n connected: \"接続済み\",\n error: \"エラー\",\n },\n mcp: {\n none: \"現在のプロジェクトで MCP サーバーは設定されていません。\",\n title: \"MCP サーバー\",\n currentProject(worktree: string) {\n return `現在のプロジェクト: ${worktree}`;\n },\n connected: \"接続済み\",\n disabled: \"無効\",\n needsAuth: \"認証が必要\",\n failed(error: string) {\n return `失敗: ${error}`;\n },\n needsClientRegistration(error: string) {\n return `クライアント登録が必要: ${error}`;\n },\n },\n agents: {\n none: \"利用可能なエージェントはありません。\",\n title: \"エージェント一覧\",\n current(agent: string) {\n return `現在のエージェント: ${agent}`;\n },\n switched: \"エージェントを切り替えました。\",\n expired: \"このエージェントはもう利用できません。/agents を再実行してください。\",\n },\n models: {\n none: \"利用可能なモデルはありません。\",\n title: \"モデル一覧\",\n configuredOnly: \"OpenCode と接続済み provider で現在利用可能なモデルのみ表示します。\",\n current(model: string) {\n return `現在のモデル: ${model}`;\n },\n switched: \"モデルを切り替えました。\",\n currentReasoningLevel(variant: string) {\n return `現在の推論レベル: ${variant}`;\n },\n reasoningLevel(variant: string) {\n return `推論レベル: ${variant}`;\n },\n noReasoningLevels: \"このモデルには選択可能な推論レベルがありません。\",\n reasoningLevelsTitle: \"推論レベル\",\n model(model: string) {\n return `モデル: ${model}`;\n },\n modelNumber(modelIndex: number) {\n return `モデル番号: ${modelIndex}`;\n },\n expired: \"このモデルはもう利用できません。/model を再実行してください。\",\n reasoningLevelExpired: \"この推論レベルはもう利用できません。/model を再実行してください。\",\n defaultReasoningLevel: \"デフォルト\",\n },\n language: {\n title: \"言語\",\n choose: \"Bot のメニューと返信に使う表示言語を選択してください。\",\n current(label: string) {\n return `現在の言語: ${label}`;\n },\n switched: \"言語を切り替えました。\",\n expired: \"この言語オプションはもう利用できません。/language を再実行してください。\",\n labels: {\n en: \"English\",\n \"zh-CN\": \"简体中文\",\n ja: \"日本語\",\n },\n },\n};\n\nexport const BOT_COPY = EN_BOT_COPY;\n\nexport function isBotLanguage(value: string): value is BotLanguage {\n return SUPPORTED_BOT_LANGUAGES.includes(value as BotLanguage);\n}\n\nexport function normalizeBotLanguage(value: string | null | undefined): BotLanguage {\n if (!value) {\n return DEFAULT_BOT_LANGUAGE;\n }\n\n const normalized = value.trim().toLowerCase();\n\n if (normalized === \"zh-cn\" || normalized === \"zh-hans\" || normalized === \"zh\") {\n return \"zh-CN\";\n }\n\n if (normalized === \"ja\" || normalized === \"ja-jp\" || normalized === \"ja_jp\") {\n return \"ja\";\n }\n\n return \"en\";\n}\n\nexport function getBotCopy(language: BotLanguage | null | undefined = DEFAULT_BOT_LANGUAGE): BotCopy {\n const normalized = normalizeBotLanguage(language);\n\n if (normalized === \"zh-CN\") {\n return ZH_CN_BOT_COPY;\n }\n\n if (normalized === \"ja\") {\n return JA_BOT_COPY;\n }\n\n return EN_BOT_COPY;\n}\n\nexport function getLanguageLabel(language: BotLanguage, copy: BotCopy = BOT_COPY): string {\n return copy.language.labels[language];\n}\n","import type { BotCommand } from \"grammy/types\";\nimport { getBotCopy, type BotLanguage } from \"../copy.js\";\n\nexport function getTelegramCommands(language: BotLanguage = \"en\"): BotCommand[] {\n const copy = getBotCopy(language);\n\n return [\n {\n command: \"start\",\n description: copy.commands.start,\n },\n {\n command: \"status\",\n description: copy.commands.status,\n },\n {\n command: \"new\",\n description: copy.commands.new,\n },\n {\n command: \"agents\",\n description: copy.commands.agents,\n },\n {\n command: \"sessions\",\n description: copy.commands.sessions,\n },\n {\n command: \"cancel\",\n description: copy.commands.cancel,\n },\n {\n command: \"model\",\n description: copy.commands.model,\n },\n {\n command: \"language\",\n description: copy.commands.language,\n },\n ];\n}\n\nexport const TELEGRAM_COMMANDS: BotCommand[] = getTelegramCommands();\n","import type { Bot } from \"grammy\";\nimport type { BotCommandScope } from \"grammy/types\";\nimport type { AppLogger } from \"../../infra/logger/index.js\";\nimport { type BotLanguage } from \"../copy.js\";\nimport { getTelegramCommands, TELEGRAM_COMMANDS } from \"./command-list.js\";\n\nexport const TELEGRAM_COMMAND_SYNC_SCOPES: ReadonlyArray<BotCommandScope> = [\n { type: \"default\" },\n { type: \"all_private_chats\" },\n];\n\nexport async function syncTelegramCommands(bot: Bot, logger: AppLogger): Promise<void> {\n await Promise.all(\n TELEGRAM_COMMAND_SYNC_SCOPES.map((scope) =>\n bot.api.setMyCommands(TELEGRAM_COMMANDS, { scope }),\n ),\n );\n\n logger.info(\n {\n component: \"runtime\",\n commands: TELEGRAM_COMMANDS.map((command) => command.command),\n event: \"runtime.commands.synced\",\n scopes: TELEGRAM_COMMAND_SYNC_SCOPES.map((scope) => scope.type),\n },\n \"telegram commands synced\",\n );\n}\n\nexport async function syncTelegramCommandsForChat(\n api: Pick<Bot[\"api\"], \"setMyCommands\">,\n chatId: number,\n language: BotLanguage,\n): Promise<void> {\n await api.setMyCommands(\n getTelegramCommands(language),\n {\n scope: {\n type: \"chat\",\n chat_id: chatId,\n },\n },\n );\n}\n","import type { AppLogger, LogComponent, LoggerContext } from \"../infra/logger/index.js\";\nimport type { BotDependencies } from \"./types.js\";\n\ninterface TelegramLogContextLike {\n callbackQuery?: { data?: string | null };\n chat?: { id?: number };\n message?: { text?: string | null };\n msg?: { text?: string | null } | null;\n update?: { update_id?: number };\n}\n\nexport function buildTelegramLoggerContext(\n ctx: TelegramLogContextLike,\n component: LogComponent = \"telegram\",\n): LoggerContext {\n const updateId = typeof ctx.update?.update_id === \"number\"\n ? ctx.update.update_id\n : undefined;\n const messageText = resolveMessageText(ctx);\n const command = extractTelegramCommand(messageText);\n const callbackData = normalizeTelegramString(ctx.callbackQuery?.data);\n const operationId = typeof updateId === \"number\"\n ? `telegram-${updateId}`\n : null;\n\n return {\n component,\n ...(typeof ctx.chat?.id === \"number\" ? { chatId: ctx.chat.id } : {}),\n ...(typeof updateId === \"number\" ? { updateId } : {}),\n ...(command ? { command } : {}),\n ...(callbackData ? { callbackData } : {}),\n correlationId: typeof updateId === \"number\"\n ? String(updateId)\n : operationId,\n operationId,\n };\n}\n\nexport function scopeLoggerToTelegramContext(\n logger: AppLogger,\n ctx: TelegramLogContextLike,\n component: LogComponent = \"telegram\",\n): AppLogger {\n return logger.child(buildTelegramLoggerContext(ctx, component));\n}\n\nexport function scopeDependenciesToTelegramContext<TDependencies extends BotDependencies>(\n dependencies: TDependencies,\n ctx: TelegramLogContextLike,\n component: LogComponent = \"telegram\",\n): TDependencies {\n return {\n ...dependencies,\n logger: scopeLoggerToTelegramContext(dependencies.logger, ctx, component),\n };\n}\n\nfunction resolveMessageText(ctx: TelegramLogContextLike): string | null {\n return normalizeTelegramString(ctx.message?.text)\n ?? normalizeTelegramString(ctx.msg?.text);\n}\n\nfunction extractTelegramCommand(value: string | null): string | null {\n if (!value || !value.startsWith(\"/\")) {\n return null;\n }\n\n const token = value.split(/\\s+/u, 1)[0]?.trim();\n\n if (!token) {\n return null;\n }\n\n return token.replace(/^\\/+/u, \"\").split(\"@\", 1)[0] ?? null;\n}\n\nfunction normalizeTelegramString(value: string | null | undefined): string | null {\n return typeof value === \"string\" && value.trim().length > 0\n ? value.trim()\n : null;\n}\n","import { BOT_COPY, type BotCopy } from \"../copy.js\";\n\ninterface PresentedError {\n cause: string | null;\n message: string;\n}\n\nexport function presentError(error: unknown, copy: BotCopy = BOT_COPY): string {\n const presented = normalizeError(error, copy);\n\n return presented.cause\n ? `${presented.message}\\n${copy.errors.causeLabel}: ${presented.cause}`\n : presented.message;\n}\n\nfunction normalizeError(error: unknown, copy: BotCopy): PresentedError {\n if (isNamedError(error, \"ProviderAuthError\")) {\n return {\n message: copy.errors.providerAuth,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"MessageAbortedError\")) {\n return {\n message: copy.errors.requestAborted,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"OpenCodePromptTimeoutError\")) {\n return {\n message: copy.errors.promptTimeout,\n cause: null,\n };\n }\n\n if (isNamedError(error, \"StructuredOutputError\")) {\n return {\n message: copy.errors.structuredOutput,\n cause: joinNonEmptyParts([\n extractMessage(error.data),\n extractRetries(error.data),\n ]),\n };\n }\n\n if (isNamedError(error, \"ImageFileDownloadError\")) {\n return {\n message: copy.errors.imageDownload,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"ImageMessageUnsupportedError\")) {\n return {\n message: copy.errors.imageUnsupported,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"MessageOutputLengthError\")) {\n return {\n message: copy.errors.outputLength,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"ContextOverflowError\")) {\n return {\n message: copy.errors.contextOverflow,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isNamedError(error, \"APIError\")) {\n const providerMessage = extractMessage(error.data);\n\n return {\n message: copy.errors.providerRequest,\n cause: joinNonEmptyParts([\n getProviderCompatibilityHint(providerMessage),\n providerMessage,\n extractStatusCode(error.data, copy),\n extractRetryable(error.data, copy),\n ]),\n };\n }\n\n if (isNamedError(error, \"NotFoundError\")) {\n return {\n message: copy.errors.notFound,\n cause: extractMessage(error.data) ?? null,\n };\n }\n\n if (isBadRequestError(error)) {\n return {\n message: copy.errors.badRequest,\n cause: extractBadRequestCause(error),\n };\n }\n\n if (error instanceof Error) {\n return {\n message: error.name === \"AbortError\" ? copy.errors.requestAborted : copy.errors.unexpected,\n cause: error.message || null,\n };\n }\n\n return {\n message: copy.errors.unexpected,\n cause: extractMessage(error) ?? stringifyUnknown(error),\n };\n}\n\nfunction getProviderCompatibilityHint(message: string | null): string | null {\n if (!message) {\n return null;\n }\n\n return /tool_choice parameter does not support being set to required or object in thinking mode/iu.test(message)\n ? \"Current model/reasoning mode is incompatible with tool calling. Switch to a compatible model or disable thinking mode.\"\n : null;\n}\n\nfunction isBadRequestError(error: unknown): error is { data?: unknown; errors?: unknown[]; success: false } {\n return !!error\n && typeof error === \"object\"\n && \"success\" in error\n && (error as { success?: unknown }).success === false;\n}\n\nfunction isNamedError<TName extends string>(\n error: unknown,\n name: TName,\n): error is { data?: unknown; name: TName } {\n return !!error\n && typeof error === \"object\"\n && \"name\" in error\n && (error as { name?: unknown }).name === name;\n}\n\nfunction extractBadRequestCause(error: { data?: unknown; errors?: unknown[] }): string | null {\n const directMessage = extractMessage(error.data);\n\n if (directMessage) {\n return directMessage;\n }\n\n const firstValidationError = Array.isArray(error.errors) && error.errors.length > 0\n ? stringifyUnknown(error.errors[0])\n : null;\n\n return firstValidationError;\n}\n\nfunction extractMessage(value: unknown): string | null {\n if (!value) {\n return null;\n }\n\n if (typeof value === \"string\") {\n return value.trim() || null;\n }\n\n if (typeof value === \"object\" && \"message\" in value) {\n const message = (value as { message?: unknown }).message;\n\n return typeof message === \"string\" && message.trim().length > 0\n ? message.trim()\n : null;\n }\n\n return null;\n}\n\nfunction extractRetries(value: unknown): string | null {\n if (!value || typeof value !== \"object\" || !(\"retries\" in value)) {\n return null;\n }\n\n const retries = (value as { retries?: unknown }).retries;\n\n return typeof retries === \"number\" && Number.isFinite(retries)\n ? `retries: ${Math.round(retries)}`\n : null;\n}\n\nfunction extractRetryable(value: unknown, copy: BotCopy): string | null {\n if (!value || typeof value !== \"object\" || !(\"isRetryable\" in value)) {\n return null;\n }\n\n const isRetryable = (value as { isRetryable?: unknown }).isRetryable;\n\n return typeof isRetryable === \"boolean\"\n ? `${copy.errors.retryableLabel}: ${isRetryable ? \"yes\" : \"no\"}`\n : null;\n}\n\nfunction extractStatusCode(value: unknown, copy: BotCopy): string | null {\n if (!value || typeof value !== \"object\" || !(\"statusCode\" in value)) {\n return null;\n }\n\n const statusCode = (value as { statusCode?: unknown }).statusCode;\n\n return typeof statusCode === \"number\" && Number.isFinite(statusCode)\n ? `${copy.errors.statusCodeLabel}: ${Math.round(statusCode)}`\n : null;\n}\n\nfunction joinNonEmptyParts(parts: Array<string | null | undefined>): string | null {\n const filtered = parts\n .map((part) => part?.trim())\n .filter((part): part is string => !!part);\n\n return filtered.length > 0 ? filtered.join(\" | \") : null;\n}\n\nfunction stringifyUnknown(value: unknown): string | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === \"string\") {\n return value.trim() || null;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n try {\n const text = JSON.stringify(value);\n\n return text && text !== \"{}\" ? text : null;\n } catch {\n return null;\n }\n}\n","import type { AppLogger } from \"../infra/logger/index.js\";\nimport { buildTelegramLoggerContext } from \"./logger-context.js\";\nimport { BOT_COPY } from \"./copy.js\";\nimport { presentError } from \"./presenters/error.presenter.js\";\n\nexport function extractTelegramUpdateContext(\n ctx: object,\n): {\n callbackData?: string;\n chatId?: number;\n command?: string;\n correlationId?: string | null;\n operationId?: string | null;\n updateId?: number;\n} {\n return buildTelegramLoggerContext({\n callbackQuery: {\n data: getNestedString(ctx, [\"callbackQuery\", \"data\"]),\n },\n chat: {\n id: getNestedNumber(ctx, [\"chat\", \"id\"]) ?? undefined,\n },\n message: {\n text: getNestedString(ctx, [\"message\", \"text\"]),\n },\n update: {\n update_id: getNestedNumber(ctx, [\"update\", \"update_id\"]) ?? undefined,\n },\n });\n}\n\nexport async function replyWithDefaultTelegramError(\n ctx: object,\n logger: AppLogger,\n error: unknown,\n): Promise<void> {\n const text = presentError(error, BOT_COPY);\n const editMessageText = getFunction(ctx, \"editMessageText\");\n const reply = getFunction(ctx, \"reply\");\n const callbackData = getNestedString(ctx, [\"callbackQuery\", \"data\"]);\n\n try {\n if (typeof callbackData === \"string\" && editMessageText) {\n await editMessageText.call(ctx, text);\n return;\n }\n\n if (reply) {\n await reply.call(ctx, text);\n }\n } catch (replyError) {\n logger.warn?.(\n {\n ...extractTelegramUpdateContext(ctx),\n error: replyError,\n },\n \"failed to deliver fallback Telegram error message\",\n );\n }\n}\n\nfunction getFunction(value: object, key: string): ((...args: unknown[]) => Promise<unknown>) | null {\n if (!(key in value)) {\n return null;\n }\n\n const candidate = (value as Record<string, unknown>)[key];\n\n return typeof candidate === \"function\"\n ? candidate as (...args: unknown[]) => Promise<unknown>\n : null;\n}\n\nfunction getNestedNumber(value: object, path: string[]): number | null {\n const candidate = getNestedValue(value, path);\n\n return typeof candidate === \"number\" ? candidate : null;\n}\n\nfunction getNestedString(value: object, path: string[]): string | null {\n const candidate = getNestedValue(value, path);\n\n return typeof candidate === \"string\" ? candidate : null;\n}\n\nfunction getNestedValue(value: object, path: string[]): unknown {\n let current: unknown = value;\n\n for (const segment of path) {\n if (!current || typeof current !== \"object\" || !(segment in current)) {\n return null;\n }\n\n current = (current as Record<string, unknown>)[segment];\n }\n\n return current;\n}\n","import type { SessionRepository } from \"../domain/session/session.repository.js\";\nimport type { AppLogger } from \"../infra/logger/index.js\";\nimport {\n BOT_COPY,\n DEFAULT_BOT_LANGUAGE,\n getBotCopy,\n normalizeBotLanguage,\n type BotCopy,\n type BotLanguage,\n} from \"./copy.js\";\n\nexport async function getChatLanguage(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n): Promise<BotLanguage> {\n if (!chatId) {\n return DEFAULT_BOT_LANGUAGE;\n }\n\n const binding = await sessionRepo.getByChatId(chatId);\n\n return normalizeBotLanguage(binding?.language);\n}\n\nexport async function getChatCopy(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n): Promise<BotCopy> {\n return getBotCopy(await getChatLanguage(sessionRepo, chatId));\n}\n\nexport async function getSafeChatLanguage(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n logger?: Pick<AppLogger, \"warn\">,\n): Promise<BotLanguage> {\n try {\n return await getChatLanguage(sessionRepo, chatId);\n } catch (error) {\n logger?.warn?.(\n {\n error,\n chatId: chatId ?? undefined,\n },\n \"failed to resolve Telegram chat language; falling back to the default locale\",\n );\n return DEFAULT_BOT_LANGUAGE;\n }\n}\n\nexport async function getSafeChatCopy(\n sessionRepo: SessionRepository,\n chatId: number | null | undefined,\n logger?: Pick<AppLogger, \"warn\">,\n): Promise<BotCopy> {\n try {\n return getBotCopy(await getSafeChatLanguage(sessionRepo, chatId, logger));\n } catch (error) {\n logger?.warn?.(\n {\n error,\n chatId: chatId ?? undefined,\n },\n \"failed to resolve Telegram copy; falling back to the default locale\",\n );\n return BOT_COPY;\n }\n}\n\nexport async function setChatLanguage(\n sessionRepo: SessionRepository,\n chatId: number,\n language: BotLanguage,\n): Promise<void> {\n const binding = await sessionRepo.getByChatId(chatId);\n\n await sessionRepo.setCurrent({\n chatId,\n sessionId: binding?.sessionId ?? null,\n projectId: binding?.projectId ?? null,\n directory: binding?.directory ?? null,\n agentName: binding?.agentName ?? null,\n modelProviderId: binding?.modelProviderId ?? null,\n modelId: binding?.modelId ?? null,\n modelVariant: binding?.modelVariant ?? null,\n language,\n updatedAt: new Date().toISOString(),\n });\n}\n","import { InlineKeyboard } from \"grammy\";\nimport {\n BOT_COPY,\n getLanguageLabel,\n SUPPORTED_BOT_LANGUAGES,\n type BotCopy,\n type BotLanguage,\n} from \"../copy.js\";\nimport type {\n OpenCodeAgent,\n OpenCodeConfiguredModel,\n OpenCodeSession,\n} from \"../../services/opencode/opencode.client.js\";\n\nexport const MODELS_PAGE_SIZE = 10;\nexport const AGENTS_PAGE_SIZE = 10;\nexport const SESSIONS_PAGE_SIZE = 10;\nconst NUMBERED_BUTTONS_PER_ROW = 5;\n\nexport interface ModelsPage {\n items: OpenCodeConfiguredModel[];\n page: number;\n startIndex: number;\n totalPages: number;\n}\n\nexport interface AgentsPage {\n items: OpenCodeAgent[];\n page: number;\n startIndex: number;\n totalPages: number;\n}\n\nexport interface SessionsPage {\n items: OpenCodeSession[];\n page: number;\n startIndex: number;\n totalPages: number;\n}\n\nexport function buildModelsKeyboard(\n models: OpenCodeConfiguredModel[],\n requestedPage: number,\n copy: BotCopy = BOT_COPY,\n) {\n const page = getModelsPage(models, requestedPage);\n const keyboard = buildNumberedKeyboard(\n page.items,\n page.startIndex,\n (_, index) => `model:pick:${page.startIndex + index + 1}`,\n );\n\n appendPaginationButtons(keyboard, page.page, page.totalPages, \"model:page\", copy);\n\n return { keyboard, page };\n}\n\nexport function buildAgentsKeyboard(\n agents: OpenCodeAgent[],\n requestedPage: number,\n copy: BotCopy = BOT_COPY,\n) {\n const page = getAgentsPage(agents, requestedPage);\n const keyboard = buildNumberedKeyboard(\n page.items,\n page.startIndex,\n (_, index) => `agents:select:${page.startIndex + index + 1}`,\n );\n\n appendPaginationButtons(keyboard, page.page, page.totalPages, \"agents:page\", copy);\n\n return { keyboard, page };\n}\n\nexport function buildSessionsKeyboard(\n sessions: OpenCodeSession[],\n requestedPage: number,\n copy: BotCopy = BOT_COPY,\n) {\n const page = getSessionsPage(sessions, requestedPage);\n const keyboard = buildNumberedKeyboard(\n page.items,\n page.startIndex,\n (session) => `sessions:pick:${page.page}:${session.id}`,\n );\n\n appendPaginationButtons(keyboard, page.page, page.totalPages, \"sessions:page\", copy);\n\n return { keyboard, page };\n}\n\nexport function buildSessionActionKeyboard(\n sessionId: string,\n page: number,\n copy: BotCopy = BOT_COPY,\n) {\n return new InlineKeyboard()\n .text(copy.sessions.switchAction, `sessions:switch:${page}:${sessionId}`)\n .text(copy.sessions.renameAction, `sessions:rename:${page}:${sessionId}`)\n .row()\n .text(copy.sessions.backToList, `sessions:back:${page}`);\n}\n\nexport function buildModelVariantsKeyboard(variants: string[], modelIndex: number) {\n return buildNumberedKeyboard(\n variants,\n 0,\n (_, index) => `model:variant:${modelIndex}:${index + 1}`,\n );\n}\n\nexport function buildLanguageKeyboard(currentLanguage: BotLanguage, copy: BotCopy = BOT_COPY) {\n const keyboard = new InlineKeyboard();\n\n SUPPORTED_BOT_LANGUAGES.forEach((language, index) => {\n const label = currentLanguage === language\n ? `[${getLanguageLabel(language, copy)}]`\n : getLanguageLabel(language, copy);\n\n keyboard.text(label, `language:select:${language}`);\n\n if (index !== SUPPORTED_BOT_LANGUAGES.length - 1) {\n keyboard.row();\n }\n });\n\n return keyboard;\n}\n\nexport function getModelsPage(models: OpenCodeConfiguredModel[], requestedPage: number): ModelsPage {\n return getPagedItems(models, requestedPage, MODELS_PAGE_SIZE);\n}\n\nexport function getAgentsPage(agents: OpenCodeAgent[], requestedPage: number): AgentsPage {\n return getPagedItems(agents, requestedPage, AGENTS_PAGE_SIZE);\n}\n\nexport function getSessionsPage(sessions: OpenCodeSession[], requestedPage: number): SessionsPage {\n return getPagedItems(sessions, requestedPage, SESSIONS_PAGE_SIZE);\n}\n\nfunction buildNumberedKeyboard<T>(\n items: T[],\n startIndex: number,\n buildCallbackData: (item: T, index: number) => string,\n) {\n const keyboard = new InlineKeyboard();\n\n items.forEach((item, index) => {\n const displayIndex = startIndex + index + 1;\n\n keyboard.text(`${displayIndex}`, buildCallbackData(item, index));\n\n if (\n index !== items.length - 1\n && (index + 1) % NUMBERED_BUTTONS_PER_ROW === 0\n ) {\n keyboard.row();\n }\n });\n\n return keyboard;\n}\n\nfunction appendPaginationButtons(\n keyboard: InlineKeyboard,\n page: number,\n totalPages: number,\n prefix: \"agents:page\" | \"sessions:page\" | \"model:page\",\n copy: BotCopy,\n) {\n if (totalPages <= 1) {\n return;\n }\n\n if (page > 0) {\n keyboard.text(copy.common.previousPage, `${prefix}:${page - 1}`);\n }\n\n if (page < totalPages - 1) {\n keyboard.text(copy.common.nextPage, `${prefix}:${page + 1}`);\n }\n}\n\nfunction getPagedItems<T>(items: T[], requestedPage: number, pageSize: number) {\n const totalPages = Math.max(1, Math.ceil(items.length / pageSize));\n const page = clampPage(requestedPage, totalPages);\n const startIndex = page * pageSize;\n\n return {\n items: items.slice(startIndex, startIndex + pageSize),\n page,\n startIndex,\n totalPages,\n };\n}\n\nfunction clampPage(page: number, totalPages: number): number {\n if (!Number.isInteger(page) || page < 0) {\n return 0;\n }\n\n return Math.min(page, totalPages - 1);\n}\n","import type {\n OpenCodeAgent,\n OpenCodeConfiguredModel,\n OpenCodeHealth,\n OpenCodeLspStatus,\n OpenCodeMcpStatus,\n OpenCodePath,\n OpenCodeSession,\n} from \"../../services/opencode/opencode.client.js\";\nimport { OPENCODE_TBOT_VERSION } from \"../../app/package-info.js\";\nimport type { GetStatusResult } from \"../../use-cases/get-status.usecase.js\";\nimport {\n BOT_COPY,\n getLanguageLabel,\n type BotCopy,\n type BotLanguage,\n} from \"../copy.js\";\nimport { presentError } from \"./error.presenter.js\";\nimport {\n getAgentsPage,\n getModelsPage,\n getSessionsPage,\n} from \"./keyboard.presenter.js\";\n\ninterface ModelsMessageInput {\n currentModelId: string | null;\n currentModelProviderId: string | null;\n currentModelVariant: string | null;\n models: OpenCodeConfiguredModel[];\n page: number;\n}\n\ninterface AgentsMessageInput {\n agents: OpenCodeAgent[];\n currentAgentName: string | null;\n page: number;\n}\n\ninterface SessionsMessageInput {\n currentDirectory: string;\n currentSessionId: string | null;\n page: number;\n sessions: OpenCodeSession[];\n}\n\ninterface McpMessageInput {\n currentDirectory: string;\n statuses: Array<{\n name: string;\n status: OpenCodeMcpStatus;\n }>;\n}\n\ninterface LspMessageInput {\n currentDirectory: string;\n statuses: OpenCodeLspStatus[];\n}\n\ninterface StatusLayoutCopy {\n connectivityLabel: string;\n currentProjectLabel: string;\n currentSessionLabel: string;\n defaultSessionValue: string;\n detailsLabel: string;\n errorStatus: string;\n lspTitle: string;\n mcpFailedStatus: string;\n mcpNotesLabel: string;\n mcpRegistrationRequiredStatus: string;\n mcpTitle: string;\n noPluginsMessage: string;\n noneStatus: string;\n openCodeVersionLabel: string;\n overviewTitle: string;\n pluginsTitle: string;\n statusLabel: string;\n tbotVersionLabel: string;\n workspaceTitle: string;\n}\n\ninterface StatusDetailLine {\n codeValue?: boolean;\n label: string;\n value: string;\n}\n\nconst VARIANT_ORDER = [\"minimal\", \"none\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\nexport function presentHealthMessage(health: OpenCodeHealth, copy: BotCopy = BOT_COPY): string {\n return [\n copy.health.title,\n copy.health.status(health.healthy),\n copy.health.version(health.version),\n ].join(\"\\n\");\n}\n\nexport function presentPathMessage(path: OpenCodePath, copy: BotCopy = BOT_COPY): string {\n return copy.path.directory(path.directory);\n}\n\nexport function presentStatusMessage(input: GetStatusResult, copy: BotCopy = BOT_COPY): string {\n const layout = getStatusLayoutCopy(copy);\n const sections = [\n presentStatusPlainSection(layout.overviewTitle, presentStatusPlainOverviewLines(input, copy, layout)),\n presentStatusPlainSection(layout.workspaceTitle, presentStatusPlainWorkspaceLines(input, copy, layout)),\n presentStatusPlainSection(layout.pluginsTitle, presentStatusPlainPluginLines(input, copy, layout)),\n presentStatusPlainSection(layout.mcpTitle, presentStatusPlainMcpLines(input, copy, layout)),\n presentStatusPlainSection(layout.lspTitle, presentStatusPlainLspLines(input, copy, layout)),\n ];\n\n return presentStatusSections(sections);\n}\n\nexport function presentStatusMarkdownMessage(input: GetStatusResult, copy: BotCopy = BOT_COPY): string {\n const layout = getStatusLayoutCopy(copy);\n const sections = [\n presentStatusMarkdownSection(layout.overviewTitle, presentStatusMarkdownOverviewLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.workspaceTitle, presentStatusMarkdownWorkspaceLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.pluginsTitle, presentStatusMarkdownPluginLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.mcpTitle, presentStatusMarkdownMcpLines(input, copy, layout)),\n presentStatusMarkdownSection(layout.lspTitle, presentStatusMarkdownLspLines(input, copy, layout)),\n ];\n\n return presentStatusSections(sections);\n}\n\nexport function presentMcpMessage(input: McpMessageInput, copy: BotCopy = BOT_COPY): string {\n const lines = [\n copy.mcp.title,\n copy.mcp.currentProject(input.currentDirectory),\n \"\",\n ];\n\n if (input.statuses.length === 0) {\n lines.push(copy.mcp.none);\n return lines.join(\"\\n\");\n }\n\n lines.push(...input.statuses.map(({ name, status }) => `${name}: ${formatMcpStatus(status, copy)}`));\n\n return lines.join(\"\\n\");\n}\n\nexport function presentLspMessage(input: LspMessageInput, copy: BotCopy = BOT_COPY): string {\n const lines = [\n copy.lsp.title,\n copy.lsp.currentProject(input.currentDirectory),\n \"\",\n ];\n\n if (input.statuses.length === 0) {\n lines.push(copy.lsp.none);\n return lines.join(\"\\n\");\n }\n\n lines.push(...input.statuses.map((status) => `${status.name}: ${formatLspStatus(status, copy)}`));\n\n return lines.join(\"\\n\");\n}\n\nfunction presentStatusSections(sections: string[]): string {\n return sections.flatMap((section, index) => index === 0 ? [section] : [\"\", section]).join(\"\\n\");\n}\n\nfunction presentStatusPlainSection(title: string, lines: string[]): string {\n return [\n title,\n ...lines,\n ].join(\"\\n\");\n}\n\nfunction presentStatusMarkdownSection(title: string, lines: string[]): string {\n return [\n `## ${title}`,\n ...lines,\n ].join(\"\\n\");\n}\n\nfunction presentStatusPlainOverviewLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const lines = [\n presentPlainStatusBullet(\n layout.connectivityLabel,\n input.health.status === \"error\"\n ? layout.errorStatus\n : formatHealthBadge(input.health.data.healthy, layout),\n ),\n ];\n\n if (input.health.status === \"error\") {\n return [\n ...lines,\n ...presentStatusPlainErrorDetailLines(input.health.error, copy, layout),\n presentPlainStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n }\n\n return [\n ...lines,\n presentPlainStatusBullet(layout.openCodeVersionLabel, input.health.data.version),\n presentPlainStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n}\n\nfunction presentStatusMarkdownOverviewLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const lines = [\n presentMarkdownStatusBullet(\n layout.connectivityLabel,\n input.health.status === \"error\"\n ? layout.errorStatus\n : formatHealthBadge(input.health.data.healthy, layout),\n ),\n ];\n\n if (input.health.status === \"error\") {\n return [\n ...lines,\n ...presentStatusMarkdownErrorDetailLines(input.health.error, copy, layout),\n presentMarkdownStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n }\n\n return [\n ...lines,\n presentMarkdownStatusBullet(layout.openCodeVersionLabel, input.health.data.version),\n presentMarkdownStatusBullet(layout.tbotVersionLabel, OPENCODE_TBOT_VERSION),\n ];\n}\n\nfunction presentStatusPlainWorkspaceLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.workspace.status === \"error\") {\n return presentStatusPlainErrorLines(input.workspace.error, copy, layout);\n }\n\n return [\n presentPlainStatusBullet(layout.currentProjectLabel, input.workspace.data.currentProject),\n presentPlainStatusBullet(layout.currentSessionLabel, input.workspace.data.currentSession ?? layout.defaultSessionValue),\n ];\n}\n\nfunction presentStatusMarkdownWorkspaceLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.workspace.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.workspace.error, copy, layout);\n }\n\n return [\n presentMarkdownStatusBullet(layout.currentProjectLabel, input.workspace.data.currentProject, {\n codeValue: true,\n }),\n presentMarkdownStatusBullet(layout.currentSessionLabel, input.workspace.data.currentSession ?? layout.defaultSessionValue),\n ];\n}\n\nfunction presentStatusPlainPluginLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.plugins.status === \"error\") {\n return presentStatusPlainErrorLines(input.plugins.error, copy, layout);\n }\n\n if (input.plugins.data.plugins.length === 0) {\n return [\n ...presentPlainEmptyStatusLines(layout.noPluginsMessage, layout),\n ];\n }\n\n return input.plugins.data.plugins.map((plugin) => `- ${plugin}`);\n}\n\nfunction presentStatusMarkdownPluginLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.plugins.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.plugins.error, copy, layout);\n }\n\n if (input.plugins.data.plugins.length === 0) {\n return [\n ...presentMarkdownEmptyStatusLines(layout.noPluginsMessage, layout),\n ];\n }\n\n return input.plugins.data.plugins.map((plugin) => `- \\`${plugin}\\``);\n}\n\nfunction presentStatusPlainLspLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.lsp.status === \"error\") {\n return presentStatusPlainErrorLines(input.lsp.error, copy, layout);\n }\n\n if (input.lsp.data.statuses.length === 0) {\n return presentPlainEmptyStatusLines(copy.lsp.none, layout);\n }\n\n return input.lsp.data.statuses.flatMap((status) => presentPlainStatusGroup(status.name, [\n {\n label: layout.statusLabel,\n value: formatLspStatusBadge(status),\n },\n ]));\n}\n\nfunction presentStatusMarkdownLspLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.lsp.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.lsp.error, copy, layout);\n }\n\n if (input.lsp.data.statuses.length === 0) {\n return presentMarkdownEmptyStatusLines(copy.lsp.none, layout);\n }\n\n return input.lsp.data.statuses.flatMap((status) => presentMarkdownStatusGroup(status.name, [\n {\n label: layout.statusLabel,\n value: formatLspStatusBadge(status),\n },\n ]));\n}\n\nfunction presentStatusPlainMcpLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.mcp.status === \"error\") {\n return presentStatusPlainErrorLines(input.mcp.error, copy, layout);\n }\n\n if (input.mcp.data.statuses.length === 0) {\n return presentPlainEmptyStatusLines(copy.mcp.none, layout);\n }\n\n return input.mcp.data.statuses.flatMap(({ name, status }) =>\n presentPlainStatusGroup(name, getMcpStatusDetailLines(status, copy, layout)),\n );\n}\n\nfunction presentStatusMarkdownMcpLines(input: GetStatusResult, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n if (input.mcp.status === \"error\") {\n return presentStatusMarkdownErrorLines(input.mcp.error, copy, layout);\n }\n\n if (input.mcp.data.statuses.length === 0) {\n return presentMarkdownEmptyStatusLines(copy.mcp.none, layout);\n }\n\n return input.mcp.data.statuses.flatMap(({ name, status }) =>\n presentMarkdownStatusGroup(name, getMcpStatusDetailLines(status, copy, layout), {\n codeName: true,\n }),\n );\n}\n\nfunction presentStatusPlainErrorLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n return [\n presentPlainStatusBullet(layout.statusLabel, layout.errorStatus),\n ...presentStatusPlainErrorDetailLines(error, copy, layout),\n ];\n}\n\nfunction presentStatusPlainErrorDetailLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const detailLines = splitStatusLines(presentError(error, copy));\n\n return detailLines.map((line) => presentPlainStatusBullet(layout.detailsLabel, line));\n}\n\nfunction presentStatusMarkdownErrorLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n return [\n presentMarkdownStatusBullet(layout.statusLabel, layout.errorStatus),\n ...presentStatusMarkdownErrorDetailLines(error, copy, layout),\n ];\n}\n\nfunction presentStatusMarkdownErrorDetailLines(error: unknown, copy: BotCopy, layout: StatusLayoutCopy): string[] {\n const detailLines = splitStatusLines(presentError(error, copy));\n\n return detailLines.map((line) => presentMarkdownStatusBullet(layout.detailsLabel, line));\n}\n\nfunction presentPlainEmptyStatusLines(message: string, layout: StatusLayoutCopy): string[] {\n return [\n presentPlainStatusBullet(layout.statusLabel, layout.noneStatus),\n presentPlainStatusBullet(layout.detailsLabel, message),\n ];\n}\n\nfunction presentMarkdownEmptyStatusLines(message: string, layout: StatusLayoutCopy): string[] {\n return [\n presentMarkdownStatusBullet(layout.statusLabel, layout.noneStatus),\n presentMarkdownStatusBullet(layout.detailsLabel, message),\n ];\n}\n\nfunction presentPlainStatusGroup(name: string, details: StatusDetailLine[]): string[] {\n return [\n `- ${normalizeStatusInlineValue(name)}`,\n ...details.map((detail) => ` - ${detail.label}: ${formatStatusValue(detail.value)}`),\n ];\n}\n\nfunction presentMarkdownStatusGroup(\n name: string,\n details: StatusDetailLine[],\n options: {\n codeName?: boolean;\n } = {},\n): string[] {\n const renderedName = options.codeName\n ? `\\`${normalizeStatusInlineValue(name)}\\``\n : `**${normalizeStatusInlineValue(name)}**`;\n\n return [\n `- ${renderedName}`,\n ...details.map((detail) => detail.codeValue\n ? ` - **${detail.label}:** \\`${formatStatusValue(detail.value)}\\``\n : ` - **${detail.label}:** ${formatStatusValue(detail.value)}`),\n ];\n}\n\nfunction presentPlainStatusBullet(label: string, value: string): string {\n return `- ${label}: ${formatStatusValue(value)}`;\n}\n\nfunction presentMarkdownStatusBullet(\n label: string,\n value: string,\n options: {\n codeValue?: boolean;\n } = {},\n): string {\n return options.codeValue\n ? `- **${label}:** \\`${formatStatusValue(value)}\\``\n : `- **${label}:** ${formatStatusValue(value)}`;\n}\n\nfunction splitStatusLines(text: string): string[] {\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n}\n\nfunction formatHealthBadge(healthy: boolean, layout: StatusLayoutCopy): string {\n return healthy ? \"\\uD83D\\uDFE2\" : layout.errorStatus;\n}\n\nfunction formatLspStatusBadge(status: OpenCodeLspStatus): string {\n switch (status.status) {\n case \"connected\":\n return \"\\uD83D\\uDFE2\";\n case \"error\":\n return \"\\uD83D\\uDD34\";\n }\n\n const exhaustiveStatus: never = status.status;\n\n return exhaustiveStatus;\n}\n\nfunction formatMcpStatusBadge(status: OpenCodeMcpStatus, layout: StatusLayoutCopy): string {\n switch (status.status) {\n case \"connected\":\n return \"\\uD83D\\uDFE2\";\n case \"disabled\":\n return \"\\u26AA\";\n case \"needs_auth\":\n return \"\\uD83D\\uDFE1\";\n case \"failed\":\n return layout.mcpFailedStatus;\n case \"needs_client_registration\":\n return layout.mcpRegistrationRequiredStatus;\n }\n\n const exhaustiveStatus: never = status;\n\n return exhaustiveStatus;\n}\n\nfunction getMcpStatusDetailLines(\n status: OpenCodeMcpStatus,\n copy: BotCopy,\n layout: StatusLayoutCopy,\n): StatusDetailLine[] {\n const notes = formatMcpStatusNotes(status, copy, layout);\n\n return notes\n ? [\n {\n label: layout.statusLabel,\n value: formatMcpStatusBadge(status, layout),\n },\n {\n label: layout.mcpNotesLabel,\n value: notes,\n },\n ]\n : [\n {\n label: layout.statusLabel,\n value: formatMcpStatusBadge(status, layout),\n },\n ];\n}\n\nfunction formatMcpStatusNotes(status: OpenCodeMcpStatus, copy: BotCopy, layout: StatusLayoutCopy): string | null {\n switch (status.status) {\n case \"connected\":\n return null;\n case \"disabled\":\n return null;\n case \"needs_auth\":\n return copy.mcp.needsAuth;\n case \"failed\":\n return status.error;\n case \"needs_client_registration\":\n return status.error;\n }\n\n const exhaustiveStatus: never = status;\n\n return exhaustiveStatus;\n}\n\nfunction formatStatusValue(value: string): string {\n const normalized = value\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .join(\" / \");\n\n return normalized.length > 0 ? normalized : \"-\";\n}\n\nfunction normalizeStatusInlineValue(value: string): string {\n return formatStatusValue(value);\n}\n\nfunction getStatusLayoutCopy(copy: BotCopy): StatusLayoutCopy {\n if (copy.locale === \"en\") {\n return {\n connectivityLabel: \"Connectivity\",\n currentProjectLabel: \"Current Project\",\n currentSessionLabel: \"Current Session\",\n defaultSessionValue: \"OpenCode Default\",\n detailsLabel: \"Details\",\n errorStatus: \"\\uD83D\\uDD34\",\n lspTitle: \"\\uD83E\\uDDE0 LSP\",\n mcpFailedStatus: \"\\uD83D\\uDD34\",\n mcpNotesLabel: \"Notes\",\n mcpRegistrationRequiredStatus: \"\\uD83D\\uDFE1\",\n mcpTitle: \"\\uD83D\\uDD0C MCP\",\n noPluginsMessage: \"No plugins detected in the current OpenCode setup.\",\n noneStatus: \"\\u26AA\",\n openCodeVersionLabel: \"OpenCode Version\",\n overviewTitle: \"\\uD83D\\uDDA5\\uFE0F Overview\",\n pluginsTitle: \"\\uD83E\\uDDE9 Plugins\",\n statusLabel: \"Status\",\n tbotVersionLabel: \"opencode-tbot Version\",\n workspaceTitle: \"\\uD83D\\uDCC1 Workspace\",\n };\n }\n\n if (copy.locale === \"ja\") {\n return {\n connectivityLabel: \"接続性\",\n currentProjectLabel: \"現在のプロジェクト\",\n currentSessionLabel: \"現在のセッション\",\n defaultSessionValue: \"OpenCode のデフォルト\",\n detailsLabel: \"詳細\",\n errorStatus: \"\\uD83D\\uDD34\",\n lspTitle: \"\\uD83E\\uDDE0 LSP\",\n mcpFailedStatus: \"\\uD83D\\uDD34\",\n mcpNotesLabel: \"補足\",\n mcpRegistrationRequiredStatus: \"\\uD83D\\uDFE1\",\n mcpTitle: \"\\uD83D\\uDD0C MCP\",\n noPluginsMessage: \"現在の OpenCode 構成ではプラグインが検出されていません。\",\n noneStatus: \"\\u26AA\",\n openCodeVersionLabel: \"OpenCode バージョン\",\n overviewTitle: \"\\uD83D\\uDDA5\\uFE0F 概要\",\n pluginsTitle: \"\\uD83E\\uDDE9 プラグイン\",\n statusLabel: \"状態\",\n tbotVersionLabel: \"opencode-tbot バージョン\",\n workspaceTitle: \"\\uD83D\\uDCC1 ワークスペース\",\n };\n }\n\n return {\n connectivityLabel: \"\\u8FDE\\u901A\\u6027\",\n currentProjectLabel: \"\\u5F53\\u524D\\u9879\\u76EE\",\n currentSessionLabel: \"\\u5F53\\u524D\\u4F1A\\u8BDD\",\n defaultSessionValue: \"OpenCode \\u9ED8\\u8BA4\",\n detailsLabel: \"\\u8BE6\\u60C5\",\n errorStatus: \"\\uD83D\\uDD34\",\n lspTitle: \"\\uD83E\\uDDE0 LSP\",\n mcpFailedStatus: \"\\uD83D\\uDD34\",\n mcpNotesLabel: \"\\u8BF4\\u660E\",\n mcpRegistrationRequiredStatus: \"\\uD83D\\uDFE1\",\n mcpTitle: \"\\uD83D\\uDD0C MCP\",\n noPluginsMessage: \"\\u5F53\\u524D OpenCode \\u73AF\\u5883\\u4E2D\\u672A\\u68C0\\u6D4B\\u5230\\u63D2\\u4EF6\\u3002\",\n noneStatus: \"\\u26AA\",\n openCodeVersionLabel: \"OpenCode\\u7248\\u672C\",\n overviewTitle: \"\\uD83D\\uDDA5\\uFE0F \\u6982\\u89C8\",\n pluginsTitle: \"\\uD83E\\uDDE9 \\u63D2\\u4EF6\",\n statusLabel: \"\\u72B6\\u6001\",\n tbotVersionLabel: \"opencode-tbot\\u7248\\u672C\",\n workspaceTitle: \"\\uD83D\\uDCC1 \\u5DE5\\u4F5C\\u533A\",\n };\n}\n\nexport function presentSessionsMessage(input: SessionsMessageInput, copy: BotCopy = BOT_COPY): string {\n if (input.sessions.length === 0) {\n return copy.sessions.none;\n }\n\n const page = getSessionsPage(input.sessions, input.page);\n const currentSession = input.currentSessionId\n ? input.sessions.find((session) => session.id === input.currentSessionId) ?? null\n : null;\n const lines = [\n copy.sessions.title,\n copy.sessions.currentProject(input.currentDirectory),\n copy.sessions.currentSession(currentSession ? formatSessionLabel(currentSession) : copy.common.notSelected),\n copy.common.page(page.page + 1, page.totalPages),\n \"\",\n ...page.items.map((session, index) => `${page.startIndex + index + 1}. ${formatSessionLabel(session)}`),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentSessionSwitchMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return [\n copy.sessions.switched,\n copy.sessions.currentSession(formatSessionLabel(session)),\n ].join(\"\\n\");\n}\n\nexport function presentSessionCreatedMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return [\n copy.sessions.created,\n copy.sessions.currentSession(formatSessionLabel(session)),\n ].join(\"\\n\");\n}\n\nexport function presentSessionActionsMessage(\n input: { currentDirectory: string; session: OpenCodeSession },\n copy: BotCopy = BOT_COPY,\n): string {\n return [\n copy.sessions.actionTitle,\n copy.sessions.currentProject(input.currentDirectory),\n copy.sessions.selectedSession(formatSessionLabel(input.session)),\n \"\",\n copy.sessions.chooseAction,\n ].join(\"\\n\");\n}\n\nexport function presentSessionRenamePromptMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return copy.sessions.renamePrompt(formatSessionLabel(session));\n}\n\nexport function presentSessionRenamedMessage(session: OpenCodeSession, copy: BotCopy = BOT_COPY): string {\n return [\n copy.sessions.renamed,\n copy.sessions.currentSession(formatSessionLabel(session)),\n ].join(\"\\n\");\n}\n\nexport function presentAgentsMessage(input: AgentsMessageInput, copy: BotCopy = BOT_COPY): string {\n if (input.agents.length === 0) {\n return copy.agents.none;\n }\n\n const page = getAgentsPage(input.agents, input.page);\n const currentAgent = input.currentAgentName\n ? input.agents.find((agent) => agent.name === input.currentAgentName) ?? null\n : null;\n const lines = [\n copy.agents.title,\n copy.agents.current(currentAgent ? formatAgentLabel(currentAgent) : copy.common.openCodeDefault),\n copy.common.page(page.page + 1, page.totalPages),\n \"\",\n ...page.items.map((agent, index) => `${page.startIndex + index + 1}. ${formatAgentLabel(agent)}`),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentAgentSwitchMessage(agent: OpenCodeAgent, copy: BotCopy = BOT_COPY): string {\n return [\n copy.agents.switched,\n copy.agents.current(formatAgentLabel(agent)),\n ].join(\"\\n\");\n}\n\nexport function presentModelsMessage(input: ModelsMessageInput, copy: BotCopy = BOT_COPY): string {\n if (input.models.length === 0) {\n return copy.models.none;\n }\n\n const page = getModelsPage(input.models, input.page);\n const currentModel = input.currentModelId && input.currentModelProviderId\n ? input.models.find((model) =>\n model.id === input.currentModelId && model.providerID === input.currentModelProviderId,\n ) ?? null\n : null;\n const currentModelLine = currentModel\n ? formatModelSelection(currentModel, input.currentModelVariant, copy)\n : copy.common.openCodeDefault;\n const lines = [\n copy.models.title,\n copy.models.configuredOnly,\n copy.models.current(currentModelLine),\n copy.common.page(page.page + 1, page.totalPages),\n \"\",\n ...page.items.map((model, index) => formatModelListLine(model, page.startIndex + index + 1)),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentModelVariantsMessage(\n model: OpenCodeConfiguredModel,\n modelIndex: number,\n copy: BotCopy = BOT_COPY,\n): string {\n const variants = getModelVariants(model);\n\n if (variants.length === 0) {\n return [\n copy.models.noReasoningLevels,\n copy.models.model(formatModelLabel(model)),\n ].join(\"\\n\");\n }\n\n const lines = [\n copy.models.reasoningLevelsTitle,\n copy.models.model(formatModelLabel(model)),\n copy.models.modelNumber(modelIndex),\n \"\",\n ...variants.map((variant, index) => `${index + 1}. ${variant}`),\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function presentModelSwitchMessage(\n model: OpenCodeConfiguredModel,\n variant: string | null,\n copy: BotCopy = BOT_COPY,\n): string {\n return [\n copy.models.switched,\n copy.models.current(formatModelLabel(model)),\n copy.models.currentReasoningLevel(variant ?? copy.models.defaultReasoningLevel),\n ].join(\"\\n\");\n}\n\nexport function presentLanguageMessage(currentLanguage: BotLanguage, copy: BotCopy = BOT_COPY): string {\n return [\n copy.language.title,\n copy.language.current(getLanguageLabel(currentLanguage, copy)),\n \"\",\n copy.language.choose,\n ].join(\"\\n\");\n}\n\nexport function presentLanguageSwitchMessage(currentLanguage: BotLanguage, copy: BotCopy = BOT_COPY): string {\n return [\n copy.language.switched,\n copy.language.current(getLanguageLabel(currentLanguage, copy)),\n ].join(\"\\n\");\n}\n\nexport function getModelVariants(model: OpenCodeConfiguredModel): string[] {\n return Object.keys(model.variants)\n .sort((left, right) => compareVariantNames(left, right));\n}\n\nfunction compareVariantNames(left: string, right: string): number {\n const leftIndex = VARIANT_ORDER.indexOf(left);\n const rightIndex = VARIANT_ORDER.indexOf(right);\n\n if (leftIndex === -1 && rightIndex === -1) {\n return left.localeCompare(right);\n }\n\n if (leftIndex === -1) {\n return 1;\n }\n\n if (rightIndex === -1) {\n return -1;\n }\n\n return leftIndex - rightIndex;\n}\n\nfunction formatAgentLabel(agent: OpenCodeAgent): string {\n return agent.name;\n}\n\nfunction formatModelListLine(model: OpenCodeConfiguredModel, displayIndex: number): string {\n return `${displayIndex}. ${formatModelLabel(model)}`;\n}\n\nfunction formatModelSelection(\n model: OpenCodeConfiguredModel,\n variant: string | null,\n copy: BotCopy,\n): string {\n return `${formatModelLabel(model)} | ${copy.models.reasoningLevel(variant ?? copy.models.defaultReasoningLevel)}`;\n}\n\nfunction formatModelLabel(model: OpenCodeConfiguredModel): string {\n return `${model.providerName} / ${model.name}`;\n}\n\nfunction formatSessionLabel(session: OpenCodeSession): string {\n const title = session.title.trim() || session.slug || session.id;\n\n return title === session.slug\n ? title\n : `${title} [${session.slug}]`;\n}\n\nfunction formatMcpStatus(status: OpenCodeMcpStatus, copy: BotCopy): string {\n switch (status.status) {\n case \"connected\":\n return copy.mcp.connected;\n case \"disabled\":\n return copy.mcp.disabled;\n case \"needs_auth\":\n return copy.mcp.needsAuth;\n case \"failed\":\n return copy.mcp.failed(status.error);\n case \"needs_client_registration\":\n return copy.mcp.needsClientRegistration(status.error);\n }\n\n const exhaustiveStatus: never = status;\n\n return exhaustiveStatus;\n}\n\nfunction formatLspStatus(status: OpenCodeLspStatus, copy: BotCopy): string {\n switch (status.status) {\n case \"connected\":\n return copy.lsp.connected;\n case \"error\":\n return copy.lsp.error;\n }\n\n const exhaustiveStatus: never = status.status;\n\n return exhaustiveStatus;\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { buildAgentsKeyboard } from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentAgentsMessage } from \"../presenters/message.presenter.js\";\n\ninterface AgentsCommandContext {\n chat: { id: number };\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleAgentsCommand(ctx: AgentsCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n const result = await dependencies.listAgentsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.agents.length === 0) {\n await ctx.reply(copy.agents.none);\n return;\n }\n\n const { keyboard, page } = buildAgentsKeyboard(result.agents, 0, copy);\n\n await ctx.reply(\n presentAgentsMessage({\n agents: result.agents,\n currentAgentName: result.currentAgentName,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to list agents\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerAgentsCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command([\"agents\", \"agent\"], async (ctx) => {\n await handleAgentsCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { OpenCodeSession } from \"../services/opencode/opencode.client.js\";\nimport { getSafeChatCopy } from \"./i18n.js\";\nimport {\n buildSessionActionKeyboard,\n buildSessionsKeyboard,\n} from \"./presenters/keyboard.presenter.js\";\nimport {\n presentSessionActionsMessage,\n presentSessionsMessage,\n} from \"./presenters/message.presenter.js\";\nimport type { BotDependencies } from \"./types.js\";\n\ninterface SessionsMessageApi {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n}\n\ninterface SessionsListView {\n copy: Awaited<ReturnType<typeof getSafeChatCopy>>;\n currentDirectory: string;\n currentSessionId: string | null;\n keyboard?: unknown;\n page: number;\n sessions: OpenCodeSession[];\n text: string;\n}\n\nexport async function buildSessionsListView(\n chatId: number,\n requestedPage: number,\n dependencies: BotDependencies,\n): Promise<SessionsListView> {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, chatId, dependencies.logger);\n const result = await dependencies.listSessionsUseCase.execute({\n chatId,\n });\n\n if (result.sessions.length === 0) {\n return {\n copy,\n currentDirectory: result.currentDirectory,\n currentSessionId: result.currentSessionId,\n page: 0,\n sessions: [],\n text: copy.sessions.none,\n };\n }\n\n const { keyboard, page } = buildSessionsKeyboard(result.sessions, requestedPage, copy);\n\n return {\n copy,\n currentDirectory: result.currentDirectory,\n currentSessionId: result.currentSessionId,\n keyboard,\n page: page.page,\n sessions: result.sessions,\n text: presentSessionsMessage({\n currentDirectory: result.currentDirectory,\n currentSessionId: result.currentSessionId,\n page: page.page,\n sessions: result.sessions,\n }, copy),\n };\n}\n\nexport async function buildSessionActionView(\n chatId: number,\n requestedPage: number,\n sessionId: string,\n dependencies: BotDependencies,\n) {\n const listView = await buildSessionsListView(chatId, requestedPage, dependencies);\n const session = listView.sessions.find((item) => item.id === sessionId);\n\n if (!session) {\n return {\n copy: listView.copy,\n found: false as const,\n };\n }\n\n return {\n copy: listView.copy,\n found: true as const,\n keyboard: buildSessionActionKeyboard(session.id, listView.page, listView.copy),\n page: listView.page,\n session,\n text: presentSessionActionsMessage({\n currentDirectory: listView.currentDirectory,\n session,\n }, listView.copy),\n };\n}\n\nexport async function restoreSessionsListMessage(\n api: SessionsMessageApi,\n chatId: number,\n messageId: number,\n requestedPage: number,\n dependencies: BotDependencies,\n) {\n const listView = await buildSessionsListView(chatId, requestedPage, dependencies);\n\n if (listView.keyboard) {\n await api.editMessageText(chatId, messageId, listView.text, {\n reply_markup: listView.keyboard,\n });\n } else {\n await api.editMessageText(chatId, messageId, listView.text);\n }\n\n return listView;\n}\n","import type { PendingChatAction, SessionRenamePendingAction } from \"../domain/pending-action/pending-action.entity.js\";\nimport { getSafeChatCopy } from \"./i18n.js\";\nimport { restoreSessionsListMessage } from \"./sessions-menu.js\";\nimport { presentError } from \"./presenters/error.presenter.js\";\nimport { presentSessionRenamedMessage } from \"./presenters/message.presenter.js\";\nimport type { BotDependencies } from \"./types.js\";\n\ninterface SessionRenameApi {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n}\n\ninterface SessionRenameReplyContext {\n api: SessionRenameApi;\n chat: { id: number };\n reply(text: string): Promise<unknown>;\n}\n\ninterface SessionRenameTextContext extends SessionRenameReplyContext {\n message: { text?: string };\n}\n\nexport async function getPendingSessionRenameAction(\n dependencies: BotDependencies,\n chatId: number,\n): Promise<SessionRenamePendingAction | null> {\n const action = await dependencies.pendingActionRepo.getByChatId(chatId);\n\n return isSessionRenamePendingAction(action) ? action : null;\n}\n\nexport async function replyIfSessionRenamePending(\n ctx: Pick<SessionRenameReplyContext, \"chat\" | \"reply\">,\n dependencies: BotDependencies,\n): Promise<boolean> {\n const pendingAction = await getPendingSessionRenameAction(dependencies, ctx.chat.id);\n\n if (!pendingAction) {\n return false;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n await ctx.reply(copy.sessions.renamePendingInput);\n\n return true;\n}\n\nexport async function handlePendingSessionRenameText(\n ctx: SessionRenameTextContext,\n dependencies: BotDependencies,\n): Promise<boolean> {\n const pendingAction = await getPendingSessionRenameAction(dependencies, ctx.chat.id);\n\n if (!pendingAction) {\n return false;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n const title = ctx.message.text?.trim() ?? \"\";\n\n if (title.startsWith(\"/\")) {\n await ctx.reply(copy.sessions.renamePendingInput);\n return true;\n }\n\n if (!title) {\n await ctx.reply(copy.sessions.renameEmpty);\n return true;\n }\n\n try {\n const result = await dependencies.renameSessionUseCase.execute({\n chatId: ctx.chat.id,\n sessionId: pendingAction.sessionId,\n title,\n });\n\n await dependencies.pendingActionRepo.clear(ctx.chat.id);\n\n await bestEffortRestoreSessionsList(ctx.api, pendingAction, dependencies);\n\n if (!result.found) {\n await ctx.reply(copy.sessions.renameExpired);\n return true;\n }\n\n await ctx.reply(presentSessionRenamedMessage(result.session, copy));\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to rename session\");\n await ctx.reply(presentError(error, copy));\n }\n\n return true;\n}\n\nexport async function cancelPendingSessionRename(\n ctx: SessionRenameReplyContext,\n dependencies: BotDependencies,\n): Promise<boolean> {\n const pendingAction = await getPendingSessionRenameAction(dependencies, ctx.chat.id);\n\n if (!pendingAction) {\n return false;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n await dependencies.pendingActionRepo.clear(ctx.chat.id);\n await bestEffortRestoreSessionsList(ctx.api, pendingAction, dependencies);\n await ctx.reply(copy.sessions.renameCancelled);\n\n return true;\n}\n\nasync function bestEffortRestoreSessionsList(\n api: SessionRenameApi,\n pendingAction: SessionRenamePendingAction,\n dependencies: BotDependencies,\n) {\n try {\n await restoreSessionsListMessage(\n api,\n pendingAction.chatId,\n pendingAction.menuMessageId,\n pendingAction.returnPage,\n dependencies,\n );\n } catch (error) {\n dependencies.logger.warn?.({ error }, \"failed to restore sessions list message\");\n }\n}\n\nfunction isSessionRenamePendingAction(action: PendingChatAction | null): action is SessionRenamePendingAction {\n return action?.kind === \"session_rename\";\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { cancelPendingSessionRename } from \"../session-rename.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface CancelCommandContext {\n api: {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n };\n chat: { id: number };\n reply(text: string): Promise<unknown>;\n}\n\nexport async function handleCancelCommand(ctx: CancelCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (await cancelPendingSessionRename(ctx, dependencies)) {\n return;\n }\n\n const result = await dependencies.abortPromptUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.status === \"no_session\") {\n await ctx.reply(copy.abort.noSession);\n return;\n }\n\n if (result.status === \"not_running\") {\n await ctx.reply(copy.abort.notRunning);\n return;\n }\n\n await ctx.reply(copy.abort.aborted);\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to cancel current action\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerCancelCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"cancel\", async (ctx) => {\n await handleCancelCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { isBotLanguage } from \"../copy.js\";\nimport {\n getSafeChatCopy,\n getSafeChatLanguage,\n setChatLanguage,\n} from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { buildLanguageKeyboard } from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport {\n presentLanguageMessage,\n presentLanguageSwitchMessage,\n} from \"../presenters/message.presenter.js\";\nimport { syncTelegramCommandsForChat } from \"./sync-commands.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface LanguageCommandContext {\n chat: { id: number };\n api: Pick<Bot[\"api\"], \"setMyCommands\">;\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleLanguageCommand(ctx: LanguageCommandContext, dependencies: BotDependencies) {\n const language = await getSafeChatLanguage(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n await syncTelegramCommandsForChat(ctx.api, ctx.chat.id, language);\n await ctx.reply(\n presentLanguageMessage(language, copy),\n {\n reply_markup: buildLanguageKeyboard(language, copy),\n },\n );\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to show language options\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport async function switchLanguageForChat(\n api: Pick<Bot[\"api\"], \"setMyCommands\">,\n chatId: number,\n language: string,\n dependencies: BotDependencies,\n): Promise<\n | { found: false; copy: Awaited<ReturnType<typeof getSafeChatCopy>> }\n | {\n found: true;\n copy: Awaited<ReturnType<typeof getSafeChatCopy>>;\n language: Awaited<ReturnType<typeof getSafeChatLanguage>>;\n }\n> {\n const currentCopy = await getSafeChatCopy(dependencies.sessionRepo, chatId, dependencies.logger);\n\n if (!isBotLanguage(language)) {\n return {\n found: false,\n copy: currentCopy,\n };\n }\n\n await setChatLanguage(dependencies.sessionRepo, chatId, language);\n await syncTelegramCommandsForChat(api, chatId, language);\n\n return {\n found: true,\n copy: await getSafeChatCopy(dependencies.sessionRepo, chatId, dependencies.logger),\n language,\n };\n}\n\nexport async function presentLanguageSwitchForChat(\n chatId: number,\n api: Pick<Bot[\"api\"], \"setMyCommands\">,\n language: string,\n dependencies: BotDependencies,\n) {\n const result = await switchLanguageForChat(api, chatId, language, dependencies);\n\n if (!result.found) {\n return {\n found: false as const,\n copy: result.copy,\n text: result.copy.language.expired,\n keyboard: buildLanguageKeyboard(\n await getSafeChatLanguage(dependencies.sessionRepo, chatId, dependencies.logger),\n result.copy,\n ),\n };\n }\n\n return {\n found: true as const,\n copy: result.copy,\n text: presentLanguageSwitchMessage(result.language, result.copy),\n keyboard: buildLanguageKeyboard(result.language, result.copy),\n };\n}\n\nexport function registerLanguageCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"language\", async (ctx) => {\n await handleLanguageCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { buildModelsKeyboard } from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentModelsMessage } from \"../presenters/message.presenter.js\";\n\ninterface ModelsCommandContext {\n chat: { id: number };\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleModelsCommand(ctx: ModelsCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.models.length === 0) {\n await ctx.reply(copy.models.none);\n return;\n }\n\n const { keyboard, page } = buildModelsKeyboard(result.models, 0, copy);\n\n await ctx.reply(\n presentModelsMessage({\n currentModelId: result.currentModelId,\n currentModelProviderId: result.currentModelProviderId,\n currentModelVariant: result.currentModelVariant,\n models: result.models,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to list models\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerModelsCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command([\"model\", \"models\"], async (ctx) => {\n await handleModelsCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentSessionCreatedMessage } from \"../presenters/message.presenter.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface NewCommandContext {\n chat: { id: number };\n message?: { text?: string };\n match?: string;\n reply(text: string): Promise<unknown>;\n}\n\nexport async function handleNewCommand(ctx: NewCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n const title = extractSessionTitle(ctx);\n const result = await dependencies.createSessionUseCase.execute({\n chatId: ctx.chat.id,\n title,\n });\n\n await ctx.reply(presentSessionCreatedMessage(result.session, copy));\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to create new session\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerNewCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"new\", async (ctx) => {\n await handleNewCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n\nfunction extractSessionTitle(ctx: NewCommandContext): string | null {\n if (typeof ctx.match === \"string\") {\n const title = ctx.match.trim();\n\n return title ? title : null;\n }\n\n const messageText = ctx.message?.text?.trim();\n\n if (!messageText) {\n return null;\n }\n\n const match = messageText.match(/^\\/new(?:@\\S+)?(?:\\s+([\\s\\S]*))?$/i);\n const title = match?.[1]?.trim();\n\n return title ? title : null;\n}\n","import { BOT_COPY, type BotCopy } from \"../../bot/copy.js\";\nimport { stripMarkdownToPlainText } from \"../../infra/utils/markdown-text.js\";\nimport type {\n PromptSessionMetrics,\n PromptSessionResult,\n} from \"../opencode/opencode.client.js\";\n\nconst MAX_TELEGRAM_MESSAGE_LENGTH = 4096;\nconst TRUNCATED_SUFFIX = \"...\";\nconst MARKDOWN_SPECIAL_CHARACTERS = /([_*\\[\\]()~`>#+\\-=|{}.!\\\\])/g;\nexport { stripMarkdownToPlainText } from \"../../infra/utils/markdown-text.js\";\n\nexport interface TelegramReplyPayload {\n options?: {\n parse_mode: \"MarkdownV2\";\n };\n text: string;\n}\n\nexport interface TelegramPromptReply {\n fallback: TelegramReplyPayload;\n preferred: TelegramReplyPayload;\n}\n\nexport interface TelegramStaticReply {\n fallback: TelegramReplyPayload;\n preferred: TelegramReplyPayload;\n}\n\nexport function buildTelegramPromptReply(\n result: PromptSessionResult,\n copy: BotCopy = BOT_COPY,\n): TelegramPromptReply {\n const renderedMarkdown = result.bodyMd ? renderMarkdownToTelegramMarkdownV2(result.bodyMd) : null;\n const footerPlain = formatPlainMetricsFooter(result.metrics, copy);\n const plainBody = normalizePlainBody(result, copy);\n const fallback = {\n text: joinBodyAndFooter(\n truncatePlainBody(plainBody, footerPlain),\n footerPlain,\n ),\n };\n\n if (!renderedMarkdown) {\n return {\n preferred: fallback,\n fallback,\n };\n }\n\n const footerMarkdown = formatMarkdownMetricsFooter(result.metrics, copy);\n const markdownText = joinBodyAndFooter(renderedMarkdown, footerMarkdown);\n\n if (markdownText.length > MAX_TELEGRAM_MESSAGE_LENGTH) {\n return {\n preferred: fallback,\n fallback,\n };\n }\n\n return {\n preferred: {\n text: markdownText,\n options: {\n parse_mode: \"MarkdownV2\",\n },\n },\n fallback,\n };\n}\n\nexport function buildTelegramStaticReply(markdown: string): TelegramStaticReply {\n const renderedMarkdown = renderMarkdownToTelegramMarkdownV2(markdown);\n const plainText = truncateStaticText(stripMarkdownToPlainText(markdown) || markdown.trim());\n const fallback = {\n text: plainText,\n };\n\n if (!renderedMarkdown || renderedMarkdown.length > MAX_TELEGRAM_MESSAGE_LENGTH) {\n return {\n preferred: fallback,\n fallback,\n };\n }\n\n return {\n preferred: {\n text: renderedMarkdown,\n options: {\n parse_mode: \"MarkdownV2\",\n },\n },\n fallback,\n };\n}\n\nexport function renderMarkdownToTelegramMarkdownV2(markdown: string): string | null {\n const normalizedMarkdown = preprocessMarkdownForTelegram(markdown).trim();\n\n if (!normalizedMarkdown) {\n return null;\n }\n\n const lines = normalizedMarkdown.split(\"\\n\");\n const rendered: string[] = [];\n let inCodeBlock = false;\n let codeBlockLanguage = \"\";\n\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index];\n const fenceMatch = line.match(/^```([A-Za-z0-9_-]+)?\\s*$/);\n\n if (fenceMatch) {\n if (inCodeBlock) {\n rendered.push(\"```\");\n inCodeBlock = false;\n codeBlockLanguage = \"\";\n } else {\n codeBlockLanguage = fenceMatch[1] ?? \"\";\n rendered.push(`\\`\\`\\`${codeBlockLanguage}`);\n inCodeBlock = true;\n }\n\n continue;\n }\n\n if (inCodeBlock) {\n rendered.push(escapeCodeContent(line));\n continue;\n }\n\n if (line.includes(\"![\")) {\n return null;\n }\n\n const tableBlock = consumeMarkdownTable(lines, index);\n\n if (tableBlock) {\n rendered.push(renderTableAsTelegramCodeBlock(tableBlock.rows));\n index = tableBlock.nextIndex - 1;\n continue;\n }\n\n if (/<[/A-Za-z][^>]*>/.test(line)) {\n return null;\n }\n\n if (!line.trim()) {\n rendered.push(\"\");\n continue;\n }\n\n const headingMatch = line.match(/^\\s{0,3}(#{1,6})\\s+(.+)$/);\n\n if (headingMatch) {\n rendered.push(`*${escapeMarkdownText(headingMatch[2].trim())}*`);\n continue;\n }\n\n const blockquoteMatch = line.match(/^\\s*>\\s?(.*)$/);\n\n if (blockquoteMatch) {\n const quote = renderInlineMarkdown(blockquoteMatch[1]);\n\n if (quote === null) {\n return null;\n }\n\n rendered.push(`>${quote ? ` ${quote}` : \"\"}`);\n continue;\n }\n\n const unorderedListMatch = line.match(/^(\\s*)[-+*]\\s+(.+)$/);\n\n if (unorderedListMatch) {\n const item = renderInlineMarkdown(unorderedListMatch[2]);\n\n if (item === null) {\n return null;\n }\n\n rendered.push(`${unorderedListMatch[1]}\\\\- ${item}`);\n continue;\n }\n\n const orderedListMatch = line.match(/^(\\s*)(\\d+)[.)]\\s+(.+)$/);\n\n if (orderedListMatch) {\n const item = renderInlineMarkdown(orderedListMatch[3]);\n\n if (item === null) {\n return null;\n }\n\n rendered.push(`${orderedListMatch[1]}${orderedListMatch[2]}\\\\. ${item}`);\n continue;\n }\n\n const paragraph = renderInlineMarkdown(line);\n\n if (paragraph === null) {\n return null;\n }\n\n rendered.push(paragraph);\n }\n\n if (inCodeBlock) {\n return null;\n }\n\n return rendered.join(\"\\n\");\n}\n\nfunction normalizePlainBody(\n result: PromptSessionResult,\n copy: BotCopy,\n): string {\n const fromStructured = result.bodyMd ? stripMarkdownToPlainText(result.bodyMd) : \"\";\n const fromFallback = result.fallbackText.trim();\n const body = fromStructured || fromFallback;\n\n return body.trim() || result.fallbackText || copy.prompt.emptyResponse;\n}\n\nfunction truncatePlainBody(body: string, footer: string): string {\n const reservedLength = footer.length + 2;\n const maxBodyLength = Math.max(0, MAX_TELEGRAM_MESSAGE_LENGTH - reservedLength);\n\n if (body.length <= maxBodyLength) {\n return body;\n }\n\n return `${body.slice(0, Math.max(0, maxBodyLength - TRUNCATED_SUFFIX.length))}${TRUNCATED_SUFFIX}`;\n}\n\nfunction truncateStaticText(text: string): string {\n if (text.length <= MAX_TELEGRAM_MESSAGE_LENGTH) {\n return text;\n }\n\n return `${text.slice(0, Math.max(0, MAX_TELEGRAM_MESSAGE_LENGTH - TRUNCATED_SUFFIX.length))}${TRUNCATED_SUFFIX}`;\n}\n\nfunction joinBodyAndFooter(body: string, footer: string): string {\n return `${body}\\n\\n${footer}`;\n}\n\nfunction preprocessMarkdownForTelegram(markdown: string): string {\n const normalizedMarkdown = markdown.replace(/\\r\\n?/g, \"\\n\");\n const lines = normalizedMarkdown.split(\"\\n\");\n const processed: string[] = [];\n let activeFence: \"markdown\" | \"plain\" | null = null;\n\n for (const line of lines) {\n const fenceMatch = line.match(/^```([A-Za-z0-9_-]+)?\\s*$/);\n\n if (fenceMatch) {\n const language = (fenceMatch[1] ?? \"\").toLowerCase();\n\n if (activeFence === \"markdown\") {\n activeFence = null;\n continue;\n }\n\n if (activeFence === \"plain\") {\n processed.push(line);\n activeFence = null;\n continue;\n }\n\n if (language === \"md\" || language === \"markdown\") {\n activeFence = \"markdown\";\n continue;\n }\n\n activeFence = \"plain\";\n processed.push(line);\n continue;\n }\n\n processed.push(line);\n }\n\n return processed.join(\"\\n\");\n}\n\nfunction formatPlainMetricsFooter(metrics: PromptSessionMetrics, copy: BotCopy): string {\n return `${copy.replyMetrics.durationLabel}: ${formatDuration(metrics.durationMs, copy)} | ${copy.replyMetrics.tokensLabel}: ${formatMetricValue(metrics.tokens.total, copy)}`;\n}\n\nfunction formatMarkdownMetricsFooter(metrics: PromptSessionMetrics, copy: BotCopy): string {\n return escapeMarkdownText(formatPlainMetricsFooter(metrics, copy));\n}\n\nfunction formatDuration(durationMs: number | null, copy: BotCopy): string {\n if (durationMs === null || !Number.isFinite(durationMs)) {\n return copy.replyMetrics.notAvailable;\n }\n\n if (durationMs < 1000) {\n return `${Math.round(durationMs)} ms`;\n }\n\n return `${(durationMs / 1000).toFixed(1)} s`;\n}\n\nfunction formatMetricValue(value: number | null, copy: BotCopy): string {\n if (value === null || !Number.isFinite(value)) {\n return copy.replyMetrics.notAvailable;\n }\n\n return `${Math.round(value)}`;\n}\n\ninterface ConsumedTable {\n nextIndex: number;\n rows: string[][];\n}\n\nfunction consumeMarkdownTable(lines: string[], startIndex: number): ConsumedTable | null {\n if (startIndex + 1 >= lines.length) {\n return null;\n }\n\n const headerCells = parseMarkdownTableRow(lines[startIndex]);\n const separatorCells = parseMarkdownTableSeparator(lines[startIndex + 1]);\n\n if (!headerCells || !separatorCells || headerCells.length !== separatorCells.length) {\n return null;\n }\n\n const rows = [headerCells];\n let index = startIndex + 2;\n\n while (index < lines.length) {\n const rowCells = parseMarkdownTableRow(lines[index]);\n\n if (!rowCells || rowCells.length !== headerCells.length) {\n break;\n }\n\n rows.push(rowCells);\n index += 1;\n }\n\n return {\n rows,\n nextIndex: index,\n };\n}\n\nfunction parseMarkdownTableRow(line: string): string[] | null {\n const trimmed = line.trim();\n\n if (!trimmed.includes(\"|\")) {\n return null;\n }\n\n const cells = splitMarkdownTableCells(trimmed)\n .map((cell) => normalizeTableCell(cell));\n\n return cells.length >= 2 ? cells : null;\n}\n\nfunction parseMarkdownTableSeparator(line: string): string[] | null {\n const cells = splitMarkdownTableCells(line.trim());\n\n if (cells.length < 2) {\n return null;\n }\n\n return cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()))\n ? cells\n : null;\n}\n\nfunction splitMarkdownTableCells(line: string): string[] {\n const content = line\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\");\n const cells: string[] = [];\n let current = \"\";\n let escaped = false;\n\n for (const char of content) {\n if (escaped) {\n current += char;\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n escaped = true;\n current += char;\n continue;\n }\n\n if (char === \"|\") {\n cells.push(current);\n current = \"\";\n continue;\n }\n\n current += char;\n }\n\n cells.push(current);\n return cells;\n}\n\nfunction normalizeTableCell(cell: string): string {\n return cell\n .trim()\n .replace(/\\\\\\|/g, \"|\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1 ($2)\")\n .replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\")\n .replace(/(\\*|_)(.*?)\\1/g, \"$2\")\n .replace(/`([^`]+)`/g, \"$1\");\n}\n\nfunction renderTableAsTelegramCodeBlock(rows: string[][]): string {\n return [\n \"```\",\n ...buildAlignedTableLines(rows).map((line) => escapeCodeContent(line)),\n \"```\",\n ].join(\"\\n\");\n}\n\nfunction buildAlignedTableLines(rows: string[][]): string[] {\n const columnWidths = calculateTableColumnWidths(rows);\n const header = formatTableRow(rows[0], columnWidths);\n const separator = columnWidths.map((width) => \"-\".repeat(Math.max(3, width))).join(\"-+-\");\n const body = rows.slice(1).map((row) => formatTableRow(row, columnWidths));\n\n return [header, separator, ...body];\n}\n\nfunction calculateTableColumnWidths(rows: string[][]): number[] {\n return rows[0].map((_, columnIndex) =>\n rows.reduce((maxWidth, row) => Math.max(maxWidth, getDisplayWidth(row[columnIndex] ?? \"\")), 0),\n );\n}\n\nfunction formatTableRow(row: string[], columnWidths: number[]): string {\n return row\n .map((cell, index) => padDisplayWidth(cell, columnWidths[index] ?? 0))\n .join(\" | \");\n}\n\nfunction padDisplayWidth(value: string, targetWidth: number): string {\n const padding = Math.max(0, targetWidth - getDisplayWidth(value));\n\n return `${value}${\" \".repeat(padding)}`;\n}\n\nfunction getDisplayWidth(value: string): number {\n let width = 0;\n\n for (const char of value) {\n width += isWideCharacter(char.codePointAt(0) ?? 0) ? 2 : 1;\n }\n\n return width;\n}\n\nfunction isWideCharacter(codePoint: number): boolean {\n return codePoint >= 0x1100 && (\n codePoint <= 0x115f ||\n codePoint === 0x2329 ||\n codePoint === 0x232a ||\n (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||\n (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||\n (codePoint >= 0xf900 && codePoint <= 0xfaff) ||\n (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||\n (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||\n (codePoint >= 0xff00 && codePoint <= 0xff60) ||\n (codePoint >= 0xffe0 && codePoint <= 0xffe6)\n );\n}\n\nfunction renderInlineMarkdown(input: string): string | null {\n let output = \"\";\n let cursor = 0;\n\n while (cursor < input.length) {\n if (input.startsWith(\"![\", cursor)) {\n return null;\n }\n\n if (input.startsWith(\"**\", cursor) || input.startsWith(\"__\", cursor)) {\n const delimiter = input.slice(cursor, cursor + 2);\n const closingIndex = input.indexOf(delimiter, cursor + 2);\n\n if (closingIndex > cursor + 2) {\n output += `*${escapeMarkdownText(input.slice(cursor + 2, closingIndex))}*`;\n cursor = closingIndex + 2;\n continue;\n }\n }\n\n if (input[cursor] === \"*\" || input[cursor] === \"_\") {\n const delimiter = input[cursor];\n const closingIndex = input.indexOf(delimiter, cursor + 1);\n\n if (closingIndex > cursor + 1) {\n output += `_${escapeMarkdownText(input.slice(cursor + 1, closingIndex))}_`;\n cursor = closingIndex + 1;\n continue;\n }\n }\n\n if (input[cursor] === \"`\") {\n const closingIndex = input.indexOf(\"`\", cursor + 1);\n\n if (closingIndex === -1) {\n return null;\n }\n\n output += `\\`${escapeCodeContent(input.slice(cursor + 1, closingIndex))}\\``;\n cursor = closingIndex + 1;\n continue;\n }\n\n if (input[cursor] === \"[\") {\n const linkMatch = input.slice(cursor).match(/^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/);\n\n if (!linkMatch) {\n return null;\n }\n\n output += `[${escapeMarkdownText(linkMatch[1])}](${escapeLinkDestination(linkMatch[2])})`;\n cursor += linkMatch[0].length;\n continue;\n }\n\n output += escapeMarkdownText(input[cursor]);\n cursor += 1;\n }\n\n return output;\n}\n\nfunction escapeMarkdownText(text: string): string {\n return text.replace(MARKDOWN_SPECIAL_CHARACTERS, \"\\\\$1\");\n}\n\nfunction escapeCodeContent(text: string): string {\n return text\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/`/g, \"\\\\`\");\n}\n\nfunction escapeLinkDestination(url: string): string {\n return url\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\)/g, \"\\\\)\")\n .replace(/\\(/g, \"\\\\(\");\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport {\n presentStatusMarkdownMessage,\n presentStatusMessage,\n} from \"../presenters/message.presenter.js\";\nimport { renderMarkdownToTelegramMarkdownV2 } from \"../../services/telegram/telegram-format.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface StatusCommandContext {\n chat?: { id: number };\n reply(\n text: string,\n options?: {\n parse_mode: \"MarkdownV2\";\n },\n ): Promise<unknown>;\n}\n\nexport async function handleStatusCommand(ctx: StatusCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat?.id, dependencies.logger);\n\n try {\n const result = await dependencies.getStatusUseCase.execute({\n chatId: ctx.chat?.id ?? 0,\n });\n\n const renderedMarkdown = renderMarkdownToTelegramMarkdownV2(presentStatusMarkdownMessage(result, copy));\n\n if (renderedMarkdown) {\n await ctx.reply(renderedMarkdown, { parse_mode: \"MarkdownV2\" });\n return;\n }\n\n await ctx.reply(presentStatusMessage(result, copy));\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to fetch system status\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerStatusCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"status\", async (ctx) => {\n await handleStatusCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { buildSessionsListView } from \"../sessions-menu.js\";\n\ninterface SessionsCommandContext {\n chat: { id: number };\n reply(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n}\n\nexport async function handleSessionsCommand(ctx: SessionsCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n await dependencies.pendingActionRepo.clear(ctx.chat.id);\n const view = await buildSessionsListView(ctx.chat.id, 0, dependencies);\n\n await ctx.reply(view.text, view.keyboard ? { reply_markup: view.keyboard } : undefined);\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to list sessions\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerSessionsCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"sessions\", async (ctx) => {\n await handleSessionsCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import { BOT_COPY, type BotCopy } from \"../copy.js\";\n\nexport function presentStartMarkdownMessage(copy: BotCopy = BOT_COPY): string {\n return copy.start.lines.join(\"\\n\");\n}\n","import type { Bot } from \"grammy\";\nimport { buildTelegramStaticReply } from \"../../services/telegram/telegram-format.js\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { presentStartMarkdownMessage } from \"../presenters/static.presenter.js\";\nimport type { BotDependencies } from \"../types.js\";\n\ninterface StartCommandContext {\n chat?: { id: number };\n reply(\n text: string,\n other?: {\n parse_mode: \"MarkdownV2\";\n },\n ): Promise<unknown>;\n}\n\nexport async function handleStartCommand(ctx: StartCommandContext, dependencies: BotDependencies) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat?.id, dependencies.logger);\n const reply = buildTelegramStaticReply(presentStartMarkdownMessage(copy));\n\n try {\n await ctx.reply(reply.preferred.text, reply.preferred.options);\n } catch (error) {\n if (reply.preferred.options) {\n dependencies.logger.error({ error }, \"failed to send start markdown reply, falling back to plain text\");\n await ctx.reply(reply.fallback.text);\n return;\n }\n\n dependencies.logger.error({ error }, \"failed to show start message\");\n await ctx.reply(presentError(error, copy));\n }\n}\n\nexport function registerStartCommand(bot: Pick<Bot, \"command\">, dependencies: BotDependencies) {\n bot.command(\"start\", async (ctx) => {\n await handleStartCommand(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport type { PermissionApprovalRepository } from \"../../domain/permission/approval.repository.js\";\nimport {\n getSafeChatCopy,\n getSafeChatLanguage,\n} from \"../i18n.js\";\nimport { presentLanguageSwitchForChat } from \"../commands/language.js\";\nimport type {\n AgentsCallbackData,\n BotDependencies,\n LanguageCallbackData,\n ModelCallbackData,\n PermissionApprovalCallbackData,\n SessionsCallbackData,\n} from \"../types.js\";\nimport {\n buildAgentsKeyboard,\n buildLanguageKeyboard,\n buildModelsKeyboard,\n buildModelVariantsKeyboard,\n} from \"../presenters/keyboard.presenter.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport {\n getModelVariants,\n presentAgentsMessage,\n presentAgentSwitchMessage,\n presentLanguageMessage,\n presentModelsMessage,\n presentModelSwitchMessage,\n presentModelVariantsMessage,\n presentSessionRenamePromptMessage,\n presentSessionSwitchMessage,\n} from \"../presenters/message.presenter.js\";\nimport {\n buildSessionActionView,\n buildSessionsListView,\n} from \"../sessions-menu.js\";\nimport type { OpenCodeClientLike } from \"../../services/opencode/opencode.client.js\";\nimport {\n buildPermissionApprovalResolvedMessage,\n parsePermissionApprovalCallbackData,\n} from \"../../services/permission/telegram-approval.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\n\nconst AGENTS_PAGE_PREFIX = \"agents:page:\";\nconst AGENTS_SELECT_PREFIX = \"agents:select:\";\nconst SESSIONS_PAGE_PREFIX = \"sessions:page:\";\nconst SESSIONS_PICK_PREFIX = \"sessions:pick:\";\nconst SESSIONS_SWITCH_PREFIX = \"sessions:switch:\";\nconst SESSIONS_RENAME_PREFIX = \"sessions:rename:\";\nconst SESSIONS_BACK_PREFIX = \"sessions:back:\";\nconst MODEL_PAGE_PREFIX = \"model:page:\";\nconst MODEL_PICK_PREFIX = \"model:pick:\";\nconst MODEL_VARIANT_PREFIX = \"model:variant:\";\nconst LANGUAGE_SELECT_PREFIX = \"language:select:\";\nconst PERMISSION_PREFIX = \"permission:\";\n\ntype PermissionApprovalDependencies = BotDependencies & {\n opencodeClient: OpenCodeClientLike;\n permissionApprovalRepo: PermissionApprovalRepository;\n};\n\ninterface CallbackContext {\n chat?: { id: number };\n callbackQuery: { data: string; message?: { message_id: number } };\n answerCallbackQuery(): Promise<unknown>;\n editMessageText(text: string, other?: { reply_markup?: unknown }): Promise<unknown>;\n api?: Pick<Bot[\"api\"], \"setMyCommands\">;\n}\n\nexport async function handleAgentsCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as AgentsCallbackData;\n\n if (!data.startsWith(\"agents:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (data.startsWith(AGENTS_PAGE_PREFIX)) {\n const requestedPage = Number(data.slice(AGENTS_PAGE_PREFIX.length));\n const result = await dependencies.listAgentsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.agents.length === 0) {\n await ctx.editMessageText(copy.agents.none);\n return;\n }\n\n const { keyboard, page } = buildAgentsKeyboard(result.agents, requestedPage, copy);\n\n await ctx.editMessageText(\n presentAgentsMessage({\n agents: result.agents,\n currentAgentName: result.currentAgentName,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n\n return;\n }\n\n if (data.startsWith(AGENTS_SELECT_PREFIX)) {\n const agentIndex = Number(data.slice(AGENTS_SELECT_PREFIX.length));\n const result = await dependencies.listAgentsUseCase.execute({\n chatId: ctx.chat.id,\n });\n const agent = result.agents[agentIndex - 1];\n\n if (!agent) {\n await ctx.editMessageText(copy.agents.expired);\n return;\n }\n\n const switchResult = await dependencies.switchAgentUseCase.execute({\n chatId: ctx.chat.id,\n agentName: agent.name,\n });\n\n if (!switchResult.found) {\n await ctx.editMessageText(copy.agents.expired);\n return;\n }\n\n await ctx.editMessageText(presentAgentSwitchMessage(switchResult.agent, copy));\n }\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle agent callback\");\n await ctx.editMessageText(presentError(error, copy));\n }\n}\n\nexport async function handleModelsCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as ModelCallbackData;\n\n if (!data.startsWith(\"model:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (data.startsWith(MODEL_PAGE_PREFIX)) {\n const requestedPage = Number(data.slice(MODEL_PAGE_PREFIX.length));\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n\n if (result.models.length === 0) {\n await ctx.editMessageText(copy.models.none);\n return;\n }\n\n const { keyboard, page } = buildModelsKeyboard(result.models, requestedPage, copy);\n\n await ctx.editMessageText(\n presentModelsMessage({\n currentModelId: result.currentModelId,\n currentModelProviderId: result.currentModelProviderId,\n currentModelVariant: result.currentModelVariant,\n models: result.models,\n page: page.page,\n }, copy),\n {\n reply_markup: keyboard,\n },\n );\n\n return;\n }\n\n if (data.startsWith(MODEL_PICK_PREFIX)) {\n const modelIndex = Number(data.slice(MODEL_PICK_PREFIX.length));\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n const model = result.models[modelIndex - 1];\n\n if (!model) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n const variants = getModelVariants(model);\n\n if (variants.length === 0) {\n const switchResult = await dependencies.switchModelUseCase.execute({\n chatId: ctx.chat.id,\n providerId: model.providerID,\n modelId: model.id,\n });\n\n if (!switchResult.found) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n await ctx.editMessageText(presentModelSwitchMessage(switchResult.model, switchResult.variant, copy));\n return;\n }\n\n await ctx.editMessageText(\n presentModelVariantsMessage(model, modelIndex, copy),\n {\n reply_markup: buildModelVariantsKeyboard(variants, modelIndex),\n },\n );\n\n return;\n }\n\n if (data.startsWith(MODEL_VARIANT_PREFIX)) {\n const suffix = data.slice(MODEL_VARIANT_PREFIX.length);\n const [modelIndexRaw, variantIndexRaw] = suffix.split(\":\");\n const modelIndex = Number(modelIndexRaw);\n const variantIndex = Number(variantIndexRaw);\n const result = await dependencies.listModelsUseCase.execute({\n chatId: ctx.chat.id,\n });\n const model = result.models[modelIndex - 1];\n\n if (!model) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n const variants = getModelVariants(model);\n const variant = variants[variantIndex - 1];\n\n if (!variant) {\n await ctx.editMessageText(copy.models.reasoningLevelExpired);\n return;\n }\n\n const switchResult = await dependencies.switchModelUseCase.execute({\n chatId: ctx.chat.id,\n providerId: model.providerID,\n modelId: model.id,\n variant,\n });\n\n if (!switchResult.found) {\n await ctx.editMessageText(copy.models.expired);\n return;\n }\n\n await ctx.editMessageText(presentModelSwitchMessage(switchResult.model, switchResult.variant, copy));\n }\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle model callback\");\n await ctx.editMessageText(presentError(error, copy));\n }\n}\n\nexport async function handleSessionsCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as SessionsCallbackData;\n\n if (!data.startsWith(\"sessions:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (data.startsWith(SESSIONS_PAGE_PREFIX)) {\n const requestedPage = Number(data.slice(SESSIONS_PAGE_PREFIX.length));\n const view = await buildSessionsListView(ctx.chat.id, requestedPage, dependencies);\n\n await ctx.editMessageText(view.text, view.keyboard ? { reply_markup: view.keyboard } : undefined);\n\n return;\n }\n\n if (data.startsWith(SESSIONS_BACK_PREFIX)) {\n const requestedPage = Number(data.slice(SESSIONS_BACK_PREFIX.length));\n const view = await buildSessionsListView(ctx.chat.id, requestedPage, dependencies);\n\n await ctx.editMessageText(view.text, view.keyboard ? { reply_markup: view.keyboard } : undefined);\n return;\n }\n\n if (data.startsWith(SESSIONS_PICK_PREFIX)) {\n const target = parseSessionActionTarget(data, SESSIONS_PICK_PREFIX);\n\n if (!target) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n const view = await buildSessionActionView(\n ctx.chat.id,\n target.page,\n target.sessionId,\n dependencies,\n );\n\n if (!view.found) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n await ctx.editMessageText(view.text, {\n reply_markup: view.keyboard,\n });\n return;\n }\n\n if (data.startsWith(SESSIONS_SWITCH_PREFIX)) {\n const target = parseSessionActionTarget(data, SESSIONS_SWITCH_PREFIX);\n\n if (!target) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n const result = await dependencies.switchSessionUseCase.execute({\n chatId: ctx.chat.id,\n sessionId: target.sessionId,\n });\n\n if (!result.found) {\n await ctx.editMessageText(copy.sessions.expired);\n return;\n }\n\n await ctx.editMessageText(presentSessionSwitchMessage(result.session, copy));\n return;\n }\n\n if (data.startsWith(SESSIONS_RENAME_PREFIX)) {\n const target = parseSessionActionTarget(data, SESSIONS_RENAME_PREFIX);\n\n if (!target) {\n await ctx.editMessageText(copy.sessions.renameExpired);\n return;\n }\n\n const view = await buildSessionActionView(\n ctx.chat.id,\n target.page,\n target.sessionId,\n dependencies,\n );\n\n if (!view.found) {\n await ctx.editMessageText(copy.sessions.renameExpired);\n return;\n }\n\n const menuMessageId = ctx.callbackQuery.message?.message_id;\n\n if (typeof menuMessageId !== \"number\" || !Number.isInteger(menuMessageId)) {\n await ctx.editMessageText(copy.sessions.renameExpired);\n return;\n }\n\n await dependencies.pendingActionRepo.set({\n chatId: ctx.chat.id,\n kind: \"session_rename\",\n sessionId: view.session.id,\n menuMessageId,\n returnPage: view.page,\n updatedAt: new Date().toISOString(),\n });\n\n await ctx.editMessageText(presentSessionRenamePromptMessage(view.session, copy));\n }\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle session callback\");\n await ctx.editMessageText(presentError(error, copy));\n }\n}\n\nexport async function handleLanguageCallback(ctx: CallbackContext, dependencies: BotDependencies) {\n const data = ctx.callbackQuery.data as LanguageCallbackData;\n\n if (!data.startsWith(\"language:\")) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat || !ctx.api) {\n return;\n }\n\n const currentCopy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n\n try {\n if (!data.startsWith(LANGUAGE_SELECT_PREFIX)) {\n await ctx.editMessageText(\n presentLanguageMessage(\n await getSafeChatLanguage(dependencies.sessionRepo, ctx.chat.id, dependencies.logger),\n currentCopy,\n ),\n {\n reply_markup: buildLanguageKeyboard(\n await getSafeChatLanguage(dependencies.sessionRepo, ctx.chat.id, dependencies.logger),\n currentCopy,\n ),\n },\n );\n return;\n }\n\n const selectedLanguage = data.slice(LANGUAGE_SELECT_PREFIX.length);\n const result = await presentLanguageSwitchForChat(ctx.chat.id, ctx.api, selectedLanguage, dependencies);\n\n await ctx.editMessageText(result.text, {\n reply_markup: result.keyboard,\n });\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle language callback\");\n await ctx.editMessageText(presentError(error, currentCopy));\n }\n}\n\nexport async function handlePermissionApprovalCallback(\n ctx: CallbackContext,\n dependencies: PermissionApprovalDependencies,\n) {\n const data = ctx.callbackQuery.data as PermissionApprovalCallbackData;\n\n if (!data.startsWith(PERMISSION_PREFIX)) {\n return;\n }\n\n await ctx.answerCallbackQuery();\n\n if (!ctx.chat) {\n return;\n }\n\n const parsed = parsePermissionApprovalCallbackData(data);\n\n if (!parsed) {\n return;\n }\n\n try {\n const approvals = await dependencies.permissionApprovalRepo.listByRequestId(parsed.requestId);\n const approval = approvals.find((item) => item.chatId === ctx.chat?.id);\n\n await dependencies.opencodeClient.replyToPermission(\n parsed.requestId,\n parsed.reply,\n undefined,\n approval?.sessionId,\n );\n\n if (approval) {\n await dependencies.permissionApprovalRepo.set({\n ...approval,\n status: parsed.reply,\n updatedAt: new Date().toISOString(),\n });\n }\n\n await ctx.editMessageText(buildPermissionApprovalResolvedMessage(parsed.requestId, parsed.reply));\n } catch (error) {\n dependencies.logger.error({ error, requestId: parsed.requestId }, \"failed to reply to permission request\");\n await ctx.editMessageText(\"Failed to reply to the permission request.\");\n }\n}\n\nexport function registerCallbackHandler(bot: Pick<Bot, \"callbackQuery\">, dependencies: PermissionApprovalDependencies) {\n bot.callbackQuery(/^agents:/, async (ctx) => {\n await handleAgentsCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^sessions:/, async (ctx) => {\n await handleSessionsCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^model:/, async (ctx) => {\n await handleModelsCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^language:/, async (ctx) => {\n await handleLanguageCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.callbackQuery(/^permission:/, async (ctx) => {\n await handlePermissionApprovalCallback(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n\nfunction parseSessionActionTarget(data: string, prefix: string) {\n const suffix = data.slice(prefix.length);\n const separatorIndex = suffix.indexOf(\":\");\n\n if (separatorIndex === -1) {\n return null;\n }\n\n const page = Number(suffix.slice(0, separatorIndex));\n const sessionId = suffix.slice(separatorIndex + 1).trim();\n\n if (!Number.isInteger(page) || page < 0 || !sessionId) {\n return null;\n }\n\n return {\n page,\n sessionId,\n };\n}\n","import { getSafeChatCopy } from \"../i18n.js\";\nimport { presentError } from \"../presenters/error.presenter.js\";\nimport { buildTelegramPromptReply } from \"../../services/telegram/telegram-format.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport type { PromptSessionFilePartInput } from \"../../services/opencode/opencode.client.js\";\n\ninterface SentMessage {\n message_id: number;\n}\n\nexport interface PromptExecutionContext {\n chat: { id: number };\n api: {\n deleteMessage(chatId: number, messageId: number): Promise<unknown>;\n };\n reply(text: string, other?: { parse_mode?: \"MarkdownV2\" }): Promise<SentMessage>;\n}\n\nexport interface PromptExecutionInput {\n files?: PromptSessionFilePartInput[];\n text?: string | null;\n}\n\nexport async function executePromptRequest(\n ctx: PromptExecutionContext,\n dependencies: BotDependencies,\n resolvePrompt: () => Promise<PromptExecutionInput>,\n) {\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n const foregroundRequest = dependencies.foregroundSessionTracker.acquire(ctx.chat.id);\n\n if (!foregroundRequest) {\n await ctx.reply(copy.status.alreadyProcessing);\n return;\n }\n\n let processingMessage: SentMessage | null = null;\n let sentTerminalReply = false;\n\n try {\n processingMessage = await ctx.reply(copy.status.processing);\n\n const promptInput = await resolvePrompt();\n const result = await dependencies.sendPromptUseCase.execute({\n chatId: ctx.chat.id,\n files: promptInput.files,\n onExecutionSession: (sessionId: string) => {\n foregroundRequest.attachSession(sessionId);\n },\n signal: foregroundRequest.signal,\n text: promptInput.text,\n });\n const promptReply = normalizePromptReplyForDisplay(result.assistantReply, copy);\n const telegramReply = buildTelegramPromptReply(promptReply, copy);\n\n try {\n await ctx.reply(telegramReply.preferred.text, telegramReply.preferred.options);\n } catch (replyError) {\n dependencies.logger.warn?.(\n { error: replyError },\n \"failed to send preferred telegram reply, falling back to plain text\",\n );\n await ctx.reply(telegramReply.fallback.text, telegramReply.fallback.options);\n }\n sentTerminalReply = true;\n } catch (error) {\n dependencies.logger.error({ error }, \"failed to handle prompt request\");\n await ctx.reply(presentError(error, copy));\n sentTerminalReply = true;\n } finally {\n foregroundRequest.dispose();\n if (processingMessage && sentTerminalReply) {\n try {\n await ctx.api.deleteMessage(ctx.chat.id, processingMessage.message_id);\n } catch (error) {\n dependencies.logger.warn?.({ error }, \"failed to delete processing message\");\n }\n }\n }\n}\n\nfunction normalizePromptReplyForDisplay(\n promptReply: Awaited<ReturnType<BotDependencies[\"sendPromptUseCase\"][\"execute\"]>>[\"assistantReply\"],\n copy: Awaited<ReturnType<typeof getSafeChatCopy>>,\n) {\n if (!promptReply.assistantError) {\n return promptReply;\n }\n\n return {\n ...promptReply,\n bodyMd: null,\n fallbackText: presentError(promptReply.assistantError, copy),\n };\n}\n","import type { Bot } from \"grammy\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { executePromptRequest, type PromptExecutionContext } from \"./prompt.handler.js\";\nimport { replyIfSessionRenamePending } from \"../session-rename.js\";\nimport { ImageMessageUnsupportedError } from \"../../use-cases/upload-file.usecase.js\";\n\nconst TELEGRAM_MAX_DOWNLOAD_BYTES = 20 * 1024 * 1024;\n\ninterface TelegramPhotoSize {\n file_id: string;\n file_size?: number;\n}\n\ninterface TelegramDocument {\n file_id: string;\n file_name?: string;\n file_size?: number;\n mime_type?: string;\n}\n\ninterface FileContext extends PromptExecutionContext {\n getFile(): Promise<{ file_path?: string }>;\n message: {\n caption?: string;\n document?: TelegramDocument;\n photo?: TelegramPhotoSize[];\n };\n}\n\nexport async function handleImageMessage(ctx: FileContext, dependencies: BotDependencies) {\n const image = resolveTelegramImage(ctx.message);\n\n if (!image) {\n return;\n }\n\n if (await replyIfSessionRenamePending(ctx, dependencies)) {\n return;\n }\n\n await executePromptRequest(ctx, dependencies, async () => {\n if (typeof image.fileSize === \"number\" && image.fileSize > TELEGRAM_MAX_DOWNLOAD_BYTES) {\n throw new ImageMessageUnsupportedError(\n `Image file size ${image.fileSize} exceeds the Telegram download limit of ${TELEGRAM_MAX_DOWNLOAD_BYTES} bytes.`,\n );\n }\n\n const file = await ctx.getFile();\n const filePath = file.file_path?.trim();\n\n if (!filePath) {\n throw new ImageMessageUnsupportedError(\"Telegram did not provide a downloadable image file path.\");\n }\n\n const promptFile = await dependencies.uploadFileUseCase.execute({\n expectedType: \"image\",\n filePath,\n filename: image.filename,\n mimeType: image.mimeType,\n });\n\n return {\n files: [promptFile],\n text: ctx.message.caption?.trim() || null,\n };\n });\n}\n\nexport function registerFileHandler(bot: Pick<Bot, \"on\">, dependencies: BotDependencies) {\n bot.on(\"message:photo\", async (ctx) => {\n await handleImageMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n\n bot.on(\"message:document\", async (ctx) => {\n await handleImageMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n\nfunction resolveTelegramImage(message: FileContext[\"message\"]) {\n const document = message.document;\n\n if (document && isImageDocument(document)) {\n return {\n fileId: document.file_id,\n fileSize: document.file_size,\n filename: document.file_name ?? null,\n mimeType: document.mime_type ?? null,\n };\n }\n\n const photo = pickLargestPhoto(message.photo);\n\n if (!photo) {\n return null;\n }\n\n return {\n fileId: photo.file_id,\n fileSize: photo.file_size,\n filename: null,\n mimeType: \"image/jpeg\",\n };\n}\n\nfunction isImageDocument(document: TelegramDocument): boolean {\n const mimeType = document.mime_type?.trim().toLowerCase();\n const filename = document.file_name?.trim().toLowerCase() ?? \"\";\n\n return !!mimeType?.startsWith(\"image/\")\n || /\\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(filename);\n}\n\nfunction pickLargestPhoto(photos: TelegramPhotoSize[] | undefined): TelegramPhotoSize | null {\n if (!photos || photos.length === 0) {\n return null;\n }\n\n return photos.reduce<TelegramPhotoSize>((largest, current) => {\n const currentSize = current.file_size ?? 0;\n const largestSize = largest.file_size ?? 0;\n\n return currentSize >= largestSize ? current : largest;\n }, photos[0]);\n}\n","import type { Bot } from \"grammy\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { executePromptRequest, type PromptExecutionContext } from \"./prompt.handler.js\";\nimport { handlePendingSessionRenameText } from \"../session-rename.js\";\n\ninterface MessageContext extends PromptExecutionContext {\n api: PromptExecutionContext[\"api\"] & {\n editMessageText(\n chatId: number,\n messageId: number,\n text: string,\n other?: { reply_markup?: unknown },\n ): Promise<unknown>;\n };\n message: { text?: string };\n}\n\nexport async function handleTextMessage(ctx: MessageContext, dependencies: BotDependencies) {\n const text = ctx.message.text?.trim();\n\n if (await handlePendingSessionRenameText(ctx, dependencies)) return;\n if (!text) return;\n if (text.startsWith(\"/\")) return;\n await executePromptRequest(ctx, dependencies, async () => ({ text }));\n}\n\nexport function registerMessageHandler(bot: Pick<Bot, \"on\">, dependencies: BotDependencies) {\n bot.on(\"message:text\", async (ctx) => {\n await handleTextMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { Bot } from \"grammy\";\nimport { getSafeChatCopy } from \"../i18n.js\";\nimport { scopeDependenciesToTelegramContext } from \"../logger-context.js\";\nimport type { BotDependencies } from \"../types.js\";\nimport { replyIfSessionRenamePending } from \"../session-rename.js\";\n\ninterface VoiceContext {\n chat: { id: number };\n message: { voice?: unknown };\n reply(text: string): Promise<unknown>;\n}\n\nexport async function handleVoiceMessage(ctx: VoiceContext, dependencies: BotDependencies) {\n if (!ctx.message.voice) {\n return;\n }\n\n if (await replyIfSessionRenamePending(ctx, dependencies)) {\n return;\n }\n\n const copy = await getSafeChatCopy(dependencies.sessionRepo, ctx.chat.id, dependencies.logger);\n await ctx.reply(copy.errors.voiceUnsupported);\n}\n\nexport function registerVoiceHandler(bot: Pick<Bot, \"on\">, dependencies: BotDependencies) {\n bot.on(\"message:voice\", async (ctx) => {\n await handleVoiceMessage(ctx, scopeDependenciesToTelegramContext(dependencies, ctx, \"telegram\"));\n });\n}\n","import type { MiddlewareFn } from \"grammy\";\n\nexport function createAuthMiddleware(allowedChatIds: readonly number[]): MiddlewareFn {\n return async (ctx, next) => {\n if (allowedChatIds.length === 0) {\n return next();\n }\n\n const chatId = ctx.chat?.id;\n\n if (!chatId || !allowedChatIds.includes(chatId)) {\n await ctx.reply(\"Unauthorized chat.\");\n return;\n }\n\n return next();\n };\n}\n","import type { MiddlewareFn } from \"grammy\";\nimport {\n logTelegramUpdate,\n type AppLogger,\n} from \"../../infra/logger/index.js\";\nimport { buildTelegramLoggerContext } from \"../logger-context.js\";\n\ninterface LoggingContextLike {\n chat?: { id?: number };\n from?: { id?: number };\n msg?: { text?: string } | null;\n update: { update_id: number };\n}\n\nexport function buildIncomingUpdateLogFields(ctx: LoggingContextLike) {\n const messageText = ctx.msg && \"text\" in ctx.msg\n ? ctx.msg.text\n : undefined;\n const loggerContext = buildTelegramLoggerContext(ctx);\n\n return {\n ...loggerContext,\n event: \"telegram.update.received\",\n updateId: ctx.update.update_id,\n chatId: ctx.chat?.id,\n fromId: ctx.from?.id,\n hasText: typeof messageText === \"string\" && messageText.length > 0,\n textLength: typeof messageText === \"string\" ? messageText.length : 0,\n };\n}\n\nexport function createLoggingMiddleware(logger: Pick<AppLogger, \"info\">): MiddlewareFn {\n return async (ctx, next) => {\n logTelegramUpdate(logger as AppLogger, {\n ...buildIncomingUpdateLogFields(ctx),\n }, \"incoming update\");\n\n return next();\n };\n}\n","import type { Bot } from \"grammy\";\nimport type { PermissionApprovalRepository } from \"../domain/permission/approval.repository.js\";\nimport type { OpenCodeClientLike } from \"../services/opencode/opencode.client.js\";\nimport { registerAgentsCommand } from \"./commands/agents.js\";\nimport { registerCancelCommand } from \"./commands/cancel.js\";\nimport { registerLanguageCommand } from \"./commands/language.js\";\nimport { registerModelsCommand } from \"./commands/models.js\";\nimport { registerNewCommand } from \"./commands/new.js\";\nimport { registerStatusCommand } from \"./commands/status.js\";\nimport type { BotDependencies } from \"./types.js\";\nimport { registerSessionsCommand } from \"./commands/sessions.js\";\nimport { registerStartCommand } from \"./commands/start.js\";\nimport { registerCallbackHandler } from \"./handlers/callback.handler.js\";\nimport { registerFileHandler } from \"./handlers/file.handler.js\";\nimport { registerMessageHandler } from \"./handlers/message.handler.js\";\nimport { registerVoiceHandler } from \"./handlers/voice.handler.js\";\nimport { createAuthMiddleware } from \"./middlewares/auth.js\";\nimport { createLoggingMiddleware } from \"./middlewares/logging.js\";\nimport {\n extractTelegramUpdateContext,\n replyWithDefaultTelegramError,\n} from \"./error-boundary.js\";\nimport { scopeLoggerToTelegramContext } from \"./logger-context.js\";\n\nexport interface RegisterBotOptions {\n telegramAllowedChatIds: number[];\n}\n\nexport function registerBot(\n bot: Bot,\n container: BotDependencies & {\n opencodeClient: OpenCodeClientLike;\n permissionApprovalRepo: PermissionApprovalRepository;\n },\n options: RegisterBotOptions,\n) {\n bot.use(createLoggingMiddleware(container.logger));\n bot.use(createAuthMiddleware(options.telegramAllowedChatIds));\n\n const safeBot = bot.errorBoundary(async (error) => {\n const scopedLogger = scopeLoggerToTelegramContext(container.logger, error.ctx, \"telegram\");\n\n scopedLogger.error(\n {\n ...extractTelegramUpdateContext(error.ctx),\n event: \"telegram.middleware.failed\",\n error: error.error,\n },\n \"telegram middleware failed\",\n );\n await replyWithDefaultTelegramError(error.ctx, scopedLogger, error.error);\n });\n\n registerStartCommand(safeBot, container);\n registerStatusCommand(safeBot, container);\n registerNewCommand(safeBot, container);\n registerAgentsCommand(safeBot, container);\n registerSessionsCommand(safeBot, container);\n registerCancelCommand(safeBot, container);\n registerModelsCommand(safeBot, container);\n registerLanguageCommand(safeBot, container);\n registerCallbackHandler(safeBot, container);\n registerFileHandler(safeBot, container);\n registerMessageHandler(safeBot, container);\n registerVoiceHandler(safeBot, container);\n}\n","import { run } from \"@grammyjs/runner\";\nimport { Bot, GrammyError, HttpError } from \"grammy\";\nimport { syncTelegramCommands } from \"../bot/commands/sync-commands.js\";\nimport { extractTelegramUpdateContext } from \"../bot/error-boundary.js\";\nimport { registerBot } from \"../bot/index.js\";\nimport type { AppConfig } from \"./config.js\";\nimport type { AppContainer } from \"./container.js\";\n\nexport interface StartTelegramBotRuntimeInput {\n botFactory?: (token: string, options: ConstructorParameters<typeof Bot>[1]) => Bot;\n config: AppConfig;\n container: AppContainer;\n registerBotHandlers?: typeof registerBot;\n runBot?: typeof run;\n syncCommands?: boolean;\n syncCommandsHandler?: typeof syncTelegramCommands;\n}\n\nexport interface TelegramBotRuntime {\n bot: Bot;\n container: AppContainer;\n stop(): void;\n dispose(): Promise<void>;\n}\n\ninterface TelegramBotRuntimeRegistry {\n activeByKey: Map<string, Promise<TelegramBotRuntime>>;\n}\n\nconst TELEGRAM_RUNNER_OPTIONS = {\n runner: {\n fetch: {\n timeout: 30,\n },\n maxRetryTime: 15 * 60 * 1000,\n retryInterval: \"exponential\" as const,\n silent: true,\n },\n};\n\nexport async function startTelegramBotRuntime(\n input: StartTelegramBotRuntimeInput,\n): Promise<TelegramBotRuntime> {\n const runtimeKey = buildTelegramRuntimeKey(input.config);\n const registry = getTelegramBotRuntimeRegistry();\n const existingRuntime = registry.activeByKey.get(runtimeKey);\n const runtimeLogger = input.container.logger.child({\n component: \"runtime\",\n });\n\n if (existingRuntime) {\n runtimeLogger.warn(\n {\n event: \"runtime.reused\",\n runtimeKey,\n telegramApiRoot: input.config.telegramApiRoot,\n },\n \"telegram runtime already active in this process; reusing the existing runner\",\n );\n await input.container.dispose();\n return existingRuntime;\n }\n\n const runtimePromise = startTelegramBotRuntimeInternal(\n input,\n runtimeKey,\n () => {\n if (registry.activeByKey.get(runtimeKey) === runtimePromise) {\n registry.activeByKey.delete(runtimeKey);\n }\n },\n ).catch((error) => {\n if (registry.activeByKey.get(runtimeKey) === runtimePromise) {\n registry.activeByKey.delete(runtimeKey);\n }\n\n throw error;\n });\n\n registry.activeByKey.set(runtimeKey, runtimePromise);\n\n return runtimePromise;\n}\n\nasync function startTelegramBotRuntimeInternal(\n input: StartTelegramBotRuntimeInput,\n runtimeKey: string,\n releaseRuntime: () => void,\n): Promise<TelegramBotRuntime> {\n const botFactory = input.botFactory ?? ((token, options) => new Bot(token, options));\n const bot = botFactory(input.config.telegramBotToken, {\n client: {\n apiRoot: input.config.telegramApiRoot,\n },\n });\n const runtimeLogger = input.container.logger.child({\n component: \"runtime\",\n });\n\n wrapTelegramGetUpdates(bot, input.container);\n const registerBotHandlers = input.registerBotHandlers ?? registerBot;\n registerBotHandlers(bot, input.container, {\n telegramAllowedChatIds: input.config.telegramAllowedChatIds,\n });\n\n bot.catch((error) => {\n const metadata = extractTelegramUpdateContext(error.ctx);\n const telegramLogger = input.container.logger.child({\n component: \"telegram\",\n ...metadata,\n });\n\n if (error.error instanceof GrammyError) {\n telegramLogger.error(\n {\n event: \"telegram.api.error\",\n errorCode: error.error.error_code,\n description: error.error.description,\n method: error.error.method,\n parameters: error.error.parameters,\n payload: error.error.payload,\n },\n \"telegram bot api request failed\",\n );\n return;\n }\n\n if (error.error instanceof HttpError) {\n telegramLogger.error(\n {\n event: \"telegram.http.error\",\n error: error.error.error,\n message: error.error.message,\n },\n \"telegram bot network request failed\",\n );\n return;\n }\n\n telegramLogger.error(\n {\n event: \"telegram.update.failed\",\n error: error.error,\n },\n \"telegram bot update failed\",\n );\n });\n\n runtimeLogger.info(\n {\n event: \"runtime.polling.starting\",\n runtimeKey,\n },\n \"telegram bot polling starting\",\n );\n const runBot = input.runBot ?? run;\n const runner = runBot(bot, TELEGRAM_RUNNER_OPTIONS);\n let stopped = false;\n let disposed = false;\n\n if (input.syncCommands ?? true) {\n const syncCommandsHandler = input.syncCommandsHandler ?? syncTelegramCommands;\n\n void syncCommandsHandler(bot, input.container.logger).catch((error) => {\n runtimeLogger.warn(\n {\n event: \"runtime.commands.sync_failed\",\n error,\n runtimeKey,\n },\n \"failed to sync telegram commands; polling continues without command registration updates\",\n );\n });\n }\n\n let stopPromise: Promise<void> | null = null;\n const requestStop = async () => {\n if (stopped) {\n return;\n }\n\n stopped = true;\n stopPromise = runner.stop().catch((error) => {\n runtimeLogger.warn(\n {\n event: \"runtime.stop.failed\",\n error,\n runtimeKey,\n },\n \"failed to stop telegram runner cleanly\",\n );\n });\n\n await stopPromise;\n };\n const stop = () => {\n void requestStop();\n };\n const dispose = async () => {\n if (disposed) {\n return;\n }\n\n disposed = true;\n try {\n await requestStop();\n await input.container.dispose();\n } finally {\n releaseRuntime();\n }\n };\n\n return {\n bot,\n container: input.container,\n stop,\n dispose,\n };\n}\n\nfunction wrapTelegramGetUpdates(bot: Bot, container: AppContainer): void {\n const originalGetUpdates = bot.api.getUpdates.bind(bot.api);\n const runtimeLogger = container.logger.child({\n component: \"runtime\",\n });\n\n bot.api.getUpdates = async (options, signal) => {\n const requestOptions = options ?? {\n limit: 100,\n offset: 0,\n timeout: 30,\n };\n\n try {\n return await originalGetUpdates(requestOptions, signal);\n } catch (error) {\n runtimeLogger.warn(\n {\n event: \"runtime.telegram.get_updates_failed\",\n error,\n limit: requestOptions.limit,\n offset: requestOptions.offset,\n timeout: requestOptions.timeout,\n },\n \"telegram getUpdates failed\",\n );\n throw error;\n }\n };\n}\n\nfunction buildTelegramRuntimeKey(config: AppConfig): string {\n return `${config.telegramApiRoot}::${config.telegramBotToken}`;\n}\n\nfunction getTelegramBotRuntimeRegistry(): TelegramBotRuntimeRegistry {\n const globalScope = globalThis as typeof globalThis & {\n __opencodeTbotTelegramRuntimeRegistry__?: TelegramBotRuntimeRegistry;\n };\n\n globalScope.__opencodeTbotTelegramRuntimeRegistry__ ??= {\n activeByKey: new Map(),\n };\n\n return globalScope.__opencodeTbotTelegramRuntimeRegistry__;\n}\n\nexport function resetTelegramBotRuntimeRegistryForTests(): void {\n const globalScope = globalThis as typeof globalThis & {\n __opencodeTbotTelegramRuntimeRegistry__?: TelegramBotRuntimeRegistry;\n };\n\n globalScope.__opencodeTbotTelegramRuntimeRegistry__ = {\n activeByKey: new Map(),\n };\n}\n","import type { Hooks, Plugin, PluginInput } from \"@opencode-ai/plugin\";\nimport { bootstrapPluginApp } from \"./app/bootstrap.js\";\nimport { handleTelegramBotPluginEvent } from \"./app/plugin-events.js\";\nimport {\n preparePluginConfiguration,\n type PreparedPluginConfiguration,\n} from \"./app/plugin-config.js\";\nimport {\n startTelegramBotRuntime,\n type StartTelegramBotRuntimeInput,\n type TelegramBotRuntime,\n} from \"./app/runtime.js\";\nimport type { PluginConfigSource } from \"./app/config.js\";\nimport type { OpenCodeSdkClientLike } from \"./services/opencode/opencode.client.js\";\n\nexport interface OpenCodePluginContextLike {\n client?: OpenCodeSdkClientLike;\n directory?: string | null;\n worktree?: string | null;\n}\n\nexport interface EnsureTelegramBotPluginRuntimeOptions {\n context?: OpenCodePluginContextLike | null;\n config?: PluginConfigSource;\n bootstrapApp?: typeof bootstrapPluginApp;\n prepareConfiguration?: (input: {\n cwd: string;\n config?: PluginConfigSource;\n }) => Promise<PreparedPluginConfiguration>;\n startRuntime?: (input: StartTelegramBotRuntimeInput) => Promise<TelegramBotRuntime>;\n}\n\ninterface TelegramBotPluginRuntimeState {\n cwd: string;\n runtime: TelegramBotRuntime | null;\n runtimePromise: Promise<TelegramBotRuntime>;\n}\n\ninterface TelegramBotPluginRuntimeStateHolder {\n state: TelegramBotPluginRuntimeState | null;\n}\n\nexport async function ensureTelegramBotPluginRuntime(\n options: EnsureTelegramBotPluginRuntimeOptions,\n): Promise<TelegramBotRuntime> {\n const runtimeStateHolder = getTelegramBotPluginRuntimeStateHolder();\n const explicitCwd = resolveExplicitPluginRuntimeCwd(options.context);\n\n if (runtimeStateHolder.state && explicitCwd === null) {\n return runtimeStateHolder.state.runtimePromise;\n }\n\n if (runtimeStateHolder.state && explicitCwd !== null && runtimeStateHolder.state.cwd !== explicitCwd) {\n const activeState = runtimeStateHolder.state;\n runtimeStateHolder.state = null;\n await disposeTelegramBotPluginRuntimeState(activeState);\n }\n\n if (!runtimeStateHolder.state) {\n const runtimePromise = startPluginRuntime(\n options,\n resolvePluginRuntimeCwd(options.context),\n requirePluginClient(options.context),\n )\n .then((runtime) => {\n if (runtimeStateHolder.state?.runtimePromise === runtimePromise) {\n runtimeStateHolder.state.runtime = runtime;\n }\n\n return runtime;\n })\n .catch((error) => {\n if (runtimeStateHolder.state?.runtimePromise === runtimePromise) {\n runtimeStateHolder.state = null;\n }\n\n throw error;\n });\n\n runtimeStateHolder.state = {\n cwd: explicitCwd ?? resolvePluginRuntimeCwd(options.context),\n runtime: null,\n runtimePromise,\n };\n }\n\n return runtimeStateHolder.state.runtimePromise;\n}\n\nexport const TelegramBotPlugin: Plugin = async (context) => {\n const runtime = await ensureTelegramBotPluginRuntime({\n context: context as OpenCodePluginContextLike | undefined,\n });\n\n return createHooks(runtime);\n};\n\nexport async function resetTelegramBotPluginRuntimeForTests() {\n const runtimeStateHolder = getTelegramBotPluginRuntimeStateHolder();\n\n if (!runtimeStateHolder.state) {\n return;\n }\n\n const activeState = runtimeStateHolder.state;\n runtimeStateHolder.state = null;\n await disposeTelegramBotPluginRuntimeState(activeState);\n}\n\nexport default TelegramBotPlugin;\n\nasync function startPluginRuntime(\n options: EnsureTelegramBotPluginRuntimeOptions,\n cwd: string,\n client: OpenCodeSdkClientLike,\n): Promise<TelegramBotRuntime> {\n const bootstrapApp = options.bootstrapApp ?? bootstrapPluginApp;\n const prepareConfiguration = options.prepareConfiguration ?? preparePluginConfiguration;\n const startRuntime = options.startRuntime ?? startTelegramBotRuntime;\n const preparedConfiguration = await prepareConfiguration({\n cwd,\n config: options.config,\n });\n const { config, container } = bootstrapApp(\n client,\n preparedConfiguration.config,\n { cwd: preparedConfiguration.cwd },\n );\n\n try {\n if (preparedConfiguration.ignoredProjectConfigFilePath) {\n container.logger.child({ component: \"runtime\" }).warn(\n {\n cwd: preparedConfiguration.cwd,\n event: \"runtime.config.legacy_worktree_ignored\",\n ignoredProjectConfigFilePath: preparedConfiguration.ignoredProjectConfigFilePath,\n globalConfigFilePath: preparedConfiguration.globalConfigFilePath,\n },\n \"legacy worktree plugin config is ignored; migrate settings to the global opencode-tbot config\",\n );\n }\n\n const runtime = await startRuntime({ config, container });\n\n container.logger.child({ component: \"runtime\" }).info(\n {\n cwd: preparedConfiguration.cwd,\n event: \"runtime.plugin.started\",\n globalConfigFilePath: preparedConfiguration.globalConfigFilePath,\n ignoredProjectConfigFilePath: preparedConfiguration.ignoredProjectConfigFilePath,\n configFilePath: preparedConfiguration.configFilePath,\n mode: \"plugin\",\n },\n \"telegram bot plugin runtime started\",\n );\n\n return runtime;\n } catch (error) {\n await container.dispose();\n throw error;\n }\n}\n\nfunction resolvePluginRuntimeCwd(context?: OpenCodePluginContextLike | null): string {\n return resolveExplicitPluginRuntimeCwd(context) ?? process.cwd();\n}\n\nfunction resolveExplicitPluginRuntimeCwd(context?: OpenCodePluginContextLike | null): string | null {\n return normalizePluginRuntimePath(context?.worktree)\n ?? normalizePluginRuntimePath(context?.directory);\n}\n\nfunction requirePluginClient(context?: OpenCodePluginContextLike | null): OpenCodeSdkClientLike {\n if (context?.client) {\n return context.client;\n }\n\n throw new Error(\"OpenCode plugin context.client is required.\");\n}\n\nfunction normalizePluginRuntimePath(value: string | null | undefined): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n\n const normalized = value.trim();\n\n return normalized.length > 0\n ? normalized\n : null;\n}\n\nasync function disposeTelegramBotPluginRuntimeState(\n state: TelegramBotPluginRuntimeState,\n): Promise<void> {\n const runtime = state.runtime ?? await state.runtimePromise.catch(() => null);\n\n await runtime?.dispose();\n}\n\nfunction createHooks(runtime: TelegramBotRuntime): Hooks {\n return {\n async event({ event }) {\n await handleTelegramBotPluginEvent(runtime, event);\n },\n async \"permission.ask\"(input, output) {\n const bindings = await runtime.container.sessionRepo.listBySessionId(input.sessionID);\n const foregroundChatIds = runtime.container.foregroundSessionTracker.listChatIds(input.sessionID);\n\n if (bindings.length > 0 || foregroundChatIds.length > 0) {\n output.status = \"ask\";\n }\n },\n };\n}\n\nfunction getTelegramBotPluginRuntimeStateHolder(): TelegramBotPluginRuntimeStateHolder {\n const globalScope = globalThis as typeof globalThis & {\n __opencodeTbotPluginRuntimeState__?: TelegramBotPluginRuntimeStateHolder;\n };\n\n globalScope.__opencodeTbotPluginRuntimeState__ ??= {\n state: null,\n };\n\n return globalScope.__opencodeTbotPluginRuntimeState__;\n}\n"],"mappings":"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"}