@linxin666/dsh-client-ui-task-board 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +24 -0
- package/README.zh.md +24 -0
- package/lib/client.js +917 -81
- package/lib/client.js.map +1 -1
- package/lib/index.js +1774 -1420
- package/lib/types/client/TaskBoardSettingsCard.d.ts +4 -0
- package/lib/types/client/board/LinkSubtaskModal.d.ts +11 -0
- package/lib/types/client/board/NewTaskModal.d.ts +7 -1
- package/lib/types/client/board/TaskCard.d.ts +11 -1
- package/lib/types/client/locales.d.ts +33 -0
- package/lib/types/core/controller.d.ts +30 -1
- package/lib/types/core/subtask.d.ts +122 -0
- package/lib/types/core/tasks.d.ts +46 -3
- package/lib/types/core/use-cases/task-archive.d.ts +10 -13
- package/lib/types/core/use-cases/task-create.d.ts +13 -4
- package/lib/types/core/use-cases/task-delete.d.ts +7 -1
- package/lib/types/core/use-cases/task-parent.d.ts +21 -0
- package/lib/types/core/use-cases/task-update.d.ts +1 -1
- package/lib/types/host/agent-tools.d.ts +27 -0
- package/lib/types/host-ledger.d.ts +88 -4
- package/lib/types/host-runner.d.ts +39 -1
- package/lib/types/host-service.d.ts +47 -0
- package/lib/types/index.d.ts +83 -5
- package/lib/types/protocol.d.ts +14 -0
- package/package.json +23 -21
- package/src/client/TaskBoardSettingsCard.tsx +48 -3
- package/src/client/board/LinkSubtaskModal.tsx +82 -0
- package/src/client/board/NewTaskModal.tsx +40 -6
- package/src/client/board/TaskBoard.tsx +88 -8
- package/src/client/board/TaskCard.tsx +52 -2
- package/src/client/board/TaskDetail.tsx +124 -1
- package/src/client/board.module.css +96 -0
- package/src/client/host-api.ts +14 -4
- package/src/client/index.ts +11 -1
- package/src/client/locales.ts +70 -2
- package/src/core/controller.ts +69 -8
- package/src/core/store.ts +15 -0
- package/src/core/subtask.ts +286 -0
- package/src/core/tasks.ts +50 -2
- package/src/core/use-cases/task-archive.ts +46 -12
- package/src/core/use-cases/task-create.ts +42 -7
- package/src/core/use-cases/task-delete.ts +11 -1
- package/src/core/use-cases/task-parent.ts +64 -0
- package/src/core/use-cases/task-update.ts +3 -1
- package/src/host/agent-tools.ts +643 -0
- package/src/host-ledger.ts +323 -45
- package/src/host-runner.ts +141 -12
- package/src/host-service.ts +127 -10
- package/src/index.ts +181 -9
- package/src/protocol.ts +26 -2
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["applyScheduleRollForward","css","css","css","css","css","css","css","mountSidebarEntry","mountSharedSidebarEntry","css"],"sources":["../../../packages/dsh-task-board/src/core/tasks.ts","../../../packages/dsh-task-board/src/core/use-cases/task-archive.ts","../../../packages/dsh-task-board/src/core/schedule.ts","../../../packages/dsh-task-board/src/core/use-cases/task-create.ts","../../../packages/dsh-task-board/src/core/use-cases/task-delete.ts","../../../packages/dsh-task-board/src/core/use-cases/task-schedule.ts","../../../packages/dsh-task-board/src/core/use-cases/task-update.ts","../../../packages/dsh-task-board/src/core/controller.ts","../../../packages/dsh-task-board/src/client/main-session.ts","../../../packages/dsh-task-board/src/core/freeze-snapshot.ts","../../../packages/dsh-task-board/src/core/handover.ts","../../../packages/dsh-task-board/src/core/store.ts","../../../packages/dsh-task-board/src/client/apply-guard.ts","../../../packages/dsh-task-board/src/client/locales.ts","../../../packages/dsh-task-board/src/client/schedule-presets.ts","../../../packages/dsh-task-board/src/client/board/TaskForm.tsx","../../../packages/dsh-task-board/src/client/board/parse-model-pref.ts","../../../packages/dsh-task-board/src/client/board/NewTaskModal.tsx","../../../packages/dsh-task-board/src/client/board/status-key.ts","../../../packages/dsh-task-board/src/client/board/TaskCard.tsx","../../../packages/dsh-task-board/src/client/board/ConfirmDialog.tsx","../../../packages/dsh-task-board/src/client/board/EditTaskModal.tsx","../../../packages/dsh-task-board/src/client/board/TaskDetail.tsx","../../../packages/dsh-task-board/src/client/board/TaskBoard.tsx","../../../packages/dsh-task-board/src/client/body-mutations.ts","../../../packages/dsh-task-board/src/client/panel-mount-core.ts","../../../packages/dsh-task-board/src/client/board-mount.tsx","../../../packages/dsh-task-board/src/client/sidebar-entry-core.ts","../../../packages/dsh-task-board/src/client/sidebar-entry.ts","../../../packages/dsh-task-board/src/client/PluginSettingsCard.tsx","../../../packages/dsh-task-board/src/client/settings-form.ts","../../../packages/dsh-task-board/src/client/TaskBoardSettingsCard.tsx","../../../packages/dsh-task-board/src/protocol.ts","../../../packages/dsh-task-board/src/client/host-api.ts","../../../packages/dsh-task-board/src/client/telemetry.ts","../../../packages/dsh-task-board/src/client/plugin-card-seat.ts","../../../packages/dsh-task-board/src/client/index.ts"],"sourcesContent":["/**\n * Task board domain model: task lifecycle statuses, the task record shape,\n * and the pure transition functions the controller and tests share.\n * Framework-free (no cordis, no runtime imports) so the state machine is\n * unit-testable in isolation.\n */\nimport type { FreezeSnapshot } from './freeze-snapshot.ts'\nimport type { TaskHandover, TaskHandoverInput } from './handover.ts'\n\n/** Task lifecycle status, one per kanban column. */\nexport type TaskStatus = 'backlog' | 'todo' | 'running' | 'done' | 'failed'\n\n/**\n * One real execution attempt: the run's own id, the dsh session that ran it\n * (filled once the session is created), and the settled outcome once the\n * session's turn ended.\n */\nexport interface ExecutionRecord {\n /** Execution attempt id (uuid). */\n id: string\n /** The dsh session that ran this attempt; absent until creation resolves. */\n sessionId: string | undefined\n /** When the run started (ms epoch). */\n startedAt: number\n /** When the run settled; absent while still running. */\n endedAt: number | undefined\n /** Outcome once settled. */\n result: 'succeeded' | 'failed' | 'cancelled' | undefined\n /** Human failure text when the run failed (prompt rejection or agent error). */\n error: string | undefined\n /**\n * Session id of the DSH session that issued the run/rerun action (issue #6\n * audit origin). Client-asserted, not a trust boundary; absent when the run\n * was triggered by cron (source unknown).\n */\n initiatedBy?: string\n /** Freeze instant captured from the card snapshot when the run opened. */\n frozenAt?: number\n /** Freeze source session captured from the card snapshot when the run opened. */\n frozenBy?: string\n}\n\n/**\n * Maximum number of execution records retained per task. Older settled runs\n * are trimmed when a new execution starts so per-action ledger cost stays\n * bounded regardless of how often a task ran before.\n */\nexport const EXECUTION_HISTORY_LIMIT = 20\n\n/**\n * Trim an execution list to at most {@link EXECUTION_HISTORY_LIMIT} records,\n * most recent last. A running (unsettled) execution is never trimmed: the\n * Host monitor and restart recovery depend on the active record, and a task\n * cannot start a new run while one is still open.\n */\nexport function retainRecentExecutions(executions: readonly ExecutionRecord[]): ExecutionRecord[] {\n if (executions.length <= EXECUTION_HISTORY_LIMIT) return [...executions]\n const open = executions.filter(execution => execution.endedAt === undefined)\n const settled = executions.filter(execution => execution.endedAt !== undefined)\n const keepSettled = Math.max(EXECUTION_HISTORY_LIMIT - open.length, 0)\n return [...settled.slice(Math.max(settled.length - keepSettled, 0)), ...open]\n}\n\n/**\n * A scheduled-run rule attached to a task. The Host scheduler triggers the\n * task when `nextRunAt` is due and persists the rule in the Host ledger.\n */\nexport interface ScheduleRule {\n /** Whether the schedule is armed. */\n enabled: boolean\n /** 5-field cron expression: `分 时 日 月 周`. */\n cron: string\n /** Next due instant (ms epoch); maintained by the scheduler/controller. */\n nextRunAt: number | undefined\n /** Instant of the latest scheduled trigger (ms epoch). */\n lastTriggeredAt: number | undefined\n}\n\n/**\n * Frozen context snapshot carried by a continuation card (issue #4): the\n * goal/progress/next text (already sanitized by the freeze gates) plus the\n * freeze instant and the redaction warning flag.\n */\nexport interface TaskFreeze extends FreezeSnapshot {\n /** When the snapshot was frozen (ms epoch, stamped by the create/update use case). */\n frozenAt: number\n /** True when the freeze gates redacted sensitive patterns out of the text. */\n redacted?: boolean\n /**\n * Session id of the DSH session that authored the frozen snapshot (issue #6\n * provenance): stamped by the Host ledger from the create/update action's\n * initiator, or kept from the wire payload when no initiator was asserted.\n */\n frozenBy?: string\n}\n\n/**\n * One task label (issue #1521). The name is the badge and the tag-filter key;\n * the optional prompt line rides the execution prompt, so a label may be\n * display-only (no prefix) or carry an instruction (business-line routing,\n * output directory, house style) that every run of the task inherits.\n */\nexport interface TaskTag {\n /** Display name; trimmed, non-empty, unique within the task. */\n name: string\n /**\n * Prompt line injected ahead of the execution prompt. Absent (or blank\n * after trimming) keeps the tag display-only: it never touches the prompt,\n * so a label with no prefix has zero execution side effects.\n */\n promptPrefix?: string\n}\n\n/** Maximum number of tags carried by one task. */\nexport const TASK_TAG_LIMIT = 8\n/** Maximum length of a tag name. */\nexport const TAG_NAME_MAX_LENGTH = 32\n/** Maximum length of a tag's injected prompt line. */\nexport const TAG_PROMPT_MAX_LENGTH = 200\n\n/** Whether an unknown value is a well-formed tag (strict: the wire gate). */\nexport function isTaskTag(value: unknown): value is TaskTag {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const tag = value as Record<string, unknown>\n if (Object.keys(tag).some(key => key !== 'name' && key !== 'promptPrefix')) return false\n if (typeof tag.name !== 'string') return false\n const name = tag.name.trim()\n if (name === '' || name.length > TAG_NAME_MAX_LENGTH) return false\n if (tag.promptPrefix !== undefined && typeof tag.promptPrefix !== 'string') return false\n return tag.promptPrefix === undefined || (tag.promptPrefix as string).trim().length <= TAG_PROMPT_MAX_LENGTH\n}\n\n/**\n * Whether an unknown value is a well-formed tag list (strict: the wire gate).\n * An empty list is rejected — clearing tags is expressed by omitting the field\n * (create) or by an explicit null (update), never by an empty array.\n */\nexport function isTaskTagList(value: unknown): value is TaskTag[] {\n return Array.isArray(value) && value.length > 0 && value.length <= TASK_TAG_LIMIT && value.every(isTaskTag)\n}\n\n/**\n * Repair a persisted tag list: keep the well-formed entries, trim, drop\n * blanks and repeats, cap the count, and collapse a blank prompt line to\n * \"display-only\". Returns undefined when nothing usable remains, so the caller\n * clears the field instead of storing an empty array.\n */\nexport function normalizeTags(value: unknown): TaskTag[] | undefined {\n if (!Array.isArray(value)) return undefined\n const tags: TaskTag[] = []\n const seen = new Set<string>()\n for (const entry of value) {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) continue\n const row = entry as Record<string, unknown>\n if (typeof row.name !== 'string') continue\n const name = row.name.trim()\n if (name === '' || name.length > TAG_NAME_MAX_LENGTH || seen.has(name)) continue\n const raw = typeof row.promptPrefix === 'string' ? row.promptPrefix.trim() : ''\n const promptPrefix = raw === '' ? undefined : raw.slice(0, TAG_PROMPT_MAX_LENGTH)\n seen.add(name)\n tags.push(promptPrefix === undefined ? { name } : { name, promptPrefix })\n if (tags.length >= TASK_TAG_LIMIT) break\n }\n return tags.length === 0 ? undefined : tags\n}\n\n/**\n * Stable palette slot (0..5) for a tag name. The same label always lands on the\n * same tone, so a badge needs no stored colour and two tasks sharing a label\n * cannot disagree about it.\n */\nexport function tagTone(name: string): number {\n let hash = 0\n for (const char of name) hash = (hash * 31 + (char.codePointAt(0) ?? 0)) >>> 0\n return hash % 6\n}\n\n/**\n * Union of the labels already carried by `tasks`, first occurrence wins (the\n * oldest task's hint is the one offered). Feeds the editor's name datalist and\n * the board's tag filter, so a label defined once can be reused everywhere.\n */\nexport function collectKnownTags(tasks: readonly TaskRecord[]): TaskTag[] {\n const known: TaskTag[] = []\n const seen = new Set<string>()\n for (const task of tasks) {\n for (const tag of task.tags ?? []) {\n if (seen.has(tag.name)) continue\n seen.add(tag.name)\n known.push(tag)\n }\n }\n return known\n}\n\n/** One task on the board. */\nexport interface TaskRecord {\n /** Stable task id (uuid). */\n id: string\n /** Short display title. */\n title: string\n /** Longer human description shown in the detail view. */\n description: string\n /** The prompt sent to dsh when this task is executed. */\n prompt: string\n /** Current column. */\n status: TaskStatus\n /** Creation instant (ms epoch). */\n createdAt: number\n /** Last mutation instant (ms epoch). */\n updatedAt: number\n /**\n * Execution history retained on the task, most recent last: the latest\n * {@link EXECUTION_HISTORY_LIMIT} attempts, oldest trimmed on append.\n */\n executions: ExecutionRecord[]\n /** Optional scheduled-run rule (absent on tasks without a schedule). */\n schedule?: ScheduleRule\n /**\n * Workspace the execution must run in (a workspace-list id); absent means\n * the recent-workspace fallback at execution time.\n */\n workspaceId?: string\n /**\n * Agent preset the execution session must be composed from (an\n * `agentPreset.list` id); absent means the deployment default.\n */\n mode?: string\n /**\n * Permission preset applied to the execution session through the\n * `/permission <id>` slash command; absent leaves the session default.\n */\n permission?: TaskPermission\n /**\n * Pinned model selection for the execution session (format: \"provider/model\" or model id);\n * absent falls back to the host default (agent-default-model).\n */\n model?: string\n /**\n * Whether later executions continue in the previous execution's session\n * (issue #1419) instead of minting a fresh conversation per run. Absent or\n * false keeps the historical one-session-per-execution behavior; the reuse\n * itself only happens when that session is idle and still present (see\n * {@link reusableSessionId}).\n */\n reuseSession?: boolean\n /**\n * Frozen context snapshot for a continuation card; absent on plain tasks.\n * Sanitized before it enters the ledger (redaction, slash-command taint,\n * 8 KiB per-field cap) by the protocol gate and re-normalized on load.\n */\n freeze?: TaskFreeze\n /**\n * Handover bundle carried by a continuation card (issue #5): the pinned\n * execution triplet plus doc/script references. Sanitized before it\n * enters the ledger by the protocol gate and re-normalized on load; the\n * bundle's triplet overrides the legacy pin fields at execution time.\n */\n handover?: TaskHandover\n /**\n * Task labels (issue #1521): optional, additive, and absent on every task\n * created before the field existed. A tag whose `promptPrefix` is set is\n * prepended to the execution prompt; a bare name is display and filter only.\n */\n tags?: TaskTag[]\n /**\n * Human confirmation stamp for an above-default effective permission\n * (ms epoch). Absent while the binding awaits confirmation; any permission\n * or handover change re-arms the gate by clearing it.\n */\n permissionConfirmedAt?: number\n /**\n * When the task was archived (ms epoch). Archived tasks keep their status\n * and execution history, leave the main board, and cannot run until restored;\n * absent means on-board.\n */\n archivedAt?: number\n}\n\n/**\n * Statuses a task may be archived from: every status but `running`, whose\n * execution the runner still owns until it settles. A settled-only gate made\n * the duplicate-and-archive flow a silent no-op for scheduled tasks, which\n * return to `todo` after every successful run (issue #1447).\n */\nexport const ARCHIVABLE_STATUSES: readonly TaskStatus[] = ['backlog', 'todo', 'done', 'failed']\n\n\n/** Permission presets a task may pin on its execution session (the `/permission <id>` ids). */\nexport const TASK_PERMISSIONS = ['read-only', 'workspace-write', 'danger-full-access'] as const\n\n/** One permission preset id. */\nexport type TaskPermission = typeof TASK_PERMISSIONS[number]\n\n/** Whether an unknown value is a known permission preset id. */\nexport function isTaskPermission(value: unknown): value is TaskPermission {\n return typeof value === 'string' && (TASK_PERMISSIONS as readonly string[]).includes(value)\n}\n\n/** Input for creating a task. */\nexport interface NewTaskInput {\n title: string\n description: string\n prompt: string\n /** Workspace the execution must run in; empty/absent = the recent workspace. */\n workspaceId?: string\n /** Agent preset the execution session must be composed from; empty/absent = deployment default. */\n mode?: string\n /** Permission preset applied to the execution session; absent = session default. */\n permission?: TaskPermission\n /** Optional pinned model for the execution session; absent = host default. */\n model?: string\n /** Reuse the previous execution's session for later runs (issue #1419). */\n reuseSession?: boolean\n /**\n * Optional scheduled-run rule requested at creation time (the new-task\n * dialog): an enable flag plus a 5-field cron expression. The create use\n * case arms it only when enabled and the expression is valid.\n */\n schedule?: { enabled: boolean; cron: string }\n /**\n * Optional frozen context snapshot (goal/progress/next, sanitized by the\n * protocol gate) turning the new task into a continuation card.\n */\n freeze?: FreezeSnapshot & { redacted?: boolean; frozenBy?: string }\n /**\n * Optional handover bundle (pinned triplet + doc/script references,\n * sanitized by the protocol gate) attached at creation.\n */\n handover?: TaskHandoverInput\n /**\n * Optional task labels. A tag with a non-blank `promptPrefix` is injected\n * ahead of the execution prompt; a bare name changes nothing at run time.\n */\n tags?: TaskTag[]\n}\n\n/** The five kanban columns, in display order. */\nexport const COLUMNS: readonly { status: TaskStatus; label: string }[] = [\n { status: 'backlog', label: '待规划' },\n { status: 'todo', label: '待办' },\n { status: 'running', label: '进行中' },\n { status: 'done', label: '已完成' },\n { status: 'failed', label: '已失败' },\n]\n\n/** Statuses a user may move a card to manually (execution states are owned by the runner). */\nexport const MANUAL_STATUSES: readonly TaskStatus[] = ['backlog', 'todo']\n\n/** Statuses the runner may move a card to from 'running'. */\nexport const RUNNER_SETTLE_STATUSES: readonly TaskStatus[] = ['done', 'failed']\n\n/** All valid statuses (closed union guard). */\nexport const ALL_STATUSES: readonly TaskStatus[] = [\n 'backlog', 'todo', 'running', 'done', 'failed',\n]\n\n/** Brand an unknown string as a status; undefined when it is not one. */\nexport function isTaskStatus(value: unknown): value is TaskStatus {\n return typeof value === 'string' && (ALL_STATUSES as readonly string[]).includes(value)\n}\n\n/** Whether a manual move target is allowed from the given status. */\nexport function canMoveManually(from: TaskStatus, to: TaskStatus): boolean {\n return from !== 'running' && (MANUAL_STATUSES as readonly TaskStatus[]).includes(to)\n}\n\n/** Normalize one optional execution-target string: trim; blank collapses to undefined. */\nexport function normalizeTargetId(value: string | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed === undefined || trimmed === '' ? undefined : trimmed\n}\n\n/**\n * Build the persisted freeze snapshot from a sanitized input, stamping the\n * freeze instant (shared by the create and update use cases).\n */\nexport function freezeOf(\n input: FreezeSnapshot & { redacted?: boolean; frozenBy?: string },\n now: number,\n): TaskFreeze {\n return {\n goal: input.goal,\n progress: input.progress,\n next: input.next,\n frozenAt: now,\n ...(input.redacted === true ? { redacted: true } : {}),\n ...(input.frozenBy === undefined || input.frozenBy === '' ? {} : { frozenBy: input.frozenBy }),\n }\n}\n\n/** Create a task from user input. */\nexport function createTask(input: NewTaskInput, now: number, id: string): TaskRecord {\n const tags = normalizeTags(input.tags)\n return {\n id,\n title: input.title.trim(),\n description: input.description.trim(),\n prompt: input.prompt.trim(),\n status: 'todo',\n createdAt: now,\n updatedAt: now,\n executions: [],\n workspaceId: normalizeTargetId(input.workspaceId),\n mode: normalizeTargetId(input.mode),\n permission: isTaskPermission(input.permission) ? input.permission : undefined,\n model: normalizeTargetId(input.model),\n reuseSession: input.reuseSession === true ? true : undefined,\n ...(input.freeze === undefined ? {} : { freeze: freezeOf(input.freeze, now) }),\n ...(input.handover === undefined ? {} : { handover: { ...input.handover, bundledAt: now } }),\n ...(tags === undefined ? {} : { tags }),\n }\n}\n\n/** Clone a task with an updated status and a fresh updatedAt. */\nexport function withStatus(task: TaskRecord, status: TaskStatus, now: number): TaskRecord {\n return { ...task, status, updatedAt: now }\n}\n\n/**\n * Merge a schedule patch into a task's schedule rule (creating it when\n * absent), with a fresh updatedAt. Keys present in the patch overwrite the\n * current value — including explicit `undefined`, which clears a field (used\n * to disarm `nextRunAt`); absent keys keep their current value.\n */\nexport function withSchedule(\n task: TaskRecord,\n patch: Partial<ScheduleRule>,\n now: number,\n): TaskRecord {\n const current = task.schedule\n const schedule: ScheduleRule = {\n enabled: current?.enabled ?? false,\n cron: current?.cron ?? '',\n nextRunAt: current?.nextRunAt,\n lastTriggeredAt: current?.lastTriggeredAt,\n }\n if ('enabled' in patch) schedule.enabled = patch.enabled ?? false\n if ('cron' in patch) schedule.cron = patch.cron ?? ''\n if ('nextRunAt' in patch) schedule.nextRunAt = patch.nextRunAt\n if ('lastTriggeredAt' in patch) schedule.lastTriggeredAt = patch.lastTriggeredAt\n return { ...task, updatedAt: now, schedule }\n}\n\n/**\n * Open a fresh execution on a task: move it to 'running' and append a\n * running execution record. Returns the new task and the new execution.\n */\nexport function startExecution(\n task: TaskRecord,\n now: number,\n executionId: string,\n initiatedBy?: string,\n): { task: TaskRecord; execution: ExecutionRecord } {\n const execution: ExecutionRecord = {\n id: executionId,\n sessionId: undefined,\n startedAt: now,\n endedAt: undefined,\n result: undefined,\n error: undefined,\n ...(initiatedBy === undefined || initiatedBy === '' ? {} : { initiatedBy }),\n // Capture the card's freeze provenance on the execution record so the\n // audit trail stays queryable even if the snapshot is replaced later.\n ...(task.freeze === undefined ? {} : {\n frozenAt: task.freeze.frozenAt,\n ...(task.freeze.frozenBy === undefined ? {} : { frozenBy: task.freeze.frozenBy }),\n }),\n }\n return {\n task: {\n ...task,\n status: 'running',\n updatedAt: now,\n executions: retainRecentExecutions([...task.executions, execution]),\n },\n execution,\n }\n}\n\n/**\n * Settle a running execution: record the outcome and move the task into the\n * matching column. No-op (returns the input task) when the execution is not\n * the task's latest or is already settled.\n */\nexport function settleExecution(\n task: TaskRecord,\n executionId: string,\n outcome: 'succeeded' | 'failed' | 'cancelled',\n now: number,\n error: string | undefined,\n): TaskRecord {\n const index = task.executions.findIndex(execution => execution.id === executionId)\n if (index === -1) return task\n const execution = task.executions[index]\n if (execution.endedAt !== undefined) return task\n const settled: ExecutionRecord = { ...execution, endedAt: now, result: outcome, error }\n const executions = [...task.executions]\n executions[index] = settled\n const status: TaskStatus = outcome === 'succeeded'\n ? (task.schedule?.enabled ? 'todo' : 'done')\n : outcome === 'failed' ? 'failed'\n : task.status === 'running' ? 'todo' : task.status\n return { ...task, status, updatedAt: now, executions }\n}\n\n/** A settled-execution summary string for the detail view. */\nexport function executionLabel(execution: ExecutionRecord): string {\n if (execution.result === 'succeeded') return 'succeeded'\n if (execution.result === 'failed') return 'failed'\n if (execution.result === 'cancelled') return 'cancelled'\n return 'running'\n}\n","/**\n * Archive/restore task use case: move a task off the main board and back,\n * whatever its status but `running`. The task keeps its status, execution history, and\n * transcript references, while archiving disarms any schedule so it cannot\n * create more execution records until the user restores and re-enables it.\n */\nimport type { TaskRecord } from '../tasks.ts'\nimport { ARCHIVABLE_STATUSES } from '../tasks.ts'\n\n/** Result of an archive transition. */\nexport interface ArchiveTaskResult {\n /** The next ledger. */\n tasks: readonly TaskRecord[]\n /** Whether the archive was applied (false = unknown task / not archivable). */\n archived: boolean\n}\n\n/**\n * Archive one task: only a `running` task stays on the board (its runner\n * still owns its lifecycle until the execution settles); every other status\n * can be archived. Archiving disarms a schedule; already-archived tasks are\n * a no-op.\n */\nexport function applyArchiveTask(\n tasks: readonly TaskRecord[],\n id: string,\n now: number,\n): ArchiveTaskResult {\n let applied = false\n const next = tasks.map(task => {\n if (task.id !== id || task.archivedAt !== undefined) return task\n if (!(ARCHIVABLE_STATUSES as readonly string[]).includes(task.status)) return task\n applied = true\n const schedule = task.schedule === undefined\n ? undefined\n : { ...task.schedule, enabled: false, nextRunAt: undefined }\n return {\n ...task,\n ...(schedule === undefined ? {} : { schedule }),\n archivedAt: now,\n updatedAt: now,\n }\n })\n return { tasks: next, archived: applied }\n}\n\n/** Restore one task back onto the main board (clears the archive marker). */\nexport function applyRestoreTask(tasks: readonly TaskRecord[], id: string, now: number): ArchiveTaskResult {\n let applied = false\n const next = tasks.map(task => {\n if (task.id !== id || task.archivedAt === undefined) return task\n applied = true\n const { archivedAt: _archived, ...rest } = task\n return { ...rest, updatedAt: now }\n })\n return { tasks: next, archived: applied }\n}\n","/**\n * Minimal 5-field cron parsing and next-run computation for scheduled task\n * runs. Framework-free and dependency-free so the scheduler and controller\n * share one tiny pure module.\n *\n * Grammar: five whitespace-separated fields, 分 时 日 月 周. Every field\n * supports the wildcard, step (wildcard or range + \"/n\"), single value,\n * inclusive range a-b, and comma lists mixing any of those. Ranges: minutes\n * 0-59, hours 0-23, days 1-31, months 1-12, weekdays 0-7 (0 and 7 both mean\n * Sunday). When both the day and weekday fields are restricted they combine\n * with OR semantics (standard cron). Invalid expressions parse to null and\n * are rejected by the UI/controller.\n */\n\n/** The parsed match sets of one cron expression. */\nexport interface CronSchedule {\n minutes: ReadonlySet<number>\n hours: ReadonlySet<number>\n days: ReadonlySet<number>\n months: ReadonlySet<number>\n /** Weekdays 0-6, 0 = Sunday (input 7 normalized to 0). */\n weekdays: ReadonlySet<number>\n /** Whether the day-of-month field was the literal '*' (unrestricted). */\n dayWildcard: boolean\n /** Whether the weekday field was the literal '*' (unrestricted). */\n weekdayWildcard: boolean\n}\n\n/** Inclusive ranges per field, in cron order. */\nconst FIELD_RANGES: ReadonlyArray<readonly [number, number]> = [\n [0, 59], // minutes\n [0, 23], // hours\n [1, 31], // days\n [1, 12], // months\n [0, 7], // weekdays (7 = Sunday, normalized below)\n]\n\n/**\n * Parse a 5-field cron expression.\n * @returns the match sets, or null when the expression is invalid.\n */\nexport function parseCron(expr: string): CronSchedule | null {\n const fields = expr.trim().split(/\\s+/)\n if (fields.length !== 5) return null\n const sets: Set<number>[] = []\n for (let index = 0; index < 5; index++) {\n const [min, max] = FIELD_RANGES[index]\n const set = new Set<number>()\n if (!parseField(fields[index], min, max, set)) return null\n sets.push(set)\n }\n const weekdays = new Set<number>()\n for (const day of sets[4]) weekdays.add(day === 7 ? 0 : day)\n return {\n minutes: sets[0],\n hours: sets[1],\n days: sets[2],\n months: sets[3],\n weekdays,\n // Only the literal '*' marks a field unrestricted: an explicit full\n // enumeration such as '1-31' is a restricted field and must not collapse\n // into the wildcard (it participates in day/weekday OR semantics).\n dayWildcard: fields[2] === '*',\n weekdayWildcard: fields[4] === '*',\n }\n}\n\n/** Whether the expression parses. */\nexport function isValidCron(expr: string): boolean {\n return parseCron(expr) !== null\n}\n\n/**\n * Compute the next matching instant after `fromMs` (ms epoch), in local time,\n * at minute granularity, strictly greater than `fromMs`. Returns the ms epoch\n * of the matching minute's start, or undefined when the calendar constraint\n * can never match (for example `0 0 30 2 *`). The five-year horizon includes\n * a full leap cycle, so a valid February 29 schedule remains reachable from\n * every non-leap year.\n *\n * Walks candidate year/month/day/hour/minute values straight from the parsed\n * field sets instead of scanning every minute: a sparse expression such as\n * `0 0 29 2 *` used to iterate ~1.5M wall-clock minutes before reaching the\n * next leap day. Wall-clock field construction + the final `matches` re-check\n * preserve the old minute scan's DST semantics exactly (nonexistent spring\n * minutes normalize forward and the repeated fall-back hour is never visited).\n */\nexport function nextRunAtMs(expr: string, fromMs: number): number | undefined {\n const schedule = parseCron(expr)\n if (schedule === null) return undefined\n if (!hasPossibleCalendarDay(schedule)) return undefined\n const from = new Date(fromMs)\n const limitMs = fromMs + 5 * 366 * 24 * 60 * 60 * 1000\n\n const sortedMinutes = [...schedule.minutes].sort((a, b) => a - b)\n const sortedHours = [...schedule.hours].sort((a, b) => a - b)\n const sortedMonths = [...schedule.months].sort((a, b) => a - b)\n\n let year = from.getFullYear()\n let month = from.getMonth() + 1\n let day = from.getDate()\n let hour = from.getHours()\n // Strictly after fromMs: the old scan started from the next minute.\n let minute = from.getMinutes() + 1\n\n while (new Date(year, month - 1, 1, 0, 0, 0, 0).getTime() <= limitMs) {\n for (const candidateMonth of sortedMonths) {\n if (candidateMonth < month) continue\n const daysInMonth = new Date(year, candidateMonth, 0).getDate()\n const dayStart = candidateMonth === month ? day : 1\n for (let candidateDay = dayStart; candidateDay <= daysInMonth; candidateDay += 1) {\n const dayProbe = new Date(year, candidateMonth - 1, candidateDay, 0, 0, 0, 0)\n if (!dayCandidate(schedule, dayProbe)) continue\n const hourStart = candidateMonth === month && candidateDay === day ? hour : 0\n for (const candidateHour of sortedHours) {\n if (candidateHour < hourStart) continue\n const minuteStart = candidateMonth === month && candidateDay === day && candidateHour === hour ? minute : 0\n for (const candidateMinute of sortedMinutes) {\n if (candidateMinute < minuteStart) continue\n const candidate = new Date(year, candidateMonth - 1, candidateDay, candidateHour, candidateMinute, 0, 0)\n const time = candidate.getTime()\n if (time <= fromMs) continue\n if (time > limitMs) return undefined\n if (matches(schedule, candidate)) return time\n }\n }\n }\n }\n year += 1\n month = 1\n day = 1\n hour = 0\n minute = 0\n }\n return undefined\n}\n\n/** Day/weekday OR gate shared by {@link matches} and the candidate scan. */\nfunction dayCandidate(schedule: CronSchedule, date: Date): boolean {\n const dayMatches = schedule.days.has(date.getDate())\n const weekdayMatches = schedule.weekdays.has(date.getDay())\n if (schedule.dayWildcard) return weekdayMatches\n if (schedule.weekdayWildcard) return dayMatches\n return dayMatches || weekdayMatches\n}\n\n/** Reject impossible month/day pairs without spending the multi-year scan. */\nfunction hasPossibleCalendarDay(schedule: CronSchedule): boolean {\n if (schedule.dayWildcard || !schedule.weekdayWildcard) return true\n const maximumDay = new Map<number, number>([\n [1, 31], [2, 29], [3, 31], [4, 30], [5, 31], [6, 30],\n [7, 31], [8, 31], [9, 30], [10, 31], [11, 30], [12, 31],\n ])\n for (const month of schedule.months) {\n const maximum = maximumDay.get(month) ?? 0\n if ([...schedule.days].some(day => day <= maximum)) return true\n }\n return false\n}\n\n/** Parse one comma-list field into the match set. */\nfunction parseField(field: string, min: number, max: number, out: Set<number>): boolean {\n if (field === '*') {\n for (let value = min; value <= max; value++) out.add(value)\n return true\n }\n for (const part of field.split(',')) {\n if (part === '') return false\n const [range, stepRaw] = part.split('/')\n let low: number\n let high: number\n if (range === '*') {\n low = min\n high = max\n } else if (range.includes('-')) {\n const [a, b] = range.split('-')\n if (a === '' || b === '' || !isDigits(a) || !isDigits(b)) return false\n low = Number(a)\n high = Number(b)\n } else if (isDigits(range)) {\n low = Number(range)\n // Standard cron: a bare value carrying a step runs from that value to the\n // field maximum (minutes 5/15 are 5,20,35,50), while a bare value alone is\n // exactly itself (#1493).\n high = stepRaw === undefined ? low : max\n } else {\n return false\n }\n if (low < min || high > max || low > high) return false\n const step = stepRaw === undefined ? 1 : isDigits(stepRaw) ? Number(stepRaw) : NaN\n if (!Number.isInteger(step) || step < 1) return false\n for (let value = low; value <= high; value += step) out.add(value)\n }\n return true\n}\n\n/** Day/weekday OR semantics: a restricted day field alone gates, and vice versa. */\nfunction matches(schedule: CronSchedule, date: Date): boolean {\n if (!schedule.minutes.has(date.getMinutes())) return false\n if (!schedule.hours.has(date.getHours())) return false\n if (!schedule.months.has(date.getMonth() + 1)) return false\n return dayCandidate(schedule, date)\n}\n\nfunction isDigits(value: string): boolean {\n return /^\\d+$/.test(value)\n}\n","/**\n * Create-task use case: mint a new task from user input, rejecting a blank\n * title. Pure ledger transition (no persistence or notify — the controller\n * orchestrates those), so it is unit-testable without any runtime face.\n */\nimport { isValidCron, nextRunAtMs } from '../schedule.ts'\nimport { createTask, withSchedule, type NewTaskInput, type TaskRecord } from '../tasks.ts'\n\n/** Result of a create transition: the new task (when accepted) + the next ledger. */\nexport interface CreateTaskResult {\n /** The minted task, or undefined when the input was rejected (blank title). */\n task: TaskRecord | undefined\n /** The next ledger; identical reference when rejected. */\n tasks: readonly TaskRecord[]\n}\n\n/**\n * Apply a create against the current ledger. Returns the new task and the\n * appended ledger, or the unchanged ledger when the title is blank.\n * @param tasks - current ledger.\n * @param input - raw user input (title/description/prompt + optional schedule).\n * @param now - clock instant (ms epoch).\n * @param id - minted task id.\n */\nexport function applyCreateTask(\n tasks: readonly TaskRecord[],\n input: NewTaskInput,\n now: number,\n id: string,\n): CreateTaskResult {\n if (input.title.trim() === '') return { task: undefined, tasks }\n let task = createTask(input, now, id)\n // Arm the requested schedule (new-task dialog): only an enabled rule with\n // a valid cron is applied; blank, invalid, or disabled requests leave the\n // task unscheduled.\n const requested = input.schedule\n if (requested?.enabled === true && requested.cron.trim() !== '' && isValidCron(requested.cron)) {\n const cron = requested.cron.trim()\n task = withSchedule(task, { enabled: true, cron, nextRunAt: nextRunAtMs(cron, now) }, now)\n }\n return { task, tasks: [...tasks, task] }\n}\n","/**\n * Delete-task use case: drop a task from the ledger and clear the selection\n * when it pointed at the removed task. Pure ledger transition (no persistence\n * or notify — the controller orchestrates those).\n */\nimport type { TaskRecord } from '../tasks.ts'\n\n/** Result of a delete transition. */\nexport interface DeleteTaskResult {\n /** The next ledger (the removed task absent). */\n tasks: readonly TaskRecord[]\n /** Whether the previous selection referenced the removed task. */\n selectionCleared: boolean\n}\n\n/**\n * Apply a delete across the ledger. The selection (a task id) is cleared when\n * it matches the removed task, so the UI never lingers on a vanished detail.\n * @param tasks - current ledger.\n * @param selectedTaskId - the currently selected task id (may be undefined).\n * @param id - the task to remove.\n */\nexport function applyDeleteTask(\n tasks: readonly TaskRecord[],\n selectedTaskId: string | undefined,\n id: string,\n): DeleteTaskResult {\n const next = tasks.filter(task => task.id !== id)\n return {\n tasks: next,\n selectionCleared: selectedTaskId === id,\n }\n}\n","/**\n * Schedule use case: arm/disarm a task's cron rule and roll a rule forward.\n * Pure ledger transitions (no persistence or notify — the controller\n * orchestrates those). Validation and next-run computation live here, sharing\n * the core cron parser (schedule.ts) and the withSchedule transition.\n */\nimport { isValidCron, nextRunAtMs } from '../schedule.ts'\nimport { withSchedule, type TaskRecord } from '../tasks.ts'\n\n/** Fields the schedule use case may change on a rule. */\nexport interface SetSchedulePatch {\n enabled?: boolean\n cron?: string\n}\n\n/** Result of arming/disarming a rule. */\nexport interface SetScheduleResult {\n /** The next ledger; unchanged reference when rejected. */\n tasks: readonly TaskRecord[]\n /** Whether the rule was applied (false on unknown task / invalid cron). */\n applied: boolean\n}\n\n/**\n * Set an on-board task's schedule rule. A blank or invalid cron, or an\n * archived task, is rejected (state untouched); an enabled rule computes the\n * next run instant immediately, a disabled one carries no next-run instant.\n * @param tasks - current ledger.\n * @param id - the task to schedule.\n * @param patch - rule fields to change (absent fields keep their current value).\n * @param now - clock instant (ms epoch).\n */\nexport function applySetSchedule(\n tasks: readonly TaskRecord[],\n id: string,\n patch: SetSchedulePatch,\n now: number,\n): SetScheduleResult {\n const task = tasks.find(candidate => candidate.id === id)\n if (task === undefined || task.archivedAt !== undefined) return { tasks, applied: false }\n const current = task.schedule\n const cron = (patch.cron ?? current?.cron ?? '').trim()\n if (cron === '' || !isValidCron(cron)) return { tasks, applied: false }\n const enabled = patch.enabled ?? current?.enabled ?? false\n const nextRunAt = enabled ? nextRunAtMs(cron, now) : undefined\n if (enabled && nextRunAt === undefined) return { tasks, applied: false }\n return {\n tasks: tasks.map(candidate =>\n candidate.id === id ? withSchedule(candidate, { enabled, cron, nextRunAt }, now) : candidate),\n applied: true,\n }\n}\n\n/**\n * Roll a task's schedule rule forward (scheduler callback): persist the next\n * due instant and the trigger instant. No-op for tasks without a rule (deleted\n * mid-tick, for example).\n * @param tasks - current ledger.\n * @param id - the task to roll forward.\n * @param nextRunAt - next due instant (may be undefined to clear).\n * @param lastTriggeredAt - the trigger instant of this run.\n * @param now - clock instant (ms epoch).\n */\nexport function applyScheduleNextRun(\n tasks: readonly TaskRecord[],\n id: string,\n nextRunAt: number | undefined,\n lastTriggeredAt: number | undefined,\n now: number,\n): readonly TaskRecord[] {\n return tasks.map(task =>\n task.id === id && task.archivedAt === undefined && task.schedule !== undefined\n ? withSchedule(task, { nextRunAt, lastTriggeredAt }, now)\n : task)\n}\n","/**\n * Update-task use case: apply an editable-field patch (title/description/\n * prompt plus the execution targets workspaceId/mode/permission) with a\n * fresh updatedAt. Pure ledger transition (no persistence or notify — the\n * controller orchestrates those).\n *\n * An explicit `undefined` in the patch clears the field (the task falls\n * back to the runtime default); an unknown permission string is ignored so\n * stale UI can never persist a value the execution service rejects.\n */\nimport { freezeOf, isTaskPermission, normalizeTags, normalizeTargetId, type TaskRecord, type TaskPermission, type TaskTag } from '../tasks.ts'\nimport type { FreezeSnapshot } from '../freeze-snapshot.ts'\nimport type { TaskHandoverInput } from '../handover.ts'\n\n/**\n * Editable fields on a task (the update patch surface). `freeze` replaces the\n * continuation-card snapshot (restamping frozenAt); an explicit null clears it.\n */\nexport type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession'>> & {\n freeze?: FreezeSnapshot & { redacted?: boolean } | null\n /** Replaces the handover bundle (restamping bundledAt); an explicit null clears it. */\n handover?: TaskHandoverInput | null\n /**\n * Replaces the task's labels (issue #1521). Unlike the content fields, tags\n * stay editable after the first run: they classify the task and shape the\n * NEXT execution prompt, they are not the record of what already ran. An\n * explicit null (or a list that normalizes to nothing) clears them.\n */\n tags?: TaskTag[] | null\n}\n\n/** The fields that edit the task's content (what the user reads and what the\n * next execution sends). Unlike the execution targets they stay editable only\n * while the task has never started executing — after the first run the\n * recorded prompt is the record of what actually ran, so it becomes read-only.\n */\nexport const TASK_CONTENT_FIELDS = ['title', 'description', 'prompt'] as const\n\n/** Whether an update patch touches any task-content field. */\nexport function hasContentPatch(patch: TaskUpdatePatch): boolean {\n return (TASK_CONTENT_FIELDS as readonly string[]).some(field => field in patch)\n}\n\n/**\n * Whether a task's content may still be edited: the task must be on-board\n * (not archived) and must never have started executing. Fail-closed: a\n * running, settled, or cancelled-before-launch task keeps its content fixed.\n */\nexport function canEditTaskContent(task: TaskRecord): boolean {\n return task.archivedAt === undefined && task.status !== 'running' && task.executions.length === 0\n}\n\n/** Keep an unknown permission string from entering the ledger. */\nfunction normalizePermission(\n current: TaskPermission | undefined,\n value: TaskPermission | undefined,\n): TaskPermission | undefined {\n if (value === undefined) return undefined\n return isTaskPermission(value) ? value : current\n}\n\n/**\n * Apply an update across the ledger. Tasks that do not match the id are left\n * untouched; the matched task receives the patch plus a fresh updatedAt.\n * @param tasks - current ledger.\n * @param id - the task to update.\n * @param patch - editable-field changes.\n * @param now - clock instant (ms epoch).\n */\nexport function applyUpdateTask(\n tasks: readonly TaskRecord[],\n id: string,\n patch: TaskUpdatePatch,\n now: number,\n): readonly TaskRecord[] {\n return tasks.map(task => {\n if (task.id !== id) return task\n const { freeze: freezePatch, handover: handoverPatch, tags: tagsPatch, ...rest } = patch\n const workspaceId = 'workspaceId' in patch ? normalizeTargetId(patch.workspaceId) : undefined\n const mode = 'mode' in patch ? normalizeTargetId(patch.mode) : undefined\n const permission = 'permission' in patch ? normalizePermission(task.permission, patch.permission) : undefined\n const model = 'model' in patch ? normalizeTargetId(patch.model) : undefined\n const next: TaskRecord = { ...task, ...rest, updatedAt: now }\n // Content fields normalize like creation does (trimmed); an explicit\n // undefined keeps the current value — content cannot be cleared.\n for (const field of TASK_CONTENT_FIELDS) {\n if (!(field in patch)) continue\n const value = patch[field]\n next[field] = value === undefined ? task[field] : value.trim()\n }\n // null (or a vanished key value) clears the snapshot; a present object\n // replaces it with a fresh frozenAt stamp.\n next.freeze = freezePatch == null ? undefined : freezeOf(freezePatch, now)\n // Handover follows the same null-clears convention, restamping bundledAt.\n next.handover = handoverPatch == null ? undefined : { ...handoverPatch, bundledAt: now }\n // Tags use the same convention: a present array replaces the set (after\n // repair), an explicit null or a fully-invalid list clears it.\n if ('tags' in patch) next.tags = tagsPatch == null ? undefined : normalizeTags(tagsPatch)\n // The permission confirmation binds the exact permission value: a change\n // of the pinned permission or of the handover bundle re-arms the gate\n // (blocking confirm-then-swap escalation). handover was destructured out\n // of rest above, so the stamp survives only when explicitly kept.\n if (('permission' in patch && patch.permission !== undefined && patch.permission !== task.permission) || 'handover' in patch) {\n next.permissionConfirmedAt = undefined\n }\n // Session reuse is a boolean opt-in; false (or an explicit null from a\n // caller that needs to clear it) returns the task to one session per run.\n if ('reuseSession' in patch) next.reuseSession = patch.reuseSession === true ? true : undefined\n if (workspaceId !== undefined || 'workspaceId' in patch) next.workspaceId = workspaceId\n if (mode !== undefined || 'mode' in patch) next.mode = mode\n if (permission !== undefined || 'permission' in patch) next.permission = permission\n if (model !== undefined || 'model' in patch) next.model = model\n return next\n })\n}\n","/**\n * Board controller: the single owner of task-ledger state and view state.\n *\n * In production it projects the Host ledger and submits confirmed actions;\n * the legacy store seam remains for v1 migration tests. The board closes\n * only on explicit user navigation, never implicitly on session-list churn.\n * Framework-free (structural runtime faces) so the whole orchestration is\n * unit-testable with fakes.\n *\n * The per use-case domain transitions (create/update/delete/schedule) live in\n * dedicated modules under core/use-cases and are applied here; the controller\n * owns only the orchestration seam (state, persistence, notify, navigation).\n */\nimport type { TaskStore } from './store.ts'\nimport { withStatus, type NewTaskInput, type TaskRecord, type TaskStatus } from './tasks.ts'\nimport { applyArchiveTask, applyRestoreTask } from './use-cases/task-archive.ts'\nimport { applyCreateTask } from './use-cases/task-create.ts'\nimport { applyDeleteTask } from './use-cases/task-delete.ts'\nimport { applyScheduleNextRun as applyScheduleRollForward, applySetSchedule } from './use-cases/task-schedule.ts'\nimport { applyUpdateTask, type TaskUpdatePatch } from './use-cases/task-update.ts'\nimport type {\n TaskBoardAction,\n TaskBoardEventPayload,\n TaskBoardParseDraft,\n TaskBoardParseRequest,\n TaskBoardSnapshot,\n} from '../protocol.ts'\n\nexport interface TaskBoardTransport {\n bootstrap(legacy: readonly TaskRecord[]): Promise<TaskBoardSnapshot>\n state(): Promise<TaskBoardSnapshot>\n /**\n * Submit one action; the optional initiator is the current DSH session id\n * (issue #6 audit origin), asserted by the client and recorded by the Host.\n */\n action(action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot>\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void\n /**\n * One-shot model parse of pasted text (issue #1540). Optional: a deployment\n * that cannot parse simply omits it, and the form hides the section.\n */\n parseDraft?(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft>\n}\n\n/**\n * The sessions face the controller needs for navigation awareness. The Client\n * Session Controller carries no global selection since 0.1.6-alpha.2, so the\n * wiring resolves the main-view Session once and exposes it as current().\n */\nexport interface SessionsControllerFace {\n /** The Session the main view currently shows, when any. */\n current(): string | undefined\n /** Navigate the main view to a Session. */\n open(id: string): void\n /** Subscribe to catalog changes; selection ownership rides the same snapshot. */\n subscribe(fn: () => void): () => void\n}\n\nfunction currentOf(sessions: SessionsControllerFace | undefined): string | undefined {\n return sessions?.current()\n}\n\n/** Controller dependencies (all swappable in tests). */\nexport interface ControllerDeps {\n store: TaskStore\n sessions: SessionsControllerFace\n /** Clock; defaults to Date.now. */\n now?: () => number\n /** Id minting; defaults to a random-uuid. */\n uuid?: () => string\n /** Host-authoritative transport; absent keeps the legacy in-memory test path. */\n transport?: TaskBoardTransport\n}\n\n/**\n * Register one host directory as a DSH project (workspace). Wired by the\n * browser apply() to the runtime's workspace controller; without it the board\n * hides its \"new project\" action instead of offering a dead control (#1536).\n */\nexport type WorkspaceCreator = (path: string) => Promise<{ workspaceId: string }>\n\n/** One workspace option the execution-target pickers offer. */\nexport interface ExecutionWorkspaceOption {\n workspaceId: string\n /** Display label (workspace title; the wiring falls back to the path). */\n title: string\n}\n\n/** One agent-preset option the execution-target pickers offer. */\nexport interface ExecutionPresetOption {\n id: string\n name?: string\n description?: string\n /** Why this preset cannot compose a session; the pickers disable it. */\n broken?: string\n isDefault: boolean\n}\n\n/** One model option the execution-target pickers offer. */\nexport interface ExecutionModelOption {\n id: string\n name?: string\n label?: string\n provider?: string\n}\n\n/** The execution-target option sets the UI feeds into the controller. */\nexport interface ExecutionOptionsSnapshot {\n workspaces: readonly ExecutionWorkspaceOption[]\n presets: readonly ExecutionPresetOption[]\n models?: readonly ExecutionModelOption[]\n}\n\n/** Immutable controller snapshot for UI subscriptions. */\nexport interface ControllerSnapshot {\n tasks: readonly TaskRecord[]\n boardOpen: boolean\n /** True when the board shows the archive view instead of the columns. */\n archiveView: boolean\n selectedTaskId: string | undefined\n /** Picker option sets (workspace list + agent-preset roster). */\n executionOptions: ExecutionOptionsSnapshot\n pendingTaskIds: readonly string[]\n /** Whether the board may offer \"register a new project\" (issue #1536). */\n canCreateWorkspace?: boolean\n /** Whether this deployment can parse pasted text into task fields (issue #1540). */\n canParseTask?: boolean\n transportError?: string\n host?: Pick<TaskBoardSnapshot, 'revision' | 'scheduler' | 'power' | 'sessionDefaultPermission'>\n}\n\n/** The selected task (resolved from the ledger), or undefined. */\nexport function selectedTaskOf(snapshot: ControllerSnapshot): TaskRecord | undefined {\n if (snapshot.selectedTaskId === undefined) return undefined\n return snapshot.tasks.find(task => task.id === snapshot.selectedTaskId)\n}\n\nfunction randomUuid(): string {\n const randomUUID = globalThis.crypto?.randomUUID\n if (randomUUID !== undefined) {\n return randomUUID.call(globalThis.crypto!)\n }\n const bytes = globalThis.crypto?.getRandomValues(new Uint8Array(16))\n if (bytes === undefined) {\n // Non-secure fallback (tests, odd environments).\n return `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`\n }\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/**\n * Board controller (see module doc). All mutations bump the snapshot and\n * persist through the store; UI and DOM mounts subscribe and re-render.\n */\nexport class BoardController {\n private tasks: TaskRecord[] = []\n private boardOpen = false\n private archiveView = false\n private selectedTaskId: string | undefined\n private executionOptions: ExecutionOptionsSnapshot = { workspaces: [], presets: [], models: [] }\n private workspaceCreator: WorkspaceCreator | undefined\n private listeners = new Set<() => void>()\n private disposers: Array<() => void> = []\n private readonly now: () => number\n private readonly uuid: () => string\n private readonly pendingTaskIds = new Set<string>()\n private readonly taskQueues = new Map<string, Promise<void>>()\n private transportError: string | undefined\n private hostState: Pick<TaskBoardSnapshot, 'revision' | 'scheduler' | 'power' | 'sessionDefaultPermission'> | undefined\n private remoteSubscribed = false\n private remoteInitialization: Promise<boolean> | undefined\n\n /** @param deps - store and the sessions navigation face. */\n constructor(private readonly deps: ControllerDeps) {\n this.now = deps.now ?? (() => Date.now())\n this.uuid = deps.uuid ?? randomUuid\n }\n\n // --- lifecycle -------------------------------------------------------------\n\n /** Load the persisted ledger and start the navigation/status subscriptions. */\n start(): void {\n this.tasks = this.deps.store.load()\n if (this.deps.transport !== undefined) void this.initializeRemote()\n // A sibling tab may have edited or deleted the ledger (same origin,\n // storage events). Reload on external change so a task deleted in\n // another tab stops firing here — and is never written back by this\n // tab's stale copy (scheduler roll-forward, execution settlement).\n const unsubscribeExternal = this.deps.transport === undefined ? this.deps.store.subscribeExternal?.(() => {\n this.tasks = this.deps.store.load()\n this.notify()\n }) : undefined\n if (unsubscribeExternal !== undefined) this.disposers.push(unsubscribeExternal)\n this.disposers.push(this.deps.sessions.subscribe(() => {\n this.onSessionsChanged()\n }))\n this.notify()\n }\n\n /** Stop all subscriptions and drop retained state (idempotent). */\n dispose(): void {\n for (const dispose of this.disposers.splice(0)) dispose()\n this.listeners.clear()\n }\n\n // --- snapshot / subscription ------------------------------------------------\n\n getSnapshot(): ControllerSnapshot {\n return {\n tasks: this.tasks,\n boardOpen: this.boardOpen,\n archiveView: this.archiveView,\n selectedTaskId: this.selectedTaskId,\n executionOptions: this.executionOptions,\n pendingTaskIds: [...this.pendingTaskIds],\n ...(this.workspaceCreator === undefined ? {} : { canCreateWorkspace: true }),\n ...(typeof this.deps.transport?.parseDraft === 'function' ? { canParseTask: true } : {}),\n ...(this.transportError === undefined ? {} : { transportError: this.transportError }),\n ...(this.hostState === undefined ? {} : { host: this.hostState }),\n }\n }\n\n subscribe(fn: () => void): () => void {\n this.listeners.add(fn)\n return () => { this.listeners.delete(fn) }\n }\n\n /** Whether production mutations are confirmed by the Host transport. */\n isHostBacked(): boolean {\n return this.deps.transport !== undefined\n }\n\n /** Retry initial migration/state synchronization after an explicit Host error. */\n async retryHostSync(): Promise<boolean> {\n return await this.initializeRemote()\n }\n\n // --- view state -------------------------------------------------------------\n\n openBoard(): void {\n if (this.boardOpen) return\n this.boardOpen = true\n this.notify()\n }\n\n closeBoard(): void {\n this.boardOpen = false\n this.notify()\n }\n\n toggleBoard(): void {\n if (this.boardOpen) this.closeBoard()\n else this.openBoard()\n }\n\n /**\n * Switch between the kanban columns and the archive view. Leaving the\n * archive view with an archived task still selected closes the selection —\n * the detail overlay must not linger over a task that is off-board.\n */\n toggleArchiveView(): void {\n this.archiveView = !this.archiveView\n if (!this.archiveView && this.selectedTaskId !== undefined) {\n const selected = this.tasks.find(task => task.id === this.selectedTaskId)\n if (selected?.archivedAt !== undefined) this.selectedTaskId = undefined\n }\n this.notify()\n }\n\n openTask(id: string): void {\n if (this.tasks.some(task => task.id === id)) {\n this.selectedTaskId = id\n this.notify()\n }\n }\n\n closeTask(): void {\n if (this.selectedTaskId === undefined) return\n this.selectedTaskId = undefined\n this.notify()\n }\n\n // --- task mutations (use-case transitions in core/use-cases) -----------------\n\n createTask(input: NewTaskInput): TaskRecord | undefined {\n const id = this.uuid()\n const { task, tasks } = applyCreateTask(this.tasks, input, this.now(), id)\n if (task === undefined) return undefined\n this.tasks = [...tasks]\n this.persistAndNotify()\n return task\n }\n\n /** Create through the Host and expose the task only after confirmation. */\n async createTaskConfirmed(input: NewTaskInput): Promise<TaskRecord | undefined> {\n if (this.deps.transport === undefined) return this.createTask(input)\n const id = this.uuid()\n const preview = applyCreateTask(this.tasks, input, this.now(), id).task\n if (preview === undefined) return undefined\n return await this.commitRemote({ kind: 'create', id, input }, id)\n ? this.tasks.find(task => task.id === id)\n : undefined\n }\n\n /**\n * Apply an editable-field patch (task content + execution targets).\n * Host-backed: the Host ledger owns the fail-closed checks (the content of\n * an executed task is read-only) and confirms the mutation, so the resolved\n * value reflects whether the Host accepted it; the legacy in-memory path\n * applies and persists synchronously.\n * @returns true when the patch was accepted by the authority.\n */\n async updateTask(id: string, patch: TaskUpdatePatch): Promise<boolean> {\n if (this.deps.transport !== undefined) {\n return await this.commitRemote({ kind: 'update', taskId: id, patch }, id)\n }\n this.tasks = [...applyUpdateTask(this.tasks, id, patch, this.now())]\n this.persistAndNotify()\n return true\n }\n\n /**\n * Replace (a part of) the picker option sets the UI feeds (workspace list\n * and agent-preset roster come from the runtime, not the ledger).\n */\n setExecutionOptions(patch: Partial<ExecutionOptionsSnapshot>): void {\n this.executionOptions = { ...this.executionOptions, ...patch }\n this.notify()\n }\n\n /** Wire (or clear) the runtime's project registration face (issue #1536). */\n setWorkspaceCreator(creator: WorkspaceCreator | undefined): void {\n this.workspaceCreator = creator\n this.notify()\n }\n\n /**\n * Register an existing host directory as a DSH project, exactly as the GUI's\n * own \"add project\" does; the runtime's failure message surfaces unchanged.\n */\n async createWorkspace(path: string): Promise<{ workspaceId: string }> {\n if (this.workspaceCreator === undefined) throw new Error('workspace creation is unavailable')\n return await this.workspaceCreator(path)\n }\n\n /** Whether this deployment can parse pasted text into task fields (issue #1540). */\n canParseTask(): boolean {\n return typeof this.deps.transport?.parseDraft === 'function'\n }\n\n /**\n * Parse pasted text into task fields through the Host. The transport already\n * phrases every failure for the user, so its message surfaces unchanged.\n */\n async parseTaskDraft(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft> {\n const transport = this.deps.transport\n const parse = transport?.parseDraft\n if (transport === undefined || parse === undefined) throw new Error('task parsing is unavailable')\n return await parse.call(transport, request, signal)\n }\n\n moveTask(id: string, status: TaskStatus): void {\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'move', taskId: id, status }, id)\n return\n }\n this.tasks = this.tasks.map(task => task.id === id ? withStatus(task, status, this.now()) : task)\n this.persistAndNotify()\n }\n\n deleteTask(id: string): void {\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'delete', taskId: id }, id)\n return\n }\n const { tasks, selectionCleared } = applyDeleteTask(this.tasks, this.selectedTaskId, id)\n this.tasks = [...tasks]\n if (selectionCleared) this.selectedTaskId = undefined\n this.persistAndNotify()\n }\n\n /**\n * Archive a task from any status but `running`, whose lifecycle the runner\n * keeps exclusive ownership of until it settles.\n * @returns true when applied.\n */\n archiveTask(id: string): boolean {\n const { tasks, archived } = applyArchiveTask(this.tasks, id, this.now())\n if (!archived) return false\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'archive', taskId: id }, id)\n return true\n }\n this.tasks = [...tasks]\n this.persistAndNotify()\n return true\n }\n\n /** Restore an archived task back onto the board (same status column). */\n restoreTask(id: string): boolean {\n const { tasks, archived } = applyRestoreTask(this.tasks, id, this.now())\n if (!archived) return false\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'restore', taskId: id }, id).then(restored => {\n if (restored && this.selectedTaskId === id) this.closeTask()\n })\n return true\n }\n this.tasks = [...tasks]\n if (this.selectedTaskId === id) this.selectedTaskId = undefined\n this.persistAndNotify()\n return true\n }\n\n // --- scheduling ---------------------------------------------------------------\n\n /**\n * Update a task's schedule rule. A blank or invalid cron expression is\n * rejected (returns false, state untouched). When the rule ends up enabled\n * the next run instant is computed immediately; a disabled rule carries no\n * next-run instant. Delegates the domain transition to the schedule use case.\n * @param id - the task to schedule.\n * @param patch - fields to change (absent fields keep their current value).\n * @returns true when applied, false when rejected (invalid cron / unknown task).\n */\n setSchedule(id: string, patch: { enabled?: boolean; cron?: string }): boolean {\n const { tasks, applied } = applySetSchedule(this.tasks, id, patch, this.now())\n if (!applied) return false\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'set-schedule', taskId: id, patch }, id)\n return true\n }\n this.tasks = [...tasks]\n this.persistAndNotify()\n return true\n }\n\n /**\n * Legacy pure-controller seam retained for migration-focused tests. The\n * production browser never rolls schedules; the Host ledger owns them.\n */\n applyScheduleNextRun(id: string, nextRunAt: number | undefined, lastTriggeredAt: number | undefined): void {\n const next = applyScheduleRollForward(this.tasks, id, nextRunAt, lastTriggeredAt, this.now())\n this.tasks = [...next]\n this.persistAndNotify()\n }\n\n /**\n * Reload the legacy v1 store without notifying subscribers. Production v2\n * reads Host snapshots instead; this remains only for isolated legacy tests.\n */\n reloadFromStore(): void {\n this.tasks = this.deps.store.load()\n }\n\n /**\n * Jump to an execution's session transcript. Selecting the session changes\n * `current`, which closes the board (the conversation view takes over).\n * @param sessionId - the execution session to open.\n */\n openSession(sessionId: string): void {\n this.closeBoard()\n this.deps.sessions.open(sessionId)\n }\n\n // --- execution ---------------------------------------------------------------\n\n /**\n * Request a Host execution for a task: the Host ledger owns the running\n * transition, the execution record, and the settlement. A second call\n * while the task is already running is ignored; without a Host transport\n * the run is refused (returns false).\n */\n async runTask(id: string): Promise<boolean> {\n const task = this.tasks.find(candidate => candidate.id === id)\n if (task === undefined || task.archivedAt !== undefined || task.status === 'running') return false\n if (this.deps.transport === undefined) return false\n return await this.commitRemote({ kind: 'run', taskId: id }, id, currentOf(this.deps.sessions))\n }\n\n /**\n * Confirm a card's above-default permission binding through the Host\n * (resolves the pending-confirmation transaction; no-op otherwise).\n */\n async confirmPermission(id: string): Promise<boolean> {\n const task = this.tasks.find(candidate => candidate.id === id)\n if (task === undefined) return false\n if (this.deps.transport === undefined) {\n this.tasks = this.tasks.map(candidate => candidate.id === id\n ? { ...candidate, permissionConfirmedAt: this.now(), updatedAt: this.now() }\n : candidate)\n this.persistAndNotify()\n return true\n }\n return await this.commitRemote({ kind: 'confirm-permission', taskId: id }, id)\n }\n\n /** Re-run a settled task through the Host (the Host replans and executes). */\n async rerunTask(id: string): Promise<void> {\n const task = this.tasks.find(candidate => candidate.id === id)\n if (task === undefined || task.archivedAt !== undefined) return\n if (this.deps.transport === undefined) return\n await this.commitRemote({ kind: 'rerun', taskId: id }, id, currentOf(this.deps.sessions))\n }\n\n // --- internals ---------------------------------------------------------------\n\n /**\n * Session-list notifications fire for all kinds of incidental churn\n * (background navigation, the Host runner creating and selecting a fresh\n * execution session, settlement, other plugins), so closing on `current`\n * changes would evict the board without the user asking. The board closes\n * only on explicit user navigation: a sidebar session/workspace row click\n * (board-mount onClickSidebarRow) or the board's own actions\n * (openSession / close). Keeping the hook preserves the subscription\n * contract for future listeners.\n */\n private onSessionsChanged(): void {\n // Intentionally empty: never close the board implicitly.\n }\n\n private persistAndNotify(): void {\n if (this.deps.transport === undefined) this.deps.store.save(this.tasks)\n this.notify()\n }\n\n private async commitRemote(action: TaskBoardAction, taskId?: string, initiator?: string): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n if (taskId === undefined) return await this.performRemote(action, initiator)\n const previous = this.taskQueues.get(taskId) ?? Promise.resolve()\n const operation = previous.catch(() => {}).then(async () => await this.performRemote(action, initiator))\n const tail = operation.then(() => {}, () => {})\n this.taskQueues.set(taskId, tail)\n this.pendingTaskIds.add(taskId)\n this.notify()\n try {\n return await operation\n } finally {\n if (this.taskQueues.get(taskId) === tail) {\n this.taskQueues.delete(taskId)\n this.pendingTaskIds.delete(taskId)\n this.notify()\n }\n }\n }\n\n private async performRemote(action: TaskBoardAction, initiator?: string): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n this.transportError = undefined\n this.notify()\n try {\n const accepted = this.acceptRemote(await transport.action(action, initiator))\n return accepted || await this.refreshRemote()\n } catch (error) {\n await this.refreshRemote(messageOf(error))\n return false\n }\n }\n\n private async initializeRemote(): Promise<boolean> {\n if (this.remoteInitialization !== undefined) return await this.remoteInitialization\n const initialization = this.doInitializeRemote()\n this.remoteInitialization = initialization\n try {\n return await initialization\n } finally {\n if (this.remoteInitialization === initialization) this.remoteInitialization = undefined\n }\n }\n\n private async doInitializeRemote(): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n try {\n this.acceptRemote(await transport.bootstrap(this.tasks))\n if (!this.remoteSubscribed) {\n this.remoteSubscribed = true\n this.disposers.push(transport.subscribe((event) => { this.onRemoteEvent(event) }))\n }\n return true\n } catch (error) {\n this.transportError = messageOf(error)\n this.notify()\n return false\n }\n }\n\n /**\n * SSE frames carry revision/scheduler/power. When the revision matches the\n * one already applied, apply the frame's scheduler/power in place and skip\n * the full /state fetch; otherwise the 5 s heartbeat would re-clone and\n * re-serialize the whole ledger per tab even while nothing changes.\n */\n private onRemoteEvent(event: TaskBoardEventPayload | undefined): void {\n if (event !== undefined && this.hostState !== undefined && event.revision === this.hostState.revision\n && typeof event.scheduler === 'object' && event.scheduler !== null\n && typeof event.power === 'object' && event.power !== null) {\n this.hostState = { revision: event.revision, scheduler: event.scheduler, power: event.power }\n this.notify()\n return\n }\n void this.refreshRemote()\n }\n\n private async refreshRemote(preserveError?: string): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n try {\n this.acceptRemote(await transport.state())\n if (preserveError !== undefined) {\n this.transportError = preserveError\n this.notify()\n }\n return true\n } catch (error) {\n this.transportError = preserveError ?? messageOf(error)\n this.notify()\n return false\n }\n }\n\n private acceptRemote(snapshot: TaskBoardSnapshot): boolean {\n const currentLedgerId = this.hostState?.scheduler.ledgerId\n const nextLedgerId = snapshot.scheduler.ledgerId\n const sameGeneration = currentLedgerId === nextLedgerId\n if (sameGeneration && this.hostState !== undefined && snapshot.revision < this.hostState.revision) return false\n this.tasks = [...snapshot.tasks]\n this.hostState = { revision: snapshot.revision, scheduler: snapshot.scheduler, power: snapshot.power }\n this.transportError = undefined\n if (this.selectedTaskId !== undefined && !this.tasks.some(task => task.id === this.selectedTaskId)) {\n this.selectedTaskId = undefined\n }\n if (!this.archiveView && this.selectedTaskId !== undefined\n && this.tasks.find(task => task.id === this.selectedTaskId)?.archivedAt !== undefined) {\n this.selectedTaskId = undefined\n }\n this.notify()\n return true\n }\n\n private notify(): void {\n for (const fn of [...this.listeners]) fn()\n }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/main-session.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Main-view Session derivation for the multi-instance Client Session model.\n *\n * The Client Session Controller carries no global \"current\" selection: view\n * selection belongs to the workspace UI, which owns the main-area reference and\n * publishes it through the catalog's per-source ownership counts\n * (`SessionSummary.retainedBy.mainView`). A plugin that needs the Session the\n * main view shows derives it from that marker instead of the removed\n * `SessionListState.current` field.\n *\n * The marker describes view ownership, not authority. It is the right input for\n * presentation and for deciding which view a navigation targets; it is not a\n * business fallback, because source counts never imply visibility or success.\n * @module dsh-web/shared/main-session\n */\n\n/** The catalog row subset this helper reads (a `SessionSummary` projection). */\nexport interface MainViewOwnedRow<Id extends string = string> {\n /** Catalog row identity. */\n readonly id: Id\n /** Per-source local ownership counts; absent rows are never owned. */\n readonly retainedBy?: Readonly<Partial<Record<string, number>>> | undefined\n}\n\n/**\n * Resolve the Session the main view currently shows.\n *\n * Reads the catalog's rows rather than a per-id retain-info source: ownership\n * counts ride the list snapshot, so this neither allocates observers nor opens\n * history, and a subscription to the list still fires when the selection moves.\n * @param byId - the session catalog's rows (`SessionListState.byId`), when available.\n * @returns the main-view session id, or undefined when the main view shows none.\n */\nexport function mainViewSessionId<Id extends string>(\n byId: Readonly<Record<Id, MainViewOwnedRow<Id> | undefined>> | undefined | null,\n): Id | undefined {\n if (byId === undefined || byId === null) return undefined\n for (const row of Object.values<MainViewOwnedRow<Id> | undefined>(byId)) {\n if (row !== undefined && (row.retainedBy?.mainView ?? 0) > 0) return row.id\n }\n return undefined\n}\n","/**\n * Freeze-request parser and security gate: parses the system-prompt-agreed\n * freeze format into a structured context snapshot (goal / progress / next),\n * redacts sensitive patterns to markers, rejects slash-prefixed DSH command\n * lines, and enforces the 8 KiB per-field byte limit.\n * Pure functions only: no session, network, or filesystem access.\n */\n\n/** Hard per-field limit: 8 KiB measured in UTF-8 bytes. */\nexport const FREEZE_FIELD_BYTE_LIMIT = 8 * 1024\n\n/** Marker replacing every sensitive match. */\nexport const REDACTED_MARKER = '[REDACTED]'\n\n/** Structured context snapshot carried by a continuation card. */\nexport interface FreezeSnapshot {\n goal: string\n progress: string\n next: string\n}\n\n/** Non-fatal notices produced by the security gate. */\nexport type FreezeWarning = 'redacted'\n\nexport type FreezeResult =\n | { ok: true; snapshot: FreezeSnapshot; warnings: FreezeWarning[] }\n | { ok: false; error: { code: string; message: string } }\n\nconst BEGIN = '<<<FREEZE'\nconst END = '>>>FREEZE'\n\nconst SECTION_KEYS: ReadonlyMap<string, SectionKey> = new Map([\n ['目标:', 'goal'],\n ['进度:', 'progress'],\n ['下一步:', 'next'],\n])\n\ntype SectionKey = 'goal' | 'progress' | 'next'\n\nconst SECTION_ORDER: readonly SectionKey[] = ['goal', 'progress', 'next']\n\nconst SECTION_NAMES: Record<SectionKey, string> = {\n goal: '目标',\n progress: '进度',\n next: '下一步',\n}\n\n/**\n * Sensitive patterns, each matched globally over every field body:\n * PEM private key blocks (whole block collapses to one marker), Bearer\n * credentials, OpenAI sk-, GitHub ghp_, GitLab glpat-, Slack xox* tokens,\n * and AWS access key ids.\n */\nconst SENSITIVE_PATTERNS: RegExp[] = [\n /-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,\n /Bearer\\s+[A-Za-z0-9._~+\\/=:-]{8,}/gi,\n /sk-[A-Za-z0-9_-]{8,}/g,\n /ghp_[A-Za-z0-9]{20,}/g,\n /glpat-[A-Za-z0-9_-]{15,}/g,\n /xox[bpars]-[A-Za-z0-9-]{10,}/g,\n /AKIA[0-9A-Z]{16}/g,\n]\n\nfunction fail(code: string, message: string): FreezeResult {\n return { ok: false, error: { code, message } }\n}\n\nfunction utf8Bytes(text: string): number {\n return new TextEncoder().encode(text).length\n}\n\n/** Redact sensitive patterns to the marker; reports whether any hit occurred. */\nexport function redactSensitive(text: string): { text: string; redacted: boolean } {\n let out = text\n let redacted = false\n for (const pattern of SENSITIVE_PATTERNS) {\n if (pattern.test(out)) {\n redacted = true\n out = out.replace(pattern, REDACTED_MARKER)\n }\n pattern.lastIndex = 0\n }\n return { text: out, redacted }\n}\n\n/**\n * True when any line of the text starts with \"/\" (a DSH command line).\n * Leading horizontal whitespace before the slash counts too: a frozen\n * body line like ` /kill` is still a command, not prose.\n */\nexport function hasSlashCommandLines(text: string): boolean {\n return text.split(/\\r?\\n/).some(line => /^[ \\t]+\\//.test(line) || line.startsWith('/'))\n}\n\n/**\n * Sanitize a structured freeze snapshot (the create/update action payload):\n * shape check, slash-command taint rejection, sensitive redaction, and the\n * per-field byte cap - the same gate parseFreezeRequest applies to\n * free-text freeze requests, exposed for the action data plane (issue #4).\n * @param value - the freeze object carried by an action or read back from disk.\n * @param extraKeys - keys allowed alongside goal/progress/next (e.g. the\n * protocol redacted flag, the ledger frozenAt stamp) and preserved verbatim\n * when present; their validation stays with the caller.\n */\nexport function sanitizeFreezeSnapshot(\n value: unknown,\n extraKeys: readonly string[] = [],\n): { ok: true; snapshot: FreezeSnapshot; redacted: boolean; extras: Record<string, unknown> } | { ok: false; error: { code: string; message: string } } {\n const bad = (code: string, message: string) => ({ ok: false as const, error: { code, message } })\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return bad('invalid-freeze', '冻结快照必须是 goal/progress/next 字符串对象')\n }\n const record = value as Record<string, unknown>\n const allowed = ['goal', 'progress', 'next', ...extraKeys]\n if (!Object.keys(record).every(key => allowed.includes(key))) {\n return bad('invalid-freeze', '冻结快照包含未知字段')\n }\n for (const key of SECTION_ORDER) {\n if (typeof record[key] !== 'string') {\n return bad('invalid-freeze', '冻结快照字段 ' + SECTION_NAMES[key] + ' 必须是字符串')\n }\n }\n for (const key of SECTION_ORDER) {\n if (hasSlashCommandLines(record[key] as string)) {\n return bad('dsh-command-line', '冻结文本的' + SECTION_NAMES[key] + '包含以 / 开头的命令行,整体拒绝')\n }\n }\n let redacted = false\n const snapshot: Record<SectionKey, string> = { goal: '', progress: '', next: '' }\n for (const key of SECTION_ORDER) {\n const result = redactSensitive(record[key] as string)\n snapshot[key] = result.text\n redacted = redacted || result.redacted\n }\n for (const key of SECTION_ORDER) {\n if (utf8Bytes(snapshot[key]) > FREEZE_FIELD_BYTE_LIMIT) {\n return bad('field-too-large', '冻结快照字段 ' + SECTION_NAMES[key] + ' 超过 8 KiB 上限')\n }\n }\n const extras: Record<string, unknown> = {}\n for (const key of extraKeys) if (key in record) extras[key] = record[key]\n return { ok: true, snapshot: { goal: snapshot.goal, progress: snapshot.progress, next: snapshot.next }, redacted, extras }\n}\n\n/**\n * Parse the freeze-request format: a <<<FREEZE ... >>>FREEZE block whose body\n * is 目标: / 进度: / 下一步: section headers, each followed by body lines.\n * The gate applies before returning: slash-command taint rejects the whole\n * request, sensitive patterns are redacted to markers, and each field is\n * capped at FREEZE_FIELD_BYTE_LIMIT UTF-8 bytes.\n */\nexport function parseFreezeRequest(input: string): FreezeResult {\n const beginIndex = input.indexOf(BEGIN)\n if (beginIndex === -1) {\n return fail('missing-block', '未找到冻结请求块(需要 <<<FREEZE ... >>>FREEZE)')\n }\n const bodyStart = beginIndex + BEGIN.length\n const endIndex = input.indexOf(END, bodyStart)\n if (endIndex === -1) {\n return fail('unterminated-block', '冻结请求块未闭合(缺少 >>>FREEZE)')\n }\n const block = input.slice(bodyStart, endIndex)\n\n const raw = new Map<SectionKey, string[]>()\n let current: SectionKey | undefined\n for (const line of block.split(/\\r?\\n/)) {\n const key = SECTION_KEYS.get(line)\n if (key !== undefined) {\n if (raw.has(key)) {\n return fail('duplicate-section', `重复的段落标题:${SECTION_NAMES[key]}`)\n }\n raw.set(key, [])\n current = key\n } else if (current !== undefined) {\n raw.get(current)!.push(line)\n }\n }\n\n const snapshot: Record<SectionKey, string> = { goal: '', progress: '', next: '' }\n for (const key of SECTION_ORDER) {\n if (!raw.has(key)) {\n return fail('missing-section', `冻结请求缺少段落:${SECTION_NAMES[key]}`)\n }\n const lines = raw.get(key)!\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop()\n snapshot[key] = lines.join('\\n')\n }\n\n for (const key of SECTION_ORDER) {\n if (hasSlashCommandLines(snapshot[key])) {\n return fail('dsh-command-line', `冻结文本的${SECTION_NAMES[key]}包含以 / 开头的命令行,整体拒绝`)\n }\n }\n\n let redacted = false\n for (const key of SECTION_ORDER) {\n const result = redactSensitive(snapshot[key])\n snapshot[key] = result.text\n redacted = redacted || result.redacted\n }\n\n for (const key of SECTION_ORDER) {\n if (utf8Bytes(snapshot[key]) > FREEZE_FIELD_BYTE_LIMIT) {\n return fail('field-too-large', `冻结快照字段 ${SECTION_NAMES[key]} 超过 8 KiB 上限`)\n }\n }\n\n return {\n ok: true,\n snapshot: { goal: snapshot.goal, progress: snapshot.progress, next: snapshot.next },\n warnings: redacted ? ['redacted'] : [],\n }\n}\n","/**\n * Handover bundle (issue #5, ADR 0001): the resource reference set a\n * continuation card carries — the pinned execution triplet (workspace /\n * agent preset / permission) plus doc/script references — so a picking-up\n * session can start with zero context.\n *\n * Security gate (adversarial scenario b): a bundle whose effective\n * permission is HIGHER than the session default is an unconfirmed binding.\n * It enters the pending-confirmation state (the card stores the binding\n * without a permissionConfirmedAt stamp); manual execution refuses, cron\n * refuses to schedule, and the human confirm-permission action resolves the\n * transaction by stamping the confirmation. Any later permission or\n * handover change re-arms the gate (the confirmation binds the exact\n * permission value, blocking confirm-then-swap escalation).\n */\nimport { isTaskPermission, type TaskPermission, type TaskRecord } from './tasks.ts'\n\nexport type { TaskPermission }\n\n/** Wire shape of a handover bundle (before bundledAt is stamped). */\nexport interface TaskHandoverInput {\n workspaceId?: string\n mode?: string\n permission?: TaskPermission\n references: string[]\n}\n\n/** Persisted handover bundle on a task record. */\nexport interface TaskHandover extends TaskHandoverInput {\n /** When the bundle was attached/replaced (ms epoch, stamped by the use case). */\n bundledAt: number\n}\n\n/** Most references a bundle may carry. */\nexport const HANDOVER_MAX_REFERENCES = 32\n/** Per-reference UTF-8 byte cap. */\nexport const HANDOVER_MAX_REFERENCE_BYTES = 512\n/** Total references UTF-8 byte cap. */\nexport const HANDOVER_MAX_TOTAL_BYTES = 8 * 1024\n/** Per target-id (workspace/preset) byte cap. */\nexport const HANDOVER_MAX_TARGET_BYTES = 256\n\n/** The board's notion of the deployment session-default permission (fail-safe default). */\nexport const DEFAULT_SESSION_PERMISSION: TaskPermission = 'read-only'\n\n/** Permission elevation rank (higher = more authority). */\nexport const PERMISSION_RANK: ReadonlyMap<TaskPermission, number> = new Map([\n ['read-only', 0],\n ['workspace-write', 1],\n ['danger-full-access', 2],\n])\n\nfunction byteLength(value: string): number {\n return new TextEncoder().encode(value).length\n}\n\n/**\n * Gate a handover bundle from the wire or disk: exact keys, string targets\n * under the byte cap, a known permission, and a bounded string reference\n * list. Returns the sanitized bundle, or undefined when rejected.\n */\nexport function sanitizeHandover(value: unknown): TaskHandoverInput | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const bundle = value as Record<string, unknown>\n const keys = Object.keys(bundle)\n if (!keys.every(key => ['workspaceId', 'mode', 'permission', 'references'].includes(key))) return undefined\n if (!Array.isArray(bundle.references)) return undefined\n if (bundle.references.length > HANDOVER_MAX_REFERENCES) return undefined\n let total = 0\n for (const reference of bundle.references) {\n if (typeof reference !== 'string' || reference === '') return undefined\n const size = byteLength(reference)\n if (size > HANDOVER_MAX_REFERENCE_BYTES) return undefined\n total += size\n if (total > HANDOVER_MAX_TOTAL_BYTES) return undefined\n }\n for (const key of ['workspaceId', 'mode'] as const) {\n const target: unknown = bundle[key]\n if (target !== undefined && (typeof target !== 'string' || byteLength(target) > HANDOVER_MAX_TARGET_BYTES)) return undefined\n }\n if (bundle.permission !== undefined && !isTaskPermission(bundle.permission)) return undefined\n const workspaceId = bundle.workspaceId\n const mode = bundle.mode\n return {\n ...(typeof workspaceId === 'string' ? { workspaceId } : {}),\n ...(typeof mode === 'string' ? { mode } : {}),\n ...(bundle.permission === undefined ? {} : { permission: bundle.permission as TaskPermission }),\n references: [...bundle.references as string[]],\n }\n}\n\n/** Build the persisted bundle from a sanitized input, stamping bundledAt. */\nexport function handoverOf(input: TaskHandoverInput, now: number): TaskHandover {\n return { ...input, bundledAt: now }\n}\n\n/** The permission an execution session would actually run under. */\nexport function effectivePermission(task: Pick<TaskRecord, 'permission' | 'handover'>): TaskPermission | undefined {\n return task.handover?.permission ?? task.permission\n}\n\n/** Whether a binding's permission is elevated above the session default. */\nexport function exceedsSessionDefault(permission: TaskPermission | undefined, sessionDefault: TaskPermission): boolean {\n if (permission === undefined) return false\n return (PERMISSION_RANK.get(permission) ?? -1) > (PERMISSION_RANK.get(sessionDefault) ?? -1)\n}\n\n/**\n * The confirmation-gate predicate: an elevated permission without a human\n * confirmation stamp. Manual run/rerun and cron must refuse such a card.\n */\nexport function requiresPermissionConfirmation(\n task: Pick<TaskRecord, 'permission' | 'handover' | 'permissionConfirmedAt'>,\n sessionDefault: TaskPermission = DEFAULT_SESSION_PERMISSION,\n): boolean {\n return exceedsSessionDefault(effectivePermission(task), sessionDefault) && task.permissionConfirmedAt === undefined\n}\n","/**\n * Legacy v1 browser persistence and the store seam used by pure client tests.\n *\n * Production v2 state is Host-authoritative. This backend is retained only to\n * read `dsh.taskBoard.v1` for one-time import; the old value is never removed,\n * so it remains a read-only rollback copy after migration.\n *\n * The seam keeps the backend swappable (e.g. an IndexedDB or a host-file\n * channel later); tests run against the in-memory backend and a jsdom\n * localStorage backend.\n */\nimport { isValidCron } from './schedule.ts'\nimport { isTaskPermission, isTaskStatus, normalizeTags, normalizeTargetId, type ScheduleRule, type TaskFreeze, type TaskRecord, type TaskPermission, type TaskStatus } from './tasks.ts'\nimport type { TaskHandover } from './handover.ts'\nimport { sanitizeFreezeSnapshot } from './freeze-snapshot.ts'\nimport { sanitizeHandover } from './handover.ts'\n\n/** Persistence seam for the task ledger. */\nexport interface TaskStore {\n /** Read the persisted ledger (empty when nothing is stored yet). */\n load(): TaskRecord[]\n /** Persist the whole ledger (replaces the stored document). */\n save(tasks: readonly TaskRecord[]): void\n /** Drop the persisted ledger (leaves the in-memory state alone). */\n clear(): void\n /**\n * Subscribe to ledger changes written by ANOTHER tab of the same origin\n * (browser storage events). The board controller reloads the ledger on\n * such a change, so a task deleted in one tab cannot keep firing (or be\n * written back) from the stale in-memory copy of another tab. No-op when\n * the backend has no cross-instance channel (in-memory store).\n */\n subscribeExternal?(listener: () => void): () => void\n}\n\n/** Storage key for the task ledger document. */\nexport const DEFAULT_STORAGE_KEY = 'dsh.taskBoard.v1'\n\n/** Structural shape of the storage event fired in sibling tabs (DOM-free). */\nexport interface StorageChangeEvent {\n key: string | null\n}\n\n/** The event-target face the store needs for cross-tab notifications. */\nexport interface StorageEvents {\n addEventListener(type: 'storage', listener: (event: StorageChangeEvent) => void): void\n removeEventListener(type: 'storage', listener: (event: StorageChangeEvent) => void): void\n}\n\n/**\n * Structural row check with the status left unvalidated (see {@link parseLedger}).\n * The `schedule` field is deliberately NOT checked here: a malformed schedule\n * never drops the task row — {@link normalizeSchedule} repairs or drops the\n * schedule alone.\n */\nfunction isTaskRecordShape(value: unknown): value is Omit<TaskRecord, 'status'> & { status: unknown } {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Record<string, unknown>\n if (typeof record.id !== 'string' || record.id === '') return false\n if (typeof record.title !== 'string') return false\n if (typeof record.description !== 'string') return false\n if (typeof record.prompt !== 'string') return false\n if (typeof record.createdAt !== 'number') return false\n if (typeof record.updatedAt !== 'number') return false\n if (record.workspaceId !== undefined && typeof record.workspaceId !== 'string') return false\n if (record.mode !== undefined && typeof record.mode !== 'string') return false\n if (record.permission !== undefined && typeof record.permission !== 'string') return false\n if (record.reuseSession !== undefined && typeof record.reuseSession !== 'boolean') return false\n if (!Array.isArray(record.executions)) return false\n for (const execution of record.executions) {\n if (typeof execution !== 'object' || execution === null) return false\n const entry = execution as Record<string, unknown>\n if (typeof entry.id !== 'string') return false\n if (entry.sessionId !== undefined && typeof entry.sessionId !== 'string') return false\n if (typeof entry.startedAt !== 'number') return false\n if (entry.endedAt !== undefined && typeof entry.endedAt !== 'number') return false\n if (entry.result !== undefined && entry.result !== 'succeeded' && entry.result !== 'failed' && entry.result !== 'cancelled') return false\n if (entry.error !== undefined && typeof entry.error !== 'string') return false\n if (entry.initiatedBy !== undefined && typeof entry.initiatedBy !== 'string') return false\n if (entry.frozenBy !== undefined && typeof entry.frozenBy !== 'string') return false\n if (entry.frozenAt !== undefined && typeof entry.frozenAt !== 'number') return false\n }\n return true\n}\n\n/** A task record is structurally valid if it round-trips through the UI. */\nexport function isTaskRecord(value: unknown): value is TaskRecord {\n return isTaskRecordShape(value) && isTaskStatus(value.status)\n}\n\n/** Normalize an unknown persisted status back into the closed status union. */\nfunction normalizeStatus(status: unknown): TaskStatus {\n return isTaskStatus(status) ? status : 'todo'\n}\n\n/**\n * Repair a persisted schedule rule: drop rules without a usable cron string,\n * coerce booleans/numbers, and leave `nextRunAt`/`lastTriggeredAt` undefined\n * when missing (a fresh recompute or the next tick fixes them).\n */\nfunction normalizeSchedule(schedule: unknown): ScheduleRule | undefined {\n if (typeof schedule !== 'object' || schedule === null) return undefined\n const rule = schedule as Record<string, unknown>\n // Reject (drop) a schedule whose cron is not a well-formed 5-field\n // expression: a malformed rule would otherwise linger as a never-firing\n // schedule instead of being dropped for later repair.\n if (typeof rule.cron !== 'string') return undefined\n if (rule.cron.trim() === '' || !isValidCron(rule.cron)) return undefined\n return {\n enabled: rule.enabled === true,\n cron: rule.cron,\n nextRunAt: typeof rule.nextRunAt === 'number' ? rule.nextRunAt : undefined,\n lastTriggeredAt: typeof rule.lastTriggeredAt === 'number' ? rule.lastTriggeredAt : undefined,\n }\n}\n\n/**\n * Repair a persisted freeze snapshot: shape + gate re-check (slash taint,\n * redaction idempotence, byte cap); a malformed or tainted snapshot is\n * dropped (undefined) rather than dropping the whole task row, mirroring\n * the schedule repair policy.\n */\nfunction normalizeFreeze(value: unknown): TaskFreeze | undefined {\n const result = sanitizeFreezeSnapshot(value, ['frozenAt', 'redacted', 'frozenBy'])\n if (!result.ok) return undefined\n const frozenAt = result.extras.frozenAt\n if (typeof frozenAt !== 'number' || !Number.isFinite(frozenAt)) return undefined\n if (result.extras.redacted !== undefined && result.extras.redacted !== true) return undefined\n const frozenBy = result.extras.frozenBy\n if (frozenBy !== undefined && (typeof frozenBy !== 'string' || frozenBy === '')) return undefined\n return {\n goal: result.snapshot.goal,\n progress: result.snapshot.progress,\n next: result.snapshot.next,\n frozenAt,\n ...(result.redacted || result.extras.redacted === true ? { redacted: true } : {}),\n ...(frozenBy === undefined ? {} : { frozenBy }),\n }\n}\n\n/**\n * Repair a persisted handover bundle: shape re-check through the same gate\n * as the wire path; a malformed bundle is dropped rather than dropping the\n * task row (mirroring the schedule/freeze repair policy).\n */\nfunction normalizeHandover(value: unknown): TaskHandover | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const { bundledAt, ...rest } = value as Record<string, unknown> & { bundledAt: unknown }\n const bundle = sanitizeHandover(rest)\n if (bundle === undefined) return undefined\n if (typeof bundledAt !== 'number' || !Number.isFinite(bundledAt)) return undefined\n return { ...bundle, bundledAt }\n}\n\n/** Parse + validate a persisted ledger document; invalid rows are dropped. */\nexport function parseLedger(raw: string | null): TaskRecord[] {\n if (raw === null) return []\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (error) {\n console.error('[dsh-task-board] persisted task ledger is not valid JSON; starting empty', error)\n return []\n }\n if (!Array.isArray(parsed)) {\n console.error('[dsh-task-board] persisted task ledger is not an array; starting empty')\n return []\n }\n const tasks: TaskRecord[] = []\n for (const row of parsed) {\n // Status is normalized (an unknown status from a future version lands in\n // todo instead of dropping the row); the schedule is repaired field by\n // field; every other field must be valid.\n if (!isTaskRecordShape(row)) {\n console.warn('[dsh-task-board] dropping invalid task row from persisted ledger', row)\n continue\n }\n // Always (re)assign the schedule: a repair that returns undefined must\n // clear a malformed persisted rule rather than leave it in the row.\n const task: TaskRecord = { ...row, status: normalizeStatus(row.status) }\n task.schedule = normalizeSchedule(row.schedule)\n // Execution targets are normalized like the schedule: blank strings\n // clear the pin and unknown permission strings from a future version\n // fall back to the session default instead of dropping the row.\n task.workspaceId = normalizeTargetId(row.workspaceId)\n task.mode = normalizeTargetId(row.mode)\n task.archivedAt = typeof row.archivedAt === 'number' && Number.isFinite(row.archivedAt) ? row.archivedAt : undefined\n task.permission = isTaskPermission(row.permission) ? row.permission as TaskPermission : undefined\n task.reuseSession = row.reuseSession === true ? true : undefined\n task.freeze = normalizeFreeze(row.freeze)\n task.handover = normalizeHandover(row.handover)\n // Tags are repaired field by field like the schedule: a malformed entry is\n // dropped, and a list that repairs to nothing clears the field instead of\n // dropping the task row.\n task.tags = normalizeTags(row.tags)\n task.permissionConfirmedAt = typeof row.permissionConfirmedAt === 'number' && Number.isFinite(row.permissionConfirmedAt) ? row.permissionConfirmedAt : undefined\n tasks.push(task)\n }\n return tasks\n}\n\n/** localStorage-backed store (the browser backend). */\nexport class LocalStorageTaskStore implements TaskStore {\n /**\n * @param key - storage key for the ledger document.\n * @param storage - storage backend (defaults to the global localStorage; tests inject fakes).\n * @param events - storage-event target for cross-tab notifications (defaults\n * to the browser global; undefined in non-browser runtimes, where the\n * subscription becomes a no-op).\n */\n constructor(\n private readonly key: string = DEFAULT_STORAGE_KEY,\n private readonly storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | undefined = globalThis.localStorage,\n private readonly events: StorageEvents | undefined = typeof (globalThis as { addEventListener?: unknown }).addEventListener === 'function'\n ? (globalThis as unknown as StorageEvents)\n : undefined,\n ) {}\n\n load(): TaskRecord[] {\n if (this.storage === undefined) return []\n try {\n return parseLedger(this.storage.getItem(this.key))\n } catch (error) {\n // Storage read failures (private mode, quota) degrade to an empty ledger,\n // never break the board.\n console.error('[dsh-task-board] task ledger read failed; starting empty', error)\n return []\n }\n }\n\n save(tasks: readonly TaskRecord[]): void {\n if (this.storage === undefined) return\n try {\n this.storage.setItem(this.key, JSON.stringify(tasks))\n } catch (error) {\n // Write failures only skip persistence; in-memory state stays live.\n console.error('[dsh-task-board] task ledger write failed (persistence skipped)', error)\n }\n }\n\n clear(): void {\n if (this.storage === undefined) return\n try {\n this.storage.removeItem(this.key)\n } catch (error) {\n console.error('[dsh-task-board] task ledger clear failed', error)\n }\n }\n\n /**\n * Cross-tab change subscription (see {@link TaskStore.subscribeExternal}).\n * The browser fires the storage event in every OTHER tab of the same origin\n * when one tab writes; a null key means the whole storage was cleared. Both\n * cases reload the ledger here; unrelated keys are ignored.\n */\n subscribeExternal(listener: () => void): () => void {\n if (this.events === undefined) return () => {}\n const onStorage = (event: StorageChangeEvent): void => {\n if (event.key !== null && event.key !== this.key) return\n listener()\n }\n this.events.addEventListener('storage', onStorage)\n return () => { this.events?.removeEventListener('storage', onStorage) }\n }\n}\n\n/** In-memory backend (tests, and a fallback when storage is unavailable). */\nexport class InMemoryTaskStore implements TaskStore {\n private ledger: TaskRecord[] = []\n\n load(): TaskRecord[] {\n return this.ledger.map(task => ({ ...task, executions: [...task.executions] }))\n }\n\n save(tasks: readonly TaskRecord[]): void {\n this.ledger = tasks.map(task => ({ ...task, executions: [...task.executions] }))\n }\n\n clear(): void {\n this.ledger = []\n }\n}\n","/**\n * Cross-module-instance apply guard for the task-board client bundle.\n *\n * The client factory can run more than once in a single page lifetime (for\n * example when a stale bundle is mixed with a rebuilt one while `dsh web` is\n * restarted). Without a guard, every factory run mounts its own sidebar entry\n * and board view, so the shell ends up showing two \"task board\" rows.\n *\n * The flag lives on globalThis so separate module instances (independent\n * factory runs) still share one guard. First claim wins; later claims become\n * no-ops until the claim is released (fiber unload / hot-reload) or the page\n * reloads.\n */\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __dshTaskboardApplied: boolean | undefined\n}\n\n/** Claims the plugin apply slot. Returns true when this call won the slot. */\nexport function claimTaskboardApply(): boolean {\n if (globalThis.__dshTaskboardApplied === true) return false\n globalThis.__dshTaskboardApplied = true\n return true\n}\n\n/**\n * Releases the claim. Called from the client fiber cleanup so that a\n * hot-reloaded bundle (the loader unloads the old plugin fiber and invokes\n * the rebuilt one in the same page) can claim again instead of being\n * silently dropped.\n */\nexport function releaseTaskboardApply(): void {\n globalThis.__dshTaskboardApplied = undefined\n}\n","/**\n * Task-board copy: zh-first dictionaries with an English fallback, selected\n * by the document language. Kept dependency-free (no dsh locale service) so\n * the DOM-injected entry row and the standalone board tree share one tiny\n * lookup.\n */\n\n/** zh dictionary (key-set source of truth). */\nexport const zh = {\n 'entry.label': '任务看板',\n 'board.title': '任务看板',\n 'board.close': '返回会话',\n 'board.new': '新建任务',\n 'board.search': '筛选任务…',\n 'board.empty': '这个状态还没有任务',\n 'board.filterAll': '全部',\n 'board.archive': '归档',\n 'board.archiveView': '归档 ({count})',\n 'board.backToBoard': '返回看板',\n 'archive.empty': '没有已归档的任务',\n 'board.status': '状态',\n 'board.status.backlog': '待规划',\n 'board.status.todo': '待办',\n 'board.status.running': '进行中',\n 'board.status.done': '已完成',\n 'board.status.failed': '已失败',\n 'board.runs': '次执行',\n 'board.pending': '正在提交',\n 'board.updated': '更新于',\n 'board.created': '创建于',\n 'board.hostError': 'Host 操作失败:{error}',\n 'board.hostError.notMounted': '任务看板的后台接口没有挂载:宿主可能没有加载该插件,也可能后台数据正被另一个 DSH 实例占用。重启 DSH 服务后再试',\n 'board.hostError.unauthorized': '登录状态已失效,请刷新页面后重试',\n 'board.hostError.locked': '任务看板的后台数据被占用:{detail}',\n 'board.hostError.timeout': '后台 {seconds} 秒内没有响应,请稍后重试',\n 'board.hostError.unreachable': '连接不上本机 DSH 服务,请确认它仍在运行',\n 'board.hostError.unexpected': '后台返回了无法识别的响应(HTTP {status})',\n 'board.project': '项目',\n 'board.projectAll': '全部项目',\n 'board.projectNew': '新建项目…',\n 'board.projectNewPath': '项目目录(宿主上的绝对路径)',\n 'board.projectNewPathPlaceholder': '例如 C:\\\\work\\\\my-project 或 /home/me/project',\n 'board.projectCreate': '创建项目',\n 'board.projectCreateFailed': '创建项目失败:{error}',\n 'new.aiParse': 'AI 解析',\n 'new.aiParseHint': '把从别处复制的一段话粘进来,让模型整理成标题、描述和执行 Prompt;解析结果只填进下面的表单,你可以先改再创建。',\n 'new.aiParsePlaceholder': '粘贴要变成任务的内容…',\n 'new.aiParseModel': '解析用模型',\n 'new.aiParseRun': '解析并填入',\n 'new.aiParseCancel': '取消解析',\n 'new.aiParseEmpty': '先粘贴一段内容再解析',\n 'new.aiParseNoModel': '这个部署还没有可用的模型,请先在 DSH 里配置模型提供商,或换一个模型再试',\n 'new.aiParseUnavailable': '后台没有解析接口可用,重启 DSH 服务后再试',\n 'new.aiParseTimeout': '模型 {seconds} 秒内没有返回结果,请重试或换一个更快的模型',\n 'new.aiParseFailed': '解析失败:{error}',\n 'board.retryHost': '重试连接 Host',\n 'board.hostMeta': 'Host 时区 {timeZone} · revision {revision}',\n 'new.title': '标题',\n 'new.titlePlaceholder': '一句话描述要做什么',\n 'new.description': '描述',\n 'new.descriptionPlaceholder': '补充背景、范围与验收(可选)',\n 'new.prompt': '执行 Prompt',\n 'new.promptPlaceholder': '发给 agent 的完整指令(留空则使用标题)',\n 'new.submit': '创建',\n 'new.createAndRun': '创建并执行',\n 'new.cancel': '取消',\n 'new.required': '标题不能为空',\n 'new.freeze': '冻结快照(可选)',\n 'new.freezePlaceholder': '粘贴会话输出的 <<<FREEZE … >>>FREEZE 冻结块,解析为目标/进度/下一步(可选)',\n 'detail.freeze': '冻结快照',\n 'detail.freeze.goal': '目标',\n 'detail.freeze.progress': '进度',\n 'detail.freeze.next': '下一步',\n 'detail.freeze.frozenAt': '冻结于 {time}',\n 'detail.freeze.frozenBy': '来源会话 {session}',\n 'detail.freeze.redacted': '冻结文本命中敏感模式,已自动替换为 [REDACTED];接手前请人工复核。',\n 'card.frozen': '冻结',\n 'new.handover': '交接包引用(可选)',\n 'new.handoverPlaceholder': '每行一个文档/脚本引用;填写后,上面选择的钉住三元组(工作区/模式/权限)会作为交接包附加到卡片',\n 'detail.handover': '交接包',\n 'detail.handover.bundledAt': '打包于 {time}',\n 'detail.handover.references': '引用',\n 'new.tags': '标签(可选)',\n 'new.tagsHint': '标签用于卡片徽章与顶栏筛选;填了「执行提示」的行会在每次执行前注入 Prompt,留空则只作展示。',\n 'new.tagName': '标签名',\n 'new.tagNamePlaceholder': '例如:工作',\n 'new.tagPrompt': '执行提示(可选)',\n 'new.tagPromptPlaceholder': '例如:产物归档到 02-工作/',\n 'new.tagAdd': '添加标签',\n 'new.tagRemove': '移除标签 {name}',\n 'board.tagFilter': '按标签筛选',\n 'board.tagFilterClear': '清除标签筛选',\n 'board.tagEmpty': '没有同时带这些标签的任务',\n 'detail.permissionPending': '权限待确认:本卡有效权限({permission})高于会话默认,手动执行与定时调度都会被拒绝,需人工确认后才能运行。',\n 'detail.permissionConfirm': '确认权限绑定',\n 'detail.permissionConfirmed': '已确认权限绑定 · {time}',\n 'detail.title': '任务详情',\n 'detail.edit': '编辑',\n 'detail.editTags': '编辑标签',\n 'detail.duplicate': '复制为新任务',\n 'detail.duplicateAndEdit': '修改并新建副本',\n 'detail.close': '关闭',\n 'edit.title': '编辑任务',\n 'edit.save': '保存',\n 'new.duplicateTitle': '新建任务(副本)',\n 'new.archiveOriginal': '创建后归档原任务',\n 'detail.prompt': '执行 Prompt',\n 'detail.description': '描述',\n 'detail.execution': '执行记录',\n 'detail.noExecution': '尚未执行',\n 'detail.run': '执行',\n 'detail.rerun': '重新执行',\n 'detail.delete': '删除',\n 'detail.archive': '归档',\n 'detail.restore': '恢复',\n 'detail.archivedAt': '已归档 · {time}',\n 'detail.viewSession': '查看会话',\n 'detail.noSession': '暂无会话',\n 'detail.executionStarted': '已启动',\n 'detail.execution.initiator': '发起会话 {session}',\n 'detail.executionEnded': '已结束',\n 'detail.result.succeeded': '成功',\n 'detail.result.failed': '失败',\n 'detail.result.cancelled': '已取消',\n 'detail.result.running': '进行中',\n 'delete.title': '删除任务',\n 'delete.confirm': '确定删除「{name}」吗?删除后不可恢复。',\n 'delete.ok': '删除',\n 'delete.cancel': '取消',\n 'status.move.backlog': '移到待规划',\n 'status.move.todo': '移到待办',\n 'exec.error.noWorkspace': '没有可用工作区,无法执行任务',\n 'exec.error.promptRejected': 'Prompt 被拒绝',\n 'run.failed': '执行失败:{error}',\n 'time.justNow': '刚刚',\n 'detail.schedule': '定时运行',\n 'detail.schedule.enable': '启用定时执行',\n 'detail.schedule.cron': 'Cron 表达式',\n 'detail.schedule.presets': '预设',\n 'detail.schedule.preset.daily9': '每天 09:00',\n 'detail.schedule.preset.hourly': '每小时',\n 'detail.schedule.preset.tenMin': '每 10 分钟',\n 'detail.schedule.preset.weeklyMon9': '每周一 09:00',\n 'detail.schedule.nextRun': '下次运行',\n 'detail.schedule.lastTriggered': '上次触发',\n 'detail.schedule.invalid': 'Cron 表达式无效',\n 'detail.schedule.notScheduled': '尚未排程',\n 'detail.schedule.dueSoon': '即将运行',\n 'card.scheduled': '定时',\n 'new.workspace': '工作区',\n 'new.mode': '模式',\n 'new.permission': '权限',\n 'new.model': '模型',\n 'exec.workspace.recent': '最近使用(默认)',\n 'exec.mode.default': '部署默认',\n 'exec.mode.defaultSuffix': '(默认)',\n 'exec.mode.brokenSuffix': '(不可用)',\n 'exec.mode.removed': '(已移除)',\n 'exec.permission.default': '会话默认',\n 'exec.permission.read-only': '只读',\n 'exec.permission.workspace-write': '工作区可写',\n 'exec.permission.danger-full-access': '完全访问',\n 'exec.model.default': '宿主默认(agent-default-model)',\n 'exec.model.unknown': '(未知模型/回退默认)',\n 'exec.reuseSession': '在同一对话继续',\n 'exec.reuseSessionHint': '开启后,本任务的后续执行在上一次会话里继续(该会话空闲且仍存在时),不再每次新建对话;每次复用时都会重新应用上面钉住的权限与模型。',\n 'detail.executionSettings': '执行设置',\n 'exec.hint': '执行时生效:工作区决定执行会话落在哪个工作区;模式决定会话的 agent 预设;权限经 /permission 命令应用到会话。留空则使用运行时默认。',\n // 插件设置卡片(settings.plugin.item 席位)。\n 'settings.title': '任务看板',\n 'settings.description': '控制 Host 任务看板、agent 播报与运行期间的系统空闲睡眠保护。',\n 'settings.enabled': '启用任务看板',\n 'settings.enabledHint': '关闭后隐藏侧边栏入口与看板视图。',\n 'settings.announceToAgent': '向 agent 播报任务看板',\n 'settings.announceToAgentHint': '开启:每条 agent 系统提示都会包含本看板的说明;关闭:不播报,agent 仅在用户主动提及时了解看板。',\n 'settings.preventIdleSleep': '阻止系统空闲睡眠',\n 'settings.preventIdleSleepHint': '默认关闭。开启后,只要存在运行中的 DSH 会话、已启用的定时任务或会话状态尚未确认,Host 就阻止整机因空闲睡眠;屏幕仍可自动关闭。',\n 'settings.powerStatus': '平台:{platform};保护状态:{phase};运行会话:{running};已启用计划:{schedules}',\n 'settings.powerBoundary': '这可能增加电池消耗。合盖、手动睡眠、休眠、关机、低电量或企业策略不在保证范围内,也不会唤醒已经睡眠的机器。',\n 'settings.powerUnknown': '未知',\n 'settings.powerError': '最近一次电源保护错误:{error}',\n 'settings.inherit': '继承',\n 'settings.on': '开',\n 'settings.off': '关',\n 'settings.overridden': '已覆盖',\n 'settings.reset': '恢复默认',\n 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或将本命名空间加入 Host 设置白名单后重启。',\n 'settings.readOnly': '当前部署的设置只读。',\n 'settings.expand': '展开设置',\n 'settings.collapse': '收起设置',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.discard': '放弃',\n 'settings.unsaved': '未保存',\n 'settings.saveFailed': '部署未接受这些值,已保留供你修改。',\n 'settings.invalidNumber': '请输入数字,留空则使用默认值。',\n} satisfies Record<string, string>\n\n/** en dictionary, complete against the zh key set. */\nexport const en: Record<keyof typeof zh, string> = {\n 'entry.label': 'Task Board',\n 'board.title': 'Task Board',\n 'board.close': 'Back to chat',\n 'board.new': 'New Task',\n 'board.search': 'Filter tasks…',\n 'board.empty': 'No tasks in this column',\n 'board.filterAll': 'All',\n 'board.archive': 'Archive',\n 'board.archiveView': 'Archived ({count})',\n 'board.backToBoard': 'Back to board',\n 'archive.empty': 'No archived tasks',\n 'board.status': 'Status',\n 'board.status.backlog': 'Backlog',\n 'board.status.todo': 'To Do',\n 'board.status.running': 'In Progress',\n 'board.status.done': 'Done',\n 'board.status.failed': 'Failed',\n 'board.runs': 'runs',\n 'board.pending': 'Submitting',\n 'board.updated': 'Updated',\n 'board.created': 'Created',\n 'board.hostError': 'Host action failed: {error}',\n 'board.hostError.notMounted': 'The task board Host API is not mounted: the Host may not have loaded the plugin, or another DSH instance holds the ledger. Restart the DSH service and try again',\n 'board.hostError.unauthorized': 'This session is no longer signed in; reload the page and try again',\n 'board.hostError.locked': 'The task board ledger is locked: {detail}',\n 'board.hostError.timeout': 'The Host did not answer within {seconds}s; try again shortly',\n 'board.hostError.unreachable': 'Cannot reach the local DSH service; make sure it is still running',\n 'board.hostError.unexpected': 'The Host returned an unrecognized response (HTTP {status})',\n 'board.project': 'Project',\n 'board.projectAll': 'All projects',\n 'board.projectNew': 'New project…',\n 'board.projectNewPath': 'Project directory (absolute path on the Host)',\n 'board.projectNewPathPlaceholder': 'e.g. C:\\\\work\\\\my-project or /home/me/project',\n 'board.projectCreate': 'Create project',\n 'board.projectCreateFailed': 'Could not create the project: {error}',\n 'new.aiParse': 'Parse with AI',\n 'new.aiParseHint': 'Paste text copied from somewhere else and let a model turn it into a title, description, and run prompt; the result only fills the form below, so you can edit it before creating the task.',\n 'new.aiParsePlaceholder': 'Paste the content to turn into a task…',\n 'new.aiParseModel': 'Model used for parsing',\n 'new.aiParseRun': 'Parse and fill',\n 'new.aiParseCancel': 'Cancel parsing',\n 'new.aiParseEmpty': 'Paste something to parse first',\n 'new.aiParseNoModel': 'This deployment has no model available; configure a model provider in DSH or pick another model',\n 'new.aiParseUnavailable': 'The Host has no parse endpoint; restart the DSH service and try again',\n 'new.aiParseTimeout': 'The model did not answer within {seconds}s; try again or pick a faster model',\n 'new.aiParseFailed': 'Parsing failed: {error}',\n 'board.retryHost': 'Retry Host connection',\n 'board.hostMeta': 'Host time zone {timeZone} · revision {revision}',\n 'new.title': 'Title',\n 'new.titlePlaceholder': 'What should be done, in one line',\n 'new.description': 'Description',\n 'new.descriptionPlaceholder': 'Background, scope, acceptance criteria (optional)',\n 'new.prompt': 'Run Prompt',\n 'new.promptPlaceholder': 'The full instruction sent to the agent (title is used when blank)',\n 'new.submit': 'Create',\n 'new.createAndRun': 'Create and run',\n 'new.cancel': 'Cancel',\n 'new.required': 'Title is required',\n 'new.freeze': 'Frozen snapshot (optional)',\n 'new.freezePlaceholder': 'Paste a <<<FREEZE ... >>>FREEZE block from a session; it parses into goal/progress/next (optional)',\n 'detail.freeze': 'Frozen snapshot',\n 'detail.freeze.goal': 'Goal',\n 'detail.freeze.progress': 'Progress',\n 'detail.freeze.next': 'Next',\n 'detail.freeze.frozenAt': 'Frozen at {time}',\n 'detail.freeze.frozenBy': 'Source session {session}',\n 'detail.freeze.redacted': 'Sensitive patterns were detected in the frozen text and replaced with [REDACTED]; review manually before resuming.',\n 'card.frozen': 'frozen',\n 'new.handover': 'Handover references (optional)',\n 'new.handoverPlaceholder': 'One doc/script reference per line; when filled, the pinned triplet picked above (workspace/mode/permission) is attached to the card as a handover bundle',\n 'detail.handover': 'Handover bundle',\n 'detail.handover.bundledAt': 'Bundled at {time}',\n 'detail.handover.references': 'References',\n 'new.tags': 'Tags (optional)',\n 'new.tagsHint': 'Tags drive the card badges and the board filter; a row with an execution hint is injected ahead of the prompt on every run, an empty one is display-only.',\n 'new.tagName': 'Tag name',\n 'new.tagNamePlaceholder': 'e.g. Work',\n 'new.tagPrompt': 'Execution hint (optional)',\n 'new.tagPromptPlaceholder': 'e.g. Archive artefacts under 02-work/',\n 'new.tagAdd': 'Add tag',\n 'new.tagRemove': 'Remove tag {name}',\n 'board.tagFilter': 'Filter by tag',\n 'board.tagFilterClear': 'Clear tag filter',\n 'board.tagEmpty': 'No task carries all of these tags',\n 'detail.permissionPending': 'Permission pending confirmation: this card\\'s effective permission ({permission}) is above the session default; manual runs and cron are refused until a human confirms.',\n 'detail.permissionConfirm': 'Confirm permission binding',\n 'detail.permissionConfirmed': 'Permission confirmed · {time}',\n 'detail.title': 'Task Detail',\n 'detail.edit': 'Edit',\n 'detail.editTags': 'Edit tags',\n 'detail.duplicate': 'Duplicate Task',\n 'detail.duplicateAndEdit': 'Edit as New Copy',\n 'detail.close': 'Close',\n 'edit.title': 'Edit Task',\n 'edit.save': 'Save',\n 'new.duplicateTitle': 'New Task (Copy)',\n 'new.archiveOriginal': 'Archive original task upon creation',\n 'detail.prompt': 'Run Prompt',\n 'detail.description': 'Description',\n 'detail.execution': 'Execution History',\n 'detail.noExecution': 'Not executed yet',\n 'detail.run': 'Run',\n 'detail.rerun': 'Run Again',\n 'detail.delete': 'Delete',\n 'detail.archive': 'Archive',\n 'detail.restore': 'Restore',\n 'detail.archivedAt': 'Archived · {time}',\n 'detail.viewSession': 'View Session',\n 'detail.noSession': 'No session',\n 'detail.executionStarted': 'Started',\n 'detail.execution.initiator': 'Initiated by session {session}',\n 'detail.executionEnded': 'Ended',\n 'detail.result.succeeded': 'Succeeded',\n 'detail.result.failed': 'Failed',\n 'detail.result.cancelled': 'Cancelled',\n 'detail.result.running': 'Running',\n 'delete.title': 'Delete Task',\n 'delete.confirm': 'Delete \"{name}\"? This cannot be undone.',\n 'delete.ok': 'Delete',\n 'delete.cancel': 'Cancel',\n 'status.move.backlog': 'Move to Backlog',\n 'status.move.todo': 'Move to To Do',\n 'exec.error.noWorkspace': 'No workspace is available to run the task',\n 'exec.error.promptRejected': 'Prompt rejected',\n 'run.failed': 'Run failed: {error}',\n 'time.justNow': 'just now',\n 'detail.schedule': 'Scheduled Runs',\n 'detail.schedule.enable': 'Enable scheduled runs',\n 'detail.schedule.cron': 'Cron expression',\n 'detail.schedule.presets': 'Presets',\n 'detail.schedule.preset.daily9': 'Every day 09:00',\n 'detail.schedule.preset.hourly': 'Every hour',\n 'detail.schedule.preset.tenMin': 'Every 10 minutes',\n 'detail.schedule.preset.weeklyMon9': 'Every Monday 09:00',\n 'detail.schedule.nextRun': 'Next run',\n 'detail.schedule.lastTriggered': 'Last triggered',\n 'detail.schedule.invalid': 'Invalid cron expression',\n 'detail.schedule.notScheduled': 'Not scheduled yet',\n 'detail.schedule.dueSoon': 'Due soon',\n 'card.scheduled': 'scheduled',\n 'new.workspace': 'Workspace',\n 'new.mode': 'Mode',\n 'new.permission': 'Permission',\n 'new.model': 'Model',\n 'exec.workspace.recent': 'Most recent (default)',\n 'exec.mode.default': 'Deployment default',\n 'exec.mode.defaultSuffix': ' (default)',\n 'exec.mode.brokenSuffix': ' (unavailable)',\n 'exec.mode.removed': ' (removed)',\n 'exec.permission.default': 'Session default',\n 'exec.permission.read-only': 'Read-only',\n 'exec.permission.workspace-write': 'Workspace Write',\n 'exec.permission.danger-full-access': 'Full Access',\n 'exec.model.default': 'Host default (agent-default-model)',\n 'exec.model.unknown': ' (unknown / fallback to default)',\n 'exec.reuseSession': 'Continue in the same conversation',\n 'exec.reuseSessionHint': 'When on, later runs continue in the previous session (when that session is idle and still exists) instead of starting a new conversation each time; the pinned permission and model above are re-applied on every reuse.',\n 'detail.executionSettings': 'Execution Settings',\n 'exec.hint': 'Applied when the task runs: the workspace decides where the execution session lands; the mode composes the session\\'s agent preset; the permission is applied through the /permission command. Blank = runtime default.',\n // Plugin settings card (the `settings.plugin.item` seat).\n 'settings.title': 'Task Board',\n 'settings.description': 'Configure the Host task board, agent announcement, and idle-system-sleep protection while work is pending.',\n 'settings.enabled': 'Enable the task board',\n 'settings.enabledHint': 'When off, the sidebar entry and board view are hidden.',\n 'settings.announceToAgent': 'Announce the task board to agents',\n 'settings.announceToAgentHint': 'On: every agent system prompt includes a note about this board. Off: no announcement; agents learn about the board only when you mention it.',\n 'settings.preventIdleSleep': 'Prevent idle system sleep',\n 'settings.preventIdleSleepHint': 'Off by default. When enabled, the Host prevents idle system sleep while any DSH session runs, any schedule is enabled, or session state is not yet known. The display may still turn off.',\n 'settings.powerStatus': 'Platform: {platform}; protection: {phase}; running sessions: {running}; enabled schedules: {schedules}',\n 'settings.powerBoundary': 'This may use more battery. Lid close, manual sleep, hibernation, shutdown, low-battery actions, and enterprise policy are outside the guarantee; an already sleeping computer is not woken.',\n 'settings.powerUnknown': 'unknown',\n 'settings.powerError': 'Latest power-protection error: {error}',\n 'settings.inherit': 'Inherit',\n 'settings.on': 'On',\n 'settings.off': 'Off',\n 'settings.overridden': 'Overridden',\n 'settings.reset': 'Reset to default',\n 'settings.notExposed': 'This DSH version does not expose this plugin\\'s settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to the Host settings allowlist and restart.',\n 'settings.readOnly': 'This deployment stores settings read-only.',\n 'settings.expand': 'Show settings',\n 'settings.collapse': 'Hide settings',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.discard': 'Discard',\n 'settings.unsaved': 'Unsaved',\n 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'settings.invalidNumber': 'Enter a number, or leave blank to use the default.',\n}\n\n/** The dictionary key union. */\nexport type TaskBoardKey = keyof typeof zh\n\n/** The settings-card slice of the task-board dictionary. */\nexport type SettingsCardKey = TaskBoardKey\n\n/** Active dictionary, picked by the document language at call time. */\nexport function dictionary(): Record<TaskBoardKey, string> {\n const lang = typeof document !== 'undefined' ? document.documentElement.lang : 'zh'\n return lang.toLowerCase().startsWith('en') ? en : zh\n}\n\n/**\n * SDK translate seat wired by the browser apply() once ctx.locale is bound\n * (setRuntimeTranslate). When present it reads the ACTIVE locale at call\n * time, so plain-DOM surfaces (sidebar row, toggles) follow a runtime\n * language switch; the document-language pick above stays only as the\n * unwired fallback (locale service absent, module-scope early callers).\n */\nlet runtimeT: ((key: TaskBoardKey, params?: Record<string, string>) => string) | undefined\n\n/** Wire the SDK translate seat; pass undefined to restore the document-language pick. */\nexport function setRuntimeTranslate(t: ((key: TaskBoardKey, params?: Record<string, string>) => string) | undefined): void {\n runtimeT = t\n}\n\n/** Translate a key with optional {name} template params. */\nexport function t(key: TaskBoardKey, params?: Record<string, string>): string {\n if (runtimeT !== undefined) return runtimeT(key, params)\n let text: string = dictionary()[key]\n if (params !== undefined) {\n for (const [name, value] of Object.entries(params)) {\n text = text.replaceAll(`{${name}}`, value)\n }\n }\n return text\n}\n","/**\n * Shared scheduled-run presets for the schedule editors (the new-task dialog\n * and the task detail panel): cron expression → locale label.\n */\nimport type { TaskBoardKey } from './locales.ts'\n\n/** Common scheduled-run presets (cron → locale label). */\nexport const SCHEDULE_PRESETS: ReadonlyArray<{ cron: string; label: TaskBoardKey }> = [\n { cron: '0 9 * * *', label: 'detail.schedule.preset.daily9' },\n { cron: '0 * * * *', label: 'detail.schedule.preset.hourly' },\n { cron: '*/10 * * * *', label: 'detail.schedule.preset.tenMin' },\n { cron: '0 9 * * 1', label: 'detail.schedule.preset.weeklyMon9' },\n]\n","/**\n * Shared task-modal pieces: the overlay shell (backdrop, form, title, error,\n * footer) and the title/description/prompt field trio used by both the\n * NewTaskModal and the EditTaskModal. State stays in the owning modal; these\n * are controlled components.\n */\nimport type { ReactNode } from 'react'\nimport { TAG_NAME_MAX_LENGTH, TAG_PROMPT_MAX_LENGTH, TASK_TAG_LIMIT, normalizeTags, type TaskTag } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\n\n/** DOM id shared by the tag-name inputs and their datalist (one board at a time). */\nconst TAG_NAME_LIST_ID = 'dsh-task-board-tag-names'\n\n/** Modal overlay: closes on backdrop press, submits through the form. */\nexport function ModalShell({\n ariaLabel,\n title,\n error,\n pending,\n submitLabel,\n onSubmit,\n onClose,\n secondaryAction,\n children,\n}: {\n ariaLabel: string\n title: string\n error: string | undefined\n pending: boolean\n submitLabel: string\n onSubmit: () => void\n onClose: () => void\n /** Optional second action beside the primary submit (e.g. create and run). */\n secondaryAction?: { label: string; onSubmit: () => void }\n children: ReactNode\n}) {\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onClose() }}>\n <form\n className={css.modal}\n role=\"dialog\"\n aria-label={ariaLabel}\n onSubmit={event => { event.preventDefault(); onSubmit() }}\n >\n <h2 className={css.modalTitle}>{title}</h2>\n\n {children}\n\n {error !== undefined && <p className={css.formError}>{error}</p>}\n\n <footer className={css.modalFooter}>\n <button type=\"button\" className={css.ghostButton} onClick={onClose}>\n {t('new.cancel')}\n </button>\n {secondaryAction !== undefined && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={secondaryAction.onSubmit}\n >\n {secondaryAction.label}\n </button>\n )}\n <button type=\"submit\" className={css.primaryButton} disabled={pending}>\n {submitLabel}\n </button>\n </footer>\n </form>\n </div>\n )\n}\n\n/** Title + description + prompt fields shared by the new and edit task forms. */\nexport function TaskContentFields({\n title,\n description,\n prompt,\n onTitleChange,\n onDescriptionChange,\n onPromptChange,\n}: {\n title: string\n description: string\n prompt: string\n /** Receives the new title; the owner also clears its error state. */\n onTitleChange: (value: string) => void\n onDescriptionChange: (value: string) => void\n onPromptChange: (value: string) => void\n}) {\n return (\n <>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.title')}</span>\n <input\n className={css.input}\n value={title}\n autoFocus\n placeholder={t('new.titlePlaceholder')}\n onChange={event => onTitleChange(event.target.value)}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.description')}</span>\n <textarea\n className={css.input}\n rows={3}\n value={description}\n placeholder={t('new.descriptionPlaceholder')}\n onChange={event => onDescriptionChange(event.target.value)}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.prompt')}</span>\n <textarea\n className={css.input}\n rows={4}\n value={prompt}\n placeholder={t('new.promptPlaceholder')}\n onChange={event => onPromptChange(event.target.value)}\n />\n </label>\n </>\n )\n}\n\n/**\n * Task labels (issue #1521): one row per label holding the badge name and an\n * optional execution hint. The name inputs offer the labels already used on the\n * board through a datalist, and picking one adopts its hint when the row has\n * none — so a business line is defined once and reused by every later task.\n */\nexport function TaskTagFields({\n tags,\n knownTags,\n onChange,\n}: {\n tags: TaskTag[]\n /** Labels already carried elsewhere on the board. */\n knownTags: TaskTag[]\n onChange: (tags: TaskTag[]) => void\n}) {\n const update = (index: number, patch: Partial<TaskTag>): void => {\n onChange(tags.map((tag, position) => (position === index ? { ...tag, ...patch } : tag)))\n }\n\n return (\n <div className={css.field}>\n <span className={css.fieldLabel}>{t('new.tags')}</span>\n <span className={css.fieldHint}>{t('new.tagsHint')}</span>\n {tags.map((tag, index) => (\n <div className={css.tagRow} key={index}>\n <input\n className={css.input}\n list={TAG_NAME_LIST_ID}\n value={tag.name}\n maxLength={TAG_NAME_MAX_LENGTH}\n placeholder={t('new.tagNamePlaceholder')}\n aria-label={t('new.tagName')}\n onChange={(event) => {\n const name = event.target.value\n const known = knownTags.find(candidate => candidate.name === name)\n const adoptsHint = known?.promptPrefix !== undefined && (tag.promptPrefix ?? '').trim() === ''\n update(index, adoptsHint ? { name, promptPrefix: known.promptPrefix } : { name })\n }}\n />\n <input\n className={css.input}\n value={tag.promptPrefix ?? ''}\n maxLength={TAG_PROMPT_MAX_LENGTH}\n placeholder={t('new.tagPromptPlaceholder')}\n aria-label={t('new.tagPrompt')}\n onChange={event => { update(index, { promptPrefix: event.target.value }) }}\n />\n <button\n type=\"button\"\n className={css.ghostButton}\n aria-label={t('new.tagRemove', { name: tag.name })}\n onClick={() => { onChange(tags.filter((_, position) => position !== index)) }}\n >\n ×\n </button>\n </div>\n ))}\n <datalist id={TAG_NAME_LIST_ID}>\n {knownTags.map(tag => <option key={tag.name} value={tag.name} />)}\n </datalist>\n <button\n type=\"button\"\n className={css.ghostButton + ' ' + css.tagAddButton}\n disabled={tags.length >= TASK_TAG_LIMIT}\n onClick={() => { onChange([...tags, { name: '' }]) }}\n >\n + {t('new.tagAdd')}\n </button>\n </div>\n )\n}\n\n/**\n * Clean a tag list via normalizeTags: trim, drop blanks and duplicates, cap\n * lengths and count, so the wire always carries a valid tag list.\n */\nexport function cleanTags(tags: readonly TaskTag[]): TaskTag[] {\n return normalizeTags(tags) ?? []\n}\n","/**\n * The model the user last picked for AI parsing, remembered per browser so the\n * next new-task modal starts from it instead of the roster's first entry\n * (issue #1621). An empty value is a real choice — \"let the Host use its\n * default model\" — and is remembered as such.\n */\nconst PARSE_MODEL_KEY = 'dsh-task-board.parse-model'\n\n/** The nearest browser storage, or undefined when the global itself throws. */\nfunction defaultStorage(): Storage | undefined {\n try {\n return globalThis.localStorage\n } catch {\n return undefined\n }\n}\n\n/** The remembered parse model; '' means the Host default (or no preference). */\nexport function readParseModelPreference(storage: Pick<Storage, 'getItem'> | undefined = defaultStorage()): string {\n try {\n return storage?.getItem(PARSE_MODEL_KEY) ?? ''\n } catch {\n // A blocked or full store must never break the form.\n return ''\n }\n}\n\n/** Remember the picked parse model; '' records the Host-default choice. */\nexport function writeParseModelPreference(model: string, storage: Pick<Storage, 'setItem'> | undefined = defaultStorage()): void {\n try {\n storage?.setItem(PARSE_MODEL_KEY, model)\n } catch {\n // Storage is optional: the picker still works without it.\n }\n}\n","/**\n * New-task modal: title + description + the prompt that execution will send.\n * Creates through the Host and closes only after the Host confirms it.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { isValidCron, nextRunAtMs } from '../../core/schedule.ts'\nimport { parseFreezeRequest } from '../../core/freeze-snapshot.ts'\nimport { collectKnownTags, TASK_PERMISSIONS, type TaskPermission, type TaskRecord, type TaskTag } from '../../core/tasks.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\nimport { ModalShell, TaskContentFields, TaskTagFields, cleanTags } from './TaskForm.tsx'\nimport { readParseModelPreference, writeParseModelPreference } from './parse-model-pref.ts'\nimport css from '../board.module.css'\n\nexport interface NewTaskModalProps {\n controller: BoardController\n onClose: () => void\n /** Optional task template to clone/duplicate from. */\n initialTask?: TaskRecord\n /**\n * Workspace the board's project filter has selected (#1536): a task created\n * while a project is open belongs to that project unless the user changes it.\n */\n defaultWorkspaceId?: string\n /** Optional callback after successful duplication (e.g. to archive source). */\n onDuplicateSuccess?: (sourceTaskId: string) => Promise<void>\n}\n\n/** New-task form overlay. */\nexport function NewTaskModal({ controller, onClose, initialTask, defaultWorkspaceId, onDuplicateSuccess }: NewTaskModalProps) {\n const isDuplicate = initialTask !== undefined\n const [title, setTitle] = useState(initialTask?.title ?? '')\n const [description, setDescription] = useState(initialTask?.description ?? '')\n const [prompt, setPrompt] = useState(initialTask?.prompt ?? '')\n const [workspaceId, setWorkspaceId] = useState(initialTask?.workspaceId ?? defaultWorkspaceId ?? '')\n const [mode, setMode] = useState(initialTask?.mode ?? '')\n const [permission, setPermission] = useState(initialTask?.permission ?? '')\n const [model, setModel] = useState(initialTask?.model ?? '')\n const [reuseSession, setReuseSession] = useState(initialTask?.reuseSession ?? false)\n const [scheduleEnabled, setScheduleEnabled] = useState(initialTask?.schedule?.enabled ?? false)\n const [scheduleCron, setScheduleCron] = useState(initialTask?.schedule?.cron ?? '')\n const [scheduleError, setScheduleError] = useState<string | undefined>(undefined)\n const [freezeText, setFreezeText] = useState('')\n const [freezeError, setFreezeError] = useState<string | undefined>(undefined)\n const [handoverText, setHandoverText] = useState(\n initialTask?.handover?.references !== undefined ? initialTask.handover.references.join('\\n') : '',\n )\n const [tags, setTags] = useState<TaskTag[]>(initialTask?.tags ?? [])\n const [archiveOriginal, setArchiveOriginal] = useState(true)\n const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n const [options, setOptions] = useState(controller.getSnapshot().executionOptions)\n // \"Parse pasted text\" (issue #1540) exists only when the deployment carries a\n // parse face; the section stays hidden otherwise.\n const [canParse] = useState(controller.getSnapshot().canParseTask === true)\n const [parseText, setParseText] = useState('')\n // Issue #1621: start from the model this browser used last, not from the\n // roster's first entry; '' is the Host default and stays valid.\n const [parseModel, setParseModel] = useState(() => readParseModelPreference())\n const [parsePending, setParsePending] = useState(false)\n const [parseError, setParseError] = useState<string | undefined>(undefined)\n const parseAbort = useRef<AbortController | undefined>(undefined)\n const parseModels = options.models ?? []\n\n // The workspace list and preset roster arrive from the runtime after mount;\n // follow them so the pickers never freeze on an empty snapshot.\n useEffect(\n () => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)),\n [controller],\n )\n\n // The model roster arrives asynchronously. A remembered model the deployment\n // no longer offers falls back to the Host default; an empty value is the\n // Host-default choice and is never overwritten by the roster (issue #1621).\n useEffect(() => {\n if (parseModel === '' || parseModels.length === 0) return\n if (parseModels.some(option => option.id === parseModel)) return\n setParseModel('')\n writeParseModelPreference('')\n }, [parseModel, options.models])\n\n const runParse = async (): Promise<void> => {\n const text = parseText.trim()\n if (text === '') {\n setParseError(t('new.aiParseEmpty'))\n return\n }\n const abort = new AbortController()\n parseAbort.current = abort\n setParsePending(true)\n setParseError(undefined)\n try {\n const draft = await controller.parseTaskDraft({ text, ...(parseModel === '' ? {} : { model: parseModel }) }, abort.signal)\n setTitle(draft.title)\n setDescription(draft.description)\n setPrompt(draft.prompt)\n } catch (parseFailure) {\n // A cancelled parse reports nothing: the user asked for it to stop.\n if (!abort.signal.aborted) setParseError(parseFailure instanceof Error ? parseFailure.message : String(parseFailure))\n } finally {\n parseAbort.current = undefined\n setParsePending(false)\n }\n }\n\n /**\n * Create the task through the Host, then optionally start it.\n * @param runAfterCreate - true for the \"create and run\" action: the task is\n * committed either way, and a refused start opens the task instead of\n * reporting the creation as failed.\n */\n const submit = async (runAfterCreate: boolean): Promise<void> => {\n if (scheduleEnabled) {\n const cron = scheduleCron.trim()\n if (cron === '' || !isValidCron(cron)) {\n setScheduleError(t('detail.schedule.invalid'))\n return\n }\n }\n // Optional continuation-card snapshot: parse the freeze block through the\n // T2 gate (structure + redaction + taint + size); a malformed block stops\n // submission with the parser's error instead of creating a plain task.\n let freeze: Parameters<typeof controller.createTaskConfirmed>[0]['freeze'] = undefined\n if (freezeText.trim() !== '') {\n const parsed = parseFreezeRequest(freezeText)\n if (!parsed.ok) {\n setFreezeError(parsed.error.message)\n return\n }\n freeze = { ...parsed.snapshot, ...(parsed.warnings.includes('redacted') ? { redacted: true } : {}) }\n }\n // Optional handover bundle: non-empty reference lines attach the picked\n // triplet (workspace/mode/permission above) plus the references.\n const references = handoverText.split('\\n').map(line => line.trim()).filter(line => line !== '')\n const handover = references.length === 0 ? undefined : {\n references,\n workspaceId: workspaceId === '' ? undefined : workspaceId,\n mode: mode === '' ? undefined : mode,\n permission: permission === '' ? undefined : permission as TaskPermission,\n }\n // Blank rows never reach the wire: the protocol rejects a tag with an\n // empty name, and an empty list is expressed by omitting the field.\n const tagList = cleanTags(tags)\n setPending(true)\n const task = await controller.createTaskConfirmed({\n title,\n description,\n prompt,\n freeze,\n handover,\n workspaceId: workspaceId === '' ? undefined : workspaceId,\n mode: mode === '' ? undefined : mode,\n permission: permission === '' ? undefined : permission as TaskPermission,\n model: model === '' ? undefined : model,\n ...(reuseSession ? { reuseSession: true } : {}),\n ...(tagList.length > 0 ? { tags: tagList } : {}),\n schedule: scheduleEnabled ? { enabled: true, cron: scheduleCron.trim() } : undefined,\n })\n if (task === undefined) {\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n return\n }\n if (isDuplicate && archiveOriginal && initialTask !== undefined) {\n if (onDuplicateSuccess !== undefined) {\n await onDuplicateSuccess(initialTask.id)\n } else {\n await controller.archiveTask(initialTask.id)\n }\n }\n if (runAfterCreate) {\n // The task exists from here on, so a refused start (a permission above\n // the session default, a pinned target that went stale) must not read as\n // a failed creation: open the task, whose detail view owns the\n // confirmation step and the refusal message.\n const started = await controller.runTask(task.id)\n if (!started) controller.openTask(task.id)\n }\n onClose()\n }\n\n /** Next-run preview for a valid armed cron (creation-time only). */\n const scheduleNextRun = scheduleEnabled && scheduleCron.trim() !== '' && isValidCron(scheduleCron)\n ? nextRunAtMs(scheduleCron, Date.now())\n : undefined\n\n const modalTitle = isDuplicate ? t('new.duplicateTitle') : t('board.new')\n\n return (\n <ModalShell\n ariaLabel={modalTitle}\n title={modalTitle}\n error={error}\n pending={pending}\n submitLabel={t('new.submit')}\n onSubmit={() => { void submit(false) }}\n onClose={onClose}\n secondaryAction={{ label: t('new.createAndRun'), onSubmit: () => { void submit(true) } }}\n >\n {canParse && (\n <section className={css.aiParse} data-dsh-part=\"ai-parse\">\n <span className={css.fieldLabel}>{t('new.aiParse')}</span>\n <p className={css.fieldHint}>{t('new.aiParseHint')}</p>\n <textarea\n className={css.input}\n rows={3}\n value={parseText}\n placeholder={t('new.aiParsePlaceholder')}\n spellCheck={false}\n onChange={event => { setParseText(event.target.value); setParseError(undefined) }}\n />\n <div className={css.aiParseRow}>\n <select\n className={css.select}\n value={parseModel}\n aria-label={t('new.aiParseModel')}\n onChange={event => {\n setParseModel(event.target.value)\n writeParseModelPreference(event.target.value)\n }}\n >\n <option value=\"\">{t('exec.model.default')}</option>\n {parseModels.map(option => (\n <option key={option.id} value={option.id}>{option.name ?? option.id}</option>\n ))}\n </select>\n {parsePending\n ? (\n <button type=\"button\" className={css.ghostButton} onClick={() => { parseAbort.current?.abort() }}>\n {t('new.aiParseCancel')}\n </button>\n )\n : (\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={parseText.trim() === ''}\n onClick={() => { void runParse() }}\n >\n {t('new.aiParseRun')}\n </button>\n )}\n </div>\n {parseError !== undefined && <p className={css.formError}>{parseError}</p>}\n </section>\n )}\n\n <TaskContentFields\n title={title}\n description={description}\n prompt={prompt}\n onTitleChange={value => { setTitle(value); setError(undefined) }}\n onDescriptionChange={setDescription}\n onPromptChange={setPrompt}\n />\n\n <TaskTagFields tags={tags} knownTags={collectKnownTags(controller.getSnapshot().tasks)} onChange={setTags} />\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.freeze')}</span>\n <textarea\n className={css.input}\n rows={4}\n value={freezeText}\n placeholder={t('new.freezePlaceholder')}\n spellCheck={false}\n onChange={event => { setFreezeText(event.target.value); setFreezeError(undefined) }}\n />\n </label>\n {freezeError !== undefined && <p className={css.formError}>{freezeError}</p>}\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.handover')}</span>\n <textarea\n className={css.input}\n rows={3}\n value={handoverText}\n placeholder={t('new.handoverPlaceholder')}\n spellCheck={false}\n onChange={event => { setHandoverText(event.target.value) }}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.workspace')}</span>\n <select\n className={css.select}\n value={workspaceId}\n onChange={event => { setWorkspaceId(event.target.value) }}\n >\n <option value=\"\">{t('exec.workspace.recent')}</option>\n {options.workspaces.map(workspace => (\n <option key={workspace.workspaceId} value={workspace.workspaceId}>{workspace.title}</option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.mode')}</span>\n <select\n className={css.select}\n value={mode}\n onChange={event => { setMode(event.target.value) }}\n >\n <option value=\"\">{t('exec.mode.default')}</option>\n {options.presets.map(preset => (\n <option key={preset.id} value={preset.id} disabled={preset.broken !== undefined}>\n {preset.name ?? preset.id}\n {preset.isDefault ? t('exec.mode.defaultSuffix') : ''}\n {preset.broken !== undefined ? t('exec.mode.brokenSuffix') : ''}\n </option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.permission')}</span>\n <select\n className={css.select}\n value={permission}\n onChange={event => { setPermission(event.target.value) }}\n >\n <option value=\"\">{t('exec.permission.default')}</option>\n {TASK_PERMISSIONS.map(id => (\n <option key={id} value={id}>{t(`exec.permission.${id}` as TaskBoardKey)}</option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.model')}</span>\n <select\n className={css.select}\n value={model}\n onChange={event => { setModel(event.target.value) }}\n >\n <option value=\"\">{t('exec.model.default')}</option>\n {options.models?.map(item => (\n <option key={item.id} value={item.id}>{item.name ?? item.id}</option>\n ))}\n </select>\n </label>\n\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={reuseSession}\n onChange={event => { setReuseSession(event.target.checked) }}\n />\n <span>{t('exec.reuseSession')}</span>\n </label>\n <p className={css.detailText}>{t('exec.reuseSessionHint')}</p>\n\n <section className={css.detailSection}>\n <h4>{t('detail.schedule')}</h4>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={scheduleEnabled}\n onChange={event => {\n setScheduleEnabled(event.target.checked)\n if (!event.target.checked) setScheduleError(undefined)\n }}\n />\n <span>{t('detail.schedule.enable')}</span>\n </label>\n {scheduleEnabled && (\n <>\n <div className={css.scheduleRow}>\n <input\n className={`${css.input} ${css.scheduleInput}${scheduleError !== undefined ? ` ${css.scheduleInputInvalid}` : ''}`}\n value={scheduleCron}\n placeholder=\"0 9 * * *\"\n spellCheck={false}\n aria-label={t('detail.schedule.cron')}\n onChange={event => { setScheduleCron(event.target.value); setScheduleError(undefined) }}\n />\n <select\n className={css.schedulePreset}\n value=\"\"\n aria-label={t('detail.schedule.presets')}\n onChange={event => {\n if (event.target.value === '') return\n setScheduleCron(event.target.value)\n setScheduleError(undefined)\n }}\n >\n <option value=\"\">{t('detail.schedule.presets')}…</option>\n {SCHEDULE_PRESETS.map(preset => (\n <option key={preset.cron} value={preset.cron}>{t(preset.label)}</option>\n ))}\n </select>\n </div>\n {scheduleError !== undefined && <p className={css.formError}>{scheduleError}</p>}\n {scheduleError === undefined && scheduleNextRun !== undefined && (\n <p className={css.scheduleMeta}>\n {t('detail.schedule.nextRun')} {new Date(scheduleNextRun).toLocaleString()}\n </p>\n )}\n </>\n )}\n </section>\n {isDuplicate && (\n <label className={css.checkboxLabel} style={{ marginTop: '12px' }}>\n <input\n type=\"checkbox\"\n checked={archiveOriginal}\n onChange={event => { setArchiveOriginal(event.target.checked) }}\n />\n <span>{t('new.archiveOriginal')}</span>\n </label>\n )}\n </ModalShell>\n )\n}\n","import type { TaskStatus } from '../../core/tasks.ts'\nimport type { TaskBoardKey } from '../locales.ts'\n\n/** Task status → locale key (board column titles and the detail badge). */\nexport const STATUS_KEY: Record<TaskStatus, TaskBoardKey> = {\n backlog: 'board.status.backlog',\n todo: 'board.status.todo',\n running: 'board.status.running',\n done: 'board.status.done',\n failed: 'board.status.failed',\n}\n","/**\n * Task card: the board's column item. Clicking opens the task detail — it\n * never executes anything directly (detail holds the Run button).\n *\n * Memoized: the card re-renders only when its own task record changes, so a\n * status/filter update on one card (or scrolling) never re-renders every\n * card on the board. The per-card onClick is built with a stable task reference\n * by the board, so the memo boundary is effective.\n */\nimport { memo } from 'react'\nimport type { TaskRecord } from '../../core/tasks.ts'\nimport { executionLabel, tagTone } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\n\n/** Compact relative/absolute time label. */\nexport function formatHostTimestamp(ms: number, timeZone?: string): string {\n try {\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'medium',\n ...(timeZone === undefined ? {} : { timeZone }),\n }).format(new Date(ms))\n } catch {\n return new Date(ms).toISOString()\n }\n}\n\nexport function formatTime(ms: number, timeZone?: string): string {\n const date = new Date(ms)\n const now = Date.now()\n const minutes = Math.floor((now - ms) / 60000)\n if (minutes < 1) return t('time.justNow')\n if (minutes < 60) return `${minutes}m`\n if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`\n if (timeZone !== undefined) return formatHostTimestamp(ms, timeZone)\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n}\n\nfunction TaskCardInner({ task, pending, timeZone, onClick }: { task: TaskRecord; pending: boolean; timeZone?: string; onClick: () => void }) {\n const latest = task.executions[task.executions.length - 1]\n const runs = task.executions.length\n const archived = task.archivedAt !== undefined\n const isDraggable = !archived && task.status !== 'running' && !pending\n\n return (\n <button\n type=\"button\"\n className={css.card}\n data-status={archived ? 'archived' : task.status}\n data-dsh-part=\"card\"\n data-pending={pending || undefined}\n draggable={isDraggable}\n onDragStart={isDraggable ? (event) => {\n event.dataTransfer.setData('text/plain', task.id)\n event.dataTransfer.effectAllowed = 'move'\n } : undefined}\n onClick={onClick}\n title={task.description !== '' ? task.description : task.title}\n >\n <span className={css.cardTitle}>{task.title}</span>\n {task.tags !== undefined && task.tags.length > 0 && (\n <span className={css.cardTags}>\n {task.tags.map(tag => (\n <span\n key={tag.name}\n className={css.cardTag}\n data-tag-tone={tagTone(tag.name)}\n data-dsh-part=\"tag-badge\"\n data-tag-hint={tag.promptPrefix === undefined ? undefined : tag.promptPrefix}\n title={tag.promptPrefix === undefined ? tag.name : tag.promptPrefix}\n >\n {tag.name}\n </span>\n ))}\n </span>\n )}\n {task.description !== '' && <span className={css.cardExcerpt}>{task.description}</span>}\n <span className={css.cardMeta}>\n <span className={css.cardTime}>{t('board.updated')} {formatTime(task.updatedAt)}</span>\n {task.freeze !== undefined && (\n <span className={css.cardSchedule} title={task.freeze.goal}>{t('card.frozen')}</span>\n )}\n {!archived && task.schedule?.enabled === true && (\n <span\n className={css.cardSchedule}\n title={task.schedule.nextRunAt !== undefined\n ? `${t('card.scheduled')} · ${formatHostTimestamp(task.schedule.nextRunAt, timeZone)}`\n : t('card.scheduled')}\n >\n {t('card.scheduled')}\n </span>\n )}\n {latest !== undefined && (\n <span className={css.cardRun} data-result={archived ? undefined : latest.result}>\n {runs} {t('board.runs')}\n </span>\n )}\n {latest?.sessionId !== undefined && (\n <span className={css.cardSession} title={latest.sessionId}>⌁</span>\n )}\n {!archived && (task.status === 'running' || pending) && <span className={css.cardSpinner} aria-hidden=\"true\" />}\n </span>\n {!archived && pending && <span className={css.cardRunningLabel}>{t('board.pending')}…</span>}\n {!archived && latest !== undefined && executionLabel(latest) === 'running' && (\n <span className={css.cardRunningLabel}>{t('detail.result.running')}…</span>\n )}\n </button>\n )\n}\n\n/** Memoized card: re-renders only when the card's own task record changes. */\nexport const TaskCard = memo(TaskCardInner)\n","/**\n * Generic confirm dialog used by destructive actions (task delete).\n */\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\n\n/** Confirm overlay props. */\nexport interface ConfirmDialogProps {\n title: string\n message: string\n confirmLabel: string\n /** Render the confirm button in the danger style. */\n danger?: boolean\n onCancel: () => void\n onConfirm: () => void\n}\n\n/** Small confirm overlay. */\nexport function ConfirmDialog({ title, message, confirmLabel, danger, onCancel, onConfirm }: ConfirmDialogProps) {\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onCancel() }}>\n <div className={css.modal} role=\"alertdialog\" aria-label={title}>\n <h2 className={css.modalTitle}>{title}</h2>\n <p className={css.confirmMessage}>{message}</p>\n <footer className={css.modalFooter}>\n <button type=\"button\" className={css.ghostButton} onClick={onCancel}>\n {t('delete.cancel')}\n </button>\n <button\n type=\"button\"\n className={danger ? css.dangerButton : css.primaryButton}\n onClick={onConfirm}\n >\n {confirmLabel}\n </button>\n </footer>\n </div>\n </div>\n )\n}\n","/**\n * Edit-task modal: title + description + the prompt the next execution will\n * send, pre-filled from the task. Shown only for tasks that have never\n * started executing (the detail view gates on canEditTaskContent); the Host\n * still re-checks at submit, so a task that started running while the modal\n * was open fails closed and the error surfaces here.\n */\nimport { useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { collectKnownTags, type TaskRecord, type TaskTag } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport { ModalShell, TaskContentFields, TaskTagFields, cleanTags } from './TaskForm.tsx'\n\n/** Edit-task form overlay. */\nexport function EditTaskModal({ controller, task, onClose }: { controller: BoardController; task: TaskRecord; onClose: () => void }) {\n const [title, setTitle] = useState(task.title)\n const [description, setDescription] = useState(task.description)\n const [prompt, setPrompt] = useState(task.prompt)\n const [tags, setTags] = useState<TaskTag[]>(task.tags ?? [])\n const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n\n const submit = async (): Promise<void> => {\n if (title.trim() === '') {\n setError(t('new.required'))\n return\n }\n setPending(true)\n // The Host confirms the mutation (and its fail-closed checks); only a\n // confirmed save closes the modal.\n // Labels ride the same patch as the content fields. A task that never\n // carried one is not sent a clearing null: the wire stays minimal, and the\n // no-tags path keeps producing exactly the patch it produced before.\n const tagList = cleanTags(tags)\n const patch = {\n title,\n description,\n prompt,\n ...(tagList.length > 0 ? { tags: tagList } : (task.tags === undefined ? {} : { tags: null })),\n }\n if (await controller.updateTask(task.id, patch)) {\n onClose()\n return\n }\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n }\n\n return (\n <ModalShell\n ariaLabel={t('edit.title')}\n title={t('edit.title')}\n error={error}\n pending={pending}\n submitLabel={t('edit.save')}\n onSubmit={() => { void submit() }}\n onClose={onClose}\n >\n <TaskContentFields\n title={title}\n description={description}\n prompt={prompt}\n onTitleChange={value => { setTitle(value); setError(undefined) }}\n onDescriptionChange={setDescription}\n onPromptChange={setPrompt}\n />\n\n <TaskTagFields tags={tags} knownTags={collectKnownTags(controller.getSnapshot().tasks)} onChange={setTags} />\n </ModalShell>\n )\n}\n\n/** Edit-tags modal: edit labels only, shown for tasks after first execution. */\nexport function EditTagsModal({ controller, task, onClose }: { controller: BoardController; task: TaskRecord; onClose: () => void }) {\n const [tags, setTags] = useState<TaskTag[]>(task.tags ?? [])\n const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n\n const submit = async (): Promise<void> => {\n setPending(true)\n const tagList = cleanTags(tags)\n const patch = {\n tags: tagList.length > 0 ? tagList : null,\n }\n if (await controller.updateTask(task.id, patch)) {\n onClose()\n return\n }\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n }\n\n return (\n <ModalShell\n ariaLabel={t('detail.editTags')}\n title={t('detail.editTags')}\n error={error}\n pending={pending}\n submitLabel={t('edit.save')}\n onSubmit={() => { void submit() }}\n onClose={onClose}\n >\n <TaskTagFields tags={tags} knownTags={collectKnownTags(controller.getSnapshot().tasks)} onChange={setTags} />\n </ModalShell>\n )\n}\n\n","/**\n * Task detail: the full view of one task — content, prompt, execution\n * history — and the only place execution can be triggered. Also offers\n * delete (with confirmation), manual status moves, and a jump to the\n * execution's session transcript.\n */\nimport { useEffect, useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { isValidCron } from '../../core/schedule.ts'\nimport { MANUAL_STATUSES, TASK_PERMISSIONS, tagTone, type ExecutionRecord, type TaskPermission, type TaskRecord } from '../../core/tasks.ts'\nimport { canEditTaskContent } from '../../core/use-cases/task-update.ts'\nimport { requiresPermissionConfirmation } from '../../core/handover.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\nimport css from '../board.module.css'\nimport { ConfirmDialog } from './ConfirmDialog.tsx'\nimport { EditTaskModal, EditTagsModal } from './EditTaskModal.tsx'\nimport { NewTaskModal } from './NewTaskModal.tsx'\nimport { formatHostTimestamp, formatTime } from './TaskCard.tsx'\nimport { STATUS_KEY } from './status-key.ts'\n\n/** Execution outcome → locale key. */\nconst RESULT_KEY: Record<NonNullable<ExecutionRecord['result']>, TaskBoardKey> = {\n succeeded: 'detail.result.succeeded',\n failed: 'detail.result.failed',\n cancelled: 'detail.result.cancelled',\n}\n\n/** One execution-history row. */\nfunction ExecutionRow({ execution, timeZone, onOpen }: { execution: ExecutionRecord; timeZone?: string; onOpen: (sessionId: string) => void }) {\n const result = execution.result\n return (\n <li className={css.executionRow} data-result={result}>\n <span className={css.executionBadge} data-result={result}>\n {result === undefined ? t('detail.result.running') : t(RESULT_KEY[result])}\n </span>\n <span className={css.executionTimes}>\n {t('detail.executionStarted')} {formatTime(execution.startedAt, timeZone)}\n {execution.endedAt !== undefined && ` · ${t('detail.executionEnded')} ${formatTime(execution.endedAt, timeZone)}`}\n </span>\n {execution.initiatedBy !== undefined && (\n <span className={css.executionTimes} title={execution.initiatedBy}>\n {t('detail.execution.initiator', { session: execution.initiatedBy })}\n </span>\n )}\n {execution.sessionId !== undefined && (\n <button\n type=\"button\"\n className={css.linkButton}\n onClick={() => { onOpen(execution.sessionId as string) }}\n title={execution.sessionId}\n >\n {t('detail.viewSession')} ⌁\n </button>\n )}\n {execution.error !== undefined && execution.error !== '' && (\n <span className={css.executionError}>{execution.error}</span>\n )}\n </li>\n )\n}\n\n/** The execution-target editor: workspace / mode / permission pickers. */\nfunction ExecutionSettingsSection({ controller, task, pending }: { controller: BoardController; task: TaskRecord; pending: boolean }) {\n const [options, setOptions] = useState(controller.getSnapshot().executionOptions)\n useEffect(\n () => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)),\n [controller],\n )\n const workspaceId = task.workspaceId ?? ''\n const mode = task.mode ?? ''\n const permission = task.permission ?? ''\n const model = task.model ?? ''\n // A pinned target may disappear from the runtime (workspace deleted,\n // preset removed); keep it selectable as a stale row instead of silently\n // dropping it, so the user sees exactly what the task will ask for.\n const workspaceKnown = workspaceId === '' || options.workspaces.some(item => item.workspaceId === workspaceId)\n const modeKnown = mode === '' || options.presets.some(item => item.id === mode)\n const modelKnown = model === '' || (options.models ?? []).some(item => item.id === model)\n return (\n <section className={css.detailSection}>\n <h4>{t('detail.executionSettings')}</h4>\n <p className={css.detailText}>{t('exec.hint')}</p>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.workspace')}</span>\n <select\n className={css.select}\n value={workspaceId}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { workspaceId: event.target.value }) }}\n >\n <option value=\"\">{t('exec.workspace.recent')}</option>\n {!workspaceKnown && <option value={workspaceId}>{workspaceId}{t('exec.mode.removed')}</option>}\n {options.workspaces.map(workspace => (\n <option key={workspace.workspaceId} value={workspace.workspaceId}>{workspace.title}</option>\n ))}\n </select>\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.mode')}</span>\n <select\n className={css.select}\n value={mode}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { mode: event.target.value }) }}\n >\n <option value=\"\">{t('exec.mode.default')}</option>\n {!modeKnown && <option value={mode}>{mode}{t('exec.mode.removed')}</option>}\n {options.presets.map(preset => (\n <option key={preset.id} value={preset.id} disabled={preset.broken !== undefined}>\n {preset.name ?? preset.id}\n {preset.isDefault ? t('exec.mode.defaultSuffix') : ''}\n {preset.broken !== undefined ? t('exec.mode.brokenSuffix') : ''}\n </option>\n ))}\n </select>\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.permission')}</span>\n <select\n className={css.select}\n value={permission}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { permission: event.target.value === '' ? undefined : event.target.value as TaskPermission }) }}\n >\n <option value=\"\">{t('exec.permission.default')}</option>\n {TASK_PERMISSIONS.map(id => (\n <option key={id} value={id}>{t(`exec.permission.${id}` as TaskBoardKey)}</option>\n ))}\n </select>\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.model')}</span>\n <select\n className={css.select}\n value={model}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { model: event.target.value === '' ? undefined : event.target.value }) }}\n >\n <option value=\"\">{t('exec.model.default')}</option>\n {!modelKnown && <option value={model}>{model}{t('exec.model.unknown')}</option>}\n {options.models?.map(item => (\n <option key={item.id} value={item.id}>{item.name ?? item.id}</option>\n ))}\n </select>\n </label>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={task.reuseSession === true}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { reuseSession: event.target.checked }) }}\n />\n <span>{t('exec.reuseSession')}</span>\n </label>\n <p className={css.detailText}>{t('exec.reuseSessionHint')}</p>\n </section>\n )\n}\n\n/** The scheduled-runs editor: enable toggle, cron input + presets, next-run info. */\nfunction ScheduleSection({ controller, task, pending }: { controller: BoardController; task: TaskRecord; pending: boolean }) {\n const schedule = task.schedule\n const [cron, setCron] = useState(schedule?.cron ?? '0 9 * * *')\n const [enabled, setEnabled] = useState(schedule?.enabled ?? false)\n const [nextRunAt, setNextRunAt] = useState<number | undefined>(schedule?.nextRunAt)\n const [lastTriggeredAt, setLastTriggeredAt] = useState<number | undefined>(schedule?.lastTriggeredAt)\n const [error, setError] = useState<string | undefined>(undefined)\n const timeZone = controller.getSnapshot().host?.scheduler.timeZone\n\n // Keep the editor in sync when the task record changes underneath (the\n // schedule rolls forward as runs trigger).\n useEffect(() => {\n setCron(schedule?.cron ?? '0 9 * * *')\n setEnabled(schedule?.enabled ?? false)\n setNextRunAt(schedule?.nextRunAt)\n setLastTriggeredAt(schedule?.lastTriggeredAt)\n setError(undefined)\n }, [task.id, schedule?.enabled, schedule?.cron, schedule?.nextRunAt, schedule?.lastTriggeredAt])\n\n /** Validate + persist the current cron text (Enter or blur). */\n const saveCron = (value: string): void => {\n const trimmed = value.trim()\n setCron(trimmed)\n if (trimmed === '' || !isValidCron(trimmed)) {\n setError(t('detail.schedule.invalid'))\n return\n }\n setError(undefined)\n controller.setSchedule(task.id, { cron: trimmed })\n }\n\n /** Arm/disarm the schedule (arming first persists the edited cron). */\n const toggleEnabled = (next: boolean): void => {\n const trimmed = cron.trim()\n if (next && (trimmed === '' || !isValidCron(trimmed))) {\n setError(t('detail.schedule.invalid'))\n return\n }\n setError(undefined)\n const submitted = controller.setSchedule(task.id, {\n enabled: next,\n ...(next && trimmed !== schedule?.cron ? { cron: trimmed } : {}),\n })\n if (submitted && !controller.isHostBacked()) setEnabled(next)\n }\n\n const applyPreset = (preset: string): void => {\n if (preset === '') return\n setCron(preset)\n setError(undefined)\n controller.setSchedule(task.id, { cron: preset })\n }\n\n const nextLabel = !enabled || nextRunAt === undefined\n ? t('detail.schedule.notScheduled')\n : nextRunAt <= Date.now()\n ? t('detail.schedule.dueSoon')\n : formatHostTimestamp(nextRunAt, timeZone)\n const lastLabel = lastTriggeredAt === undefined ? '—' : formatHostTimestamp(lastTriggeredAt, timeZone)\n\n return (\n <section className={css.detailSection}>\n <h4>{t('detail.schedule')}</h4>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={enabled}\n disabled={pending}\n onChange={event => { toggleEnabled(event.target.checked) }}\n />\n <span>{t('detail.schedule.enable')}</span>\n </label>\n <div className={css.scheduleRow}>\n <input\n className={`${css.input} ${css.scheduleInput}${error !== undefined ? ` ${css.scheduleInputInvalid}` : ''}`}\n value={cron}\n disabled={pending}\n placeholder=\"0 9 * * *\"\n spellCheck={false}\n aria-label={t('detail.schedule.cron')}\n onChange={event => { setCron(event.target.value); setError(undefined) }}\n onBlur={() => { saveCron(cron) }}\n onKeyDown={event => { if (event.key === 'Enter') saveCron(cron) }}\n />\n <select\n className={css.schedulePreset}\n value=\"\"\n disabled={pending}\n aria-label={t('detail.schedule.presets')}\n onChange={event => { applyPreset(event.target.value) }}\n >\n <option value=\"\">{t('detail.schedule.presets')}…</option>\n {SCHEDULE_PRESETS.map(preset => (\n <option key={preset.cron} value={preset.cron}>{t(preset.label)}</option>\n ))}\n </select>\n </div>\n {error !== undefined && <p className={css.formError}>{error}</p>}\n <p className={css.scheduleMeta}>\n {t('detail.schedule.nextRun')} {nextLabel}\n {' · '}{t('detail.schedule.lastTriggered')} {lastLabel}\n </p>\n </section>\n )\n}\n\n/** Task detail overlay. */\nexport function TaskDetail({ controller, task }: { controller: BoardController; task: TaskRecord }) {\n const [confirmDelete, setConfirmDelete] = useState(false)\n const [showEdit, setShowEdit] = useState(false)\n const [showEditTags, setShowEditTags] = useState(false)\n const [showDuplicate, setShowDuplicate] = useState(false)\n\n // Keep the overlay in sync if the task record changes underneath.\n const [latest, setLatest] = useState(task)\n useEffect(() => { setLatest(task) }, [task])\n // A re-used overlay instance must not carry an edit session across tasks.\n useEffect(() => {\n setShowEdit(false)\n setShowEditTags(false)\n setShowDuplicate(false)\n }, [task.id])\n const current = latest\n const snapshot = controller.getSnapshot()\n const running = current.status === 'running'\n const archived = current.archivedAt !== undefined\n const pending = snapshot.pendingTaskIds.includes(current.id)\n const transportError = snapshot.transportError\n const timeZone = snapshot.host?.scheduler.timeZone\n const permissionPending = requiresPermissionConfirmation(current, snapshot.host?.sessionDefaultPermission)\n\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) controller.closeTask() }}>\n <div className={css.detail} role=\"dialog\" aria-label={t('detail.title')}>\n <header className={css.detailHeader}>\n <h2 className={css.detailTitle}>{current.title}</h2>\n <span className={css.statusBadge} data-status={archived ? 'archived' : current.status}>\n {archived ? t('board.archive') : t(STATUS_KEY[current.status])}\n </span>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('detail.close')}\n onClick={() => { controller.closeTask() }}\n >\n ×\n </button>\n </header>\n\n <div className={css.detailBody}>\n {transportError !== undefined && (\n <div className={css.formError}>\n {t('board.hostError', { error: transportError })}{' '}\n <button type=\"button\" className={css.linkButton} onClick={() => { void controller.retryHostSync() }}>\n {t('board.retryHost')}\n </button>\n </div>\n )}\n <section className={css.detailSection}>\n <h4>{t('detail.description')}</h4>\n <p className={css.detailText}>{current.description !== '' ? current.description : '—'}</p>\n </section>\n\n {current.tags !== undefined && current.tags.length > 0 && (\n <section className={css.detailSection} data-dsh-part=\"tags\">\n <h4>{t('new.tags')}</h4>\n <div className={css.cardTags}>\n {current.tags.map(tag => (\n <span\n key={tag.name}\n className={css.cardTag}\n data-tag-tone={tagTone(tag.name)}\n data-dsh-part=\"tag-badge\"\n data-tag-hint={tag.promptPrefix === undefined ? undefined : tag.promptPrefix}\n title={tag.promptPrefix === undefined ? tag.name : tag.promptPrefix}\n >\n {tag.name}\n </span>\n ))}\n </div>\n </section>\n )}\n\n {current.freeze !== undefined && (\n <section className={css.detailSection} data-dsh-part=\"freeze\">\n <h4>{t('detail.freeze')}</h4>\n {current.freeze.redacted === true && <p className={css.formError}>{t('detail.freeze.redacted')}</p>}\n <p className={css.detailText}><strong>{t('detail.freeze.goal')}</strong></p>\n <pre className={css.promptBlock}>{current.freeze.goal}</pre>\n <p className={css.detailText}><strong>{t('detail.freeze.progress')}</strong></p>\n <pre className={css.promptBlock}>{current.freeze.progress}</pre>\n <p className={css.detailText}><strong>{t('detail.freeze.next')}</strong></p>\n <pre className={css.promptBlock}>{current.freeze.next}</pre>\n <p className={css.detailMeta}>{t('detail.freeze.frozenAt', { time: formatHostTimestamp(current.freeze.frozenAt, timeZone) })}</p>\n {current.freeze.frozenBy !== undefined && (\n <p className={css.detailMeta}>{t('detail.freeze.frozenBy', { session: current.freeze.frozenBy })}</p>\n )}\n </section>\n )}\n\n {current.handover !== undefined && (\n <section className={css.detailSection} data-dsh-part=\"handover\">\n <h4>{t('detail.handover')}</h4>\n <p className={css.detailText}>\n {t('new.workspace')}: {current.handover.workspaceId ?? t('exec.workspace.recent')}\n {' · '}{t('new.mode')}: {current.handover.mode ?? t('exec.mode.default')}\n {' · '}{t('new.permission')}: {current.handover.permission === undefined ? t('exec.permission.default') : t(`exec.permission.${current.handover.permission}` as TaskBoardKey)}\n </p>\n <p className={css.detailText}><strong>{t('detail.handover.references')}</strong></p>\n <ul className={css.executionList}>\n {current.handover.references.map((reference, index) => (\n // References are free text from the freeze block, so the same\n // string can appear twice; the index keeps the key unique (#1492).\n <li key={`${reference}-${index}`} className={css.executionRow}><code>{reference}</code></li>\n ))}\n </ul>\n <p className={css.detailMeta}>{t('detail.handover.bundledAt', { time: formatHostTimestamp(current.handover.bundledAt, timeZone) })}</p>\n </section>\n )}\n\n {permissionPending && (\n <section className={css.detailSection} data-dsh-part=\"permission-gate\">\n <p className={css.formError}>{t('detail.permissionPending', { permission: t(`exec.permission.${current.handover?.permission ?? current.permission}` as TaskBoardKey) })}</p>\n <button type=\"button\" className={css.primaryButton} disabled={pending} onClick={() => { void controller.confirmPermission(current.id) }}>\n {t('detail.permissionConfirm')}\n </button>\n </section>\n )}\n {current.permissionConfirmedAt !== undefined && (\n <p className={css.detailMeta}>{t('detail.permissionConfirmed', { time: formatHostTimestamp(current.permissionConfirmedAt, timeZone) })}</p>\n )}\n\n <section className={css.detailSection}>\n <h4>{t('detail.prompt')}</h4>\n <pre className={css.promptBlock}>{current.prompt !== '' ? current.prompt : current.title}</pre>\n </section>\n\n {!archived && (\n <>\n <ExecutionSettingsSection controller={controller} task={current} pending={pending} />\n <ScheduleSection controller={controller} task={current} pending={pending} />\n </>\n )}\n\n <section className={css.detailSection}>\n <h4>{t('detail.execution')}</h4>\n {current.executions.length === 0 ? (\n <p className={css.detailText}>{t('detail.noExecution')}</p>\n ) : (\n <ul className={css.executionList}>\n {[...current.executions].reverse().map(execution => (\n <ExecutionRow\n key={execution.id}\n execution={execution}\n timeZone={timeZone}\n onOpen={sessionId => { controller.openSession(sessionId) }}\n />\n ))}\n </ul>\n )}\n </section>\n\n {!archived && (\n <section className={css.detailSection}>\n <h4>{t('board.status')}</h4>\n <div className={css.moveRow}>\n {MANUAL_STATUSES.map(status => (\n <button\n key={status}\n type=\"button\"\n className={css.ghostButton}\n disabled={current.status === status || running || pending}\n onClick={() => { controller.moveTask(current.id, status) }}\n >\n {t(`status.move.${status}` as TaskBoardKey)}\n </button>\n ))}\n </div>\n </section>\n )}\n </div>\n\n <footer className={css.detailFooter}>\n {!archived && pending && <span className={css.detailMeta}>{t('board.pending')}…</span>}\n {!archived && canEditTaskContent(current) && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => { setShowEdit(true) }}\n >\n {t('detail.edit')}\n </button>\n )}\n {!archived && !canEditTaskContent(current) && current.status !== 'running' && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => { setShowEditTags(true) }}\n >\n {t('detail.editTags')}\n </button>\n )}\n {!archived && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => { setShowDuplicate(true) }}\n title={canEditTaskContent(current) ? t('detail.duplicate') : t('detail.duplicateAndEdit')}\n >\n {canEditTaskContent(current) ? t('detail.duplicate') : t('detail.duplicateAndEdit')}\n </button>\n )}\n {!archived && (\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={running || pending}\n onClick={() => {\n void controller.rerunTask(current.id).then(() => {\n if (controller.getSnapshot().transportError === undefined) controller.closeTask()\n })\n }}\n >\n {current.executions.length === 0 ? t('detail.run') : t('detail.rerun')}\n </button>\n )}\n {archived ? (\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={pending}\n onClick={() => {\n controller.restoreTask(current.id)\n }}\n >\n {t('detail.restore')}\n </button>\n ) : (\n (current.status === 'done' || current.status === 'failed') && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => {\n controller.archiveTask(current.id)\n }}\n >\n {t('detail.archive')}\n </button>\n )\n )}\n <button\n type=\"button\"\n className={css.dangerButton}\n disabled={pending}\n onClick={() => { setConfirmDelete(true) }}\n >\n {t('detail.delete')}\n </button>\n <span className={css.detailMeta}>\n {t('board.created')} {formatTime(current.createdAt, timeZone)}\n {archived && ` · ${t('detail.archivedAt', { time: formatTime(current.archivedAt!, timeZone) })}`}\n </span>\n </footer>\n </div>\n\n {confirmDelete && (\n <ConfirmDialog\n title={t('delete.title')}\n message={t('delete.confirm', { name: current.title })}\n confirmLabel={t('delete.ok')}\n danger\n onCancel={() => { setConfirmDelete(false) }}\n onConfirm={() => {\n setConfirmDelete(false)\n controller.deleteTask(current.id)\n }}\n />\n )}\n\n {showEdit && !archived && canEditTaskContent(current) && (\n <EditTaskModal controller={controller} task={current} onClose={() => { setShowEdit(false) }} />\n )}\n\n {showEditTags && !archived && current.status !== 'running' && (\n <EditTagsModal controller={controller} task={current} onClose={() => { setShowEditTags(false) }} />\n )}\n\n {showDuplicate && !archived && (\n <NewTaskModal\n controller={controller}\n initialTask={current}\n onClose={() => { setShowDuplicate(false) }}\n onDuplicateSuccess={async (sourceId) => {\n await controller.archiveTask(sourceId)\n controller.closeTask()\n }}\n />\n )}\n </div>\n )\n}\n","/**\n * Board view: the multi-column kanban that replaces the middle column while\n * active. Cards open the task detail (never execute directly); the header\n * offers filter, new-task, and a back-to-chat escape.\n */\nimport { memo, useCallback, useEffect, useState } from 'react'\nimport { selectedTaskOf, type BoardController } from '../../core/controller.ts'\nimport { COLUMNS, canMoveManually, collectKnownTags, tagTone, type TaskRecord } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\nimport { NewTaskModal } from './NewTaskModal.tsx'\nimport { STATUS_KEY } from './status-key.ts'\nimport { TaskCard } from './TaskCard.tsx'\nimport { TaskDetail } from './TaskDetail.tsx'\n\n/** Sentinel option value of the project row's \"register a new project\" entry. */\nexport const NEW_PROJECT_VALUE = '__dsh_new_project__'\n\n/** Case-insensitive title/description/tag/freeze-snapshot match. */\nexport function matchesFilter(task: TaskRecord, filter: string): boolean {\n if (filter.trim() === '') return true\n const needle = filter.trim().toLowerCase()\n const haystacks = [task.title, task.description, ...(task.tags ?? []).map(tag => tag.name)]\n if (task.freeze !== undefined) haystacks.push(task.freeze.goal, task.freeze.progress, task.freeze.next)\n return haystacks.some(text => text.toLowerCase().includes(needle))\n}\n\n/**\n * Whether a task carries every selected label (issue #1521). Multi-select is\n * conjunctive: adding a label narrows the board instead of widening it, which\n * is the only reading that keeps \"工作\" selected from dragging unrelated cards\n * back in when a second label is added.\n */\nexport function matchesTagFilter(task: TaskRecord, selected: readonly string[]): boolean {\n if (selected.length === 0) return true\n const names = new Set((task.tags ?? []).map(tag => tag.name))\n return selected.every(name => names.has(name))\n}\n\n/**\n * Memoized per-card adapter: with a stable `onOpen` from the board and an\n * immutable task record (only the changed card gets a new object ref), a card\n * re-renders only when its own task changes — not when a sibling card status,\n * the filter, or the selection moves.\n */\nconst MemoTaskCard = memo(function MemoTaskCard({ task, pending, timeZone, onOpen }: { task: TaskRecord; pending: boolean; timeZone?: string; onOpen: (id: string) => void }) {\n const onClick = useCallback(() => { onOpen(task.id) }, [task.id, onOpen])\n return <TaskCard task={task} pending={pending} timeZone={timeZone} onClick={onClick} />\n})\n\n/** Board component; subscribes to the controller snapshot. */\nexport function TaskBoard({ controller }: { controller: BoardController }) {\n const [snapshot, setSnapshot] = useState(controller.getSnapshot())\n useEffect(\n () => controller.subscribe(() => setSnapshot(controller.getSnapshot())),\n [controller],\n )\n const [filter, setFilter] = useState('')\n const [tagFilter, setTagFilter] = useState<string[]>([])\n const [showNew, setShowNew] = useState(false)\n // Project partition (#1536): '' means \"all projects\". A selected project\n // narrows the board and becomes the new-task form's default workspace.\n const [projectId, setProjectId] = useState('')\n const [showNewProject, setShowNewProject] = useState(false)\n const [newProjectPath, setNewProjectPath] = useState('')\n const [newProjectError, setNewProjectError] = useState<string | undefined>(undefined)\n const [newProjectPending, setNewProjectPending] = useState(false)\n const selected = selectedTaskOf(snapshot)\n const archiveView = snapshot.archiveView\n // Every label in use across the ledger (board and archive alike), so the\n // filter never loses an option just because its task was archived.\n const knownTags = collectKnownTags(snapshot.tasks)\n // Archived tasks leave the columns; the archive view shows them instead.\n const visible = snapshot.tasks.filter(task =>\n (archiveView ? task.archivedAt !== undefined : task.archivedAt === undefined)\n && (projectId === '' || task.workspaceId === projectId)\n && matchesFilter(task, filter)\n && matchesTagFilter(task, tagFilter),\n )\n const projects = snapshot.executionOptions.workspaces\n const canCreateProject = snapshot.canCreateWorkspace === true\n const submitNewProject = async (): Promise<void> => {\n const path = newProjectPath.trim()\n if (path === '') return\n setNewProjectPending(true)\n setNewProjectError(undefined)\n try {\n const created = await controller.createWorkspace(path)\n setProjectId(created.workspaceId)\n setShowNewProject(false)\n setNewProjectPath('')\n } catch (error) {\n setNewProjectError(error instanceof Error ? error.message : String(error))\n } finally {\n setNewProjectPending(false)\n }\n }\n const toggleTag = useCallback((name: string): void => {\n setTagFilter(current => current.includes(name)\n ? current.filter(entry => entry !== name)\n : [...current, name])\n }, [])\n const openTask = useCallback((id: string): void => { controller.openTask(id) }, [controller])\n\n return (\n <div className={css.board} data-dsh-taskboard-board=\"\" data-dsh-plugin=\"task-board\">\n <header className={css.boardHeader}>\n {/* Shared hook: dsh-web-all offsets center-view back controls beside the collapsed mobile sidebar. */}\n <button\n type=\"button\"\n className={`${css.ghostButton} ${css.backButton}`}\n data-dsh-center-view-back=\"\"\n aria-label={t('board.close')}\n onClick={() => { controller.closeBoard() }}\n >\n <span aria-hidden=\"true\">‹</span>\n <span>{t('board.close')}</span>\n </button>\n <h2 className={css.boardTitle}>{t('board.title')}</h2>\n {snapshot.host !== undefined && (\n <span className={css.detailMeta}>\n {t('board.hostMeta', {\n revision: String(snapshot.host.revision),\n timeZone: snapshot.host.scheduler.timeZone,\n })}\n </span>\n )}\n {(projects.length > 0 || canCreateProject) && (\n <label className={css.projectFilter}>\n <span className={css.projectFilterLabel}>{t('board.project')}</span>\n <select\n className={css.select}\n data-dsh-part=\"project-filter\"\n value={projectId}\n aria-label={t('board.project')}\n onChange={event => {\n const value = event.target.value\n if (value === NEW_PROJECT_VALUE) {\n setNewProjectError(undefined)\n setShowNewProject(true)\n return\n }\n setProjectId(value)\n }}\n >\n <option value=\"\">{t('board.projectAll')}</option>\n {projects.map(project => (\n <option key={project.workspaceId} value={project.workspaceId}>{project.title}</option>\n ))}\n {canCreateProject && <option value={NEW_PROJECT_VALUE}>{t('board.projectNew')}</option>}\n </select>\n </label>\n )}\n <input\n className={css.search}\n type=\"search\"\n placeholder={t('board.search')}\n value={filter}\n onChange={event => { setFilter(event.target.value) }}\n aria-label={t('board.search')}\n />\n <button\n type=\"button\"\n className={archiveView ? css.primaryButton : css.ghostButton}\n onClick={() => { controller.toggleArchiveView() }}\n >\n {archiveView\n ? t('board.backToBoard')\n : t('board.archiveView', { count: String(snapshot.tasks.filter(task => task.archivedAt !== undefined).length) })}\n </button>\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => { setShowNew(true) }}\n >\n + {t('board.new')}\n </button>\n </header>\n\n {showNewProject && (\n <div className={css.projectDialog} data-dsh-part=\"project-dialog\">\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('board.projectNewPath')}</span>\n <input\n className={css.input}\n value={newProjectPath}\n placeholder={t('board.projectNewPathPlaceholder')}\n spellCheck={false}\n onChange={event => { setNewProjectPath(event.target.value); setNewProjectError(undefined) }}\n />\n </label>\n {newProjectError !== undefined && <p className={css.formError}>{t('board.projectCreateFailed', { error: newProjectError })}</p>}\n <div className={css.projectDialogActions}>\n <button\n type=\"button\"\n className={css.ghostButton}\n onClick={() => { setShowNewProject(false); setNewProjectError(undefined) }}\n >\n {t('new.cancel')}\n </button>\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={newProjectPending || newProjectPath.trim() === ''}\n onClick={() => { void submitNewProject() }}\n >\n {t('board.projectCreate')}\n </button>\n </div>\n </div>\n )}\n\n {!archiveView && knownTags.length > 0 && (\n <div className={css.tagFilter} data-dsh-part=\"tag-filter\">\n <span className={css.tagFilterLabel}>{t('board.tagFilter')}</span>\n {knownTags.map(tag => {\n const active = tagFilter.includes(tag.name)\n return (\n <button\n key={tag.name}\n type=\"button\"\n className={css.tagChip}\n data-dsh-part=\"tag-chip\"\n data-tag-tone={tagTone(tag.name)}\n data-active={active ? 'true' : undefined}\n aria-pressed={active}\n title={tag.promptPrefix === undefined ? tag.name : tag.promptPrefix}\n onClick={() => { toggleTag(tag.name) }}\n >\n {tag.name}\n </button>\n )\n })}\n {tagFilter.length > 0 && (\n <button type=\"button\" className={css.linkButton} onClick={() => { setTagFilter([]) }}>\n {t('board.tagFilterClear')}\n </button>\n )}\n </div>\n )}\n\n {snapshot.transportError !== undefined && (\n <div className={css.formError}>\n {t('board.hostError', { error: snapshot.transportError })}{' '}\n <button type=\"button\" className={css.linkButton} onClick={() => { void controller.retryHostSync() }}>\n {t('board.retryHost')}\n </button>\n </div>\n )}\n\n <div className={css.columns}>\n {archiveView ? (\n <section className={css.column} data-status=\"archived\" data-dsh-part=\"column\">\n <header className={css.columnHeader}>\n <h3 className={css.columnTitle}>{t('board.archive')}</h3>\n <span className={css.columnCount}>{visible.length}</span>\n </header>\n <div className={css.cards}>\n {visible.map(task => (\n <MemoTaskCard key={task.id} task={task} pending={snapshot.pendingTaskIds.includes(task.id)} timeZone={snapshot.host?.scheduler.timeZone} onOpen={openTask} />\n ))}\n {visible.length === 0 && (\n <div className={css.columnEmpty}>{tagFilter.length > 0 ? t('board.tagEmpty') : t('archive.empty')}</div>\n )}\n </div>\n </section>\n ) : (\n COLUMNS.map(column => {\n const tasks = visible.filter(task => task.status === column.status)\n const isManualDropTarget = column.status === 'backlog' || column.status === 'todo'\n return (\n <section\n key={column.status}\n className={css.column}\n data-status={column.status}\n data-dsh-part=\"column\"\n onDragOver={isManualDropTarget ? (event) => {\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n } : undefined}\n onDrop={isManualDropTarget ? (event) => {\n event.preventDefault()\n const taskId = event.dataTransfer.getData('text/plain')\n if (!taskId) return\n const dropped = snapshot.tasks.find(t => t.id === taskId)\n if (dropped && canMoveManually(dropped.status, column.status) && dropped.status !== column.status) {\n controller.moveTask(taskId, column.status)\n }\n } : undefined}\n >\n <header className={css.columnHeader}>\n <span className={css.statusDot} data-status={column.status} aria-hidden=\"true\" />\n <h3 className={css.columnTitle}>{t(STATUS_KEY[column.status])}</h3>\n <span className={css.columnCount}>{tasks.length}</span>\n </header>\n <div className={css.cards}>\n {tasks.map(task => (\n <MemoTaskCard key={task.id} task={task} pending={snapshot.pendingTaskIds.includes(task.id)} timeZone={snapshot.host?.scheduler.timeZone} onOpen={openTask} />\n ))}\n {tasks.length === 0 && (\n <div className={css.columnEmpty}>{tagFilter.length > 0 ? t('board.tagEmpty') : t('board.empty')}</div>\n )}\n </div>\n </section>\n )\n })\n )}\n </div>\n\n {selected !== undefined && (\n <TaskDetail controller={controller} task={selected} />\n )}\n {showNew && (\n <NewTaskModal\n controller={controller}\n {...(projectId === '' ? {} : { defaultWorkspaceId: projectId })}\n onClose={() => { setShowNew(false) }}\n />\n )}\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/body-mutations.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * One `document.body` MutationObserver per page, shared by every family\n * plugin bundle.\n *\n * Family plugins that inject at the DOM level must notice when the shell\n * re-renders around their injected node: the sidebar entry rows\n * (sidebar-entry-core), the center-column panel containers\n * (panel-mount-core), and the aggregate shell's column shims. Each consumer\n * used to install its OWN `MutationObserver` on `document.body` with\n * `{ childList: true, subtree: true }`, so a page carrying N family plugins\n * paid N native observers and N callback invocations for EVERY mutation batch\n * the app produced — chat token streaming alone produces many per second, and\n * the count grows with the number of installed plugins.\n *\n * This module keeps exactly ONE body observer per page. The registry lives on\n * `globalThis` under a `Symbol.for` key, so the per-package generated copies\n * of this file (scripts/sync-shared.mjs) and separately bundled plugins all\n * reach the same hub at runtime instead of one hub per module instance.\n * Record subscribers receive the mutations accumulated since the last flush.\n * Consumers that only re-check their DOM use subscribeBodyInvalidations:\n * when all subscribers use that path, the hub retains no mutation records\n * (or detached subtrees) while a background page's animation frames pause.\n * Both paths run at most once per frame. The last subscriber disconnects the\n * observer, cancels the pending frame and releases its records.\n *\n * Failure policy: without a DOM or `MutationObserver` the subscription is a\n * no-op disposer (the same silence the per-consumer observers had), and when\n * `requestAnimationFrame` is unavailable the flush runs synchronously so a\n * subscriber is never silently dropped. A throwing subscriber cannot stop the\n * others.\n */\n\n/** The page-wide hub: one observer plus its subscribers and pending records. */\ninterface BodyMutationHub {\n observer: MutationObserver\n subscribers: Set<(records: MutationRecord[]) => void>\n pending: MutationRecord[]\n scheduled: boolean\n frame?: number\n}\n\n/** Cross-bundle registry key; `Symbol.for` so every module copy agrees. */\nconst HUB_KEY = Symbol.for('dsh-web.body-mutation-hub')\nconst INVALIDATION_ONLY = Symbol.for('dsh-web.body-mutation-invalidation')\ntype Subscriber = ((records: MutationRecord[]) => void) & { [INVALIDATION_ONLY]?: true }\n\nfunction needsRecords(subscribers: Set<(records: MutationRecord[]) => void>): boolean {\n for (const listener of subscribers) {\n if (!(listener as Subscriber)[INVALIDATION_ONLY]) return true\n }\n return false\n}\n\n/**\n * Subscribe to a coalesced DOM re-check without retaining mutation records.\n * The marked wrapper also works with an older hub, which delivers records\n * that it simply ignores until a page reload picks up the updated hub.\n */\nexport function subscribeBodyInvalidations(subscriber: () => void): () => void {\n const listener: Subscriber = () => { subscriber() }\n listener[INVALIDATION_ONLY] = true\n return subscribeBodyMutations(listener)\n}\n\n/**\n * Subscribe to body-level childList mutations.\n * @param subscriber - called at most once per animation frame with the records\n * collected since the previous flush; must be safe to run repeatedly.\n * @returns the disposer removing this subscriber (and the observer when it was\n * the last one).\n */\nexport function subscribeBodyMutations(subscriber: (records: MutationRecord[]) => void): () => void {\n if (typeof globalThis === 'undefined' || typeof document === 'undefined') return () => {}\n if (typeof MutationObserver !== 'function') return () => {}\n const registry = globalThis as unknown as Record<symbol, unknown>\n let hub = registry[HUB_KEY] as BodyMutationHub | undefined\n if (hub === undefined) {\n const subscribers = new Set<(records: MutationRecord[]) => void>()\n const created: BodyMutationHub = {\n observer: undefined as unknown as MutationObserver,\n subscribers,\n pending: [],\n scheduled: false,\n }\n const flush = (): void => {\n created.frame = undefined\n created.scheduled = false\n const batch = created.pending\n created.pending = []\n for (const listener of [...subscribers]) {\n if (!subscribers.has(listener)) continue\n try {\n listener(batch)\n } catch {\n // One subscriber must never break the others; the next flush retries it.\n }\n }\n }\n const schedule = (): void => {\n if (created.scheduled) return\n created.scheduled = true\n if (typeof requestAnimationFrame === 'function') created.frame = requestAnimationFrame(flush)\n else flush()\n }\n created.observer = new MutationObserver((records) => {\n if (needsRecords(subscribers)) {\n for (const record of records) created.pending.push(record)\n }\n schedule()\n })\n created.observer.observe(document.body ?? document.documentElement, { childList: true, subtree: true })\n registry[HUB_KEY] = created\n hub = created\n }\n const active = hub\n active.subscribers.add(subscriber)\n let subscribed = true\n return () => {\n if (!subscribed) return\n subscribed = false\n active.subscribers.delete(subscriber)\n if (!needsRecords(active.subscribers)) active.pending = []\n if (active.subscribers.size === 0 && registry[HUB_KEY] === active) {\n active.observer.disconnect()\n if (active.frame !== undefined && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(active.frame)\n active.frame = undefined\n active.pending = []\n active.scheduled = false\n delete registry[HUB_KEY]\n }\n }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/panel-mount-core.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Center-column panel takeover lifecycle.\n *\n * The `conversation` slot is single-occupant (ui-conversation) and external\n * plugins cannot declare slots, so a family panel takes over the center\n * column at the DOM level: a container is appended inside the center column\n * (`[class*=\"centerCol\"]`, the 0.1.0-rc.6+ AppFrame layout; previously\n * `[data-pane=\"conversation\"]` on older shells — the mount selector keeps\n * both, ssh #243 / task-board #107) as an extra trailing child React never\n * manages, and a stylesheet rule hides the conversation content while the\n * panel is active. Toggling is a data attribute on <html> — no React\n * involvement, so the conversation subtree underneath stays mounted and\n * stateful.\n *\n * Consuming plugins keep a thin wrapper that supplies the panel tree,\n * container attribute names, and stylesheet class; those names are pinned by\n * each package's CSS, skins, and the semantic-attributes contract. The\n * sidebar row toggling the panel shares its core the same way\n * (shared/client/sidebar-entry-core.ts, synced copy).\n */\nimport { createRoot, type Root } from 'react-dom/client'\nimport { subscribeBodyInvalidations } from './body-mutations.ts'\n\n/** Options for mountCenterPanel; dsh-ssh mount.tsx and dsh-task-board board-mount.tsx are the canonical consumers. */\nexport interface CenterPanelMountOptions {\n /** Render the panel tree (first open, remount while open, locale refresh). */\n render: (root: Root) => void\n /** dataset key of the injected container's view attribute, e.g. `dshSshView` for `data-dsh-ssh-view`. */\n viewDatasetKey: string\n /** value of the container's L2 `data-dsh-plugin` semantic attribute. */\n pluginName: string\n /** stylesheet class applied to the injected container. */\n viewClassName: string\n /** <html> attribute set while this panel is active. */\n activeAttribute: string\n /** the sibling panel's active attribute, removed from <html> when this panel opens. */\n siblingActiveAttribute: string\n /** detail value this panel broadcasts on the cross-plugin activation event. */\n panelName: string\n /** sibling detail value whose activation closes this panel. */\n siblingPanelName: string\n /** open flag of the owning controller. */\n isOpen: () => boolean\n /** close the panel, handing the center column back to the conversation. */\n close: () => void\n /** subscribe to the owning controller's open-state changes; returns an unsubscriber. */\n subscribe: (listener: () => void) => () => void\n /** locale-change source; when given, re-renders an open panel on a Language switch. */\n locale?: { subscribe(listener: () => void): () => void }\n}\n\nconst CONVERSATION_COLUMN_SELECTOR = '[data-pane=\"conversation\"], [class*=\"centerCol\"]'\n/** Cross-plugin activation event; detail is the activating panel name. */\nconst ACTIVATE_EVENT = 'dsh-panel-activate'\n// Sidebar rows whose clicks hand the center column back to the conversation\n// (including the already-current row, which produces no session-change\n// event). Capture phase, so the panel closes before the shell processes the\n// click.\nconst SIDEBAR_ROW_SELECTOR = '[class*=\"sessionRow\"], [class*=\"projectRow\"], [class*=\"searchResultRow\"], [class*=\"searchResultWorkspace\"], [class*=\"newSession\"]'\n\n/** Find the center column, or undefined while the frame is not mounted. */\nfunction conversationColumn(): HTMLElement | undefined {\n return document.querySelector<HTMLElement>(CONVERSATION_COLUMN_SELECTOR) ?? undefined\n}\n\n/**\n * Mount a family panel into the center column and bind its visibility to the\n * owning controller's open state.\n * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountCenterPanel(options: CenterPanelMountOptions): () => void {\n let root: Root | undefined\n let container: HTMLDivElement | undefined\n let unsubscribeLocale: (() => void) | undefined\n try {\n unsubscribeLocale = options.locale?.subscribe(() => {\n if (root !== undefined) options.render(root)\n })\n } catch { /* locale service absent: the panel follows its next natural re-render */ }\n\n const ensure = (): void => {\n if (container !== undefined && !container.isConnected) {\n // The conversation pane was replaced; drop the stale tree and remount.\n root?.unmount()\n root = undefined\n container.remove()\n container = undefined\n }\n if (container === undefined) {\n const column = conversationColumn()\n if (column === undefined) return\n container = document.createElement('div')\n container.dataset[options.viewDatasetKey] = ''\n container.dataset.dshPlugin = options.pluginName\n container.className = options.viewClassName\n column.appendChild(container)\n }\n // Keep a visited tree mounted so drafts and terminal sessions survive\n // close/reopen; an unused panel needs neither a React root nor effects.\n if (root !== undefined || !options.isOpen()) return\n root = createRoot(container)\n options.render(root)\n }\n\n // The frame mounts after boot settlement; watch for the column's arrival.\n // The observation is the page-wide hub (shared/client/body-mutations.ts):\n // every family panel used to hold its own document.body subtree observer, so\n // the per-mutation cost grew with the number of installed plugins.\n const unsubscribeBody = subscribeBodyInvalidations(() => { ensure() })\n\n const applyActive = (): void => {\n if (options.isOpen()) {\n ensure()\n // Single-occupant center column: opening this panel must evict the\n // sibling panel, both its html attribute and its controller state,\n // otherwise the two panels' visibility rules fight and the second\n // click appears dead.\n document.documentElement.removeAttribute(options.siblingActiveAttribute)\n document.documentElement.setAttribute(options.activeAttribute, '')\n document.dispatchEvent(new CustomEvent(ACTIVATE_EVENT, { detail: options.panelName }))\n } else {\n document.documentElement.removeAttribute(options.activeAttribute)\n }\n }\n const onOtherActivate = (event: Event): void => {\n if ((event as CustomEvent).detail === options.siblingPanelName && options.isOpen()) {\n options.close()\n }\n }\n const onClickSidebarRow = (event: MouseEvent): void => {\n if (!options.isOpen()) return\n const target = event.target as HTMLElement | null\n if (target === null) return\n if (target.closest(SIDEBAR_ROW_SELECTOR) !== null) options.close()\n }\n document.addEventListener('click', onClickSidebarRow, true)\n document.addEventListener(ACTIVATE_EVENT, onOtherActivate)\n const unsubscribe = options.subscribe(applyActive)\n applyActive()\n ensure()\n\n return () => {\n document.removeEventListener('click', onClickSidebarRow, true)\n document.removeEventListener(ACTIVATE_EVENT, onOtherActivate)\n unsubscribeBody()\n unsubscribe()\n unsubscribeLocale?.()\n document.documentElement.removeAttribute(options.activeAttribute)\n root?.unmount()\n root = undefined\n container?.remove()\n container = undefined\n }\n}\n","/**\n * Board view mounting (dsh-task-board wrapper).\n *\n * The single-occupant takeover lifecycle — container injection into the\n * center column, sibling eviction, remount resilience, sidebar click-out —\n * lives exactly once in shared/client/panel-mount-core.ts (synced copy); this\n * wrapper supplies the board tree, view dataset key, CSS module, and the html\n * attribute names. Those names are pinned by board.module.css, skins, and the\n * semantic attributes contract.\n */\nimport type { BoardController } from '../core/controller.ts'\nimport { TaskBoard } from './board/TaskBoard.tsx'\nimport { mountCenterPanel } from './panel-mount-core.ts'\nimport type { LocaleRefreshSource } from './sidebar-entry.ts'\nimport css from './board.module.css'\n\n/** The injected board container (kept in the DOM, hidden when inactive). */\nexport const BOARD_VIEW_SELECTOR = '[data-dsh-taskboard-view]'\n\n/**\n * Mount the board React tree into the center column and bind its visibility\n * to the controller's boardOpen state.\n * @param controller - the board controller driving the view.\n * @param locale - locale-change source; when given, re-renders a mounted board\n * on a Language switch.\n * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountBoard(controller: BoardController, locale?: LocaleRefreshSource): () => void {\n return mountCenterPanel({\n render: root => root.render(<TaskBoard controller={controller} />),\n viewDatasetKey: 'dshTaskboardView',\n pluginName: 'task-board',\n viewClassName: css.boardView,\n activeAttribute: 'data-dsh-taskboard-active',\n siblingActiveAttribute: 'data-dsh-ssh-active',\n panelName: 'taskboard',\n siblingPanelName: 'ssh',\n isOpen: () => controller.getSnapshot().boardOpen,\n close: () => controller.closeBoard(),\n subscribe: listener => controller.subscribe(listener),\n locale,\n })\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/sidebar-entry-core.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Shared sidebar entry injection core.\n *\n * dsh's sidebar shell exposes no slot an external plugin can register into,\n * so the entry row is injected between the shell's New Session button and the\n * workspace browser. The injection self-heals: a MutationObserver watches the\n * sidebar root and re-inserts the row whenever a React re-render displaces it\n * (re-insertion happens in the same frame, before paint, so no flicker).\n *\n * The row is plain DOM (no React tree) so it can never disturb the shell's\n * reconciliation; the view it toggles is a separate root owned by the caller.\n *\n * Packages receive this file as a generated copy via scripts/sync-shared.mjs;\n * edit the shared source and re-run the sync instead of editing a copy.\n */\nimport { subscribeBodyInvalidations } from './body-mutations.ts'\n\n/** Per-package configuration for one sidebar entry row. */\nexport interface SidebarEntryOptions {\n /** Full attribute name identifying the injected row (idempotency key), e.g. 'data-dsh-ssh-entry'. */\n rowAttribute: string\n /** CSS selector matching the injected row, e.g. '[data-dsh-ssh-entry]'. */\n rowSelector: string\n /**\n * L2 semantic-attribute plugin id (issue #506, enum table:\n * skins/skin-center/contracts/semantic-attrs-v1.md). When set, the row also\n * outputs data-dsh-plugin=\"<id>\" and data-dsh-part=\"sidebar-entry\"; unset\n * leaves the row without semantic attributes.\n */\n plugin?: string\n /** Inline icon markup (matches the shell's 16px nav-icon look). */\n icon: string\n /** CSS module class names for the row and its two spans (entry / entryIcon / entryLabel). */\n css: Record<string, string>\n /** Localized row label (aria-label + visible text). */\n label(): string\n /** Optional localized tooltip (title attribute). */\n tooltip?(): string\n /**\n * Optional locale-change subscription: re-applies label / aria-label /\n * tooltip whenever the active locale changes. Plain-DOM rows would\n * otherwise keep the label captured at mount; pass the SDK locale runtime\n * subscription (ctx.locale.subscribe) so the row follows the language\n * switch without a reload.\n */\n refresh?: { subscribe(listener: () => void): () => void }\n /** Click action (open/toggle the owning panel). */\n onToggle(): void\n /** Family-block position: 'before' inserts ahead of sibling plugin rows, 'after' behind them. */\n position: 'before' | 'after'\n /**\n * Selectors of the sibling plugin entry rows this package orders against\n * (its own row included — the placement guard excludes a row that is\n * already inside the root). Each package passes the same list it used\n * before the consolidation so the rendered order stays stable.\n */\n familySelectors: readonly string[]\n /** Optional active-state bridge; highlights the row while the panel is open. */\n active?: {\n subscribe(listener: () => void): () => void\n isOpen(): boolean\n }\n}\n\n/** Find the sidebar shell root element, or undefined while not yet mounted. */\nfunction sidebarRoot(): HTMLElement | undefined {\n const column = document.querySelector<HTMLElement>('[data-pane=\"sidebar\"], [class*=\"sidebarCol\"]')\n if (column === null) return undefined\n // Current shells wrap the sidebar UI: column > wrapper > root(logoRow owner).\n // Prefer the element that owns the logo row — the real sidebar UI root —\n // and fall back to the column's first child for legacy shells.\n const logoOwner = column.querySelector<HTMLElement>('[class*=\"logoRow\"]')?.parentElement\n return logoOwner ?? (column.firstElementChild as HTMLElement | undefined)\n}\n\n/** The New Session button: nested in the logo row on current shells, a direct child on legacy shells. */\nfunction newSessionButton(root: HTMLElement): HTMLButtonElement | undefined {\n const nested = root.querySelector<HTMLButtonElement>('button[class*=\"newSession\"]')\n if (nested !== null) return nested\n for (const child of root.children) {\n if (child.tagName === 'BUTTON') return child as HTMLButtonElement\n }\n return undefined\n}\n\n/** Build the entry row (detached; inserted once the shell is up). */\nfunction createEntry(options: SidebarEntryOptions): { entry: HTMLElement; applyLabel: () => void } {\n const entry = document.createElement('button')\n entry.type = 'button'\n entry.setAttribute(options.rowAttribute, '')\n if (options.plugin !== undefined) {\n entry.setAttribute('data-dsh-plugin', options.plugin)\n entry.setAttribute('data-dsh-part', 'sidebar-entry')\n }\n entry.className = options.css['entry'] ?? ''\n const labelSpan = document.createElement('span')\n labelSpan.className = options.css['entryLabel'] ?? ''\n const iconSpan = document.createElement('span')\n iconSpan.className = options.css['entryIcon'] ?? ''\n iconSpan.innerHTML = options.icon\n entry.append(iconSpan, labelSpan)\n const applyLabel = (): void => {\n entry.setAttribute('aria-label', options.label())\n if (options.tooltip !== undefined) entry.setAttribute('title', options.tooltip())\n labelSpan.textContent = options.label()\n }\n applyLabel()\n entry.addEventListener('click', options.onToggle)\n return { entry, applyLabel }\n}\n\n/** Re-insert the entry after the New Session row (before the browser region). */\nfunction placeEntry(root: HTMLElement, entry: HTMLElement, options: SidebarEntryOptions): boolean {\n const button = newSessionButton(root)\n if (button === undefined) return false\n if (entry.parentElement !== root) {\n // Position relative to the family block (entries injected by sibling\n // plugins), never relative to transient logoRow geometry: every family\n // plugin that self-heals during a re-render then lands in the same\n // relative order, so the entries cannot swap positions regardless of\n // observer callback order or of shell wrapper changes. There is no\n // append-to-end fallback: appending at the end would randomly reorder\n // the block after a shell re-render.\n const row = button.closest('[class*=\"logoRow\"]')\n const base = (row !== null && row.parentElement === root) ? row : button\n const family = Array.from(root.children).filter(\n (el): el is HTMLElement => el instanceof HTMLElement && el.matches(options.familySelectors.join(', ')),\n )\n const anchor = options.position === 'before'\n ? (family.length > 0 ? family[0] : base.nextElementSibling)\n : (family.length > 0 ? family[family.length - 1]!.nextElementSibling : base.nextElementSibling)\n root.insertBefore(entry, anchor)\n }\n return true\n}\n\n/**\n * Mount the sidebar entry, waiting for the shell to render and self-healing\n * on later React re-renders.\n * @param options - the row's attribute/icon/copy/action/ordering configuration.\n * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(options: SidebarEntryOptions): () => void {\n // DOM-level idempotency: whatever path mounted an entry row before this\n // call (a duplicated apply, an HMR re-injection, a stale module still\n // alive), never mount a second one. The existing row keeps working; a full\n // page reload is the ultimate reset.\n if (typeof document !== 'undefined' && document.querySelector(options.rowSelector) !== null) {\n return () => {}\n }\n const { entry, applyLabel } = createEntry(options)\n let root: HTMLElement | undefined\n let placed = false\n let unsubscribeRefresh: (() => void) | undefined\n if (options.refresh !== undefined) {\n try {\n unsubscribeRefresh = options.refresh.subscribe(applyLabel)\n } catch {\n // A throwing subscription must not break the mount; the label stays at\n // its initial value and the next reload resolves it again.\n }\n }\n\n const tryPlace = (): void => {\n if (root !== undefined && !root.isConnected) {\n // The shell rebuilt the sidebar pane (whole-tree teardown); the root\n // observer is gone with the old tree, so detach it and re-query from\n // scratch. The new pane is later noticed by the body-level watcher.\n rootObserver.disconnect()\n root = undefined\n placed = false\n }\n if (placed) {\n // Cheap short-circuit: entry still lives in a mountable subtree.\n if (document.body.contains(entry)) return\n // Entry was torn down together with the old tree; reset and re-place.\n rootObserver.disconnect()\n root = undefined\n placed = false\n }\n root ??= sidebarRoot()\n if (root === undefined) return\n placed = placeEntry(root, entry, options)\n if (placed) {\n rootObserver.observe(root, { childList: true, subtree: true })\n }\n }\n\n // Body-level watcher retained as the \"whole rebuild\" fallback: when the shell\n // tears down the whole sidebar pane, the root observer is gone with it and\n // only this body observation can notice the new pane mounting. It stays\n // subscribed after placement; the placed-and-still-mounted case\n // short-circuits through the cheap document.body.contains(entry) check, so\n // unrelated app mutations (e.g. chat streaming) cost one contains check per\n // frame instead of churning the full re-query. The body observation itself is\n // the page-wide hub (shared/client/body-mutations.ts): every family plugin\n // used to hold its own body subtree observer, so the per-mutation cost grew\n // with the number of installed plugins; the hub keeps exactly one.\n const unsubscribeBody = subscribeBodyInvalidations(() => { tryPlace() })\n\n // Self-heal: if a React re-render displaces the row, re-insert it in the\n // same frame (microtask before paint -> no visible flicker).\n const rootObserver = new MutationObserver(() => {\n if (root === undefined || !root.isConnected) {\n placed = false\n tryPlace()\n return\n }\n if (!root.contains(entry)) {\n placed = placeEntry(root, entry, options)\n }\n })\n\n // Reflect the panel's open state on the row (active highlight). Note: assigning\n // undefined to dataset.active materializes data-active=\"undefined\" and keeps the\n // row permanently highlighted — delete the attribute instead.\n const unsubscribeActive = options.active === undefined ? undefined : (() => {\n const syncActive = (): void => {\n if (options.active!.isOpen()) entry.dataset.active = 'true'\n else delete entry.dataset.active\n }\n const unsubscribe = options.active.subscribe(syncActive)\n syncActive()\n return unsubscribe\n })()\n\n tryPlace()\n\n return () => {\n unsubscribeBody()\n rootObserver.disconnect()\n unsubscribeRefresh?.()\n unsubscribeActive?.()\n entry.remove()\n }\n}\n","/**\n * Sidebar entry injection — package-specific wiring over the shared core.\n *\n * dsh's sidebar shell exposes no slot an external plugin can register into\n * (`sidebar.workspaces` / `sidebar.settings` are single-occupant and already\n * taken), so the entry row is injected between the shell's New Session button\n * and the workspace browser. The DOM injection / self-healing / idempotency\n * logic lives exactly once in shared/client/sidebar-entry-core.ts (synced\n * copy); this wrapper supplies the task-board icon, copy, CSS module, and the\n * board toggle. The row is plain DOM (no React tree); the board view it\n * toggles is a separate React root mounted in the center column\n * (see board-mount.ts).\n */\nimport type { BoardController } from '../core/controller.ts'\nimport { t } from './locales.ts'\nimport css from './board.module.css'\nimport { mountSidebarEntry as mountSharedSidebarEntry } from './sidebar-entry-core.ts'\n\n/** Stable data attribute identifying the injected entry row. */\nexport const ENTRY_SELECTOR = '[data-dsh-taskboard-entry]'\n\n/** Inline icon normalized to the shell's 16px navigation glyph size. */\nconst ICON = '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"2\" y=\"2.5\" width=\"12\" height=\"11\" rx=\"1.5\"/><path d=\"M2 6.5h12M6.5 6.5v7\"/></svg>'\n\n/** Locale-change subscription the shared core asks for (ctx.locale.subscribe shape). */\nexport interface LocaleRefreshSource { subscribe(listener: () => void): () => void }\n\n/**\n * Mount the sidebar entry, waiting for the shell to render and self-healing\n * on later React re-renders.\n * @param controller - the board controller the entry toggles.\n * @param locale - locale-change source; when given, re-applies the label on\n * a Language switch (the plain-DOM row otherwise keeps the mount-time copy).\n * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(controller: BoardController, locale?: LocaleRefreshSource): () => void {\n return mountSharedSidebarEntry({\n rowAttribute: 'data-dsh-taskboard-entry',\n rowSelector: ENTRY_SELECTOR,\n plugin: 'task-board',\n icon: ICON,\n css,\n label: () => t('entry.label'),\n refresh: locale === undefined ? undefined : { subscribe: (listener) => locale.subscribe(listener) },\n onToggle: () => { controller.toggleBoard() },\n position: 'before',\n familySelectors: ['[data-dsh-taskboard-entry]', '[data-dsh-ssh-entry]'],\n active: {\n subscribe: (listener) => controller.subscribe(listener),\n isOpen: () => controller.getSnapshot().boardOpen,\n },\n })\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/PluginSettingsCard.tsx. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family-shared chrome for plugin settings cards: a disclosure header naming\n * the plugin and what its settings govern, the controls inside, and the save\n * that writes them. Renders nothing while the namespace is unavailable — a\n * deployment that does not compose the owning plugin should show no trace of\n * it. Inlined into each consumer's client bundle; mirrors the official\n * ui-plugin-config PluginCard in a self-contained slice.\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\nimport type { CardShell } from './settings-form.ts'\nimport css from './settings-card.module.css'\n\n/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */\nexport const CARD_COPY_KEYS = [\n 'settings.collapse',\n 'settings.expand',\n 'settings.notExposed',\n 'settings.unsaved',\n 'settings.readOnly',\n 'settings.saveFailed',\n 'settings.discard',\n 'settings.save',\n 'settings.saving',\n] as const\n\n/** Copy key the card chrome itself reads. */\nexport type CardCopyKey = (typeof CARD_COPY_KEYS)[number]\n\n/** Key domain for the plugin's own copy (inferred per consumer). */\nexport type SettingsCardKey<TKey extends string = string> = TKey | CardCopyKey\n\n/** Card chrome shared by every plugin settings card. */\nexport interface PluginSettingsCardProps<TKey extends string = string> {\n /** Locale reader for this card's copy. */\n t: (key: SettingsCardKey<TKey>, params?: Record<string, string | number>) => string\n /** Locale key of the plugin's name. */\n titleKey: TKey\n /** Locale key of the line describing what this plugin's settings govern. */\n descriptionKey: TKey\n /** Optional rich header description rendered instead of the plain t(descriptionKey) text (the plain text stays as the tooltip). */\n descriptionNode?: ReactNode\n /** The card's form state: availability, writability, and what a save would do. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /**\n * Render the controls expanded on arrival (still collapsible). Defaults to\n * true: promoted first-level sections show their settings immediately.\n */\n defaultOpen?: boolean\n /**\n * Render without the collapse affordance: a static header and an always\n * visible body. Used by first-level settings sections whose nav entry\n * already provides the selection.\n */\n alwaysOpen?: boolean\n /**\n * Hide the save/discard footer: cards whose body applies its own changes\n * immediately (an embedded external settings section) have no staged\n * edits, so the footer would sit there permanently disabled.\n */\n hideFooter?: boolean\n /** Render children even when the settings namespace is not exposed by the host. */\n renderChildrenWhenNotExposed?: boolean\n /** Hide the 'not exposed' warning banner when the settings namespace is not exposed. */\n hideNotExposedNotice?: boolean\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin settings card.\n * @param props - the plugin's copy keys, its form state, and its controls.\n * @returns the card, or nothing while the namespace is still loading.\n */\nexport function PluginSettingsCard<TKey extends string = string>(props: PluginSettingsCardProps<TKey>) {\n const [open, setOpen] = useState(props.defaultOpen ?? true)\n const { state, alwaysOpen } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const description = props.t(props.descriptionKey)\n const blocked = !state.dirty || state.invalid || state.saving\n const expanded = alwaysOpen === true || open\n const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card\n // With alwaysOpen the nav entry already provides the selection, so the\n // header is a static title row instead of a disclosure button.\n const header = alwaysOpen === true\n ? (\n <div className={css.headerStatic}>\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{props.descriptionNode ?? description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n </div>\n )\n : (\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{props.descriptionNode ?? description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron}\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n )\n // The namespace exists but the Host does not serve it to this client (the\n // official settings allowlist omits third-party namespaces): show a card\n // that explains the gap instead of vanishing, so a missing card never\n // reads as a missing plugin.\n if (!state.exposed && props.renderChildrenWhenNotExposed !== true) {\n const showNotice = props.hideNotExposedNotice !== true\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {showNotice ? <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p> : null}\n </div>\n )\n : null}\n </li>\n )\n }\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('settings.readOnly')}</p> : null}\n {props.children}\n {props.hideFooter === true\n ? null\n : (\n <div className={css.footer}>\n {state.failed\n ? (\n <p className={css.failed} role=\"status\">\n {props.t('settings.saveFailed')}{state.failedReason ? ' - ' + state.failedReason : ''}\n </p>\n )\n : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('settings.discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(!state.saving ? 'settings.save' : 'settings.saving')}\n </button>\n </div>\n )}\n </div>\n )\n : null}\n </li>\n )\n}\n\n/** Props every field control needs regardless of its value type. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation rendered under the control. */\n hint: string\n /** Draft text this control renders. */\n text: string\n /** True when saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** True when the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control (read-only document, or an unavailable namespace). */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing what the control accepts. */\n numeric?: boolean\n /** Placeholder shown while the draft is empty. */\n placeholder?: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\nconst NON_SKIN_BODY_MARKERS = new Set(['dshSkinCenter', 'dshSidebarCollapsed'])\n// 检测使用使用皮肤,用了皮肤退回原生select样式,防止样式冲突。默认外观下使用优化后的select样式。\nfunction isSkinActive(): boolean {\n const datasetList = Object.keys(document.body.dataset)\n const isActive = datasetList.some(key => key.startsWith('dsh') && !NON_SKIN_BODY_MARKERS.has(key))\n return isActive\n}\n\ninterface SelectOption {\n value: string\n label: string\n}\n\nconst SELECT_CLOSE_MS = 100\n\n/**\n * The shared dual-mode select control. While an appearance skin is active it\n * renders the legacy native `<select>` untouched, so element-level skin\n * selectors keep working; under the default appearance it renders a\n * self-drawn `role=\"listbox\"` popup whose open/close is transition-animated.\n * Staged cards reach it through BooleanField/ChoiceField; immediate-apply\n * editors (the side-card prefs) bind it directly through onEdit.\n * 双模式下拉框:皮肤激活时用原生 select,默认外观用自绘动画弹层。\n */\nexport function SelectField(props: {\n id: string\n options: ReadonlyArray<SelectOption>\n value: string\n disabled: boolean\n invalid: boolean\n onEdit: (text: string) => void\n}) {\n const { id, options, value } = props\n const [open, setOpen] = useState(false)\n const [closing, setClosing] = useState(false)\n const [phase, setPhase] = useState<'initial' | 'open'>('initial')\n const [activeIndex, setActiveIndex] = useState(0)\n const closeTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const popupRef = useRef<HTMLDivElement | null>(null)\n\n const currentIndex = () => {\n const index = options.findIndex(option => option.value === value)\n return index >= 0 ? index : 0\n }\n\n const close = useCallback(() => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setClosing(true)\n closeTimer.current = setTimeout(() => {\n setClosing(false)\n setOpen(false)\n }, SELECT_CLOSE_MS)\n }, [])\n\n const openPopup = () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setActiveIndex(currentIndex())\n setPhase('initial')\n setClosing(false)\n setOpen(true)\n }\n\n const commit = (index: number) => {\n const option = options[index]\n if (option) props.onEdit(option.value)\n close()\n }\n\n const onTriggerClick = () => {\n if (props.disabled) return\n if (open && !closing) close()\n else openPopup()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (props.disabled) return\n const count = options.length\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Enter':\n case ' ':\n event.preventDefault()\n if (!open) {\n openPopup()\n } else if (!closing) {\n if (event.key === 'ArrowDown') setActiveIndex(index => (index + 1) % count)\n else if (event.key === 'ArrowUp') setActiveIndex(index => (index - 1 + count) % count)\n else commit(activeIndex)\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation()\n close()\n }\n break\n case 'Tab':\n if (open) close()\n break\n }\n }\n\n useEffect(() => () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n }, [])\n useLayoutEffect(() => {\n if (open && !closing && phase === 'initial') {\n void popupRef.current?.offsetHeight\n setPhase('open')\n }\n }, [open, closing, phase])\n\n useEffect(() => {\n if (!open) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target\n if (target instanceof Node && !wrapRef.current?.contains(target)) close()\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => document.removeEventListener('pointerdown', onPointerDown)\n }, [open, close])\n\n useEffect(() => {\n if (props.disabled && open) close()\n }, [props.disabled, open, close])\n\n // 使用了皮肤则退回原生select样式防止样式冲突。\n if (isSkinActive()) {\n return (\n <select\n id={id}\n className={css.select}\n value={value}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n {options.map(option => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n )\n }\n\n const label = options.find(option => option.value === value)?.label ?? ''\n const popupClass = closing\n ? `${css.selectPopup} ${css.selectPopupClose}`\n : phase === 'open'\n ? `${css.selectPopup} ${css.selectPopupOpen}`\n : css.selectPopup\n return (\n <div className={css.selectWrap} ref={wrapRef}>\n <button\n type=\"button\"\n id={id}\n className={`${css.select} ${css.selectButton}`}\n disabled={props.disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-activedescendant={open ? `${id}-o${activeIndex}` : undefined}\n aria-invalid={props.invalid || undefined}\n onClick={onTriggerClick}\n onKeyDown={onKeyDown}\n >\n <span className={css.selectLabel}>{label}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.selectChevron} ${css.selectChevronOpen}` : css.selectChevron}\n aria-hidden=\"true\"\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n {open\n ? (\n <div className={popupClass} role=\"listbox\" ref={popupRef}>\n {options.map((option, index) => (\n <div\n key={option.value}\n id={`${id}-o${index}`}\n role=\"option\"\n aria-selected={option.value === value}\n className={`${css.selectOption}${option.value === value ? ` ${css.selectOptionSelected}` : ''}${index === activeIndex && !closing ? ` ${css.selectOptionActive}` : ''}`}\n onClick={() => { commit(index) }}\n >\n {option.label}\n </div>\n ))}\n </div>\n )\n : null}\n </div>\n )\n}\n\n/** A staged boolean field: 继承 / 开 / 关. */\nexport function BooleanField(props: FieldProps & {\n /** Copy for the inherit option. */\n inheritLabel: string\n /** Copy for the on option. */\n onLabel: string\n /** Copy for the off option. */\n offLabel: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[\n { value: '', label: props.inheritLabel },\n { value: 'true', label: props.onLabel },\n { value: 'false', label: props.offLabel },\n ]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n\n/** A staged enumerated field rendered as a select. */\nexport function ChoiceField(props: FieldProps & {\n /** Copy for the inherit option (draft text is the empty string). */\n inheritLabel: string\n /** Choices rendered in order; `value` is the draft/stored text. */\n choices: ReadonlyArray<{ value: string; label: string }>\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[{ value: '', label: props.inheritLabel }, ...props.choices]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/settings-form.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Staged form model behind the plugin settings card. A card stages what the\n * user types and writes it only when they save — the settings write is a\n * durable, revision-fenced document mutation, so staging keeps what is on\n * screen exactly what a save would store. Family-shared slice inlined into\n * each plugin's client bundle; mirrors the official ui-plugin-config\n * card-store pattern.\n */\n\nimport type { ConfigForm, ConfigFormSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** How one field converts between its stored value and its draft text. */\nexport interface FieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /**\n * Whether the Host treats this field as a secret and redacts its value from\n * the read-back (role('secret') in the section schema). Redacted secrets are\n * never compared against the draft on save: the Host strips them from every\n * wire view layer, so the settled snapshot carries nothing to read back. A\n * staged secret set is judged by the mutation settling; the rest of its\n * batch, when one exists, is still judged by read-back, and the atomic\n * mutation lands every write or none.\n */\n secret?: boolean\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/** One field as the card renders it. */\nexport interface FieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean\n}\n\n/** Form state every plugin settings card shares. */\nexport interface CardShell {\n /** False while the namespace is still loading; the card renders nothing. */\n available: boolean\n /**\n * Whether the namespace is actually served to this client. False when the\n * Host deployment does not expose it (e.g. the owning plugin's settings\n * domain is not mounted): the card renders an explanation\n * instead of its form, so a missing namespace never looks like a missing\n * plugin.\n */\n exposed: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits that a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean\n /**\n * The rejection code/message the Host returned for the last failed save,\n * surfaced next to the generic failure text. Undefined while no save has\n * failed (or the failure carried no server reason).\n */\n failedReason?: string\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean\n}\n\n/** One staged edit resolved into the write a save performs. */\ninterface PlannedWrite {\n /** Field this entry writes. */\n field: string\n /** The durable write this entry performs, inside the save's one atomic mutation. */\n op: BatchedWrite\n /**\n * Read the settled snapshot back and report whether the Host holds this\n * write's effect. Undefined when the draft is not a value the field\n * accepts: there is nothing to write, and the entry blocks the save.\n */\n judge: (() => boolean) | undefined\n}\n\n/** One durable write inside the save's atomic form mutation. */\nexport interface BatchedWrite {\n /** Field this entry writes. */\n field: string\n /** set stores a value; unset drops the leaf. */\n op: 'set' | 'unset'\n /** Value for op set (absent for unset). */\n value?: unknown\n}\n\n/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */\nexport interface NumberConstraints {\n /** The accepted value must be a whole number. */\n integer?: boolean\n /** The accepted value must be at least this. */\n min?: number\n}\n\n/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */\nexport function numberField(field: string, constraints: NumberConstraints = {}): FieldSpec {\n const { integer = false, min } = constraints\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return undefined\n if (integer && !Number.isInteger(parsed)) return undefined\n if (min !== undefined && parsed < min) return undefined\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A free-text field. An empty draft clears the field. */\nexport function textField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A free-text field the Host treats as a secret and redacts from the read-back\n * (role('secret') in the section schema). The card still edits it like text,\n * but a save never compares the redacted value back: the staged set is judged\n * by the mutation settling (see {@link FieldSpec.secret}).\n */\nexport function secretField(field: string): FieldSpec {\n return { ...textField(field), secret: true }\n}\n\n/** A boolean field, edited through true/false draft text. */\nexport function booleanField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'boolean' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n },\n }\n}\n\n/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */\nexport function choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' && choices.includes(value) ? value : '',\n parse: (text) => {\n if (text === '') return { kind: 'clear' }\n return choices.includes(text) ? { kind: 'set', value: text } : undefined\n },\n }\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted — its\n * validators own the constraints no schema can express — so the outcome is\n * read back from the section rather than predicted here. A save that did not\n * land keeps its drafts, so the user can correct them instead of retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, FieldSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n /** The form subscription installed in the constructor; released by dispose(). */\n private readonly disposeForm: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound configuration form for this card's namespace. */\n constructor(\n private readonly scope: ConfigForm<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeForm = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the form subscription and every bound store listener. The card\n * must call this on teardown; later calls are no-ops.\n */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.disposeForm()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the form or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status !== 'loading',\n exposed: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.judge === undefined),\n saving: this.saving,\n failed: this.failed,\n ...this.failedReason === undefined ? {} : { failedReason: this.failedReason },\n }\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): FieldState {\n const spec = this.specOf(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.failedReason = undefined\n this.publish()\n },\n }\n }\n\n /**\n * Write every staged edit in one atomic form mutation, then re-seed from\n * what the Host accepted.\n *\n * The whole batch rides one mutate, so cross-field validate hooks\n * (baseURL+model) judge it as a unit: the Host either applies every write\n * or refuses the batch. The form contract answers a refusal or a skipped\n * write with `false` (it recovers with a fresh Host view instead of\n * throwing), so the outcome is judged twice: the answer itself, and then the\n * settled snapshot read back one planned write at a time. One missed write\n * fails the whole save. A transport that rejects instead (the dsh-web bridge\n * controller on a dead connection) reports through the same failure path\n * with its rejection message. A save that did not land keeps its drafts, so\n * the user can correct them instead of retyping.\n * @returns settlement after the mutation and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter((item): item is PlannedWrite & { judge: () => boolean } => item.judge !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n // Snapshot the staged entries this save writes, so an edit staged while it\n // is in flight (which replaces the same key) survives: only delete the key\n // when the entry is still the one this save started from.\n const pending = new Map<string, StagedEdit | undefined>()\n for (const item of plan) pending.set(item.field, this.staged.get(item.field))\n this.saving = true\n this.failed = false\n this.failedReason = undefined\n this.publish()\n // One atomic namespace mutation: the form contract takes ordered path\n // operations, so the whole staged batch is validated, persisted, and\n // recovered together — either every write lands or none does.\n const ops: Array<{ op: 'set'; path: string[]; value: string | number | boolean } | { op: 'unset'; path: string[] }> = valid.map(item => item.op.op === 'set'\n ? { op: 'set', path: [item.field], value: (item.op as { value: string | number | boolean }).value }\n : { op: 'unset', path: [item.field] })\n let failedReason: string | undefined\n let accepted = false\n try {\n accepted = await this.scope.mutate(ops)\n } catch (error) {\n failedReason = error instanceof Error ? error.message : String(error)\n }\n // `false` is the contract's refusal/skip answer, and the form still\n // resolves after a refusal (it recovers with a fresh view), so the answer\n // alone is not enough: judge every planned write against the settled\n // snapshot as well. The mutation is atomic, so one missed write fails the\n // whole save and keeps the drafts.\n const landed = accepted && failedReason === undefined && valid.every(item => item.judge())\n for (const [field, before] of pending) {\n if (landed && this.staged.get(field) === before) this.staged.delete(field)\n }\n this.saving = false\n this.failed = !landed\n // A refused or unlanded batch carries no server reason: the card surfaces\n // its generic failure copy; a rejecting transport (the bridge) adds its\n // message.\n this.failedReason = failedReason\n this.publish()\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n * @returns the planned writes, in the order the fields were staged.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, op: { field, op: 'unset' }, judge: () => this.landedUnset(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, op: { field, op: 'unset' }, judge: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, judge: () => this.landedUnset(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, judge: () => this.landedSet(field, write.value) })\n }\n return plan\n }\n\n /**\n * Read-back judgment for a planned set: the user layer must hold the\n * intended value once the mutation has settled.\n */\n private landedSet(field: string, value: unknown): boolean {\n // A redacted secret never appears in any wire view layer: the Host strips\n // role('secret') fields and reports them through a sidecar the form\n // snapshot does not expose, so there is nothing to compare the draft\n // against. Settling is the only signal the form has; the rest of the\n // batch, when one exists, still carries the atomic verdict by read-back.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\n }\n\n /**\n * Read-back judgment for a planned unset: the field must be gone from the\n * user layer once the mutation has settled.\n */\n private landedUnset(field: string): boolean {\n return !this.stored(field)\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.failedReason = undefined\n this.publish()\n }\n\n private specOf(field: string): FieldSpec {\n const spec = this.specs.get(field)\n // Every call site names a field this card declared; a missing one is a\n // wiring mistake that must not degrade into a silently inert control.\n if (spec === undefined) throw new Error(`settings card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): ConfigFormSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * Task-board settings for availability, agent announcement, and optional Host\n * idle-sleep protection. Registers into the `web-ui.plugin.item` child slot\n * the Web UI plugin group renders, bound to the `task-board` namespace.\n */\n\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { useEffect, useState } from 'react'\nimport type { TaskBoardPowerSnapshot } from '../protocol.ts'\nimport { PluginSettingsCard, BooleanField } from './PluginSettingsCard.tsx'\nimport { CardForm, booleanField, type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts'\n\n/** The task-board fields this card edits (the namespace's full schema). */\nexport interface TaskBoardSettings {\n /** Master switch for the plugin. */\n enabled?: boolean\n /** Whether the board announces itself in every agent's system prompt. */\n announceToAgent?: boolean\n /** Prevent host idle sleep while sessions run or schedules are armed. */\n preventIdleSleep?: boolean\n}\n\n/** What the task-board card renders. */\nexport interface TaskBoardSettingsCardState extends CardShell {\n /** Master switch. */\n enabled: CardFieldState\n /** System-prompt announcement flag. */\n announceToAgent: CardFieldState\n /** Idle-system-sleep protection flag. */\n preventIdleSleep: CardFieldState\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface TaskBoardSettingsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useTaskBoardSettingsCard. */\n taskBoardSettingsCard: SnapshotStore<TaskBoardSettingsCardState>\n }\n}\n\n/** Bridges the `task-board` settings form onto the card's staged form. */\nexport class TaskBoardSettingsCardController {\n private readonly form: CardForm<TaskBoardSettings>\n private readonly store: SnapshotStore<TaskBoardSettingsCardState>\n\n /** @param scope - the bound configuration form for the `task-board` namespace. */\n constructor(scope: ConfigForm<TaskBoardSettings>) {\n this.form = new CardForm(scope, [\n booleanField('enabled'),\n booleanField('announceToAgent'),\n booleanField('preventIdleSleep'),\n ])\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): TaskBoardSettingsCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n announceToAgent: this.form.field('announceToAgent'),\n preventIdleSleep: this.form.field('preventIdleSleep'),\n }\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): TaskBoardSettingsCardFace {\n return { hooks: { taskBoardSettingsCard: this.store }, ...this.form.actions() }\n }\n\n /**\n * Release the card's form subscription and bound stores; the slot\n * disposer calls this on teardown.\n */\n dispose(): void {\n this.form.dispose()\n }\n}\n\n/** Props the renderer binds for the task-board card. */\nexport type TaskBoardSettingsCardProps =\n PropsRuntime<'web-ui.plugin.item'>\n & PropsLocale<'task-board'>\n & InjectFace<TaskBoardSettingsCardFace>\n\n/**\n * Render the task-board card.\n * @param props - locale copy, the card snapshot, and its form actions.\n * @returns the card.\n */\nexport function TaskBoardSettingsCard(props: TaskBoardSettingsCardProps) {\n const { t } = props\n const state = props.useTaskBoardSettingsCard(snapshot => snapshot)\n const disabled = !state.writable\n const [power, setPower] = useState<TaskBoardPowerSnapshot | undefined>()\n useEffect(() => {\n // The SSE channel already carries power on every real change and pushes\n // one frame on subscribe; polling the full /state snapshot every 5 s\n // re-cloned and re-serialized the whole ledger server-side for one field.\n let live = true\n const events = new EventSource('/api/task-board/events')\n events.onmessage = (message: MessageEvent<string>): void => {\n try {\n const frame = JSON.parse(message.data) as { power?: TaskBoardPowerSnapshot }\n if (frame.power !== undefined && live) setPower(frame.power)\n } catch {\n // The settings form remains usable while the host status is reconnecting.\n }\n }\n return () => { live = false; events.close() }\n }, [])\n const fieldProps = {\n overriddenLabel: t('settings.overridden'),\n resetLabel: t('settings.reset'),\n invalidLabel: t('settings.invalidNumber'),\n disabled,\n }\n return (\n <PluginSettingsCard\n t={t}\n titleKey=\"settings.title\"\n descriptionKey=\"settings.description\"\n defaultOpen={false}\n state={state}\n renderChildrenWhenNotExposed\n hideNotExposedNotice\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"settings-task-board-enabled\"\n label={t('settings.enabled')}\n hint={t('settings.enabledHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.enabled}\n onEdit={(text) => { props.edit('enabled', text) }}\n onReset={() => { props.resetField('enabled') }}\n />\n <BooleanField\n id=\"settings-task-board-announce\"\n label={t('settings.announceToAgent')}\n hint={t('settings.announceToAgentHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.announceToAgent}\n onEdit={(text) => { props.edit('announceToAgent', text) }}\n onReset={() => { props.resetField('announceToAgent') }}\n />\n <BooleanField\n id=\"settings-task-board-prevent-idle-sleep\"\n label={t('settings.preventIdleSleep')}\n hint={t('settings.preventIdleSleepHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.preventIdleSleep}\n onEdit={(text) => { props.edit('preventIdleSleep', text) }}\n onReset={() => { props.resetField('preventIdleSleep') }}\n />\n <p>\n {t('settings.powerStatus', {\n platform: power?.platform ?? t('settings.powerUnknown'),\n phase: power?.phase ?? t('settings.powerUnknown'),\n running: String(power?.runningSessions ?? 0),\n schedules: String(power?.armedSchedules ?? 0),\n })}\n </p>\n <p>{t('settings.powerBoundary')}</p>\n {power?.lastError !== undefined && <p>{t('settings.powerError', { error: power.lastError })}</p>}\n </PluginSettingsCard>\n )\n}\n","import type { TaskUpdatePatch } from './core/use-cases/task-update.ts'\nimport { isTaskPermission, isTaskStatus, isTaskTagList, type NewTaskInput, type TaskPermission, type TaskRecord, type TaskStatus } from './core/tasks.ts'\nimport { parseLedger } from './core/store.ts'\nimport { sanitizeFreezeSnapshot, type FreezeSnapshot } from './core/freeze-snapshot.ts'\nimport { sanitizeHandover, type TaskHandoverInput } from './core/handover.ts'\n\n/** Freeze payload carried by create/update actions after the gate (redacted in place). */\ntype FreezePayload = FreezeSnapshot & { redacted?: boolean; frozenBy?: string }\n\nexport const TASK_BOARD_SCHEMA_VERSION = 3 as const\n/** Ledger documents written before v3; loaded once and migrated on startup. */\nexport const TASK_BOARD_LEGACY_SCHEMA_VERSION = 2 as const\nexport const TASK_BOARD_API_PREFIX = '/api/task-board'\n\nexport type PowerPhase = 'disabled' | 'idle' | 'acquiring' | 'active' | 'error' | 'unsupported'\n\nexport interface TaskBoardPowerSnapshot {\n platform: string\n phase: PowerPhase\n enabled: boolean\n runningSessions: number\n armedSchedules: number\n sessionStateKnown: boolean\n lastError?: string\n}\n\nexport interface TaskBoardSchedulerSnapshot {\n timeZone: string\n /** Opaque identity of the current Host ledger generation. */\n ledgerId?: string\n lastTickAt?: number\n error?: string\n}\n\nexport interface TaskBoardSnapshot {\n schemaVersion: typeof TASK_BOARD_SCHEMA_VERSION\n revision: number\n tasks: TaskRecord[]\n scheduler: TaskBoardSchedulerSnapshot\n power: TaskBoardPowerSnapshot\n /** Session-default permission the confirmation gate compares against. */\n sessionDefaultPermission?: TaskPermission\n}\n\n/** SSE event frame: revision/scheduler/power only, never the task list. */\nexport interface TaskBoardEventPayload {\n revision: number\n scheduler: TaskBoardSchedulerSnapshot\n power: TaskBoardPowerSnapshot\n}\n\n/**\n * Request body of `POST {TASK_BOARD_API_PREFIX}/parse` (issue #1540): the text\n * the user pasted plus the `provider/model` route that should parse it.\n */\nexport interface TaskBoardParseRequest {\n text: string\n /** Qualified route from the model picker; absent when no route was chosen. */\n model?: string\n}\n\n/** Draft fields a parse returns; the user reviews them before creating the task. */\nexport interface TaskBoardParseDraft {\n title: string\n description: string\n prompt: string\n}\n\n/** Strict parse of a `/parse` request body; undefined rejects the request. */\nexport function parseTaskParseRequest(value: unknown): TaskBoardParseRequest | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const record = value as { text?: unknown; model?: unknown }\n if (typeof record.text !== 'string' || record.text.trim() === '') return undefined\n if (record.model !== undefined && typeof record.model !== 'string') return undefined\n const model = typeof record.model === 'string' ? record.model.trim() : ''\n return { text: record.text, ...(model === '' ? {} : { model }) }\n}\n\n/** Whether a decoded reply carries the three draft strings the form accepts. */\nexport function isTaskParseDraft(value: unknown): value is TaskBoardParseDraft {\n if (typeof value !== 'object' || value === null) return false\n const record = value as { title?: unknown; description?: unknown; prompt?: unknown }\n return typeof record.title === 'string' && typeof record.description === 'string' && typeof record.prompt === 'string'\n}\n\nexport type TaskBoardAction =\n | { kind: 'import'; sourceId: string; tasks: TaskRecord[] }\n | { kind: 'create'; id: string; input: NewTaskInput }\n | { kind: 'update'; taskId: string; patch: TaskUpdatePatch }\n | { kind: 'delete'; taskId: string }\n | { kind: 'move'; taskId: string; status: TaskStatus }\n | { kind: 'archive'; taskId: string }\n | { kind: 'restore'; taskId: string }\n | { kind: 'set-schedule'; taskId: string; patch: { enabled?: boolean; cron?: string } }\n | { kind: 'run'; taskId: string }\n | { kind: 'rerun'; taskId: string }\n | { kind: 'confirm-permission'; taskId: string }\n\nexport interface TaskBoardActionEnvelope {\n requestId: string\n action: TaskBoardAction\n /**\n * Session id of the DSH session issuing the action, for the execution audit\n * trail (issue #6). Client-asserted, not a trust boundary; parsed only as a\n * bounded non-empty string and recorded on opened executions / freeze stamps.\n */\n initiator?: string\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : undefined\n}\n\nfunction exactKeys(value: Record<string, unknown>, allowed: readonly string[]): boolean {\n return Object.keys(value).every(key => allowed.includes(key))\n}\n\nfunction optionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string'\n}\n\nconst FORBIDDEN_IMPORT_FIELDS = new Set(['args', 'command', 'executable', 'powershell', 'shell'])\n\nfunction hasForbiddenImportField(value: unknown): boolean {\n if (Array.isArray(value)) return value.some(hasForbiddenImportField)\n const row = record(value)\n if (row === undefined) return false\n return Object.entries(row).some(([key, nested]) => FORBIDDEN_IMPORT_FIELDS.has(key.toLowerCase()) || hasForbiddenImportField(nested))\n}\n\nfunction optionalFiniteNumber(value: unknown): boolean {\n return value === undefined || (typeof value === 'number' && Number.isFinite(value))\n}\n\nfunction validImportedKnownFields(value: Record<string, unknown>): boolean {\n // Tags are validated (not repaired) on the import path: an imported task\n // must carry a well-formed list or none at all, so a hand-edited export\n // cannot smuggle a malformed tag past the gate.\n if (value.tags !== undefined && !isTaskTagList(value.tags)) return false\n if (value.schedule !== undefined) {\n const schedule = record(value.schedule)\n if (schedule === undefined || typeof schedule.enabled !== 'boolean' || typeof schedule.cron !== 'string') return false\n if (!optionalFiniteNumber(schedule.nextRunAt) || !optionalFiniteNumber(schedule.lastTriggeredAt)) return false\n }\n if (value.executions !== undefined) {\n if (!Array.isArray(value.executions)) return false\n for (const item of value.executions) {\n const execution = record(item)\n if (execution === undefined || typeof execution.id !== 'string' || !optionalString(execution.sessionId)) return false\n if (typeof execution.startedAt !== 'number' || !Number.isFinite(execution.startedAt)) return false\n if (!optionalFiniteNumber(execution.endedAt) || !optionalString(execution.error)) return false\n if (execution.result !== undefined && !['succeeded', 'failed', 'cancelled'].includes(String(execution.result))) return false\n if (execution.initiatedBy !== undefined && typeof execution.initiatedBy !== 'string') return false\n if (execution.frozenBy !== undefined && typeof execution.frozenBy !== 'string') return false\n if (execution.frozenAt !== undefined && typeof execution.frozenAt !== 'number') return false\n }\n }\n return true\n}\n\nfunction importedTask(value: unknown): TaskRecord | undefined {\n const input = record(value)\n if (input === undefined || hasForbiddenImportField(input) || !validImportedKnownFields(input)) return undefined\n const task = parseLedger(JSON.stringify([value]))[0]\n if (task === undefined) return undefined\n return {\n id: task.id,\n title: task.title,\n description: task.description,\n prompt: task.prompt,\n status: task.status,\n createdAt: task.createdAt,\n updatedAt: task.updatedAt,\n executions: task.executions.map(execution => ({\n id: execution.id,\n sessionId: execution.sessionId,\n startedAt: execution.startedAt,\n endedAt: execution.endedAt,\n result: execution.result,\n error: execution.error,\n ...(execution.initiatedBy === undefined ? {} : { initiatedBy: execution.initiatedBy }),\n ...(execution.frozenAt === undefined ? {} : { frozenAt: execution.frozenAt }),\n ...(execution.frozenBy === undefined ? {} : { frozenBy: execution.frozenBy }),\n })),\n ...(task.schedule === undefined ? {} : {\n schedule: {\n enabled: task.schedule.enabled,\n cron: task.schedule.cron,\n nextRunAt: task.schedule.nextRunAt,\n lastTriggeredAt: task.schedule.lastTriggeredAt,\n },\n }),\n ...(task.workspaceId === undefined ? {} : { workspaceId: task.workspaceId }),\n ...(task.mode === undefined ? {} : { mode: task.mode }),\n ...(task.permission === undefined ? {} : { permission: task.permission }),\n ...(task.reuseSession === undefined ? {} : { reuseSession: task.reuseSession }),\n ...(task.archivedAt === undefined ? {} : { archivedAt: task.archivedAt }),\n ...(task.freeze === undefined ? {} : { freeze: task.freeze }),\n ...(task.handover === undefined ? {} : { handover: task.handover }),\n ...(task.tags === undefined ? {} : { tags: task.tags }),\n // 安全门(对抗场景 b):import 不是人工确认动作,确认戳一律剥除——\n // 高于会话默认权限的绑定经 import 进入后必须重新武装 confirm-permission 门。\n }\n}\n\n/**\n * Gate a freeze payload from the wire: same T2 security gates as the parser\n * (slash-command taint rejects, sensitive patterns redact in place, 8 KiB\n * per-field cap). Returns the sanitized payload, or undefined when rejected.\n */\nfunction freezePayload(value: unknown): FreezePayload | undefined {\n const result = sanitizeFreezeSnapshot(value, ['redacted', 'frozenBy'])\n if (!result.ok) return undefined\n const frozenBy = result.extras.frozenBy\n if (frozenBy !== undefined && (typeof frozenBy !== 'string' || frozenBy === '')) return undefined\n return {\n ...result.snapshot,\n ...(result.redacted || result.extras.redacted === true ? { redacted: true } : {}),\n ...(frozenBy === undefined ? {} : { frozenBy }),\n }\n}\n\n/**\n * Gate a handover bundle from the wire: exact keys, bounded string targets,\n * a known permission, and a bounded references list. Returns the sanitized\n * bundle, or undefined when rejected.\n */\nfunction handoverPayload(value: unknown): TaskHandoverInput | undefined {\n return sanitizeHandover(value)\n}\n\nfunction createInput(value: unknown): value is NewTaskInput {\n const input = record(value)\n if (input === undefined || !exactKeys(input, ['title', 'description', 'prompt', 'workspaceId', 'mode', 'permission', 'schedule', 'freeze', 'handover', 'model', 'reuseSession', 'tags'])) return false\n if (typeof input.title !== 'string' || typeof input.description !== 'string' || typeof input.prompt !== 'string') return false\n if (!optionalString(input.workspaceId) || !optionalString(input.mode) || !optionalString(input.model)) return false\n if (input.reuseSession !== undefined && typeof input.reuseSession !== 'boolean') return false\n if (input.permission !== undefined && !isTaskPermission(input.permission)) return false\n if (input.tags !== undefined && !isTaskTagList(input.tags)) return false\n if (input.freeze !== undefined && freezePayload(input.freeze) === undefined) return false\n if (input.handover !== undefined && handoverPayload(input.handover) === undefined) return false\n if (input.schedule !== undefined) {\n const schedule = record(input.schedule)\n if (schedule === undefined || !exactKeys(schedule, ['enabled', 'cron'])) return false\n if (typeof schedule.enabled !== 'boolean' || typeof schedule.cron !== 'string') return false\n }\n return true\n}\n\nfunction updatePatch(value: unknown): boolean {\n const patch = record(value)\n if (patch === undefined || !exactKeys(patch, ['title', 'description', 'prompt', 'workspaceId', 'mode', 'permission', 'freeze', 'handover', 'model', 'reuseSession', 'tags'])) return false\n // null (or false) clears the reuse opt-in; only a real boolean is accepted.\n if (patch.reuseSession !== undefined && patch.reuseSession !== null && typeof patch.reuseSession !== 'boolean') return false\n for (const key of ['title', 'description', 'prompt', 'workspaceId', 'mode', 'model'] as const) {\n if (!optionalString(patch[key])) return false\n }\n if (patch.permission !== undefined && !isTaskPermission(patch.permission)) return false\n // null clears the label set; a present array must be a well-formed list.\n if (patch.tags !== undefined && patch.tags !== null && !isTaskTagList(patch.tags)) return false\n // null clears the snapshot; an object must pass the freeze gate.\n if (patch.freeze !== undefined && patch.freeze !== null && freezePayload(patch.freeze) === undefined) return false\n // Same convention for the handover bundle.\n return patch.handover === undefined || patch.handover === null || handoverPayload(patch.handover) !== undefined\n}\n\nfunction schedulePatch(value: unknown): boolean {\n const patch = record(value)\n return patch !== undefined\n && exactKeys(patch, ['enabled', 'cron'])\n && (patch.enabled === undefined || typeof patch.enabled === 'boolean')\n && (patch.cron === undefined || typeof patch.cron === 'string')\n}\n\nexport function parseActionEnvelope(value: unknown): TaskBoardActionEnvelope | undefined {\n const parsed = parseEnvelopeAction(value)\n if (parsed === undefined) return undefined\n // Attach the audit-only initiator stamp (already validated above) to every accepted action.\n const initiator = initiatorOf(value)\n return initiator === undefined ? parsed : { ...parsed, initiator }\n}\n\nfunction initiatorOf(value: unknown): string | undefined {\n const envelope = record(value)\n const id = envelope?.initiator\n return typeof id === 'string' && id.trim() !== '' && id.length <= 256 ? id : undefined\n}\n\nfunction parseEnvelopeAction(value: unknown): TaskBoardActionEnvelope | undefined {\n const envelope = record(value)\n if (envelope === undefined || !exactKeys(envelope, ['requestId', 'action', 'initiator'])) return undefined\n if (typeof envelope.requestId !== 'string' || envelope.requestId.trim() === '' || envelope.requestId.length > 256) return undefined\n if (envelope.initiator !== undefined && initiatorOf(value) === undefined) return undefined\n const action = record(envelope.action)\n if (action === undefined || typeof action.kind !== 'string') return undefined\n const taskId = typeof action.taskId === 'string' && action.taskId !== '' ? action.taskId : undefined\n switch (action.kind) {\n case 'import':\n if (!exactKeys(action, ['kind', 'sourceId', 'tasks'])) return undefined\n if (typeof action.sourceId !== 'string' || action.sourceId === '' || !Array.isArray(action.tasks)) return undefined\n {\n const tasks = action.tasks.map(importedTask)\n return tasks.every((task): task is TaskRecord => task !== undefined)\n ? { requestId: envelope.requestId, action: { kind: 'import', sourceId: action.sourceId, tasks } }\n : undefined\n }\n case 'create': {\n if (!exactKeys(action, ['kind', 'id', 'input'])) return undefined\n if (typeof action.id !== 'string' || action.id === '' || !createInput(action.input)) return undefined\n const input = action.input as NewTaskInput\n const freeze = input.freeze === undefined ? undefined : freezePayload(input.freeze)\n const handover = input.handover === undefined ? undefined : handoverPayload(input.handover)\n const sanitized = freeze === undefined && handover === undefined ? input : { ...input, ...(freeze === undefined ? {} : { freeze }), ...(handover === undefined ? {} : { handover }) }\n return { requestId: envelope.requestId, action: { kind: 'create', id: action.id as string, input: sanitized } }\n }\n case 'update': {\n if (!exactKeys(action, ['kind', 'taskId', 'patch'])) return undefined\n if (taskId === undefined || !updatePatch(action.patch)) return undefined\n const patch = action.patch as TaskUpdatePatch\n const freeze = patch.freeze === undefined || patch.freeze === null ? patch.freeze : freezePayload(patch.freeze)\n const handover = patch.handover === undefined || patch.handover === null ? patch.handover : handoverPayload(patch.handover)\n const sanitized = ('freeze' in patch && freeze !== patch.freeze) || ('handover' in patch && handover !== patch.handover)\n ? { ...patch, ...(freeze === patch.freeze ? {} : { freeze }), ...(handover === patch.handover ? {} : { handover }) }\n : patch\n return { requestId: envelope.requestId, action: { kind: 'update', taskId, patch: sanitized } }\n }\n case 'set-schedule':\n if (!exactKeys(action, ['kind', 'taskId', 'patch'])) return undefined\n return taskId !== undefined && schedulePatch(action.patch)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'set-schedule' }> }\n : undefined\n case 'move':\n if (!exactKeys(action, ['kind', 'taskId', 'status'])) return undefined\n return taskId !== undefined && isTaskStatus(action.status)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'move' }> }\n : undefined\n case 'confirm-permission':\n case 'delete':\n case 'archive':\n case 'restore':\n case 'run':\n case 'rerun':\n if (!exactKeys(action, ['kind', 'taskId'])) return undefined\n return taskId === undefined ? undefined : { requestId: envelope.requestId, action: action as TaskBoardAction }\n default:\n return undefined\n }\n}\n","import type { TaskRecord } from '../core/tasks.ts'\nimport { t } from './locales.ts'\nimport {\n isTaskParseDraft,\n TASK_BOARD_API_PREFIX,\n type TaskBoardAction,\n type TaskBoardActionEnvelope,\n type TaskBoardEventPayload,\n type TaskBoardParseDraft,\n type TaskBoardParseRequest,\n type TaskBoardSnapshot,\n} from '../protocol.ts'\n\nconst IMPORT_MARKER = 'dsh.taskBoard.v2.hostImported'\nconst SOURCE_KEY = 'dsh.taskBoard.v2.sourceId'\nconst IMPORT_REQUEST_KEY = 'dsh.taskBoard.v2.importRequestId'\nconst REQUEST_TIMEOUT_MS = 15_000\n/** Re-notify the panel at most this often while the event stream stays broken. */\nconst STREAM_ERROR_NOTIFY_MS = 15_000\n/** Mirrors the Host's own parse budget; only used to phrase the timeout. */\nconst TASK_PARSE_TIMEOUT_SECONDS = 45\n\n/**\n * Failure classes of the Host API, in the language the panel renders\n * (issue #1528). The Host is the only part that knows whether a task-board\n * route exists at all, so a raw fetch/parse error must never reach the user:\n * \"Unexpected token 'o', \\\"not found\\\" is not valid JSON\" is what a missing\n * Host half looks like today.\n */\nexport type HostApiFailure = 'not-mounted' | 'unauthorized' | 'locked' | 'rejected' | 'timeout' | 'unreachable' | 'unexpected'\n\n/** Transport failure carrying a stable class next to its user-facing message. */\nexport class HostApiError extends Error {\n constructor(readonly failure: HostApiFailure, message: string, readonly status?: number) {\n super(message)\n this.name = 'HostApiError'\n }\n}\n\nfunction uuid(): string {\n return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n}\n\n/**\n * Read one Host response without ever handing a non-JSON body to JSON.parse:\n * the core webserver answers an unmounted `/api/*` path with the plain text\n * \"not found\", which used to surface as a JavaScript parse error in the panel.\n */\nasync function readJson<T>(response: Response): Promise<T> {\n const text = await response.text()\n let parsed: unknown\n let readable = false\n if (text.trim() !== '') {\n try {\n parsed = JSON.parse(text)\n readable = true\n } catch {\n readable = false\n }\n }\n const hostError = readable && typeof parsed === 'object' && parsed !== null && typeof (parsed as { error?: unknown }).error === 'string'\n ? (parsed as { error: string }).error\n : undefined\n if (response.ok) {\n if (!readable) throw new HostApiError('unexpected', t('board.hostError.unexpected', { status: String(response.status) }), response.status)\n return parsed as T\n }\n if (hostError !== undefined) {\n // The Host answered with a reason of its own. A ledger lock is the one\n // class worth naming in the panel's words; the authentication fence and\n // every other action rejection are reported as they arrive.\n if (hostError === 'forbidden') throw new HostApiError('unauthorized', t('board.hostError.unauthorized'), response.status)\n if (response.status === 503 || /lock/i.test(hostError)) {\n throw new HostApiError('locked', t('board.hostError.locked', { detail: hostError }), response.status)\n }\n throw new HostApiError('rejected', hostError, response.status)\n }\n if (response.status === 404) throw new HostApiError('not-mounted', t('board.hostError.notMounted'), 404)\n if (response.status === 401 || response.status === 403) throw new HostApiError('unauthorized', t('board.hostError.unauthorized'), response.status)\n throw new HostApiError('unexpected', t('board.hostError.unexpected', { status: String(response.status) }), response.status)\n}\n\nexport interface TaskBoardHostTransport {\n bootstrap(legacy: readonly TaskRecord[]): Promise<TaskBoardSnapshot>\n state(): Promise<TaskBoardSnapshot>\n action(action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot>\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void\n /** One-shot model parse of pasted text (issue #1540). */\n parseDraft(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft>\n}\n\nexport class HttpTaskBoardHostTransport implements TaskBoardHostTransport {\n constructor(private readonly storage: Pick<Storage, 'getItem' | 'setItem'> | undefined = globalThis.localStorage) {}\n\n async bootstrap(legacy: readonly TaskRecord[]): Promise<TaskBoardSnapshot> {\n const initial = await this.state()\n const ledgerId = initial.scheduler.ledgerId\n if (legacy.length > 0 && ledgerId !== undefined && this.storage?.getItem(IMPORT_MARKER) !== ledgerId) {\n let sourceId = this.storage?.getItem(SOURCE_KEY)\n if (sourceId === null || sourceId === undefined || sourceId === '') {\n sourceId = uuid()\n this.storage?.setItem(SOURCE_KEY, sourceId)\n }\n let requestId = this.storage?.getItem(IMPORT_REQUEST_KEY)\n if (requestId === null || requestId === undefined || requestId === '') {\n requestId = uuid()\n this.storage?.setItem(IMPORT_REQUEST_KEY, requestId)\n }\n const snapshot = await this.post(requestId, { kind: 'import', sourceId, tasks: [...legacy] })\n this.storage?.setItem(IMPORT_MARKER, snapshot.scheduler.ledgerId ?? ledgerId)\n return snapshot\n }\n return initial\n }\n\n async state(): Promise<TaskBoardSnapshot> {\n return await this.request(`${TASK_BOARD_API_PREFIX}/state`, { cache: 'no-store' })\n }\n\n async action(action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot> {\n return await this.post(uuid(), action, initiator)\n }\n\n private async post(requestId: string, action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot> {\n const envelope: TaskBoardActionEnvelope = { requestId, action, ...(initiator === undefined || initiator === '' ? {} : { initiator }) }\n return await this.request(`${TASK_BOARD_API_PREFIX}/action`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(envelope),\n })\n }\n\n private async request(url: string, init: RequestInit): Promise<TaskBoardSnapshot> {\n const controller = new AbortController()\n const timeout = globalThis.setTimeout(() => { controller.abort() }, REQUEST_TIMEOUT_MS)\n try {\n return await readJson<TaskBoardSnapshot>(await fetch(url, { ...init, signal: controller.signal }))\n } catch (error) {\n if (error instanceof HostApiError) throw error\n if (controller.signal.aborted) throw new HostApiError('timeout', t('board.hostError.timeout', { seconds: String(REQUEST_TIMEOUT_MS / 1_000) }))\n // fetch itself failed (server stopped, connection reset, DNS): the panel\n // says so in its own words instead of leaking \"Failed to fetch\".\n throw new HostApiError('unreachable', t('board.hostError.unreachable'))\n } finally {\n globalThis.clearTimeout(timeout)\n }\n }\n\n /**\n * Ask the Host to turn pasted text into task fields. The route answers a\n * typed failure (no model, timeout, unparseable reply) already phrased for\n * the form, so the UI never renders a raw status code (issue #1540).\n */\n async parseDraft(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft> {\n let response: Response\n try {\n response = await fetch(`${TASK_BOARD_API_PREFIX}/parse`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(request),\n ...(signal === undefined ? {} : { signal }),\n })\n } catch {\n // A cancelled parse and a stopped Host look the same to fetch; the form\n // checks its own abort flag before showing anything.\n throw new HostApiError('unreachable', t('board.hostError.unreachable'))\n }\n const text = await response.text()\n let parsed: unknown\n let readable = false\n if (text.trim() !== '') {\n try {\n parsed = JSON.parse(text)\n readable = true\n } catch {\n readable = false\n }\n }\n const record = readable && typeof parsed === 'object' && parsed !== null\n ? parsed as { code?: unknown; error?: unknown; draft?: unknown }\n : undefined\n if (response.ok) {\n if (record !== undefined && isTaskParseDraft(record.draft)) return record.draft\n throw new HostApiError('unexpected', t('new.aiParseFailed', { error: t('board.hostError.unexpected', { status: String(response.status) }) }), response.status)\n }\n if (response.status === 404) throw new HostApiError('not-mounted', t('new.aiParseUnavailable'), 404)\n if (response.status === 401 || response.status === 403) throw new HostApiError('unauthorized', t('board.hostError.unauthorized'), response.status)\n const code = typeof record?.code === 'string' ? record.code : undefined\n if (code === 'no-model') throw new HostApiError('rejected', t('new.aiParseNoModel'), response.status)\n if (code === 'timeout') throw new HostApiError('timeout', t('new.aiParseTimeout', { seconds: String(TASK_PARSE_TIMEOUT_SECONDS) }), response.status)\n const detail = typeof record?.error === 'string' && record.error !== '' ? record.error : String(response.status)\n throw new HostApiError('rejected', t('new.aiParseFailed', { error: detail }), response.status)\n }\n\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void {\n const events = new EventSource(`${TASK_BOARD_API_PREFIX}/events`)\n let lastStreamErrorNotify = 0\n events.onmessage = (message: MessageEvent<string>): void => {\n try {\n const parsed = JSON.parse(message.data) as TaskBoardEventPayload\n if (parsed === null || typeof parsed !== 'object' || typeof parsed.revision !== 'number') throw new Error('invalid event frame')\n listener(parsed)\n } catch {\n listener()\n }\n }\n // A stream that cannot connect at all (unmounted route, refused socket) is\n // how a Host half that never mounted looks from the browser; nudge the\n // panel into one state read so the failure becomes visible (#1528).\n events.onerror = (): void => {\n const now = Date.now()\n if (now - lastStreamErrorNotify < STREAM_ERROR_NOTIFY_MS) return\n lastStreamErrorNotify = now\n listener()\n }\n const onVisible = (): void => { if (document.visibilityState === 'visible') listener() }\n document.addEventListener('visibilitychange', onVisible)\n return () => {\n document.removeEventListener('visibilitychange', onVisible)\n events.close()\n }\n }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/telemetry.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Anonymous install telemetry shared by the DSH Web UI family plugins.\n *\n * Once per UTC day per browser, each wired plugin sends one heartbeat to\n * the dsh-market edge API listing its package name (and version when known).\n * The payload carries no conversation data and no identifiers beyond a random\n * UUID generated in localStorage; the server hashes it with a deployment salt\n * before storage and never persists IP addresses. Sends are fire-and-forget:\n * failures stay silent and simply retry on a later mount or day. The system\n * is documented in docs/telemetry.md.\n */\n\nexport type TelemetryChannel = 'market' | 'npm' | 'unknown'\n\nexport interface TelemetryItem {\n /** npm package name or asset id, e.g. \"@linxin666/dsh-pet\" or \"skin:harbor\". */\n name: string\n /** Installed version when known; omitted otherwise. */\n version?: string\n /** Install channel when determinable (market = Workshop install). */\n channel?: TelemetryChannel\n}\n\nconst VISITOR_KEY = 'dsh-web-ui-telemetry-visitor'\nconst DAY_KEY_PREFIX = 'dsh-web-ui-telemetry-day:'\nconst ENDPOINT = 'https://dsh-market.com/api/telemetry/event'\n\n// Baked into each client bundle by shared/tsdown.client.ts (the package's own\n// package.json version at build time). Undefined in dev/test builds.\ndeclare const __DSH_PKG_VERSION__: string | undefined\n\n/** The building package's version, when the bundle carries it. */\nfunction bakedVersion(): string | undefined {\n try {\n return typeof __DSH_PKG_VERSION__ === 'string' && __DSH_PKG_VERSION__ !== ''\n ? __DSH_PKG_VERSION__\n : undefined\n } catch {\n return undefined\n }\n}\n\n/** Read or lazily create the anonymous visitor id; null when storage is unavailable. */\nfunction visitorId(): string | null {\n try {\n const existing = localStorage.getItem(VISITOR_KEY)\n if (existing && /^[A-Za-z0-9_-]{16,64}$/.test(existing)) return existing\n const fresh = crypto.randomUUID().replaceAll('-', '')\n localStorage.setItem(VISITOR_KEY, fresh)\n return fresh\n } catch {\n // Storage unavailable (privacy mode, sandboxed frame): report nothing.\n return null\n }\n}\n\n/** Drop stale per-day dedup keys so localStorage does not grow forever. */\nfunction pruneDayKeys(today: string): void {\n try {\n for (let index = localStorage.length - 1; index >= 0; index -= 1) {\n const key = localStorage.key(index)\n if (key !== null && key.startsWith(DAY_KEY_PREFIX) && key !== DAY_KEY_PREFIX + today) {\n localStorage.removeItem(key)\n }\n }\n } catch { /* best effort */ }\n}\n\n/**\n * Fire the daily heartbeat for the given items at most once per UTC day per\n * browser. Never throws and never blocks the caller. Items without an explicit\n * version inherit the bundle's baked build version.\n */\nexport function reportDailyHeartbeat(items: readonly TelemetryItem[]): void {\n try {\n if (items.length === 0) return\n const today = new Date().toISOString().slice(0, 10)\n // Automation contexts (CDP-driven QA browsers, fresh isolated profiles)\n // mint a new visitor id per run and would inflate instance counts.\n if (navigator.webdriver) return\n if (localStorage.getItem(DAY_KEY_PREFIX + today) !== null) return\n const visitor = visitorId()\n if (visitor === null) return\n pruneDayKeys(today)\n const payloadItems = items.map((item) => {\n const out: Record<string, string> = { name: item.name }\n const version = item.version ?? bakedVersion()\n if (version !== undefined) out.version = version\n if (item.channel !== undefined) out.channel = item.channel\n return out\n })\n const body = JSON.stringify({ kind: 'heartbeat', visitor, items: payloadItems })\n void fetch(ENDPOINT, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body,\n keepalive: true,\n }).then((response) => {\n // Mark the day only after an accepted send, so offline browsers retry\n // on a later mount instead of going dark until tomorrow.\n if (response.ok) localStorage.setItem(DAY_KEY_PREFIX + today, '1')\n }).catch(() => { /* unreachable endpoint: stay silent */ })\n } catch { /* never break the host UI over telemetry */ }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/plugin-card-seat.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family plugin-card seat.\n *\n * A family plugin contributes its settings card to whichever plugin-card seat\n * the running host actually renders:\n *\n * - `web-ui.plugin.item` — the list seat declared by the dsh-web-settings\n * group section (this family's own first-level \"Web UI plugins\" section);\n * - `plugins.bundle.config` — the official keyed seat of the harness's plugin\n * manager page, keyed by the bundle's package name and rendered on that\n * bundle's page. alpha.2 removed the `settings.plugin.item` keyed seat of the\n * `ui-settings-plugins` tab that this helper used before, so a card keyed by\n * its settings namespace has no seat to land in any more.\n *\n * SEAT SELECTION IS NOT A DECLARATION PROBE. The official plugin surface\n * belongs to the harness bundle and declares its seats before any external\n * plugin's `apply()` runs, so \"is the official seat declared?\" answers yes even\n * in the deployment whose whole point is the family group. Choosing on that\n * probe sends every family card to the official page and leaves the group's own\n * section permanently empty — the family of reports where the section renders\n * its heading and zero cards.\n *\n * The signal that actually distinguishes the two deployments is whether\n * dsh-web-settings is loaded: it is the package that owns the group section and\n * it publishes the `webUiSettings` service during `apply()`, which every\n * family plugin already reads for its settings form. Group loaded -> the family\n * seat; group absent -> the official seat.\n *\n * The decision is re-evaluated on every `slots/changed` because the group may\n * apply after this plugin (the family aggregate orders it first, a profile that\n * installs the group separately need not): the initial contribution goes to the\n * official seat, then moves to the family seat the moment the group's section\n * registers. The entry is disposed before the replacement is registered, so a\n * card is never in two seats at once.\n *\n * The shared tree has no client-SDK dependency, so this module reads its\n * context through the structural shape below; callers pass the plugin's own\n * `ctx`.\n */\n\n/** The family list seat key. */\nexport const FAMILY_PLUGIN_CARD_SEAT = 'web-ui.plugin.item'\n\n/** The official keyed plugin-card seat key (the alpha.2 bundle-configuration seat). */\nexport const OFFICIAL_PLUGIN_CARD_SEAT = 'plugins.bundle.config'\n\n/** The service dsh-web-settings publishes while it is loaded. */\nexport const FAMILY_GROUP_SERVICE = 'webUiSettings'\n\n/** The slot-registry member this helper uses (structurally satisfied by ctx.slots). */\nexport interface PluginCardSlots {\n /** Contribution of one card entry. */\n register(options: never, component: never): unknown\n}\n\n/** The slice of the client context a card contribution needs. */\nexport interface PluginCardContext {\n slots: PluginCardSlots\n /** Service lookup; absent on a context double that only models the slots. */\n get?(name: string): unknown\n /** Event subscription seat; absent on an event-less test double. */\n on?(event: string, listener: (...args: never[]) => void): unknown\n}\n\n/** Owner share of a family list-seat card (that seat supplies nothing). */\nexport interface SettingsPluginItemOwnerProps {\n /** Marker field: card owner props are intentionally empty. */\n children?: never\n}\n\n/** One family plugin's card contribution. */\nexport interface PluginCardSeat {\n /**\n * Npm package name of the bundle this card configures; the official keyed\n * seat dispatches on it. Every family package ships its own bundle patch, so\n * a standalone install lists that package as the bundle whose page renders\n * this card.\n */\n bundle: string\n /** Family list-seat entry id. */\n id: string\n /** Family list-seat sort order. */\n order?: number\n /** Family list-seat display label; the official keyed seat carries none. */\n label?: () => string\n /** Locale namespace the card renders with. */\n locale: string\n /** Business-face factory of the registration. */\n inject?: () => object\n /**\n * The card component. Its props type is the seat's composed shape, which is\n * chosen at runtime, so the helper takes it erased; the registrant keeps its\n * own precise typing at the call site.\n */\n component: unknown\n}\n\n/**\n * Whether the family group (dsh-web-settings) is loaded in this page. The\n * service is the group package's own contract, so the probe cannot be fooled\n * by a harness release that starts declaring the official seat differently.\n */\nexport function familyGroupLoaded(ctx: PluginCardContext): boolean {\n const get = ctx.get\n if (typeof get !== 'function') return false\n try {\n return get.call(ctx, FAMILY_GROUP_SERVICE) !== undefined\n } catch {\n // A context that refuses the lookup: treat the group as absent, which\n // falls back to the official seat the harness declares.\n return false\n }\n}\n\n/** Report a refused registration instead of leaving the user with no card. */\nfunction warnRefusedSeat(seat: string, error: unknown): void {\n try {\n console.warn(`[dsh-web] plugin card registration into \"${seat}\" was refused; the card will not render`, error)\n } catch {\n // Best-effort console write; a failed warning must not break the plugin.\n }\n}\n\n/**\n * Contribute one family plugin card to the seat this host renders, following\n * the group if it loads later. The entry is disposed and re-registered on a\n * seat change, never duplicated.\n * @param ctx - client context (its slot registry decides the seat).\n * @param seat - the card contribution.\n */\nexport function installPluginCard(ctx: PluginCardContext, seat: PluginCardSeat): void {\n const slots = ctx.slots\n const component = seat.component as never\n const inject = seat.inject as never\n\n let dispose: (() => void) | undefined\n let current: string | undefined\n /**\n * Re-entrancy latch. The registry emits a change event synchronously from\n * inside both `register` and the previous entry's disposer, so an unguarded\n * reconcile would re-enter itself mid-move and register the card twice into\n * the seat it is leaving (\"already has an entry for key ...\").\n */\n let reconciling = false\n\n /** Reconcile the contribution with the currently live seat (no-op when unchanged). */\n const reconcile = (): void => {\n if (reconciling) return\n const target = familyGroupLoaded(ctx) ? FAMILY_PLUGIN_CARD_SEAT : OFFICIAL_PLUGIN_CARD_SEAT\n if (current === target) return\n reconciling = true\n const previous = dispose\n dispose = undefined\n current = undefined\n previous?.()\n try {\n dispose = slots.register((target === FAMILY_PLUGIN_CARD_SEAT\n ? {\n name: FAMILY_PLUGIN_CARD_SEAT,\n id: seat.id,\n ...(seat.order === undefined ? {} : { order: seat.order }),\n ...(seat.label === undefined ? {} : { label: seat.label }),\n locale: seat.locale,\n ...(seat.inject === undefined ? {} : { inject }),\n }\n : {\n name: OFFICIAL_PLUGIN_CARD_SEAT,\n key: seat.bundle,\n locale: seat.locale,\n ...(seat.inject === undefined ? {} : { inject }),\n }) as never, component) as () => void\n current = target\n } catch (error) {\n warnRefusedSeat(target, error)\n } finally {\n reconciling = false\n }\n }\n\n if (typeof ctx.on === 'function') {\n try {\n ctx.on('slots/changed', () => { reconcile() })\n } catch {\n // An event seat that refuses the subscription leaves the initial\n // decision in place; the card still renders in the seat chosen below.\n }\n }\n // The initial decision: the group, when it is already loaded (the aggregate\n // order), otherwise the official seat the harness declares.\n reconcile()\n}\n","/**\n * Task-board client plugin: wires the framework-free core (controller,\n * execution service, store) to the real client runtime and mounts the two\n * DOM surfaces — the sidebar entry row and the board view in the center\n * column.\n *\n * Failure policy: DOM mounting problems are logged, never thrown — the web\n * shell fails the whole boot when a plugin apply throws, and an external\n * plugin must not take the GUI down.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { ClientRemote, SessionId } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { IWorkspaces } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { ConfigForm, ConfigForms } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale) and its\n// LocaleNamespaceMap merge table.\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the shared-forms Context merge (ctx.configForms).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the workspace plugin's Context merge (ctx.uiWorkspace), the\n// multi-instance navigation face that replaced ISessions.open().\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { BoardController } from '../core/controller.ts'\nimport { mainViewSessionId } from './main-session.ts'\nimport { LocalStorageTaskStore } from '../core/store.ts'\nimport { claimTaskboardApply, releaseTaskboardApply } from './apply-guard.ts'\nimport { mountBoard } from './board-mount.tsx'\nimport { mountSidebarEntry } from './sidebar-entry.ts'\nimport { TaskBoardSettingsCard, TaskBoardSettingsCardController, type TaskBoardSettings } from './TaskBoardSettingsCard.tsx'\nimport { en, zh, setRuntimeTranslate, type TaskBoardKey } from './locales.ts'\nimport { HttpTaskBoardHostTransport } from './host-api.ts'\nimport { reportDailyHeartbeat } from './telemetry.ts'\nimport { installPluginCard } from './plugin-card-seat.ts'\n\n/** Locale namespace this plugin owns. */\nconst NS = 'task-board'\n\n/** Settings namespace this card edits (the family identity of the plugin's own settings form). */\nconst TASK_BOARD_NS = 'task-board'\n\n/**\n * Profile entry id the family aggregate's generated row carries — the\n * deployment shape nearly every user runs. Under 0.1.7 a settings form is\n * addressed by profile entry id, so the shared-forms fallback below has to\n * name it; the family binder resolves the family namespace instead.\n */\nconst AGGREGATE_ENTRY_ID = 'web-ui-task-board'\n\n/**\n * Profile entry ids this package's two patch rows carry: the aggregate's\n * generated row and the standalone bundle patch's row (`ui-task-board`), plus\n * the bare namespace as the last resort for a Host whose descriptor is keyed\n * by the family namespace itself.\n */\nconst TASK_BOARD_ENTRY_IDS: readonly string[] = [AGGREGATE_ENTRY_ID, 'ui-task-board', TASK_BOARD_NS]\n\n/** Domain-owned description of one settings namespace a family card binds. */\nexport interface SettingsFormSpec<T> {\n /** Settings namespace the card edits. */\n namespace: string\n /**\n * Narrow one wire section; undefined keeps the last accepted value. The\n * shared form already resolves the namespace's own serialized wire schema,\n * so a decoder exists only to narrow beyond that schema.\n */\n decode?: (section: unknown) => T | undefined\n}\n\n/**\n * The family settings binder published by dsh-web-settings. Its `bind` resolves\n * a family namespace to the profile entry id that owns it and hands back the\n * shared configuration form, so it is the only seat that can reach this card's\n * form on a Host whose row id is not the namespace.\n */\nexport interface SettingsFormBinder {\n /** Bind one family settings namespace. */\n bind<T>(spec: SettingsFormSpec<T>): ConfigForm<T>\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Task-board surface copy. */\n 'task-board': TaskBoardKey\n }\n\n interface SlotMap {\n /**\n * The child slot the Web UI plugin group declares; this card registers\n * into the group's list seat rather than the official\n * bundle-configuration seat. Spelled here with the same shape so this\n * package can register without depending on the sibling UI package.\n */\n 'web-ui.plugin.item': { kind: 'list'; scope: 'root'; owner: SettingsPluginItemOwnerProps }\n }\n}\n\n/** Owner share of a plugin card (the section supplies nothing). */\nexport interface SettingsPluginItemOwnerProps {\n /** Marker field: card owner props are intentionally empty. */\n children?: never\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * Optional family settings binder provided by dsh-web-settings; absent\n * when that group plugin is not installed, so callers fall back to the\n * shared configuration forms service.\n */\n webUiSettings?: SettingsFormBinder\n }\n}\n\n\n/**\n * Required services (fiber inject waiting — the runtime must be up first).\n * The generated remote faces are probed at use time instead of injected:\n * `remote.agentPresets` only registers on 0.1.2-alpha.2 hosts (the\n * api-remotes contribution), so a hard wait would pend the entry forever\n * on hosts below that cohort, which serve the same roster through the\n * connection RPC face.\n */\nexport const inject = ['slots', 'sessions', 'workspaces', 'connection', 'configForms', 'locale', 'remote', 'remote.session', 'uiWorkspace']\n\n/** One agent-preset row the mode picker consumes (either face's wire shape). */\ninterface PresetRosterRow {\n id: string\n name?: string\n description?: string\n /** Why this preset cannot compose a session; absent when it can. */\n broken?: string\n isDefault: boolean\n}\n\n/**\n * Read the agent-preset roster through whichever face the running host\n * serves: the generated api-remotes face (`remote.agentPresets`,\n * 0.1.2-alpha.2) or the connection RPC face\n * (`connection.api.agentPresets`, hosts below that cohort). Answers\n * undefined when the host serves neither, so the caller leaves the picker\n * options untouched instead of erroring.\n */\nasync function readPresetRoster(\n ctx: ClientContext,\n remote: ClientRemote,\n): Promise<{ ok: boolean; presets: readonly PresetRosterRow[] } | undefined> {\n // The cordis `remote` proxy throws on a property that was never injected\n // (\"cannot get property X without inject\") rather than returning undefined,\n // so the probe must guard the access — a hard read would abort mounting on\n // hosts below the 0.1.2-alpha.2 cohort instead of degrading to the legacy\n // connection RPC face below.\n let remotes: ClientRemote['agentPresets'] | undefined\n try {\n remotes = (remote as Partial<ClientRemote>).agentPresets\n } catch {\n remotes = undefined\n }\n if (remotes !== undefined) {\n const response = await remotes.list()\n if (!response.ok) return { ok: false, presets: [] }\n return { ok: true, presets: response.value.presets }\n }\n const connection = ctx.get('connection') as unknown as {\n api?: { agentPresets?: { list(request: Record<string, never>): Promise<{ result: { ok: boolean; value?: { presets?: readonly PresetRosterRow[] } } }> } }\n }\n const legacy = connection.api?.agentPresets\n if (legacy === undefined) return undefined\n const response = await legacy.list({})\n if (!response.result.ok || response.result.value === undefined) return { ok: false, presets: [] }\n return { ok: true, presets: response.result.value.presets ?? [] }\n}\n\n/**\n * Mount the task board.\n * @param ctx - client root context (services: sessions, workspaces).\n */\nexport function apply(ctx: ClientContext): void {\n // Anonymous install heartbeat (docs/telemetry.md): one beat per browser per\n // UTC day, package name only, silent failure.\n reportDailyHeartbeat([{ name: '@linxin666/dsh-client-ui-task-board' }])\n\n // A duplicated client injection (module factory executed twice in one page\n // lifetime) would otherwise mount a second sidebar entry and board view.\n // First application wins; later calls become no-ops (see apply-guard.ts).\n if (!claimTaskboardApply()) return\n\n // Release the claim when this fiber unloads (the loader supports plugin\n // unloads / hot-reloads), so a rebuilt bundle can claim again in the same\n // page instead of being silently dropped.\n ctx.effect(() => releaseTaskboardApply, 'task-board: apply claim')\n\n ctx.effect(() => {\n try {\n return ctx.locale.register(NS, { zh, en })\n } catch {\n return () => {}\n }\n }, 'task-board: dictionaries')\n\n // Wire the SDK translate seat into the module-level t (sidebar row and\n // other plain-DOM callers): reads the active locale at call time, so they\n // follow the Language setting without a reload. The register effect above\n // guarantees the dictionaries exist before the first read.\n try { setRuntimeTranslate(ctx.locale.bind(NS)) } catch { /* locale missing: document-language fallback stays */ }\n\n // Plugin configuration card: one staged form over the `task-board` settings\n // namespace, contributed to whichever plugin-card seat this host declares\n // (the family group's list seat, or the official bundle-configuration seat).\n const settingsForm = bindSettingsForm(ctx)\n const settingsCard = new TaskBoardSettingsCardController(settingsForm)\n installPluginCard(ctx, {\n bundle: '@linxin666/dsh-client-ui-task-board',\n id: 'task-board',\n order: 110,\n locale: NS,\n inject: () => settingsCard.inject(),\n component: TaskBoardSettingsCard,\n })\n ctx.effect(() => () => { settingsCard.dispose() }, 'task-board: settings card')\n\n // The sidebar entry and board view mount once the settings form settles;\n // while the form is still loading, the composition default is unknown, so\n // nothing mounts yet. Only an unavailable form (no settings surface served)\n // falls back to the composition default (enabled).\n let uiDisposer: (() => void) | undefined\n const mountUi = (): void => {\n if (uiDisposer !== undefined) return\n // Host and browser SDK declarations share the Cordis Context name. Read\n // the browser faces explicitly so Host-side declaration merging cannot\n // narrow these two client services during a combined package build.\n const sessions = ctx.get('sessions') as unknown as ISessions\n const workspaces = ctx.get('workspaces') as unknown as IWorkspaces\n const remote = ctx.get('remote') as unknown as ClientRemote\n\n // Core wiring: real runtime faces into the framework-free services.\n const store = new LocalStorageTaskStore()\n const controller = new BoardController({\n store,\n transport: new HttpTaskBoardHostTransport(),\n sessions: {\n // The main-view Session comes from the catalog's per-source ownership\n // counts; navigation belongs to the workspace UI since the\n // multi-instance Client Session model.\n current: () => mainViewSessionId(sessions.list.getSnapshot().byId),\n open: id => ctx.uiWorkspace.openSession(id as never),\n subscribe: fn => sessions.list.subscribe(fn),\n },\n })\n controller.start()\n\n const disposers: Array<() => void> = []\n\n // Execution-target option feeds: the workspace list drives the workspace\n // picker, and the agent-preset roster drives the mode picker. Both are\n // runtime facts (not ledger state), so the wiring pushes them into the\n // controller on change; the preset roster is re-read after reconnects\n // because a reconnect may serve a different deployment.\n const pushWorkspaceOptions = (): void => {\n const snapshot = workspaces.list.getSnapshot()\n controller.setExecutionOptions({\n workspaces: snapshot.items.map(item => ({\n workspaceId: item.workspaceId,\n title: item.title !== '' ? item.title : item.path,\n })),\n })\n }\n pushWorkspaceOptions()\n disposers.push(workspaces.list.subscribe(pushWorkspaceOptions))\n // \"New project\" on the board is the GUI's own add-project call (#1536);\n // the runtime emits the created Workspace through workspaces.list, which\n // refreshes the filter above without a local re-read.\n controller.setWorkspaceCreator(async path => {\n const created = await workspaces.create({ path })\n return { workspaceId: created.workspaceId }\n })\n const pushPresetOptions = async (): Promise<void> => {\n try {\n const roster = await readPresetRoster(ctx, remote)\n if (roster === undefined || !roster.ok) return\n controller.setExecutionOptions({\n presets: roster.presets.map(preset => ({\n id: preset.id,\n name: preset.name,\n description: preset.description,\n broken: preset.broken,\n isDefault: preset.isDefault,\n })),\n })\n } catch (error) {\n // A failed roster read leaves the previous options in place; the\n // picker stays usable and the next reconnect retries the read.\n console.error('[dsh-task-board] agent preset roster read failed', error)\n }\n }\n const pushModelOptions = async (): Promise<void> => {\n try {\n let models: Array<{ id: string; name?: string; provider?: string }> = []\n let sessionRemote: ClientRemote['session'] | undefined\n try {\n sessionRemote = (remote as Partial<ClientRemote>).session\n } catch {\n sessionRemote = undefined\n }\n if (typeof sessionRemote?.modelCatalog === 'function') {\n const res = await sessionRemote.modelCatalog()\n if (res.ok && Array.isArray(res.value?.groups)) {\n for (const g of res.value.groups) {\n const provider = (g as { id?: string; provider?: string }).id ?? (g as { id?: string; provider?: string }).provider\n for (const m of g.models ?? []) {\n const qualifiedId = provider ? `${provider}/${m.id}` : m.id\n models.push({ id: qualifiedId, name: m.name ?? m.id, provider })\n }\n }\n }\n }\n if (models.length === 0) {\n const conn = ctx.get('connection') as {\n api?: {\n llm?: { discoverModels?: () => Promise<unknown> }\n sessions?: { modelCatalog?: () => Promise<unknown> }\n session?: { modelCatalog?: () => Promise<unknown> }\n }\n } | undefined\n if (conn?.api) {\n if (typeof conn.api.llm?.discoverModels === 'function') {\n const res = await conn.api.llm.discoverModels() as { result?: { value?: { models?: Array<{ id: string; name?: string }> } } }\n const list = res?.result?.value?.models\n if (Array.isArray(list)) {\n models = list.map(m => ({ id: m.id, name: m.name }))\n }\n }\n const catalogFn = typeof conn.api.session?.modelCatalog === 'function'\n ? conn.api.session.modelCatalog\n : typeof conn.api.sessions?.modelCatalog === 'function'\n ? conn.api.sessions.modelCatalog\n : undefined\n if (models.length === 0 && catalogFn !== undefined) {\n const res = await catalogFn() as { result?: { value?: { groups?: Array<{ id?: string; provider?: string; models?: Array<{ id: string; name?: string }> }> } } }\n const groups = res?.result?.value?.groups\n if (Array.isArray(groups)) {\n for (const g of groups) {\n const provider = g.id ?? g.provider\n for (const m of g.models ?? []) {\n const qualifiedId = provider ? `${provider}/${m.id}` : m.id\n models.push({ id: qualifiedId, name: m.name ?? m.id, provider })\n }\n }\n }\n }\n }\n }\n if (models.length > 0) {\n controller.setExecutionOptions({ models })\n }\n } catch (error) {\n console.error('[dsh-task-board] model options read failed', error)\n }\n }\n void pushModelOptions()\n disposers.push(ctx.on('connection/reset', () => { void pushModelOptions() }))\n try {\n disposers.push(mountSidebarEntry(controller, ctx.locale))\n disposers.push(mountBoard(controller, ctx.locale))\n } catch (error) {\n // DOM failures degrade the board, never the GUI.\n console.error('[dsh-task-board] mount failed:', error)\n }\n\n uiDisposer = () => {\n for (const dispose of disposers.splice(0)) dispose()\n controller.dispose()\n uiDisposer = undefined\n }\n }\n const syncEnabled = (): void => {\n const snapshot = settingsForm.getSnapshot()\n const enabled = snapshot.status === 'ready'\n ? snapshot.value?.enabled ?? true\n : snapshot.status === 'unavailable'\n if (enabled) mountUi()\n else uiDisposer?.()\n }\n settingsForm.subscribe(syncEnabled)\n syncEnabled()\n}\n\n/**\n * Bind the settings form this card stages over.\n *\n * The family binder (`ctx.get('webUiSettings')`, published by dsh-web-settings)\n * comes first: it is what traces this package's family namespace onto the\n * profile entry id the Host serves the form under, and it keeps the loopback\n * bridge as its own fallback. A page without that group falls back to the\n * shared configuration forms service bound directly at one of this package's\n * own profile entry ids.\n * @param ctx - client root context.\n * @returns the form the settings card reads and writes.\n */\nexport function bindSettingsForm(ctx: ClientContext): ConfigForm<TaskBoardSettings> {\n const binder = ctx.get('webUiSettings')\n if (binder !== undefined && typeof binder.bind === 'function') {\n return binder.bind<TaskBoardSettings>({ namespace: TASK_BOARD_NS })\n }\n return ctx.configForms.get<TaskBoardSettings>(servedEntryId(ctx.configForms))\n}\n\n/**\n * The profile entry id this package's own row carries.\n *\n * The shared describe mirror is the only local evidence of which row id this\n * profile actually serves, but it answers asynchronously: at plugin\n * activation it usually holds nothing yet. An unanswered mirror therefore\n * binds the aggregate row id rather than guessing among the candidates —\n * the form is bound once for the session, so a wrong guess would leave the\n * card reporting an unserved namespace even after the mirror settles.\n * @param forms - the shared configuration forms service.\n * @returns the entry id to bind.\n */\nfunction servedEntryId(forms: ConfigForms): string {\n let served: readonly string[] | undefined\n try {\n served = forms.describe().getSnapshot().view?.namespaces.map(view => view.ns)\n } catch {\n served = undefined\n }\n if (served === undefined) return AGGREGATE_ENTRY_ID\n return TASK_BOARD_ENTRY_IDS.find(id => served.includes(id)) ?? TASK_BOARD_NS\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["applyScheduleRollForward","css","css","css","css","css","css","css","css","mountSidebarEntry","mountSharedSidebarEntry","css"],"sources":["../../../packages/dsh-task-board/src/core/tasks.ts","../../../packages/dsh-task-board/src/core/subtask.ts","../../../packages/dsh-task-board/src/core/use-cases/task-archive.ts","../../../packages/dsh-task-board/src/core/schedule.ts","../../../packages/dsh-task-board/src/core/use-cases/task-create.ts","../../../packages/dsh-task-board/src/core/use-cases/task-delete.ts","../../../packages/dsh-task-board/src/core/use-cases/task-schedule.ts","../../../packages/dsh-task-board/src/core/use-cases/task-parent.ts","../../../packages/dsh-task-board/src/core/use-cases/task-update.ts","../../../packages/dsh-task-board/src/core/controller.ts","../../../packages/dsh-task-board/src/client/main-session.ts","../../../packages/dsh-task-board/src/core/freeze-snapshot.ts","../../../packages/dsh-task-board/src/core/handover.ts","../../../packages/dsh-task-board/src/core/store.ts","../../../packages/dsh-task-board/src/client/apply-guard.ts","../../../packages/dsh-task-board/src/client/locales.ts","../../../packages/dsh-task-board/src/client/schedule-presets.ts","../../../packages/dsh-task-board/src/client/board/TaskForm.tsx","../../../packages/dsh-task-board/src/client/board/parse-model-pref.ts","../../../packages/dsh-task-board/src/client/board/NewTaskModal.tsx","../../../packages/dsh-task-board/src/client/board/status-key.ts","../../../packages/dsh-task-board/src/client/board/TaskCard.tsx","../../../packages/dsh-task-board/src/client/board/ConfirmDialog.tsx","../../../packages/dsh-task-board/src/client/board/EditTaskModal.tsx","../../../packages/dsh-task-board/src/client/board/LinkSubtaskModal.tsx","../../../packages/dsh-task-board/src/client/board/TaskDetail.tsx","../../../packages/dsh-task-board/src/client/board/TaskBoard.tsx","../../../packages/dsh-task-board/src/client/body-mutations.ts","../../../packages/dsh-task-board/src/client/panel-mount-core.ts","../../../packages/dsh-task-board/src/client/board-mount.tsx","../../../packages/dsh-task-board/src/client/sidebar-entry-core.ts","../../../packages/dsh-task-board/src/client/sidebar-entry.ts","../../../packages/dsh-task-board/src/client/PluginSettingsCard.tsx","../../../packages/dsh-task-board/src/client/settings-form.ts","../../../packages/dsh-task-board/src/client/TaskBoardSettingsCard.tsx","../../../packages/dsh-task-board/src/protocol.ts","../../../packages/dsh-task-board/src/client/host-api.ts","../../../packages/dsh-task-board/src/client/telemetry.ts","../../../packages/dsh-task-board/src/client/plugin-card-seat.ts","../../../packages/dsh-task-board/src/client/index.ts"],"sourcesContent":["/**\n * Task board domain model: task lifecycle statuses, the task record shape,\n * and the pure transition functions the controller and tests share.\n * Framework-free (no cordis, no runtime imports) so the state machine is\n * unit-testable in isolation.\n */\nimport type { FreezeSnapshot } from './freeze-snapshot.ts'\nimport type { TaskHandover, TaskHandoverInput } from './handover.ts'\n\n/** Task lifecycle status, one per kanban column. */\nexport type TaskStatus = 'backlog' | 'todo' | 'running' | 'done' | 'failed'\n\n/** Settled outcome of one execution attempt. */\nexport type ExecutionOutcome = 'succeeded' | 'failed' | 'cancelled'\n\n/**\n * One real execution attempt: the run's own id, the dsh session that ran it\n * (filled once the session is created), and the settled outcome once the\n * session's turn ended.\n */\nexport interface ExecutionRecord {\n /** Execution attempt id (uuid). */\n id: string\n /** The dsh session that ran this attempt; absent until creation resolves. */\n sessionId: string | undefined\n /** When the run started (ms epoch). */\n startedAt: number\n /** When the run settled; absent while still running. */\n endedAt: number | undefined\n /** Outcome once settled. */\n result: ExecutionOutcome | undefined\n /** Human failure text when the run failed (prompt rejection or agent error). */\n error: string | undefined\n /**\n * Session id of the DSH session that issued the run/rerun action (issue #6\n * audit origin). Client-asserted, not a trust boundary; absent when the run\n * was triggered by cron (source unknown).\n */\n initiatedBy?: string\n /** Freeze instant captured from the card snapshot when the run opened. */\n frozenAt?: number\n /** Freeze source session captured from the card snapshot when the run opened. */\n frozenBy?: string\n /**\n * Cascade run group shared by the parent execution and every descendant\n * execution one run request opened. Absent on a plain single-task run.\n */\n runGroupId?: string\n /**\n * A cascade parent's own session outcome, recorded as soon as its own turn\n * settles and held while its subtask executions finish. The execution stays\n * open (no `endedAt`) until the last child settles; the Host monitor skips\n * an execution whose own outcome is already recorded.\n */\n ownResult?: ExecutionOutcome\n /** Human failure text that arrived with {@link ownResult}. */\n ownError?: string\n}\n\n/**\n * Maximum number of execution records retained per task. Older settled runs\n * are trimmed when a new execution starts so per-action ledger cost stays\n * bounded regardless of how often a task ran before.\n */\nexport const EXECUTION_HISTORY_LIMIT = 20\n\n/**\n * Trim an execution list to at most {@link EXECUTION_HISTORY_LIMIT} records,\n * most recent last. A running (unsettled) execution is never trimmed: the\n * Host monitor and restart recovery depend on the active record, and a task\n * cannot start a new run while one is still open.\n */\nexport function retainRecentExecutions(executions: readonly ExecutionRecord[]): ExecutionRecord[] {\n if (executions.length <= EXECUTION_HISTORY_LIMIT) return [...executions]\n const open = executions.filter(execution => execution.endedAt === undefined)\n const settled = executions.filter(execution => execution.endedAt !== undefined)\n const keepSettled = Math.max(EXECUTION_HISTORY_LIMIT - open.length, 0)\n return [...settled.slice(Math.max(settled.length - keepSettled, 0)), ...open]\n}\n\n/**\n * A scheduled-run rule attached to a task. The Host scheduler triggers the\n * task when `nextRunAt` is due and persists the rule in the Host ledger.\n */\nexport interface ScheduleRule {\n /** Whether the schedule is armed. */\n enabled: boolean\n /** 5-field cron expression: `分 时 日 月 周`. */\n cron: string\n /** Next due instant (ms epoch); maintained by the scheduler/controller. */\n nextRunAt: number | undefined\n /** Instant of the latest scheduled trigger (ms epoch). */\n lastTriggeredAt: number | undefined\n}\n\n/**\n * Frozen context snapshot carried by a continuation card (issue #4): the\n * goal/progress/next text (already sanitized by the freeze gates) plus the\n * freeze instant and the redaction warning flag.\n */\nexport interface TaskFreeze extends FreezeSnapshot {\n /** When the snapshot was frozen (ms epoch, stamped by the create/update use case). */\n frozenAt: number\n /** True when the freeze gates redacted sensitive patterns out of the text. */\n redacted?: boolean\n /**\n * Session id of the DSH session that authored the frozen snapshot (issue #6\n * provenance): stamped by the Host ledger from the create/update action's\n * initiator, or kept from the wire payload when no initiator was asserted.\n */\n frozenBy?: string\n}\n\n/**\n * One task label (issue #1521). The name is the badge and the tag-filter key;\n * the optional prompt line rides the execution prompt, so a label may be\n * display-only (no prefix) or carry an instruction (business-line routing,\n * output directory, house style) that every run of the task inherits.\n */\nexport interface TaskTag {\n /** Display name; trimmed, non-empty, unique within the task. */\n name: string\n /**\n * Prompt line injected ahead of the execution prompt. Absent (or blank\n * after trimming) keeps the tag display-only: it never touches the prompt,\n * so a label with no prefix has zero execution side effects.\n */\n promptPrefix?: string\n}\n\n/** Maximum number of tags carried by one task. */\nexport const TASK_TAG_LIMIT = 8\n/** Maximum length of a tag name. */\nexport const TAG_NAME_MAX_LENGTH = 32\n/** Maximum length of a tag's injected prompt line. */\nexport const TAG_PROMPT_MAX_LENGTH = 200\n\n/** Whether an unknown value is a well-formed tag (strict: the wire gate). */\nexport function isTaskTag(value: unknown): value is TaskTag {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const tag = value as Record<string, unknown>\n if (Object.keys(tag).some(key => key !== 'name' && key !== 'promptPrefix')) return false\n if (typeof tag.name !== 'string') return false\n const name = tag.name.trim()\n if (name === '' || name.length > TAG_NAME_MAX_LENGTH) return false\n if (tag.promptPrefix !== undefined && typeof tag.promptPrefix !== 'string') return false\n return tag.promptPrefix === undefined || (tag.promptPrefix as string).trim().length <= TAG_PROMPT_MAX_LENGTH\n}\n\n/**\n * Whether an unknown value is a well-formed tag list (strict: the wire gate).\n * An empty list is rejected — clearing tags is expressed by omitting the field\n * (create) or by an explicit null (update), never by an empty array.\n */\nexport function isTaskTagList(value: unknown): value is TaskTag[] {\n return Array.isArray(value) && value.length > 0 && value.length <= TASK_TAG_LIMIT && value.every(isTaskTag)\n}\n\n/**\n * Repair a persisted tag list: keep the well-formed entries, trim, drop\n * blanks and repeats, cap the count, and collapse a blank prompt line to\n * \"display-only\". Returns undefined when nothing usable remains, so the caller\n * clears the field instead of storing an empty array.\n */\nexport function normalizeTags(value: unknown): TaskTag[] | undefined {\n if (!Array.isArray(value)) return undefined\n const tags: TaskTag[] = []\n const seen = new Set<string>()\n for (const entry of value) {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) continue\n const row = entry as Record<string, unknown>\n if (typeof row.name !== 'string') continue\n const name = row.name.trim()\n if (name === '' || name.length > TAG_NAME_MAX_LENGTH || seen.has(name)) continue\n const raw = typeof row.promptPrefix === 'string' ? row.promptPrefix.trim() : ''\n const promptPrefix = raw === '' ? undefined : raw.slice(0, TAG_PROMPT_MAX_LENGTH)\n seen.add(name)\n tags.push(promptPrefix === undefined ? { name } : { name, promptPrefix })\n if (tags.length >= TASK_TAG_LIMIT) break\n }\n return tags.length === 0 ? undefined : tags\n}\n\n/**\n * Stable palette slot (0..5) for a tag name. The same label always lands on the\n * same tone, so a badge needs no stored colour and two tasks sharing a label\n * cannot disagree about it.\n */\nexport function tagTone(name: string): number {\n let hash = 0\n for (const char of name) hash = (hash * 31 + (char.codePointAt(0) ?? 0)) >>> 0\n return hash % 6\n}\n\n/**\n * Union of the labels already carried by `tasks`, first occurrence wins (the\n * oldest task's hint is the one offered). Feeds the editor's name datalist and\n * the board's tag filter, so a label defined once can be reused everywhere.\n */\nexport function collectKnownTags(tasks: readonly TaskRecord[]): TaskTag[] {\n const known: TaskTag[] = []\n const seen = new Set<string>()\n for (const task of tasks) {\n for (const tag of task.tags ?? []) {\n if (seen.has(tag.name)) continue\n seen.add(tag.name)\n known.push(tag)\n }\n }\n return known\n}\n\n/** One task on the board. */\nexport interface TaskRecord {\n /** Stable task id (uuid). */\n id: string\n /** Short display title. */\n title: string\n /** Longer human description shown in the detail view. */\n description: string\n /** The prompt sent to dsh when this task is executed. */\n prompt: string\n /**\n * Parent task id: present only on a subtask. The Host owns the lineage gate\n * (see `core/subtask.ts`), which refuses a cycle, an archived parent, and\n * any link that would exceed `maxSubtaskDepth` — so every chain the Host\n * wrote under the current setting is at most that many links long. Lowering\n * the limit later neither rewrites nor deletes an already stored link.\n */\n parentId?: string\n /** Current column. */\n status: TaskStatus\n /** Creation instant (ms epoch). */\n createdAt: number\n /** Last mutation instant (ms epoch). */\n updatedAt: number\n /**\n * Execution history retained on the task, most recent last: the latest\n * {@link EXECUTION_HISTORY_LIMIT} attempts, oldest trimmed on append.\n */\n executions: ExecutionRecord[]\n /** Optional scheduled-run rule (absent on tasks without a schedule). */\n schedule?: ScheduleRule\n /**\n * Workspace the execution must run in (a workspace-list id); absent means\n * the recent-workspace fallback at execution time.\n */\n workspaceId?: string\n /**\n * Agent preset the execution session must be composed from (an\n * `agentPreset.list` id); absent means the deployment default.\n */\n mode?: string\n /**\n * Permission preset applied to the execution session through the\n * `/permission <id>` slash command; absent leaves the session default.\n */\n permission?: TaskPermission\n /**\n * Pinned model selection for the execution session (format: \"provider/model\" or model id);\n * absent falls back to the host default (agent-default-model).\n */\n model?: string\n /**\n * Whether later executions continue in the previous execution's session\n * (issue #1419) instead of minting a fresh conversation per run. Absent or\n * false keeps the historical one-session-per-execution behavior; the reuse\n * itself only happens when that session is idle and still present (see\n * {@link reusableSessionId}).\n */\n reuseSession?: boolean\n /**\n * Run this task's subtree as an Agent Team instead of one Host-launched\n * session per participant: the root becomes the Team Lead session and the\n * Host spawns one teammate for each direct subtask inside it. Absent or false\n * keeps the plain concurrent cascade. A deployment that does not serve the\n * Agent Teams service refuses a team run instead of silently falling back,\n * and a subtask's own permission pin cannot be honored in this mode.\n */\n teamRun?: boolean\n /**\n * Frozen context snapshot for a continuation card; absent on plain tasks.\n * Sanitized before it enters the ledger (redaction, slash-command taint,\n * 8 KiB per-field cap) by the protocol gate and re-normalized on load.\n */\n freeze?: TaskFreeze\n /**\n * Handover bundle carried by a continuation card (issue #5): the pinned\n * execution triplet plus doc/script references. Sanitized before it\n * enters the ledger by the protocol gate and re-normalized on load; the\n * bundle's triplet overrides the legacy pin fields at execution time.\n */\n handover?: TaskHandover\n /**\n * Task labels (issue #1521): optional, additive, and absent on every task\n * created before the field existed. A tag whose `promptPrefix` is set is\n * prepended to the execution prompt; a bare name is display and filter only.\n */\n tags?: TaskTag[]\n /**\n * Human confirmation stamp for an above-default effective permission\n * (ms epoch). Absent while the binding awaits confirmation; any permission\n * or handover change re-arms the gate by clearing it.\n */\n permissionConfirmedAt?: number\n /**\n * When the task was archived (ms epoch). Archived tasks keep their status\n * and execution history, leave the main board, and cannot run until restored;\n * absent means on-board.\n */\n archivedAt?: number\n}\n\n/**\n * Statuses a task may be archived from: every status but `running`, whose\n * execution the runner still owns until it settles. A settled-only gate made\n * the duplicate-and-archive flow a silent no-op for scheduled tasks, which\n * return to `todo` after every successful run (issue #1447).\n */\nexport const ARCHIVABLE_STATUSES: readonly TaskStatus[] = ['backlog', 'todo', 'done', 'failed']\n\n\n/** Permission presets a task may pin on its execution session (the `/permission <id>` ids). */\nexport const TASK_PERMISSIONS = ['read-only', 'workspace-write', 'danger-full-access'] as const\n\n/** One permission preset id. */\nexport type TaskPermission = typeof TASK_PERMISSIONS[number]\n\n/** Whether an unknown value is a known permission preset id. */\nexport function isTaskPermission(value: unknown): value is TaskPermission {\n return typeof value === 'string' && (TASK_PERMISSIONS as readonly string[]).includes(value)\n}\n\n/** Input for creating a task. */\nexport interface NewTaskInput {\n title: string\n description: string\n prompt: string\n /**\n * Parent task id, turning this creation into a subtask. Absent keeps a root\n * task; the create use case validates the link (existence, depth) and\n * inherits the parent's unset execution targets.\n */\n parentId?: string\n /** Workspace the execution must run in; empty/absent = the recent workspace. */\n workspaceId?: string\n /** Agent preset the execution session must be composed from; empty/absent = deployment default. */\n mode?: string\n /** Permission preset applied to the execution session; absent = session default. */\n permission?: TaskPermission\n /** Optional pinned model for the execution session; absent = host default. */\n model?: string\n /** Reuse the previous execution's session for later runs (issue #1419). */\n reuseSession?: boolean\n /** Run the subtree as an Agent Team (Team Lead session plus one teammate per direct subtask). */\n teamRun?: boolean\n /**\n * Optional scheduled-run rule requested at creation time (the new-task\n * dialog): an enable flag plus a 5-field cron expression. The create use\n * case arms it only when enabled and the expression is valid.\n */\n schedule?: { enabled: boolean; cron: string }\n /**\n * Optional frozen context snapshot (goal/progress/next, sanitized by the\n * protocol gate) turning the new task into a continuation card.\n */\n freeze?: FreezeSnapshot & { redacted?: boolean; frozenBy?: string }\n /**\n * Optional handover bundle (pinned triplet + doc/script references,\n * sanitized by the protocol gate) attached at creation.\n */\n handover?: TaskHandoverInput\n /**\n * Optional task labels. A tag with a non-blank `promptPrefix` is injected\n * ahead of the execution prompt; a bare name changes nothing at run time.\n */\n tags?: TaskTag[]\n}\n\n/** The five kanban columns, in display order. */\nexport const COLUMNS: readonly { status: TaskStatus; label: string }[] = [\n { status: 'backlog', label: '待规划' },\n { status: 'todo', label: '待办' },\n { status: 'running', label: '进行中' },\n { status: 'done', label: '已完成' },\n { status: 'failed', label: '已失败' },\n]\n\n/** Statuses a user may move a card to manually (execution states are owned by the runner). */\nexport const MANUAL_STATUSES: readonly TaskStatus[] = ['backlog', 'todo']\n\n/** Statuses the runner may move a card to from 'running'. */\nexport const RUNNER_SETTLE_STATUSES: readonly TaskStatus[] = ['done', 'failed']\n\n/** All valid statuses (closed union guard). */\nexport const ALL_STATUSES: readonly TaskStatus[] = [\n 'backlog', 'todo', 'running', 'done', 'failed',\n]\n\n/** Brand an unknown string as a status; undefined when it is not one. */\nexport function isTaskStatus(value: unknown): value is TaskStatus {\n return typeof value === 'string' && (ALL_STATUSES as readonly string[]).includes(value)\n}\n\n/** Whether a manual move target is allowed from the given status. */\nexport function canMoveManually(from: TaskStatus, to: TaskStatus): boolean {\n return from !== 'running' && (MANUAL_STATUSES as readonly TaskStatus[]).includes(to)\n}\n\n/** Normalize one optional execution-target string: trim; blank collapses to undefined. */\nexport function normalizeTargetId(value: string | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed === undefined || trimmed === '' ? undefined : trimmed\n}\n\n/**\n * Build the persisted freeze snapshot from a sanitized input, stamping the\n * freeze instant (shared by the create and update use cases).\n */\nexport function freezeOf(\n input: FreezeSnapshot & { redacted?: boolean; frozenBy?: string },\n now: number,\n): TaskFreeze {\n return {\n goal: input.goal,\n progress: input.progress,\n next: input.next,\n frozenAt: now,\n ...(input.redacted === true ? { redacted: true } : {}),\n ...(input.frozenBy === undefined || input.frozenBy === '' ? {} : { frozenBy: input.frozenBy }),\n }\n}\n\n/** Create a task from user input. */\nexport function createTask(input: NewTaskInput, now: number, id: string): TaskRecord {\n const tags = normalizeTags(input.tags)\n return {\n id,\n title: input.title.trim(),\n description: input.description.trim(),\n prompt: input.prompt.trim(),\n parentId: normalizeTargetId(input.parentId),\n status: 'todo',\n createdAt: now,\n updatedAt: now,\n executions: [],\n workspaceId: normalizeTargetId(input.workspaceId),\n mode: normalizeTargetId(input.mode),\n permission: isTaskPermission(input.permission) ? input.permission : undefined,\n model: normalizeTargetId(input.model),\n reuseSession: input.reuseSession === true ? true : undefined,\n teamRun: input.teamRun === true ? true : undefined,\n ...(input.freeze === undefined ? {} : { freeze: freezeOf(input.freeze, now) }),\n ...(input.handover === undefined ? {} : { handover: { ...input.handover, bundledAt: now } }),\n ...(tags === undefined ? {} : { tags }),\n }\n}\n\n/** Clone a task with an updated status and a fresh updatedAt. */\nexport function withStatus(task: TaskRecord, status: TaskStatus, now: number): TaskRecord {\n return { ...task, status, updatedAt: now }\n}\n\n/**\n * Merge a schedule patch into a task's schedule rule (creating it when\n * absent), with a fresh updatedAt. Keys present in the patch overwrite the\n * current value — including explicit `undefined`, which clears a field (used\n * to disarm `nextRunAt`); absent keys keep their current value.\n */\nexport function withSchedule(\n task: TaskRecord,\n patch: Partial<ScheduleRule>,\n now: number,\n): TaskRecord {\n const current = task.schedule\n const schedule: ScheduleRule = {\n enabled: current?.enabled ?? false,\n cron: current?.cron ?? '',\n nextRunAt: current?.nextRunAt,\n lastTriggeredAt: current?.lastTriggeredAt,\n }\n if ('enabled' in patch) schedule.enabled = patch.enabled ?? false\n if ('cron' in patch) schedule.cron = patch.cron ?? ''\n if ('nextRunAt' in patch) schedule.nextRunAt = patch.nextRunAt\n if ('lastTriggeredAt' in patch) schedule.lastTriggeredAt = patch.lastTriggeredAt\n return { ...task, updatedAt: now, schedule }\n}\n\n/**\n * Open a fresh execution on a task: move it to 'running' and append a\n * running execution record. Returns the new task and the new execution.\n * @param runGroupId - cascade run group, when this run also opened executions\n * for the task's subtasks (see `core/subtask.ts`).\n */\nexport function startExecution(\n task: TaskRecord,\n now: number,\n executionId: string,\n initiatedBy?: string,\n runGroupId?: string,\n): { task: TaskRecord; execution: ExecutionRecord } {\n const execution: ExecutionRecord = {\n id: executionId,\n sessionId: undefined,\n startedAt: now,\n endedAt: undefined,\n result: undefined,\n error: undefined,\n ...(runGroupId === undefined || runGroupId === '' ? {} : { runGroupId }),\n ...(initiatedBy === undefined || initiatedBy === '' ? {} : { initiatedBy }),\n // Capture the card's freeze provenance on the execution record so the\n // audit trail stays queryable even if the snapshot is replaced later.\n ...(task.freeze === undefined ? {} : {\n frozenAt: task.freeze.frozenAt,\n ...(task.freeze.frozenBy === undefined ? {} : { frozenBy: task.freeze.frozenBy }),\n }),\n }\n return {\n task: {\n ...task,\n status: 'running',\n updatedAt: now,\n executions: retainRecentExecutions([...task.executions, execution]),\n },\n execution,\n }\n}\n\n/**\n * Settle a running execution: record the outcome and move the task into the\n * matching column. No-op (returns the input task) when the execution is not\n * the task's latest or is already settled.\n */\nexport function settleExecution(\n task: TaskRecord,\n executionId: string,\n outcome: ExecutionOutcome,\n now: number,\n error: string | undefined,\n): TaskRecord {\n const index = task.executions.findIndex(execution => execution.id === executionId)\n if (index === -1) return task\n const execution = task.executions[index]\n if (execution.endedAt !== undefined) return task\n const settled: ExecutionRecord = { ...execution, endedAt: now, result: outcome, error }\n const executions = [...task.executions]\n executions[index] = settled\n const status: TaskStatus = outcome === 'succeeded'\n ? (task.schedule?.enabled ? 'todo' : 'done')\n : outcome === 'failed' ? 'failed'\n : task.status === 'running' ? 'todo' : task.status\n return { ...task, status, updatedAt: now, executions }\n}\n\n/** A settled-execution summary string for the detail view. */\nexport function executionLabel(execution: ExecutionRecord): string {\n if (execution.result === 'succeeded') return 'succeeded'\n if (execution.result === 'failed') return 'failed'\n if (execution.result === 'cancelled') return 'cancelled'\n return 'running'\n}\n","/**\n * Subtask lineage: the depth gate, the ancestry/descendant queries, the\n * cascade participant set one run request opens, the deferred settlement of a\n * cascade parent, and the execution-target inheritance a subtask resolves at\n * run time.\n *\n * Framework-free (no cordis, no runtime imports) so every rule is\n * unit-testable in isolation. The Host ledger is the only authority; the\n * browser mirrors these predicates to enable or disable controls, never to\n * decide them.\n */\nimport type { ExecutionOutcome, ExecutionRecord, TaskRecord } from './tasks.ts'\n\n/** Lowest configurable subtask depth. */\nexport const SUBTASK_DEPTH_MIN = 1\n/** Highest configurable subtask depth. */\nexport const SUBTASK_DEPTH_MAX = 3\n/** Deployment default: one level of subtasks, and no subtask of a subtask. */\nexport const DEFAULT_SUBTASK_DEPTH = 1\n\n/**\n * Clamp a configured depth into the supported range. Anything unusable\n * (absent, non-numeric, not finite) falls back to the default, so a bad\n * configuration narrows the tree instead of lifting the guard.\n */\nexport function normalizeSubtaskDepth(value: unknown): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_SUBTASK_DEPTH\n const depth = Math.trunc(value)\n if (depth < SUBTASK_DEPTH_MIN) return SUBTASK_DEPTH_MIN\n if (depth > SUBTASK_DEPTH_MAX) return SUBTASK_DEPTH_MAX\n return depth\n}\n\n/** Whether an unknown value is a settled execution outcome. */\nexport function isExecutionOutcome(value: unknown): value is ExecutionOutcome {\n return value === 'succeeded' || value === 'failed' || value === 'cancelled'\n}\n\nfunction indexOf(tasks: readonly TaskRecord[]): Map<string, TaskRecord> {\n return new Map(tasks.map(task => [task.id, task]))\n}\n\n/**\n * Nearest-first ancestor chain of a task. The walk is cycle-safe and bounded\n * by the ledger size rather than by the deployment maximum: a chain stored\n * under a larger limit survives that limit being lowered, and restore and\n * inheritance must still see all of it.\n */\nexport function ancestorChain(tasks: readonly TaskRecord[], task: TaskRecord): TaskRecord[] {\n const index = indexOf(tasks)\n const chain: TaskRecord[] = []\n const seen = new Set<string>([task.id])\n let current = task.parentId === undefined ? undefined : index.get(task.parentId)\n while (current !== undefined && chain.length < tasks.length) {\n if (seen.has(current.id)) break\n seen.add(current.id)\n chain.push(current)\n current = current.parentId === undefined ? undefined : index.get(current.parentId)\n }\n return chain\n}\n\n/** Root-to-task depth: a root task is 0, its subtask 1, and so on. */\nexport function taskDepth(tasks: readonly TaskRecord[], id: string): number {\n const task = indexOf(tasks).get(id)\n return task === undefined ? 0 : ancestorChain(tasks, task).length\n}\n\n/** Direct subtasks of a task, in ledger order. */\nexport function directSubtasks(tasks: readonly TaskRecord[], id: string): TaskRecord[] {\n return tasks.filter(task => task.parentId === id)\n}\n\n/**\n * Descendants of a task in breadth-first order, bounded by maxSubtaskDepth\n * total depth. The visited set keeps a malformed ledger from looping.\n */\nexport function descendantTasks(tasks: readonly TaskRecord[], id: string, maxSubtaskDepth: number): TaskRecord[] {\n const visited = new Set<string>([id])\n const found: TaskRecord[] = []\n let frontier = [id]\n for (let depth = 1; depth <= maxSubtaskDepth && frontier.length > 0; depth += 1) {\n const next: string[] = []\n for (const parentId of frontier) {\n for (const task of tasks) {\n if (task.parentId !== parentId || visited.has(task.id)) continue\n visited.add(task.id)\n found.push(task)\n next.push(task.id)\n }\n }\n frontier = next\n }\n return found\n}\n\n/**\n * Height of a task's own subtree (0 for a leaf), bounded by the hard maximum.\n * The visited set makes the walk terminate on a cyclic hand-edited ledger\n * instead of recursing until the stack overflows.\n */\nexport function subtreeHeight(tasks: readonly TaskRecord[], id: string, visited: ReadonlySet<string> = new Set<string>()): number {\n if (visited.has(id)) return 0\n const seen = new Set([...visited, id])\n const children = directSubtasks(tasks, id)\n if (children.length === 0) return 0\n let height = 0\n for (const child of children) height = Math.max(height, 1 + subtreeHeight(tasks, child.id, seen))\n return Math.min(height, SUBTASK_DEPTH_MAX)\n}\n\n/** Why a parent link was refused; also the source of the Host error text. */\nexport type ParentLinkRejection =\n | 'unknown-task'\n | 'unknown-parent'\n | 'archived-parent'\n | 'self-parent'\n | 'cycle'\n | 'depth-exceeded'\n\nexport interface ParentLinkCheck {\n /** True when the link (or the detachment) may be stored. */\n ok: boolean\n /** Why it was refused; absent when ok. */\n reason?: ParentLinkRejection\n}\n\n/**\n * Whether childId may be attached under parentId. A null parent detaches and\n * is always allowed for a known task. Otherwise the link must name an\n * on-board task that is neither the child itself nor one of its descendants,\n * and the resulting depth (parent depth + 1 + the child own subtree height)\n * must stay within maxSubtaskDepth.\n */\nexport function checkParentLink(\n tasks: readonly TaskRecord[],\n childId: string,\n parentId: string | null,\n maxSubtaskDepth: number,\n): ParentLinkCheck {\n const child = tasks.find(task => task.id === childId)\n if (child === undefined) return { ok: false, reason: 'unknown-task' }\n if (parentId === null || parentId === '') return { ok: true }\n if (parentId === childId) return { ok: false, reason: 'self-parent' }\n const parent = tasks.find(task => task.id === parentId)\n if (parent === undefined) return { ok: false, reason: 'unknown-parent' }\n if (parent.archivedAt !== undefined) return { ok: false, reason: 'archived-parent' }\n if (descendantTasks(tasks, childId, SUBTASK_DEPTH_MAX).some(task => task.id === parentId)) return { ok: false, reason: 'cycle' }\n const depth = taskDepth(tasks, parentId) + 1 + subtreeHeight(tasks, childId)\n if (depth > maxSubtaskDepth) return { ok: false, reason: 'depth-exceeded' }\n return { ok: true }\n}\n\n/**\n * The tasks one run request opens executions for: the requested task first,\n * then its on-board descendants within the configured depth. Archived tasks\n * never run; a participant that already has an open execution is skipped by\n * the caller, which cannot start it twice.\n */\nexport function cascadeTargets(\n tasks: readonly TaskRecord[],\n rootId: string,\n maxSubtaskDepth: number,\n): TaskRecord[] {\n const root = tasks.find(task => task.id === rootId)\n if (root === undefined) return []\n return [root, ...descendantTasks(tasks, rootId, maxSubtaskDepth)]\n}\n\n/** One still-open execution belonging to a cascade run group. */\nexport interface OpenCascadeChild {\n taskId: string\n execution: ExecutionRecord\n}\n\n/** The open execution of a task inside a run group, if it still exists. */\nexport function openGroupExecution(task: TaskRecord, runGroupId: string): ExecutionRecord | undefined {\n return task.executions.find(execution => execution.runGroupId === runGroupId && execution.endedAt === undefined)\n}\n\n/**\n * The direct subtasks of parentTaskId whose execution in this run group is\n * still open: the parent remaining waiters. The parent may settle once this\n * list is empty and its own outcome is known.\n */\nexport function pendingCascadeChildren(\n tasks: readonly TaskRecord[],\n parentTaskId: string,\n runGroupId: string,\n): OpenCascadeChild[] {\n const pending: OpenCascadeChild[] = []\n for (const task of tasks) {\n if (task.parentId !== parentTaskId) continue\n const execution = openGroupExecution(task, runGroupId)\n if (execution !== undefined) pending.push({ taskId: task.id, execution })\n }\n return pending\n}\n\n/**\n * Fold a cascade parent own outcome and its children outcomes into one\n * verdict: failure dominates, then cancellation, then success. The error text\n * is the first failure, falling back to the first cancellation.\n */\nexport function combineCascadeOutcome(\n entries: readonly { result: ExecutionOutcome; error?: string }[],\n): { result: ExecutionOutcome; error: string | undefined } {\n let result: ExecutionOutcome = 'succeeded'\n let error: string | undefined\n for (const entry of entries) {\n if (entry.result === 'failed') {\n if (result !== 'failed') error = undefined\n result = 'failed'\n if (error === undefined && entry.error !== undefined && entry.error !== '') error = entry.error\n continue\n }\n if (entry.result === 'cancelled') {\n if (result === 'succeeded') result = 'cancelled'\n if (error === undefined && entry.error !== undefined && entry.error !== '') error = entry.error\n }\n }\n return error === undefined ? { result, error: undefined } : { result, error }\n}\n\n/**\n * The permission a task would actually run under: its handover bundle's pin\n * wins over the plain pin field, exactly as the runner resolves it.\n */\nexport function effectiveTaskPermission(task: TaskRecord): TaskRecord['permission'] {\n return task.handover?.permission ?? task.permission\n}\n\n/**\n * Resolve the execution targets a (sub)task actually runs with: its own value\n * wins, and an unset target inherits the nearest ancestor up to the root.\n * Workspace, agent preset and model inherit the ancestor's PIN only — a\n * handover bundle is a per-card continuation artefact and is never inherited.\n * The permission inherits the ancestor's EFFECTIVE binding, and its human\n * confirmation travels with it, so a subtask of an already-confirmed elevated\n * card is runnable while a subtask's own unconfirmed binding stays gated.\n */\n/**\n * The immutable teammate name for one team-mode member. Teammate names are\n * lower-kebab-case and must stay unique for the lifetime of the Team, so the\n * run-group token is appended: two runs of the same tree never collide. A title\n * with no ASCII word characters (a CJK title, for example) keeps a stable\n * generic prefix and is still distinguished by the token.\n * @param title - the member task's title.\n * @param token - the run group id (the task id when no group is recorded).\n * @returns the teammate name handed to the Agent Teams service.\n */\nexport function teammateName(title: string, token: string): string {\n const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 32).replace(/-+$/g, '')\n const suffix = token.replace(/[^a-z0-9]/gi, '').slice(0, 8).toLowerCase()\n return `${slug === '' ? 'subtask' : slug}-${suffix === '' ? 'run' : suffix}`\n}\n\nexport function resolveExecutionTargets(\n task: TaskRecord,\n tasks: readonly TaskRecord[],\n maxSubtaskDepth: number = SUBTASK_DEPTH_MAX,\n): TaskRecord {\n if (task.parentId === undefined) return task\n const chain = [task, ...ancestorChain(tasks, task).slice(0, maxSubtaskDepth)]\n const first = (key: 'workspaceId' | 'mode' | 'model'): string | undefined => {\n for (const candidate of chain) {\n const value = candidate[key]\n if (value !== undefined) return value\n }\n return undefined\n }\n const own = effectiveTaskPermission(task)\n // An own binding (pin or handover) keeps its own confirmation stamp; only an\n // absent one borrows the ancestor's binding AND that ancestor's stamp.\n const owner = own === undefined\n ? chain.slice(1).find(candidate => effectiveTaskPermission(candidate) !== undefined)\n : undefined\n return {\n ...task,\n workspaceId: first('workspaceId'),\n mode: first('mode'),\n model: first('model'),\n permission: own ?? (owner === undefined ? undefined : effectiveTaskPermission(owner)),\n permissionConfirmedAt: own === undefined ? owner?.permissionConfirmedAt : task.permissionConfirmedAt,\n }\n}\n","/**\n * Archive/restore task use case: move a task off the main board and back,\n * whatever its status but running. The task keeps its status, execution\n * history, and transcript references, while archiving disarms any schedule so\n * it cannot create more execution records until the user restores and\n * re-enables it.\n *\n * Subtask trees move as a unit: archiving takes the whole subtree (an on-board\n * subtask under an archived parent would be unreachable from its parent) and\n * refuses the whole group while any member is running. Restoring brings the\n * task, its ancestors and its subtree back together.\n */\nimport { DEFAULT_SUBTASK_DEPTH, ancestorChain, descendantTasks, normalizeSubtaskDepth } from '../subtask.ts'\nimport type { TaskRecord } from '../tasks.ts'\nimport { ARCHIVABLE_STATUSES } from '../tasks.ts'\n\n/** Result of an archive transition. */\nexport interface ArchiveTaskResult {\n /** The next ledger. */\n tasks: readonly TaskRecord[]\n /** Whether the archive was applied (false = unknown task / not archivable). */\n archived: boolean\n}\n\n/** The archive/restore id set: the task, its subtree, and (for restore) its ancestors. */\nfunction groupIds(tasks: readonly TaskRecord[], id: string, maxSubtaskDepth: number, withAncestors: boolean): Set<string> {\n const target = tasks.find(task => task.id === id)\n const ids = new Set<string>([id])\n for (const task of descendantTasks(tasks, id, normalizeSubtaskDepth(maxSubtaskDepth))) ids.add(task.id)\n if (withAncestors && target !== undefined) {\n for (const ancestor of ancestorChain(tasks, target)) ids.add(ancestor.id)\n }\n return ids\n}\n\n/**\n * Archive one task and its subtasks: only a running member keeps the group on\n * the board (its runner still owns its lifecycle until the execution settles);\n * any other status can be archived. Archiving disarms schedules; an\n * already-archived task is a no-op.\n */\nexport function applyArchiveTask(\n tasks: readonly TaskRecord[],\n id: string,\n now: number,\n maxSubtaskDepth: number = DEFAULT_SUBTASK_DEPTH,\n): ArchiveTaskResult {\n const target = tasks.find(task => task.id === id)\n if (target === undefined || target.archivedAt !== undefined) return { tasks, archived: false }\n const ids = groupIds(tasks, id, maxSubtaskDepth, false)\n const declining = tasks.some(task => ids.has(task.id) && !(ARCHIVABLE_STATUSES as readonly string[]).includes(task.status))\n if (declining) return { tasks, archived: false }\n let applied = false\n const next = tasks.map(task => {\n if (!ids.has(task.id) || task.archivedAt !== undefined) return task\n applied = true\n const schedule = task.schedule === undefined\n ? undefined\n : { ...task.schedule, enabled: false, nextRunAt: undefined }\n return {\n ...task,\n ...(schedule === undefined ? {} : { schedule }),\n archivedAt: now,\n updatedAt: now,\n }\n })\n return { tasks: next, archived: applied }\n}\n\n/**\n * Restore one task back onto the main board, together with its ancestors (an\n * on-board subtask must not point at an archived parent) and its subtasks.\n */\nexport function applyRestoreTask(\n tasks: readonly TaskRecord[],\n id: string,\n now: number,\n maxSubtaskDepth: number = DEFAULT_SUBTASK_DEPTH,\n): ArchiveTaskResult {\n const target = tasks.find(task => task.id === id)\n if (target === undefined || target.archivedAt === undefined) return { tasks, archived: false }\n const ids = groupIds(tasks, id, maxSubtaskDepth, true)\n let applied = false\n const next = tasks.map(task => {\n if (!ids.has(task.id) || task.archivedAt === undefined) return task\n applied = true\n const { archivedAt: _archived, ...rest } = task\n return { ...rest, updatedAt: now }\n })\n return { tasks: next, archived: applied }\n}\n","/**\n * Minimal 5-field cron parsing and next-run computation for scheduled task\n * runs. Framework-free and dependency-free so the scheduler and controller\n * share one tiny pure module.\n *\n * Grammar: five whitespace-separated fields, 分 时 日 月 周. Every field\n * supports the wildcard, step (wildcard or range + \"/n\"), single value,\n * inclusive range a-b, and comma lists mixing any of those. Ranges: minutes\n * 0-59, hours 0-23, days 1-31, months 1-12, weekdays 0-7 (0 and 7 both mean\n * Sunday). When both the day and weekday fields are restricted they combine\n * with OR semantics (standard cron). Invalid expressions parse to null and\n * are rejected by the UI/controller.\n */\n\n/** The parsed match sets of one cron expression. */\nexport interface CronSchedule {\n minutes: ReadonlySet<number>\n hours: ReadonlySet<number>\n days: ReadonlySet<number>\n months: ReadonlySet<number>\n /** Weekdays 0-6, 0 = Sunday (input 7 normalized to 0). */\n weekdays: ReadonlySet<number>\n /** Whether the day-of-month field was the literal '*' (unrestricted). */\n dayWildcard: boolean\n /** Whether the weekday field was the literal '*' (unrestricted). */\n weekdayWildcard: boolean\n}\n\n/** Inclusive ranges per field, in cron order. */\nconst FIELD_RANGES: ReadonlyArray<readonly [number, number]> = [\n [0, 59], // minutes\n [0, 23], // hours\n [1, 31], // days\n [1, 12], // months\n [0, 7], // weekdays (7 = Sunday, normalized below)\n]\n\n/**\n * Parse a 5-field cron expression.\n * @returns the match sets, or null when the expression is invalid.\n */\nexport function parseCron(expr: string): CronSchedule | null {\n const fields = expr.trim().split(/\\s+/)\n if (fields.length !== 5) return null\n const sets: Set<number>[] = []\n for (let index = 0; index < 5; index++) {\n const [min, max] = FIELD_RANGES[index]\n const set = new Set<number>()\n if (!parseField(fields[index], min, max, set)) return null\n sets.push(set)\n }\n const weekdays = new Set<number>()\n for (const day of sets[4]) weekdays.add(day === 7 ? 0 : day)\n return {\n minutes: sets[0],\n hours: sets[1],\n days: sets[2],\n months: sets[3],\n weekdays,\n // Only the literal '*' marks a field unrestricted: an explicit full\n // enumeration such as '1-31' is a restricted field and must not collapse\n // into the wildcard (it participates in day/weekday OR semantics).\n dayWildcard: fields[2] === '*',\n weekdayWildcard: fields[4] === '*',\n }\n}\n\n/** Whether the expression parses. */\nexport function isValidCron(expr: string): boolean {\n return parseCron(expr) !== null\n}\n\n/**\n * Compute the next matching instant after `fromMs` (ms epoch), in local time,\n * at minute granularity, strictly greater than `fromMs`. Returns the ms epoch\n * of the matching minute's start, or undefined when the calendar constraint\n * can never match (for example `0 0 30 2 *`). The five-year horizon includes\n * a full leap cycle, so a valid February 29 schedule remains reachable from\n * every non-leap year.\n *\n * Walks candidate year/month/day/hour/minute values straight from the parsed\n * field sets instead of scanning every minute: a sparse expression such as\n * `0 0 29 2 *` used to iterate ~1.5M wall-clock minutes before reaching the\n * next leap day. Wall-clock field construction + the final `matches` re-check\n * preserve the old minute scan's DST semantics exactly (nonexistent spring\n * minutes normalize forward and the repeated fall-back hour is never visited).\n */\nexport function nextRunAtMs(expr: string, fromMs: number): number | undefined {\n const schedule = parseCron(expr)\n if (schedule === null) return undefined\n if (!hasPossibleCalendarDay(schedule)) return undefined\n const from = new Date(fromMs)\n const limitMs = fromMs + 5 * 366 * 24 * 60 * 60 * 1000\n\n const sortedMinutes = [...schedule.minutes].sort((a, b) => a - b)\n const sortedHours = [...schedule.hours].sort((a, b) => a - b)\n const sortedMonths = [...schedule.months].sort((a, b) => a - b)\n\n let year = from.getFullYear()\n let month = from.getMonth() + 1\n let day = from.getDate()\n let hour = from.getHours()\n // Strictly after fromMs: the old scan started from the next minute.\n let minute = from.getMinutes() + 1\n\n while (new Date(year, month - 1, 1, 0, 0, 0, 0).getTime() <= limitMs) {\n for (const candidateMonth of sortedMonths) {\n if (candidateMonth < month) continue\n const daysInMonth = new Date(year, candidateMonth, 0).getDate()\n const dayStart = candidateMonth === month ? day : 1\n for (let candidateDay = dayStart; candidateDay <= daysInMonth; candidateDay += 1) {\n const dayProbe = new Date(year, candidateMonth - 1, candidateDay, 0, 0, 0, 0)\n if (!dayCandidate(schedule, dayProbe)) continue\n const hourStart = candidateMonth === month && candidateDay === day ? hour : 0\n for (const candidateHour of sortedHours) {\n if (candidateHour < hourStart) continue\n const minuteStart = candidateMonth === month && candidateDay === day && candidateHour === hour ? minute : 0\n for (const candidateMinute of sortedMinutes) {\n if (candidateMinute < minuteStart) continue\n const candidate = new Date(year, candidateMonth - 1, candidateDay, candidateHour, candidateMinute, 0, 0)\n const time = candidate.getTime()\n if (time <= fromMs) continue\n if (time > limitMs) return undefined\n if (matches(schedule, candidate)) return time\n }\n }\n }\n }\n year += 1\n month = 1\n day = 1\n hour = 0\n minute = 0\n }\n return undefined\n}\n\n/** Day/weekday OR gate shared by {@link matches} and the candidate scan. */\nfunction dayCandidate(schedule: CronSchedule, date: Date): boolean {\n const dayMatches = schedule.days.has(date.getDate())\n const weekdayMatches = schedule.weekdays.has(date.getDay())\n if (schedule.dayWildcard) return weekdayMatches\n if (schedule.weekdayWildcard) return dayMatches\n return dayMatches || weekdayMatches\n}\n\n/** Reject impossible month/day pairs without spending the multi-year scan. */\nfunction hasPossibleCalendarDay(schedule: CronSchedule): boolean {\n if (schedule.dayWildcard || !schedule.weekdayWildcard) return true\n const maximumDay = new Map<number, number>([\n [1, 31], [2, 29], [3, 31], [4, 30], [5, 31], [6, 30],\n [7, 31], [8, 31], [9, 30], [10, 31], [11, 30], [12, 31],\n ])\n for (const month of schedule.months) {\n const maximum = maximumDay.get(month) ?? 0\n if ([...schedule.days].some(day => day <= maximum)) return true\n }\n return false\n}\n\n/** Parse one comma-list field into the match set. */\nfunction parseField(field: string, min: number, max: number, out: Set<number>): boolean {\n if (field === '*') {\n for (let value = min; value <= max; value++) out.add(value)\n return true\n }\n for (const part of field.split(',')) {\n if (part === '') return false\n const [range, stepRaw] = part.split('/')\n let low: number\n let high: number\n if (range === '*') {\n low = min\n high = max\n } else if (range.includes('-')) {\n const [a, b] = range.split('-')\n if (a === '' || b === '' || !isDigits(a) || !isDigits(b)) return false\n low = Number(a)\n high = Number(b)\n } else if (isDigits(range)) {\n low = Number(range)\n // Standard cron: a bare value carrying a step runs from that value to the\n // field maximum (minutes 5/15 are 5,20,35,50), while a bare value alone is\n // exactly itself (#1493).\n high = stepRaw === undefined ? low : max\n } else {\n return false\n }\n if (low < min || high > max || low > high) return false\n const step = stepRaw === undefined ? 1 : isDigits(stepRaw) ? Number(stepRaw) : NaN\n if (!Number.isInteger(step) || step < 1) return false\n for (let value = low; value <= high; value += step) out.add(value)\n }\n return true\n}\n\n/** Day/weekday OR semantics: a restricted day field alone gates, and vice versa. */\nfunction matches(schedule: CronSchedule, date: Date): boolean {\n if (!schedule.minutes.has(date.getMinutes())) return false\n if (!schedule.hours.has(date.getHours())) return false\n if (!schedule.months.has(date.getMonth() + 1)) return false\n return dayCandidate(schedule, date)\n}\n\nfunction isDigits(value: string): boolean {\n return /^\\d+$/.test(value)\n}\n","/**\n * Create-task use case: mint a new task from user input, rejecting a blank\n * title and any parent link the lineage gate refuses. Pure ledger transition\n * (no persistence or notify - the controller orchestrates those), so it is\n * unit-testable without any runtime face.\n */\nimport { isValidCron, nextRunAtMs } from '../schedule.ts'\nimport { DEFAULT_SUBTASK_DEPTH, normalizeSubtaskDepth, taskDepth } from '../subtask.ts'\nimport { createTask, withSchedule, type NewTaskInput, type TaskRecord } from '../tasks.ts'\n\n/** Result of a create transition: the new task (when accepted) + the next ledger. */\nexport interface CreateTaskResult {\n /** The minted task, or undefined when the input was rejected. */\n task: TaskRecord | undefined\n /** The next ledger; identical reference when rejected. */\n tasks: readonly TaskRecord[]\n /** Why the input was rejected; absent when a task was minted. */\n error?: string\n}\n\n/**\n * Apply a create against the current ledger. Returns the new task and the\n * appended ledger, or the unchanged ledger when the title is blank or the\n * requested parent link is refused.\n *\n * A subtask inherits the execution targets its parent already pins (workspace,\n * agent preset, permission, model) unless the form supplied its own; the\n * parent human permission confirmation travels with an inherited permission,\n * so a subtask of an already-confirmed elevated card is runnable at once.\n * @param tasks - current ledger.\n * @param input - raw user input (title/description/prompt + optional schedule/parent).\n * @param now - clock instant (ms epoch).\n * @param id - minted task id.\n * @param maxSubtaskDepth - deployment subtask depth limit.\n */\nexport function applyCreateTask(\n tasks: readonly TaskRecord[],\n input: NewTaskInput,\n now: number,\n id: string,\n maxSubtaskDepth: number = DEFAULT_SUBTASK_DEPTH,\n): CreateTaskResult {\n if (input.title.trim() === '') return { task: undefined, tasks, error: 'title is required' }\n const limit = normalizeSubtaskDepth(maxSubtaskDepth)\n let parent: TaskRecord | undefined\n if (input.parentId !== undefined) {\n parent = tasks.find(task => task.id === input.parentId)\n if (parent === undefined) return { task: undefined, tasks, error: 'parent task not found' }\n if (parent.archivedAt !== undefined) return { task: undefined, tasks, error: 'parent task is archived' }\n if (taskDepth(tasks, parent.id) + 1 > limit) {\n return { task: undefined, tasks, error: `subtask depth limit (${limit}) exceeded` }\n }\n }\n // A subtask copies the execution targets its parent pins so the card shows\n // what it will run with — EXCEPT the permission. A copied permission would\n // also have to copy the parent's human confirmation to stay runnable, and the\n // child would keep both after being detached: one confirmed parent would mint\n // unbounded confirmed elevated roots. The permission is resolved live from the\n // attached ancestors at launch instead (see core/subtask.ts), so detaching\n // removes the inheritance by construction.\n const effective: NewTaskInput = parent === undefined ? input : {\n ...input,\n workspaceId: input.workspaceId ?? parent.workspaceId,\n mode: input.mode ?? parent.mode,\n model: input.model ?? parent.model,\n }\n let task = createTask(effective, now, id)\n // Arm the requested schedule (new-task dialog): only an enabled rule with\n // a valid cron is applied; blank, invalid, or disabled requests leave the\n // task unscheduled.\n const requested = input.schedule\n if (requested?.enabled === true && requested.cron.trim() !== '' && isValidCron(requested.cron)) {\n const cron = requested.cron.trim()\n task = withSchedule(task, { enabled: true, cron, nextRunAt: nextRunAtMs(cron, now) }, now)\n }\n return { task, tasks: [...tasks, task] }\n}\n","/**\n * Delete-task use case: drop a task from the ledger and clear the selection\n * when it pointed at the removed task. Pure ledger transition (no persistence\n * or notify - the controller orchestrates those).\n *\n * A task that still has subtasks is refused: deleting the parent would leave\n * dangling child links, and silently detaching (or cascading) the children is\n * a data-loss decision the user must make explicitly.\n */\nimport type { TaskRecord } from '../tasks.ts'\n\n/** Result of a delete transition. */\nexport interface DeleteTaskResult {\n /** The next ledger (the removed task absent). */\n tasks: readonly TaskRecord[]\n /** Whether the previous selection referenced the removed task. */\n selectionCleared: boolean\n /** True when the task still carries subtasks, so nothing was removed. */\n blocked: boolean\n}\n\n/**\n * Apply a delete across the ledger. The selection (a task id) is cleared when\n * it matches the removed task, so the UI never lingers on a vanished detail.\n * @param tasks - current ledger.\n * @param selectedTaskId - the currently selected task id (may be undefined).\n * @param id - the task to remove.\n */\nexport function applyDeleteTask(\n tasks: readonly TaskRecord[],\n selectedTaskId: string | undefined,\n id: string,\n): DeleteTaskResult {\n if (tasks.some(task => task.parentId === id)) {\n return { tasks, selectionCleared: false, blocked: true }\n }\n const next = tasks.filter(task => task.id !== id)\n return {\n tasks: next,\n selectionCleared: selectedTaskId === id,\n blocked: false,\n }\n}\n","/**\n * Schedule use case: arm/disarm a task's cron rule and roll a rule forward.\n * Pure ledger transitions (no persistence or notify — the controller\n * orchestrates those). Validation and next-run computation live here, sharing\n * the core cron parser (schedule.ts) and the withSchedule transition.\n */\nimport { isValidCron, nextRunAtMs } from '../schedule.ts'\nimport { withSchedule, type TaskRecord } from '../tasks.ts'\n\n/** Fields the schedule use case may change on a rule. */\nexport interface SetSchedulePatch {\n enabled?: boolean\n cron?: string\n}\n\n/** Result of arming/disarming a rule. */\nexport interface SetScheduleResult {\n /** The next ledger; unchanged reference when rejected. */\n tasks: readonly TaskRecord[]\n /** Whether the rule was applied (false on unknown task / invalid cron). */\n applied: boolean\n}\n\n/**\n * Set an on-board task's schedule rule. A blank or invalid cron, or an\n * archived task, is rejected (state untouched); an enabled rule computes the\n * next run instant immediately, a disabled one carries no next-run instant.\n * @param tasks - current ledger.\n * @param id - the task to schedule.\n * @param patch - rule fields to change (absent fields keep their current value).\n * @param now - clock instant (ms epoch).\n */\nexport function applySetSchedule(\n tasks: readonly TaskRecord[],\n id: string,\n patch: SetSchedulePatch,\n now: number,\n): SetScheduleResult {\n const task = tasks.find(candidate => candidate.id === id)\n if (task === undefined || task.archivedAt !== undefined) return { tasks, applied: false }\n const current = task.schedule\n const cron = (patch.cron ?? current?.cron ?? '').trim()\n if (cron === '' || !isValidCron(cron)) return { tasks, applied: false }\n const enabled = patch.enabled ?? current?.enabled ?? false\n const nextRunAt = enabled ? nextRunAtMs(cron, now) : undefined\n if (enabled && nextRunAt === undefined) return { tasks, applied: false }\n return {\n tasks: tasks.map(candidate =>\n candidate.id === id ? withSchedule(candidate, { enabled, cron, nextRunAt }, now) : candidate),\n applied: true,\n }\n}\n\n/**\n * Roll a task's schedule rule forward (scheduler callback): persist the next\n * due instant and the trigger instant. No-op for tasks without a rule (deleted\n * mid-tick, for example).\n * @param tasks - current ledger.\n * @param id - the task to roll forward.\n * @param nextRunAt - next due instant (may be undefined to clear).\n * @param lastTriggeredAt - the trigger instant of this run.\n * @param now - clock instant (ms epoch).\n */\nexport function applyScheduleNextRun(\n tasks: readonly TaskRecord[],\n id: string,\n nextRunAt: number | undefined,\n lastTriggeredAt: number | undefined,\n now: number,\n): readonly TaskRecord[] {\n return tasks.map(task =>\n task.id === id && task.archivedAt === undefined && task.schedule !== undefined\n ? withSchedule(task, { nextRunAt, lastTriggeredAt }, now)\n : task)\n}\n","/**\n * Parent-link use case: attach an existing on-board task under another as a\n * subtask, or detach it back to the root. The lineage gate is the same one\n * creation uses (unknown or archived parent, self, cycle, depth), so the two\n * ways into the tree cannot disagree. Pure ledger transition.\n */\nimport { DEFAULT_SUBTASK_DEPTH, checkParentLink, normalizeSubtaskDepth, type ParentLinkRejection } from '../subtask.ts'\nimport type { TaskRecord } from '../tasks.ts'\n\n/** Result of a parent-link transition. */\nexport interface SetParentResult {\n /** The next ledger; the input reference when refused. */\n tasks: readonly TaskRecord[]\n /** Whether the link (or the detachment) was stored. */\n applied: boolean\n /** User-facing refusal reason; absent when applied. */\n error?: string\n}\n\n/** Host error text per refusal reason (the wire carries the same strings). */\nconst REJECTION_TEXT: Record<ParentLinkRejection, string> = {\n 'unknown-task': 'task not found',\n 'unknown-parent': 'parent task not found',\n 'archived-parent': 'parent task is archived',\n 'self-parent': 'a task cannot be its own parent',\n 'cycle': 'a task cannot be attached under its own subtask',\n 'depth-exceeded': 'subtask depth limit exceeded',\n}\n\n/**\n * Attach or detach one task. A null (or blank) parent detaches, which is always\n * allowed for a known on-board task; attaching validates the whole chain so a\n * cyclic or too-deep ledger can never be stored.\n * @param tasks - current ledger.\n * @param id - the task being moved.\n * @param parentId - the new parent, or null to detach.\n * @param now - clock instant (ms epoch).\n * @param maxSubtaskDepth - deployment subtask depth limit.\n */\nexport function applySetParent(\n tasks: readonly TaskRecord[],\n id: string,\n parentId: string | null,\n now: number,\n maxSubtaskDepth: number = DEFAULT_SUBTASK_DEPTH,\n): SetParentResult {\n const task = tasks.find(candidate => candidate.id === id)\n if (task === undefined) return { tasks, applied: false, error: REJECTION_TEXT['unknown-task'] }\n if (task.archivedAt !== undefined) return { tasks, applied: false, error: 'archived task is read-only' }\n // A task with an open execution may be a participant of a running cascade.\n // Moving it would break that group's parent walk and leave the parent card\n // in the running column forever, so the link is frozen until it settles.\n if (task.status === 'running' || task.executions.some(execution => execution.endedAt === undefined)) {\n return { tasks, applied: false, error: 'running task cannot be re-parented' }\n }\n const check = checkParentLink(tasks, id, parentId, normalizeSubtaskDepth(maxSubtaskDepth))\n if (!check.ok) return { tasks, applied: false, error: REJECTION_TEXT[check.reason ?? 'unknown-task'] }\n const nextParentId = parentId === null || parentId === '' ? undefined : parentId\n if (nextParentId === task.parentId) return { tasks: [...tasks], applied: true }\n return {\n tasks: tasks.map(candidate => candidate.id === id ? { ...candidate, parentId: nextParentId, updatedAt: now } : candidate),\n applied: true,\n }\n}\n","/**\n * Update-task use case: apply an editable-field patch (title/description/\n * prompt plus the execution targets workspaceId/mode/permission) with a\n * fresh updatedAt. Pure ledger transition (no persistence or notify — the\n * controller orchestrates those).\n *\n * An explicit `undefined` in the patch clears the field (the task falls\n * back to the runtime default); an unknown permission string is ignored so\n * stale UI can never persist a value the execution service rejects.\n */\nimport { freezeOf, isTaskPermission, normalizeTags, normalizeTargetId, type TaskRecord, type TaskPermission, type TaskTag } from '../tasks.ts'\nimport type { FreezeSnapshot } from '../freeze-snapshot.ts'\nimport type { TaskHandoverInput } from '../handover.ts'\n\n/**\n * Editable fields on a task (the update patch surface). `freeze` replaces the\n * continuation-card snapshot (restamping frozenAt); an explicit null clears it.\n */\nexport type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession' | 'teamRun'>> & {\n freeze?: FreezeSnapshot & { redacted?: boolean } | null\n /** Replaces the handover bundle (restamping bundledAt); an explicit null clears it. */\n handover?: TaskHandoverInput | null\n /**\n * Replaces the task's labels (issue #1521). Unlike the content fields, tags\n * stay editable after the first run: they classify the task and shape the\n * NEXT execution prompt, they are not the record of what already ran. An\n * explicit null (or a list that normalizes to nothing) clears them.\n */\n tags?: TaskTag[] | null\n}\n\n/** The fields that edit the task's content (what the user reads and what the\n * next execution sends). Unlike the execution targets they stay editable only\n * while the task has never started executing — after the first run the\n * recorded prompt is the record of what actually ran, so it becomes read-only.\n */\nexport const TASK_CONTENT_FIELDS = ['title', 'description', 'prompt'] as const\n\n/** Whether an update patch touches any task-content field. */\nexport function hasContentPatch(patch: TaskUpdatePatch): boolean {\n return (TASK_CONTENT_FIELDS as readonly string[]).some(field => field in patch)\n}\n\n/**\n * Whether a task's content may still be edited: the task must be on-board\n * (not archived) and must never have started executing. Fail-closed: a\n * running, settled, or cancelled-before-launch task keeps its content fixed.\n */\nexport function canEditTaskContent(task: TaskRecord): boolean {\n return task.archivedAt === undefined && task.status !== 'running' && task.executions.length === 0\n}\n\n/** Keep an unknown permission string from entering the ledger. */\nfunction normalizePermission(\n current: TaskPermission | undefined,\n value: TaskPermission | undefined,\n): TaskPermission | undefined {\n if (value === undefined) return undefined\n return isTaskPermission(value) ? value : current\n}\n\n/**\n * Apply an update across the ledger. Tasks that do not match the id are left\n * untouched; the matched task receives the patch plus a fresh updatedAt.\n * @param tasks - current ledger.\n * @param id - the task to update.\n * @param patch - editable-field changes.\n * @param now - clock instant (ms epoch).\n */\nexport function applyUpdateTask(\n tasks: readonly TaskRecord[],\n id: string,\n patch: TaskUpdatePatch,\n now: number,\n): readonly TaskRecord[] {\n return tasks.map(task => {\n if (task.id !== id) return task\n const { freeze: freezePatch, handover: handoverPatch, tags: tagsPatch, ...rest } = patch\n const workspaceId = 'workspaceId' in patch ? normalizeTargetId(patch.workspaceId) : undefined\n const mode = 'mode' in patch ? normalizeTargetId(patch.mode) : undefined\n const permission = 'permission' in patch ? normalizePermission(task.permission, patch.permission) : undefined\n const model = 'model' in patch ? normalizeTargetId(patch.model) : undefined\n const next: TaskRecord = { ...task, ...rest, updatedAt: now }\n // Content fields normalize like creation does (trimmed); an explicit\n // undefined keeps the current value — content cannot be cleared.\n for (const field of TASK_CONTENT_FIELDS) {\n if (!(field in patch)) continue\n const value = patch[field]\n next[field] = value === undefined ? task[field] : value.trim()\n }\n // null (or a vanished key value) clears the snapshot; a present object\n // replaces it with a fresh frozenAt stamp.\n next.freeze = freezePatch == null ? undefined : freezeOf(freezePatch, now)\n // Handover follows the same null-clears convention, restamping bundledAt.\n next.handover = handoverPatch == null ? undefined : { ...handoverPatch, bundledAt: now }\n // Tags use the same convention: a present array replaces the set (after\n // repair), an explicit null or a fully-invalid list clears it.\n if ('tags' in patch) next.tags = tagsPatch == null ? undefined : normalizeTags(tagsPatch)\n // The permission confirmation binds the exact permission value: a change\n // of the pinned permission or of the handover bundle re-arms the gate\n // (blocking confirm-then-swap escalation). handover was destructured out\n // of rest above, so the stamp survives only when explicitly kept.\n if (('permission' in patch && patch.permission !== undefined && patch.permission !== task.permission) || 'handover' in patch) {\n next.permissionConfirmedAt = undefined\n }\n // Session reuse is a boolean opt-in; false (or an explicit null from a\n // caller that needs to clear it) returns the task to one session per run.\n if ('reuseSession' in patch) next.reuseSession = patch.reuseSession === true ? true : undefined\n // Team execution is a boolean opt-in with the same clear-by-false rule.\n if ('teamRun' in patch) next.teamRun = patch.teamRun === true ? true : undefined\n if (workspaceId !== undefined || 'workspaceId' in patch) next.workspaceId = workspaceId\n if (mode !== undefined || 'mode' in patch) next.mode = mode\n if (permission !== undefined || 'permission' in patch) next.permission = permission\n if (model !== undefined || 'model' in patch) next.model = model\n return next\n })\n}\n","/**\n * Board controller: the single owner of task-ledger state and view state.\n *\n * In production it projects the Host ledger and submits confirmed actions;\n * the legacy store seam remains for v1 migration tests. The board closes\n * only on explicit user navigation, never implicitly on session-list churn.\n * Framework-free (structural runtime faces) so the whole orchestration is\n * unit-testable with fakes.\n *\n * The per use-case domain transitions (create/update/delete/schedule) live in\n * dedicated modules under core/use-cases and are applied here; the controller\n * owns only the orchestration seam (state, persistence, notify, navigation).\n */\nimport type { TaskStore } from './store.ts'\nimport { withStatus, type NewTaskInput, type TaskRecord, type TaskStatus } from './tasks.ts'\nimport { applyArchiveTask, applyRestoreTask } from './use-cases/task-archive.ts'\nimport { applyCreateTask } from './use-cases/task-create.ts'\nimport { applyDeleteTask } from './use-cases/task-delete.ts'\nimport { applyScheduleNextRun as applyScheduleRollForward, applySetSchedule } from './use-cases/task-schedule.ts'\nimport { applySetParent } from './use-cases/task-parent.ts'\nimport { applyUpdateTask, type TaskUpdatePatch } from './use-cases/task-update.ts'\nimport { DEFAULT_SUBTASK_DEPTH } from './subtask.ts'\nimport type {\n TaskBoardAction,\n TaskBoardEventPayload,\n TaskBoardParseDraft,\n TaskBoardParseRequest,\n TaskBoardSnapshot,\n} from '../protocol.ts'\n\nexport interface TaskBoardTransport {\n bootstrap(legacy: readonly TaskRecord[]): Promise<TaskBoardSnapshot>\n state(): Promise<TaskBoardSnapshot>\n /**\n * Submit one action; the optional initiator is the current DSH session id\n * (issue #6 audit origin), asserted by the client and recorded by the Host.\n */\n action(action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot>\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void\n /**\n * One-shot model parse of pasted text (issue #1540). Optional: a deployment\n * that cannot parse simply omits it, and the form hides the section.\n */\n parseDraft?(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft>\n}\n\n/**\n * The sessions face the controller needs for navigation awareness. The Client\n * Session Controller carries no global selection since 0.1.6-alpha.2, so the\n * wiring resolves the main-view Session once and exposes it as current().\n */\nexport interface SessionsControllerFace {\n /** The Session the main view currently shows, when any. */\n current(): string | undefined\n /** Navigate the main view to a Session. */\n open(id: string): void\n /** Subscribe to catalog changes; selection ownership rides the same snapshot. */\n subscribe(fn: () => void): () => void\n}\n\nfunction currentOf(sessions: SessionsControllerFace | undefined): string | undefined {\n return sessions?.current()\n}\n\n/** Controller dependencies (all swappable in tests). */\nexport interface ControllerDeps {\n store: TaskStore\n sessions: SessionsControllerFace\n /** Clock; defaults to Date.now. */\n now?: () => number\n /** Id minting; defaults to a random-uuid. */\n uuid?: () => string\n /** Host-authoritative transport; absent keeps the legacy in-memory test path. */\n transport?: TaskBoardTransport\n}\n\n/**\n * Register one host directory as a DSH project (workspace). Wired by the\n * browser apply() to the runtime's workspace controller; without it the board\n * hides its \"new project\" action instead of offering a dead control (#1536).\n */\nexport type WorkspaceCreator = (path: string) => Promise<{ workspaceId: string }>\n\n/** One workspace option the execution-target pickers offer. */\nexport interface ExecutionWorkspaceOption {\n workspaceId: string\n /** Display label (workspace title; the wiring falls back to the path). */\n title: string\n}\n\n/** One agent-preset option the execution-target pickers offer. */\nexport interface ExecutionPresetOption {\n id: string\n name?: string\n description?: string\n /** Why this preset cannot compose a session; the pickers disable it. */\n broken?: string\n isDefault: boolean\n}\n\n/** One model option the execution-target pickers offer. */\nexport interface ExecutionModelOption {\n id: string\n name?: string\n label?: string\n provider?: string\n}\n\n/** The execution-target option sets the UI feeds into the controller. */\nexport interface ExecutionOptionsSnapshot {\n workspaces: readonly ExecutionWorkspaceOption[]\n presets: readonly ExecutionPresetOption[]\n models?: readonly ExecutionModelOption[]\n}\n\n/**\n * Host-owned state the browser mirrors. SSE frames carry the volatile subset\n * (revision/scheduler/power); a full snapshot also carries the deployment\n * constants the UI reads (session default permission, subtask depth).\n */\nexport type HostMirror = Pick<TaskBoardSnapshot, 'revision' | 'scheduler' | 'power' | 'sessionDefaultPermission' | 'maxSubtaskDepth' | 'teamRunAvailable'>\n\n/** Immutable controller snapshot for UI subscriptions. */\nexport interface ControllerSnapshot {\n tasks: readonly TaskRecord[]\n boardOpen: boolean\n /** True when the board shows the archive view instead of the columns. */\n archiveView: boolean\n selectedTaskId: string | undefined\n /** Picker option sets (workspace list + agent-preset roster). */\n executionOptions: ExecutionOptionsSnapshot\n pendingTaskIds: readonly string[]\n /** Whether the board may offer \"register a new project\" (issue #1536). */\n canCreateWorkspace?: boolean\n /** Whether this deployment can parse pasted text into task fields (issue #1540). */\n canParseTask?: boolean\n transportError?: string\n host?: HostMirror\n}\n\n/** The selected task (resolved from the ledger), or undefined. */\nexport function selectedTaskOf(snapshot: ControllerSnapshot): TaskRecord | undefined {\n if (snapshot.selectedTaskId === undefined) return undefined\n return snapshot.tasks.find(task => task.id === snapshot.selectedTaskId)\n}\n\nfunction randomUuid(): string {\n const randomUUID = globalThis.crypto?.randomUUID\n if (randomUUID !== undefined) {\n return randomUUID.call(globalThis.crypto!)\n }\n const bytes = globalThis.crypto?.getRandomValues(new Uint8Array(16))\n if (bytes === undefined) {\n // Non-secure fallback (tests, odd environments).\n return `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`\n }\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/**\n * Board controller (see module doc). All mutations bump the snapshot and\n * persist through the store; UI and DOM mounts subscribe and re-render.\n */\nexport class BoardController {\n private tasks: TaskRecord[] = []\n private boardOpen = false\n private archiveView = false\n private selectedTaskId: string | undefined\n private executionOptions: ExecutionOptionsSnapshot = { workspaces: [], presets: [], models: [] }\n private workspaceCreator: WorkspaceCreator | undefined\n private listeners = new Set<() => void>()\n private disposers: Array<() => void> = []\n private readonly now: () => number\n private readonly uuid: () => string\n private readonly pendingTaskIds = new Set<string>()\n private readonly taskQueues = new Map<string, Promise<void>>()\n private transportError: string | undefined\n private hostState: HostMirror | undefined\n private remoteSubscribed = false\n private remoteInitialization: Promise<boolean> | undefined\n\n /** @param deps - store and the sessions navigation face. */\n constructor(private readonly deps: ControllerDeps) {\n this.now = deps.now ?? (() => Date.now())\n this.uuid = deps.uuid ?? randomUuid\n }\n\n // --- lifecycle -------------------------------------------------------------\n\n /** Load the persisted ledger and start the navigation/status subscriptions. */\n start(): void {\n this.tasks = this.deps.store.load()\n if (this.deps.transport !== undefined) void this.initializeRemote()\n // A sibling tab may have edited or deleted the ledger (same origin,\n // storage events). Reload on external change so a task deleted in\n // another tab stops firing here — and is never written back by this\n // tab's stale copy (scheduler roll-forward, execution settlement).\n const unsubscribeExternal = this.deps.transport === undefined ? this.deps.store.subscribeExternal?.(() => {\n this.tasks = this.deps.store.load()\n this.notify()\n }) : undefined\n if (unsubscribeExternal !== undefined) this.disposers.push(unsubscribeExternal)\n this.disposers.push(this.deps.sessions.subscribe(() => {\n this.onSessionsChanged()\n }))\n this.notify()\n }\n\n /** Stop all subscriptions and drop retained state (idempotent). */\n dispose(): void {\n for (const dispose of this.disposers.splice(0)) dispose()\n this.listeners.clear()\n }\n\n // --- snapshot / subscription ------------------------------------------------\n\n getSnapshot(): ControllerSnapshot {\n return {\n tasks: this.tasks,\n boardOpen: this.boardOpen,\n archiveView: this.archiveView,\n selectedTaskId: this.selectedTaskId,\n executionOptions: this.executionOptions,\n pendingTaskIds: [...this.pendingTaskIds],\n ...(this.workspaceCreator === undefined ? {} : { canCreateWorkspace: true }),\n ...(typeof this.deps.transport?.parseDraft === 'function' ? { canParseTask: true } : {}),\n ...(this.transportError === undefined ? {} : { transportError: this.transportError }),\n ...(this.hostState === undefined ? {} : { host: this.hostState }),\n }\n }\n\n subscribe(fn: () => void): () => void {\n this.listeners.add(fn)\n return () => { this.listeners.delete(fn) }\n }\n\n /** Whether production mutations are confirmed by the Host transport. */\n isHostBacked(): boolean {\n return this.deps.transport !== undefined\n }\n\n /** Retry initial migration/state synchronization after an explicit Host error. */\n async retryHostSync(): Promise<boolean> {\n return await this.initializeRemote()\n }\n\n // --- view state -------------------------------------------------------------\n\n openBoard(): void {\n if (this.boardOpen) return\n this.boardOpen = true\n this.notify()\n }\n\n closeBoard(): void {\n this.boardOpen = false\n this.notify()\n }\n\n toggleBoard(): void {\n if (this.boardOpen) this.closeBoard()\n else this.openBoard()\n }\n\n /**\n * Switch between the kanban columns and the archive view. Leaving the\n * archive view with an archived task still selected closes the selection —\n * the detail overlay must not linger over a task that is off-board.\n */\n toggleArchiveView(): void {\n this.archiveView = !this.archiveView\n if (!this.archiveView && this.selectedTaskId !== undefined) {\n const selected = this.tasks.find(task => task.id === this.selectedTaskId)\n if (selected?.archivedAt !== undefined) this.selectedTaskId = undefined\n }\n this.notify()\n }\n\n openTask(id: string): void {\n if (this.tasks.some(task => task.id === id)) {\n this.selectedTaskId = id\n this.notify()\n }\n }\n\n closeTask(): void {\n if (this.selectedTaskId === undefined) return\n this.selectedTaskId = undefined\n this.notify()\n }\n\n // --- task mutations (use-case transitions in core/use-cases) -----------------\n\n createTask(input: NewTaskInput): TaskRecord | undefined {\n const id = this.uuid()\n const { task, tasks } = applyCreateTask(this.tasks, input, this.now(), id, this.mirrorDepth())\n if (task === undefined) return undefined\n this.tasks = [...tasks]\n this.persistAndNotify()\n return task\n }\n\n /** Create through the Host and expose the task only after confirmation. */\n async createTaskConfirmed(input: NewTaskInput): Promise<TaskRecord | undefined> {\n if (this.deps.transport === undefined) return this.createTask(input)\n const id = this.uuid()\n // The preview must obey the SAME lineage gate the Host will: a browser-side\n // default of one level would reject a legal subtask-of-subtask before the\n // request is ever sent.\n const preview = applyCreateTask(this.tasks, input, this.now(), id, this.mirrorDepth()).task\n if (preview === undefined) return undefined\n return await this.commitRemote({ kind: 'create', id, input }, id)\n ? this.tasks.find(task => task.id === id)\n : undefined\n }\n\n /**\n * Apply an editable-field patch (task content + execution targets).\n * Host-backed: the Host ledger owns the fail-closed checks (the content of\n * an executed task is read-only) and confirms the mutation, so the resolved\n * value reflects whether the Host accepted it; the legacy in-memory path\n * applies and persists synchronously.\n * @returns true when the patch was accepted by the authority.\n */\n async updateTask(id: string, patch: TaskUpdatePatch): Promise<boolean> {\n if (this.deps.transport !== undefined) {\n return await this.commitRemote({ kind: 'update', taskId: id, patch }, id)\n }\n this.tasks = [...applyUpdateTask(this.tasks, id, patch, this.now())]\n this.persistAndNotify()\n return true\n }\n\n /**\n * Replace (a part of) the picker option sets the UI feeds (workspace list\n * and agent-preset roster come from the runtime, not the ledger).\n */\n setExecutionOptions(patch: Partial<ExecutionOptionsSnapshot>): void {\n this.executionOptions = { ...this.executionOptions, ...patch }\n this.notify()\n }\n\n /** Wire (or clear) the runtime's project registration face (issue #1536). */\n setWorkspaceCreator(creator: WorkspaceCreator | undefined): void {\n this.workspaceCreator = creator\n this.notify()\n }\n\n /**\n * Register an existing host directory as a DSH project, exactly as the GUI's\n * own \"add project\" does; the runtime's failure message surfaces unchanged.\n */\n async createWorkspace(path: string): Promise<{ workspaceId: string }> {\n if (this.workspaceCreator === undefined) throw new Error('workspace creation is unavailable')\n return await this.workspaceCreator(path)\n }\n\n /** Whether this deployment can parse pasted text into task fields (issue #1540). */\n canParseTask(): boolean {\n return typeof this.deps.transport?.parseDraft === 'function'\n }\n\n /**\n * Parse pasted text into task fields through the Host. The transport already\n * phrases every failure for the user, so its message surfaces unchanged.\n */\n async parseTaskDraft(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft> {\n const transport = this.deps.transport\n const parse = transport?.parseDraft\n if (transport === undefined || parse === undefined) throw new Error('task parsing is unavailable')\n return await parse.call(transport, request, signal)\n }\n\n moveTask(id: string, status: TaskStatus): void {\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'move', taskId: id, status }, id)\n return\n }\n this.tasks = this.tasks.map(task => task.id === id ? withStatus(task, status, this.now()) : task)\n this.persistAndNotify()\n }\n\n deleteTask(id: string): void {\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'delete', taskId: id }, id)\n return\n }\n const { tasks, selectionCleared } = applyDeleteTask(this.tasks, this.selectedTaskId, id)\n this.tasks = [...tasks]\n if (selectionCleared) this.selectedTaskId = undefined\n this.persistAndNotify()\n }\n\n /**\n * Archive a task from any status but `running`, whose lifecycle the runner\n * keeps exclusive ownership of until it settles.\n * @returns true when applied.\n */\n archiveTask(id: string): boolean {\n const { tasks, archived } = applyArchiveTask(this.tasks, id, this.now(), this.mirrorDepth())\n if (!archived) return false\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'archive', taskId: id }, id)\n return true\n }\n this.tasks = [...tasks]\n this.persistAndNotify()\n return true\n }\n\n /**\n * Attach an existing task under a parent (or detach it with a null parent)\n * through the Host. The lineage gate — parent exists and is on-board, no\n * cycle, depth within the deployment limit — belongs to the Host; a refusal\n * surfaces through the transport error like every other rejected action.\n * @returns true when the link was accepted by the authority.\n */\n async setParent(id: string, parentId: string | null): Promise<boolean> {\n if (this.deps.transport === undefined) {\n const result = applySetParent(this.tasks, id, parentId, this.now(), this.mirrorDepth())\n if (!result.applied) return false\n this.tasks = [...result.tasks]\n this.persistAndNotify()\n return true\n }\n return await this.commitRemote({ kind: 'set-parent', taskId: id, parentId }, id)\n }\n\n /** Restore an archived task back onto the board (same status column). */\n restoreTask(id: string): boolean {\n const { tasks, archived } = applyRestoreTask(this.tasks, id, this.now(), this.mirrorDepth())\n if (!archived) return false\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'restore', taskId: id }, id).then(restored => {\n if (restored && this.selectedTaskId === id) this.closeTask()\n })\n return true\n }\n this.tasks = [...tasks]\n if (this.selectedTaskId === id) this.selectedTaskId = undefined\n this.persistAndNotify()\n return true\n }\n\n // --- scheduling ---------------------------------------------------------------\n\n /**\n * Update a task's schedule rule. A blank or invalid cron expression is\n * rejected (returns false, state untouched). When the rule ends up enabled\n * the next run instant is computed immediately; a disabled rule carries no\n * next-run instant. Delegates the domain transition to the schedule use case.\n * @param id - the task to schedule.\n * @param patch - fields to change (absent fields keep their current value).\n * @returns true when applied, false when rejected (invalid cron / unknown task).\n */\n setSchedule(id: string, patch: { enabled?: boolean; cron?: string }): boolean {\n const { tasks, applied } = applySetSchedule(this.tasks, id, patch, this.now())\n if (!applied) return false\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'set-schedule', taskId: id, patch }, id)\n return true\n }\n this.tasks = [...tasks]\n this.persistAndNotify()\n return true\n }\n\n /**\n * Legacy pure-controller seam retained for migration-focused tests. The\n * production browser never rolls schedules; the Host ledger owns them.\n */\n applyScheduleNextRun(id: string, nextRunAt: number | undefined, lastTriggeredAt: number | undefined): void {\n const next = applyScheduleRollForward(this.tasks, id, nextRunAt, lastTriggeredAt, this.now())\n this.tasks = [...next]\n this.persistAndNotify()\n }\n\n /**\n * Reload the legacy v1 store without notifying subscribers. Production v2\n * reads Host snapshots instead; this remains only for isolated legacy tests.\n */\n reloadFromStore(): void {\n this.tasks = this.deps.store.load()\n }\n\n /**\n * Jump to an execution's session transcript. Selecting the session changes\n * `current`, which closes the board (the conversation view takes over).\n * @param sessionId - the execution session to open.\n */\n openSession(sessionId: string): void {\n this.closeBoard()\n this.deps.sessions.open(sessionId)\n }\n\n // --- execution ---------------------------------------------------------------\n\n /**\n * Request a Host execution for a task: the Host ledger owns the running\n * transition, the execution record, and the settlement. A second call\n * while the task is already running is ignored; without a Host transport\n * the run is refused (returns false).\n */\n async runTask(id: string): Promise<boolean> {\n const task = this.tasks.find(candidate => candidate.id === id)\n if (task === undefined || task.archivedAt !== undefined || task.status === 'running') return false\n if (this.deps.transport === undefined) return false\n return await this.commitRemote({ kind: 'run', taskId: id }, id, currentOf(this.deps.sessions))\n }\n\n /**\n * Confirm a card's above-default permission binding through the Host\n * (resolves the pending-confirmation transaction; no-op otherwise).\n */\n async confirmPermission(id: string): Promise<boolean> {\n const task = this.tasks.find(candidate => candidate.id === id)\n if (task === undefined) return false\n if (this.deps.transport === undefined) {\n this.tasks = this.tasks.map(candidate => candidate.id === id\n ? { ...candidate, permissionConfirmedAt: this.now(), updatedAt: this.now() }\n : candidate)\n this.persistAndNotify()\n return true\n }\n return await this.commitRemote({ kind: 'confirm-permission', taskId: id }, id)\n }\n\n /** Re-run a settled task through the Host (the Host replans and executes). */\n async rerunTask(id: string): Promise<void> {\n const task = this.tasks.find(candidate => candidate.id === id)\n if (task === undefined || task.archivedAt !== undefined) return\n if (this.deps.transport === undefined) return\n await this.commitRemote({ kind: 'rerun', taskId: id }, id, currentOf(this.deps.sessions))\n }\n\n // --- internals ---------------------------------------------------------------\n\n /**\n * Session-list notifications fire for all kinds of incidental churn\n * (background navigation, the Host runner creating and selecting a fresh\n * execution session, settlement, other plugins), so closing on `current`\n * changes would evict the board without the user asking. The board closes\n * only on explicit user navigation: a sidebar session/workspace row click\n * (board-mount onClickSidebarRow) or the board's own actions\n * (openSession / close). Keeping the hook preserves the subscription\n * contract for future listeners.\n */\n private onSessionsChanged(): void {\n // Intentionally empty: never close the board implicitly.\n }\n\n private persistAndNotify(): void {\n if (this.deps.transport === undefined) this.deps.store.save(this.tasks)\n this.notify()\n }\n\n private async commitRemote(action: TaskBoardAction, taskId?: string, initiator?: string): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n if (taskId === undefined) return await this.performRemote(action, initiator)\n const previous = this.taskQueues.get(taskId) ?? Promise.resolve()\n const operation = previous.catch(() => {}).then(async () => await this.performRemote(action, initiator))\n const tail = operation.then(() => {}, () => {})\n this.taskQueues.set(taskId, tail)\n this.pendingTaskIds.add(taskId)\n this.notify()\n try {\n return await operation\n } finally {\n if (this.taskQueues.get(taskId) === tail) {\n this.taskQueues.delete(taskId)\n this.pendingTaskIds.delete(taskId)\n this.notify()\n }\n }\n }\n\n private async performRemote(action: TaskBoardAction, initiator?: string): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n this.transportError = undefined\n this.notify()\n try {\n const accepted = this.acceptRemote(await transport.action(action, initiator))\n return accepted || await this.refreshRemote()\n } catch (error) {\n await this.refreshRemote(messageOf(error))\n return false\n }\n }\n\n private async initializeRemote(): Promise<boolean> {\n if (this.remoteInitialization !== undefined) return await this.remoteInitialization\n const initialization = this.doInitializeRemote()\n this.remoteInitialization = initialization\n try {\n return await initialization\n } finally {\n if (this.remoteInitialization === initialization) this.remoteInitialization = undefined\n }\n }\n\n private async doInitializeRemote(): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n try {\n this.acceptRemote(await transport.bootstrap(this.tasks))\n if (!this.remoteSubscribed) {\n this.remoteSubscribed = true\n this.disposers.push(transport.subscribe((event) => { this.onRemoteEvent(event) }))\n }\n return true\n } catch (error) {\n this.transportError = messageOf(error)\n this.notify()\n return false\n }\n }\n\n /**\n * SSE frames carry revision/scheduler/power. When the revision matches the\n * one already applied, apply the frame's scheduler/power in place and skip\n * the full /state fetch; otherwise the 5 s heartbeat would re-clone and\n * re-serialize the whole ledger per tab even while nothing changes.\n */\n private onRemoteEvent(event: TaskBoardEventPayload | undefined): void {\n if (event !== undefined && this.hostState !== undefined && event.revision === this.hostState.revision\n && typeof event.scheduler === 'object' && event.scheduler !== null\n && typeof event.power === 'object' && event.power !== null) {\n this.hostState = { ...this.hostState, revision: event.revision, scheduler: event.scheduler, power: event.power }\n this.notify()\n return\n }\n void this.refreshRemote()\n }\n\n /**\n * Deployment subtask depth limit the browser mirrors from the last Host\n * snapshot; the fallback is the deployment default for the legacy path (no\n * transport) and for the window before the first snapshot arrives.\n */\n private mirrorDepth(): number {\n return this.hostState?.maxSubtaskDepth ?? DEFAULT_SUBTASK_DEPTH\n }\n\n /**\n * Project a Host snapshot onto the browser's mirror. SSE frames and partial\n * snapshots carry only the volatile subset (revision/scheduler/power), so the\n * deployment constants the UI reads — the session-default permission the\n * confirmation banner compares against and the subtask depth limit — are\n * carried over from the last full snapshot instead of being dropped by a\n * heartbeat frame.\n */\n private mirrorOf(snapshot: TaskBoardSnapshot): HostMirror {\n const sessionDefaultPermission = snapshot.sessionDefaultPermission ?? this.hostState?.sessionDefaultPermission\n const maxSubtaskDepth = snapshot.maxSubtaskDepth ?? this.hostState?.maxSubtaskDepth\n const teamRunAvailable = snapshot.teamRunAvailable ?? this.hostState?.teamRunAvailable\n return {\n revision: snapshot.revision,\n scheduler: snapshot.scheduler,\n power: snapshot.power,\n ...(sessionDefaultPermission === undefined ? {} : { sessionDefaultPermission }),\n ...(maxSubtaskDepth === undefined ? {} : { maxSubtaskDepth }),\n ...(teamRunAvailable === undefined ? {} : { teamRunAvailable }),\n }\n }\n\n private async refreshRemote(preserveError?: string): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n try {\n this.acceptRemote(await transport.state())\n if (preserveError !== undefined) {\n this.transportError = preserveError\n this.notify()\n }\n return true\n } catch (error) {\n this.transportError = preserveError ?? messageOf(error)\n this.notify()\n return false\n }\n }\n\n private acceptRemote(snapshot: TaskBoardSnapshot): boolean {\n const currentLedgerId = this.hostState?.scheduler.ledgerId\n const nextLedgerId = snapshot.scheduler.ledgerId\n const sameGeneration = currentLedgerId === nextLedgerId\n if (sameGeneration && this.hostState !== undefined && snapshot.revision < this.hostState.revision) return false\n this.tasks = [...snapshot.tasks]\n this.hostState = this.mirrorOf(snapshot)\n this.transportError = undefined\n if (this.selectedTaskId !== undefined && !this.tasks.some(task => task.id === this.selectedTaskId)) {\n this.selectedTaskId = undefined\n }\n if (!this.archiveView && this.selectedTaskId !== undefined\n && this.tasks.find(task => task.id === this.selectedTaskId)?.archivedAt !== undefined) {\n this.selectedTaskId = undefined\n }\n this.notify()\n return true\n }\n\n private notify(): void {\n for (const fn of [...this.listeners]) fn()\n }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/main-session.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Main-view Session derivation for the multi-instance Client Session model.\n *\n * The Client Session Controller carries no global \"current\" selection: view\n * selection belongs to the workspace UI, which owns the main-area reference and\n * publishes it through the catalog's per-source ownership counts\n * (`SessionSummary.retainedBy.mainView`). A plugin that needs the Session the\n * main view shows derives it from that marker instead of the removed\n * `SessionListState.current` field.\n *\n * The marker describes view ownership, not authority. It is the right input for\n * presentation and for deciding which view a navigation targets; it is not a\n * business fallback, because source counts never imply visibility or success.\n * @module dsh-web/shared/main-session\n */\n\n/** The catalog row subset this helper reads (a `SessionSummary` projection). */\nexport interface MainViewOwnedRow<Id extends string = string> {\n /** Catalog row identity. */\n readonly id: Id\n /** Per-source local ownership counts; absent rows are never owned. */\n readonly retainedBy?: Readonly<Partial<Record<string, number>>> | undefined\n}\n\n/**\n * Resolve the Session the main view currently shows.\n *\n * Reads the catalog's rows rather than a per-id retain-info source: ownership\n * counts ride the list snapshot, so this neither allocates observers nor opens\n * history, and a subscription to the list still fires when the selection moves.\n * @param byId - the session catalog's rows (`SessionListState.byId`), when available.\n * @returns the main-view session id, or undefined when the main view shows none.\n */\nexport function mainViewSessionId<Id extends string>(\n byId: Readonly<Record<Id, MainViewOwnedRow<Id> | undefined>> | undefined | null,\n): Id | undefined {\n if (byId === undefined || byId === null) return undefined\n for (const row of Object.values<MainViewOwnedRow<Id> | undefined>(byId)) {\n if (row !== undefined && (row.retainedBy?.mainView ?? 0) > 0) return row.id\n }\n return undefined\n}\n","/**\n * Freeze-request parser and security gate: parses the system-prompt-agreed\n * freeze format into a structured context snapshot (goal / progress / next),\n * redacts sensitive patterns to markers, rejects slash-prefixed DSH command\n * lines, and enforces the 8 KiB per-field byte limit.\n * Pure functions only: no session, network, or filesystem access.\n */\n\n/** Hard per-field limit: 8 KiB measured in UTF-8 bytes. */\nexport const FREEZE_FIELD_BYTE_LIMIT = 8 * 1024\n\n/** Marker replacing every sensitive match. */\nexport const REDACTED_MARKER = '[REDACTED]'\n\n/** Structured context snapshot carried by a continuation card. */\nexport interface FreezeSnapshot {\n goal: string\n progress: string\n next: string\n}\n\n/** Non-fatal notices produced by the security gate. */\nexport type FreezeWarning = 'redacted'\n\nexport type FreezeResult =\n | { ok: true; snapshot: FreezeSnapshot; warnings: FreezeWarning[] }\n | { ok: false; error: { code: string; message: string } }\n\nconst BEGIN = '<<<FREEZE'\nconst END = '>>>FREEZE'\n\nconst SECTION_KEYS: ReadonlyMap<string, SectionKey> = new Map([\n ['目标:', 'goal'],\n ['进度:', 'progress'],\n ['下一步:', 'next'],\n])\n\ntype SectionKey = 'goal' | 'progress' | 'next'\n\nconst SECTION_ORDER: readonly SectionKey[] = ['goal', 'progress', 'next']\n\nconst SECTION_NAMES: Record<SectionKey, string> = {\n goal: '目标',\n progress: '进度',\n next: '下一步',\n}\n\n/**\n * Sensitive patterns, each matched globally over every field body:\n * PEM private key blocks (whole block collapses to one marker), Bearer\n * credentials, OpenAI sk-, GitHub ghp_, GitLab glpat-, Slack xox* tokens,\n * and AWS access key ids.\n */\nconst SENSITIVE_PATTERNS: RegExp[] = [\n /-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,\n /Bearer\\s+[A-Za-z0-9._~+\\/=:-]{8,}/gi,\n /sk-[A-Za-z0-9_-]{8,}/g,\n /ghp_[A-Za-z0-9]{20,}/g,\n /glpat-[A-Za-z0-9_-]{15,}/g,\n /xox[bpars]-[A-Za-z0-9-]{10,}/g,\n /AKIA[0-9A-Z]{16}/g,\n]\n\nfunction fail(code: string, message: string): FreezeResult {\n return { ok: false, error: { code, message } }\n}\n\nfunction utf8Bytes(text: string): number {\n return new TextEncoder().encode(text).length\n}\n\n/** Redact sensitive patterns to the marker; reports whether any hit occurred. */\nexport function redactSensitive(text: string): { text: string; redacted: boolean } {\n let out = text\n let redacted = false\n for (const pattern of SENSITIVE_PATTERNS) {\n if (pattern.test(out)) {\n redacted = true\n out = out.replace(pattern, REDACTED_MARKER)\n }\n pattern.lastIndex = 0\n }\n return { text: out, redacted }\n}\n\n/**\n * True when any line of the text starts with \"/\" (a DSH command line).\n * Leading horizontal whitespace before the slash counts too: a frozen\n * body line like ` /kill` is still a command, not prose.\n */\nexport function hasSlashCommandLines(text: string): boolean {\n return text.split(/\\r?\\n/).some(line => /^[ \\t]+\\//.test(line) || line.startsWith('/'))\n}\n\n/**\n * Sanitize a structured freeze snapshot (the create/update action payload):\n * shape check, slash-command taint rejection, sensitive redaction, and the\n * per-field byte cap - the same gate parseFreezeRequest applies to\n * free-text freeze requests, exposed for the action data plane (issue #4).\n * @param value - the freeze object carried by an action or read back from disk.\n * @param extraKeys - keys allowed alongside goal/progress/next (e.g. the\n * protocol redacted flag, the ledger frozenAt stamp) and preserved verbatim\n * when present; their validation stays with the caller.\n */\nexport function sanitizeFreezeSnapshot(\n value: unknown,\n extraKeys: readonly string[] = [],\n): { ok: true; snapshot: FreezeSnapshot; redacted: boolean; extras: Record<string, unknown> } | { ok: false; error: { code: string; message: string } } {\n const bad = (code: string, message: string) => ({ ok: false as const, error: { code, message } })\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return bad('invalid-freeze', '冻结快照必须是 goal/progress/next 字符串对象')\n }\n const record = value as Record<string, unknown>\n const allowed = ['goal', 'progress', 'next', ...extraKeys]\n if (!Object.keys(record).every(key => allowed.includes(key))) {\n return bad('invalid-freeze', '冻结快照包含未知字段')\n }\n for (const key of SECTION_ORDER) {\n if (typeof record[key] !== 'string') {\n return bad('invalid-freeze', '冻结快照字段 ' + SECTION_NAMES[key] + ' 必须是字符串')\n }\n }\n for (const key of SECTION_ORDER) {\n if (hasSlashCommandLines(record[key] as string)) {\n return bad('dsh-command-line', '冻结文本的' + SECTION_NAMES[key] + '包含以 / 开头的命令行,整体拒绝')\n }\n }\n let redacted = false\n const snapshot: Record<SectionKey, string> = { goal: '', progress: '', next: '' }\n for (const key of SECTION_ORDER) {\n const result = redactSensitive(record[key] as string)\n snapshot[key] = result.text\n redacted = redacted || result.redacted\n }\n for (const key of SECTION_ORDER) {\n if (utf8Bytes(snapshot[key]) > FREEZE_FIELD_BYTE_LIMIT) {\n return bad('field-too-large', '冻结快照字段 ' + SECTION_NAMES[key] + ' 超过 8 KiB 上限')\n }\n }\n const extras: Record<string, unknown> = {}\n for (const key of extraKeys) if (key in record) extras[key] = record[key]\n return { ok: true, snapshot: { goal: snapshot.goal, progress: snapshot.progress, next: snapshot.next }, redacted, extras }\n}\n\n/**\n * Parse the freeze-request format: a <<<FREEZE ... >>>FREEZE block whose body\n * is 目标: / 进度: / 下一步: section headers, each followed by body lines.\n * The gate applies before returning: slash-command taint rejects the whole\n * request, sensitive patterns are redacted to markers, and each field is\n * capped at FREEZE_FIELD_BYTE_LIMIT UTF-8 bytes.\n */\nexport function parseFreezeRequest(input: string): FreezeResult {\n const beginIndex = input.indexOf(BEGIN)\n if (beginIndex === -1) {\n return fail('missing-block', '未找到冻结请求块(需要 <<<FREEZE ... >>>FREEZE)')\n }\n const bodyStart = beginIndex + BEGIN.length\n const endIndex = input.indexOf(END, bodyStart)\n if (endIndex === -1) {\n return fail('unterminated-block', '冻结请求块未闭合(缺少 >>>FREEZE)')\n }\n const block = input.slice(bodyStart, endIndex)\n\n const raw = new Map<SectionKey, string[]>()\n let current: SectionKey | undefined\n for (const line of block.split(/\\r?\\n/)) {\n const key = SECTION_KEYS.get(line)\n if (key !== undefined) {\n if (raw.has(key)) {\n return fail('duplicate-section', `重复的段落标题:${SECTION_NAMES[key]}`)\n }\n raw.set(key, [])\n current = key\n } else if (current !== undefined) {\n raw.get(current)!.push(line)\n }\n }\n\n const snapshot: Record<SectionKey, string> = { goal: '', progress: '', next: '' }\n for (const key of SECTION_ORDER) {\n if (!raw.has(key)) {\n return fail('missing-section', `冻结请求缺少段落:${SECTION_NAMES[key]}`)\n }\n const lines = raw.get(key)!\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop()\n snapshot[key] = lines.join('\\n')\n }\n\n for (const key of SECTION_ORDER) {\n if (hasSlashCommandLines(snapshot[key])) {\n return fail('dsh-command-line', `冻结文本的${SECTION_NAMES[key]}包含以 / 开头的命令行,整体拒绝`)\n }\n }\n\n let redacted = false\n for (const key of SECTION_ORDER) {\n const result = redactSensitive(snapshot[key])\n snapshot[key] = result.text\n redacted = redacted || result.redacted\n }\n\n for (const key of SECTION_ORDER) {\n if (utf8Bytes(snapshot[key]) > FREEZE_FIELD_BYTE_LIMIT) {\n return fail('field-too-large', `冻结快照字段 ${SECTION_NAMES[key]} 超过 8 KiB 上限`)\n }\n }\n\n return {\n ok: true,\n snapshot: { goal: snapshot.goal, progress: snapshot.progress, next: snapshot.next },\n warnings: redacted ? ['redacted'] : [],\n }\n}\n","/**\n * Handover bundle (issue #5, ADR 0001): the resource reference set a\n * continuation card carries — the pinned execution triplet (workspace /\n * agent preset / permission) plus doc/script references — so a picking-up\n * session can start with zero context.\n *\n * Security gate (adversarial scenario b): a bundle whose effective\n * permission is HIGHER than the session default is an unconfirmed binding.\n * It enters the pending-confirmation state (the card stores the binding\n * without a permissionConfirmedAt stamp); manual execution refuses, cron\n * refuses to schedule, and the human confirm-permission action resolves the\n * transaction by stamping the confirmation. Any later permission or\n * handover change re-arms the gate (the confirmation binds the exact\n * permission value, blocking confirm-then-swap escalation).\n */\nimport { isTaskPermission, type TaskPermission, type TaskRecord } from './tasks.ts'\n\nexport type { TaskPermission }\n\n/** Wire shape of a handover bundle (before bundledAt is stamped). */\nexport interface TaskHandoverInput {\n workspaceId?: string\n mode?: string\n permission?: TaskPermission\n references: string[]\n}\n\n/** Persisted handover bundle on a task record. */\nexport interface TaskHandover extends TaskHandoverInput {\n /** When the bundle was attached/replaced (ms epoch, stamped by the use case). */\n bundledAt: number\n}\n\n/** Most references a bundle may carry. */\nexport const HANDOVER_MAX_REFERENCES = 32\n/** Per-reference UTF-8 byte cap. */\nexport const HANDOVER_MAX_REFERENCE_BYTES = 512\n/** Total references UTF-8 byte cap. */\nexport const HANDOVER_MAX_TOTAL_BYTES = 8 * 1024\n/** Per target-id (workspace/preset) byte cap. */\nexport const HANDOVER_MAX_TARGET_BYTES = 256\n\n/** The board's notion of the deployment session-default permission (fail-safe default). */\nexport const DEFAULT_SESSION_PERMISSION: TaskPermission = 'read-only'\n\n/** Permission elevation rank (higher = more authority). */\nexport const PERMISSION_RANK: ReadonlyMap<TaskPermission, number> = new Map([\n ['read-only', 0],\n ['workspace-write', 1],\n ['danger-full-access', 2],\n])\n\nfunction byteLength(value: string): number {\n return new TextEncoder().encode(value).length\n}\n\n/**\n * Gate a handover bundle from the wire or disk: exact keys, string targets\n * under the byte cap, a known permission, and a bounded string reference\n * list. Returns the sanitized bundle, or undefined when rejected.\n */\nexport function sanitizeHandover(value: unknown): TaskHandoverInput | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const bundle = value as Record<string, unknown>\n const keys = Object.keys(bundle)\n if (!keys.every(key => ['workspaceId', 'mode', 'permission', 'references'].includes(key))) return undefined\n if (!Array.isArray(bundle.references)) return undefined\n if (bundle.references.length > HANDOVER_MAX_REFERENCES) return undefined\n let total = 0\n for (const reference of bundle.references) {\n if (typeof reference !== 'string' || reference === '') return undefined\n const size = byteLength(reference)\n if (size > HANDOVER_MAX_REFERENCE_BYTES) return undefined\n total += size\n if (total > HANDOVER_MAX_TOTAL_BYTES) return undefined\n }\n for (const key of ['workspaceId', 'mode'] as const) {\n const target: unknown = bundle[key]\n if (target !== undefined && (typeof target !== 'string' || byteLength(target) > HANDOVER_MAX_TARGET_BYTES)) return undefined\n }\n if (bundle.permission !== undefined && !isTaskPermission(bundle.permission)) return undefined\n const workspaceId = bundle.workspaceId\n const mode = bundle.mode\n return {\n ...(typeof workspaceId === 'string' ? { workspaceId } : {}),\n ...(typeof mode === 'string' ? { mode } : {}),\n ...(bundle.permission === undefined ? {} : { permission: bundle.permission as TaskPermission }),\n references: [...bundle.references as string[]],\n }\n}\n\n/** Build the persisted bundle from a sanitized input, stamping bundledAt. */\nexport function handoverOf(input: TaskHandoverInput, now: number): TaskHandover {\n return { ...input, bundledAt: now }\n}\n\n/** The permission an execution session would actually run under. */\nexport function effectivePermission(task: Pick<TaskRecord, 'permission' | 'handover'>): TaskPermission | undefined {\n return task.handover?.permission ?? task.permission\n}\n\n/** Whether a binding's permission is elevated above the session default. */\nexport function exceedsSessionDefault(permission: TaskPermission | undefined, sessionDefault: TaskPermission): boolean {\n if (permission === undefined) return false\n return (PERMISSION_RANK.get(permission) ?? -1) > (PERMISSION_RANK.get(sessionDefault) ?? -1)\n}\n\n/**\n * The confirmation-gate predicate: an elevated permission without a human\n * confirmation stamp. Manual run/rerun and cron must refuse such a card.\n */\nexport function requiresPermissionConfirmation(\n task: Pick<TaskRecord, 'permission' | 'handover' | 'permissionConfirmedAt'>,\n sessionDefault: TaskPermission = DEFAULT_SESSION_PERMISSION,\n): boolean {\n return exceedsSessionDefault(effectivePermission(task), sessionDefault) && task.permissionConfirmedAt === undefined\n}\n","/**\n * Legacy v1 browser persistence and the store seam used by pure client tests.\n *\n * Production v2 state is Host-authoritative. This backend is retained only to\n * read `dsh.taskBoard.v1` for one-time import; the old value is never removed,\n * so it remains a read-only rollback copy after migration.\n *\n * The seam keeps the backend swappable (e.g. an IndexedDB or a host-file\n * channel later); tests run against the in-memory backend and a jsdom\n * localStorage backend.\n */\nimport { isValidCron } from './schedule.ts'\nimport { isTaskPermission, isTaskStatus, normalizeTags, normalizeTargetId, type ScheduleRule, type TaskFreeze, type TaskRecord, type TaskPermission, type TaskStatus } from './tasks.ts'\nimport { isExecutionOutcome } from './subtask.ts'\nimport type { TaskHandover } from './handover.ts'\nimport { sanitizeFreezeSnapshot } from './freeze-snapshot.ts'\nimport { sanitizeHandover } from './handover.ts'\n\n/** Persistence seam for the task ledger. */\nexport interface TaskStore {\n /** Read the persisted ledger (empty when nothing is stored yet). */\n load(): TaskRecord[]\n /** Persist the whole ledger (replaces the stored document). */\n save(tasks: readonly TaskRecord[]): void\n /** Drop the persisted ledger (leaves the in-memory state alone). */\n clear(): void\n /**\n * Subscribe to ledger changes written by ANOTHER tab of the same origin\n * (browser storage events). The board controller reloads the ledger on\n * such a change, so a task deleted in one tab cannot keep firing (or be\n * written back) from the stale in-memory copy of another tab. No-op when\n * the backend has no cross-instance channel (in-memory store).\n */\n subscribeExternal?(listener: () => void): () => void\n}\n\n/** Storage key for the task ledger document. */\nexport const DEFAULT_STORAGE_KEY = 'dsh.taskBoard.v1'\n\n/** Structural shape of the storage event fired in sibling tabs (DOM-free). */\nexport interface StorageChangeEvent {\n key: string | null\n}\n\n/** The event-target face the store needs for cross-tab notifications. */\nexport interface StorageEvents {\n addEventListener(type: 'storage', listener: (event: StorageChangeEvent) => void): void\n removeEventListener(type: 'storage', listener: (event: StorageChangeEvent) => void): void\n}\n\n/**\n * Structural row check with the status left unvalidated (see {@link parseLedger}).\n * The `schedule` field is deliberately NOT checked here: a malformed schedule\n * never drops the task row — {@link normalizeSchedule} repairs or drops the\n * schedule alone.\n */\nfunction isTaskRecordShape(value: unknown): value is Omit<TaskRecord, 'status'> & { status: unknown } {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Record<string, unknown>\n if (typeof record.id !== 'string' || record.id === '') return false\n if (typeof record.title !== 'string') return false\n if (typeof record.description !== 'string') return false\n if (typeof record.prompt !== 'string') return false\n if (typeof record.createdAt !== 'number') return false\n if (typeof record.updatedAt !== 'number') return false\n if (record.parentId !== undefined && typeof record.parentId !== 'string') return false\n if (record.workspaceId !== undefined && typeof record.workspaceId !== 'string') return false\n if (record.mode !== undefined && typeof record.mode !== 'string') return false\n if (record.permission !== undefined && typeof record.permission !== 'string') return false\n if (record.reuseSession !== undefined && typeof record.reuseSession !== 'boolean') return false\n if (!Array.isArray(record.executions)) return false\n for (const execution of record.executions) {\n if (typeof execution !== 'object' || execution === null) return false\n const entry = execution as Record<string, unknown>\n if (typeof entry.id !== 'string') return false\n if (entry.sessionId !== undefined && typeof entry.sessionId !== 'string') return false\n if (typeof entry.startedAt !== 'number') return false\n if (entry.endedAt !== undefined && typeof entry.endedAt !== 'number') return false\n if (entry.result !== undefined && entry.result !== 'succeeded' && entry.result !== 'failed' && entry.result !== 'cancelled') return false\n if (entry.error !== undefined && typeof entry.error !== 'string') return false\n if (entry.initiatedBy !== undefined && typeof entry.initiatedBy !== 'string') return false\n if (entry.frozenBy !== undefined && typeof entry.frozenBy !== 'string') return false\n if (entry.frozenAt !== undefined && typeof entry.frozenAt !== 'number') return false\n }\n return true\n}\n\n/** A task record is structurally valid if it round-trips through the UI. */\nexport function isTaskRecord(value: unknown): value is TaskRecord {\n return isTaskRecordShape(value) && isTaskStatus(value.status)\n}\n\n/** Normalize an unknown persisted status back into the closed status union. */\nfunction normalizeStatus(status: unknown): TaskStatus {\n return isTaskStatus(status) ? status : 'todo'\n}\n\n/**\n * Repair a persisted schedule rule: drop rules without a usable cron string,\n * coerce booleans/numbers, and leave `nextRunAt`/`lastTriggeredAt` undefined\n * when missing (a fresh recompute or the next tick fixes them).\n */\nfunction normalizeSchedule(schedule: unknown): ScheduleRule | undefined {\n if (typeof schedule !== 'object' || schedule === null) return undefined\n const rule = schedule as Record<string, unknown>\n // Reject (drop) a schedule whose cron is not a well-formed 5-field\n // expression: a malformed rule would otherwise linger as a never-firing\n // schedule instead of being dropped for later repair.\n if (typeof rule.cron !== 'string') return undefined\n if (rule.cron.trim() === '' || !isValidCron(rule.cron)) return undefined\n return {\n enabled: rule.enabled === true,\n cron: rule.cron,\n nextRunAt: typeof rule.nextRunAt === 'number' ? rule.nextRunAt : undefined,\n lastTriggeredAt: typeof rule.lastTriggeredAt === 'number' ? rule.lastTriggeredAt : undefined,\n }\n}\n\n/**\n * Repair a persisted freeze snapshot: shape + gate re-check (slash taint,\n * redaction idempotence, byte cap); a malformed or tainted snapshot is\n * dropped (undefined) rather than dropping the whole task row, mirroring\n * the schedule repair policy.\n */\nfunction normalizeFreeze(value: unknown): TaskFreeze | undefined {\n const result = sanitizeFreezeSnapshot(value, ['frozenAt', 'redacted', 'frozenBy'])\n if (!result.ok) return undefined\n const frozenAt = result.extras.frozenAt\n if (typeof frozenAt !== 'number' || !Number.isFinite(frozenAt)) return undefined\n if (result.extras.redacted !== undefined && result.extras.redacted !== true) return undefined\n const frozenBy = result.extras.frozenBy\n if (frozenBy !== undefined && (typeof frozenBy !== 'string' || frozenBy === '')) return undefined\n return {\n goal: result.snapshot.goal,\n progress: result.snapshot.progress,\n next: result.snapshot.next,\n frozenAt,\n ...(result.redacted || result.extras.redacted === true ? { redacted: true } : {}),\n ...(frozenBy === undefined ? {} : { frozenBy }),\n }\n}\n\n/**\n * Repair a persisted handover bundle: shape re-check through the same gate\n * as the wire path; a malformed bundle is dropped rather than dropping the\n * task row (mirroring the schedule/freeze repair policy).\n */\nfunction normalizeHandover(value: unknown): TaskHandover | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const { bundledAt, ...rest } = value as Record<string, unknown> & { bundledAt: unknown }\n const bundle = sanitizeHandover(rest)\n if (bundle === undefined) return undefined\n if (typeof bundledAt !== 'number' || !Number.isFinite(bundledAt)) return undefined\n return { ...bundle, bundledAt }\n}\n\n/** Parse + validate a persisted ledger document; invalid rows are dropped. */\nexport function parseLedger(raw: string | null): TaskRecord[] {\n if (raw === null) return []\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (error) {\n console.error('[dsh-task-board] persisted task ledger is not valid JSON; starting empty', error)\n return []\n }\n if (!Array.isArray(parsed)) {\n console.error('[dsh-task-board] persisted task ledger is not an array; starting empty')\n return []\n }\n const tasks: TaskRecord[] = []\n for (const row of parsed) {\n // Status is normalized (an unknown status from a future version lands in\n // todo instead of dropping the row); the schedule is repaired field by\n // field; every other field must be valid.\n if (!isTaskRecordShape(row)) {\n console.warn('[dsh-task-board] dropping invalid task row from persisted ledger', row)\n continue\n }\n // Always (re)assign the schedule: a repair that returns undefined must\n // clear a malformed persisted rule rather than leave it in the row.\n const task: TaskRecord = { ...row, status: normalizeStatus(row.status) }\n task.schedule = normalizeSchedule(row.schedule)\n // The lineage link is repaired like every other optional field: a blank or\n // non-string parent id clears the link instead of dropping the row. Whether\n // the link is structurally sound (parent exists, no cycle) is decided where\n // the whole list is known (HostTaskLedger.parseHostTasks).\n task.parentId = normalizeTargetId(row.parentId)\n // Cascade bookkeeping on execution records is repaired field by field too,\n // so a hand-edited ledger degrades a run group instead of the whole task.\n task.executions = task.executions.map(execution => ({\n ...execution,\n runGroupId: normalizeTargetId(execution.runGroupId),\n ownResult: isExecutionOutcome(execution.ownResult) ? execution.ownResult : undefined,\n ownError: typeof execution.ownError === 'string' ? execution.ownError : undefined,\n }))\n // Execution targets are normalized like the schedule: blank strings\n // clear the pin and unknown permission strings from a future version\n // fall back to the session default instead of dropping the row.\n task.workspaceId = normalizeTargetId(row.workspaceId)\n task.mode = normalizeTargetId(row.mode)\n task.archivedAt = typeof row.archivedAt === 'number' && Number.isFinite(row.archivedAt) ? row.archivedAt : undefined\n task.permission = isTaskPermission(row.permission) ? row.permission as TaskPermission : undefined\n task.reuseSession = row.reuseSession === true ? true : undefined\n task.freeze = normalizeFreeze(row.freeze)\n task.handover = normalizeHandover(row.handover)\n // Tags are repaired field by field like the schedule: a malformed entry is\n // dropped, and a list that repairs to nothing clears the field instead of\n // dropping the task row.\n task.tags = normalizeTags(row.tags)\n task.permissionConfirmedAt = typeof row.permissionConfirmedAt === 'number' && Number.isFinite(row.permissionConfirmedAt) ? row.permissionConfirmedAt : undefined\n tasks.push(task)\n }\n return tasks\n}\n\n/** localStorage-backed store (the browser backend). */\nexport class LocalStorageTaskStore implements TaskStore {\n /**\n * @param key - storage key for the ledger document.\n * @param storage - storage backend (defaults to the global localStorage; tests inject fakes).\n * @param events - storage-event target for cross-tab notifications (defaults\n * to the browser global; undefined in non-browser runtimes, where the\n * subscription becomes a no-op).\n */\n constructor(\n private readonly key: string = DEFAULT_STORAGE_KEY,\n private readonly storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | undefined = globalThis.localStorage,\n private readonly events: StorageEvents | undefined = typeof (globalThis as { addEventListener?: unknown }).addEventListener === 'function'\n ? (globalThis as unknown as StorageEvents)\n : undefined,\n ) {}\n\n load(): TaskRecord[] {\n if (this.storage === undefined) return []\n try {\n return parseLedger(this.storage.getItem(this.key))\n } catch (error) {\n // Storage read failures (private mode, quota) degrade to an empty ledger,\n // never break the board.\n console.error('[dsh-task-board] task ledger read failed; starting empty', error)\n return []\n }\n }\n\n save(tasks: readonly TaskRecord[]): void {\n if (this.storage === undefined) return\n try {\n this.storage.setItem(this.key, JSON.stringify(tasks))\n } catch (error) {\n // Write failures only skip persistence; in-memory state stays live.\n console.error('[dsh-task-board] task ledger write failed (persistence skipped)', error)\n }\n }\n\n clear(): void {\n if (this.storage === undefined) return\n try {\n this.storage.removeItem(this.key)\n } catch (error) {\n console.error('[dsh-task-board] task ledger clear failed', error)\n }\n }\n\n /**\n * Cross-tab change subscription (see {@link TaskStore.subscribeExternal}).\n * The browser fires the storage event in every OTHER tab of the same origin\n * when one tab writes; a null key means the whole storage was cleared. Both\n * cases reload the ledger here; unrelated keys are ignored.\n */\n subscribeExternal(listener: () => void): () => void {\n if (this.events === undefined) return () => {}\n const onStorage = (event: StorageChangeEvent): void => {\n if (event.key !== null && event.key !== this.key) return\n listener()\n }\n this.events.addEventListener('storage', onStorage)\n return () => { this.events?.removeEventListener('storage', onStorage) }\n }\n}\n\n/** In-memory backend (tests, and a fallback when storage is unavailable). */\nexport class InMemoryTaskStore implements TaskStore {\n private ledger: TaskRecord[] = []\n\n load(): TaskRecord[] {\n return this.ledger.map(task => ({ ...task, executions: [...task.executions] }))\n }\n\n save(tasks: readonly TaskRecord[]): void {\n this.ledger = tasks.map(task => ({ ...task, executions: [...task.executions] }))\n }\n\n clear(): void {\n this.ledger = []\n }\n}\n","/**\n * Cross-module-instance apply guard for the task-board client bundle.\n *\n * The client factory can run more than once in a single page lifetime (for\n * example when a stale bundle is mixed with a rebuilt one while `dsh web` is\n * restarted). Without a guard, every factory run mounts its own sidebar entry\n * and board view, so the shell ends up showing two \"task board\" rows.\n *\n * The flag lives on globalThis so separate module instances (independent\n * factory runs) still share one guard. First claim wins; later claims become\n * no-ops until the claim is released (fiber unload / hot-reload) or the page\n * reloads.\n */\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __dshTaskboardApplied: boolean | undefined\n}\n\n/** Claims the plugin apply slot. Returns true when this call won the slot. */\nexport function claimTaskboardApply(): boolean {\n if (globalThis.__dshTaskboardApplied === true) return false\n globalThis.__dshTaskboardApplied = true\n return true\n}\n\n/**\n * Releases the claim. Called from the client fiber cleanup so that a\n * hot-reloaded bundle (the loader unloads the old plugin fiber and invokes\n * the rebuilt one in the same page) can claim again instead of being\n * silently dropped.\n */\nexport function releaseTaskboardApply(): void {\n globalThis.__dshTaskboardApplied = undefined\n}\n","/**\n * Task-board copy: zh-first dictionaries with an English fallback, selected\n * by the document language. Kept dependency-free (no dsh locale service) so\n * the DOM-injected entry row and the standalone board tree share one tiny\n * lookup.\n */\n\n/** zh dictionary (key-set source of truth). */\nexport const zh = {\n 'entry.label': '任务看板',\n 'board.title': '任务看板',\n 'board.close': '返回会话',\n 'board.new': '新建任务',\n 'board.search': '筛选任务…',\n 'board.empty': '这个状态还没有任务',\n 'board.filterAll': '全部',\n 'board.archive': '归档',\n 'board.archiveView': '归档 ({count})',\n 'board.backToBoard': '返回看板',\n 'archive.empty': '没有已归档的任务',\n 'board.status': '状态',\n 'board.status.backlog': '待规划',\n 'board.status.todo': '待办',\n 'board.status.running': '进行中',\n 'board.status.done': '已完成',\n 'board.status.failed': '已失败',\n 'board.runs': '次执行',\n 'board.pending': '正在提交',\n 'board.updated': '更新于',\n 'board.created': '创建于',\n 'board.hostError': 'Host 操作失败:{error}',\n 'board.hostError.notMounted': '任务看板的后台接口没有挂载:宿主可能没有加载该插件,也可能后台数据正被另一个 DSH 实例占用。重启 DSH 服务后再试',\n 'board.hostError.unauthorized': '登录状态已失效,请刷新页面后重试',\n 'board.hostError.locked': '任务看板的后台数据被占用:{detail}',\n 'board.hostError.timeout': '后台 {seconds} 秒内没有响应,请稍后重试',\n 'board.hostError.unreachable': '连接不上本机 DSH 服务,请确认它仍在运行',\n 'board.hostError.unexpected': '后台返回了无法识别的响应(HTTP {status})',\n 'board.project': '项目',\n 'board.projectAll': '全部项目',\n 'board.projectNew': '新建项目…',\n 'board.projectNewPath': '项目目录(宿主上的绝对路径)',\n 'board.projectNewPathPlaceholder': '例如 C:\\\\work\\\\my-project 或 /home/me/project',\n 'board.projectCreate': '创建项目',\n 'board.projectCreateFailed': '创建项目失败:{error}',\n 'new.aiParse': 'AI 解析',\n 'new.aiParseHint': '把从别处复制的一段话粘进来,让模型整理成标题、描述和执行 Prompt;解析结果只填进下面的表单,你可以先改再创建。',\n 'new.aiParsePlaceholder': '粘贴要变成任务的内容…',\n 'new.aiParseModel': '解析用模型',\n 'new.aiParseRun': '解析并填入',\n 'new.aiParseCancel': '取消解析',\n 'new.aiParseEmpty': '先粘贴一段内容再解析',\n 'new.aiParseNoModel': '这个部署还没有可用的模型,请先在 DSH 里配置模型提供商,或换一个模型再试',\n 'new.aiParseUnavailable': '后台没有解析接口可用,重启 DSH 服务后再试',\n 'new.aiParseTimeout': '模型 {seconds} 秒内没有返回结果,请重试或换一个更快的模型',\n 'new.aiParseFailed': '解析失败:{error}',\n 'board.retryHost': '重试连接 Host',\n 'board.hostMeta': 'Host 时区 {timeZone} · revision {revision}',\n 'new.title': '标题',\n 'new.titlePlaceholder': '一句话描述要做什么',\n 'new.description': '描述',\n 'new.descriptionPlaceholder': '补充背景、范围与验收(可选)',\n 'new.prompt': '执行 Prompt',\n 'new.promptPlaceholder': '发给 agent 的完整指令(留空则使用标题)',\n 'new.submit': '创建',\n 'new.createAndRun': '创建并执行',\n 'new.cancel': '取消',\n 'new.required': '标题不能为空',\n 'new.freeze': '冻结快照(可选)',\n 'new.freezePlaceholder': '粘贴会话输出的 <<<FREEZE … >>>FREEZE 冻结块,解析为目标/进度/下一步(可选)',\n 'detail.freeze': '冻结快照',\n 'detail.freeze.goal': '目标',\n 'detail.freeze.progress': '进度',\n 'detail.freeze.next': '下一步',\n 'detail.freeze.frozenAt': '冻结于 {time}',\n 'detail.freeze.frozenBy': '来源会话 {session}',\n 'detail.freeze.redacted': '冻结文本命中敏感模式,已自动替换为 [REDACTED];接手前请人工复核。',\n 'card.frozen': '冻结',\n 'new.handover': '交接包引用(可选)',\n 'new.handoverPlaceholder': '每行一个文档/脚本引用;填写后,上面选择的钉住三元组(工作区/模式/权限)会作为交接包附加到卡片',\n 'detail.handover': '交接包',\n 'detail.handover.bundledAt': '打包于 {time}',\n 'detail.handover.references': '引用',\n 'new.tags': '标签(可选)',\n 'new.tagsHint': '标签用于卡片徽章与顶栏筛选;填了「执行提示」的行会在每次执行前注入 Prompt,留空则只作展示。',\n 'new.tagName': '标签名',\n 'new.tagNamePlaceholder': '例如:工作',\n 'new.tagPrompt': '执行提示(可选)',\n 'new.tagPromptPlaceholder': '例如:产物归档到 02-工作/',\n 'new.tagAdd': '添加标签',\n 'new.tagRemove': '移除标签 {name}',\n 'board.tagFilter': '按标签筛选',\n 'board.tagFilterClear': '清除标签筛选',\n 'board.tagEmpty': '没有同时带这些标签的任务',\n 'detail.permissionPending': '权限待确认:本卡有效权限({permission})高于会话默认,手动执行与定时调度都会被拒绝,需人工确认后才能运行。',\n 'detail.permissionConfirm': '确认权限绑定',\n 'detail.permissionConfirmed': '已确认权限绑定 · {time}',\n 'detail.title': '任务详情',\n 'detail.edit': '编辑',\n 'detail.editTags': '编辑标签',\n 'detail.duplicate': '复制为新任务',\n 'detail.duplicateAndEdit': '修改并新建副本',\n 'detail.close': '关闭',\n 'edit.title': '编辑任务',\n 'edit.save': '保存',\n 'new.duplicateTitle': '新建任务(副本)',\n 'new.archiveOriginal': '创建后归档原任务',\n 'detail.prompt': '执行 Prompt',\n 'detail.description': '描述',\n 'detail.execution': '执行记录',\n 'detail.noExecution': '尚未执行',\n 'detail.run': '执行',\n 'detail.rerun': '重新执行',\n 'detail.delete': '删除',\n 'detail.archive': '归档',\n 'detail.restore': '恢复',\n 'detail.archivedAt': '已归档 · {time}',\n 'detail.viewSession': '查看会话',\n 'detail.noSession': '暂无会话',\n 'detail.executionStarted': '已启动',\n 'detail.execution.initiator': '发起会话 {session}',\n 'detail.executionEnded': '已结束',\n 'detail.result.succeeded': '成功',\n 'detail.result.failed': '失败',\n 'detail.result.cancelled': '已取消',\n 'detail.result.running': '进行中',\n 'delete.title': '删除任务',\n 'delete.confirm': '确定删除「{name}」吗?删除后不可恢复。',\n 'delete.ok': '删除',\n 'delete.cancel': '取消',\n 'status.move.backlog': '移到待规划',\n 'status.move.todo': '移到待办',\n 'exec.error.noWorkspace': '没有可用工作区,无法执行任务',\n 'exec.error.promptRejected': 'Prompt 被拒绝',\n 'run.failed': '执行失败:{error}',\n 'time.justNow': '刚刚',\n 'detail.schedule': '定时运行',\n 'detail.schedule.enable': '启用定时执行',\n 'detail.schedule.cron': 'Cron 表达式',\n 'detail.schedule.presets': '预设',\n 'detail.schedule.preset.daily9': '每天 09:00',\n 'detail.schedule.preset.hourly': '每小时',\n 'detail.schedule.preset.tenMin': '每 10 分钟',\n 'detail.schedule.preset.weeklyMon9': '每周一 09:00',\n 'detail.schedule.nextRun': '下次运行',\n 'detail.schedule.lastTriggered': '上次触发',\n 'detail.schedule.invalid': 'Cron 表达式无效',\n 'detail.schedule.notScheduled': '尚未排程',\n 'detail.schedule.dueSoon': '即将运行',\n 'card.scheduled': '定时',\n 'new.workspace': '工作区',\n 'new.mode': '模式',\n 'new.permission': '权限',\n 'new.model': '模型',\n 'exec.workspace.recent': '最近使用(默认)',\n 'exec.mode.default': '部署默认',\n 'exec.mode.defaultSuffix': '(默认)',\n 'exec.mode.brokenSuffix': '(不可用)',\n 'exec.mode.removed': '(已移除)',\n 'exec.permission.default': '会话默认',\n 'exec.permission.inheritParent': '继承父任务({permission})',\n 'exec.permission.read-only': '只读',\n 'exec.permission.workspace-write': '工作区可写',\n 'exec.permission.danger-full-access': '完全访问',\n 'exec.model.default': '宿主默认(agent-default-model)',\n 'exec.model.unknown': '(未知模型/回退默认)',\n 'exec.reuseSession': '在同一对话继续',\n 'exec.teamRun': '用 Agent Team 执行(Leader/teammate)',\n 'exec.teamRunHint': '开启后:执行本任务只启动一个 Leader 会话,每个子任务由它派生为 teammate 并在该会话内并行工作(子任务自身的权限钉住不适用)。关闭则每个成员各开独立会话。',\n 'exec.teamRunUnavailable': '当前部署未提供 Agent Teams 服务,无法启用。',\n 'exec.reuseSessionHint': '开启后,本任务的后续执行在上一次会话里继续(该会话空闲且仍存在时),不再每次新建对话;每次复用时都会重新应用上面钉住的权限与模型。',\n 'detail.executionSettings': '执行设置',\n 'exec.hint': '执行时生效:工作区决定执行会话落在哪个工作区;模式决定会话的 agent 预设;权限经 /permission 命令应用到会话。留空则使用运行时默认。',\n // 插件设置卡片(settings.plugin.item 席位)。\n 'settings.title': '任务看板',\n 'settings.description': '控制 Host 任务看板、agent 播报与运行期间的系统空闲睡眠保护。',\n 'settings.enabled': '启用任务看板',\n 'settings.enabledHint': '关闭后隐藏侧边栏入口与看板视图,并注销 task_board_* agent 工具;开启时任何会话都可以通过这些工具读写看板、子任务与定时计划。',\n 'settings.announceToAgent': '向 agent 播报任务看板',\n 'settings.announceToAgentHint': '开启:每条 agent 系统提示都会包含本看板的说明;关闭:不播报,agent 仅在用户主动提及时了解看板。',\n 'settings.preventIdleSleep': '阻止系统空闲睡眠',\n 'settings.preventIdleSleepHint': '默认关闭。开启后,只要存在运行中的 DSH 会话、已启用的定时任务或会话状态尚未确认,Host 就阻止整机因空闲睡眠;屏幕仍可自动关闭。',\n 'settings.powerStatus': '平台:{platform};保护状态:{phase};运行会话:{running};已启用计划:{schedules}',\n 'settings.powerBoundary': '这可能增加电池消耗。合盖、手动睡眠、休眠、关机、低电量或企业策略不在保证范围内,也不会唤醒已经睡眠的机器。',\n 'settings.powerUnknown': '未知',\n 'settings.powerError': '最近一次电源保护错误:{error}',\n 'settings.inherit': '继承',\n 'settings.on': '开',\n 'settings.off': '关',\n 'settings.overridden': '已覆盖',\n 'settings.reset': '恢复默认',\n 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或将本命名空间加入 Host 设置白名单后重启。',\n 'settings.readOnly': '当前部署的设置只读。',\n 'settings.expand': '展开设置',\n 'settings.collapse': '收起设置',\n 'settings.save': '保存',\n 'settings.saving': '保存中…',\n 'settings.discard': '放弃',\n 'settings.unsaved': '未保存',\n 'settings.saveFailed': '部署未接受这些值,已保留供你修改。',\n 'settings.invalidNumber': '请输入数字,留空则使用默认值。',\n 'settings.maxSubtaskDepth': '子任务深度上限',\n 'settings.maxSubtaskDepthHint': '默认 1:一个任务只允许一层子任务,子任务不能再创建或关联子任务。最大 3。执行父任务会并发执行它的整棵子任务树,层级越深,一次执行开启的会话越多。',\n 'settings.maxSubtaskDepthOption': '{depth} 层',\n // 子任务(父子关系、级联执行、关联/解除关联)。\n 'detail.parent': '父任务',\n 'detail.parent.open': '打开父任务',\n 'detail.subtasks': '子任务',\n 'detail.subtasks.empty': '还没有子任务',\n 'detail.subtasks.add': '添加子任务',\n 'detail.subtasks.link': '关联现有任务',\n 'detail.subtasks.detach': '解除关联',\n 'detail.subtasks.runningLock': '子任务正在执行,结算后才能解除关联或改挂父任务',\n 'detail.subtasks.runHint': '执行本任务会同时并发执行它的 {count} 个子任务;子任务失败不影响其它子任务继续执行。',\n 'detail.subtasks.waiting': '等待子任务结算',\n 'detail.subtasks.depthLimit': '当前子任务深度上限为 {depth} 层,子任务不能再创建或关联子任务。',\n 'detail.subtasks.hostOnly': '连接 Host 后才能创建或关联子任务。',\n 'new.subtaskTitle': '新建子任务',\n 'new.subtaskInherit': '未单独选择的执行设置继承父任务(工作区、模式、权限、模型),可在此覆盖。',\n 'link.subtask.title': '关联现有任务',\n 'link.subtask.hint': '只能关联没有父任务的在看板任务;关联后它成为本任务的子任务。',\n 'link.subtask.empty': '没有可关联的任务',\n 'link.subtask.confirm': '关联',\n 'card.subtask': '子任务',\n 'card.subtasks': '{count} 子任务',\n 'card.subtasksFailed': '{count} 失败',\n 'card.subtasksRunning': '{count} 运行中',\n 'card.subtasksBreakdown': '子任务 {total}:已完成 {done},运行中 {running},失败 {failed}',\n 'board.hideSubtasks': '隐藏子任务',\n 'board.showSubtasks': '显示子任务',\n 'board.subtaskFilterHint': '看板默认只显示父任务;搜索或按标签筛选时会自动展开子任务。',\n} satisfies Record<string, string>\n\n/** en dictionary, complete against the zh key set. */\nexport const en: Record<keyof typeof zh, string> = {\n 'entry.label': 'Task Board',\n 'board.title': 'Task Board',\n 'board.close': 'Back to chat',\n 'board.new': 'New Task',\n 'board.search': 'Filter tasks…',\n 'board.empty': 'No tasks in this column',\n 'board.filterAll': 'All',\n 'board.archive': 'Archive',\n 'board.archiveView': 'Archived ({count})',\n 'board.backToBoard': 'Back to board',\n 'archive.empty': 'No archived tasks',\n 'board.status': 'Status',\n 'board.status.backlog': 'Backlog',\n 'board.status.todo': 'To Do',\n 'board.status.running': 'In Progress',\n 'board.status.done': 'Done',\n 'board.status.failed': 'Failed',\n 'board.runs': 'runs',\n 'board.pending': 'Submitting',\n 'board.updated': 'Updated',\n 'board.created': 'Created',\n 'board.hostError': 'Host action failed: {error}',\n 'board.hostError.notMounted': 'The task board Host API is not mounted: the Host may not have loaded the plugin, or another DSH instance holds the ledger. Restart the DSH service and try again',\n 'board.hostError.unauthorized': 'This session is no longer signed in; reload the page and try again',\n 'board.hostError.locked': 'The task board ledger is locked: {detail}',\n 'board.hostError.timeout': 'The Host did not answer within {seconds}s; try again shortly',\n 'board.hostError.unreachable': 'Cannot reach the local DSH service; make sure it is still running',\n 'board.hostError.unexpected': 'The Host returned an unrecognized response (HTTP {status})',\n 'board.project': 'Project',\n 'board.projectAll': 'All projects',\n 'board.projectNew': 'New project…',\n 'board.projectNewPath': 'Project directory (absolute path on the Host)',\n 'board.projectNewPathPlaceholder': 'e.g. C:\\\\work\\\\my-project or /home/me/project',\n 'board.projectCreate': 'Create project',\n 'board.projectCreateFailed': 'Could not create the project: {error}',\n 'new.aiParse': 'Parse with AI',\n 'new.aiParseHint': 'Paste text copied from somewhere else and let a model turn it into a title, description, and run prompt; the result only fills the form below, so you can edit it before creating the task.',\n 'new.aiParsePlaceholder': 'Paste the content to turn into a task…',\n 'new.aiParseModel': 'Model used for parsing',\n 'new.aiParseRun': 'Parse and fill',\n 'new.aiParseCancel': 'Cancel parsing',\n 'new.aiParseEmpty': 'Paste something to parse first',\n 'new.aiParseNoModel': 'This deployment has no model available; configure a model provider in DSH or pick another model',\n 'new.aiParseUnavailable': 'The Host has no parse endpoint; restart the DSH service and try again',\n 'new.aiParseTimeout': 'The model did not answer within {seconds}s; try again or pick a faster model',\n 'new.aiParseFailed': 'Parsing failed: {error}',\n 'board.retryHost': 'Retry Host connection',\n 'board.hostMeta': 'Host time zone {timeZone} · revision {revision}',\n 'new.title': 'Title',\n 'new.titlePlaceholder': 'What should be done, in one line',\n 'new.description': 'Description',\n 'new.descriptionPlaceholder': 'Background, scope, acceptance criteria (optional)',\n 'new.prompt': 'Run Prompt',\n 'new.promptPlaceholder': 'The full instruction sent to the agent (title is used when blank)',\n 'new.submit': 'Create',\n 'new.createAndRun': 'Create and run',\n 'new.cancel': 'Cancel',\n 'new.required': 'Title is required',\n 'new.freeze': 'Frozen snapshot (optional)',\n 'new.freezePlaceholder': 'Paste a <<<FREEZE ... >>>FREEZE block from a session; it parses into goal/progress/next (optional)',\n 'detail.freeze': 'Frozen snapshot',\n 'detail.freeze.goal': 'Goal',\n 'detail.freeze.progress': 'Progress',\n 'detail.freeze.next': 'Next',\n 'detail.freeze.frozenAt': 'Frozen at {time}',\n 'detail.freeze.frozenBy': 'Source session {session}',\n 'detail.freeze.redacted': 'Sensitive patterns were detected in the frozen text and replaced with [REDACTED]; review manually before resuming.',\n 'card.frozen': 'frozen',\n 'new.handover': 'Handover references (optional)',\n 'new.handoverPlaceholder': 'One doc/script reference per line; when filled, the pinned triplet picked above (workspace/mode/permission) is attached to the card as a handover bundle',\n 'detail.handover': 'Handover bundle',\n 'detail.handover.bundledAt': 'Bundled at {time}',\n 'detail.handover.references': 'References',\n 'new.tags': 'Tags (optional)',\n 'new.tagsHint': 'Tags drive the card badges and the board filter; a row with an execution hint is injected ahead of the prompt on every run, an empty one is display-only.',\n 'new.tagName': 'Tag name',\n 'new.tagNamePlaceholder': 'e.g. Work',\n 'new.tagPrompt': 'Execution hint (optional)',\n 'new.tagPromptPlaceholder': 'e.g. Archive artefacts under 02-work/',\n 'new.tagAdd': 'Add tag',\n 'new.tagRemove': 'Remove tag {name}',\n 'board.tagFilter': 'Filter by tag',\n 'board.tagFilterClear': 'Clear tag filter',\n 'board.tagEmpty': 'No task carries all of these tags',\n 'detail.permissionPending': 'Permission pending confirmation: this card\\'s effective permission ({permission}) is above the session default; manual runs and cron are refused until a human confirms.',\n 'detail.permissionConfirm': 'Confirm permission binding',\n 'detail.permissionConfirmed': 'Permission confirmed · {time}',\n 'detail.title': 'Task Detail',\n 'detail.edit': 'Edit',\n 'detail.editTags': 'Edit tags',\n 'detail.duplicate': 'Duplicate Task',\n 'detail.duplicateAndEdit': 'Edit as New Copy',\n 'detail.close': 'Close',\n 'edit.title': 'Edit Task',\n 'edit.save': 'Save',\n 'new.duplicateTitle': 'New Task (Copy)',\n 'new.archiveOriginal': 'Archive original task upon creation',\n 'detail.prompt': 'Run Prompt',\n 'detail.description': 'Description',\n 'detail.execution': 'Execution History',\n 'detail.noExecution': 'Not executed yet',\n 'detail.run': 'Run',\n 'detail.rerun': 'Run Again',\n 'detail.delete': 'Delete',\n 'detail.archive': 'Archive',\n 'detail.restore': 'Restore',\n 'detail.archivedAt': 'Archived · {time}',\n 'detail.viewSession': 'View Session',\n 'detail.noSession': 'No session',\n 'detail.executionStarted': 'Started',\n 'detail.execution.initiator': 'Initiated by session {session}',\n 'detail.executionEnded': 'Ended',\n 'detail.result.succeeded': 'Succeeded',\n 'detail.result.failed': 'Failed',\n 'detail.result.cancelled': 'Cancelled',\n 'detail.result.running': 'Running',\n 'delete.title': 'Delete Task',\n 'delete.confirm': 'Delete \"{name}\"? This cannot be undone.',\n 'delete.ok': 'Delete',\n 'delete.cancel': 'Cancel',\n 'status.move.backlog': 'Move to Backlog',\n 'status.move.todo': 'Move to To Do',\n 'exec.error.noWorkspace': 'No workspace is available to run the task',\n 'exec.error.promptRejected': 'Prompt rejected',\n 'run.failed': 'Run failed: {error}',\n 'time.justNow': 'just now',\n 'detail.schedule': 'Scheduled Runs',\n 'detail.schedule.enable': 'Enable scheduled runs',\n 'detail.schedule.cron': 'Cron expression',\n 'detail.schedule.presets': 'Presets',\n 'detail.schedule.preset.daily9': 'Every day 09:00',\n 'detail.schedule.preset.hourly': 'Every hour',\n 'detail.schedule.preset.tenMin': 'Every 10 minutes',\n 'detail.schedule.preset.weeklyMon9': 'Every Monday 09:00',\n 'detail.schedule.nextRun': 'Next run',\n 'detail.schedule.lastTriggered': 'Last triggered',\n 'detail.schedule.invalid': 'Invalid cron expression',\n 'detail.schedule.notScheduled': 'Not scheduled yet',\n 'detail.schedule.dueSoon': 'Due soon',\n 'card.scheduled': 'scheduled',\n 'new.workspace': 'Workspace',\n 'new.mode': 'Mode',\n 'new.permission': 'Permission',\n 'new.model': 'Model',\n 'exec.workspace.recent': 'Most recent (default)',\n 'exec.mode.default': 'Deployment default',\n 'exec.mode.defaultSuffix': ' (default)',\n 'exec.mode.brokenSuffix': ' (unavailable)',\n 'exec.mode.removed': ' (removed)',\n 'exec.permission.default': 'Session default',\n 'exec.permission.inheritParent': 'Inherit parent ({permission})',\n 'exec.permission.read-only': 'Read-only',\n 'exec.permission.workspace-write': 'Workspace Write',\n 'exec.permission.danger-full-access': 'Full Access',\n 'exec.model.default': 'Host default (agent-default-model)',\n 'exec.model.unknown': ' (unknown / fallback to default)',\n 'exec.reuseSession': 'Continue in the same conversation',\n 'exec.teamRun': 'Run with an Agent Team (Lead + teammates)',\n 'exec.teamRunHint': 'On: running this task starts one Lead session and spawns a teammate per subtask inside it, working in parallel (a subtask permission pin does not apply). Off: every member gets its own independent session.',\n 'exec.teamRunUnavailable': 'This deployment serves no Agent Teams service, so team runs cannot be enabled.',\n 'exec.reuseSessionHint': 'When on, later runs continue in the previous session (when that session is idle and still exists) instead of starting a new conversation each time; the pinned permission and model above are re-applied on every reuse.',\n 'detail.executionSettings': 'Execution Settings',\n 'exec.hint': 'Applied when the task runs: the workspace decides where the execution session lands; the mode composes the session\\'s agent preset; the permission is applied through the /permission command. Blank = runtime default.',\n // Plugin settings card (the `settings.plugin.item` seat).\n 'settings.title': 'Task Board',\n 'settings.description': 'Configure the Host task board, agent announcement, and idle-system-sleep protection while work is pending.',\n 'settings.enabled': 'Enable the task board',\n 'settings.enabledHint': 'When off, the sidebar entry and board view are hidden and the task_board_* agent tools are unregistered; while on, any session can read and drive the board, its subtasks and its schedules through those tools.',\n 'settings.announceToAgent': 'Announce the task board to agents',\n 'settings.announceToAgentHint': 'On: every agent system prompt includes a note about this board. Off: no announcement; agents learn about the board only when you mention it.',\n 'settings.preventIdleSleep': 'Prevent idle system sleep',\n 'settings.preventIdleSleepHint': 'Off by default. When enabled, the Host prevents idle system sleep while any DSH session runs, any schedule is enabled, or session state is not yet known. The display may still turn off.',\n 'settings.powerStatus': 'Platform: {platform}; protection: {phase}; running sessions: {running}; enabled schedules: {schedules}',\n 'settings.powerBoundary': 'This may use more battery. Lid close, manual sleep, hibernation, shutdown, low-battery actions, and enterprise policy are outside the guarantee; an already sleeping computer is not woken.',\n 'settings.powerUnknown': 'unknown',\n 'settings.powerError': 'Latest power-protection error: {error}',\n 'settings.inherit': 'Inherit',\n 'settings.on': 'On',\n 'settings.off': 'Off',\n 'settings.overridden': 'Overridden',\n 'settings.reset': 'Reset to default',\n 'settings.notExposed': 'This DSH version does not expose this plugin\\'s settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to the Host settings allowlist and restart.',\n 'settings.readOnly': 'This deployment stores settings read-only.',\n 'settings.expand': 'Show settings',\n 'settings.collapse': 'Hide settings',\n 'settings.save': 'Save',\n 'settings.saving': 'Saving…',\n 'settings.discard': 'Discard',\n 'settings.unsaved': 'Unsaved',\n 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'settings.invalidNumber': 'Enter a number, or leave blank to use the default.',\n 'settings.maxSubtaskDepth': 'Subtask depth limit',\n 'settings.maxSubtaskDepthHint': 'Default 1: a task may carry one level of subtasks, and a subtask cannot create or link further subtasks. Maximum 3. Running a task also runs its whole subtask tree concurrently, and every extra level opens more sessions per run.',\n 'settings.maxSubtaskDepthOption': '{depth} levels',\n // Subtasks (parent/child links, cascade runs, link/detach).\n 'detail.parent': 'Parent task',\n 'detail.parent.open': 'Open parent task',\n 'detail.subtasks': 'Subtasks',\n 'detail.subtasks.empty': 'No subtasks yet',\n 'detail.subtasks.add': 'Add subtask',\n 'detail.subtasks.link': 'Link existing task',\n 'detail.subtasks.detach': 'Detach',\n 'detail.subtasks.runningLock': 'This subtask is running; it can be detached or re-linked once it settles',\n 'detail.subtasks.runHint': 'Running this task also runs its {count} subtasks concurrently; one subtask failing does not stop the others.',\n 'detail.subtasks.waiting': 'Waiting for subtasks',\n 'detail.subtasks.depthLimit': 'The subtask depth limit is {depth}; a subtask cannot create or link further subtasks.',\n 'detail.subtasks.hostOnly': 'Connect to the Host to create or link subtasks.',\n 'new.subtaskTitle': 'New Subtask',\n 'new.subtaskInherit': 'Execution settings left unset inherit the parent (workspace, mode, permission, model); override any of them here.',\n 'link.subtask.title': 'Link an existing task',\n 'link.subtask.hint': 'Only an on-board task without a parent can be linked; it then becomes a subtask of this task.',\n 'link.subtask.empty': 'No task can be linked',\n 'link.subtask.confirm': 'Link',\n 'card.subtask': 'subtask',\n 'card.subtasks': '{count} subtasks',\n 'card.subtasksFailed': '{count} failed',\n 'card.subtasksRunning': '{count} running',\n 'card.subtasksBreakdown': 'Subtasks {total}: {done} done, {running} running, {failed} failed',\n 'board.hideSubtasks': 'Hide subtasks',\n 'board.showSubtasks': 'Show subtasks',\n 'board.subtaskFilterHint': 'The board shows parent tasks only; a text or label filter reveals the subtasks automatically.',\n}\n\n/** The dictionary key union. */\nexport type TaskBoardKey = keyof typeof zh\n\n/** The settings-card slice of the task-board dictionary. */\nexport type SettingsCardKey = TaskBoardKey\n\n/** Active dictionary, picked by the document language at call time. */\nexport function dictionary(): Record<TaskBoardKey, string> {\n const lang = typeof document !== 'undefined' ? document.documentElement.lang : 'zh'\n return lang.toLowerCase().startsWith('en') ? en : zh\n}\n\n/**\n * SDK translate seat wired by the browser apply() once ctx.locale is bound\n * (setRuntimeTranslate). When present it reads the ACTIVE locale at call\n * time, so plain-DOM surfaces (sidebar row, toggles) follow a runtime\n * language switch; the document-language pick above stays only as the\n * unwired fallback (locale service absent, module-scope early callers).\n */\nlet runtimeT: ((key: TaskBoardKey, params?: Record<string, string>) => string) | undefined\n\n/** Wire the SDK translate seat; pass undefined to restore the document-language pick. */\nexport function setRuntimeTranslate(t: ((key: TaskBoardKey, params?: Record<string, string>) => string) | undefined): void {\n runtimeT = t\n}\n\n/** Translate a key with optional {name} template params. */\nexport function t(key: TaskBoardKey, params?: Record<string, string>): string {\n if (runtimeT !== undefined) return runtimeT(key, params)\n let text: string = dictionary()[key]\n if (params !== undefined) {\n for (const [name, value] of Object.entries(params)) {\n text = text.replaceAll(`{${name}}`, value)\n }\n }\n return text\n}\n","/**\n * Shared scheduled-run presets for the schedule editors (the new-task dialog\n * and the task detail panel): cron expression → locale label.\n */\nimport type { TaskBoardKey } from './locales.ts'\n\n/** Common scheduled-run presets (cron → locale label). */\nexport const SCHEDULE_PRESETS: ReadonlyArray<{ cron: string; label: TaskBoardKey }> = [\n { cron: '0 9 * * *', label: 'detail.schedule.preset.daily9' },\n { cron: '0 * * * *', label: 'detail.schedule.preset.hourly' },\n { cron: '*/10 * * * *', label: 'detail.schedule.preset.tenMin' },\n { cron: '0 9 * * 1', label: 'detail.schedule.preset.weeklyMon9' },\n]\n","/**\n * Shared task-modal pieces: the overlay shell (backdrop, form, title, error,\n * footer) and the title/description/prompt field trio used by both the\n * NewTaskModal and the EditTaskModal. State stays in the owning modal; these\n * are controlled components.\n */\nimport type { ReactNode } from 'react'\nimport { TAG_NAME_MAX_LENGTH, TAG_PROMPT_MAX_LENGTH, TASK_TAG_LIMIT, normalizeTags, type TaskTag } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\n\n/** DOM id shared by the tag-name inputs and their datalist (one board at a time). */\nconst TAG_NAME_LIST_ID = 'dsh-task-board-tag-names'\n\n/** Modal overlay: closes on backdrop press, submits through the form. */\nexport function ModalShell({\n ariaLabel,\n title,\n error,\n pending,\n submitLabel,\n onSubmit,\n onClose,\n secondaryAction,\n children,\n}: {\n ariaLabel: string\n title: string\n error: string | undefined\n pending: boolean\n submitLabel: string\n onSubmit: () => void\n onClose: () => void\n /** Optional second action beside the primary submit (e.g. create and run). */\n secondaryAction?: { label: string; onSubmit: () => void }\n children: ReactNode\n}) {\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onClose() }}>\n <form\n className={css.modal}\n role=\"dialog\"\n aria-label={ariaLabel}\n onSubmit={event => { event.preventDefault(); onSubmit() }}\n >\n <h2 className={css.modalTitle}>{title}</h2>\n\n {children}\n\n {error !== undefined && <p className={css.formError}>{error}</p>}\n\n <footer className={css.modalFooter}>\n <button type=\"button\" className={css.ghostButton} onClick={onClose}>\n {t('new.cancel')}\n </button>\n {secondaryAction !== undefined && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={secondaryAction.onSubmit}\n >\n {secondaryAction.label}\n </button>\n )}\n <button type=\"submit\" className={css.primaryButton} disabled={pending}>\n {submitLabel}\n </button>\n </footer>\n </form>\n </div>\n )\n}\n\n/** Title + description + prompt fields shared by the new and edit task forms. */\nexport function TaskContentFields({\n title,\n description,\n prompt,\n onTitleChange,\n onDescriptionChange,\n onPromptChange,\n}: {\n title: string\n description: string\n prompt: string\n /** Receives the new title; the owner also clears its error state. */\n onTitleChange: (value: string) => void\n onDescriptionChange: (value: string) => void\n onPromptChange: (value: string) => void\n}) {\n return (\n <>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.title')}</span>\n <input\n className={css.input}\n value={title}\n autoFocus\n placeholder={t('new.titlePlaceholder')}\n onChange={event => onTitleChange(event.target.value)}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.description')}</span>\n <textarea\n className={css.input}\n rows={3}\n value={description}\n placeholder={t('new.descriptionPlaceholder')}\n onChange={event => onDescriptionChange(event.target.value)}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.prompt')}</span>\n <textarea\n className={css.input}\n rows={4}\n value={prompt}\n placeholder={t('new.promptPlaceholder')}\n onChange={event => onPromptChange(event.target.value)}\n />\n </label>\n </>\n )\n}\n\n/**\n * Task labels (issue #1521): one row per label holding the badge name and an\n * optional execution hint. The name inputs offer the labels already used on the\n * board through a datalist, and picking one adopts its hint when the row has\n * none — so a business line is defined once and reused by every later task.\n */\nexport function TaskTagFields({\n tags,\n knownTags,\n onChange,\n}: {\n tags: TaskTag[]\n /** Labels already carried elsewhere on the board. */\n knownTags: TaskTag[]\n onChange: (tags: TaskTag[]) => void\n}) {\n const update = (index: number, patch: Partial<TaskTag>): void => {\n onChange(tags.map((tag, position) => (position === index ? { ...tag, ...patch } : tag)))\n }\n\n return (\n <div className={css.field}>\n <span className={css.fieldLabel}>{t('new.tags')}</span>\n <span className={css.fieldHint}>{t('new.tagsHint')}</span>\n {tags.map((tag, index) => (\n <div className={css.tagRow} key={index}>\n <input\n className={css.input}\n list={TAG_NAME_LIST_ID}\n value={tag.name}\n maxLength={TAG_NAME_MAX_LENGTH}\n placeholder={t('new.tagNamePlaceholder')}\n aria-label={t('new.tagName')}\n onChange={(event) => {\n const name = event.target.value\n const known = knownTags.find(candidate => candidate.name === name)\n const adoptsHint = known?.promptPrefix !== undefined && (tag.promptPrefix ?? '').trim() === ''\n update(index, adoptsHint ? { name, promptPrefix: known.promptPrefix } : { name })\n }}\n />\n <input\n className={css.input}\n value={tag.promptPrefix ?? ''}\n maxLength={TAG_PROMPT_MAX_LENGTH}\n placeholder={t('new.tagPromptPlaceholder')}\n aria-label={t('new.tagPrompt')}\n onChange={event => { update(index, { promptPrefix: event.target.value }) }}\n />\n <button\n type=\"button\"\n className={css.ghostButton}\n aria-label={t('new.tagRemove', { name: tag.name })}\n onClick={() => { onChange(tags.filter((_, position) => position !== index)) }}\n >\n ×\n </button>\n </div>\n ))}\n <datalist id={TAG_NAME_LIST_ID}>\n {knownTags.map(tag => <option key={tag.name} value={tag.name} />)}\n </datalist>\n <button\n type=\"button\"\n className={css.ghostButton + ' ' + css.tagAddButton}\n disabled={tags.length >= TASK_TAG_LIMIT}\n onClick={() => { onChange([...tags, { name: '' }]) }}\n >\n + {t('new.tagAdd')}\n </button>\n </div>\n )\n}\n\n/**\n * Clean a tag list via normalizeTags: trim, drop blanks and duplicates, cap\n * lengths and count, so the wire always carries a valid tag list.\n */\nexport function cleanTags(tags: readonly TaskTag[]): TaskTag[] {\n return normalizeTags(tags) ?? []\n}\n","/**\n * The model the user last picked for AI parsing, remembered per browser so the\n * next new-task modal starts from it instead of the roster's first entry\n * (issue #1621). An empty value is a real choice — \"let the Host use its\n * default model\" — and is remembered as such.\n */\nconst PARSE_MODEL_KEY = 'dsh-task-board.parse-model'\n\n/** The nearest browser storage, or undefined when the global itself throws. */\nfunction defaultStorage(): Storage | undefined {\n try {\n return globalThis.localStorage\n } catch {\n return undefined\n }\n}\n\n/** The remembered parse model; '' means the Host default (or no preference). */\nexport function readParseModelPreference(storage: Pick<Storage, 'getItem'> | undefined = defaultStorage()): string {\n try {\n return storage?.getItem(PARSE_MODEL_KEY) ?? ''\n } catch {\n // A blocked or full store must never break the form.\n return ''\n }\n}\n\n/** Remember the picked parse model; '' records the Host-default choice. */\nexport function writeParseModelPreference(model: string, storage: Pick<Storage, 'setItem'> | undefined = defaultStorage()): void {\n try {\n storage?.setItem(PARSE_MODEL_KEY, model)\n } catch {\n // Storage is optional: the picker still works without it.\n }\n}\n","/**\n * New-task modal: title + description + the prompt that execution will send.\n * Creates through the Host and closes only after the Host confirms it.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { isValidCron, nextRunAtMs } from '../../core/schedule.ts'\nimport { parseFreezeRequest } from '../../core/freeze-snapshot.ts'\nimport { effectiveTaskPermission } from '../../core/subtask.ts'\nimport { collectKnownTags, TASK_PERMISSIONS, type TaskPermission, type TaskRecord, type TaskTag } from '../../core/tasks.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\nimport { ModalShell, TaskContentFields, TaskTagFields, cleanTags } from './TaskForm.tsx'\nimport { readParseModelPreference, writeParseModelPreference } from './parse-model-pref.ts'\nimport css from '../board.module.css'\n\nexport interface NewTaskModalProps {\n controller: BoardController\n onClose: () => void\n /** Optional task template to clone/duplicate from. */\n initialTask?: TaskRecord\n /**\n * Workspace the board's project filter has selected (#1536): a task created\n * while a project is open belongs to that project unless the user changes it.\n */\n defaultWorkspaceId?: string\n /** Optional callback after successful duplication (e.g. to archive source). */\n onDuplicateSuccess?: (sourceTaskId: string) => Promise<void>\n /**\n * Task the new card becomes a subtask of (\"add subtask\" from its detail\n * view). The execution targets start from the parent's and the create action\n * carries the parent link; unset targets inherit again at run time.\n */\n parentTask?: TaskRecord\n}\n\n/** New-task form overlay. */\nexport function NewTaskModal({ controller, onClose, initialTask, defaultWorkspaceId, onDuplicateSuccess, parentTask }: NewTaskModalProps) {\n const isDuplicate = initialTask !== undefined\n const [title, setTitle] = useState(initialTask?.title ?? '')\n const [description, setDescription] = useState(initialTask?.description ?? '')\n const [prompt, setPrompt] = useState(initialTask?.prompt ?? '')\n // A subtask starts from its parent's execution contract (issue: subtask\n // inheritance); each picker below still overrides it for this card. The\n // permission stays UNSET by default: leaving it empty is what makes the Host\n // inherit the parent's binding together with its human confirmation, while\n // picking a value pins this card's own binding and re-arms the gate.\n const [workspaceId, setWorkspaceId] = useState(initialTask?.workspaceId ?? parentTask?.workspaceId ?? defaultWorkspaceId ?? '')\n const [mode, setMode] = useState(initialTask?.mode ?? parentTask?.mode ?? '')\n const [permission, setPermission] = useState(initialTask?.permission ?? '')\n const [model, setModel] = useState(initialTask?.model ?? parentTask?.model ?? '')\n const inheritedPermission = parentTask === undefined ? undefined : effectiveTaskPermission(parentTask)\n const [reuseSession, setReuseSession] = useState(initialTask?.reuseSession ?? false)\n const [scheduleEnabled, setScheduleEnabled] = useState(initialTask?.schedule?.enabled ?? false)\n const [scheduleCron, setScheduleCron] = useState(initialTask?.schedule?.cron ?? '')\n const [scheduleError, setScheduleError] = useState<string | undefined>(undefined)\n const [freezeText, setFreezeText] = useState('')\n const [freezeError, setFreezeError] = useState<string | undefined>(undefined)\n const [handoverText, setHandoverText] = useState(\n initialTask?.handover?.references !== undefined ? initialTask.handover.references.join('\\n') : '',\n )\n const [tags, setTags] = useState<TaskTag[]>(initialTask?.tags ?? [])\n const [archiveOriginal, setArchiveOriginal] = useState(true)\n const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n const [options, setOptions] = useState(controller.getSnapshot().executionOptions)\n // \"Parse pasted text\" (issue #1540) exists only when the deployment carries a\n // parse face; the section stays hidden otherwise.\n const [canParse] = useState(controller.getSnapshot().canParseTask === true)\n const [parseText, setParseText] = useState('')\n // Issue #1621: start from the model this browser used last, not from the\n // roster's first entry; '' is the Host default and stays valid.\n const [parseModel, setParseModel] = useState(() => readParseModelPreference())\n const [parsePending, setParsePending] = useState(false)\n const [parseError, setParseError] = useState<string | undefined>(undefined)\n const parseAbort = useRef<AbortController | undefined>(undefined)\n const parseModels = options.models ?? []\n // A pinned target may have disappeared from the runtime (workspace deleted,\n // preset removed) — especially when the form starts from a subtask's parent.\n // Keep it selectable as a stale row, so the field shows what the create\n // action will actually send instead of silently displaying the default.\n const workspaceKnown = workspaceId === '' || options.workspaces.some(item => item.workspaceId === workspaceId)\n const modeKnown = mode === '' || options.presets.some(item => item.id === mode)\n const modelKnown = model === '' || parseModels.some(item => item.id === model)\n\n // The workspace list and preset roster arrive from the runtime after mount;\n // follow them so the pickers never freeze on an empty snapshot.\n useEffect(\n () => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)),\n [controller],\n )\n\n // The model roster arrives asynchronously. A remembered model the deployment\n // no longer offers falls back to the Host default; an empty value is the\n // Host-default choice and is never overwritten by the roster (issue #1621).\n useEffect(() => {\n if (parseModel === '' || parseModels.length === 0) return\n if (parseModels.some(option => option.id === parseModel)) return\n setParseModel('')\n writeParseModelPreference('')\n }, [parseModel, options.models])\n\n const runParse = async (): Promise<void> => {\n const text = parseText.trim()\n if (text === '') {\n setParseError(t('new.aiParseEmpty'))\n return\n }\n const abort = new AbortController()\n parseAbort.current = abort\n setParsePending(true)\n setParseError(undefined)\n try {\n const draft = await controller.parseTaskDraft({ text, ...(parseModel === '' ? {} : { model: parseModel }) }, abort.signal)\n setTitle(draft.title)\n setDescription(draft.description)\n setPrompt(draft.prompt)\n } catch (parseFailure) {\n // A cancelled parse reports nothing: the user asked for it to stop.\n if (!abort.signal.aborted) setParseError(parseFailure instanceof Error ? parseFailure.message : String(parseFailure))\n } finally {\n parseAbort.current = undefined\n setParsePending(false)\n }\n }\n\n /**\n * Create the task through the Host, then optionally start it.\n * @param runAfterCreate - true for the \"create and run\" action: the task is\n * committed either way, and a refused start opens the task instead of\n * reporting the creation as failed.\n */\n const submit = async (runAfterCreate: boolean): Promise<void> => {\n if (scheduleEnabled) {\n const cron = scheduleCron.trim()\n if (cron === '' || !isValidCron(cron)) {\n setScheduleError(t('detail.schedule.invalid'))\n return\n }\n }\n // Optional continuation-card snapshot: parse the freeze block through the\n // T2 gate (structure + redaction + taint + size); a malformed block stops\n // submission with the parser's error instead of creating a plain task.\n let freeze: Parameters<typeof controller.createTaskConfirmed>[0]['freeze'] = undefined\n if (freezeText.trim() !== '') {\n const parsed = parseFreezeRequest(freezeText)\n if (!parsed.ok) {\n setFreezeError(parsed.error.message)\n return\n }\n freeze = { ...parsed.snapshot, ...(parsed.warnings.includes('redacted') ? { redacted: true } : {}) }\n }\n // Optional handover bundle: non-empty reference lines attach the picked\n // triplet (workspace/mode/permission above) plus the references.\n const references = handoverText.split('\\n').map(line => line.trim()).filter(line => line !== '')\n const handover = references.length === 0 ? undefined : {\n references,\n workspaceId: workspaceId === '' ? undefined : workspaceId,\n mode: mode === '' ? undefined : mode,\n permission: permission === '' ? undefined : permission as TaskPermission,\n }\n // Blank rows never reach the wire: the protocol rejects a tag with an\n // empty name, and an empty list is expressed by omitting the field.\n const tagList = cleanTags(tags)\n setPending(true)\n const task = await controller.createTaskConfirmed({\n title,\n description,\n prompt,\n ...(parentTask === undefined ? {} : { parentId: parentTask.id }),\n freeze,\n handover,\n workspaceId: workspaceId === '' ? undefined : workspaceId,\n mode: mode === '' ? undefined : mode,\n permission: permission === '' ? undefined : permission as TaskPermission,\n model: model === '' ? undefined : model,\n ...(reuseSession ? { reuseSession: true } : {}),\n ...(tagList.length > 0 ? { tags: tagList } : {}),\n schedule: scheduleEnabled ? { enabled: true, cron: scheduleCron.trim() } : undefined,\n })\n if (task === undefined) {\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n return\n }\n if (isDuplicate && archiveOriginal && initialTask !== undefined) {\n if (onDuplicateSuccess !== undefined) {\n await onDuplicateSuccess(initialTask.id)\n } else {\n await controller.archiveTask(initialTask.id)\n }\n }\n if (runAfterCreate) {\n // The task exists from here on, so a refused start (a permission above\n // the session default, a pinned target that went stale) must not read as\n // a failed creation: open the task, whose detail view owns the\n // confirmation step and the refusal message.\n const started = await controller.runTask(task.id)\n if (!started) controller.openTask(task.id)\n }\n onClose()\n }\n\n /** Next-run preview for a valid armed cron (creation-time only). */\n const scheduleNextRun = scheduleEnabled && scheduleCron.trim() !== '' && isValidCron(scheduleCron)\n ? nextRunAtMs(scheduleCron, Date.now())\n : undefined\n\n const modalTitle = parentTask !== undefined\n ? t('new.subtaskTitle')\n : isDuplicate ? t('new.duplicateTitle') : t('board.new')\n\n return (\n <ModalShell\n ariaLabel={modalTitle}\n title={modalTitle}\n error={error}\n pending={pending}\n submitLabel={t('new.submit')}\n onSubmit={() => { void submit(false) }}\n onClose={onClose}\n secondaryAction={{ label: t('new.createAndRun'), onSubmit: () => { void submit(true) } }}\n >\n {canParse && (\n <section className={css.aiParse} data-dsh-part=\"ai-parse\">\n <span className={css.fieldLabel}>{t('new.aiParse')}</span>\n <p className={css.fieldHint}>{t('new.aiParseHint')}</p>\n <textarea\n className={css.input}\n rows={3}\n value={parseText}\n placeholder={t('new.aiParsePlaceholder')}\n spellCheck={false}\n onChange={event => { setParseText(event.target.value); setParseError(undefined) }}\n />\n <div className={css.aiParseRow}>\n <select\n className={css.select}\n value={parseModel}\n aria-label={t('new.aiParseModel')}\n onChange={event => {\n setParseModel(event.target.value)\n writeParseModelPreference(event.target.value)\n }}\n >\n <option value=\"\">{t('exec.model.default')}</option>\n {parseModels.map(option => (\n <option key={option.id} value={option.id}>{option.name ?? option.id}</option>\n ))}\n </select>\n {parsePending\n ? (\n <button type=\"button\" className={css.ghostButton} onClick={() => { parseAbort.current?.abort() }}>\n {t('new.aiParseCancel')}\n </button>\n )\n : (\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={parseText.trim() === ''}\n onClick={() => { void runParse() }}\n >\n {t('new.aiParseRun')}\n </button>\n )}\n </div>\n {parseError !== undefined && <p className={css.formError}>{parseError}</p>}\n </section>\n )}\n\n {parentTask !== undefined && (\n <p className={css.detailText} data-dsh-part=\"subtask-inherit\">\n {t('detail.parent')}: {parentTask.title} · {t('new.subtaskInherit')}\n </p>\n )}\n\n <TaskContentFields\n title={title}\n description={description}\n prompt={prompt}\n onTitleChange={value => { setTitle(value); setError(undefined) }}\n onDescriptionChange={setDescription}\n onPromptChange={setPrompt}\n />\n\n <TaskTagFields tags={tags} knownTags={collectKnownTags(controller.getSnapshot().tasks)} onChange={setTags} />\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.freeze')}</span>\n <textarea\n className={css.input}\n rows={4}\n value={freezeText}\n placeholder={t('new.freezePlaceholder')}\n spellCheck={false}\n onChange={event => { setFreezeText(event.target.value); setFreezeError(undefined) }}\n />\n </label>\n {freezeError !== undefined && <p className={css.formError}>{freezeError}</p>}\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.handover')}</span>\n <textarea\n className={css.input}\n rows={3}\n value={handoverText}\n placeholder={t('new.handoverPlaceholder')}\n spellCheck={false}\n onChange={event => { setHandoverText(event.target.value) }}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.workspace')}</span>\n <select\n className={css.select}\n value={workspaceId}\n onChange={event => { setWorkspaceId(event.target.value) }}\n >\n <option value=\"\">{t('exec.workspace.recent')}</option>\n {!workspaceKnown && <option value={workspaceId}>{workspaceId}{t('exec.mode.removed')}</option>}\n {options.workspaces.map(workspace => (\n <option key={workspace.workspaceId} value={workspace.workspaceId}>{workspace.title}</option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.mode')}</span>\n <select\n className={css.select}\n value={mode}\n onChange={event => { setMode(event.target.value) }}\n >\n <option value=\"\">{t('exec.mode.default')}</option>\n {!modeKnown && <option value={mode}>{mode}{t('exec.mode.removed')}</option>}\n {options.presets.map(preset => (\n <option key={preset.id} value={preset.id} disabled={preset.broken !== undefined}>\n {preset.name ?? preset.id}\n {preset.isDefault ? t('exec.mode.defaultSuffix') : ''}\n {preset.broken !== undefined ? t('exec.mode.brokenSuffix') : ''}\n </option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.permission')}</span>\n <select\n className={css.select}\n value={permission}\n onChange={event => { setPermission(event.target.value) }}\n >\n <option value=\"\">{inheritedPermission === undefined\n ? t('exec.permission.default')\n : t('exec.permission.inheritParent', { permission: t(`exec.permission.${inheritedPermission}` as TaskBoardKey) })}</option>\n {TASK_PERMISSIONS.map(id => (\n <option key={id} value={id}>{t(`exec.permission.${id}` as TaskBoardKey)}</option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.model')}</span>\n <select\n className={css.select}\n value={model}\n onChange={event => { setModel(event.target.value) }}\n >\n <option value=\"\">{t('exec.model.default')}</option>\n {!modelKnown && <option value={model}>{model}{t('exec.model.unknown')}</option>}\n {options.models?.map(item => (\n <option key={item.id} value={item.id}>{item.name ?? item.id}</option>\n ))}\n </select>\n </label>\n\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={reuseSession}\n onChange={event => { setReuseSession(event.target.checked) }}\n />\n <span>{t('exec.reuseSession')}</span>\n </label>\n <p className={css.detailText}>{t('exec.reuseSessionHint')}</p>\n\n <section className={css.detailSection}>\n <h4>{t('detail.schedule')}</h4>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={scheduleEnabled}\n onChange={event => {\n setScheduleEnabled(event.target.checked)\n if (!event.target.checked) setScheduleError(undefined)\n }}\n />\n <span>{t('detail.schedule.enable')}</span>\n </label>\n {scheduleEnabled && (\n <>\n <div className={css.scheduleRow}>\n <input\n className={`${css.input} ${css.scheduleInput}${scheduleError !== undefined ? ` ${css.scheduleInputInvalid}` : ''}`}\n value={scheduleCron}\n placeholder=\"0 9 * * *\"\n spellCheck={false}\n aria-label={t('detail.schedule.cron')}\n onChange={event => { setScheduleCron(event.target.value); setScheduleError(undefined) }}\n />\n <select\n className={css.schedulePreset}\n value=\"\"\n aria-label={t('detail.schedule.presets')}\n onChange={event => {\n if (event.target.value === '') return\n setScheduleCron(event.target.value)\n setScheduleError(undefined)\n }}\n >\n <option value=\"\">{t('detail.schedule.presets')}…</option>\n {SCHEDULE_PRESETS.map(preset => (\n <option key={preset.cron} value={preset.cron}>{t(preset.label)}</option>\n ))}\n </select>\n </div>\n {scheduleError !== undefined && <p className={css.formError}>{scheduleError}</p>}\n {scheduleError === undefined && scheduleNextRun !== undefined && (\n <p className={css.scheduleMeta}>\n {t('detail.schedule.nextRun')} {new Date(scheduleNextRun).toLocaleString()}\n </p>\n )}\n </>\n )}\n </section>\n {isDuplicate && (\n <label className={css.checkboxLabel} style={{ marginTop: '12px' }}>\n <input\n type=\"checkbox\"\n checked={archiveOriginal}\n onChange={event => { setArchiveOriginal(event.target.checked) }}\n />\n <span>{t('new.archiveOriginal')}</span>\n </label>\n )}\n </ModalShell>\n )\n}\n","import type { TaskStatus } from '../../core/tasks.ts'\nimport type { TaskBoardKey } from '../locales.ts'\n\n/** Task status → locale key (board column titles and the detail badge). */\nexport const STATUS_KEY: Record<TaskStatus, TaskBoardKey> = {\n backlog: 'board.status.backlog',\n todo: 'board.status.todo',\n running: 'board.status.running',\n done: 'board.status.done',\n failed: 'board.status.failed',\n}\n","/**\n * Task card: the board's column item. Clicking opens the task detail — it\n * never executes anything directly (detail holds the Run button).\n *\n * Memoized: the card re-renders only when its own task record changes, so a\n * status/filter update on one card (or scrolling) never re-renders every\n * card on the board. The per-card onClick is built with a stable task reference\n * by the board, so the memo boundary is effective.\n */\nimport { memo } from 'react'\nimport type { TaskRecord } from '../../core/tasks.ts'\nimport { executionLabel, tagTone } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\n\n/** Compact relative/absolute time label. */\nexport function formatHostTimestamp(ms: number, timeZone?: string): string {\n try {\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'medium',\n ...(timeZone === undefined ? {} : { timeZone }),\n }).format(new Date(ms))\n } catch {\n return new Date(ms).toISOString()\n }\n}\n\nexport function formatTime(ms: number, timeZone?: string): string {\n const date = new Date(ms)\n const now = Date.now()\n const minutes = Math.floor((now - ms) / 60000)\n if (minutes < 1) return t('time.justNow')\n if (minutes < 60) return `${minutes}m`\n if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`\n if (timeZone !== undefined) return formatHostTimestamp(ms, timeZone)\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n}\n\nfunction TaskCardInner({\n task,\n pending,\n timeZone,\n onClick,\n subtaskCount = 0,\n isSubtask = false,\n subtasksDone = 0,\n subtasksRunning = 0,\n subtasksFailed = 0,\n}: {\n task: TaskRecord\n pending: boolean\n timeZone?: string\n onClick: () => void\n /** Direct subtasks of this card, shown as a badge (0 hides it). */\n subtaskCount?: number\n /** Whether this card is itself a subtask. */\n isSubtask?: boolean\n /** Direct subtasks already settled as done, for the roll-up badge. */\n subtasksDone?: number\n /** Direct subtasks currently running, for the roll-up badge. */\n subtasksRunning?: number\n /** Direct subtasks that failed, for the roll-up badge. */\n subtasksFailed?: number\n}) {\n const latest = task.executions[task.executions.length - 1]\n const runs = task.executions.length\n const archived = task.archivedAt !== undefined\n const isDraggable = !archived && task.status !== 'running' && !pending\n\n return (\n <button\n type=\"button\"\n className={css.card}\n data-status={archived ? 'archived' : task.status}\n data-dsh-part=\"card\"\n data-pending={pending || undefined}\n draggable={isDraggable}\n onDragStart={isDraggable ? (event) => {\n event.dataTransfer.setData('text/plain', task.id)\n event.dataTransfer.effectAllowed = 'move'\n } : undefined}\n onClick={onClick}\n title={task.description !== '' ? task.description : task.title}\n >\n <span className={css.cardTitle}>{task.title}</span>\n {task.tags !== undefined && task.tags.length > 0 && (\n <span className={css.cardTags}>\n {task.tags.map(tag => (\n <span\n key={tag.name}\n className={css.cardTag}\n data-tag-tone={tagTone(tag.name)}\n data-dsh-part=\"tag-badge\"\n data-tag-hint={tag.promptPrefix === undefined ? undefined : tag.promptPrefix}\n title={tag.promptPrefix === undefined ? tag.name : tag.promptPrefix}\n >\n {tag.name}\n </span>\n ))}\n </span>\n )}\n {task.description !== '' && <span className={css.cardExcerpt}>{task.description}</span>}\n <span className={css.cardMeta}>\n {isSubtask && (\n <span className={css.cardSubtask} data-dsh-part=\"subtask-badge\">{t('card.subtask')}</span>\n )}\n {subtaskCount > 0 && (\n // A board that hides subtask cards still has to report them: the badge\n // rolls up the direct children and takes the tone of the worst state,\n // so a hidden failing tree cannot look green.\n <span\n className={css.cardSubtask}\n data-dsh-part=\"subtask-count\"\n data-tone={subtasksFailed > 0 ? 'failed' : subtasksRunning > 0 ? 'running' : subtasksDone === subtaskCount ? 'done' : undefined}\n title={t('card.subtasksBreakdown', {\n total: String(subtaskCount),\n done: String(subtasksDone),\n running: String(subtasksRunning),\n failed: String(subtasksFailed),\n })}\n >\n {t('card.subtasks', { count: String(subtaskCount) })}\n {subtasksFailed > 0 ? ' · ' + t('card.subtasksFailed', { count: String(subtasksFailed) }) : ''}\n {subtasksFailed === 0 && subtasksRunning > 0 ? ' · ' + t('card.subtasksRunning', { count: String(subtasksRunning) }) : ''}\n </span>\n )}\n <span className={css.cardTime}>{t('board.updated')} {formatTime(task.updatedAt)}</span>\n {task.freeze !== undefined && (\n <span className={css.cardSchedule} title={task.freeze.goal}>{t('card.frozen')}</span>\n )}\n {!archived && task.schedule?.enabled === true && (\n <span\n className={css.cardSchedule}\n title={task.schedule.nextRunAt !== undefined\n ? `${t('card.scheduled')} · ${formatHostTimestamp(task.schedule.nextRunAt, timeZone)}`\n : t('card.scheduled')}\n >\n {t('card.scheduled')}\n </span>\n )}\n {latest !== undefined && (\n <span className={css.cardRun} data-result={archived ? undefined : latest.result}>\n {runs} {t('board.runs')}\n </span>\n )}\n {latest?.sessionId !== undefined && (\n <span className={css.cardSession} title={latest.sessionId}>⌁</span>\n )}\n {!archived && (task.status === 'running' || pending) && <span className={css.cardSpinner} aria-hidden=\"true\" />}\n </span>\n {!archived && pending && <span className={css.cardRunningLabel}>{t('board.pending')}…</span>}\n {!archived && latest !== undefined && executionLabel(latest) === 'running' && (\n <span className={css.cardRunningLabel}>\n {latest.ownResult === undefined ? t('detail.result.running') : t('detail.subtasks.waiting')}…\n </span>\n )}\n </button>\n )\n}\n\n/** Memoized card: re-renders only when the card's own task record changes. */\nexport const TaskCard = memo(TaskCardInner)\n","/**\n * Generic confirm dialog used by destructive actions (task delete).\n */\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\n\n/** Confirm overlay props. */\nexport interface ConfirmDialogProps {\n title: string\n message: string\n confirmLabel: string\n /** Render the confirm button in the danger style. */\n danger?: boolean\n onCancel: () => void\n onConfirm: () => void\n}\n\n/** Small confirm overlay. */\nexport function ConfirmDialog({ title, message, confirmLabel, danger, onCancel, onConfirm }: ConfirmDialogProps) {\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onCancel() }}>\n <div className={css.modal} role=\"alertdialog\" aria-label={title}>\n <h2 className={css.modalTitle}>{title}</h2>\n <p className={css.confirmMessage}>{message}</p>\n <footer className={css.modalFooter}>\n <button type=\"button\" className={css.ghostButton} onClick={onCancel}>\n {t('delete.cancel')}\n </button>\n <button\n type=\"button\"\n className={danger ? css.dangerButton : css.primaryButton}\n onClick={onConfirm}\n >\n {confirmLabel}\n </button>\n </footer>\n </div>\n </div>\n )\n}\n","/**\n * Edit-task modal: title + description + the prompt the next execution will\n * send, pre-filled from the task. Shown only for tasks that have never\n * started executing (the detail view gates on canEditTaskContent); the Host\n * still re-checks at submit, so a task that started running while the modal\n * was open fails closed and the error surfaces here.\n */\nimport { useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { collectKnownTags, type TaskRecord, type TaskTag } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport { ModalShell, TaskContentFields, TaskTagFields, cleanTags } from './TaskForm.tsx'\n\n/** Edit-task form overlay. */\nexport function EditTaskModal({ controller, task, onClose }: { controller: BoardController; task: TaskRecord; onClose: () => void }) {\n const [title, setTitle] = useState(task.title)\n const [description, setDescription] = useState(task.description)\n const [prompt, setPrompt] = useState(task.prompt)\n const [tags, setTags] = useState<TaskTag[]>(task.tags ?? [])\n const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n\n const submit = async (): Promise<void> => {\n if (title.trim() === '') {\n setError(t('new.required'))\n return\n }\n setPending(true)\n // The Host confirms the mutation (and its fail-closed checks); only a\n // confirmed save closes the modal.\n // Labels ride the same patch as the content fields. A task that never\n // carried one is not sent a clearing null: the wire stays minimal, and the\n // no-tags path keeps producing exactly the patch it produced before.\n const tagList = cleanTags(tags)\n const patch = {\n title,\n description,\n prompt,\n ...(tagList.length > 0 ? { tags: tagList } : (task.tags === undefined ? {} : { tags: null })),\n }\n if (await controller.updateTask(task.id, patch)) {\n onClose()\n return\n }\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n }\n\n return (\n <ModalShell\n ariaLabel={t('edit.title')}\n title={t('edit.title')}\n error={error}\n pending={pending}\n submitLabel={t('edit.save')}\n onSubmit={() => { void submit() }}\n onClose={onClose}\n >\n <TaskContentFields\n title={title}\n description={description}\n prompt={prompt}\n onTitleChange={value => { setTitle(value); setError(undefined) }}\n onDescriptionChange={setDescription}\n onPromptChange={setPrompt}\n />\n\n <TaskTagFields tags={tags} knownTags={collectKnownTags(controller.getSnapshot().tasks)} onChange={setTags} />\n </ModalShell>\n )\n}\n\n/** Edit-tags modal: edit labels only, shown for tasks after first execution. */\nexport function EditTagsModal({ controller, task, onClose }: { controller: BoardController; task: TaskRecord; onClose: () => void }) {\n const [tags, setTags] = useState<TaskTag[]>(task.tags ?? [])\n const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n\n const submit = async (): Promise<void> => {\n setPending(true)\n const tagList = cleanTags(tags)\n const patch = {\n tags: tagList.length > 0 ? tagList : null,\n }\n if (await controller.updateTask(task.id, patch)) {\n onClose()\n return\n }\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n }\n\n return (\n <ModalShell\n ariaLabel={t('detail.editTags')}\n title={t('detail.editTags')}\n error={error}\n pending={pending}\n submitLabel={t('edit.save')}\n onSubmit={() => { void submit() }}\n onClose={onClose}\n >\n <TaskTagFields tags={tags} knownTags={collectKnownTags(controller.getSnapshot().tasks)} onChange={setTags} />\n </ModalShell>\n )\n}\n\n","/**\n * Link-subtask modal: attach an existing on-board root task under the open\n * task. The candidate list mirrors the Host lineage gate (checkParentLink), so\n * a link the Host would refuse is not offered in the first place; the Host\n * still re-checks the action at submit time.\n */\nimport { useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { DEFAULT_SUBTASK_DEPTH, checkParentLink } from '../../core/subtask.ts'\nimport type { TaskRecord } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\nimport { STATUS_KEY } from './status-key.ts'\n\n/** Link-subtask overlay props. */\nexport interface LinkSubtaskModalProps {\n controller: BoardController\n /** The task the picked card becomes a subtask of. */\n parent: TaskRecord\n onClose: () => void\n}\n\n/** Link-subtask overlay. */\nexport function LinkSubtaskModal({ controller, parent, onClose }: LinkSubtaskModalProps) {\n const [pending, setPending] = useState(false)\n const [error, setError] = useState<string | undefined>(undefined)\n const snapshot = controller.getSnapshot()\n const limit = snapshot.host?.maxSubtaskDepth ?? DEFAULT_SUBTASK_DEPTH\n // Only root, on-board tasks can move under another parent; the lineage gate\n // decides the rest (depth, cycle, archived parent).\n const candidates = snapshot.tasks.filter(task =>\n task.archivedAt === undefined\n // A running task may already be a participant of another run group; the\n // Host refuses the move, so it is not offered here.\n && task.status !== 'running'\n && task.parentId === undefined\n && task.id !== parent.id\n && checkParentLink(snapshot.tasks, task.id, parent.id, limit).ok,\n )\n const link = async (taskId: string): Promise<void> => {\n setPending(true)\n setError(undefined)\n if (await controller.setParent(taskId, parent.id)) {\n onClose()\n return\n }\n setPending(false)\n setError(controller.getSnapshot().transportError ?? t('new.required'))\n }\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onClose() }}>\n <div className={css.modal} role=\"dialog\" aria-label={t('link.subtask.title')}>\n <h2 className={css.modalTitle}>{t('link.subtask.title')}</h2>\n <p className={css.fieldHint}>{t('link.subtask.hint')}</p>\n {candidates.length === 0\n ? <p className={css.detailText}>{t('link.subtask.empty')}</p>\n : (\n <ul className={css.pickList}>\n {candidates.map(task => (\n <li key={task.id} className={css.pickRow}>\n <span className={css.pickTitle}>{task.title}</span>\n <span className={css.statusBadge} data-status={task.status}>{t(STATUS_KEY[task.status])}</span>\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={pending}\n onClick={() => { void link(task.id) }}\n >\n {t('link.subtask.confirm')}\n </button>\n </li>\n ))}\n </ul>\n )}\n {error !== undefined && <p className={css.formError}>{error}</p>}\n <footer className={css.modalFooter}>\n <button type=\"button\" className={css.ghostButton} onClick={onClose}>{t('new.cancel')}</button>\n </footer>\n </div>\n </div>\n )\n}\n","/**\n * Task detail: the full view of one task — content, prompt, execution\n * history — and the only place execution can be triggered. Also offers\n * delete (with confirmation), manual status moves, and a jump to the\n * execution's session transcript.\n */\nimport { useEffect, useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { isValidCron } from '../../core/schedule.ts'\nimport { MANUAL_STATUSES, TASK_PERMISSIONS, tagTone, type ExecutionRecord, type TaskPermission, type TaskRecord } from '../../core/tasks.ts'\nimport { canEditTaskContent } from '../../core/use-cases/task-update.ts'\nimport { requiresPermissionConfirmation } from '../../core/handover.ts'\nimport { DEFAULT_SUBTASK_DEPTH, directSubtasks, taskDepth } from '../../core/subtask.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\nimport css from '../board.module.css'\nimport { ConfirmDialog } from './ConfirmDialog.tsx'\nimport { EditTaskModal, EditTagsModal } from './EditTaskModal.tsx'\nimport { LinkSubtaskModal } from './LinkSubtaskModal.tsx'\nimport { NewTaskModal } from './NewTaskModal.tsx'\nimport { formatHostTimestamp, formatTime } from './TaskCard.tsx'\nimport { STATUS_KEY } from './status-key.ts'\n\n/** Execution outcome → locale key. */\nconst RESULT_KEY: Record<NonNullable<ExecutionRecord['result']>, TaskBoardKey> = {\n succeeded: 'detail.result.succeeded',\n failed: 'detail.result.failed',\n cancelled: 'detail.result.cancelled',\n}\n\n/** One execution-history row. */\nfunction ExecutionRow({ execution, timeZone, onOpen }: { execution: ExecutionRecord; timeZone?: string; onOpen: (sessionId: string) => void }) {\n const result = execution.result\n return (\n <li className={css.executionRow} data-result={result}>\n <span className={css.executionBadge} data-result={result}>\n {result === undefined ? t('detail.result.running') : t(RESULT_KEY[result])}\n </span>\n <span className={css.executionTimes}>\n {t('detail.executionStarted')} {formatTime(execution.startedAt, timeZone)}\n {execution.endedAt !== undefined && ` · ${t('detail.executionEnded')} ${formatTime(execution.endedAt, timeZone)}`}\n </span>\n {execution.initiatedBy !== undefined && (\n <span className={css.executionTimes} title={execution.initiatedBy}>\n {t('detail.execution.initiator', { session: execution.initiatedBy })}\n </span>\n )}\n {execution.sessionId !== undefined && (\n <button\n type=\"button\"\n className={css.linkButton}\n onClick={() => { onOpen(execution.sessionId as string) }}\n title={execution.sessionId}\n >\n {t('detail.viewSession')} ⌁\n </button>\n )}\n {execution.error !== undefined && execution.error !== '' && (\n <span className={css.executionError}>{execution.error}</span>\n )}\n </li>\n )\n}\n\n/** The execution-target editor: workspace / mode / permission pickers. */\nfunction ExecutionSettingsSection({ controller, task, pending }: { controller: BoardController; task: TaskRecord; pending: boolean }) {\n const [options, setOptions] = useState(controller.getSnapshot().executionOptions)\n // Whether this deployment serves the Agent Teams service: without it a team\n // run is refused, so the opt-in is offered read-only with the reason.\n const teamRunOffered = (): boolean => controller.getSnapshot().host?.teamRunAvailable === true\n const [teamRunAvailable, setTeamRunAvailable] = useState(teamRunOffered())\n useEffect(\n () => controller.subscribe(() => {\n const snapshot = controller.getSnapshot()\n setOptions(snapshot.executionOptions)\n setTeamRunAvailable(snapshot.host?.teamRunAvailable === true)\n }),\n [controller],\n )\n const workspaceId = task.workspaceId ?? ''\n const mode = task.mode ?? ''\n const permission = task.permission ?? ''\n const model = task.model ?? ''\n // A pinned target may disappear from the runtime (workspace deleted,\n // preset removed); keep it selectable as a stale row instead of silently\n // dropping it, so the user sees exactly what the task will ask for.\n const workspaceKnown = workspaceId === '' || options.workspaces.some(item => item.workspaceId === workspaceId)\n const modeKnown = mode === '' || options.presets.some(item => item.id === mode)\n const modelKnown = model === '' || (options.models ?? []).some(item => item.id === model)\n return (\n <section className={css.detailSection}>\n <h4>{t('detail.executionSettings')}</h4>\n <p className={css.detailText}>{t('exec.hint')}</p>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.workspace')}</span>\n <select\n className={css.select}\n value={workspaceId}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { workspaceId: event.target.value }) }}\n >\n <option value=\"\">{t('exec.workspace.recent')}</option>\n {!workspaceKnown && <option value={workspaceId}>{workspaceId}{t('exec.mode.removed')}</option>}\n {options.workspaces.map(workspace => (\n <option key={workspace.workspaceId} value={workspace.workspaceId}>{workspace.title}</option>\n ))}\n </select>\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.mode')}</span>\n <select\n className={css.select}\n value={mode}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { mode: event.target.value }) }}\n >\n <option value=\"\">{t('exec.mode.default')}</option>\n {!modeKnown && <option value={mode}>{mode}{t('exec.mode.removed')}</option>}\n {options.presets.map(preset => (\n <option key={preset.id} value={preset.id} disabled={preset.broken !== undefined}>\n {preset.name ?? preset.id}\n {preset.isDefault ? t('exec.mode.defaultSuffix') : ''}\n {preset.broken !== undefined ? t('exec.mode.brokenSuffix') : ''}\n </option>\n ))}\n </select>\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.permission')}</span>\n <select\n className={css.select}\n value={permission}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { permission: event.target.value === '' ? undefined : event.target.value as TaskPermission }) }}\n >\n <option value=\"\">{t('exec.permission.default')}</option>\n {TASK_PERMISSIONS.map(id => (\n <option key={id} value={id}>{t(`exec.permission.${id}` as TaskBoardKey)}</option>\n ))}\n </select>\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('new.model')}</span>\n <select\n className={css.select}\n value={model}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { model: event.target.value === '' ? undefined : event.target.value }) }}\n >\n <option value=\"\">{t('exec.model.default')}</option>\n {!modelKnown && <option value={model}>{model}{t('exec.model.unknown')}</option>}\n {options.models?.map(item => (\n <option key={item.id} value={item.id}>{item.name ?? item.id}</option>\n ))}\n </select>\n </label>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={task.reuseSession === true}\n disabled={pending}\n onChange={event => { controller.updateTask(task.id, { reuseSession: event.target.checked }) }}\n />\n <span>{t('exec.reuseSession')}</span>\n </label>\n <p className={css.detailText}>{t('exec.reuseSessionHint')}</p>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={task.teamRun === true}\n disabled={pending || !teamRunAvailable}\n onChange={event => { controller.updateTask(task.id, { teamRun: event.target.checked }) }}\n />\n <span>{t('exec.teamRun')}</span>\n </label>\n <p className={css.detailText}>{teamRunAvailable ? t('exec.teamRunHint') : t('exec.teamRunUnavailable')}</p>\n </section>\n )\n}\n\n/** The scheduled-runs editor: enable toggle, cron input + presets, next-run info. */\nfunction ScheduleSection({ controller, task, pending }: { controller: BoardController; task: TaskRecord; pending: boolean }) {\n const schedule = task.schedule\n const [cron, setCron] = useState(schedule?.cron ?? '0 9 * * *')\n const [enabled, setEnabled] = useState(schedule?.enabled ?? false)\n const [nextRunAt, setNextRunAt] = useState<number | undefined>(schedule?.nextRunAt)\n const [lastTriggeredAt, setLastTriggeredAt] = useState<number | undefined>(schedule?.lastTriggeredAt)\n const [error, setError] = useState<string | undefined>(undefined)\n const timeZone = controller.getSnapshot().host?.scheduler.timeZone\n\n // Keep the editor in sync when the task record changes underneath (the\n // schedule rolls forward as runs trigger).\n useEffect(() => {\n setCron(schedule?.cron ?? '0 9 * * *')\n setEnabled(schedule?.enabled ?? false)\n setNextRunAt(schedule?.nextRunAt)\n setLastTriggeredAt(schedule?.lastTriggeredAt)\n setError(undefined)\n }, [task.id, schedule?.enabled, schedule?.cron, schedule?.nextRunAt, schedule?.lastTriggeredAt])\n\n /** Validate + persist the current cron text (Enter or blur). */\n const saveCron = (value: string): void => {\n const trimmed = value.trim()\n setCron(trimmed)\n if (trimmed === '' || !isValidCron(trimmed)) {\n setError(t('detail.schedule.invalid'))\n return\n }\n setError(undefined)\n controller.setSchedule(task.id, { cron: trimmed })\n }\n\n /** Arm/disarm the schedule (arming first persists the edited cron). */\n const toggleEnabled = (next: boolean): void => {\n const trimmed = cron.trim()\n if (next && (trimmed === '' || !isValidCron(trimmed))) {\n setError(t('detail.schedule.invalid'))\n return\n }\n setError(undefined)\n const submitted = controller.setSchedule(task.id, {\n enabled: next,\n ...(next && trimmed !== schedule?.cron ? { cron: trimmed } : {}),\n })\n if (submitted && !controller.isHostBacked()) setEnabled(next)\n }\n\n const applyPreset = (preset: string): void => {\n if (preset === '') return\n setCron(preset)\n setError(undefined)\n controller.setSchedule(task.id, { cron: preset })\n }\n\n const nextLabel = !enabled || nextRunAt === undefined\n ? t('detail.schedule.notScheduled')\n : nextRunAt <= Date.now()\n ? t('detail.schedule.dueSoon')\n : formatHostTimestamp(nextRunAt, timeZone)\n const lastLabel = lastTriggeredAt === undefined ? '—' : formatHostTimestamp(lastTriggeredAt, timeZone)\n\n return (\n <section className={css.detailSection}>\n <h4>{t('detail.schedule')}</h4>\n <label className={css.scheduleToggle}>\n <input\n type=\"checkbox\"\n checked={enabled}\n disabled={pending}\n onChange={event => { toggleEnabled(event.target.checked) }}\n />\n <span>{t('detail.schedule.enable')}</span>\n </label>\n <div className={css.scheduleRow}>\n <input\n className={`${css.input} ${css.scheduleInput}${error !== undefined ? ` ${css.scheduleInputInvalid}` : ''}`}\n value={cron}\n disabled={pending}\n placeholder=\"0 9 * * *\"\n spellCheck={false}\n aria-label={t('detail.schedule.cron')}\n onChange={event => { setCron(event.target.value); setError(undefined) }}\n onBlur={() => { saveCron(cron) }}\n onKeyDown={event => { if (event.key === 'Enter') saveCron(cron) }}\n />\n <select\n className={css.schedulePreset}\n value=\"\"\n disabled={pending}\n aria-label={t('detail.schedule.presets')}\n onChange={event => { applyPreset(event.target.value) }}\n >\n <option value=\"\">{t('detail.schedule.presets')}…</option>\n {SCHEDULE_PRESETS.map(preset => (\n <option key={preset.cron} value={preset.cron}>{t(preset.label)}</option>\n ))}\n </select>\n </div>\n {error !== undefined && <p className={css.formError}>{error}</p>}\n <p className={css.scheduleMeta}>\n {t('detail.schedule.nextRun')} {nextLabel}\n {' · '}{t('detail.schedule.lastTriggered')} {lastLabel}\n </p>\n </section>\n )\n}\n\n/**\n * The subtask block: the parent link, the direct subtasks with their status,\n * and the actions that grow or prune the tree. Every gate here mirrors the\n * Host lineage gate for affordance only; the Host re-checks the action.\n */\nfunction SubtaskSection({ controller, task, pending, archived }: {\n controller: BoardController\n task: TaskRecord\n pending: boolean\n archived: boolean\n}) {\n const [snapshot, setSnapshot] = useState(controller.getSnapshot())\n useEffect(\n () => controller.subscribe(() => setSnapshot(controller.getSnapshot())),\n [controller],\n )\n const [showAdd, setShowAdd] = useState(false)\n const [showLink, setShowLink] = useState(false)\n const tasks = snapshot.tasks\n const parent = task.parentId === undefined ? undefined : tasks.find(candidate => candidate.id === task.parentId)\n const children = directSubtasks(tasks, task.id)\n const limit = snapshot.host?.maxSubtaskDepth ?? DEFAULT_SUBTASK_DEPTH\n // A new subtask is a leaf, so it fits whenever one more level is allowed.\n const canAddChild = taskDepth(tasks, task.id) + 1 <= limit\n const editable = !archived && !pending\n return (\n <section className={css.detailSection} data-dsh-part=\"subtasks\">\n <h4>{t('detail.subtasks')}</h4>\n {parent !== undefined && (\n <p className={css.detailText}>\n {t('detail.parent')}:{' '}\n <button\n type=\"button\"\n className={css.linkButton}\n title={t('detail.parent.open')}\n onClick={() => { controller.openTask(parent.id) }}\n >\n {parent.title}\n </button>\n </p>\n )}\n {children.length === 0\n ? <p className={css.detailText}>{t('detail.subtasks.empty')}</p>\n : (\n <ul className={css.subtaskList}>\n {children.map(child => (\n <li key={child.id} className={css.subtaskRow}>\n <button\n type=\"button\"\n className={css.linkButton}\n onClick={() => { controller.openTask(child.id) }}\n >\n {child.title}\n </button>\n <span className={css.statusBadge} data-status={child.status}>{t(STATUS_KEY[child.status])}</span>\n {!archived && (\n <button\n type=\"button\"\n className={css.linkButton}\n disabled={pending || child.status === 'running'}\n title={child.status === 'running' ? t('detail.subtasks.runningLock') : undefined}\n onClick={() => { void controller.setParent(child.id, null) }}\n >\n {t('detail.subtasks.detach')}\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n {children.length > 0 && (\n <p className={css.detailText}>{t('detail.subtasks.runHint', { count: String(children.length) })}</p>\n )}\n {!archived && (canAddChild\n ? (controller.isHostBacked()\n ? (\n <div className={css.subtaskAddRow}>\n <button type=\"button\" className={css.ghostButton} disabled={!editable} onClick={() => { setShowAdd(true) }}>\n + {t('detail.subtasks.add')}\n </button>\n <button type=\"button\" className={css.ghostButton} disabled={!editable} onClick={() => { setShowLink(true) }}>\n {t('detail.subtasks.link')}\n </button>\n </div>\n )\n : <p className={css.detailMeta}>{t('detail.subtasks.hostOnly')}</p>)\n : <p className={css.detailMeta}>{t('detail.subtasks.depthLimit', { depth: String(limit) })}</p>)}\n {showAdd && (\n <NewTaskModal controller={controller} parentTask={task} onClose={() => { setShowAdd(false) }} />\n )}\n {showLink && (\n <LinkSubtaskModal controller={controller} parent={task} onClose={() => { setShowLink(false) }} />\n )}\n </section>\n )\n}\n\n/** Task detail overlay. */\nexport function TaskDetail({ controller, task }: { controller: BoardController; task: TaskRecord }) {\n const [confirmDelete, setConfirmDelete] = useState(false)\n const [showEdit, setShowEdit] = useState(false)\n const [showEditTags, setShowEditTags] = useState(false)\n const [showDuplicate, setShowDuplicate] = useState(false)\n\n // Keep the overlay in sync if the task record changes underneath.\n const [latest, setLatest] = useState(task)\n useEffect(() => { setLatest(task) }, [task])\n // A re-used overlay instance must not carry an edit session across tasks.\n useEffect(() => {\n setShowEdit(false)\n setShowEditTags(false)\n setShowDuplicate(false)\n }, [task.id])\n const current = latest\n const snapshot = controller.getSnapshot()\n const running = current.status === 'running'\n const archived = current.archivedAt !== undefined\n const pending = snapshot.pendingTaskIds.includes(current.id)\n const transportError = snapshot.transportError\n const timeZone = snapshot.host?.scheduler.timeZone\n const permissionPending = requiresPermissionConfirmation(current, snapshot.host?.sessionDefaultPermission)\n const subtaskChildren = directSubtasks(snapshot.tasks, current.id)\n\n return (\n <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) controller.closeTask() }}>\n <div className={css.detail} role=\"dialog\" aria-label={t('detail.title')}>\n <header className={css.detailHeader}>\n <h2 className={css.detailTitle}>{current.title}</h2>\n <span className={css.statusBadge} data-status={archived ? 'archived' : current.status}>\n {archived ? t('board.archive') : t(STATUS_KEY[current.status])}\n </span>\n <button\n type=\"button\"\n className={css.iconButton}\n aria-label={t('detail.close')}\n onClick={() => { controller.closeTask() }}\n >\n ×\n </button>\n </header>\n\n <div className={css.detailBody}>\n {transportError !== undefined && (\n <div className={css.formError}>\n {t('board.hostError', { error: transportError })}{' '}\n <button type=\"button\" className={css.linkButton} onClick={() => { void controller.retryHostSync() }}>\n {t('board.retryHost')}\n </button>\n </div>\n )}\n <section className={css.detailSection}>\n <h4>{t('detail.description')}</h4>\n <p className={css.detailText}>{current.description !== '' ? current.description : '—'}</p>\n </section>\n\n <SubtaskSection controller={controller} task={current} pending={pending} archived={archived} />\n\n {current.tags !== undefined && current.tags.length > 0 && (\n <section className={css.detailSection} data-dsh-part=\"tags\">\n <h4>{t('new.tags')}</h4>\n <div className={css.cardTags}>\n {current.tags.map(tag => (\n <span\n key={tag.name}\n className={css.cardTag}\n data-tag-tone={tagTone(tag.name)}\n data-dsh-part=\"tag-badge\"\n data-tag-hint={tag.promptPrefix === undefined ? undefined : tag.promptPrefix}\n title={tag.promptPrefix === undefined ? tag.name : tag.promptPrefix}\n >\n {tag.name}\n </span>\n ))}\n </div>\n </section>\n )}\n\n {current.freeze !== undefined && (\n <section className={css.detailSection} data-dsh-part=\"freeze\">\n <h4>{t('detail.freeze')}</h4>\n {current.freeze.redacted === true && <p className={css.formError}>{t('detail.freeze.redacted')}</p>}\n <p className={css.detailText}><strong>{t('detail.freeze.goal')}</strong></p>\n <pre className={css.promptBlock}>{current.freeze.goal}</pre>\n <p className={css.detailText}><strong>{t('detail.freeze.progress')}</strong></p>\n <pre className={css.promptBlock}>{current.freeze.progress}</pre>\n <p className={css.detailText}><strong>{t('detail.freeze.next')}</strong></p>\n <pre className={css.promptBlock}>{current.freeze.next}</pre>\n <p className={css.detailMeta}>{t('detail.freeze.frozenAt', { time: formatHostTimestamp(current.freeze.frozenAt, timeZone) })}</p>\n {current.freeze.frozenBy !== undefined && (\n <p className={css.detailMeta}>{t('detail.freeze.frozenBy', { session: current.freeze.frozenBy })}</p>\n )}\n </section>\n )}\n\n {current.handover !== undefined && (\n <section className={css.detailSection} data-dsh-part=\"handover\">\n <h4>{t('detail.handover')}</h4>\n <p className={css.detailText}>\n {t('new.workspace')}: {current.handover.workspaceId ?? t('exec.workspace.recent')}\n {' · '}{t('new.mode')}: {current.handover.mode ?? t('exec.mode.default')}\n {' · '}{t('new.permission')}: {current.handover.permission === undefined ? t('exec.permission.default') : t(`exec.permission.${current.handover.permission}` as TaskBoardKey)}\n </p>\n <p className={css.detailText}><strong>{t('detail.handover.references')}</strong></p>\n <ul className={css.executionList}>\n {current.handover.references.map((reference, index) => (\n // References are free text from the freeze block, so the same\n // string can appear twice; the index keeps the key unique (#1492).\n <li key={`${reference}-${index}`} className={css.executionRow}><code>{reference}</code></li>\n ))}\n </ul>\n <p className={css.detailMeta}>{t('detail.handover.bundledAt', { time: formatHostTimestamp(current.handover.bundledAt, timeZone) })}</p>\n </section>\n )}\n\n {permissionPending && (\n <section className={css.detailSection} data-dsh-part=\"permission-gate\">\n <p className={css.formError}>{t('detail.permissionPending', { permission: t(`exec.permission.${current.handover?.permission ?? current.permission}` as TaskBoardKey) })}</p>\n <button type=\"button\" className={css.primaryButton} disabled={pending} onClick={() => { void controller.confirmPermission(current.id) }}>\n {t('detail.permissionConfirm')}\n </button>\n </section>\n )}\n {current.permissionConfirmedAt !== undefined && (\n <p className={css.detailMeta}>{t('detail.permissionConfirmed', { time: formatHostTimestamp(current.permissionConfirmedAt, timeZone) })}</p>\n )}\n\n <section className={css.detailSection}>\n <h4>{t('detail.prompt')}</h4>\n <pre className={css.promptBlock}>{current.prompt !== '' ? current.prompt : current.title}</pre>\n </section>\n\n {!archived && (\n <>\n <ExecutionSettingsSection controller={controller} task={current} pending={pending} />\n <ScheduleSection controller={controller} task={current} pending={pending} />\n </>\n )}\n\n <section className={css.detailSection}>\n <h4>{t('detail.execution')}</h4>\n {current.executions.length === 0 ? (\n <p className={css.detailText}>{t('detail.noExecution')}</p>\n ) : (\n <ul className={css.executionList}>\n {[...current.executions].reverse().map(execution => (\n <ExecutionRow\n key={execution.id}\n execution={execution}\n timeZone={timeZone}\n onOpen={sessionId => { controller.openSession(sessionId) }}\n />\n ))}\n </ul>\n )}\n </section>\n\n {!archived && (\n <section className={css.detailSection}>\n <h4>{t('board.status')}</h4>\n <div className={css.moveRow}>\n {MANUAL_STATUSES.map(status => (\n <button\n key={status}\n type=\"button\"\n className={css.ghostButton}\n disabled={current.status === status || running || pending}\n onClick={() => { controller.moveTask(current.id, status) }}\n >\n {t(`status.move.${status}` as TaskBoardKey)}\n </button>\n ))}\n </div>\n </section>\n )}\n </div>\n\n <footer className={css.detailFooter}>\n {!archived && pending && <span className={css.detailMeta}>{t('board.pending')}…</span>}\n {!archived && canEditTaskContent(current) && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => { setShowEdit(true) }}\n >\n {t('detail.edit')}\n </button>\n )}\n {!archived && !canEditTaskContent(current) && current.status !== 'running' && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => { setShowEditTags(true) }}\n >\n {t('detail.editTags')}\n </button>\n )}\n {!archived && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => { setShowDuplicate(true) }}\n title={canEditTaskContent(current) ? t('detail.duplicate') : t('detail.duplicateAndEdit')}\n >\n {canEditTaskContent(current) ? t('detail.duplicate') : t('detail.duplicateAndEdit')}\n </button>\n )}\n {!archived && (\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={running || pending}\n title={subtaskChildren.length > 0\n ? t('detail.subtasks.runHint', { count: String(subtaskChildren.length) })\n : undefined}\n onClick={() => {\n void controller.rerunTask(current.id).then(() => {\n if (controller.getSnapshot().transportError === undefined) controller.closeTask()\n })\n }}\n >\n {current.executions.length === 0 ? t('detail.run') : t('detail.rerun')}\n </button>\n )}\n {archived ? (\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={pending}\n onClick={() => {\n controller.restoreTask(current.id)\n }}\n >\n {t('detail.restore')}\n </button>\n ) : (\n (current.status === 'done' || current.status === 'failed') && (\n <button\n type=\"button\"\n className={css.ghostButton}\n disabled={pending}\n onClick={() => {\n controller.archiveTask(current.id)\n }}\n >\n {t('detail.archive')}\n </button>\n )\n )}\n <button\n type=\"button\"\n className={css.dangerButton}\n disabled={pending}\n onClick={() => { setConfirmDelete(true) }}\n >\n {t('detail.delete')}\n </button>\n <span className={css.detailMeta}>\n {t('board.created')} {formatTime(current.createdAt, timeZone)}\n {archived && ` · ${t('detail.archivedAt', { time: formatTime(current.archivedAt!, timeZone) })}`}\n </span>\n </footer>\n </div>\n\n {confirmDelete && (\n <ConfirmDialog\n title={t('delete.title')}\n message={t('delete.confirm', { name: current.title })}\n confirmLabel={t('delete.ok')}\n danger\n onCancel={() => { setConfirmDelete(false) }}\n onConfirm={() => {\n setConfirmDelete(false)\n controller.deleteTask(current.id)\n }}\n />\n )}\n\n {showEdit && !archived && canEditTaskContent(current) && (\n <EditTaskModal controller={controller} task={current} onClose={() => { setShowEdit(false) }} />\n )}\n\n {showEditTags && !archived && current.status !== 'running' && (\n <EditTagsModal controller={controller} task={current} onClose={() => { setShowEditTags(false) }} />\n )}\n\n {showDuplicate && !archived && (\n <NewTaskModal\n controller={controller}\n initialTask={current}\n onClose={() => { setShowDuplicate(false) }}\n onDuplicateSuccess={async (sourceId) => {\n await controller.archiveTask(sourceId)\n controller.closeTask()\n }}\n />\n )}\n </div>\n )\n}\n","/**\n * Board view: the multi-column kanban that replaces the middle column while\n * active. Cards open the task detail (never execute directly); the header\n * offers filter, new-task, and a back-to-chat escape.\n */\nimport { memo, useCallback, useEffect, useState } from 'react'\nimport { selectedTaskOf, type BoardController } from '../../core/controller.ts'\nimport { COLUMNS, canMoveManually, collectKnownTags, tagTone, type TaskRecord } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport css from '../board.module.css'\nimport { NewTaskModal } from './NewTaskModal.tsx'\nimport { STATUS_KEY } from './status-key.ts'\nimport { TaskCard } from './TaskCard.tsx'\nimport { TaskDetail } from './TaskDetail.tsx'\n\n/** Sentinel option value of the project row's \"register a new project\" entry. */\nexport const NEW_PROJECT_VALUE = '__dsh_new_project__'\n\n/** Case-insensitive title/description/tag/freeze-snapshot match. */\nexport function matchesFilter(task: TaskRecord, filter: string): boolean {\n if (filter.trim() === '') return true\n const needle = filter.trim().toLowerCase()\n const haystacks = [task.title, task.description, ...(task.tags ?? []).map(tag => tag.name)]\n if (task.freeze !== undefined) haystacks.push(task.freeze.goal, task.freeze.progress, task.freeze.next)\n return haystacks.some(text => text.toLowerCase().includes(needle))\n}\n\n/**\n * Whether a task carries every selected label (issue #1521). Multi-select is\n * conjunctive: adding a label narrows the board instead of widening it, which\n * is the only reading that keeps \"工作\" selected from dragging unrelated cards\n * back in when a second label is added.\n */\nexport function matchesTagFilter(task: TaskRecord, selected: readonly string[]): boolean {\n if (selected.length === 0) return true\n const names = new Set((task.tags ?? []).map(tag => tag.name))\n return selected.every(name => names.has(name))\n}\n\n/**\n * Memoized per-card adapter: with a stable `onOpen` from the board and an\n * immutable task record (only the changed card gets a new object ref), a card\n * re-renders only when its own task changes — not when a sibling card status,\n * the filter, or the selection moves.\n */\nconst MemoTaskCard = memo(function MemoTaskCard({ task, pending, timeZone, onOpen, subtaskCount, isSubtask, subtasksDone, subtasksRunning, subtasksFailed }: {\n task: TaskRecord\n pending: boolean\n timeZone?: string\n onOpen: (id: string) => void\n subtaskCount: number\n isSubtask: boolean\n subtasksDone: number\n subtasksRunning: number\n subtasksFailed: number\n}) {\n const onClick = useCallback(() => { onOpen(task.id) }, [task.id, onOpen])\n return (\n <TaskCard\n task={task}\n pending={pending}\n timeZone={timeZone}\n onClick={onClick}\n subtaskCount={subtaskCount}\n isSubtask={isSubtask}\n subtasksDone={subtasksDone}\n subtasksRunning={subtasksRunning}\n subtasksFailed={subtasksFailed}\n />\n )\n})\n\n/** Board component; subscribes to the controller snapshot. */\nexport function TaskBoard({ controller }: { controller: BoardController }) {\n const [snapshot, setSnapshot] = useState(controller.getSnapshot())\n useEffect(\n () => controller.subscribe(() => setSnapshot(controller.getSnapshot())),\n [controller],\n )\n const [filter, setFilter] = useState('')\n const [tagFilter, setTagFilter] = useState<string[]>([])\n // Subtask cards are real board cards, but a tree with dozens of children\n // turns a column into a wall: the board starts from the parent cards only and\n // the header switch reveals the flat view. A text or label filter re-enables\n // them automatically, so searching a subtask title still finds it.\n const [hideSubtasks, setHideSubtasks] = useState(true)\n const [showNew, setShowNew] = useState(false)\n // Project partition (#1536): '' means \"all projects\". A selected project\n // narrows the board and becomes the new-task form's default workspace.\n const [projectId, setProjectId] = useState('')\n const [showNewProject, setShowNewProject] = useState(false)\n const [newProjectPath, setNewProjectPath] = useState('')\n const [newProjectError, setNewProjectError] = useState<string | undefined>(undefined)\n const [newProjectPending, setNewProjectPending] = useState(false)\n const selected = selectedTaskOf(snapshot)\n const archiveView = snapshot.archiveView\n // Every label in use across the ledger (board and archive alike), so the\n // filter never loses an option just because its task was archived.\n const knownTags = collectKnownTags(snapshot.tasks)\n // The family of cards this view owns: the board columns, or the archive.\n const onBoard = snapshot.tasks.filter(task =>\n archiveView ? task.archivedAt !== undefined : task.archivedAt === undefined,\n )\n // Direct subtask count and state roll-up per task, for the card badge: a\n // hidden tree still has to report how many children run, fail, or finish.\n const subtaskCounts = new Map<string, number>()\n const subtaskRollup = new Map<string, { done: number; running: number; failed: number }>()\n for (const task of onBoard) {\n if (task.parentId === undefined) continue\n subtaskCounts.set(task.parentId, (subtaskCounts.get(task.parentId) ?? 0) + 1)\n const rollup = subtaskRollup.get(task.parentId) ?? { done: 0, running: 0, failed: 0 }\n if (task.status === 'done') rollup.done += 1\n else if (task.status === 'running') rollup.running += 1\n else if (task.status === 'failed') rollup.failed += 1\n subtaskRollup.set(task.parentId, rollup)\n }\n const hasSubtasks = subtaskCounts.size > 0\n const searchActive = filter.trim() !== '' || tagFilter.length > 0\n const hidingSubtasks = hideSubtasks && !searchActive\n const visible = onBoard.filter(task =>\n (projectId === '' || task.workspaceId === projectId)\n && (!hidingSubtasks || task.parentId === undefined)\n && matchesFilter(task, filter)\n && matchesTagFilter(task, tagFilter),\n )\n const projects = snapshot.executionOptions.workspaces\n const canCreateProject = snapshot.canCreateWorkspace === true\n const submitNewProject = async (): Promise<void> => {\n const path = newProjectPath.trim()\n if (path === '') return\n setNewProjectPending(true)\n setNewProjectError(undefined)\n try {\n const created = await controller.createWorkspace(path)\n setProjectId(created.workspaceId)\n setShowNewProject(false)\n setNewProjectPath('')\n } catch (error) {\n setNewProjectError(error instanceof Error ? error.message : String(error))\n } finally {\n setNewProjectPending(false)\n }\n }\n const toggleTag = useCallback((name: string): void => {\n setTagFilter(current => current.includes(name)\n ? current.filter(entry => entry !== name)\n : [...current, name])\n }, [])\n const openTask = useCallback((id: string): void => { controller.openTask(id) }, [controller])\n\n return (\n <div className={css.board} data-dsh-taskboard-board=\"\" data-dsh-plugin=\"task-board\">\n <header className={css.boardHeader}>\n {/* Shared hook: dsh-web-all offsets center-view back controls beside the collapsed mobile sidebar. */}\n <button\n type=\"button\"\n className={`${css.ghostButton} ${css.backButton}`}\n data-dsh-center-view-back=\"\"\n aria-label={t('board.close')}\n onClick={() => { controller.closeBoard() }}\n >\n <span aria-hidden=\"true\">‹</span>\n <span>{t('board.close')}</span>\n </button>\n <h2 className={css.boardTitle}>{t('board.title')}</h2>\n {snapshot.host !== undefined && (\n <span className={css.detailMeta}>\n {t('board.hostMeta', {\n revision: String(snapshot.host.revision),\n timeZone: snapshot.host.scheduler.timeZone,\n })}\n </span>\n )}\n {(projects.length > 0 || canCreateProject) && (\n <label className={css.projectFilter}>\n <span className={css.projectFilterLabel}>{t('board.project')}</span>\n <select\n className={css.select}\n data-dsh-part=\"project-filter\"\n value={projectId}\n aria-label={t('board.project')}\n onChange={event => {\n const value = event.target.value\n if (value === NEW_PROJECT_VALUE) {\n setNewProjectError(undefined)\n setShowNewProject(true)\n return\n }\n setProjectId(value)\n }}\n >\n <option value=\"\">{t('board.projectAll')}</option>\n {projects.map(project => (\n <option key={project.workspaceId} value={project.workspaceId}>{project.title}</option>\n ))}\n {canCreateProject && <option value={NEW_PROJECT_VALUE}>{t('board.projectNew')}</option>}\n </select>\n </label>\n )}\n <input\n className={css.search}\n type=\"search\"\n placeholder={t('board.search')}\n value={filter}\n onChange={event => { setFilter(event.target.value) }}\n aria-label={t('board.search')}\n />\n {hasSubtasks && (\n <button\n type=\"button\"\n className={hidingSubtasks ? css.primaryButton : css.ghostButton}\n data-dsh-part=\"subtask-filter\"\n aria-pressed={hidingSubtasks}\n title={t('board.subtaskFilterHint')}\n onClick={() => { setHideSubtasks(value => !value) }}\n >\n {hidingSubtasks ? t('board.showSubtasks') : t('board.hideSubtasks')}\n </button>\n )}\n <button\n type=\"button\"\n className={archiveView ? css.primaryButton : css.ghostButton}\n onClick={() => { controller.toggleArchiveView() }}\n >\n {archiveView\n ? t('board.backToBoard')\n : t('board.archiveView', { count: String(snapshot.tasks.filter(task => task.archivedAt !== undefined).length) })}\n </button>\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => { setShowNew(true) }}\n >\n + {t('board.new')}\n </button>\n </header>\n\n {showNewProject && (\n <div className={css.projectDialog} data-dsh-part=\"project-dialog\">\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('board.projectNewPath')}</span>\n <input\n className={css.input}\n value={newProjectPath}\n placeholder={t('board.projectNewPathPlaceholder')}\n spellCheck={false}\n onChange={event => { setNewProjectPath(event.target.value); setNewProjectError(undefined) }}\n />\n </label>\n {newProjectError !== undefined && <p className={css.formError}>{t('board.projectCreateFailed', { error: newProjectError })}</p>}\n <div className={css.projectDialogActions}>\n <button\n type=\"button\"\n className={css.ghostButton}\n onClick={() => { setShowNewProject(false); setNewProjectError(undefined) }}\n >\n {t('new.cancel')}\n </button>\n <button\n type=\"button\"\n className={css.primaryButton}\n disabled={newProjectPending || newProjectPath.trim() === ''}\n onClick={() => { void submitNewProject() }}\n >\n {t('board.projectCreate')}\n </button>\n </div>\n </div>\n )}\n\n {!archiveView && knownTags.length > 0 && (\n <div className={css.tagFilter} data-dsh-part=\"tag-filter\">\n <span className={css.tagFilterLabel}>{t('board.tagFilter')}</span>\n {knownTags.map(tag => {\n const active = tagFilter.includes(tag.name)\n return (\n <button\n key={tag.name}\n type=\"button\"\n className={css.tagChip}\n data-dsh-part=\"tag-chip\"\n data-tag-tone={tagTone(tag.name)}\n data-active={active ? 'true' : undefined}\n aria-pressed={active}\n title={tag.promptPrefix === undefined ? tag.name : tag.promptPrefix}\n onClick={() => { toggleTag(tag.name) }}\n >\n {tag.name}\n </button>\n )\n })}\n {tagFilter.length > 0 && (\n <button type=\"button\" className={css.linkButton} onClick={() => { setTagFilter([]) }}>\n {t('board.tagFilterClear')}\n </button>\n )}\n </div>\n )}\n\n {snapshot.transportError !== undefined && (\n <div className={css.formError}>\n {t('board.hostError', { error: snapshot.transportError })}{' '}\n <button type=\"button\" className={css.linkButton} onClick={() => { void controller.retryHostSync() }}>\n {t('board.retryHost')}\n </button>\n </div>\n )}\n\n <div className={css.columns}>\n {archiveView ? (\n <section className={css.column} data-status=\"archived\" data-dsh-part=\"column\">\n <header className={css.columnHeader}>\n <h3 className={css.columnTitle}>{t('board.archive')}</h3>\n <span className={css.columnCount}>{visible.length}</span>\n </header>\n <div className={css.cards}>\n {visible.map(task => (\n <MemoTaskCard\n key={task.id}\n task={task}\n pending={snapshot.pendingTaskIds.includes(task.id)}\n timeZone={snapshot.host?.scheduler.timeZone}\n onOpen={openTask}\n subtaskCount={subtaskCounts.get(task.id) ?? 0}\n isSubtask={task.parentId !== undefined}\n subtasksDone={subtaskRollup.get(task.id)?.done ?? 0}\n subtasksRunning={subtaskRollup.get(task.id)?.running ?? 0}\n subtasksFailed={subtaskRollup.get(task.id)?.failed ?? 0}\n />\n ))}\n {visible.length === 0 && (\n <div className={css.columnEmpty}>{tagFilter.length > 0 ? t('board.tagEmpty') : t('archive.empty')}</div>\n )}\n </div>\n </section>\n ) : (\n COLUMNS.map(column => {\n const tasks = visible.filter(task => task.status === column.status)\n const isManualDropTarget = column.status === 'backlog' || column.status === 'todo'\n return (\n <section\n key={column.status}\n className={css.column}\n data-status={column.status}\n data-dsh-part=\"column\"\n onDragOver={isManualDropTarget ? (event) => {\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n } : undefined}\n onDrop={isManualDropTarget ? (event) => {\n event.preventDefault()\n const taskId = event.dataTransfer.getData('text/plain')\n if (!taskId) return\n const dropped = snapshot.tasks.find(t => t.id === taskId)\n if (dropped && canMoveManually(dropped.status, column.status) && dropped.status !== column.status) {\n controller.moveTask(taskId, column.status)\n }\n } : undefined}\n >\n <header className={css.columnHeader}>\n <span className={css.statusDot} data-status={column.status} aria-hidden=\"true\" />\n <h3 className={css.columnTitle}>{t(STATUS_KEY[column.status])}</h3>\n <span className={css.columnCount}>{tasks.length}</span>\n </header>\n <div className={css.cards}>\n {tasks.map(task => (\n <MemoTaskCard\n key={task.id}\n task={task}\n pending={snapshot.pendingTaskIds.includes(task.id)}\n timeZone={snapshot.host?.scheduler.timeZone}\n onOpen={openTask}\n subtaskCount={subtaskCounts.get(task.id) ?? 0}\n isSubtask={task.parentId !== undefined}\n subtasksDone={subtaskRollup.get(task.id)?.done ?? 0}\n subtasksRunning={subtaskRollup.get(task.id)?.running ?? 0}\n subtasksFailed={subtaskRollup.get(task.id)?.failed ?? 0}\n />\n ))}\n {tasks.length === 0 && (\n <div className={css.columnEmpty}>{tagFilter.length > 0 ? t('board.tagEmpty') : t('board.empty')}</div>\n )}\n </div>\n </section>\n )\n })\n )}\n </div>\n\n {selected !== undefined && (\n <TaskDetail controller={controller} task={selected} />\n )}\n {showNew && (\n <NewTaskModal\n controller={controller}\n {...(projectId === '' ? {} : { defaultWorkspaceId: projectId })}\n onClose={() => { setShowNew(false) }}\n />\n )}\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/body-mutations.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * One `document.body` MutationObserver per page, shared by every family\n * plugin bundle.\n *\n * Family plugins that inject at the DOM level must notice when the shell\n * re-renders around their injected node: the sidebar entry rows\n * (sidebar-entry-core), the center-column panel containers\n * (panel-mount-core), and the aggregate shell's column shims. Each consumer\n * used to install its OWN `MutationObserver` on `document.body` with\n * `{ childList: true, subtree: true }`, so a page carrying N family plugins\n * paid N native observers and N callback invocations for EVERY mutation batch\n * the app produced — chat token streaming alone produces many per second, and\n * the count grows with the number of installed plugins.\n *\n * This module keeps exactly ONE body observer per page. The registry lives on\n * `globalThis` under a `Symbol.for` key, so the per-package generated copies\n * of this file (scripts/sync-shared.mjs) and separately bundled plugins all\n * reach the same hub at runtime instead of one hub per module instance.\n * Record subscribers receive the mutations accumulated since the last flush.\n * Consumers that only re-check their DOM use subscribeBodyInvalidations:\n * when all subscribers use that path, the hub retains no mutation records\n * (or detached subtrees) while a background page's animation frames pause.\n * Both paths run at most once per frame. The last subscriber disconnects the\n * observer, cancels the pending frame and releases its records.\n *\n * Failure policy: without a DOM or `MutationObserver` the subscription is a\n * no-op disposer (the same silence the per-consumer observers had), and when\n * `requestAnimationFrame` is unavailable the flush runs synchronously so a\n * subscriber is never silently dropped. A throwing subscriber cannot stop the\n * others.\n */\n\n/** The page-wide hub: one observer plus its subscribers and pending records. */\ninterface BodyMutationHub {\n observer: MutationObserver\n subscribers: Set<(records: MutationRecord[]) => void>\n pending: MutationRecord[]\n scheduled: boolean\n frame?: number\n}\n\n/** Cross-bundle registry key; `Symbol.for` so every module copy agrees. */\nconst HUB_KEY = Symbol.for('dsh-web.body-mutation-hub')\nconst INVALIDATION_ONLY = Symbol.for('dsh-web.body-mutation-invalidation')\ntype Subscriber = ((records: MutationRecord[]) => void) & { [INVALIDATION_ONLY]?: true }\n\nfunction needsRecords(subscribers: Set<(records: MutationRecord[]) => void>): boolean {\n for (const listener of subscribers) {\n if (!(listener as Subscriber)[INVALIDATION_ONLY]) return true\n }\n return false\n}\n\n/**\n * Subscribe to a coalesced DOM re-check without retaining mutation records.\n * The marked wrapper also works with an older hub, which delivers records\n * that it simply ignores until a page reload picks up the updated hub.\n */\nexport function subscribeBodyInvalidations(subscriber: () => void): () => void {\n const listener: Subscriber = () => { subscriber() }\n listener[INVALIDATION_ONLY] = true\n return subscribeBodyMutations(listener)\n}\n\n/**\n * Subscribe to body-level childList mutations.\n * @param subscriber - called at most once per animation frame with the records\n * collected since the previous flush; must be safe to run repeatedly.\n * @returns the disposer removing this subscriber (and the observer when it was\n * the last one).\n */\nexport function subscribeBodyMutations(subscriber: (records: MutationRecord[]) => void): () => void {\n if (typeof globalThis === 'undefined' || typeof document === 'undefined') return () => {}\n if (typeof MutationObserver !== 'function') return () => {}\n const registry = globalThis as unknown as Record<symbol, unknown>\n let hub = registry[HUB_KEY] as BodyMutationHub | undefined\n if (hub === undefined) {\n const subscribers = new Set<(records: MutationRecord[]) => void>()\n const created: BodyMutationHub = {\n observer: undefined as unknown as MutationObserver,\n subscribers,\n pending: [],\n scheduled: false,\n }\n const flush = (): void => {\n created.frame = undefined\n created.scheduled = false\n const batch = created.pending\n created.pending = []\n for (const listener of [...subscribers]) {\n if (!subscribers.has(listener)) continue\n try {\n listener(batch)\n } catch {\n // One subscriber must never break the others; the next flush retries it.\n }\n }\n }\n const schedule = (): void => {\n if (created.scheduled) return\n created.scheduled = true\n if (typeof requestAnimationFrame === 'function') created.frame = requestAnimationFrame(flush)\n else flush()\n }\n created.observer = new MutationObserver((records) => {\n if (needsRecords(subscribers)) {\n for (const record of records) created.pending.push(record)\n }\n schedule()\n })\n created.observer.observe(document.body ?? document.documentElement, { childList: true, subtree: true })\n registry[HUB_KEY] = created\n hub = created\n }\n const active = hub\n active.subscribers.add(subscriber)\n let subscribed = true\n return () => {\n if (!subscribed) return\n subscribed = false\n active.subscribers.delete(subscriber)\n if (!needsRecords(active.subscribers)) active.pending = []\n if (active.subscribers.size === 0 && registry[HUB_KEY] === active) {\n active.observer.disconnect()\n if (active.frame !== undefined && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(active.frame)\n active.frame = undefined\n active.pending = []\n active.scheduled = false\n delete registry[HUB_KEY]\n }\n }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/panel-mount-core.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Center-column panel takeover lifecycle.\n *\n * The `conversation` slot is single-occupant (ui-conversation) and external\n * plugins cannot declare slots, so a family panel takes over the center\n * column at the DOM level: a container is appended inside the center column\n * (`[class*=\"centerCol\"]`, the 0.1.0-rc.6+ AppFrame layout; previously\n * `[data-pane=\"conversation\"]` on older shells — the mount selector keeps\n * both, ssh #243 / task-board #107) as an extra trailing child React never\n * manages, and a stylesheet rule hides the conversation content while the\n * panel is active. Toggling is a data attribute on <html> — no React\n * involvement, so the conversation subtree underneath stays mounted and\n * stateful.\n *\n * Consuming plugins keep a thin wrapper that supplies the panel tree,\n * container attribute names, and stylesheet class; those names are pinned by\n * each package's CSS, skins, and the semantic-attributes contract. The\n * sidebar row toggling the panel shares its core the same way\n * (shared/client/sidebar-entry-core.ts, synced copy).\n */\nimport { createRoot, type Root } from 'react-dom/client'\nimport { subscribeBodyInvalidations } from './body-mutations.ts'\n\n/** Options for mountCenterPanel; dsh-ssh mount.tsx and dsh-task-board board-mount.tsx are the canonical consumers. */\nexport interface CenterPanelMountOptions {\n /** Render the panel tree (first open, remount while open, locale refresh). */\n render: (root: Root) => void\n /** dataset key of the injected container's view attribute, e.g. `dshSshView` for `data-dsh-ssh-view`. */\n viewDatasetKey: string\n /** value of the container's L2 `data-dsh-plugin` semantic attribute. */\n pluginName: string\n /** stylesheet class applied to the injected container. */\n viewClassName: string\n /** <html> attribute set while this panel is active. */\n activeAttribute: string\n /** the sibling panel's active attribute, removed from <html> when this panel opens. */\n siblingActiveAttribute: string\n /** detail value this panel broadcasts on the cross-plugin activation event. */\n panelName: string\n /** sibling detail value whose activation closes this panel. */\n siblingPanelName: string\n /** open flag of the owning controller. */\n isOpen: () => boolean\n /** close the panel, handing the center column back to the conversation. */\n close: () => void\n /** subscribe to the owning controller's open-state changes; returns an unsubscriber. */\n subscribe: (listener: () => void) => () => void\n /** locale-change source; when given, re-renders an open panel on a Language switch. */\n locale?: { subscribe(listener: () => void): () => void }\n}\n\nconst CONVERSATION_COLUMN_SELECTOR = '[data-pane=\"conversation\"], [class*=\"centerCol\"]'\n/** Cross-plugin activation event; detail is the activating panel name. */\nconst ACTIVATE_EVENT = 'dsh-panel-activate'\n// Sidebar rows whose clicks hand the center column back to the conversation\n// (including the already-current row, which produces no session-change\n// event). Capture phase, so the panel closes before the shell processes the\n// click.\nconst SIDEBAR_ROW_SELECTOR = '[class*=\"sessionRow\"], [class*=\"projectRow\"], [class*=\"searchResultRow\"], [class*=\"searchResultWorkspace\"], [class*=\"newSession\"]'\n\n/** Find the center column, or undefined while the frame is not mounted. */\nfunction conversationColumn(): HTMLElement | undefined {\n return document.querySelector<HTMLElement>(CONVERSATION_COLUMN_SELECTOR) ?? undefined\n}\n\n/**\n * Mount a family panel into the center column and bind its visibility to the\n * owning controller's open state.\n * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountCenterPanel(options: CenterPanelMountOptions): () => void {\n let root: Root | undefined\n let container: HTMLDivElement | undefined\n let unsubscribeLocale: (() => void) | undefined\n try {\n unsubscribeLocale = options.locale?.subscribe(() => {\n if (root !== undefined) options.render(root)\n })\n } catch { /* locale service absent: the panel follows its next natural re-render */ }\n\n const ensure = (): void => {\n if (container !== undefined && !container.isConnected) {\n // The conversation pane was replaced; drop the stale tree and remount.\n root?.unmount()\n root = undefined\n container.remove()\n container = undefined\n }\n if (container === undefined) {\n const column = conversationColumn()\n if (column === undefined) return\n container = document.createElement('div')\n container.dataset[options.viewDatasetKey] = ''\n container.dataset.dshPlugin = options.pluginName\n container.className = options.viewClassName\n column.appendChild(container)\n }\n // Keep a visited tree mounted so drafts and terminal sessions survive\n // close/reopen; an unused panel needs neither a React root nor effects.\n if (root !== undefined || !options.isOpen()) return\n root = createRoot(container)\n options.render(root)\n }\n\n // The frame mounts after boot settlement; watch for the column's arrival.\n // The observation is the page-wide hub (shared/client/body-mutations.ts):\n // every family panel used to hold its own document.body subtree observer, so\n // the per-mutation cost grew with the number of installed plugins.\n const unsubscribeBody = subscribeBodyInvalidations(() => { ensure() })\n\n const applyActive = (): void => {\n if (options.isOpen()) {\n ensure()\n // Single-occupant center column: opening this panel must evict the\n // sibling panel, both its html attribute and its controller state,\n // otherwise the two panels' visibility rules fight and the second\n // click appears dead.\n document.documentElement.removeAttribute(options.siblingActiveAttribute)\n document.documentElement.setAttribute(options.activeAttribute, '')\n document.dispatchEvent(new CustomEvent(ACTIVATE_EVENT, { detail: options.panelName }))\n } else {\n document.documentElement.removeAttribute(options.activeAttribute)\n }\n }\n const onOtherActivate = (event: Event): void => {\n if ((event as CustomEvent).detail === options.siblingPanelName && options.isOpen()) {\n options.close()\n }\n }\n const onClickSidebarRow = (event: MouseEvent): void => {\n if (!options.isOpen()) return\n const target = event.target as HTMLElement | null\n if (target === null) return\n if (target.closest(SIDEBAR_ROW_SELECTOR) !== null) options.close()\n }\n document.addEventListener('click', onClickSidebarRow, true)\n document.addEventListener(ACTIVATE_EVENT, onOtherActivate)\n const unsubscribe = options.subscribe(applyActive)\n applyActive()\n ensure()\n\n return () => {\n document.removeEventListener('click', onClickSidebarRow, true)\n document.removeEventListener(ACTIVATE_EVENT, onOtherActivate)\n unsubscribeBody()\n unsubscribe()\n unsubscribeLocale?.()\n document.documentElement.removeAttribute(options.activeAttribute)\n root?.unmount()\n root = undefined\n container?.remove()\n container = undefined\n }\n}\n","/**\n * Board view mounting (dsh-task-board wrapper).\n *\n * The single-occupant takeover lifecycle — container injection into the\n * center column, sibling eviction, remount resilience, sidebar click-out —\n * lives exactly once in shared/client/panel-mount-core.ts (synced copy); this\n * wrapper supplies the board tree, view dataset key, CSS module, and the html\n * attribute names. Those names are pinned by board.module.css, skins, and the\n * semantic attributes contract.\n */\nimport type { BoardController } from '../core/controller.ts'\nimport { TaskBoard } from './board/TaskBoard.tsx'\nimport { mountCenterPanel } from './panel-mount-core.ts'\nimport type { LocaleRefreshSource } from './sidebar-entry.ts'\nimport css from './board.module.css'\n\n/** The injected board container (kept in the DOM, hidden when inactive). */\nexport const BOARD_VIEW_SELECTOR = '[data-dsh-taskboard-view]'\n\n/**\n * Mount the board React tree into the center column and bind its visibility\n * to the controller's boardOpen state.\n * @param controller - the board controller driving the view.\n * @param locale - locale-change source; when given, re-renders a mounted board\n * on a Language switch.\n * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountBoard(controller: BoardController, locale?: LocaleRefreshSource): () => void {\n return mountCenterPanel({\n render: root => root.render(<TaskBoard controller={controller} />),\n viewDatasetKey: 'dshTaskboardView',\n pluginName: 'task-board',\n viewClassName: css.boardView,\n activeAttribute: 'data-dsh-taskboard-active',\n siblingActiveAttribute: 'data-dsh-ssh-active',\n panelName: 'taskboard',\n siblingPanelName: 'ssh',\n isOpen: () => controller.getSnapshot().boardOpen,\n close: () => controller.closeBoard(),\n subscribe: listener => controller.subscribe(listener),\n locale,\n })\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/sidebar-entry-core.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Shared sidebar entry injection core.\n *\n * dsh's sidebar shell exposes no slot an external plugin can register into,\n * so the entry row is injected between the shell's New Session button and the\n * workspace browser. The injection self-heals: a MutationObserver watches the\n * sidebar root and re-inserts the row whenever a React re-render displaces it\n * (re-insertion happens in the same frame, before paint, so no flicker).\n *\n * The row is plain DOM (no React tree) so it can never disturb the shell's\n * reconciliation; the view it toggles is a separate root owned by the caller.\n *\n * Packages receive this file as a generated copy via scripts/sync-shared.mjs;\n * edit the shared source and re-run the sync instead of editing a copy.\n */\nimport { subscribeBodyInvalidations } from './body-mutations.ts'\n\n/** Per-package configuration for one sidebar entry row. */\nexport interface SidebarEntryOptions {\n /** Full attribute name identifying the injected row (idempotency key), e.g. 'data-dsh-ssh-entry'. */\n rowAttribute: string\n /** CSS selector matching the injected row, e.g. '[data-dsh-ssh-entry]'. */\n rowSelector: string\n /**\n * L2 semantic-attribute plugin id (issue #506, enum table:\n * skins/skin-center/contracts/semantic-attrs-v1.md). When set, the row also\n * outputs data-dsh-plugin=\"<id>\" and data-dsh-part=\"sidebar-entry\"; unset\n * leaves the row without semantic attributes.\n */\n plugin?: string\n /** Inline icon markup (matches the shell's 16px nav-icon look). */\n icon: string\n /** CSS module class names for the row and its two spans (entry / entryIcon / entryLabel). */\n css: Record<string, string>\n /** Localized row label (aria-label + visible text). */\n label(): string\n /** Optional localized tooltip (title attribute). */\n tooltip?(): string\n /**\n * Optional locale-change subscription: re-applies label / aria-label /\n * tooltip whenever the active locale changes. Plain-DOM rows would\n * otherwise keep the label captured at mount; pass the SDK locale runtime\n * subscription (ctx.locale.subscribe) so the row follows the language\n * switch without a reload.\n */\n refresh?: { subscribe(listener: () => void): () => void }\n /** Click action (open/toggle the owning panel). */\n onToggle(): void\n /** Family-block position: 'before' inserts ahead of sibling plugin rows, 'after' behind them. */\n position: 'before' | 'after'\n /**\n * Selectors of the sibling plugin entry rows this package orders against\n * (its own row included — the placement guard excludes a row that is\n * already inside the root). Each package passes the same list it used\n * before the consolidation so the rendered order stays stable.\n */\n familySelectors: readonly string[]\n /** Optional active-state bridge; highlights the row while the panel is open. */\n active?: {\n subscribe(listener: () => void): () => void\n isOpen(): boolean\n }\n}\n\n/** Find the sidebar shell root element, or undefined while not yet mounted. */\nfunction sidebarRoot(): HTMLElement | undefined {\n const column = document.querySelector<HTMLElement>('[data-pane=\"sidebar\"], [class*=\"sidebarCol\"]')\n if (column === null) return undefined\n // Current shells wrap the sidebar UI: column > wrapper > root(logoRow owner).\n // Prefer the element that owns the logo row — the real sidebar UI root —\n // and fall back to the column's first child for legacy shells.\n const logoOwner = column.querySelector<HTMLElement>('[class*=\"logoRow\"]')?.parentElement\n return logoOwner ?? (column.firstElementChild as HTMLElement | undefined)\n}\n\n/** The New Session button: nested in the logo row on current shells, a direct child on legacy shells. */\nfunction newSessionButton(root: HTMLElement): HTMLButtonElement | undefined {\n const nested = root.querySelector<HTMLButtonElement>('button[class*=\"newSession\"]')\n if (nested !== null) return nested\n for (const child of root.children) {\n if (child.tagName === 'BUTTON') return child as HTMLButtonElement\n }\n return undefined\n}\n\n/** Build the entry row (detached; inserted once the shell is up). */\nfunction createEntry(options: SidebarEntryOptions): { entry: HTMLElement; applyLabel: () => void } {\n const entry = document.createElement('button')\n entry.type = 'button'\n entry.setAttribute(options.rowAttribute, '')\n if (options.plugin !== undefined) {\n entry.setAttribute('data-dsh-plugin', options.plugin)\n entry.setAttribute('data-dsh-part', 'sidebar-entry')\n }\n entry.className = options.css['entry'] ?? ''\n const labelSpan = document.createElement('span')\n labelSpan.className = options.css['entryLabel'] ?? ''\n const iconSpan = document.createElement('span')\n iconSpan.className = options.css['entryIcon'] ?? ''\n iconSpan.innerHTML = options.icon\n entry.append(iconSpan, labelSpan)\n const applyLabel = (): void => {\n entry.setAttribute('aria-label', options.label())\n if (options.tooltip !== undefined) entry.setAttribute('title', options.tooltip())\n labelSpan.textContent = options.label()\n }\n applyLabel()\n entry.addEventListener('click', options.onToggle)\n return { entry, applyLabel }\n}\n\n/** Re-insert the entry after the New Session row (before the browser region). */\nfunction placeEntry(root: HTMLElement, entry: HTMLElement, options: SidebarEntryOptions): boolean {\n const button = newSessionButton(root)\n if (button === undefined) return false\n if (entry.parentElement !== root) {\n // Position relative to the family block (entries injected by sibling\n // plugins), never relative to transient logoRow geometry: every family\n // plugin that self-heals during a re-render then lands in the same\n // relative order, so the entries cannot swap positions regardless of\n // observer callback order or of shell wrapper changes. There is no\n // append-to-end fallback: appending at the end would randomly reorder\n // the block after a shell re-render.\n const row = button.closest('[class*=\"logoRow\"]')\n const base = (row !== null && row.parentElement === root) ? row : button\n const family = Array.from(root.children).filter(\n (el): el is HTMLElement => el instanceof HTMLElement && el.matches(options.familySelectors.join(', ')),\n )\n const anchor = options.position === 'before'\n ? (family.length > 0 ? family[0] : base.nextElementSibling)\n : (family.length > 0 ? family[family.length - 1]!.nextElementSibling : base.nextElementSibling)\n root.insertBefore(entry, anchor)\n }\n return true\n}\n\n/**\n * Mount the sidebar entry, waiting for the shell to render and self-healing\n * on later React re-renders.\n * @param options - the row's attribute/icon/copy/action/ordering configuration.\n * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(options: SidebarEntryOptions): () => void {\n // DOM-level idempotency: whatever path mounted an entry row before this\n // call (a duplicated apply, an HMR re-injection, a stale module still\n // alive), never mount a second one. The existing row keeps working; a full\n // page reload is the ultimate reset.\n if (typeof document !== 'undefined' && document.querySelector(options.rowSelector) !== null) {\n return () => {}\n }\n const { entry, applyLabel } = createEntry(options)\n let root: HTMLElement | undefined\n let placed = false\n let unsubscribeRefresh: (() => void) | undefined\n if (options.refresh !== undefined) {\n try {\n unsubscribeRefresh = options.refresh.subscribe(applyLabel)\n } catch {\n // A throwing subscription must not break the mount; the label stays at\n // its initial value and the next reload resolves it again.\n }\n }\n\n const tryPlace = (): void => {\n if (root !== undefined && !root.isConnected) {\n // The shell rebuilt the sidebar pane (whole-tree teardown); the root\n // observer is gone with the old tree, so detach it and re-query from\n // scratch. The new pane is later noticed by the body-level watcher.\n rootObserver.disconnect()\n root = undefined\n placed = false\n }\n if (placed) {\n // Cheap short-circuit: entry still lives in a mountable subtree.\n if (document.body.contains(entry)) return\n // Entry was torn down together with the old tree; reset and re-place.\n rootObserver.disconnect()\n root = undefined\n placed = false\n }\n root ??= sidebarRoot()\n if (root === undefined) return\n placed = placeEntry(root, entry, options)\n if (placed) {\n rootObserver.observe(root, { childList: true, subtree: true })\n }\n }\n\n // Body-level watcher retained as the \"whole rebuild\" fallback: when the shell\n // tears down the whole sidebar pane, the root observer is gone with it and\n // only this body observation can notice the new pane mounting. It stays\n // subscribed after placement; the placed-and-still-mounted case\n // short-circuits through the cheap document.body.contains(entry) check, so\n // unrelated app mutations (e.g. chat streaming) cost one contains check per\n // frame instead of churning the full re-query. The body observation itself is\n // the page-wide hub (shared/client/body-mutations.ts): every family plugin\n // used to hold its own body subtree observer, so the per-mutation cost grew\n // with the number of installed plugins; the hub keeps exactly one.\n const unsubscribeBody = subscribeBodyInvalidations(() => { tryPlace() })\n\n // Self-heal: if a React re-render displaces the row, re-insert it in the\n // same frame (microtask before paint -> no visible flicker).\n const rootObserver = new MutationObserver(() => {\n if (root === undefined || !root.isConnected) {\n placed = false\n tryPlace()\n return\n }\n if (!root.contains(entry)) {\n placed = placeEntry(root, entry, options)\n }\n })\n\n // Reflect the panel's open state on the row (active highlight). Note: assigning\n // undefined to dataset.active materializes data-active=\"undefined\" and keeps the\n // row permanently highlighted — delete the attribute instead.\n const unsubscribeActive = options.active === undefined ? undefined : (() => {\n const syncActive = (): void => {\n if (options.active!.isOpen()) entry.dataset.active = 'true'\n else delete entry.dataset.active\n }\n const unsubscribe = options.active.subscribe(syncActive)\n syncActive()\n return unsubscribe\n })()\n\n tryPlace()\n\n return () => {\n unsubscribeBody()\n rootObserver.disconnect()\n unsubscribeRefresh?.()\n unsubscribeActive?.()\n entry.remove()\n }\n}\n","/**\n * Sidebar entry injection — package-specific wiring over the shared core.\n *\n * dsh's sidebar shell exposes no slot an external plugin can register into\n * (`sidebar.workspaces` / `sidebar.settings` are single-occupant and already\n * taken), so the entry row is injected between the shell's New Session button\n * and the workspace browser. The DOM injection / self-healing / idempotency\n * logic lives exactly once in shared/client/sidebar-entry-core.ts (synced\n * copy); this wrapper supplies the task-board icon, copy, CSS module, and the\n * board toggle. The row is plain DOM (no React tree); the board view it\n * toggles is a separate React root mounted in the center column\n * (see board-mount.ts).\n */\nimport type { BoardController } from '../core/controller.ts'\nimport { t } from './locales.ts'\nimport css from './board.module.css'\nimport { mountSidebarEntry as mountSharedSidebarEntry } from './sidebar-entry-core.ts'\n\n/** Stable data attribute identifying the injected entry row. */\nexport const ENTRY_SELECTOR = '[data-dsh-taskboard-entry]'\n\n/** Inline icon normalized to the shell's 16px navigation glyph size. */\nconst ICON = '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"2\" y=\"2.5\" width=\"12\" height=\"11\" rx=\"1.5\"/><path d=\"M2 6.5h12M6.5 6.5v7\"/></svg>'\n\n/** Locale-change subscription the shared core asks for (ctx.locale.subscribe shape). */\nexport interface LocaleRefreshSource { subscribe(listener: () => void): () => void }\n\n/**\n * Mount the sidebar entry, waiting for the shell to render and self-healing\n * on later React re-renders.\n * @param controller - the board controller the entry toggles.\n * @param locale - locale-change source; when given, re-applies the label on\n * a Language switch (the plain-DOM row otherwise keeps the mount-time copy).\n * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(controller: BoardController, locale?: LocaleRefreshSource): () => void {\n return mountSharedSidebarEntry({\n rowAttribute: 'data-dsh-taskboard-entry',\n rowSelector: ENTRY_SELECTOR,\n plugin: 'task-board',\n icon: ICON,\n css,\n label: () => t('entry.label'),\n refresh: locale === undefined ? undefined : { subscribe: (listener) => locale.subscribe(listener) },\n onToggle: () => { controller.toggleBoard() },\n position: 'before',\n familySelectors: ['[data-dsh-taskboard-entry]', '[data-dsh-ssh-entry]'],\n active: {\n subscribe: (listener) => controller.subscribe(listener),\n isOpen: () => controller.getSnapshot().boardOpen,\n },\n })\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/PluginSettingsCard.tsx. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family-shared chrome for plugin settings cards: a disclosure header naming\n * the plugin and what its settings govern, the controls inside, and the save\n * that writes them. Renders nothing while the namespace is unavailable — a\n * deployment that does not compose the owning plugin should show no trace of\n * it. Inlined into each consumer's client bundle; mirrors the official\n * ui-plugin-config PluginCard in a self-contained slice.\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'\nimport type { CardShell } from './settings-form.ts'\nimport css from './settings-card.module.css'\n\n/** Copy keys the card chrome itself reads; every consumer locale carries this shared vocabulary. */\nexport const CARD_COPY_KEYS = [\n 'settings.collapse',\n 'settings.expand',\n 'settings.notExposed',\n 'settings.unsaved',\n 'settings.readOnly',\n 'settings.saveFailed',\n 'settings.discard',\n 'settings.save',\n 'settings.saving',\n] as const\n\n/** Copy key the card chrome itself reads. */\nexport type CardCopyKey = (typeof CARD_COPY_KEYS)[number]\n\n/** Key domain for the plugin's own copy (inferred per consumer). */\nexport type SettingsCardKey<TKey extends string = string> = TKey | CardCopyKey\n\n/** Card chrome shared by every plugin settings card. */\nexport interface PluginSettingsCardProps<TKey extends string = string> {\n /** Locale reader for this card's copy. */\n t: (key: SettingsCardKey<TKey>, params?: Record<string, string | number>) => string\n /** Locale key of the plugin's name. */\n titleKey: TKey\n /** Locale key of the line describing what this plugin's settings govern. */\n descriptionKey: TKey\n /** Optional rich header description rendered instead of the plain t(descriptionKey) text (the plain text stays as the tooltip). */\n descriptionNode?: ReactNode\n /** The card's form state: availability, writability, and what a save would do. */\n state: CardShell\n /** Write every staged edit. */\n onSave: () => void\n /** Drop every staged edit. */\n onDiscard: () => void\n /**\n * Render the controls expanded on arrival (still collapsible). Defaults to\n * true: promoted first-level sections show their settings immediately.\n */\n defaultOpen?: boolean\n /**\n * Render without the collapse affordance: a static header and an always\n * visible body. Used by first-level settings sections whose nav entry\n * already provides the selection.\n */\n alwaysOpen?: boolean\n /**\n * Hide the save/discard footer: cards whose body applies its own changes\n * immediately (an embedded external settings section) have no staged\n * edits, so the footer would sit there permanently disabled.\n */\n hideFooter?: boolean\n /** Render children even when the settings namespace is not exposed by the host. */\n renderChildrenWhenNotExposed?: boolean\n /** Hide the 'not exposed' warning banner when the settings namespace is not exposed. */\n hideNotExposedNotice?: boolean\n /** The plugin's controls. */\n children: ReactNode\n}\n\n/**\n * Render one plugin settings card.\n * @param props - the plugin's copy keys, its form state, and its controls.\n * @returns the card, or nothing while the namespace is still loading.\n */\nexport function PluginSettingsCard<TKey extends string = string>(props: PluginSettingsCardProps<TKey>) {\n const [open, setOpen] = useState(props.defaultOpen ?? true)\n const { state, alwaysOpen } = props\n if (!state.available) return null\n const title = props.t(props.titleKey)\n const description = props.t(props.descriptionKey)\n const blocked = !state.dirty || state.invalid || state.saving\n const expanded = alwaysOpen === true || open\n const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card\n // With alwaysOpen the nav entry already provides the selection, so the\n // header is a static title row instead of a disclosure button.\n const header = alwaysOpen === true\n ? (\n <div className={css.headerStatic}>\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{props.descriptionNode ?? description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n </div>\n )\n : (\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name} title={title}>{title}</span>\n <span className={css.description} title={description}>{props.descriptionNode ?? description}</span>\n </span>\n {state.dirty ? <span className={css.pending} title={props.t('settings.unsaved')}>{props.t('settings.unsaved')}</span> : null}\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.chevron} ${css.chevronOpen}` : css.chevron}\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n )\n // The namespace exists but the Host does not serve it to this client (the\n // official settings allowlist omits third-party namespaces): show a card\n // that explains the gap instead of vanishing, so a missing card never\n // reads as a missing plugin.\n if (!state.exposed && props.renderChildrenWhenNotExposed !== true) {\n const showNotice = props.hideNotExposedNotice !== true\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {showNotice ? <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p> : null}\n </div>\n )\n : null}\n </li>\n )\n }\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n {!state.writable ? <p className={css.readOnly} role=\"status\">{props.t('settings.readOnly')}</p> : null}\n {props.children}\n {props.hideFooter === true\n ? null\n : (\n <div className={css.footer}>\n {state.failed\n ? (\n <p className={css.failed} role=\"status\">\n {props.t('settings.saveFailed')}{state.failedReason ? ' - ' + state.failedReason : ''}\n </p>\n )\n : null}\n <button\n type=\"button\"\n className={css.discard}\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('settings.discard')}\n </button>\n <button\n type=\"button\"\n className={css.save}\n disabled={blocked}\n onClick={props.onSave}\n >\n {props.t(!state.saving ? 'settings.save' : 'settings.saving')}\n </button>\n </div>\n )}\n </div>\n )\n : null}\n </li>\n )\n}\n\n/** Props every field control needs regardless of its value type. */\nexport interface FieldProps {\n /** Stable id associating the label with its control. */\n id: string\n /** Visible label. */\n label: string\n /** One-line explanation rendered under the control. */\n hint: string\n /** Draft text this control renders. */\n text: string\n /** True when saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** True when the draft is not a value this field accepts. */\n invalid: boolean\n /** Copy for the overridden badge. */\n overriddenLabel: string\n /** Copy for the reset control. */\n resetLabel: string\n /** Copy shown in place of the hint while the draft is invalid. */\n invalidLabel: string\n /** Disables every control (read-only document, or an unavailable namespace). */\n disabled: boolean\n /** Stage draft text. */\n onEdit: (text: string) => void\n /** Stage a clear so the field re-inherits the composition layer. */\n onReset: () => void\n}\n\n/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */\nexport function ValueField(props: FieldProps & {\n /** Hints a numeric keypad without narrowing what the control accepts. */\n numeric?: boolean\n /** Placeholder shown while the draft is empty. */\n placeholder?: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? css.inputInvalid : css.input}\n type=\"text\"\n {...props.numeric === true ? { inputMode: 'numeric' as const } : {}}\n {...props.invalid ? { 'aria-invalid': true } : {}}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n\nconst NON_SKIN_BODY_MARKERS = new Set(['dshSkinCenter', 'dshSidebarCollapsed'])\n// 检测使用使用皮肤,用了皮肤退回原生select样式,防止样式冲突。默认外观下使用优化后的select样式。\nfunction isSkinActive(): boolean {\n const datasetList = Object.keys(document.body.dataset)\n const isActive = datasetList.some(key => key.startsWith('dsh') && !NON_SKIN_BODY_MARKERS.has(key))\n return isActive\n}\n\ninterface SelectOption {\n value: string\n label: string\n}\n\nconst SELECT_CLOSE_MS = 100\n\n/**\n * The shared dual-mode select control. While an appearance skin is active it\n * renders the legacy native `<select>` untouched, so element-level skin\n * selectors keep working; under the default appearance it renders a\n * self-drawn `role=\"listbox\"` popup whose open/close is transition-animated.\n * Staged cards reach it through BooleanField/ChoiceField; immediate-apply\n * editors (the side-card prefs) bind it directly through onEdit.\n * 双模式下拉框:皮肤激活时用原生 select,默认外观用自绘动画弹层。\n */\nexport function SelectField(props: {\n id: string\n options: ReadonlyArray<SelectOption>\n value: string\n disabled: boolean\n invalid: boolean\n onEdit: (text: string) => void\n}) {\n const { id, options, value } = props\n const [open, setOpen] = useState(false)\n const [closing, setClosing] = useState(false)\n const [phase, setPhase] = useState<'initial' | 'open'>('initial')\n const [activeIndex, setActiveIndex] = useState(0)\n const closeTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const popupRef = useRef<HTMLDivElement | null>(null)\n\n const currentIndex = () => {\n const index = options.findIndex(option => option.value === value)\n return index >= 0 ? index : 0\n }\n\n const close = useCallback(() => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setClosing(true)\n closeTimer.current = setTimeout(() => {\n setClosing(false)\n setOpen(false)\n }, SELECT_CLOSE_MS)\n }, [])\n\n const openPopup = () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n setActiveIndex(currentIndex())\n setPhase('initial')\n setClosing(false)\n setOpen(true)\n }\n\n const commit = (index: number) => {\n const option = options[index]\n if (option) props.onEdit(option.value)\n close()\n }\n\n const onTriggerClick = () => {\n if (props.disabled) return\n if (open && !closing) close()\n else openPopup()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (props.disabled) return\n const count = options.length\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Enter':\n case ' ':\n event.preventDefault()\n if (!open) {\n openPopup()\n } else if (!closing) {\n if (event.key === 'ArrowDown') setActiveIndex(index => (index + 1) % count)\n else if (event.key === 'ArrowUp') setActiveIndex(index => (index - 1 + count) % count)\n else commit(activeIndex)\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation()\n close()\n }\n break\n case 'Tab':\n if (open) close()\n break\n }\n }\n\n useEffect(() => () => {\n if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)\n }, [])\n useLayoutEffect(() => {\n if (open && !closing && phase === 'initial') {\n void popupRef.current?.offsetHeight\n setPhase('open')\n }\n }, [open, closing, phase])\n\n useEffect(() => {\n if (!open) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target\n if (target instanceof Node && !wrapRef.current?.contains(target)) close()\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => document.removeEventListener('pointerdown', onPointerDown)\n }, [open, close])\n\n useEffect(() => {\n if (props.disabled && open) close()\n }, [props.disabled, open, close])\n\n // 使用了皮肤则退回原生select样式防止样式冲突。\n if (isSkinActive()) {\n return (\n <select\n id={id}\n className={css.select}\n value={value}\n disabled={props.disabled}\n onChange={(event) => { props.onEdit(event.target.value) }}\n >\n {options.map(option => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n )\n }\n\n const label = options.find(option => option.value === value)?.label ?? ''\n const popupClass = closing\n ? `${css.selectPopup} ${css.selectPopupClose}`\n : phase === 'open'\n ? `${css.selectPopup} ${css.selectPopupOpen}`\n : css.selectPopup\n return (\n <div className={css.selectWrap} ref={wrapRef}>\n <button\n type=\"button\"\n id={id}\n className={`${css.select} ${css.selectButton}`}\n disabled={props.disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-activedescendant={open ? `${id}-o${activeIndex}` : undefined}\n aria-invalid={props.invalid || undefined}\n onClick={onTriggerClick}\n onKeyDown={onKeyDown}\n >\n <span className={css.selectLabel}>{label}</span>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={open ? `${css.selectChevron} ${css.selectChevronOpen}` : css.selectChevron}\n aria-hidden=\"true\"\n >\n <path\n d=\"M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n {open\n ? (\n <div className={popupClass} role=\"listbox\" ref={popupRef}>\n {options.map((option, index) => (\n <div\n key={option.value}\n id={`${id}-o${index}`}\n role=\"option\"\n aria-selected={option.value === value}\n className={`${css.selectOption}${option.value === value ? ` ${css.selectOptionSelected}` : ''}${index === activeIndex && !closing ? ` ${css.selectOptionActive}` : ''}`}\n onClick={() => { commit(index) }}\n >\n {option.label}\n </div>\n ))}\n </div>\n )\n : null}\n </div>\n )\n}\n\n/** A staged boolean field: 继承 / 开 / 关. */\nexport function BooleanField(props: FieldProps & {\n /** Copy for the inherit option. */\n inheritLabel: string\n /** Copy for the on option. */\n onLabel: string\n /** Copy for the off option. */\n offLabel: string\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[\n { value: '', label: props.inheritLabel },\n { value: 'true', label: props.onLabel },\n { value: 'false', label: props.offLabel },\n ]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={css.hint}>{props.hint}</p>\n </div>\n )\n}\n\n/** A staged enumerated field rendered as a select. */\nexport function ChoiceField(props: FieldProps & {\n /** Copy for the inherit option (draft text is the empty string). */\n inheritLabel: string\n /** Choices rendered in order; `value` is the draft/stored text. */\n choices: ReadonlyArray<{ value: string; label: string }>\n}) {\n return (\n <div className={css.field}>\n <div className={css.head}>\n <label className={css.label} htmlFor={props.id}>{props.label}</label>\n {props.overridden\n ? (\n <span className={css.badges}>\n <span className={css.badge}>{props.overriddenLabel}</span>\n <button\n type=\"button\"\n className={css.reset}\n disabled={props.disabled}\n onClick={props.onReset}\n >\n {props.resetLabel}\n </button>\n </span>\n )\n : null}\n </div>\n <SelectField\n id={props.id}\n options={[{ value: '', label: props.inheritLabel }, ...props.choices]}\n value={props.text}\n disabled={props.disabled}\n invalid={props.invalid}\n onEdit={props.onEdit}\n />\n <p className={props.invalid ? css.invalid : css.hint}>\n {props.invalid ? props.invalidLabel : props.hint}\n </p>\n </div>\n )\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/settings-form.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Staged form model behind the plugin settings card. A card stages what the\n * user types and writes it only when they save — the settings write is a\n * durable, revision-fenced document mutation, so staging keeps what is on\n * screen exactly what a save would store. Family-shared slice inlined into\n * each plugin's client bundle; mirrors the official ui-plugin-config\n * card-store pattern.\n */\n\nimport type { ConfigForm, ConfigFormSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-store'\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite =\n | { kind: 'set'; value: unknown }\n | { kind: 'clear' }\n\n/** How one field converts between its stored value and its draft text. */\nexport interface FieldSpec {\n /** Field name inside the namespace section. */\n field: string\n /**\n * Whether the Host treats this field as a secret and redacts its value from\n * the read-back (role('secret') in the section schema). Redacted secrets are\n * never compared against the draft on save: the Host strips them from every\n * wire view layer, so the settled snapshot carries nothing to read back. A\n * staged secret set is judged by the mutation settling; the rest of its\n * batch, when one exists, is still judged by read-back, and the atomic\n * mutation lands every write or none.\n */\n secret?: boolean\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined\n}\n\n/** One field as the card renders it. */\nexport interface FieldState {\n /** Draft text the control renders. */\n text: string\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean\n}\n\n/** Form state every plugin settings card shares. */\nexport interface CardShell {\n /** False while the namespace is still loading; the card renders nothing. */\n available: boolean\n /**\n * Whether the namespace is actually served to this client. False when the\n * Host deployment does not expose it (e.g. the owning plugin's settings\n * domain is not mounted): the card renders an explanation\n * instead of its form, so a missing namespace never looks like a missing\n * plugin.\n */\n exposed: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the form holds edits that a save would write. */\n dirty: boolean\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean\n /** Whether a save is crossing the wire. */\n saving: boolean\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean\n /**\n * The rejection code/message the Host returned for the last failed save,\n * surfaced next to the generic failure text. Undefined while no save has\n * failed (or the failure carried no server reason).\n */\n failedReason?: string\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void\n /** Drop every staged edit. */\n discard: () => void\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean\n}\n\n/** One staged edit resolved into the write a save performs. */\ninterface PlannedWrite {\n /** Field this entry writes. */\n field: string\n /** The durable write this entry performs, inside the save's one atomic mutation. */\n op: BatchedWrite\n /**\n * Read the settled snapshot back and report whether the Host holds this\n * write's effect. Undefined when the draft is not a value the field\n * accepts: there is nothing to write, and the entry blocks the save.\n */\n judge: (() => boolean) | undefined\n}\n\n/** One durable write inside the save's atomic form mutation. */\nexport interface BatchedWrite {\n /** Field this entry writes. */\n field: string\n /** set stores a value; unset drops the leaf. */\n op: 'set' | 'unset'\n /** Value for op set (absent for unset). */\n value?: unknown\n}\n\n/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */\nexport interface NumberConstraints {\n /** The accepted value must be a whole number. */\n integer?: boolean\n /** The accepted value must be at least this. */\n min?: number\n}\n\n/** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */\nexport function numberField(field: string, constraints: NumberConstraints = {}): FieldSpec {\n const { integer = false, min } = constraints\n return {\n field,\n format: value => typeof value === 'number' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return undefined\n if (integer && !Number.isInteger(parsed)) return undefined\n if (min !== undefined && parsed < min) return undefined\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A free-text field. An empty draft clears the field. */\nexport function textField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' ? value : '',\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A free-text field the Host treats as a secret and redacts from the read-back\n * (role('secret') in the section schema). The card still edits it like text,\n * but a save never compares the redacted value back: the staged set is judged\n * by the mutation settling (see {@link FieldSpec.secret}).\n */\nexport function secretField(field: string): FieldSpec {\n return { ...textField(field), secret: true }\n}\n\n/** A boolean field, edited through true/false draft text. */\nexport function booleanField(field: string): FieldSpec {\n return {\n field,\n format: value => typeof value === 'boolean' ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n },\n }\n}\n\n/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */\nexport function choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: value => typeof value === 'string' && choices.includes(value) ? value : '',\n parse: (text) => {\n if (text === '') return { kind: 'clear' }\n return choices.includes(text) ? { kind: 'set', value: text } : undefined\n },\n }\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted — its\n * validators own the constraints no schema can express — so the outcome is\n * read back from the section rather than predicted here. A save that did not\n * land keeps its drafts, so the user can correct them instead of retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, FieldSpec>\n private readonly staged = new Map<string, StagedEdit>()\n private readonly listeners = new Set<() => void>()\n /** The form subscription installed in the constructor; released by dispose(). */\n private readonly disposeForm: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound configuration form for this card's namespace. */\n constructor(\n private readonly scope: ConfigForm<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeForm = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the form subscription and every bound store listener. The card\n * must call this on teardown; later calls are no-ops.\n */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.disposeForm()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the form or a draft changes. */\n bind<S>(project: () => S): SnapshotStore<S> {\n const store = createSnapshotStore(project())\n this.listeners.add(() => { store.set(project()) })\n return store\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status !== 'loading',\n exposed: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some(item => item.judge === undefined),\n saving: this.saving,\n failed: this.failed,\n ...this.failedReason === undefined ? {} : { failedReason: this.failedReason },\n }\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): FieldState {\n const spec = this.specOf(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n }\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => { this.stage(field, { text, clear: false }) },\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true })\n },\n save: () => { void this.save() },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.failed = false\n this.failedReason = undefined\n this.publish()\n },\n }\n }\n\n /**\n * Write every staged edit in one atomic form mutation, then re-seed from\n * what the Host accepted.\n *\n * The whole batch rides one mutate, so cross-field validate hooks\n * (baseURL+model) judge it as a unit: the Host either applies every write\n * or refuses the batch. The form contract answers a refusal or a skipped\n * write with `false` (it recovers with a fresh Host view instead of\n * throwing), so the outcome is judged twice: the answer itself, and then the\n * settled snapshot read back one planned write at a time. One missed write\n * fails the whole save. A transport that rejects instead (the dsh-web bridge\n * controller on a dead connection) reports through the same failure path\n * with its rejection message. A save that did not land keeps its drafts, so\n * the user can correct them instead of retyping.\n * @returns settlement after the mutation and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter((item): item is PlannedWrite & { judge: () => boolean } => item.judge !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n // Snapshot the staged entries this save writes, so an edit staged while it\n // is in flight (which replaces the same key) survives: only delete the key\n // when the entry is still the one this save started from.\n const pending = new Map<string, StagedEdit | undefined>()\n for (const item of plan) pending.set(item.field, this.staged.get(item.field))\n this.saving = true\n this.failed = false\n this.failedReason = undefined\n this.publish()\n // One atomic namespace mutation: the form contract takes ordered path\n // operations, so the whole staged batch is validated, persisted, and\n // recovered together — either every write lands or none does.\n const ops: Array<{ op: 'set'; path: string[]; value: string | number | boolean } | { op: 'unset'; path: string[] }> = valid.map(item => item.op.op === 'set'\n ? { op: 'set', path: [item.field], value: (item.op as { value: string | number | boolean }).value }\n : { op: 'unset', path: [item.field] })\n let failedReason: string | undefined\n let accepted = false\n try {\n accepted = await this.scope.mutate(ops)\n } catch (error) {\n failedReason = error instanceof Error ? error.message : String(error)\n }\n // `false` is the contract's refusal/skip answer, and the form still\n // resolves after a refusal (it recovers with a fresh view), so the answer\n // alone is not enough: judge every planned write against the settled\n // snapshot as well. The mutation is atomic, so one missed write fails the\n // whole save and keeps the drafts.\n const landed = accepted && failedReason === undefined && valid.every(item => item.judge())\n for (const [field, before] of pending) {\n if (landed && this.staged.get(field) === before) this.staged.delete(field)\n }\n this.saving = false\n this.failed = !landed\n // A refused or unlanded batch carries no server reason: the card surfaces\n // its generic failure copy; a rejecting transport (the bridge) adds its\n // message.\n this.failedReason = failedReason\n this.publish()\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n * @returns the planned writes, in the order the fields were staged.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, op: { field, op: 'unset' }, judge: () => this.landedUnset(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, op: { field, op: 'unset' }, judge: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, judge: () => this.landedUnset(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, judge: () => this.landedSet(field, write.value) })\n }\n return plan\n }\n\n /**\n * Read-back judgment for a planned set: the user layer must hold the\n * intended value once the mutation has settled.\n */\n private landedSet(field: string, value: unknown): boolean {\n // A redacted secret never appears in any wire view layer: the Host strips\n // role('secret') fields and reports them through a sidecar the form\n // snapshot does not expose, so there is nothing to compare the draft\n // against. Settling is the only signal the form has; the rest of the\n // batch, when one exists, still carries the atomic verdict by read-back.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\n }\n\n /**\n * Read-back judgment for a planned unset: the field must be gone from the\n * user layer once the mutation has settled.\n */\n private landedUnset(field: string): boolean {\n return !this.stored(field)\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit)\n this.failed = false\n this.failedReason = undefined\n this.publish()\n }\n\n private specOf(field: string): FieldSpec {\n const spec = this.specs.get(field)\n // Every call site names a field this card declared; a missing one is a\n // wiring mistake that must not degrade into a silently inert control.\n if (spec === undefined) throw new Error(`settings card has no field ${field}`)\n return spec\n }\n\n private snapshotOf(): ConfigFormSnapshot<T> {\n return this.scope.getSnapshot()\n }\n\n private sectionValue(field: string): unknown {\n return (this.snapshotOf().value as Record<string, unknown> | undefined)?.[field]\n }\n\n private baseValue(field: string): unknown {\n return (this.snapshotOf().base as Record<string, unknown> | undefined)?.[field]\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.snapshotOf().user as Record<string, unknown> | undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.hasOwn(user, field)\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * Task-board settings for availability, agent announcement, and optional Host\n * idle-sleep protection. Registers into the `web-ui.plugin.item` child slot\n * the Web UI plugin group renders, bound to the `task-board` namespace.\n */\n\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SnapshotStore } from '@deepseek-ai/dsh-client-store'\nimport type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { useEffect, useState } from 'react'\nimport type { TaskBoardPowerSnapshot } from '../protocol.ts'\nimport { PluginSettingsCard, BooleanField, ChoiceField } from './PluginSettingsCard.tsx'\nimport { SUBTASK_DEPTH_MAX, SUBTASK_DEPTH_MIN } from '../core/subtask.ts'\nimport { CardForm, booleanField, type CardActions, type CardShell, type FieldSpec, type FieldState as CardFieldState } from './settings-form.ts'\n\n/** The depth choices the card offers, derived from the supported range. */\nconst SUBTASK_DEPTH_CHOICES: readonly string[] = Array.from(\n { length: SUBTASK_DEPTH_MAX - SUBTASK_DEPTH_MIN + 1 },\n (_, index) => String(SUBTASK_DEPTH_MIN + index),\n)\n\n/**\n * The depth field: a choice among the supported levels whose draft text is a\n * number, because the Host schema (`maxSubtaskDepth`) is numeric. A draft\n * outside the range blocks the save instead of staging a value the Host\n * refuses.\n */\nfunction subtaskDepthField(): FieldSpec {\n return {\n field: 'maxSubtaskDepth',\n format: value => typeof value === 'number' && Number.isInteger(value) ? String(value) : '',\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n return SUBTASK_DEPTH_CHOICES.includes(trimmed) ? { kind: 'set', value: Number(trimmed) } : undefined\n },\n }\n}\n\n/** The task-board fields this card edits (the namespace's full schema). */\nexport interface TaskBoardSettings {\n /** Master switch for the plugin. */\n enabled?: boolean\n /** Whether the board announces itself in every agent's system prompt. */\n announceToAgent?: boolean\n /** Prevent host idle sleep while sessions run or schedules are armed. */\n preventIdleSleep?: boolean\n /** Subtask depth limit (1..3); 1 means a single level of subtasks. */\n maxSubtaskDepth?: number\n}\n\n/** What the task-board card renders. */\nexport interface TaskBoardSettingsCardState extends CardShell {\n /** Master switch. */\n enabled: CardFieldState\n /** System-prompt announcement flag. */\n announceToAgent: CardFieldState\n /** Idle-system-sleep protection flag. */\n preventIdleSleep: CardFieldState\n /** Subtask depth limit field. */\n maxSubtaskDepth: CardFieldState\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface TaskBoardSettingsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useTaskBoardSettingsCard. */\n taskBoardSettingsCard: SnapshotStore<TaskBoardSettingsCardState>\n }\n}\n\n/** Bridges the `task-board` settings form onto the card's staged form. */\nexport class TaskBoardSettingsCardController {\n private readonly form: CardForm<TaskBoardSettings>\n private readonly store: SnapshotStore<TaskBoardSettingsCardState>\n\n /** @param scope - the bound configuration form for the `task-board` namespace. */\n constructor(scope: ConfigForm<TaskBoardSettings>) {\n this.form = new CardForm(scope, [\n booleanField('enabled'),\n booleanField('announceToAgent'),\n booleanField('preventIdleSleep'),\n subtaskDepthField(),\n ])\n this.store = this.form.bind(() => this.projection())\n }\n\n private projection(): TaskBoardSettingsCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n announceToAgent: this.form.field('announceToAgent'),\n preventIdleSleep: this.form.field('preventIdleSleep'),\n maxSubtaskDepth: this.form.field('maxSubtaskDepth'),\n }\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): TaskBoardSettingsCardFace {\n return { hooks: { taskBoardSettingsCard: this.store }, ...this.form.actions() }\n }\n\n /**\n * Release the card's form subscription and bound stores; the slot\n * disposer calls this on teardown.\n */\n dispose(): void {\n this.form.dispose()\n }\n}\n\n/** Props the renderer binds for the task-board card. */\nexport type TaskBoardSettingsCardProps =\n PropsRuntime<'web-ui.plugin.item'>\n & PropsLocale<'task-board'>\n & InjectFace<TaskBoardSettingsCardFace>\n\n/**\n * Render the task-board card.\n * @param props - locale copy, the card snapshot, and its form actions.\n * @returns the card.\n */\nexport function TaskBoardSettingsCard(props: TaskBoardSettingsCardProps) {\n const { t } = props\n const state = props.useTaskBoardSettingsCard(snapshot => snapshot)\n const disabled = !state.writable\n const [power, setPower] = useState<TaskBoardPowerSnapshot | undefined>()\n useEffect(() => {\n // The SSE channel already carries power on every real change and pushes\n // one frame on subscribe; polling the full /state snapshot every 5 s\n // re-cloned and re-serialized the whole ledger server-side for one field.\n let live = true\n const events = new EventSource('api/task-board/events')\n events.onmessage = (message: MessageEvent<string>): void => {\n try {\n const frame = JSON.parse(message.data) as { power?: TaskBoardPowerSnapshot }\n if (frame.power !== undefined && live) setPower(frame.power)\n } catch {\n // The settings form remains usable while the host status is reconnecting.\n }\n }\n return () => { live = false; events.close() }\n }, [])\n const fieldProps = {\n overriddenLabel: t('settings.overridden'),\n resetLabel: t('settings.reset'),\n invalidLabel: t('settings.invalidNumber'),\n disabled,\n }\n return (\n <PluginSettingsCard\n t={t}\n titleKey=\"settings.title\"\n descriptionKey=\"settings.description\"\n defaultOpen={false}\n state={state}\n renderChildrenWhenNotExposed\n hideNotExposedNotice\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"settings-task-board-enabled\"\n label={t('settings.enabled')}\n hint={t('settings.enabledHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.enabled}\n onEdit={(text) => { props.edit('enabled', text) }}\n onReset={() => { props.resetField('enabled') }}\n />\n <BooleanField\n id=\"settings-task-board-announce\"\n label={t('settings.announceToAgent')}\n hint={t('settings.announceToAgentHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.announceToAgent}\n onEdit={(text) => { props.edit('announceToAgent', text) }}\n onReset={() => { props.resetField('announceToAgent') }}\n />\n <BooleanField\n id=\"settings-task-board-prevent-idle-sleep\"\n label={t('settings.preventIdleSleep')}\n hint={t('settings.preventIdleSleepHint')}\n inheritLabel={t('settings.inherit')}\n onLabel={t('settings.on')}\n offLabel={t('settings.off')}\n {...fieldProps}\n {...state.preventIdleSleep}\n onEdit={(text) => { props.edit('preventIdleSleep', text) }}\n onReset={() => { props.resetField('preventIdleSleep') }}\n />\n <ChoiceField\n id=\"settings-task-board-subtask-depth\"\n label={t('settings.maxSubtaskDepth')}\n hint={t('settings.maxSubtaskDepthHint')}\n inheritLabel={t('settings.inherit')}\n choices={SUBTASK_DEPTH_CHOICES.map(value => ({\n value,\n label: t('settings.maxSubtaskDepthOption', { depth: value }),\n }))}\n {...fieldProps}\n {...state.maxSubtaskDepth}\n onEdit={(text) => { props.edit('maxSubtaskDepth', text) }}\n onReset={() => { props.resetField('maxSubtaskDepth') }}\n />\n <p>\n {t('settings.powerStatus', {\n platform: power?.platform ?? t('settings.powerUnknown'),\n phase: power?.phase ?? t('settings.powerUnknown'),\n running: String(power?.runningSessions ?? 0),\n schedules: String(power?.armedSchedules ?? 0),\n })}\n </p>\n <p>{t('settings.powerBoundary')}</p>\n {power?.lastError !== undefined && <p>{t('settings.powerError', { error: power.lastError })}</p>}\n </PluginSettingsCard>\n )\n}\n","import type { TaskUpdatePatch } from './core/use-cases/task-update.ts'\nimport { isTaskPermission, isTaskStatus, isTaskTagList, type NewTaskInput, type TaskPermission, type TaskRecord, type TaskStatus } from './core/tasks.ts'\nimport { parseLedger } from './core/store.ts'\nimport { sanitizeFreezeSnapshot, type FreezeSnapshot } from './core/freeze-snapshot.ts'\nimport { sanitizeHandover, type TaskHandoverInput } from './core/handover.ts'\n\n/** Freeze payload carried by create/update actions after the gate (redacted in place). */\ntype FreezePayload = FreezeSnapshot & { redacted?: boolean; frozenBy?: string }\n\nexport const TASK_BOARD_SCHEMA_VERSION = 3 as const\n/** Ledger documents written before v3; loaded once and migrated on startup. */\nexport const TASK_BOARD_LEGACY_SCHEMA_VERSION = 2 as const\nexport const TASK_BOARD_API_PREFIX = '/api/task-board'\n\nexport type PowerPhase = 'disabled' | 'idle' | 'acquiring' | 'active' | 'error' | 'unsupported'\n\nexport interface TaskBoardPowerSnapshot {\n platform: string\n phase: PowerPhase\n enabled: boolean\n runningSessions: number\n armedSchedules: number\n sessionStateKnown: boolean\n lastError?: string\n}\n\nexport interface TaskBoardSchedulerSnapshot {\n timeZone: string\n /** Opaque identity of the current Host ledger generation. */\n ledgerId?: string\n lastTickAt?: number\n error?: string\n}\n\nexport interface TaskBoardSnapshot {\n schemaVersion: typeof TASK_BOARD_SCHEMA_VERSION\n revision: number\n tasks: TaskRecord[]\n scheduler: TaskBoardSchedulerSnapshot\n power: TaskBoardPowerSnapshot\n /** Session-default permission the confirmation gate compares against. */\n sessionDefaultPermission?: TaskPermission\n /**\n * Deployment subtask depth limit (1..3). The browser mirrors it to enable or\n * disable the subtask controls; the Host ledger is the authority.\n */\n maxSubtaskDepth?: number\n /**\n * Whether this deployment serves the Agent Teams service, so a task may opt\n * into team execution (Team Lead session plus one teammate per subtask).\n */\n teamRunAvailable?: boolean\n}\n\n/** SSE event frame: revision/scheduler/power only, never the task list. */\nexport interface TaskBoardEventPayload {\n revision: number\n scheduler: TaskBoardSchedulerSnapshot\n power: TaskBoardPowerSnapshot\n}\n\n/**\n * Request body of `POST {TASK_BOARD_API_PREFIX}/parse` (issue #1540): the text\n * the user pasted plus the `provider/model` route that should parse it.\n */\nexport interface TaskBoardParseRequest {\n text: string\n /** Qualified route from the model picker; absent when no route was chosen. */\n model?: string\n}\n\n/** Draft fields a parse returns; the user reviews them before creating the task. */\nexport interface TaskBoardParseDraft {\n title: string\n description: string\n prompt: string\n}\n\n/** Strict parse of a `/parse` request body; undefined rejects the request. */\nexport function parseTaskParseRequest(value: unknown): TaskBoardParseRequest | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const record = value as { text?: unknown; model?: unknown }\n if (typeof record.text !== 'string' || record.text.trim() === '') return undefined\n if (record.model !== undefined && typeof record.model !== 'string') return undefined\n const model = typeof record.model === 'string' ? record.model.trim() : ''\n return { text: record.text, ...(model === '' ? {} : { model }) }\n}\n\n/** Whether a decoded reply carries the three draft strings the form accepts. */\nexport function isTaskParseDraft(value: unknown): value is TaskBoardParseDraft {\n if (typeof value !== 'object' || value === null) return false\n const record = value as { title?: unknown; description?: unknown; prompt?: unknown }\n return typeof record.title === 'string' && typeof record.description === 'string' && typeof record.prompt === 'string'\n}\n\nexport type TaskBoardAction =\n | { kind: 'import'; sourceId: string; tasks: TaskRecord[] }\n | { kind: 'create'; id: string; input: NewTaskInput }\n | { kind: 'update'; taskId: string; patch: TaskUpdatePatch }\n | { kind: 'delete'; taskId: string }\n | { kind: 'move'; taskId: string; status: TaskStatus }\n | { kind: 'archive'; taskId: string }\n | { kind: 'restore'; taskId: string }\n | { kind: 'set-schedule'; taskId: string; patch: { enabled?: boolean; cron?: string } }\n | { kind: 'run'; taskId: string }\n | { kind: 'rerun'; taskId: string }\n | { kind: 'confirm-permission'; taskId: string }\n | { kind: 'set-parent'; taskId: string; parentId: string | null }\n\nexport interface TaskBoardActionEnvelope {\n requestId: string\n action: TaskBoardAction\n /**\n * Session id of the DSH session issuing the action, for the execution audit\n * trail (issue #6). Client-asserted, not a trust boundary; parsed only as a\n * bounded non-empty string and recorded on opened executions / freeze stamps.\n */\n initiator?: string\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : undefined\n}\n\nfunction exactKeys(value: Record<string, unknown>, allowed: readonly string[]): boolean {\n return Object.keys(value).every(key => allowed.includes(key))\n}\n\nfunction optionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string'\n}\n\nconst FORBIDDEN_IMPORT_FIELDS = new Set(['args', 'command', 'executable', 'powershell', 'shell'])\n\nfunction hasForbiddenImportField(value: unknown): boolean {\n if (Array.isArray(value)) return value.some(hasForbiddenImportField)\n const row = record(value)\n if (row === undefined) return false\n return Object.entries(row).some(([key, nested]) => FORBIDDEN_IMPORT_FIELDS.has(key.toLowerCase()) || hasForbiddenImportField(nested))\n}\n\nfunction optionalFiniteNumber(value: unknown): boolean {\n return value === undefined || (typeof value === 'number' && Number.isFinite(value))\n}\n\nfunction validImportedKnownFields(value: Record<string, unknown>): boolean {\n // Tags are validated (not repaired) on the import path: an imported task\n // must carry a well-formed list or none at all, so a hand-edited export\n // cannot smuggle a malformed tag past the gate.\n if (value.tags !== undefined && !isTaskTagList(value.tags)) return false\n if (value.schedule !== undefined) {\n const schedule = record(value.schedule)\n if (schedule === undefined || typeof schedule.enabled !== 'boolean' || typeof schedule.cron !== 'string') return false\n if (!optionalFiniteNumber(schedule.nextRunAt) || !optionalFiniteNumber(schedule.lastTriggeredAt)) return false\n }\n if (value.executions !== undefined) {\n if (!Array.isArray(value.executions)) return false\n for (const item of value.executions) {\n const execution = record(item)\n if (execution === undefined || typeof execution.id !== 'string' || !optionalString(execution.sessionId)) return false\n if (typeof execution.startedAt !== 'number' || !Number.isFinite(execution.startedAt)) return false\n if (!optionalFiniteNumber(execution.endedAt) || !optionalString(execution.error)) return false\n if (execution.result !== undefined && !['succeeded', 'failed', 'cancelled'].includes(String(execution.result))) return false\n if (execution.initiatedBy !== undefined && typeof execution.initiatedBy !== 'string') return false\n if (execution.frozenBy !== undefined && typeof execution.frozenBy !== 'string') return false\n if (execution.frozenAt !== undefined && typeof execution.frozenAt !== 'number') return false\n }\n }\n return true\n}\n\nfunction importedTask(value: unknown): TaskRecord | undefined {\n const input = record(value)\n if (input === undefined || hasForbiddenImportField(input) || !validImportedKnownFields(input)) return undefined\n const task = parseLedger(JSON.stringify([value]))[0]\n if (task === undefined) return undefined\n return {\n id: task.id,\n title: task.title,\n description: task.description,\n prompt: task.prompt,\n status: task.status,\n createdAt: task.createdAt,\n updatedAt: task.updatedAt,\n executions: task.executions.map(execution => ({\n id: execution.id,\n sessionId: execution.sessionId,\n startedAt: execution.startedAt,\n endedAt: execution.endedAt,\n result: execution.result,\n error: execution.error,\n ...(execution.initiatedBy === undefined ? {} : { initiatedBy: execution.initiatedBy }),\n ...(execution.frozenAt === undefined ? {} : { frozenAt: execution.frozenAt }),\n ...(execution.frozenBy === undefined ? {} : { frozenBy: execution.frozenBy }),\n })),\n ...(task.schedule === undefined ? {} : {\n schedule: {\n enabled: task.schedule.enabled,\n cron: task.schedule.cron,\n nextRunAt: task.schedule.nextRunAt,\n lastTriggeredAt: task.schedule.lastTriggeredAt,\n },\n }),\n // The lineage link rides the import; the Host repairs a link whose parent\n // is missing from the merged ledger instead of trusting the export.\n ...(task.parentId === undefined ? {} : { parentId: task.parentId }),\n ...(task.workspaceId === undefined ? {} : { workspaceId: task.workspaceId }),\n ...(task.mode === undefined ? {} : { mode: task.mode }),\n ...(task.permission === undefined ? {} : { permission: task.permission }),\n ...(task.reuseSession === undefined ? {} : { reuseSession: task.reuseSession }),\n ...(task.archivedAt === undefined ? {} : { archivedAt: task.archivedAt }),\n ...(task.freeze === undefined ? {} : { freeze: task.freeze }),\n ...(task.handover === undefined ? {} : { handover: task.handover }),\n ...(task.tags === undefined ? {} : { tags: task.tags }),\n // 安全门(对抗场景 b):import 不是人工确认动作,确认戳一律剥除——\n // 高于会话默认权限的绑定经 import 进入后必须重新武装 confirm-permission 门。\n }\n}\n\n/**\n * Gate a freeze payload from the wire: same T2 security gates as the parser\n * (slash-command taint rejects, sensitive patterns redact in place, 8 KiB\n * per-field cap). Returns the sanitized payload, or undefined when rejected.\n */\nfunction freezePayload(value: unknown): FreezePayload | undefined {\n const result = sanitizeFreezeSnapshot(value, ['redacted', 'frozenBy'])\n if (!result.ok) return undefined\n const frozenBy = result.extras.frozenBy\n if (frozenBy !== undefined && (typeof frozenBy !== 'string' || frozenBy === '')) return undefined\n return {\n ...result.snapshot,\n ...(result.redacted || result.extras.redacted === true ? { redacted: true } : {}),\n ...(frozenBy === undefined ? {} : { frozenBy }),\n }\n}\n\n/**\n * Gate a handover bundle from the wire: exact keys, bounded string targets,\n * a known permission, and a bounded references list. Returns the sanitized\n * bundle, or undefined when rejected.\n */\nfunction handoverPayload(value: unknown): TaskHandoverInput | undefined {\n return sanitizeHandover(value)\n}\n\nfunction createInput(value: unknown): value is NewTaskInput {\n const input = record(value)\n if (input === undefined || !exactKeys(input, ['title', 'description', 'prompt', 'parentId', 'workspaceId', 'mode', 'permission', 'schedule', 'freeze', 'handover', 'model', 'reuseSession', 'teamRun', 'tags'])) return false\n if (input.parentId !== undefined && (typeof input.parentId !== 'string' || input.parentId.trim() === '')) return false\n if (typeof input.title !== 'string' || typeof input.description !== 'string' || typeof input.prompt !== 'string') return false\n if (!optionalString(input.workspaceId) || !optionalString(input.mode) || !optionalString(input.model)) return false\n if (input.reuseSession !== undefined && typeof input.reuseSession !== 'boolean') return false\n if (input.teamRun !== undefined && typeof input.teamRun !== 'boolean') return false\n if (input.permission !== undefined && !isTaskPermission(input.permission)) return false\n if (input.tags !== undefined && !isTaskTagList(input.tags)) return false\n if (input.freeze !== undefined && freezePayload(input.freeze) === undefined) return false\n if (input.handover !== undefined && handoverPayload(input.handover) === undefined) return false\n if (input.schedule !== undefined) {\n const schedule = record(input.schedule)\n if (schedule === undefined || !exactKeys(schedule, ['enabled', 'cron'])) return false\n if (typeof schedule.enabled !== 'boolean' || typeof schedule.cron !== 'string') return false\n }\n return true\n}\n\nfunction updatePatch(value: unknown): boolean {\n const patch = record(value)\n if (patch === undefined || !exactKeys(patch, ['title', 'description', 'prompt', 'workspaceId', 'mode', 'permission', 'freeze', 'handover', 'model', 'reuseSession', 'teamRun', 'tags'])) return false\n // null (or false) clears the reuse opt-in; only a real boolean is accepted.\n if (patch.reuseSession !== undefined && patch.reuseSession !== null && typeof patch.reuseSession !== 'boolean') return false\n if (patch.teamRun !== undefined && patch.teamRun !== null && typeof patch.teamRun !== 'boolean') return false\n for (const key of ['title', 'description', 'prompt', 'workspaceId', 'mode', 'model'] as const) {\n if (!optionalString(patch[key])) return false\n }\n if (patch.permission !== undefined && !isTaskPermission(patch.permission)) return false\n // null clears the label set; a present array must be a well-formed list.\n if (patch.tags !== undefined && patch.tags !== null && !isTaskTagList(patch.tags)) return false\n // null clears the snapshot; an object must pass the freeze gate.\n if (patch.freeze !== undefined && patch.freeze !== null && freezePayload(patch.freeze) === undefined) return false\n // Same convention for the handover bundle.\n return patch.handover === undefined || patch.handover === null || handoverPayload(patch.handover) !== undefined\n}\n\nfunction schedulePatch(value: unknown): boolean {\n const patch = record(value)\n return patch !== undefined\n && exactKeys(patch, ['enabled', 'cron'])\n && (patch.enabled === undefined || typeof patch.enabled === 'boolean')\n && (patch.cron === undefined || typeof patch.cron === 'string')\n}\n\nexport function parseActionEnvelope(value: unknown): TaskBoardActionEnvelope | undefined {\n const parsed = parseEnvelopeAction(value)\n if (parsed === undefined) return undefined\n // Attach the audit-only initiator stamp (already validated above) to every accepted action.\n const initiator = initiatorOf(value)\n return initiator === undefined ? parsed : { ...parsed, initiator }\n}\n\nfunction initiatorOf(value: unknown): string | undefined {\n const envelope = record(value)\n const id = envelope?.initiator\n return typeof id === 'string' && id.trim() !== '' && id.length <= 256 ? id : undefined\n}\n\nfunction parseEnvelopeAction(value: unknown): TaskBoardActionEnvelope | undefined {\n const envelope = record(value)\n if (envelope === undefined || !exactKeys(envelope, ['requestId', 'action', 'initiator'])) return undefined\n if (typeof envelope.requestId !== 'string' || envelope.requestId.trim() === '' || envelope.requestId.length > 256) return undefined\n if (envelope.initiator !== undefined && initiatorOf(value) === undefined) return undefined\n const action = record(envelope.action)\n if (action === undefined || typeof action.kind !== 'string') return undefined\n const taskId = typeof action.taskId === 'string' && action.taskId !== '' ? action.taskId : undefined\n switch (action.kind) {\n case 'import':\n if (!exactKeys(action, ['kind', 'sourceId', 'tasks'])) return undefined\n if (typeof action.sourceId !== 'string' || action.sourceId === '' || !Array.isArray(action.tasks)) return undefined\n {\n const tasks = action.tasks.map(importedTask)\n return tasks.every((task): task is TaskRecord => task !== undefined)\n ? { requestId: envelope.requestId, action: { kind: 'import', sourceId: action.sourceId, tasks } }\n : undefined\n }\n case 'create': {\n if (!exactKeys(action, ['kind', 'id', 'input'])) return undefined\n if (typeof action.id !== 'string' || action.id === '' || !createInput(action.input)) return undefined\n const input = action.input as NewTaskInput\n const freeze = input.freeze === undefined ? undefined : freezePayload(input.freeze)\n const handover = input.handover === undefined ? undefined : handoverPayload(input.handover)\n const sanitized = freeze === undefined && handover === undefined ? input : { ...input, ...(freeze === undefined ? {} : { freeze }), ...(handover === undefined ? {} : { handover }) }\n return { requestId: envelope.requestId, action: { kind: 'create', id: action.id as string, input: sanitized } }\n }\n case 'update': {\n if (!exactKeys(action, ['kind', 'taskId', 'patch'])) return undefined\n if (taskId === undefined || !updatePatch(action.patch)) return undefined\n const patch = action.patch as TaskUpdatePatch\n const freeze = patch.freeze === undefined || patch.freeze === null ? patch.freeze : freezePayload(patch.freeze)\n const handover = patch.handover === undefined || patch.handover === null ? patch.handover : handoverPayload(patch.handover)\n const sanitized = ('freeze' in patch && freeze !== patch.freeze) || ('handover' in patch && handover !== patch.handover)\n ? { ...patch, ...(freeze === patch.freeze ? {} : { freeze }), ...(handover === patch.handover ? {} : { handover }) }\n : patch\n return { requestId: envelope.requestId, action: { kind: 'update', taskId, patch: sanitized } }\n }\n case 'set-parent': {\n if (!exactKeys(action, ['kind', 'taskId', 'parentId'])) return undefined\n if (taskId === undefined) return undefined\n const parentId = action.parentId\n if (parentId !== null && (typeof parentId !== 'string' || parentId.trim() === '')) return undefined\n return { requestId: envelope.requestId, action: { kind: 'set-parent', taskId, parentId } }\n }\n case 'set-schedule':\n if (!exactKeys(action, ['kind', 'taskId', 'patch'])) return undefined\n return taskId !== undefined && schedulePatch(action.patch)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'set-schedule' }> }\n : undefined\n case 'move':\n if (!exactKeys(action, ['kind', 'taskId', 'status'])) return undefined\n return taskId !== undefined && isTaskStatus(action.status)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'move' }> }\n : undefined\n case 'confirm-permission':\n case 'delete':\n case 'archive':\n case 'restore':\n case 'run':\n case 'rerun':\n if (!exactKeys(action, ['kind', 'taskId'])) return undefined\n return taskId === undefined ? undefined : { requestId: envelope.requestId, action: action as TaskBoardAction }\n default:\n return undefined\n }\n}\n","import type { TaskRecord } from '../core/tasks.ts'\nimport { t } from './locales.ts'\nimport {\n isTaskParseDraft,\n TASK_BOARD_API_PREFIX,\n type TaskBoardAction,\n type TaskBoardActionEnvelope,\n type TaskBoardEventPayload,\n type TaskBoardParseDraft,\n type TaskBoardParseRequest,\n type TaskBoardSnapshot,\n} from '../protocol.ts'\n\n/**\n * Client-side base for the board's routes: DOCUMENT-RELATIVE (issue #1707).\n *\n * The host registers `TASK_BOARD_API_PREFIX` root-absolute; the page is served\n * with `<base href=\"./\">`, so the browser half must drop the leading slash or\n * a sub-path deployment escapes its entry directory. Derived from the shared\n * constant so host and client cannot drift.\n */\nconst CLIENT_API_PREFIX = TASK_BOARD_API_PREFIX.slice(1)\n\nconst IMPORT_MARKER = 'dsh.taskBoard.v2.hostImported'\nconst SOURCE_KEY = 'dsh.taskBoard.v2.sourceId'\nconst IMPORT_REQUEST_KEY = 'dsh.taskBoard.v2.importRequestId'\nconst REQUEST_TIMEOUT_MS = 15_000\n/** Re-notify the panel at most this often while the event stream stays broken. */\nconst STREAM_ERROR_NOTIFY_MS = 15_000\n/** Mirrors the Host's own parse budget; only used to phrase the timeout. */\nconst TASK_PARSE_TIMEOUT_SECONDS = 45\n\n/**\n * Failure classes of the Host API, in the language the panel renders\n * (issue #1528). The Host is the only part that knows whether a task-board\n * route exists at all, so a raw fetch/parse error must never reach the user:\n * \"Unexpected token 'o', \\\"not found\\\" is not valid JSON\" is what a missing\n * Host half looks like today.\n */\nexport type HostApiFailure = 'not-mounted' | 'unauthorized' | 'locked' | 'rejected' | 'timeout' | 'unreachable' | 'unexpected'\n\n/** Transport failure carrying a stable class next to its user-facing message. */\nexport class HostApiError extends Error {\n constructor(readonly failure: HostApiFailure, message: string, readonly status?: number) {\n super(message)\n this.name = 'HostApiError'\n }\n}\n\nfunction uuid(): string {\n return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n}\n\n/**\n * Read one Host response without ever handing a non-JSON body to JSON.parse:\n * the core webserver answers an unmounted `/api/*` path with the plain text\n * \"not found\", which used to surface as a JavaScript parse error in the panel.\n */\nasync function readJson<T>(response: Response): Promise<T> {\n const text = await response.text()\n let parsed: unknown\n let readable = false\n if (text.trim() !== '') {\n try {\n parsed = JSON.parse(text)\n readable = true\n } catch {\n readable = false\n }\n }\n const hostError = readable && typeof parsed === 'object' && parsed !== null && typeof (parsed as { error?: unknown }).error === 'string'\n ? (parsed as { error: string }).error\n : undefined\n if (response.ok) {\n if (!readable) throw new HostApiError('unexpected', t('board.hostError.unexpected', { status: String(response.status) }), response.status)\n return parsed as T\n }\n if (hostError !== undefined) {\n // The Host answered with a reason of its own. A ledger lock is the one\n // class worth naming in the panel's words; the authentication fence and\n // every other action rejection are reported as they arrive.\n if (hostError === 'forbidden') throw new HostApiError('unauthorized', t('board.hostError.unauthorized'), response.status)\n if (response.status === 503 || /lock/i.test(hostError)) {\n throw new HostApiError('locked', t('board.hostError.locked', { detail: hostError }), response.status)\n }\n throw new HostApiError('rejected', hostError, response.status)\n }\n if (response.status === 404) throw new HostApiError('not-mounted', t('board.hostError.notMounted'), 404)\n if (response.status === 401 || response.status === 403) throw new HostApiError('unauthorized', t('board.hostError.unauthorized'), response.status)\n throw new HostApiError('unexpected', t('board.hostError.unexpected', { status: String(response.status) }), response.status)\n}\n\nexport interface TaskBoardHostTransport {\n bootstrap(legacy: readonly TaskRecord[]): Promise<TaskBoardSnapshot>\n state(): Promise<TaskBoardSnapshot>\n action(action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot>\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void\n /** One-shot model parse of pasted text (issue #1540). */\n parseDraft(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft>\n}\n\nexport class HttpTaskBoardHostTransport implements TaskBoardHostTransport {\n constructor(private readonly storage: Pick<Storage, 'getItem' | 'setItem'> | undefined = globalThis.localStorage) {}\n\n async bootstrap(legacy: readonly TaskRecord[]): Promise<TaskBoardSnapshot> {\n const initial = await this.state()\n const ledgerId = initial.scheduler.ledgerId\n if (legacy.length > 0 && ledgerId !== undefined && this.storage?.getItem(IMPORT_MARKER) !== ledgerId) {\n let sourceId = this.storage?.getItem(SOURCE_KEY)\n if (sourceId === null || sourceId === undefined || sourceId === '') {\n sourceId = uuid()\n this.storage?.setItem(SOURCE_KEY, sourceId)\n }\n let requestId = this.storage?.getItem(IMPORT_REQUEST_KEY)\n if (requestId === null || requestId === undefined || requestId === '') {\n requestId = uuid()\n this.storage?.setItem(IMPORT_REQUEST_KEY, requestId)\n }\n const snapshot = await this.post(requestId, { kind: 'import', sourceId, tasks: [...legacy] })\n this.storage?.setItem(IMPORT_MARKER, snapshot.scheduler.ledgerId ?? ledgerId)\n return snapshot\n }\n return initial\n }\n\n async state(): Promise<TaskBoardSnapshot> {\n return await this.request(`${CLIENT_API_PREFIX}/state`, { cache: 'no-store' })\n }\n\n async action(action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot> {\n return await this.post(uuid(), action, initiator)\n }\n\n private async post(requestId: string, action: TaskBoardAction, initiator?: string): Promise<TaskBoardSnapshot> {\n const envelope: TaskBoardActionEnvelope = { requestId, action, ...(initiator === undefined || initiator === '' ? {} : { initiator }) }\n return await this.request(`${CLIENT_API_PREFIX}/action`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(envelope),\n })\n }\n\n private async request(url: string, init: RequestInit): Promise<TaskBoardSnapshot> {\n const controller = new AbortController()\n const timeout = globalThis.setTimeout(() => { controller.abort() }, REQUEST_TIMEOUT_MS)\n try {\n return await readJson<TaskBoardSnapshot>(await fetch(url, { ...init, signal: controller.signal }))\n } catch (error) {\n if (error instanceof HostApiError) throw error\n if (controller.signal.aborted) throw new HostApiError('timeout', t('board.hostError.timeout', { seconds: String(REQUEST_TIMEOUT_MS / 1_000) }))\n // fetch itself failed (server stopped, connection reset, DNS): the panel\n // says so in its own words instead of leaking \"Failed to fetch\".\n throw new HostApiError('unreachable', t('board.hostError.unreachable'))\n } finally {\n globalThis.clearTimeout(timeout)\n }\n }\n\n /**\n * Ask the Host to turn pasted text into task fields. The route answers a\n * typed failure (no model, timeout, unparseable reply) already phrased for\n * the form, so the UI never renders a raw status code (issue #1540).\n */\n async parseDraft(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft> {\n let response: Response\n try {\n response = await fetch(`${CLIENT_API_PREFIX}/parse`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(request),\n ...(signal === undefined ? {} : { signal }),\n })\n } catch {\n // A cancelled parse and a stopped Host look the same to fetch; the form\n // checks its own abort flag before showing anything.\n throw new HostApiError('unreachable', t('board.hostError.unreachable'))\n }\n const text = await response.text()\n let parsed: unknown\n let readable = false\n if (text.trim() !== '') {\n try {\n parsed = JSON.parse(text)\n readable = true\n } catch {\n readable = false\n }\n }\n const record = readable && typeof parsed === 'object' && parsed !== null\n ? parsed as { code?: unknown; error?: unknown; draft?: unknown }\n : undefined\n if (response.ok) {\n if (record !== undefined && isTaskParseDraft(record.draft)) return record.draft\n throw new HostApiError('unexpected', t('new.aiParseFailed', { error: t('board.hostError.unexpected', { status: String(response.status) }) }), response.status)\n }\n if (response.status === 404) throw new HostApiError('not-mounted', t('new.aiParseUnavailable'), 404)\n if (response.status === 401 || response.status === 403) throw new HostApiError('unauthorized', t('board.hostError.unauthorized'), response.status)\n const code = typeof record?.code === 'string' ? record.code : undefined\n if (code === 'no-model') throw new HostApiError('rejected', t('new.aiParseNoModel'), response.status)\n if (code === 'timeout') throw new HostApiError('timeout', t('new.aiParseTimeout', { seconds: String(TASK_PARSE_TIMEOUT_SECONDS) }), response.status)\n const detail = typeof record?.error === 'string' && record.error !== '' ? record.error : String(response.status)\n throw new HostApiError('rejected', t('new.aiParseFailed', { error: detail }), response.status)\n }\n\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void {\n const events = new EventSource(`${CLIENT_API_PREFIX}/events`)\n let lastStreamErrorNotify = 0\n events.onmessage = (message: MessageEvent<string>): void => {\n try {\n const parsed = JSON.parse(message.data) as TaskBoardEventPayload\n if (parsed === null || typeof parsed !== 'object' || typeof parsed.revision !== 'number') throw new Error('invalid event frame')\n listener(parsed)\n } catch {\n listener()\n }\n }\n // A stream that cannot connect at all (unmounted route, refused socket) is\n // how a Host half that never mounted looks from the browser; nudge the\n // panel into one state read so the failure becomes visible (#1528).\n events.onerror = (): void => {\n const now = Date.now()\n if (now - lastStreamErrorNotify < STREAM_ERROR_NOTIFY_MS) return\n lastStreamErrorNotify = now\n listener()\n }\n const onVisible = (): void => { if (document.visibilityState === 'visible') listener() }\n document.addEventListener('visibilitychange', onVisible)\n return () => {\n document.removeEventListener('visibilitychange', onVisible)\n events.close()\n }\n }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/telemetry.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Anonymous install telemetry shared by the DSH Web UI family plugins.\n *\n * Once per UTC day per browser, each wired plugin sends one heartbeat to\n * the dsh-market edge API listing its package name (and version when known).\n * The payload carries no conversation data and no identifiers beyond a random\n * UUID generated in localStorage; the server hashes it with a deployment salt\n * before storage and never persists IP addresses. Sends are fire-and-forget:\n * failures stay silent and simply retry on a later mount or day. The system\n * is documented in docs/telemetry.md.\n */\n\nexport type TelemetryChannel = 'market' | 'npm' | 'unknown'\n\nexport interface TelemetryItem {\n /** npm package name or asset id, e.g. \"@linxin666/dsh-pet\" or \"skin:harbor\". */\n name: string\n /** Installed version when known; omitted otherwise. */\n version?: string\n /** Install channel when determinable (market = Workshop install). */\n channel?: TelemetryChannel\n}\n\nconst VISITOR_KEY = 'dsh-web-ui-telemetry-visitor'\nconst DAY_KEY_PREFIX = 'dsh-web-ui-telemetry-day:'\nconst ENDPOINT = 'https://dsh-market.com/api/telemetry/event'\n\n// Baked into each client bundle by shared/tsdown.client.ts (the package's own\n// package.json version at build time). Undefined in dev/test builds.\ndeclare const __DSH_PKG_VERSION__: string | undefined\n\n/** The building package's version, when the bundle carries it. */\nfunction bakedVersion(): string | undefined {\n try {\n return typeof __DSH_PKG_VERSION__ === 'string' && __DSH_PKG_VERSION__ !== ''\n ? __DSH_PKG_VERSION__\n : undefined\n } catch {\n return undefined\n }\n}\n\n/** Read or lazily create the anonymous visitor id; null when storage is unavailable. */\nfunction visitorId(): string | null {\n try {\n const existing = localStorage.getItem(VISITOR_KEY)\n if (existing && /^[A-Za-z0-9_-]{16,64}$/.test(existing)) return existing\n const fresh = crypto.randomUUID().replaceAll('-', '')\n localStorage.setItem(VISITOR_KEY, fresh)\n return fresh\n } catch {\n // Storage unavailable (privacy mode, sandboxed frame): report nothing.\n return null\n }\n}\n\n/** Drop stale per-day dedup keys so localStorage does not grow forever. */\nfunction pruneDayKeys(today: string): void {\n try {\n for (let index = localStorage.length - 1; index >= 0; index -= 1) {\n const key = localStorage.key(index)\n if (key !== null && key.startsWith(DAY_KEY_PREFIX) && key !== DAY_KEY_PREFIX + today) {\n localStorage.removeItem(key)\n }\n }\n } catch { /* best effort */ }\n}\n\n/**\n * Fire the daily heartbeat for the given items at most once per UTC day per\n * browser. Never throws and never blocks the caller. Items without an explicit\n * version inherit the bundle's baked build version.\n */\nexport function reportDailyHeartbeat(items: readonly TelemetryItem[]): void {\n try {\n if (items.length === 0) return\n const today = new Date().toISOString().slice(0, 10)\n // Automation contexts (CDP-driven QA browsers, fresh isolated profiles)\n // mint a new visitor id per run and would inflate instance counts.\n if (navigator.webdriver) return\n if (localStorage.getItem(DAY_KEY_PREFIX + today) !== null) return\n const visitor = visitorId()\n if (visitor === null) return\n pruneDayKeys(today)\n const payloadItems = items.map((item) => {\n const out: Record<string, string> = { name: item.name }\n const version = item.version ?? bakedVersion()\n if (version !== undefined) out.version = version\n if (item.channel !== undefined) out.channel = item.channel\n return out\n })\n const body = JSON.stringify({ kind: 'heartbeat', visitor, items: payloadItems })\n void fetch(ENDPOINT, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body,\n keepalive: true,\n }).then((response) => {\n // Mark the day only after an accepted send, so offline browsers retry\n // on a later mount instead of going dark until tomorrow.\n if (response.ok) localStorage.setItem(DAY_KEY_PREFIX + today, '1')\n }).catch(() => { /* unreachable endpoint: stay silent */ })\n } catch { /* never break the host UI over telemetry */ }\n}\n","// Generated by scripts/sync-shared.mjs from shared/client/settings/plugin-card-seat.ts. Do not edit this copy; edit the shared source and run \"node scripts/sync-shared.mjs\".\n/**\n * Family plugin-card seat.\n *\n * A family plugin contributes its settings card to whichever plugin-card seat\n * the running host actually renders:\n *\n * - `web-ui.plugin.item` — the list seat declared by the dsh-web-settings\n * group section (this family's own first-level \"Web UI plugins\" section);\n * - `plugins.bundle.config` — the official keyed seat of the harness's plugin\n * manager page, keyed by the bundle's package name and rendered on that\n * bundle's page. alpha.2 removed the `settings.plugin.item` keyed seat of the\n * `ui-settings-plugins` tab that this helper used before, so a card keyed by\n * its settings namespace has no seat to land in any more.\n *\n * SEAT SELECTION IS NOT A DECLARATION PROBE. The official plugin surface\n * belongs to the harness bundle and declares its seats before any external\n * plugin's `apply()` runs, so \"is the official seat declared?\" answers yes even\n * in the deployment whose whole point is the family group. Choosing on that\n * probe sends every family card to the official page and leaves the group's own\n * section permanently empty — the family of reports where the section renders\n * its heading and zero cards.\n *\n * The signal that actually distinguishes the two deployments is whether\n * dsh-web-settings is loaded: it is the package that owns the group section and\n * it publishes the `webUiSettings` service during `apply()`, which every\n * family plugin already reads for its settings form. Group loaded -> the family\n * seat; group absent -> the official seat.\n *\n * The decision is re-evaluated on every `slots/changed` because the group may\n * apply after this plugin (the family aggregate orders it first, a profile that\n * installs the group separately need not): the initial contribution goes to the\n * official seat, then moves to the family seat the moment the group's section\n * registers. The entry is disposed before the replacement is registered, so a\n * card is never in two seats at once.\n *\n * The shared tree has no client-SDK dependency, so this module reads its\n * context through the structural shape below; callers pass the plugin's own\n * `ctx`.\n */\n\n/** The family list seat key. */\nexport const FAMILY_PLUGIN_CARD_SEAT = 'web-ui.plugin.item'\n\n/** The official keyed plugin-card seat key (the alpha.2 bundle-configuration seat). */\nexport const OFFICIAL_PLUGIN_CARD_SEAT = 'plugins.bundle.config'\n\n/** The service dsh-web-settings publishes while it is loaded. */\nexport const FAMILY_GROUP_SERVICE = 'webUiSettings'\n\n/** The slot-registry member this helper uses (structurally satisfied by ctx.slots). */\nexport interface PluginCardSlots {\n /** Contribution of one card entry. */\n register(options: never, component: never): unknown\n}\n\n/** The slice of the client context a card contribution needs. */\nexport interface PluginCardContext {\n slots: PluginCardSlots\n /** Service lookup; absent on a context double that only models the slots. */\n get?(name: string): unknown\n /** Event subscription seat; absent on an event-less test double. */\n on?(event: string, listener: (...args: never[]) => void): unknown\n}\n\n/** Owner share of a family list-seat card (that seat supplies nothing). */\nexport interface SettingsPluginItemOwnerProps {\n /** Marker field: card owner props are intentionally empty. */\n children?: never\n}\n\n/** One family plugin's card contribution. */\nexport interface PluginCardSeat {\n /**\n * Npm package name of the bundle this card configures; the official keyed\n * seat dispatches on it. Every family package ships its own bundle patch, so\n * a standalone install lists that package as the bundle whose page renders\n * this card.\n */\n bundle: string\n /** Family list-seat entry id. */\n id: string\n /** Family list-seat sort order. */\n order?: number\n /** Family list-seat display label; the official keyed seat carries none. */\n label?: () => string\n /** Locale namespace the card renders with. */\n locale: string\n /** Business-face factory of the registration. */\n inject?: () => object\n /**\n * The card component. Its props type is the seat's composed shape, which is\n * chosen at runtime, so the helper takes it erased; the registrant keeps its\n * own precise typing at the call site.\n */\n component: unknown\n}\n\n/**\n * Whether the family group (dsh-web-settings) is loaded in this page. The\n * service is the group package's own contract, so the probe cannot be fooled\n * by a harness release that starts declaring the official seat differently.\n */\nexport function familyGroupLoaded(ctx: PluginCardContext): boolean {\n const get = ctx.get\n if (typeof get !== 'function') return false\n try {\n return get.call(ctx, FAMILY_GROUP_SERVICE) !== undefined\n } catch {\n // A context that refuses the lookup: treat the group as absent, which\n // falls back to the official seat the harness declares.\n return false\n }\n}\n\n/** Report a refused registration instead of leaving the user with no card. */\nfunction warnRefusedSeat(seat: string, error: unknown): void {\n try {\n console.warn(`[dsh-web] plugin card registration into \"${seat}\" was refused; the card will not render`, error)\n } catch {\n // Best-effort console write; a failed warning must not break the plugin.\n }\n}\n\n/**\n * Contribute one family plugin card to the seat this host renders, following\n * the group if it loads later. The entry is disposed and re-registered on a\n * seat change, never duplicated.\n * @param ctx - client context (its slot registry decides the seat).\n * @param seat - the card contribution.\n */\nexport function installPluginCard(ctx: PluginCardContext, seat: PluginCardSeat): void {\n const slots = ctx.slots\n const component = seat.component as never\n const inject = seat.inject as never\n\n let dispose: (() => void) | undefined\n let current: string | undefined\n /**\n * Re-entrancy latch. The registry emits a change event synchronously from\n * inside both `register` and the previous entry's disposer, so an unguarded\n * reconcile would re-enter itself mid-move and register the card twice into\n * the seat it is leaving (\"already has an entry for key ...\").\n */\n let reconciling = false\n\n /** Reconcile the contribution with the currently live seat (no-op when unchanged). */\n const reconcile = (): void => {\n if (reconciling) return\n const target = familyGroupLoaded(ctx) ? FAMILY_PLUGIN_CARD_SEAT : OFFICIAL_PLUGIN_CARD_SEAT\n if (current === target) return\n reconciling = true\n const previous = dispose\n dispose = undefined\n current = undefined\n previous?.()\n try {\n dispose = slots.register((target === FAMILY_PLUGIN_CARD_SEAT\n ? {\n name: FAMILY_PLUGIN_CARD_SEAT,\n id: seat.id,\n ...(seat.order === undefined ? {} : { order: seat.order }),\n ...(seat.label === undefined ? {} : { label: seat.label }),\n locale: seat.locale,\n ...(seat.inject === undefined ? {} : { inject }),\n }\n : {\n name: OFFICIAL_PLUGIN_CARD_SEAT,\n key: seat.bundle,\n locale: seat.locale,\n ...(seat.inject === undefined ? {} : { inject }),\n }) as never, component) as () => void\n current = target\n } catch (error) {\n warnRefusedSeat(target, error)\n } finally {\n reconciling = false\n }\n }\n\n if (typeof ctx.on === 'function') {\n try {\n ctx.on('slots/changed', () => { reconcile() })\n } catch {\n // An event seat that refuses the subscription leaves the initial\n // decision in place; the card still renders in the seat chosen below.\n }\n }\n // The initial decision: the group, when it is already loaded (the aggregate\n // order), otherwise the official seat the harness declares.\n reconcile()\n}\n","/**\n * Task-board client plugin: wires the framework-free core (controller,\n * execution service, store) to the real client runtime and mounts the two\n * DOM surfaces — the sidebar entry row and the board view in the center\n * column.\n *\n * Failure policy: DOM mounting problems are logged, never thrown — the web\n * shell fails the whole boot when a plugin apply throws, and an external\n * plugin must not take the GUI down.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { ClientRemote, SessionId } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { IWorkspaces } from '@deepseek-ai/dsh-api-workspace-controller/client'\nimport type { ConfigForm, ConfigForms } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\n// Type-only: pulls the locale plugin's Context merge (ctx.locale) and its\n// LocaleNamespaceMap merge table.\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the shared-forms Context merge (ctx.configForms).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: pulls the workspace plugin's Context merge (ctx.uiWorkspace), the\n// multi-instance navigation face that replaced ISessions.open().\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { BoardController } from '../core/controller.ts'\nimport { mainViewSessionId } from './main-session.ts'\nimport { LocalStorageTaskStore } from '../core/store.ts'\nimport { claimTaskboardApply, releaseTaskboardApply } from './apply-guard.ts'\nimport { mountBoard } from './board-mount.tsx'\nimport { mountSidebarEntry } from './sidebar-entry.ts'\nimport { TaskBoardSettingsCard, TaskBoardSettingsCardController, type TaskBoardSettings } from './TaskBoardSettingsCard.tsx'\nimport { en, zh, setRuntimeTranslate, type TaskBoardKey } from './locales.ts'\nimport { HttpTaskBoardHostTransport } from './host-api.ts'\nimport { reportDailyHeartbeat } from './telemetry.ts'\nimport { installPluginCard } from './plugin-card-seat.ts'\n\n/** Locale namespace this plugin owns. */\nconst NS = 'task-board'\n\n/** Settings namespace this card edits (the family identity of the plugin's own settings form). */\nconst TASK_BOARD_NS = 'task-board'\n\n/**\n * Profile entry id the family aggregate's generated row carries — the\n * deployment shape nearly every user runs. Under 0.1.7 a settings form is\n * addressed by profile entry id, so the shared-forms fallback below has to\n * name it; the family binder resolves the family namespace instead.\n */\nconst AGGREGATE_ENTRY_ID = 'web-ui-task-board'\n\n/**\n * Profile entry ids this package's two patch rows carry: the aggregate's\n * generated row and the standalone bundle patch's row (`ui-task-board`), plus\n * the bare namespace as the last resort for a Host whose descriptor is keyed\n * by the family namespace itself.\n */\nconst TASK_BOARD_ENTRY_IDS: readonly string[] = [AGGREGATE_ENTRY_ID, 'ui-task-board', TASK_BOARD_NS]\n\n/** Domain-owned description of one settings namespace a family card binds. */\nexport interface SettingsFormSpec<T> {\n /** Settings namespace the card edits. */\n namespace: string\n /**\n * Narrow one wire section; undefined keeps the last accepted value. The\n * shared form already resolves the namespace's own serialized wire schema,\n * so a decoder exists only to narrow beyond that schema.\n */\n decode?: (section: unknown) => T | undefined\n}\n\n/**\n * The family settings binder published by dsh-web-settings. Its `bind` resolves\n * a family namespace to the profile entry id that owns it and hands back the\n * shared configuration form, so it is the only seat that can reach this card's\n * form on a Host whose row id is not the namespace.\n */\nexport interface SettingsFormBinder {\n /** Bind one family settings namespace. */\n bind<T>(spec: SettingsFormSpec<T>): ConfigForm<T>\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Task-board surface copy. */\n 'task-board': TaskBoardKey\n }\n\n interface SlotMap {\n /**\n * The child slot the Web UI plugin group declares; this card registers\n * into the group's list seat rather than the official\n * bundle-configuration seat. Spelled here with the same shape so this\n * package can register without depending on the sibling UI package.\n */\n 'web-ui.plugin.item': { kind: 'list'; scope: 'root'; owner: SettingsPluginItemOwnerProps }\n }\n}\n\n/** Owner share of a plugin card (the section supplies nothing). */\nexport interface SettingsPluginItemOwnerProps {\n /** Marker field: card owner props are intentionally empty. */\n children?: never\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /**\n * Optional family settings binder provided by dsh-web-settings; absent\n * when that group plugin is not installed, so callers fall back to the\n * shared configuration forms service.\n */\n webUiSettings?: SettingsFormBinder\n }\n}\n\n\n/**\n * Required services (fiber inject waiting — the runtime must be up first).\n * The generated remote faces are probed at use time instead of injected:\n * `remote.agentPresets` only registers on 0.1.2-alpha.2 hosts (the\n * api-remotes contribution), so a hard wait would pend the entry forever\n * on hosts below that cohort, which serve the same roster through the\n * connection RPC face.\n */\nexport const inject = ['slots', 'sessions', 'workspaces', 'connection', 'configForms', 'locale', 'remote', 'remote.session', 'uiWorkspace']\n\n/** One agent-preset row the mode picker consumes (either face's wire shape). */\ninterface PresetRosterRow {\n id: string\n name?: string\n description?: string\n /** Why this preset cannot compose a session; absent when it can. */\n broken?: string\n isDefault: boolean\n}\n\n/**\n * Read the agent-preset roster through whichever face the running host\n * serves: the generated api-remotes face (`remote.agentPresets`,\n * 0.1.2-alpha.2) or the connection RPC face\n * (`connection.api.agentPresets`, hosts below that cohort). Answers\n * undefined when the host serves neither, so the caller leaves the picker\n * options untouched instead of erroring.\n */\nasync function readPresetRoster(\n ctx: ClientContext,\n remote: ClientRemote,\n): Promise<{ ok: boolean; presets: readonly PresetRosterRow[] } | undefined> {\n // The cordis `remote` proxy throws on a property that was never injected\n // (\"cannot get property X without inject\") rather than returning undefined,\n // so the probe must guard the access — a hard read would abort mounting on\n // hosts below the 0.1.2-alpha.2 cohort instead of degrading to the legacy\n // connection RPC face below.\n let remotes: ClientRemote['agentPresets'] | undefined\n try {\n remotes = (remote as Partial<ClientRemote>).agentPresets\n } catch {\n remotes = undefined\n }\n if (remotes !== undefined) {\n const response = await remotes.list()\n if (!response.ok) return { ok: false, presets: [] }\n return { ok: true, presets: response.value.presets }\n }\n const connection = ctx.get('connection') as unknown as {\n api?: { agentPresets?: { list(request: Record<string, never>): Promise<{ result: { ok: boolean; value?: { presets?: readonly PresetRosterRow[] } } }> } }\n }\n const legacy = connection.api?.agentPresets\n if (legacy === undefined) return undefined\n const response = await legacy.list({})\n if (!response.result.ok || response.result.value === undefined) return { ok: false, presets: [] }\n return { ok: true, presets: response.result.value.presets ?? [] }\n}\n\n/**\n * Mount the task board.\n * @param ctx - client root context (services: sessions, workspaces).\n */\nexport function apply(ctx: ClientContext): void {\n // Anonymous install heartbeat (docs/telemetry.md): one beat per browser per\n // UTC day, package name only, silent failure.\n reportDailyHeartbeat([{ name: '@linxin666/dsh-client-ui-task-board' }])\n\n // A duplicated client injection (module factory executed twice in one page\n // lifetime) would otherwise mount a second sidebar entry and board view.\n // First application wins; later calls become no-ops (see apply-guard.ts).\n if (!claimTaskboardApply()) return\n\n // Release the claim when this fiber unloads (the loader supports plugin\n // unloads / hot-reloads), so a rebuilt bundle can claim again in the same\n // page instead of being silently dropped.\n ctx.effect(() => releaseTaskboardApply, 'task-board: apply claim')\n\n ctx.effect(() => {\n try {\n return ctx.locale.register(NS, { zh, en })\n } catch {\n return () => {}\n }\n }, 'task-board: dictionaries')\n\n // Wire the SDK translate seat into the module-level t (sidebar row and\n // other plain-DOM callers): reads the active locale at call time, so they\n // follow the Language setting without a reload. The register effect above\n // guarantees the dictionaries exist before the first read.\n try { setRuntimeTranslate(ctx.locale.bind(NS)) } catch { /* locale missing: document-language fallback stays */ }\n\n // Plugin configuration card: one staged form over the `task-board` settings\n // namespace, contributed to whichever plugin-card seat this host declares\n // (the family group's list seat, or the official bundle-configuration seat).\n const settingsForm = bindSettingsForm(ctx)\n const settingsCard = new TaskBoardSettingsCardController(settingsForm)\n installPluginCard(ctx, {\n bundle: '@linxin666/dsh-client-ui-task-board',\n id: 'task-board',\n order: 110,\n locale: NS,\n inject: () => settingsCard.inject(),\n component: TaskBoardSettingsCard,\n })\n ctx.effect(() => () => { settingsCard.dispose() }, 'task-board: settings card')\n\n // The sidebar entry and board view mount once the settings form settles;\n // while the form is still loading, the composition default is unknown, so\n // nothing mounts yet. Only an unavailable form (no settings surface served)\n // falls back to the composition default (enabled).\n let uiDisposer: (() => void) | undefined\n const mountUi = (): void => {\n if (uiDisposer !== undefined) return\n // Host and browser SDK declarations share the Cordis Context name. Read\n // the browser faces explicitly so Host-side declaration merging cannot\n // narrow these two client services during a combined package build.\n const sessions = ctx.get('sessions') as unknown as ISessions\n const workspaces = ctx.get('workspaces') as unknown as IWorkspaces\n const remote = ctx.get('remote') as unknown as ClientRemote\n\n // Core wiring: real runtime faces into the framework-free services.\n const store = new LocalStorageTaskStore()\n const controller = new BoardController({\n store,\n transport: new HttpTaskBoardHostTransport(),\n sessions: {\n // The main-view Session comes from the catalog's per-source ownership\n // counts; navigation belongs to the workspace UI since the\n // multi-instance Client Session model.\n current: () => mainViewSessionId(sessions.list.getSnapshot().byId),\n open: id => ctx.uiWorkspace.openSession(id as never),\n subscribe: fn => sessions.list.subscribe(fn),\n },\n })\n controller.start()\n\n const disposers: Array<() => void> = []\n\n // Execution-target option feeds: the workspace list drives the workspace\n // picker, and the agent-preset roster drives the mode picker. Both are\n // runtime facts (not ledger state), so the wiring pushes them into the\n // controller on change; the preset roster is re-read after reconnects\n // because a reconnect may serve a different deployment.\n const pushWorkspaceOptions = (): void => {\n const snapshot = workspaces.list.getSnapshot()\n controller.setExecutionOptions({\n workspaces: snapshot.items.map(item => ({\n workspaceId: item.workspaceId,\n title: item.title !== '' ? item.title : item.path,\n })),\n })\n }\n pushWorkspaceOptions()\n disposers.push(workspaces.list.subscribe(pushWorkspaceOptions))\n // \"New project\" on the board is the GUI's own add-project call (#1536);\n // the runtime emits the created Workspace through workspaces.list, which\n // refreshes the filter above without a local re-read.\n controller.setWorkspaceCreator(async path => {\n const created = await workspaces.create({ path })\n return { workspaceId: created.workspaceId }\n })\n const pushPresetOptions = async (): Promise<void> => {\n try {\n const roster = await readPresetRoster(ctx, remote)\n if (roster === undefined || !roster.ok) return\n controller.setExecutionOptions({\n presets: roster.presets.map(preset => ({\n id: preset.id,\n name: preset.name,\n description: preset.description,\n broken: preset.broken,\n isDefault: preset.isDefault,\n })),\n })\n } catch (error) {\n // A failed roster read leaves the previous options in place; the\n // picker stays usable and the next reconnect retries the read.\n console.error('[dsh-task-board] agent preset roster read failed', error)\n }\n }\n const pushModelOptions = async (): Promise<void> => {\n try {\n let models: Array<{ id: string; name?: string; provider?: string }> = []\n let sessionRemote: ClientRemote['session'] | undefined\n try {\n sessionRemote = (remote as Partial<ClientRemote>).session\n } catch {\n sessionRemote = undefined\n }\n if (typeof sessionRemote?.modelCatalog === 'function') {\n const res = await sessionRemote.modelCatalog()\n if (res.ok && Array.isArray(res.value?.groups)) {\n for (const g of res.value.groups) {\n const provider = (g as { id?: string; provider?: string }).id ?? (g as { id?: string; provider?: string }).provider\n for (const m of g.models ?? []) {\n const qualifiedId = provider ? `${provider}/${m.id}` : m.id\n models.push({ id: qualifiedId, name: m.name ?? m.id, provider })\n }\n }\n }\n }\n if (models.length === 0) {\n const conn = ctx.get('connection') as {\n api?: {\n llm?: { discoverModels?: () => Promise<unknown> }\n sessions?: { modelCatalog?: () => Promise<unknown> }\n session?: { modelCatalog?: () => Promise<unknown> }\n }\n } | undefined\n if (conn?.api) {\n if (typeof conn.api.llm?.discoverModels === 'function') {\n const res = await conn.api.llm.discoverModels() as { result?: { value?: { models?: Array<{ id: string; name?: string }> } } }\n const list = res?.result?.value?.models\n if (Array.isArray(list)) {\n models = list.map(m => ({ id: m.id, name: m.name }))\n }\n }\n const catalogFn = typeof conn.api.session?.modelCatalog === 'function'\n ? conn.api.session.modelCatalog\n : typeof conn.api.sessions?.modelCatalog === 'function'\n ? conn.api.sessions.modelCatalog\n : undefined\n if (models.length === 0 && catalogFn !== undefined) {\n const res = await catalogFn() as { result?: { value?: { groups?: Array<{ id?: string; provider?: string; models?: Array<{ id: string; name?: string }> }> } } }\n const groups = res?.result?.value?.groups\n if (Array.isArray(groups)) {\n for (const g of groups) {\n const provider = g.id ?? g.provider\n for (const m of g.models ?? []) {\n const qualifiedId = provider ? `${provider}/${m.id}` : m.id\n models.push({ id: qualifiedId, name: m.name ?? m.id, provider })\n }\n }\n }\n }\n }\n }\n if (models.length > 0) {\n controller.setExecutionOptions({ models })\n }\n } catch (error) {\n console.error('[dsh-task-board] model options read failed', error)\n }\n }\n void pushModelOptions()\n disposers.push(ctx.on('connection/reset', () => { void pushModelOptions() }))\n try {\n disposers.push(mountSidebarEntry(controller, ctx.locale))\n disposers.push(mountBoard(controller, ctx.locale))\n } catch (error) {\n // DOM failures degrade the board, never the GUI.\n console.error('[dsh-task-board] mount failed:', error)\n }\n\n uiDisposer = () => {\n for (const dispose of disposers.splice(0)) dispose()\n controller.dispose()\n uiDisposer = undefined\n }\n }\n const syncEnabled = (): void => {\n const snapshot = settingsForm.getSnapshot()\n const enabled = snapshot.status === 'ready'\n ? snapshot.value?.enabled ?? true\n : snapshot.status === 'unavailable'\n if (enabled) mountUi()\n else uiDisposer?.()\n }\n const unsubscribeSettings = settingsForm.subscribe(syncEnabled)\n // The mounted surfaces and the settings subscription belong to this fiber.\n // The loader replaces a rebuilt bundle IN PLACE (fiber teardown and re-apply\n // without a page reload), and that same teardown removes the dictionaries\n // this row and board render through — a row left behind would stay visible\n // showing raw dictionary keys, and a surviving subscription could mount a\n // second one from a dead instance.\n ctx.effect(() => () => {\n unsubscribeSettings()\n uiDisposer?.()\n }, 'task-board: DOM surfaces')\n syncEnabled()\n}\n\n/**\n * Bind the settings form this card stages over.\n *\n * The family binder (`ctx.get('webUiSettings')`, published by dsh-web-settings)\n * comes first: it is what traces this package's family namespace onto the\n * profile entry id the Host serves the form under, and it keeps the loopback\n * bridge as its own fallback. A page without that group falls back to the\n * shared configuration forms service bound directly at one of this package's\n * own profile entry ids.\n * @param ctx - client root context.\n * @returns the form the settings card reads and writes.\n */\nexport function bindSettingsForm(ctx: ClientContext): ConfigForm<TaskBoardSettings> {\n const binder = ctx.get('webUiSettings')\n if (binder !== undefined && typeof binder.bind === 'function') {\n return binder.bind<TaskBoardSettings>({ namespace: TASK_BOARD_NS })\n }\n return ctx.configForms.get<TaskBoardSettings>(servedEntryId(ctx.configForms))\n}\n\n/**\n * The profile entry id this package's own row carries.\n *\n * The shared describe mirror is the only local evidence of which row id this\n * profile actually serves, but it answers asynchronously: at plugin\n * activation it usually holds nothing yet. An unanswered mirror therefore\n * binds the aggregate row id rather than guessing among the candidates —\n * the form is bound once for the session, so a wrong guess would leave the\n * card reporting an unserved namespace even after the mirror settles.\n * @param forms - the shared configuration forms service.\n * @returns the entry id to bind.\n */\nfunction servedEntryId(forms: ConfigForms): string {\n let served: readonly string[] | undefined\n try {\n served = forms.describe().getSnapshot().view?.namespaces.map(view => view.ns)\n } catch {\n served = undefined\n }\n if (served === undefined) return AGGREGATE_ENTRY_ID\n return TASK_BOARD_ENTRY_IDS.find(id => served.includes(id)) ?? TASK_BOARD_NS\n}\n"],"mappings":";;;;;;;;;;;;;;;EAoKA,SAAgB,cAAc,OAAuC;GACnE,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;GAClC,MAAM,OAAkB,CAAC;GACzB,MAAM,uBAAO,IAAI,IAAY;GAC7B,KAAK,MAAM,SAAS,OAAO;IACzB,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;IACzE,MAAM,MAAM;IACZ,IAAI,OAAO,IAAI,SAAS,UAAU;IAClC,MAAM,OAAO,IAAI,KAAK,KAAK;IAC3B,IAAI,SAAS,MAAM,KAAK,SAAA,MAAgC,KAAK,IAAI,IAAI,GAAG;IACxE,MAAM,MAAM,OAAO,IAAI,iBAAiB,WAAW,IAAI,aAAa,KAAK,IAAI;IAC7E,MAAM,eAAe,QAAQ,KAAK,KAAA,IAAY,IAAI,MAAM,GAAA,GAAwB;IAChF,KAAK,IAAI,IAAI;IACb,KAAK,KAAK,iBAAiB,KAAA,IAAY,EAAE,KAAK,IAAI;KAAE;KAAM;IAAa,CAAC;IACxE,IAAI,KAAK,UAAA,GAA0B;GACrC;GACA,OAAO,KAAK,WAAW,IAAI,KAAA,IAAY;EACzC;;;;;;EAOA,SAAgB,QAAQ,MAAsB;GAC5C,IAAI,OAAO;GACX,KAAK,MAAM,QAAQ,MAAM,OAAQ,OAAO,MAAM,KAAK,YAAY,CAAC,KAAK,OAAQ;GAC7E,OAAO,OAAO;EAChB;;;;;;EAOA,SAAgB,iBAAiB,OAAyC;GACxE,MAAM,QAAmB,CAAC;GAC1B,MAAM,uBAAO,IAAI,IAAY;GAC7B,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,OAAO,KAAK,QAAQ,CAAC,GAAG;IACjC,IAAI,KAAK,IAAI,IAAI,IAAI,GAAG;IACxB,KAAK,IAAI,IAAI,IAAI;IACjB,MAAM,KAAK,GAAG;GAChB;GAEF,OAAO;EACT;;;;;;;EA6GA,MAAa,sBAA6C;GAAC;GAAW;GAAQ;GAAQ;EAAQ;;EAI9F,MAAa,mBAAmB;GAAC;GAAa;GAAmB;EAAoB;;EAMrF,SAAgB,iBAAiB,OAAyC;GACxE,OAAO,OAAO,UAAU,YAAa,iBAAuC,SAAS,KAAK;EAC5F;;EAiDA,MAAa,UAA4D;GACvE;IAAE,QAAQ;IAAW,OAAO;GAAM;GAClC;IAAE,QAAQ;IAAQ,OAAO;GAAK;GAC9B;IAAE,QAAQ;IAAW,OAAO;GAAM;GAClC;IAAE,QAAQ;IAAQ,OAAO;GAAM;GAC/B;IAAE,QAAQ;IAAU,OAAO;GAAM;EACnC;;EAGA,MAAa,kBAAyC,CAAC,WAAW,MAAM;;EAMxE,MAAa,eAAsC;GACjD;GAAW;GAAQ;GAAW;GAAQ;EACxC;;EAGA,SAAgB,aAAa,OAAqC;GAChE,OAAO,OAAO,UAAU,YAAa,aAAmC,SAAS,KAAK;EACxF;;EAGA,SAAgB,gBAAgB,MAAkB,IAAyB;GACzE,OAAO,SAAS,aAAc,gBAA0C,SAAS,EAAE;EACrF;;EAGA,SAAgB,kBAAkB,OAA+C;GAC/E,MAAM,UAAU,OAAO,KAAK;GAC5B,OAAO,YAAY,KAAA,KAAa,YAAY,KAAK,KAAA,IAAY;EAC/D;;;;;EAMA,SAAgB,SACd,OACA,KACY;GACZ,OAAO;IACL,MAAM,MAAM;IACZ,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ,UAAU;IACV,GAAI,MAAM,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACpD,GAAI,MAAM,aAAa,KAAA,KAAa,MAAM,aAAa,KAAK,CAAC,IAAI,EAAE,UAAU,MAAM,SAAS;GAC9F;EACF;;EAGA,SAAgB,WAAW,OAAqB,KAAa,IAAwB;GACnF,MAAM,OAAO,cAAc,MAAM,IAAI;GACrC,OAAO;IACL;IACA,OAAO,MAAM,MAAM,KAAK;IACxB,aAAa,MAAM,YAAY,KAAK;IACpC,QAAQ,MAAM,OAAO,KAAK;IAC1B,UAAU,kBAAkB,MAAM,QAAQ;IAC1C,QAAQ;IACR,WAAW;IACX,WAAW;IACX,YAAY,CAAC;IACb,aAAa,kBAAkB,MAAM,WAAW;IAChD,MAAM,kBAAkB,MAAM,IAAI;IAClC,YAAY,iBAAiB,MAAM,UAAU,IAAI,MAAM,aAAa,KAAA;IACpE,OAAO,kBAAkB,MAAM,KAAK;IACpC,cAAc,MAAM,iBAAiB,OAAO,OAAO,KAAA;IACrD,SAAS,MAAM,YAAY,OAAO,OAAO,KAAA;IACvC,GAAI,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,SAAS,MAAM,QAAQ,GAAG,EAAE;IAC5E,GAAI,MAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;KAAE,GAAG,MAAM;KAAU,WAAW;IAAI,EAAE;IAC1F,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;GACvC;EACF;;EAGA,SAAgB,WAAW,MAAkB,QAAoB,KAAyB;GACxF,OAAO;IAAE,GAAG;IAAM;IAAQ,WAAW;GAAI;EAC3C;;;;;;;EAQA,SAAgB,aACd,MACA,OACA,KACY;GACZ,MAAM,UAAU,KAAK;GACrB,MAAM,WAAyB;IAC7B,SAAS,SAAS,WAAW;IAC7B,MAAM,SAAS,QAAQ;IACvB,WAAW,SAAS;IACpB,iBAAiB,SAAS;GAC5B;GACA,IAAI,aAAa,OAAO,SAAS,UAAU,MAAM,WAAW;GAC5D,IAAI,UAAU,OAAO,SAAS,OAAO,MAAM,QAAQ;GACnD,IAAI,eAAe,OAAO,SAAS,YAAY,MAAM;GACrD,IAAI,qBAAqB,OAAO,SAAS,kBAAkB,MAAM;GACjE,OAAO;IAAE,GAAG;IAAM,WAAW;IAAK;GAAS;EAC7C;;EAqEA,SAAgB,eAAe,WAAoC;GACjE,IAAI,UAAU,WAAW,aAAa,OAAO;GAC7C,IAAI,UAAU,WAAW,UAAU,OAAO;GAC1C,IAAI,UAAU,WAAW,aAAa,OAAO;GAC7C,OAAO;EACT;;;;;;ECvhBA,SAAgB,sBAAsB,OAAwB;GAC5D,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG,OAAA;GAC1D,MAAM,QAAQ,KAAK,MAAM,KAAK;GAC9B,IAAI,QAAA,GAA2B,OAAA;GAC/B,IAAI,QAAA,GAA2B,OAAA;GAC/B,OAAO;EACT;;EAGA,SAAgB,mBAAmB,OAA2C;GAC5E,OAAO,UAAU,eAAe,UAAU,YAAY,UAAU;EAClE;EAEA,SAAS,QAAQ,OAAuD;GACtE,OAAO,IAAI,IAAI,MAAM,KAAI,SAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;EACnD;;;;;;;EAQA,SAAgB,cAAc,OAA8B,MAAgC;GAC1F,MAAM,QAAQ,QAAQ,KAAK;GAC3B,MAAM,QAAsB,CAAC;GAC7B,MAAM,uBAAO,IAAI,IAAY,CAAC,KAAK,EAAE,CAAC;GACtC,IAAI,UAAU,KAAK,aAAa,KAAA,IAAY,KAAA,IAAY,MAAM,IAAI,KAAK,QAAQ;GAC/E,OAAO,YAAY,KAAA,KAAa,MAAM,SAAS,MAAM,QAAQ;IAC3D,IAAI,KAAK,IAAI,QAAQ,EAAE,GAAG;IAC1B,KAAK,IAAI,QAAQ,EAAE;IACnB,MAAM,KAAK,OAAO;IAClB,UAAU,QAAQ,aAAa,KAAA,IAAY,KAAA,IAAY,MAAM,IAAI,QAAQ,QAAQ;GACnF;GACA,OAAO;EACT;;EAGA,SAAgB,UAAU,OAA8B,IAAoB;GAC1E,MAAM,OAAO,QAAQ,KAAK,CAAC,CAAC,IAAI,EAAE;GAClC,OAAO,SAAS,KAAA,IAAY,IAAI,cAAc,OAAO,IAAI,CAAC,CAAC;EAC7D;;EAGA,SAAgB,eAAe,OAA8B,IAA0B;GACrF,OAAO,MAAM,QAAO,SAAQ,KAAK,aAAa,EAAE;EAClD;;;;;EAMA,SAAgB,gBAAgB,OAA8B,IAAY,iBAAuC;GAC/G,MAAM,0BAAU,IAAI,IAAY,CAAC,EAAE,CAAC;GACpC,MAAM,QAAsB,CAAC;GAC7B,IAAI,WAAW,CAAC,EAAE;GAClB,KAAK,IAAI,QAAQ,GAAG,SAAS,mBAAmB,SAAS,SAAS,GAAG,SAAS,GAAG;IAC/E,MAAM,OAAiB,CAAC;IACxB,KAAK,MAAM,YAAY,UACrB,KAAK,MAAM,QAAQ,OAAO;KACxB,IAAI,KAAK,aAAa,YAAY,QAAQ,IAAI,KAAK,EAAE,GAAG;KACxD,QAAQ,IAAI,KAAK,EAAE;KACnB,MAAM,KAAK,IAAI;KACf,KAAK,KAAK,KAAK,EAAE;IACnB;IAEF,WAAW;GACb;GACA,OAAO;EACT;;;;;;EAOA,SAAgB,cAAc,OAA8B,IAAY,0BAA+B,IAAI,IAAY,GAAW;GAChI,IAAI,QAAQ,IAAI,EAAE,GAAG,OAAO;GAC5B,MAAM,uBAAO,IAAI,IAAI,CAAC,GAAG,SAAS,EAAE,CAAC;GACrC,MAAM,WAAW,eAAe,OAAO,EAAE;GACzC,IAAI,SAAS,WAAW,GAAG,OAAO;GAClC,IAAI,SAAS;GACb,KAAK,MAAM,SAAS,UAAU,SAAS,KAAK,IAAI,QAAQ,IAAI,cAAc,OAAO,MAAM,IAAI,IAAI,CAAC;GAChG,OAAO,KAAK,IAAI,QAAA,CAAyB;EAC3C;;;;;;;;EAyBA,SAAgB,gBACd,OACA,SACA,UACA,iBACiB;GAEjB,IADc,MAAM,MAAK,SAAQ,KAAK,OAAO,OACrC,MAAM,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAe;GACpE,IAAI,aAAa,QAAQ,aAAa,IAAI,OAAO,EAAE,IAAI,KAAK;GAC5D,IAAI,aAAa,SAAS,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAc;GACpE,MAAM,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,QAAQ;GACtD,IAAI,WAAW,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAiB;GACvE,IAAI,OAAO,eAAe,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAkB;GACnF,IAAI,gBAAgB,OAAO,SAAA,CAA0B,CAAC,CAAC,MAAK,SAAQ,KAAK,OAAO,QAAQ,GAAG,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAQ;GAE/H,IADc,UAAU,OAAO,QAAQ,IAAI,IAAI,cAAc,OAAO,OAAO,IAC/D,iBAAiB,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAiB;GAC1E,OAAO,EAAE,IAAI,KAAK;EACpB;;;;;EA6EA,SAAgB,wBAAwB,MAA4C;GAClF,OAAO,KAAK,UAAU,cAAc,KAAK;EAC3C;;;;;;;;;;;;;;;;EC7MA,SAAS,SAAS,OAA8B,IAAY,iBAAyB,eAAqC;GACxH,MAAM,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,EAAE;GAChD,MAAM,sBAAM,IAAI,IAAY,CAAC,EAAE,CAAC;GAChC,KAAK,MAAM,QAAQ,gBAAgB,OAAO,IAAI,sBAAsB,eAAe,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE;GACtG,IAAI,iBAAiB,WAAW,KAAA,GAC9B,KAAK,MAAM,YAAY,cAAc,OAAO,MAAM,GAAG,IAAI,IAAI,SAAS,EAAE;GAE1E,OAAO;EACT;;;;;;;EAQA,SAAgB,iBACd,OACA,IACA,KACA,kBAAA,GACmB;GACnB,MAAM,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,EAAE;GAChD,IAAI,WAAW,KAAA,KAAa,OAAO,eAAe,KAAA,GAAW,OAAO;IAAE;IAAO,UAAU;GAAM;GAC7F,MAAM,MAAM,SAAS,OAAO,IAAI,iBAAiB,KAAK;GAEtD,IADkB,MAAM,MAAK,SAAQ,IAAI,IAAI,KAAK,EAAE,KAAK,CAAE,oBAA0C,SAAS,KAAK,MAAM,CAC7G,GAAG,OAAO;IAAE;IAAO,UAAU;GAAM;GAC/C,IAAI,UAAU;GAcd,OAAO;IAAE,OAbI,MAAM,KAAI,SAAQ;KAC7B,IAAI,CAAC,IAAI,IAAI,KAAK,EAAE,KAAK,KAAK,eAAe,KAAA,GAAW,OAAO;KAC/D,UAAU;KACV,MAAM,WAAW,KAAK,aAAa,KAAA,IAC/B,KAAA,IACA;MAAE,GAAG,KAAK;MAAU,SAAS;MAAO,WAAW,KAAA;KAAU;KAC7D,OAAO;MACL,GAAG;MACH,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;MAC7C,YAAY;MACZ,WAAW;KACb;IACF,CACmB;IAAG,UAAU;GAAQ;EAC1C;;;;;EAMA,SAAgB,iBACd,OACA,IACA,KACA,kBAAA,GACmB;GACnB,MAAM,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,EAAE;GAChD,IAAI,WAAW,KAAA,KAAa,OAAO,eAAe,KAAA,GAAW,OAAO;IAAE;IAAO,UAAU;GAAM;GAC7F,MAAM,MAAM,SAAS,OAAO,IAAI,iBAAiB,IAAI;GACrD,IAAI,UAAU;GAOd,OAAO;IAAE,OANI,MAAM,KAAI,SAAQ;KAC7B,IAAI,CAAC,IAAI,IAAI,KAAK,EAAE,KAAK,KAAK,eAAe,KAAA,GAAW,OAAO;KAC/D,UAAU;KACV,MAAM,EAAE,YAAY,WAAW,GAAG,SAAS;KAC3C,OAAO;MAAE,GAAG;MAAM,WAAW;KAAI;IACnC,CACmB;IAAG,UAAU;GAAQ;EAC1C;;;;EC7DA,MAAM,eAAyD;GAC7D,CAAC,GAAG,EAAE;GACN,CAAC,GAAG,EAAE;GACN,CAAC,GAAG,EAAE;GACN,CAAC,GAAG,EAAE;GACN,CAAC,GAAG,CAAC;EACP;;;;;EAMA,SAAgB,UAAU,MAAmC;GAC3D,MAAM,SAAS,KAAK,KAAK,CAAC,CAAC,MAAM,KAAK;GACtC,IAAI,OAAO,WAAW,GAAG,OAAO;GAChC,MAAM,OAAsB,CAAC;GAC7B,KAAK,IAAI,QAAQ,GAAG,QAAQ,GAAG,SAAS;IACtC,MAAM,CAAC,KAAK,OAAO,aAAa;IAChC,MAAM,sBAAM,IAAI,IAAY;IAC5B,IAAI,CAAC,WAAW,OAAO,QAAQ,KAAK,KAAK,GAAG,GAAG,OAAO;IACtD,KAAK,KAAK,GAAG;GACf;GACA,MAAM,2BAAW,IAAI,IAAY;GACjC,KAAK,MAAM,OAAO,KAAK,IAAI,SAAS,IAAI,QAAQ,IAAI,IAAI,GAAG;GAC3D,OAAO;IACL,SAAS,KAAK;IACd,OAAO,KAAK;IACZ,MAAM,KAAK;IACX,QAAQ,KAAK;IACb;IAIA,aAAa,OAAO,OAAO;IAC3B,iBAAiB,OAAO,OAAO;GACjC;EACF;;EAGA,SAAgB,YAAY,MAAuB;GACjD,OAAO,UAAU,IAAI,MAAM;EAC7B;;;;;;;;;;;;;;;;EAiBA,SAAgB,YAAY,MAAc,QAAoC;GAC5E,MAAM,WAAW,UAAU,IAAI;GAC/B,IAAI,aAAa,MAAM,OAAO,KAAA;GAC9B,IAAI,CAAC,uBAAuB,QAAQ,GAAG,OAAO,KAAA;GAC9C,MAAM,OAAO,IAAI,KAAK,MAAM;GAC5B,MAAM,UAAU,SAAS,IAAI,MAAM,KAAK,KAAK,KAAK;GAElD,MAAM,gBAAgB,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;GAChE,MAAM,cAAc,CAAC,GAAG,SAAS,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;GAC5D,MAAM,eAAe,CAAC,GAAG,SAAS,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;GAE9D,IAAI,OAAO,KAAK,YAAY;GAC5B,IAAI,QAAQ,KAAK,SAAS,IAAI;GAC9B,IAAI,MAAM,KAAK,QAAQ;GACvB,IAAI,OAAO,KAAK,SAAS;GAEzB,IAAI,SAAS,KAAK,WAAW,IAAI;GAEjC,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS;IACpE,KAAK,MAAM,kBAAkB,cAAc;KACzC,IAAI,iBAAiB,OAAO;KAC5B,MAAM,cAAc,IAAI,KAAK,MAAM,gBAAgB,CAAC,CAAC,CAAC,QAAQ;KAC9D,MAAM,WAAW,mBAAmB,QAAQ,MAAM;KAClD,KAAK,IAAI,eAAe,UAAU,gBAAgB,aAAa,gBAAgB,GAAG;MAEhF,IAAI,CAAC,aAAa,UAAU,IADP,KAAK,MAAM,iBAAiB,GAAG,cAAc,GAAG,GAAG,GAAG,CACxC,CAAC,GAAG;MACvC,MAAM,YAAY,mBAAmB,SAAS,iBAAiB,MAAM,OAAO;MAC5E,KAAK,MAAM,iBAAiB,aAAa;OACvC,IAAI,gBAAgB,WAAW;OAC/B,MAAM,cAAc,mBAAmB,SAAS,iBAAiB,OAAO,kBAAkB,OAAO,SAAS;OAC1G,KAAK,MAAM,mBAAmB,eAAe;QAC3C,IAAI,kBAAkB,aAAa;QACnC,MAAM,YAAY,IAAI,KAAK,MAAM,iBAAiB,GAAG,cAAc,eAAe,iBAAiB,GAAG,CAAC;QACvG,MAAM,OAAO,UAAU,QAAQ;QAC/B,IAAI,QAAQ,QAAQ;QACpB,IAAI,OAAO,SAAS,OAAO,KAAA;QAC3B,IAAI,QAAQ,UAAU,SAAS,GAAG,OAAO;OAC3C;MACF;KACF;IACF;IACA,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,OAAO;IACP,SAAS;GACX;EAEF;;EAGA,SAAS,aAAa,UAAwB,MAAqB;GACjE,MAAM,aAAa,SAAS,KAAK,IAAI,KAAK,QAAQ,CAAC;GACnD,MAAM,iBAAiB,SAAS,SAAS,IAAI,KAAK,OAAO,CAAC;GAC1D,IAAI,SAAS,aAAa,OAAO;GACjC,IAAI,SAAS,iBAAiB,OAAO;GACrC,OAAO,cAAc;EACvB;;EAGA,SAAS,uBAAuB,UAAiC;GAC/D,IAAI,SAAS,eAAe,CAAC,SAAS,iBAAiB,OAAO;GAC9D,MAAM,6BAAa,IAAI,IAAoB;IACzC,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IACnD,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IAAG,CAAC,GAAG,EAAE;IAAG,CAAC,IAAI,EAAE;IAAG,CAAC,IAAI,EAAE;IAAG,CAAC,IAAI,EAAE;GACxD,CAAC;GACD,KAAK,MAAM,SAAS,SAAS,QAAQ;IACnC,MAAM,UAAU,WAAW,IAAI,KAAK,KAAK;IACzC,IAAI,CAAC,GAAG,SAAS,IAAI,CAAC,CAAC,MAAK,QAAO,OAAO,OAAO,GAAG,OAAO;GAC7D;GACA,OAAO;EACT;;EAGA,SAAS,WAAW,OAAe,KAAa,KAAa,KAA2B;GACtF,IAAI,UAAU,KAAK;IACjB,KAAK,IAAI,QAAQ,KAAK,SAAS,KAAK,SAAS,IAAI,IAAI,KAAK;IAC1D,OAAO;GACT;GACA,KAAK,MAAM,QAAQ,MAAM,MAAM,GAAG,GAAG;IACnC,IAAI,SAAS,IAAI,OAAO;IACxB,MAAM,CAAC,OAAO,WAAW,KAAK,MAAM,GAAG;IACvC,IAAI;IACJ,IAAI;IACJ,IAAI,UAAU,KAAK;KACjB,MAAM;KACN,OAAO;IACT,OAAO,IAAI,MAAM,SAAS,GAAG,GAAG;KAC9B,MAAM,CAAC,GAAG,KAAK,MAAM,MAAM,GAAG;KAC9B,IAAI,MAAM,MAAM,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,OAAO;KACjE,MAAM,OAAO,CAAC;KACd,OAAO,OAAO,CAAC;IACjB,OAAO,IAAI,SAAS,KAAK,GAAG;KAC1B,MAAM,OAAO,KAAK;KAIlB,OAAO,YAAY,KAAA,IAAY,MAAM;IACvC,OACE,OAAO;IAET,IAAI,MAAM,OAAO,OAAO,OAAO,MAAM,MAAM,OAAO;IAClD,MAAM,OAAO,YAAY,KAAA,IAAY,IAAI,SAAS,OAAO,IAAI,OAAO,OAAO,IAAI;IAC/E,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GAAG,OAAO;IAChD,KAAK,IAAI,QAAQ,KAAK,SAAS,MAAM,SAAS,MAAM,IAAI,IAAI,KAAK;GACnE;GACA,OAAO;EACT;;EAGA,SAAS,QAAQ,UAAwB,MAAqB;GAC5D,IAAI,CAAC,SAAS,QAAQ,IAAI,KAAK,WAAW,CAAC,GAAG,OAAO;GACrD,IAAI,CAAC,SAAS,MAAM,IAAI,KAAK,SAAS,CAAC,GAAG,OAAO;GACjD,IAAI,CAAC,SAAS,OAAO,IAAI,KAAK,SAAS,IAAI,CAAC,GAAG,OAAO;GACtD,OAAO,aAAa,UAAU,IAAI;EACpC;EAEA,SAAS,SAAS,OAAwB;GACxC,OAAO,QAAQ,KAAK,KAAK;EAC3B;;;;;;;;;;;;;;;;;;;;;;;;EC3KA,SAAgB,gBACd,OACA,OACA,KACA,IACA,kBAAA,GACkB;GAClB,IAAI,MAAM,MAAM,KAAK,MAAM,IAAI,OAAO;IAAE,MAAM,KAAA;IAAW;IAAO,OAAO;GAAoB;GAC3F,MAAM,QAAQ,sBAAsB,eAAe;GACnD,IAAI;GACJ,IAAI,MAAM,aAAa,KAAA,GAAW;IAChC,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,MAAM,QAAQ;IACtD,IAAI,WAAW,KAAA,GAAW,OAAO;KAAE,MAAM,KAAA;KAAW;KAAO,OAAO;IAAwB;IAC1F,IAAI,OAAO,eAAe,KAAA,GAAW,OAAO;KAAE,MAAM,KAAA;KAAW;KAAO,OAAO;IAA0B;IACvG,IAAI,UAAU,OAAO,OAAO,EAAE,IAAI,IAAI,OACpC,OAAO;KAAE,MAAM,KAAA;KAAW;KAAO,OAAO,wBAAwB,MAAM;IAAY;GAEtF;GAcA,IAAI,OAAO,WANqB,WAAW,KAAA,IAAY,QAAQ;IAC7D,GAAG;IACH,aAAa,MAAM,eAAe,OAAO;IACzC,MAAM,MAAM,QAAQ,OAAO;IAC3B,OAAO,MAAM,SAAS,OAAO;GAC/B,GACiC,KAAK,EAAE;GAIxC,MAAM,YAAY,MAAM;GACxB,IAAI,WAAW,YAAY,QAAQ,UAAU,KAAK,KAAK,MAAM,MAAM,YAAY,UAAU,IAAI,GAAG;IAC9F,MAAM,OAAO,UAAU,KAAK,KAAK;IACjC,OAAO,aAAa,MAAM;KAAE,SAAS;KAAM;KAAM,WAAW,YAAY,MAAM,GAAG;IAAE,GAAG,GAAG;GAC3F;GACA,OAAO;IAAE;IAAM,OAAO,CAAC,GAAG,OAAO,IAAI;GAAE;EACzC;;;;;;;;;;EChDA,SAAgB,gBACd,OACA,gBACA,IACkB;GAClB,IAAI,MAAM,MAAK,SAAQ,KAAK,aAAa,EAAE,GACzC,OAAO;IAAE;IAAO,kBAAkB;IAAO,SAAS;GAAK;GAGzD,OAAO;IACL,OAFW,MAAM,QAAO,SAAQ,KAAK,OAAO,EAElC;IACV,kBAAkB,mBAAmB;IACrC,SAAS;GACX;EACF;;;;;;;;;;;;;;;;;;ECVA,SAAgB,iBACd,OACA,IACA,OACA,KACmB;GACnB,MAAM,OAAO,MAAM,MAAK,cAAa,UAAU,OAAO,EAAE;GACxD,IAAI,SAAS,KAAA,KAAa,KAAK,eAAe,KAAA,GAAW,OAAO;IAAE;IAAO,SAAS;GAAM;GACxF,MAAM,UAAU,KAAK;GACrB,MAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ,GAAA,CAAI,KAAK;GACtD,IAAI,SAAS,MAAM,CAAC,YAAY,IAAI,GAAG,OAAO;IAAE;IAAO,SAAS;GAAM;GACtE,MAAM,UAAU,MAAM,WAAW,SAAS,WAAW;GACrD,MAAM,YAAY,UAAU,YAAY,MAAM,GAAG,IAAI,KAAA;GACrD,IAAI,WAAW,cAAc,KAAA,GAAW,OAAO;IAAE;IAAO,SAAS;GAAM;GACvE,OAAO;IACL,OAAO,MAAM,KAAI,cACf,UAAU,OAAO,KAAK,aAAa,WAAW;KAAE;KAAS;KAAM;IAAU,GAAG,GAAG,IAAI,SAAS;IAC9F,SAAS;GACX;EACF;;;;;;;;;;;EAYA,SAAgB,qBACd,OACA,IACA,WACA,iBACA,KACuB;GACvB,OAAO,MAAM,KAAI,SACf,KAAK,OAAO,MAAM,KAAK,eAAe,KAAA,KAAa,KAAK,aAAa,KAAA,IACjE,aAAa,MAAM;IAAE;IAAW;GAAgB,GAAG,GAAG,IACtD,IAAI;EACZ;;;;;;;;;;ECtDA,MAAM,iBAAsD;GAC1D,gBAAgB;GAChB,kBAAkB;GAClB,mBAAmB;GACnB,eAAe;GACf,SAAS;GACT,kBAAkB;EACpB;;;;;;;;;;;EAYA,SAAgB,eACd,OACA,IACA,UACA,KACA,kBAAA,GACiB;GACjB,MAAM,OAAO,MAAM,MAAK,cAAa,UAAU,OAAO,EAAE;GACxD,IAAI,SAAS,KAAA,GAAW,OAAO;IAAE;IAAO,SAAS;IAAO,OAAO,eAAe;GAAgB;GAC9F,IAAI,KAAK,eAAe,KAAA,GAAW,OAAO;IAAE;IAAO,SAAS;IAAO,OAAO;GAA6B;GAIvG,IAAI,KAAK,WAAW,aAAa,KAAK,WAAW,MAAK,cAAa,UAAU,YAAY,KAAA,CAAS,GAChG,OAAO;IAAE;IAAO,SAAS;IAAO,OAAO;GAAqC;GAE9E,MAAM,QAAQ,gBAAgB,OAAO,IAAI,UAAU,sBAAsB,eAAe,CAAC;GACzF,IAAI,CAAC,MAAM,IAAI,OAAO;IAAE;IAAO,SAAS;IAAO,OAAO,eAAe,MAAM,UAAU;GAAgB;GACrG,MAAM,eAAe,aAAa,QAAQ,aAAa,KAAK,KAAA,IAAY;GACxE,IAAI,iBAAiB,KAAK,UAAU,OAAO;IAAE,OAAO,CAAC,GAAG,KAAK;IAAG,SAAS;GAAK;GAC9E,OAAO;IACL,OAAO,MAAM,KAAI,cAAa,UAAU,OAAO,KAAK;KAAE,GAAG;KAAW,UAAU;KAAc,WAAW;IAAI,IAAI,SAAS;IACxH,SAAS;GACX;EACF;;;;;;;;;;;;;;;;;;EC3BA,MAAa,sBAAsB;GAAC;GAAS;GAAe;EAAQ;;;;;;EAYpE,SAAgB,mBAAmB,MAA2B;GAC5D,OAAO,KAAK,eAAe,KAAA,KAAa,KAAK,WAAW,aAAa,KAAK,WAAW,WAAW;EAClG;;EAGA,SAAS,oBACP,SACA,OAC4B;GAC5B,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;GAChC,OAAO,iBAAiB,KAAK,IAAI,QAAQ;EAC3C;;;;;;;;;EAUA,SAAgB,gBACd,OACA,IACA,OACA,KACuB;GACvB,OAAO,MAAM,KAAI,SAAQ;IACvB,IAAI,KAAK,OAAO,IAAI,OAAO;IAC3B,MAAM,EAAE,QAAQ,aAAa,UAAU,eAAe,MAAM,WAAW,GAAG,SAAS;IACnF,MAAM,cAAc,iBAAiB,QAAQ,kBAAkB,MAAM,WAAW,IAAI,KAAA;IACpF,MAAM,OAAO,UAAU,QAAQ,kBAAkB,MAAM,IAAI,IAAI,KAAA;IAC/D,MAAM,aAAa,gBAAgB,QAAQ,oBAAoB,KAAK,YAAY,MAAM,UAAU,IAAI,KAAA;IACpG,MAAM,QAAQ,WAAW,QAAQ,kBAAkB,MAAM,KAAK,IAAI,KAAA;IAClE,MAAM,OAAmB;KAAE,GAAG;KAAM,GAAG;KAAM,WAAW;IAAI;IAG5D,KAAK,MAAM,SAAS,qBAAqB;KACvC,IAAI,EAAE,SAAS,QAAQ;KACvB,MAAM,QAAQ,MAAM;KACpB,KAAK,SAAS,UAAU,KAAA,IAAY,KAAK,SAAS,MAAM,KAAK;IAC/D;IAGA,KAAK,SAAS,eAAe,OAAO,KAAA,IAAY,SAAS,aAAa,GAAG;IAEzE,KAAK,WAAW,iBAAiB,OAAO,KAAA,IAAY;KAAE,GAAG;KAAe,WAAW;IAAI;IAGvF,IAAI,UAAU,OAAO,KAAK,OAAO,aAAa,OAAO,KAAA,IAAY,cAAc,SAAS;IAKxF,IAAK,gBAAgB,SAAS,MAAM,eAAe,KAAA,KAAa,MAAM,eAAe,KAAK,cAAe,cAAc,OACrH,KAAK,wBAAwB,KAAA;IAI/B,IAAI,kBAAkB,OAAO,KAAK,eAAe,MAAM,iBAAiB,OAAO,OAAO,KAAA;IAEtF,IAAI,aAAa,OAAO,KAAK,UAAU,MAAM,YAAY,OAAO,OAAO,KAAA;IACvE,IAAI,gBAAgB,KAAA,KAAa,iBAAiB,OAAO,KAAK,cAAc;IAC5E,IAAI,SAAS,KAAA,KAAa,UAAU,OAAO,KAAK,OAAO;IACvD,IAAI,eAAe,KAAA,KAAa,gBAAgB,OAAO,KAAK,aAAa;IACzE,IAAI,UAAU,KAAA,KAAa,WAAW,OAAO,KAAK,QAAQ;IAC1D,OAAO;GACT,CAAC;EACH;;;ECxDA,SAAS,UAAU,UAAkE;GACnF,OAAO,UAAU,QAAQ;EAC3B;;EA+EA,SAAgB,eAAe,UAAsD;GACnF,IAAI,SAAS,mBAAmB,KAAA,GAAW,OAAO,KAAA;GAClD,OAAO,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,SAAS,cAAc;EACxE;EAEA,SAAS,aAAqB;GAC5B,MAAM,aAAa,WAAW,QAAQ;GACtC,IAAI,eAAe,KAAA,GACjB,OAAO,WAAW,KAAK,WAAW,MAAO;GAE3C,MAAM,QAAQ,WAAW,QAAQ,gCAAgB,IAAI,WAAW,EAAE,CAAC;GACnE,IAAI,UAAU,KAAA,GAEZ,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;GAE/E,MAAM,KAAM,MAAM,KAAK,KAAQ;GAC/B,MAAM,KAAM,MAAM,KAAK,KAAQ;GAC/B,MAAM,MAAM,MAAM,KAAK,QAAO,SAAQ,KAAK,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;GACjF,OAAO,GAAG,IAAI,MAAM,GAAG,CAAC,EAAE,GAAG,IAAI,MAAM,GAAG,EAAE,EAAE,GAAG,IAAI,MAAM,IAAI,EAAE,EAAE,GAAG,IAAI,MAAM,IAAI,EAAE,EAAE,GAAG,IAAI,MAAM,EAAE;EACzG;EAEA,SAAS,UAAU,OAAwB;GACzC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC9D;;;;;EAMA,IAAa,kBAAb,MAA6B;GAmBE;GAlB7B,QAA8B,CAAC;GAC/B,YAAoB;GACpB,cAAsB;GACtB;GACA,mBAAqD;IAAE,YAAY,CAAC;IAAG,SAAS,CAAC;IAAG,QAAQ,CAAC;GAAE;GAC/F;GACA,4BAAoB,IAAI,IAAgB;GACxC,YAAuC,CAAC;GACxC;GACA;GACA,iCAAkC,IAAI,IAAY;GAClD,6BAA8B,IAAI,IAA2B;GAC7D;GACA;GACA,mBAA2B;GAC3B;;GAGA,YAAY,MAAuC;IAAtB,KAAA,OAAA;IAC3B,KAAK,MAAM,KAAK,cAAc,KAAK,IAAI;IACvC,KAAK,OAAO,KAAK,QAAQ;GAC3B;;GAKA,QAAc;IACZ,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK;IAClC,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW,KAAU,iBAAiB;IAKlE,MAAM,sBAAsB,KAAK,KAAK,cAAc,KAAA,IAAY,KAAK,KAAK,MAAM,0BAA0B;KACxG,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK;KAClC,KAAK,OAAO;IACd,CAAC,IAAI,KAAA;IACL,IAAI,wBAAwB,KAAA,GAAW,KAAK,UAAU,KAAK,mBAAmB;IAC9E,KAAK,UAAU,KAAK,KAAK,KAAK,SAAS,gBAAgB;KACrD,KAAK,kBAAkB;IACzB,CAAC,CAAC;IACF,KAAK,OAAO;GACd;;GAGA,UAAgB;IACd,KAAK,MAAM,WAAW,KAAK,UAAU,OAAO,CAAC,GAAG,QAAQ;IACxD,KAAK,UAAU,MAAM;GACvB;GAIA,cAAkC;IAChC,OAAO;KACL,OAAO,KAAK;KACZ,WAAW,KAAK;KAChB,aAAa,KAAK;KAClB,gBAAgB,KAAK;KACrB,kBAAkB,KAAK;KACvB,gBAAgB,CAAC,GAAG,KAAK,cAAc;KACvC,GAAI,KAAK,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,oBAAoB,KAAK;KAC1E,GAAI,OAAO,KAAK,KAAK,WAAW,eAAe,aAAa,EAAE,cAAc,KAAK,IAAI,CAAC;KACtF,GAAI,KAAK,mBAAmB,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,KAAK,eAAe;KACnF,GAAI,KAAK,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU;IACjE;GACF;GAEA,UAAU,IAA4B;IACpC,KAAK,UAAU,IAAI,EAAE;IACrB,aAAa;KAAE,KAAK,UAAU,OAAO,EAAE;IAAE;GAC3C;;GAGA,eAAwB;IACtB,OAAO,KAAK,KAAK,cAAc,KAAA;GACjC;;GAGA,MAAM,gBAAkC;IACtC,OAAO,MAAM,KAAK,iBAAiB;GACrC;GAIA,YAAkB;IAChB,IAAI,KAAK,WAAW;IACpB,KAAK,YAAY;IACjB,KAAK,OAAO;GACd;GAEA,aAAmB;IACjB,KAAK,YAAY;IACjB,KAAK,OAAO;GACd;GAEA,cAAoB;IAClB,IAAI,KAAK,WAAW,KAAK,WAAW;SAC/B,KAAK,UAAU;GACtB;;;;;;GAOA,oBAA0B;IACxB,KAAK,cAAc,CAAC,KAAK;IACzB,IAAI,CAAC,KAAK,eAAe,KAAK,mBAAmB,KAAA;SAC9B,KAAK,MAAM,MAAK,SAAQ,KAAK,OAAO,KAAK,cAC/C,CAAC,EAAE,eAAe,KAAA,GAAW,KAAK,iBAAiB,KAAA;IAAA;IAEhE,KAAK,OAAO;GACd;GAEA,SAAS,IAAkB;IACzB,IAAI,KAAK,MAAM,MAAK,SAAQ,KAAK,OAAO,EAAE,GAAG;KAC3C,KAAK,iBAAiB;KACtB,KAAK,OAAO;IACd;GACF;GAEA,YAAkB;IAChB,IAAI,KAAK,mBAAmB,KAAA,GAAW;IACvC,KAAK,iBAAiB,KAAA;IACtB,KAAK,OAAO;GACd;GAIA,WAAW,OAA6C;IACtD,MAAM,KAAK,KAAK,KAAK;IACrB,MAAM,EAAE,MAAM,UAAU,gBAAgB,KAAK,OAAO,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,YAAY,CAAC;IAC7F,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;IAC/B,KAAK,QAAQ,CAAC,GAAG,KAAK;IACtB,KAAK,iBAAiB;IACtB,OAAO;GACT;;GAGA,MAAM,oBAAoB,OAAsD;IAC9E,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW,OAAO,KAAK,WAAW,KAAK;IACnE,MAAM,KAAK,KAAK,KAAK;IAKrB,IADgB,gBAAgB,KAAK,OAAO,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,SACvE,KAAA,GAAW,OAAO,KAAA;IAClC,OAAO,MAAM,KAAK,aAAa;KAAE,MAAM;KAAU;KAAI;IAAM,GAAG,EAAE,IAC5D,KAAK,MAAM,MAAK,SAAQ,KAAK,OAAO,EAAE,IACtC,KAAA;GACN;;;;;;;;;GAUA,MAAM,WAAW,IAAY,OAA0C;IACrE,IAAI,KAAK,KAAK,cAAc,KAAA,GAC1B,OAAO,MAAM,KAAK,aAAa;KAAE,MAAM;KAAU,QAAQ;KAAI;IAAM,GAAG,EAAE;IAE1E,KAAK,QAAQ,CAAC,GAAG,gBAAgB,KAAK,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC;IACnE,KAAK,iBAAiB;IACtB,OAAO;GACT;;;;;GAMA,oBAAoB,OAAgD;IAClE,KAAK,mBAAmB;KAAE,GAAG,KAAK;KAAkB,GAAG;IAAM;IAC7D,KAAK,OAAO;GACd;;GAGA,oBAAoB,SAA6C;IAC/D,KAAK,mBAAmB;IACxB,KAAK,OAAO;GACd;;;;;GAMA,MAAM,gBAAgB,MAAgD;IACpE,IAAI,KAAK,qBAAqB,KAAA,GAAW,MAAM,IAAI,MAAM,mCAAmC;IAC5F,OAAO,MAAM,KAAK,iBAAiB,IAAI;GACzC;;GAGA,eAAwB;IACtB,OAAO,OAAO,KAAK,KAAK,WAAW,eAAe;GACpD;;;;;GAMA,MAAM,eAAe,SAAgC,QAAoD;IACvG,MAAM,YAAY,KAAK,KAAK;IAC5B,MAAM,QAAQ,WAAW;IACzB,IAAI,cAAc,KAAA,KAAa,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,6BAA6B;IACjG,OAAO,MAAM,MAAM,KAAK,WAAW,SAAS,MAAM;GACpD;GAEA,SAAS,IAAY,QAA0B;IAC7C,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,KAAU,aAAa;MAAE,MAAM;MAAQ,QAAQ;MAAI;KAAO,GAAG,EAAE;KAC/D;IACF;IACA,KAAK,QAAQ,KAAK,MAAM,KAAI,SAAQ,KAAK,OAAO,KAAK,WAAW,MAAM,QAAQ,KAAK,IAAI,CAAC,IAAI,IAAI;IAChG,KAAK,iBAAiB;GACxB;GAEA,WAAW,IAAkB;IAC3B,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,KAAU,aAAa;MAAE,MAAM;MAAU,QAAQ;KAAG,GAAG,EAAE;KACzD;IACF;IACA,MAAM,EAAE,OAAO,qBAAqB,gBAAgB,KAAK,OAAO,KAAK,gBAAgB,EAAE;IACvF,KAAK,QAAQ,CAAC,GAAG,KAAK;IACtB,IAAI,kBAAkB,KAAK,iBAAiB,KAAA;IAC5C,KAAK,iBAAiB;GACxB;;;;;;GAOA,YAAY,IAAqB;IAC/B,MAAM,EAAE,OAAO,aAAa,iBAAiB,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,YAAY,CAAC;IAC3F,IAAI,CAAC,UAAU,OAAO;IACtB,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,KAAU,aAAa;MAAE,MAAM;MAAW,QAAQ;KAAG,GAAG,EAAE;KAC1D,OAAO;IACT;IACA,KAAK,QAAQ,CAAC,GAAG,KAAK;IACtB,KAAK,iBAAiB;IACtB,OAAO;GACT;;;;;;;;GASA,MAAM,UAAU,IAAY,UAA2C;IACrE,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,MAAM,SAAS,eAAe,KAAK,OAAO,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK,YAAY,CAAC;KACtF,IAAI,CAAC,OAAO,SAAS,OAAO;KAC5B,KAAK,QAAQ,CAAC,GAAG,OAAO,KAAK;KAC7B,KAAK,iBAAiB;KACtB,OAAO;IACT;IACA,OAAO,MAAM,KAAK,aAAa;KAAE,MAAM;KAAc,QAAQ;KAAI;IAAS,GAAG,EAAE;GACjF;;GAGA,YAAY,IAAqB;IAC/B,MAAM,EAAE,OAAO,aAAa,iBAAiB,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,YAAY,CAAC;IAC3F,IAAI,CAAC,UAAU,OAAO;IACtB,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,KAAU,aAAa;MAAE,MAAM;MAAW,QAAQ;KAAG,GAAG,EAAE,CAAC,CAAC,MAAK,aAAY;MAC3E,IAAI,YAAY,KAAK,mBAAmB,IAAI,KAAK,UAAU;KAC7D,CAAC;KACD,OAAO;IACT;IACA,KAAK,QAAQ,CAAC,GAAG,KAAK;IACtB,IAAI,KAAK,mBAAmB,IAAI,KAAK,iBAAiB,KAAA;IACtD,KAAK,iBAAiB;IACtB,OAAO;GACT;;;;;;;;;;GAaA,YAAY,IAAY,OAAsD;IAC5E,MAAM,EAAE,OAAO,YAAY,iBAAiB,KAAK,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC;IAC7E,IAAI,CAAC,SAAS,OAAO;IACrB,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,KAAU,aAAa;MAAE,MAAM;MAAgB,QAAQ;MAAI;KAAM,GAAG,EAAE;KACtE,OAAO;IACT;IACA,KAAK,QAAQ,CAAC,GAAG,KAAK;IACtB,KAAK,iBAAiB;IACtB,OAAO;GACT;;;;;GAMA,qBAAqB,IAAY,WAA+B,iBAA2C;IACzG,MAAM,OAAOA,qBAAyB,KAAK,OAAO,IAAI,WAAW,iBAAiB,KAAK,IAAI,CAAC;IAC5F,KAAK,QAAQ,CAAC,GAAG,IAAI;IACrB,KAAK,iBAAiB;GACxB;;;;;GAMA,kBAAwB;IACtB,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK;GACpC;;;;;;GAOA,YAAY,WAAyB;IACnC,KAAK,WAAW;IAChB,KAAK,KAAK,SAAS,KAAK,SAAS;GACnC;;;;;;;GAUA,MAAM,QAAQ,IAA8B;IAC1C,MAAM,OAAO,KAAK,MAAM,MAAK,cAAa,UAAU,OAAO,EAAE;IAC7D,IAAI,SAAS,KAAA,KAAa,KAAK,eAAe,KAAA,KAAa,KAAK,WAAW,WAAW,OAAO;IAC7F,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW,OAAO;IAC9C,OAAO,MAAM,KAAK,aAAa;KAAE,MAAM;KAAO,QAAQ;IAAG,GAAG,IAAI,UAAU,KAAK,KAAK,QAAQ,CAAC;GAC/F;;;;;GAMA,MAAM,kBAAkB,IAA8B;IAEpD,IADa,KAAK,MAAM,MAAK,cAAa,UAAU,OAAO,EACpD,MAAM,KAAA,GAAW,OAAO;IAC/B,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;KACrC,KAAK,QAAQ,KAAK,MAAM,KAAI,cAAa,UAAU,OAAO,KACtD;MAAE,GAAG;MAAW,uBAAuB,KAAK,IAAI;MAAG,WAAW,KAAK,IAAI;KAAE,IACzE,SAAS;KACb,KAAK,iBAAiB;KACtB,OAAO;IACT;IACA,OAAO,MAAM,KAAK,aAAa;KAAE,MAAM;KAAsB,QAAQ;IAAG,GAAG,EAAE;GAC/E;;GAGA,MAAM,UAAU,IAA2B;IACzC,MAAM,OAAO,KAAK,MAAM,MAAK,cAAa,UAAU,OAAO,EAAE;IAC7D,IAAI,SAAS,KAAA,KAAa,KAAK,eAAe,KAAA,GAAW;IACzD,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW;IACvC,MAAM,KAAK,aAAa;KAAE,MAAM;KAAS,QAAQ;IAAG,GAAG,IAAI,UAAU,KAAK,KAAK,QAAQ,CAAC;GAC1F;;;;;;;;;;;GAcA,oBAAkC,CAElC;GAEA,mBAAiC;IAC/B,IAAI,KAAK,KAAK,cAAc,KAAA,GAAW,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK;IACtE,KAAK,OAAO;GACd;GAEA,MAAc,aAAa,QAAyB,QAAiB,WAAsC;IAEzG,IADkB,KAAK,KAAK,cACV,KAAA,GAAW,OAAO;IACpC,IAAI,WAAW,KAAA,GAAW,OAAO,MAAM,KAAK,cAAc,QAAQ,SAAS;IAE3E,MAAM,aADW,KAAK,WAAW,IAAI,MAAM,KAAK,QAAQ,QAAQ,EAAA,CACrC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,MAAM,KAAK,cAAc,QAAQ,SAAS,CAAC;IACvG,MAAM,OAAO,UAAU,WAAW,CAAC,SAAS,CAAC,CAAC;IAC9C,KAAK,WAAW,IAAI,QAAQ,IAAI;IAChC,KAAK,eAAe,IAAI,MAAM;IAC9B,KAAK,OAAO;IACZ,IAAI;KACF,OAAO,MAAM;IACf,UAAU;KACR,IAAI,KAAK,WAAW,IAAI,MAAM,MAAM,MAAM;MACxC,KAAK,WAAW,OAAO,MAAM;MAC7B,KAAK,eAAe,OAAO,MAAM;MACjC,KAAK,OAAO;KACd;IACF;GACF;GAEA,MAAc,cAAc,QAAyB,WAAsC;IACzF,MAAM,YAAY,KAAK,KAAK;IAC5B,IAAI,cAAc,KAAA,GAAW,OAAO;IACpC,KAAK,iBAAiB,KAAA;IACtB,KAAK,OAAO;IACZ,IAAI;KAEF,OADiB,KAAK,aAAa,MAAM,UAAU,OAAO,QAAQ,SAAS,CAC7D,KAAK,MAAM,KAAK,cAAc;IAC9C,SAAS,OAAO;KACd,MAAM,KAAK,cAAc,UAAU,KAAK,CAAC;KACzC,OAAO;IACT;GACF;GAEA,MAAc,mBAAqC;IACjD,IAAI,KAAK,yBAAyB,KAAA,GAAW,OAAO,MAAM,KAAK;IAC/D,MAAM,iBAAiB,KAAK,mBAAmB;IAC/C,KAAK,uBAAuB;IAC5B,IAAI;KACF,OAAO,MAAM;IACf,UAAU;KACR,IAAI,KAAK,yBAAyB,gBAAgB,KAAK,uBAAuB,KAAA;IAChF;GACF;GAEA,MAAc,qBAAuC;IACnD,MAAM,YAAY,KAAK,KAAK;IAC5B,IAAI,cAAc,KAAA,GAAW,OAAO;IACpC,IAAI;KACF,KAAK,aAAa,MAAM,UAAU,UAAU,KAAK,KAAK,CAAC;KACvD,IAAI,CAAC,KAAK,kBAAkB;MAC1B,KAAK,mBAAmB;MACxB,KAAK,UAAU,KAAK,UAAU,WAAW,UAAU;OAAE,KAAK,cAAc,KAAK;MAAE,CAAC,CAAC;KACnF;KACA,OAAO;IACT,SAAS,OAAO;KACd,KAAK,iBAAiB,UAAU,KAAK;KACrC,KAAK,OAAO;KACZ,OAAO;IACT;GACF;;;;;;;GAQA,cAAsB,OAAgD;IACpE,IAAI,UAAU,KAAA,KAAa,KAAK,cAAc,KAAA,KAAa,MAAM,aAAa,KAAK,UAAU,YACxF,OAAO,MAAM,cAAc,YAAY,MAAM,cAAc,QAC3D,OAAO,MAAM,UAAU,YAAY,MAAM,UAAU,MAAM;KAC5D,KAAK,YAAY;MAAE,GAAG,KAAK;MAAW,UAAU,MAAM;MAAU,WAAW,MAAM;MAAW,OAAO,MAAM;KAAM;KAC/G,KAAK,OAAO;KACZ;IACF;IACA,KAAU,cAAc;GAC1B;;;;;;GAOA,cAA8B;IAC5B,OAAO,KAAK,WAAW,mBAAA;GACzB;;;;;;;;;GAUA,SAAiB,UAAyC;IACxD,MAAM,2BAA2B,SAAS,4BAA4B,KAAK,WAAW;IACtF,MAAM,kBAAkB,SAAS,mBAAmB,KAAK,WAAW;IACpE,MAAM,mBAAmB,SAAS,oBAAoB,KAAK,WAAW;IACtE,OAAO;KACL,UAAU,SAAS;KACnB,WAAW,SAAS;KACpB,OAAO,SAAS;KAChB,GAAI,6BAA6B,KAAA,IAAY,CAAC,IAAI,EAAE,yBAAyB;KAC7E,GAAI,oBAAoB,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB;KAC3D,GAAI,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB;IAC/D;GACF;GAEA,MAAc,cAAc,eAA0C;IACpE,MAAM,YAAY,KAAK,KAAK;IAC5B,IAAI,cAAc,KAAA,GAAW,OAAO;IACpC,IAAI;KACF,KAAK,aAAa,MAAM,UAAU,MAAM,CAAC;KACzC,IAAI,kBAAkB,KAAA,GAAW;MAC/B,KAAK,iBAAiB;MACtB,KAAK,OAAO;KACd;KACA,OAAO;IACT,SAAS,OAAO;KACd,KAAK,iBAAiB,iBAAiB,UAAU,KAAK;KACtD,KAAK,OAAO;KACZ,OAAO;IACT;GACF;GAEA,aAAqB,UAAsC;IAIzD,IAHwB,KAAK,WAAW,UAAU,aAC7B,SAAS,UAAU,YAElB,KAAK,cAAc,KAAA,KAAa,SAAS,WAAW,KAAK,UAAU,UAAU,OAAO;IAC1G,KAAK,QAAQ,CAAC,GAAG,SAAS,KAAK;IAC/B,KAAK,YAAY,KAAK,SAAS,QAAQ;IACvC,KAAK,iBAAiB,KAAA;IACtB,IAAI,KAAK,mBAAmB,KAAA,KAAa,CAAC,KAAK,MAAM,MAAK,SAAQ,KAAK,OAAO,KAAK,cAAc,GAC/F,KAAK,iBAAiB,KAAA;IAExB,IAAI,CAAC,KAAK,eAAe,KAAK,mBAAmB,KAAA,KAC5C,KAAK,MAAM,MAAK,SAAQ,KAAK,OAAO,KAAK,cAAc,CAAC,EAAE,eAAe,KAAA,GAC5E,KAAK,iBAAiB,KAAA;IAExB,KAAK,OAAO;IACZ,OAAO;GACT;GAEA,SAAuB;IACrB,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,SAAS,GAAG,GAAG;GAC3C;EACF;;;;;;;;;;;;ECvqBA,SAAgB,kBACd,MACgB;GAChB,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM,OAAO,KAAA;GAChD,KAAK,MAAM,OAAO,OAAO,OAAyC,IAAI,GACpE,IAAI,QAAQ,KAAA,MAAc,IAAI,YAAY,YAAY,KAAK,GAAG,OAAO,IAAI;EAG7E;;EC9BA,MAAa,kBAAkB;EAgB/B,MAAM,QAAQ;EACd,MAAM,MAAM;EAEZ,MAAM,+BAAgD,IAAI,IAAI;GAC5D,CAAC,OAAO,MAAM;GACd,CAAC,OAAO,UAAU;GAClB,CAAC,QAAQ,MAAM;EACjB,CAAC;EAID,MAAM,gBAAuC;GAAC;GAAQ;GAAY;EAAM;EAExE,MAAM,gBAA4C;GAChD,MAAM;GACN,UAAU;GACV,MAAM;EACR;;;;;;;EAQA,MAAM,qBAA+B;GACnC;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EAEA,SAAS,KAAK,MAAc,SAA+B;GACzD,OAAO;IAAE,IAAI;IAAO,OAAO;KAAE;KAAM;IAAQ;GAAE;EAC/C;EAEA,SAAS,UAAU,MAAsB;GACvC,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;EACxC;;EAGA,SAAgB,gBAAgB,MAAmD;GACjF,IAAI,MAAM;GACV,IAAI,WAAW;GACf,KAAK,MAAM,WAAW,oBAAoB;IACxC,IAAI,QAAQ,KAAK,GAAG,GAAG;KACrB,WAAW;KACX,MAAM,IAAI,QAAQ,SAAS,eAAe;IAC5C;IACA,QAAQ,YAAY;GACtB;GACA,OAAO;IAAE,MAAM;IAAK;GAAS;EAC/B;;;;;;EAOA,SAAgB,qBAAqB,MAAuB;GAC1D,OAAO,KAAK,MAAM,OAAO,CAAC,CAAC,MAAK,SAAQ,YAAY,KAAK,IAAI,KAAK,KAAK,WAAW,GAAG,CAAC;EACxF;;;;;;;;;;;EAYA,SAAgB,uBACd,OACA,YAA+B,CAAC,GACsH;GACtJ,MAAM,OAAO,MAAc,aAAqB;IAAE,IAAI;IAAgB,OAAO;KAAE;KAAM;IAAQ;GAAE;GAC/F,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,OAAO,IAAI,kBAAkB,kCAAkC;GAEjE,MAAM,SAAS;GACf,MAAM,UAAU;IAAC;IAAQ;IAAY;IAAQ,GAAG;GAAS;GACzD,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,OAAM,QAAO,QAAQ,SAAS,GAAG,CAAC,GACzD,OAAO,IAAI,kBAAkB,YAAY;GAE3C,KAAK,MAAM,OAAO,eAChB,IAAI,OAAO,OAAO,SAAS,UACzB,OAAO,IAAI,kBAAkB,YAAY,cAAc,OAAO,SAAS;GAG3E,KAAK,MAAM,OAAO,eAChB,IAAI,qBAAqB,OAAO,IAAc,GAC5C,OAAO,IAAI,oBAAoB,UAAU,cAAc,OAAO,mBAAmB;GAGrF,IAAI,WAAW;GACf,MAAM,WAAuC;IAAE,MAAM;IAAI,UAAU;IAAI,MAAM;GAAG;GAChF,KAAK,MAAM,OAAO,eAAe;IAC/B,MAAM,SAAS,gBAAgB,OAAO,IAAc;IACpD,SAAS,OAAO,OAAO;IACvB,WAAW,YAAY,OAAO;GAChC;GACA,KAAK,MAAM,OAAO,eAChB,IAAI,UAAU,SAAS,IAAI,IAAA,MACzB,OAAO,IAAI,mBAAmB,YAAY,cAAc,OAAO,cAAc;GAGjF,MAAM,SAAkC,CAAC;GACzC,KAAK,MAAM,OAAO,WAAW,IAAI,OAAO,QAAQ,OAAO,OAAO,OAAO;GACrE,OAAO;IAAE,IAAI;IAAM,UAAU;KAAE,MAAM,SAAS;KAAM,UAAU,SAAS;KAAU,MAAM,SAAS;IAAK;IAAG;IAAU;GAAO;EAC3H;;;;;;;;EASA,SAAgB,mBAAmB,OAA6B;GAC9D,MAAM,aAAa,MAAM,QAAQ,KAAK;GACtC,IAAI,eAAe,IACjB,OAAO,KAAK,iBAAiB,sCAAsC;GAErE,MAAM,YAAY,aAAa;GAC/B,MAAM,WAAW,MAAM,QAAQ,KAAK,SAAS;GAC7C,IAAI,aAAa,IACf,OAAO,KAAK,sBAAsB,wBAAwB;GAE5D,MAAM,QAAQ,MAAM,MAAM,WAAW,QAAQ;GAE7C,MAAM,sBAAM,IAAI,IAA0B;GAC1C,IAAI;GACJ,KAAK,MAAM,QAAQ,MAAM,MAAM,OAAO,GAAG;IACvC,MAAM,MAAM,aAAa,IAAI,IAAI;IACjC,IAAI,QAAQ,KAAA,GAAW;KACrB,IAAI,IAAI,IAAI,GAAG,GACb,OAAO,KAAK,qBAAqB,WAAW,cAAc,MAAM;KAElE,IAAI,IAAI,KAAK,CAAC,CAAC;KACf,UAAU;IACZ,OAAO,IAAI,YAAY,KAAA,GACrB,IAAI,IAAI,OAAO,CAAC,CAAE,KAAK,IAAI;GAE/B;GAEA,MAAM,WAAuC;IAAE,MAAM;IAAI,UAAU;IAAI,MAAM;GAAG;GAChF,KAAK,MAAM,OAAO,eAAe;IAC/B,IAAI,CAAC,IAAI,IAAI,GAAG,GACd,OAAO,KAAK,mBAAmB,YAAY,cAAc,MAAM;IAEjE,MAAM,QAAQ,IAAI,IAAI,GAAG;IACzB,OAAO,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,EAAE,CAAC,KAAK,MAAM,IAAI,MAAM,IAAI;IAC5E,SAAS,OAAO,MAAM,KAAK,IAAI;GACjC;GAEA,KAAK,MAAM,OAAO,eAChB,IAAI,qBAAqB,SAAS,IAAI,GACpC,OAAO,KAAK,oBAAoB,QAAQ,cAAc,KAAK,kBAAkB;GAIjF,IAAI,WAAW;GACf,KAAK,MAAM,OAAO,eAAe;IAC/B,MAAM,SAAS,gBAAgB,SAAS,IAAI;IAC5C,SAAS,OAAO,OAAO;IACvB,WAAW,YAAY,OAAO;GAChC;GAEA,KAAK,MAAM,OAAO,eAChB,IAAI,UAAU,SAAS,IAAI,IAAA,MACzB,OAAO,KAAK,mBAAmB,UAAU,cAAc,KAAK,aAAa;GAI7E,OAAO;IACL,IAAI;IACJ,UAAU;KAAE,MAAM,SAAS;KAAM,UAAU,SAAS;KAAU,MAAM,SAAS;IAAK;IAClF,UAAU,WAAW,CAAC,UAAU,IAAI,CAAC;GACvC;EACF;;ECzKA,MAAa,6BAA6C;;EAG1D,MAAa,kCAAuD,IAAI,IAAI;GAC1E,CAAC,aAAa,CAAC;GACf,CAAC,mBAAmB,CAAC;GACrB,CAAC,sBAAsB,CAAC;EAC1B,CAAC;EAED,SAAS,WAAW,OAAuB;GACzC,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC;EACzC;;;;;;EAOA,SAAgB,iBAAiB,OAA+C;GAC9E,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;GAChF,MAAM,SAAS;GAEf,IAAI,CADS,OAAO,KAAK,MACjB,CAAC,CAAC,OAAM,QAAO;IAAC;IAAe;IAAQ;IAAc;GAAY,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,OAAO,KAAA;GAClG,IAAI,CAAC,MAAM,QAAQ,OAAO,UAAU,GAAG,OAAO,KAAA;GAC9C,IAAI,OAAO,WAAW,SAAA,IAAkC,OAAO,KAAA;GAC/D,IAAI,QAAQ;GACZ,KAAK,MAAM,aAAa,OAAO,YAAY;IACzC,IAAI,OAAO,cAAc,YAAY,cAAc,IAAI,OAAO,KAAA;IAC9D,MAAM,OAAO,WAAW,SAAS;IACjC,IAAI,OAAA,KAAqC,OAAO,KAAA;IAChD,SAAS;IACT,IAAI,QAAA,MAAkC,OAAO,KAAA;GAC/C;GACA,KAAK,MAAM,OAAO,CAAC,eAAe,MAAM,GAAY;IAClD,MAAM,SAAkB,OAAO;IAC/B,IAAI,WAAW,KAAA,MAAc,OAAO,WAAW,YAAY,WAAW,MAAM,IAAA,MAAgC,OAAO,KAAA;GACrH;GACA,IAAI,OAAO,eAAe,KAAA,KAAa,CAAC,iBAAiB,OAAO,UAAU,GAAG,OAAO,KAAA;GACpF,MAAM,cAAc,OAAO;GAC3B,MAAM,OAAO,OAAO;GACpB,OAAO;IACL,GAAI,OAAO,gBAAgB,WAAW,EAAE,YAAY,IAAI,CAAC;IACzD,GAAI,OAAO,SAAS,WAAW,EAAE,KAAK,IAAI,CAAC;IAC3C,GAAI,OAAO,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,OAAO,WAA6B;IAC7F,YAAY,CAAC,GAAG,OAAO,UAAsB;GAC/C;EACF;;EAQA,SAAgB,oBAAoB,MAA+E;GACjH,OAAO,KAAK,UAAU,cAAc,KAAK;EAC3C;;EAGA,SAAgB,sBAAsB,YAAwC,gBAAyC;GACrH,IAAI,eAAe,KAAA,GAAW,OAAO;GACrC,QAAQ,gBAAgB,IAAI,UAAU,KAAK,OAAO,gBAAgB,IAAI,cAAc,KAAK;EAC3F;;;;;EAMA,SAAgB,+BACd,MACA,iBAAiC,4BACxB;GACT,OAAO,sBAAsB,oBAAoB,IAAI,GAAG,cAAc,KAAK,KAAK,0BAA0B,KAAA;EAC5G;;;;;;;;;;;;;;;EC/EA,MAAa,sBAAsB;;;;;;;EAmBnC,SAAS,kBAAkB,OAA2E;GACpG,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;GACxD,MAAM,SAAS;GACf,IAAI,OAAO,OAAO,OAAO,YAAY,OAAO,OAAO,IAAI,OAAO;GAC9D,IAAI,OAAO,OAAO,UAAU,UAAU,OAAO;GAC7C,IAAI,OAAO,OAAO,gBAAgB,UAAU,OAAO;GACnD,IAAI,OAAO,OAAO,WAAW,UAAU,OAAO;GAC9C,IAAI,OAAO,OAAO,cAAc,UAAU,OAAO;GACjD,IAAI,OAAO,OAAO,cAAc,UAAU,OAAO;GACjD,IAAI,OAAO,aAAa,KAAA,KAAa,OAAO,OAAO,aAAa,UAAU,OAAO;GACjF,IAAI,OAAO,gBAAgB,KAAA,KAAa,OAAO,OAAO,gBAAgB,UAAU,OAAO;GACvF,IAAI,OAAO,SAAS,KAAA,KAAa,OAAO,OAAO,SAAS,UAAU,OAAO;GACzE,IAAI,OAAO,eAAe,KAAA,KAAa,OAAO,OAAO,eAAe,UAAU,OAAO;GACrF,IAAI,OAAO,iBAAiB,KAAA,KAAa,OAAO,OAAO,iBAAiB,WAAW,OAAO;GAC1F,IAAI,CAAC,MAAM,QAAQ,OAAO,UAAU,GAAG,OAAO;GAC9C,KAAK,MAAM,aAAa,OAAO,YAAY;IACzC,IAAI,OAAO,cAAc,YAAY,cAAc,MAAM,OAAO;IAChE,MAAM,QAAQ;IACd,IAAI,OAAO,MAAM,OAAO,UAAU,OAAO;IACzC,IAAI,MAAM,cAAc,KAAA,KAAa,OAAO,MAAM,cAAc,UAAU,OAAO;IACjF,IAAI,OAAO,MAAM,cAAc,UAAU,OAAO;IAChD,IAAI,MAAM,YAAY,KAAA,KAAa,OAAO,MAAM,YAAY,UAAU,OAAO;IAC7E,IAAI,MAAM,WAAW,KAAA,KAAa,MAAM,WAAW,eAAe,MAAM,WAAW,YAAY,MAAM,WAAW,aAAa,OAAO;IACpI,IAAI,MAAM,UAAU,KAAA,KAAa,OAAO,MAAM,UAAU,UAAU,OAAO;IACzE,IAAI,MAAM,gBAAgB,KAAA,KAAa,OAAO,MAAM,gBAAgB,UAAU,OAAO;IACrF,IAAI,MAAM,aAAa,KAAA,KAAa,OAAO,MAAM,aAAa,UAAU,OAAO;IAC/E,IAAI,MAAM,aAAa,KAAA,KAAa,OAAO,MAAM,aAAa,UAAU,OAAO;GACjF;GACA,OAAO;EACT;;EAQA,SAAS,gBAAgB,QAA6B;GACpD,OAAO,aAAa,MAAM,IAAI,SAAS;EACzC;;;;;;EAOA,SAAS,kBAAkB,UAA6C;GACtE,IAAI,OAAO,aAAa,YAAY,aAAa,MAAM,OAAO,KAAA;GAC9D,MAAM,OAAO;GAIb,IAAI,OAAO,KAAK,SAAS,UAAU,OAAO,KAAA;GAC1C,IAAI,KAAK,KAAK,KAAK,MAAM,MAAM,CAAC,YAAY,KAAK,IAAI,GAAG,OAAO,KAAA;GAC/D,OAAO;IACL,SAAS,KAAK,YAAY;IAC1B,MAAM,KAAK;IACX,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,KAAA;IACjE,iBAAiB,OAAO,KAAK,oBAAoB,WAAW,KAAK,kBAAkB,KAAA;GACrF;EACF;;;;;;;EAQA,SAAS,gBAAgB,OAAwC;GAC/D,MAAM,SAAS,uBAAuB,OAAO;IAAC;IAAY;IAAY;GAAU,CAAC;GACjF,IAAI,CAAC,OAAO,IAAI,OAAO,KAAA;GACvB,MAAM,WAAW,OAAO,OAAO;GAC/B,IAAI,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,QAAQ,GAAG,OAAO,KAAA;GACvE,IAAI,OAAO,OAAO,aAAa,KAAA,KAAa,OAAO,OAAO,aAAa,MAAM,OAAO,KAAA;GACpF,MAAM,WAAW,OAAO,OAAO;GAC/B,IAAI,aAAa,KAAA,MAAc,OAAO,aAAa,YAAY,aAAa,KAAK,OAAO,KAAA;GACxF,OAAO;IACL,MAAM,OAAO,SAAS;IACtB,UAAU,OAAO,SAAS;IAC1B,MAAM,OAAO,SAAS;IACtB;IACA,GAAI,OAAO,YAAY,OAAO,OAAO,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/E,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;GAC/C;EACF;;;;;;EAOA,SAAS,kBAAkB,OAA0C;GACnE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO,KAAA;GACxD,MAAM,EAAE,WAAW,GAAG,SAAS;GAC/B,MAAM,SAAS,iBAAiB,IAAI;GACpC,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;GACjC,IAAI,OAAO,cAAc,YAAY,CAAC,OAAO,SAAS,SAAS,GAAG,OAAO,KAAA;GACzE,OAAO;IAAE,GAAG;IAAQ;GAAU;EAChC;;EAGA,SAAgB,YAAY,KAAkC;GAC5D,IAAI,QAAQ,MAAM,OAAO,CAAC;GAC1B,IAAI;GACJ,IAAI;IACF,SAAS,KAAK,MAAM,GAAG;GACzB,SAAS,OAAO;IACd,QAAQ,MAAM,4EAA4E,KAAK;IAC/F,OAAO,CAAC;GACV;GACA,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;IAC1B,QAAQ,MAAM,wEAAwE;IACtF,OAAO,CAAC;GACV;GACA,MAAM,QAAsB,CAAC;GAC7B,KAAK,MAAM,OAAO,QAAQ;IAIxB,IAAI,CAAC,kBAAkB,GAAG,GAAG;KAC3B,QAAQ,KAAK,oEAAoE,GAAG;KACpF;IACF;IAGA,MAAM,OAAmB;KAAE,GAAG;KAAK,QAAQ,gBAAgB,IAAI,MAAM;IAAE;IACvE,KAAK,WAAW,kBAAkB,IAAI,QAAQ;IAK9C,KAAK,WAAW,kBAAkB,IAAI,QAAQ;IAG9C,KAAK,aAAa,KAAK,WAAW,KAAI,eAAc;KAClD,GAAG;KACH,YAAY,kBAAkB,UAAU,UAAU;KAClD,WAAW,mBAAmB,UAAU,SAAS,IAAI,UAAU,YAAY,KAAA;KAC3E,UAAU,OAAO,UAAU,aAAa,WAAW,UAAU,WAAW,KAAA;IAC1E,EAAE;IAIF,KAAK,cAAc,kBAAkB,IAAI,WAAW;IACpD,KAAK,OAAO,kBAAkB,IAAI,IAAI;IACtC,KAAK,aAAa,OAAO,IAAI,eAAe,YAAY,OAAO,SAAS,IAAI,UAAU,IAAI,IAAI,aAAa,KAAA;IAC3G,KAAK,aAAa,iBAAiB,IAAI,UAAU,IAAI,IAAI,aAA+B,KAAA;IACxF,KAAK,eAAe,IAAI,iBAAiB,OAAO,OAAO,KAAA;IACvD,KAAK,SAAS,gBAAgB,IAAI,MAAM;IACxC,KAAK,WAAW,kBAAkB,IAAI,QAAQ;IAI9C,KAAK,OAAO,cAAc,IAAI,IAAI;IAClC,KAAK,wBAAwB,OAAO,IAAI,0BAA0B,YAAY,OAAO,SAAS,IAAI,qBAAqB,IAAI,IAAI,wBAAwB,KAAA;IACvJ,MAAM,KAAK,IAAI;GACjB;GACA,OAAO;EACT;;EAGA,IAAa,wBAAb,MAAwD;GASnC;GACA;GACA;;;;;;;;GAHnB,YACE,MAA+B,qBAC/B,UAA4F,WAAW,cACvG,SAAqD,OAAQ,WAA8C,qBAAqB,aAC3H,aACD,KAAA,GACJ;IALiB,KAAA,MAAA;IACA,KAAA,UAAA;IACA,KAAA,SAAA;GAGhB;GAEH,OAAqB;IACnB,IAAI,KAAK,YAAY,KAAA,GAAW,OAAO,CAAC;IACxC,IAAI;KACF,OAAO,YAAY,KAAK,QAAQ,QAAQ,KAAK,GAAG,CAAC;IACnD,SAAS,OAAO;KAGd,QAAQ,MAAM,4DAA4D,KAAK;KAC/E,OAAO,CAAC;IACV;GACF;GAEA,KAAK,OAAoC;IACvC,IAAI,KAAK,YAAY,KAAA,GAAW;IAChC,IAAI;KACF,KAAK,QAAQ,QAAQ,KAAK,KAAK,KAAK,UAAU,KAAK,CAAC;IACtD,SAAS,OAAO;KAEd,QAAQ,MAAM,mEAAmE,KAAK;IACxF;GACF;GAEA,QAAc;IACZ,IAAI,KAAK,YAAY,KAAA,GAAW;IAChC,IAAI;KACF,KAAK,QAAQ,WAAW,KAAK,GAAG;IAClC,SAAS,OAAO;KACd,QAAQ,MAAM,6CAA6C,KAAK;IAClE;GACF;;;;;;;GAQA,kBAAkB,UAAkC;IAClD,IAAI,KAAK,WAAW,KAAA,GAAW,aAAa,CAAC;IAC7C,MAAM,aAAa,UAAoC;KACrD,IAAI,MAAM,QAAQ,QAAQ,MAAM,QAAQ,KAAK,KAAK;KAClD,SAAS;IACX;IACA,KAAK,OAAO,iBAAiB,WAAW,SAAS;IACjD,aAAa;KAAE,KAAK,QAAQ,oBAAoB,WAAW,SAAS;IAAE;GACxE;EACF;;;;ECnQA,SAAgB,sBAA+B;GAC7C,IAAI,WAAW,0BAA0B,MAAM,OAAO;GACtD,WAAW,wBAAwB;GACnC,OAAO;EACT;;;;;;;EAQA,SAAgB,wBAA8B;GAC5C,WAAW,wBAAwB,KAAA;EACrC;;;;;;;;;;EC1BA,MAAa,KAAK;GAChB,eAAe;GACf,eAAe;GACf,eAAe;GACf,aAAa;GACb,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,iBAAiB;GACjB,qBAAqB;GACrB,qBAAqB;GACrB,iBAAiB;GACjB,gBAAgB;GAChB,wBAAwB;GACxB,qBAAqB;GACrB,wBAAwB;GACxB,qBAAqB;GACrB,uBAAuB;GACrB,cAAc;GACd,iBAAiB;GACnB,iBAAiB;GACjB,iBAAiB;GACjB,mBAAmB;GACnB,8BAA8B;GAC9B,gCAAgC;GAChC,0BAA0B;GAC1B,2BAA2B;GAC3B,+BAA+B;GAC/B,8BAA8B;GAC9B,iBAAiB;GACjB,oBAAoB;GACpB,oBAAoB;GACpB,wBAAwB;GACxB,mCAAmC;GACnC,uBAAuB;GACvB,6BAA6B;GAC7B,eAAe;GACf,mBAAmB;GACnB,0BAA0B;GAC1B,oBAAoB;GACpB,kBAAkB;GAClB,qBAAqB;GACrB,oBAAoB;GACpB,sBAAsB;GACtB,0BAA0B;GAC1B,sBAAsB;GACtB,qBAAqB;GACrB,mBAAmB;GACnB,kBAAkB;GAClB,aAAa;GACb,wBAAwB;GACxB,mBAAmB;GACnB,8BAA8B;GAC9B,cAAc;GACd,yBAAyB;GACzB,cAAc;GACd,oBAAoB;GACpB,cAAc;GACd,gBAAgB;GAChB,cAAc;GACd,yBAAyB;GACzB,iBAAiB;GACjB,sBAAsB;GACtB,0BAA0B;GAC1B,sBAAsB;GACtB,0BAA0B;GAC1B,0BAA0B;GAC1B,0BAA0B;GAC1B,eAAe;GACf,gBAAgB;GAChB,2BAA2B;GAC3B,mBAAmB;GACnB,6BAA6B;GAC7B,8BAA8B;GAC9B,YAAY;GACZ,gBAAgB;GAChB,eAAe;GACf,0BAA0B;GAC1B,iBAAiB;GACjB,4BAA4B;GAC5B,cAAc;GACd,iBAAiB;GACjB,mBAAmB;GACnB,wBAAwB;GACxB,kBAAkB;GAClB,4BAA4B;GAC5B,4BAA4B;GAC5B,8BAA8B;GAC9B,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,oBAAoB;GACpB,2BAA2B;GAC3B,gBAAgB;GAChB,cAAc;GACd,aAAa;GACb,sBAAsB;GACtB,uBAAuB;GACvB,iBAAiB;GACjB,sBAAsB;GACtB,oBAAoB;GACpB,sBAAsB;GACtB,cAAc;GACd,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB;GAClB,kBAAkB;GAClB,qBAAqB;GACrB,sBAAsB;GACtB,oBAAoB;GACpB,2BAA2B;GAC3B,8BAA8B;GAC9B,yBAAyB;GACzB,2BAA2B;GAC3B,wBAAwB;GACxB,2BAA2B;GAC3B,yBAAyB;GACzB,gBAAgB;GAChB,kBAAkB;GAClB,aAAa;GACb,iBAAiB;GACjB,uBAAuB;GACvB,oBAAoB;GACpB,0BAA0B;GAC1B,6BAA6B;GAC7B,cAAc;GACd,gBAAgB;GAChB,mBAAmB;GACnB,0BAA0B;GAC1B,wBAAwB;GACxB,2BAA2B;GAC3B,iCAAiC;GACjC,iCAAiC;GACjC,iCAAiC;GACjC,qCAAqC;GACrC,2BAA2B;GAC3B,iCAAiC;GACjC,2BAA2B;GAC3B,gCAAgC;GAChC,2BAA2B;GAC3B,kBAAkB;GAClB,iBAAiB;GACjB,YAAY;GACZ,kBAAkB;GAClB,aAAa;GACb,yBAAyB;GACzB,qBAAqB;GACrB,2BAA2B;GAC3B,0BAA0B;GAC1B,qBAAqB;GACrB,2BAA2B;GAC3B,iCAAiC;GACjC,6BAA6B;GAC7B,mCAAmC;GACnC,sCAAsC;GACtC,sBAAsB;GACtB,sBAAsB;GACtB,qBAAqB;GACrB,gBAAgB;GAChB,oBAAoB;GACpB,2BAA2B;GAC3B,yBAAyB;GACzB,4BAA4B;GAC5B,aAAa;GAEb,kBAAkB;GAClB,wBAAwB;GACxB,oBAAoB;GACpB,wBAAwB;GACxB,4BAA4B;GAC5B,gCAAgC;GAChC,6BAA6B;GAC7B,iCAAiC;GACjC,wBAAwB;GACxB,0BAA0B;GAC1B,yBAAyB;GACzB,uBAAuB;GACvB,oBAAoB;GACpB,eAAe;GACf,gBAAgB;GAChB,uBAAuB;GACvB,kBAAkB;GAClB,uBAAuB;GACvB,qBAAqB;GACrB,mBAAmB;GACnB,qBAAqB;GACrB,iBAAiB;GACjB,mBAAmB;GACnB,oBAAoB;GACpB,oBAAoB;GACpB,uBAAuB;GACvB,0BAA0B;GAC1B,4BAA4B;GAC5B,gCAAgC;GAChC,kCAAkC;GAElC,iBAAiB;GACjB,sBAAsB;GACtB,mBAAmB;GACnB,yBAAyB;GACzB,uBAAuB;GACvB,wBAAwB;GACxB,0BAA0B;GAC1B,+BAA+B;GAC/B,2BAA2B;GAC3B,2BAA2B;GAC3B,8BAA8B;GAC9B,4BAA4B;GAC5B,oBAAoB;GACpB,sBAAsB;GACtB,sBAAsB;GACtB,qBAAqB;GACrB,sBAAsB;GACtB,wBAAwB;GACxB,gBAAgB;GAChB,iBAAiB;GACjB,uBAAuB;GACvB,wBAAwB;GACxB,0BAA0B;GAC1B,sBAAsB;GACtB,sBAAsB;GACtB,2BAA2B;EAC7B;;EAGA,MAAa,KAAsC;GACjD,eAAe;GACf,eAAe;GACf,eAAe;GACf,aAAa;GACb,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,iBAAiB;GACjB,qBAAqB;GACrB,qBAAqB;GACrB,iBAAiB;GACjB,gBAAgB;GAChB,wBAAwB;GACxB,qBAAqB;GACrB,wBAAwB;GACxB,qBAAqB;GACrB,uBAAuB;GACrB,cAAc;GACd,iBAAiB;GACnB,iBAAiB;GACjB,iBAAiB;GACjB,mBAAmB;GACnB,8BAA8B;GAC9B,gCAAgC;GAChC,0BAA0B;GAC1B,2BAA2B;GAC3B,+BAA+B;GAC/B,8BAA8B;GAC9B,iBAAiB;GACjB,oBAAoB;GACpB,oBAAoB;GACpB,wBAAwB;GACxB,mCAAmC;GACnC,uBAAuB;GACvB,6BAA6B;GAC7B,eAAe;GACf,mBAAmB;GACnB,0BAA0B;GAC1B,oBAAoB;GACpB,kBAAkB;GAClB,qBAAqB;GACrB,oBAAoB;GACpB,sBAAsB;GACtB,0BAA0B;GAC1B,sBAAsB;GACtB,qBAAqB;GACrB,mBAAmB;GACnB,kBAAkB;GAClB,aAAa;GACb,wBAAwB;GACxB,mBAAmB;GACnB,8BAA8B;GAC9B,cAAc;GACd,yBAAyB;GACzB,cAAc;GACd,oBAAoB;GACpB,cAAc;GACd,gBAAgB;GAChB,cAAc;GACd,yBAAyB;GACzB,iBAAiB;GACjB,sBAAsB;GACtB,0BAA0B;GAC1B,sBAAsB;GACtB,0BAA0B;GAC1B,0BAA0B;GAC1B,0BAA0B;GAC1B,eAAe;GACf,gBAAgB;GAChB,2BAA2B;GAC3B,mBAAmB;GACnB,6BAA6B;GAC7B,8BAA8B;GAC9B,YAAY;GACZ,gBAAgB;GAChB,eAAe;GACf,0BAA0B;GAC1B,iBAAiB;GACjB,4BAA4B;GAC5B,cAAc;GACd,iBAAiB;GACjB,mBAAmB;GACnB,wBAAwB;GACxB,kBAAkB;GAClB,4BAA4B;GAC5B,4BAA4B;GAC5B,8BAA8B;GAC9B,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,oBAAoB;GACpB,2BAA2B;GAC3B,gBAAgB;GAChB,cAAc;GACd,aAAa;GACb,sBAAsB;GACtB,uBAAuB;GACvB,iBAAiB;GACjB,sBAAsB;GACtB,oBAAoB;GACpB,sBAAsB;GACtB,cAAc;GACd,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB;GAClB,kBAAkB;GAClB,qBAAqB;GACrB,sBAAsB;GACtB,oBAAoB;GACpB,2BAA2B;GAC3B,8BAA8B;GAC9B,yBAAyB;GACzB,2BAA2B;GAC3B,wBAAwB;GACxB,2BAA2B;GAC3B,yBAAyB;GACzB,gBAAgB;GAChB,kBAAkB;GAClB,aAAa;GACb,iBAAiB;GACjB,uBAAuB;GACvB,oBAAoB;GACpB,0BAA0B;GAC1B,6BAA6B;GAC7B,cAAc;GACd,gBAAgB;GAChB,mBAAmB;GACnB,0BAA0B;GAC1B,wBAAwB;GACxB,2BAA2B;GAC3B,iCAAiC;GACjC,iCAAiC;GACjC,iCAAiC;GACjC,qCAAqC;GACrC,2BAA2B;GAC3B,iCAAiC;GACjC,2BAA2B;GAC3B,gCAAgC;GAChC,2BAA2B;GAC3B,kBAAkB;GAClB,iBAAiB;GACjB,YAAY;GACZ,kBAAkB;GAClB,aAAa;GACb,yBAAyB;GACzB,qBAAqB;GACrB,2BAA2B;GAC3B,0BAA0B;GAC1B,qBAAqB;GACrB,2BAA2B;GAC3B,iCAAiC;GACjC,6BAA6B;GAC7B,mCAAmC;GACnC,sCAAsC;GACtC,sBAAsB;GACtB,sBAAsB;GACtB,qBAAqB;GACrB,gBAAgB;GAChB,oBAAoB;GACpB,2BAA2B;GAC3B,yBAAyB;GACzB,4BAA4B;GAC5B,aAAa;GAEb,kBAAkB;GAClB,wBAAwB;GACxB,oBAAoB;GACpB,wBAAwB;GACxB,4BAA4B;GAC5B,gCAAgC;GAChC,6BAA6B;GAC7B,iCAAiC;GACjC,wBAAwB;GACxB,0BAA0B;GAC1B,yBAAyB;GACzB,uBAAuB;GACvB,oBAAoB;GACpB,eAAe;GACf,gBAAgB;GAChB,uBAAuB;GACvB,kBAAkB;GAClB,uBAAuB;GACvB,qBAAqB;GACrB,mBAAmB;GACnB,qBAAqB;GACrB,iBAAiB;GACjB,mBAAmB;GACnB,oBAAoB;GACpB,oBAAoB;GACpB,uBAAuB;GACvB,0BAA0B;GAC1B,4BAA4B;GAC5B,gCAAgC;GAChC,kCAAkC;GAElC,iBAAiB;GACjB,sBAAsB;GACtB,mBAAmB;GACnB,yBAAyB;GACzB,uBAAuB;GACvB,wBAAwB;GACxB,0BAA0B;GAC1B,+BAA+B;GAC/B,2BAA2B;GAC3B,2BAA2B;GAC3B,8BAA8B;GAC9B,4BAA4B;GAC5B,oBAAoB;GACpB,sBAAsB;GACtB,sBAAsB;GACtB,qBAAqB;GACrB,sBAAsB;GACtB,wBAAwB;GACxB,gBAAgB;GAChB,iBAAiB;GACjB,uBAAuB;GACvB,wBAAwB;GACxB,0BAA0B;GAC1B,sBAAsB;GACtB,sBAAsB;GACtB,2BAA2B;EAC7B;;EASA,SAAgB,aAA2C;GAEzD,QADa,OAAO,aAAa,cAAc,SAAS,gBAAgB,OAAO,KAAA,CACnE,YAAY,CAAC,CAAC,WAAW,IAAI,IAAI,KAAK;EACpD;;;;;;;;EASA,IAAI;;EAGJ,SAAgB,oBAAoB,GAAuF;GACzH,WAAW;EACb;;EAGA,SAAgB,EAAE,KAAmB,QAAyC;GAC5E,IAAI,aAAa,KAAA,GAAW,OAAO,SAAS,KAAK,MAAM;GACvD,IAAI,OAAe,WAAW,CAAC,CAAC;GAChC,IAAI,WAAW,KAAA,GACb,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAC/C,OAAO,KAAK,WAAW,IAAI,KAAK,IAAI,KAAK;GAG7C,OAAO;EACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECteA,MAAa,mBAAyE;GACpF;IAAE,MAAM;IAAa,OAAO;GAAgC;GAC5D;IAAE,MAAM;IAAa,OAAO;GAAgC;GAC5D;IAAE,MAAM;IAAgB,OAAO;GAAgC;GAC/D;IAAE,MAAM;IAAa,OAAO;GAAoC;EAClE;;;;ECAA,MAAM,mBAAmB;;EAGzB,SAAgB,WAAW,EACzB,WACA,OACA,OACA,SACA,aACA,UACA,SACA,iBACA,YAYC;GACD,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWC,yBAAI;IAAe,cAAa,UAAS;KAAE,IAAI,MAAM,WAAW,MAAM,eAAe,QAAQ;IAAE;cAC7G,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KACE,WAAWA,yBAAI;KACf,MAAK;KACL,cAAY;KACZ,WAAU,UAAS;MAAE,MAAM,eAAe;MAAG,SAAS;KAAE;eAJ1D;MAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;OAAI,WAAWA,yBAAI;iBAAa;MAAU,CAAA;MAEzC;MAEA,UAAU,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,yBAAI;iBAAY;MAAS,CAAA;MAE/D,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OAAQ,WAAWA,yBAAI;iBAAvB;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,yBAAI;SAAa,SAAS;mBACxD,EAAE,YAAY;QACT,CAAA;QACP,oBAAoB,KAAA,KACnB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,yBAAI;SACf,UAAU;SACV,SAAS,gBAAgB;mBAExB,gBAAgB;QACX,CAAA;QAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,yBAAI;SAAe,UAAU;mBAC3D;QACK,CAAA;OACF;;KACJ;;GACH,CAAA;EAET;;EAGA,SAAgB,kBAAkB,EAChC,OACA,aACA,QACA,eACA,qBACA,kBASC;GACD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;IACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;KAAO,WAAWA,yBAAI;eAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAa,EAAE,WAAW;KAAQ,CAAA,GACvD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;MACE,WAAWA,yBAAI;MACf,OAAO;MACP,WAAA;MACA,aAAa,EAAE,sBAAsB;MACrC,WAAU,UAAS,cAAc,MAAM,OAAO,KAAK;KACpD,CAAA,CACI;;IAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;KAAO,WAAWA,yBAAI;eAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAa,EAAE,iBAAiB;KAAQ,CAAA,GAC7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MACE,WAAWA,yBAAI;MACf,MAAM;MACN,OAAO;MACP,aAAa,EAAE,4BAA4B;MAC3C,WAAU,UAAS,oBAAoB,MAAM,OAAO,KAAK;KAC1D,CAAA,CACI;;IAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;KAAO,WAAWA,yBAAI;eAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAa,EAAE,YAAY;KAAQ,CAAA,GACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MACE,WAAWA,yBAAI;MACf,MAAM;MACN,OAAO;MACP,aAAa,EAAE,uBAAuB;MACtC,WAAU,UAAS,eAAe,MAAM,OAAO,KAAK;KACrD,CAAA,CACI;;GACP,EAAA,CAAA;EAEN;;;;;;;EAQA,SAAgB,cAAc,EAC5B,MACA,WACA,YAMC;GACD,MAAM,UAAU,OAAe,UAAkC;IAC/D,SAAS,KAAK,KAAK,KAAK,aAAc,aAAa,QAAQ;KAAE,GAAG;KAAK,GAAG;IAAM,IAAI,GAAI,CAAC;GACzF;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,yBAAI;cAApB;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAa,EAAE,UAAU;KAAQ,CAAA;KACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAY,EAAE,cAAc;KAAQ,CAAA;KACxD,KAAK,KAAK,KAAK,UACd,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;gBAApB;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,WAAWA,yBAAI;QACf,MAAM;QACN,OAAO,IAAI;QACX,WAAA;QACA,aAAa,EAAE,wBAAwB;QACvC,cAAY,EAAE,aAAa;QAC3B,WAAW,UAAU;SACnB,MAAM,OAAO,MAAM,OAAO;SAC1B,MAAM,QAAQ,UAAU,MAAK,cAAa,UAAU,SAAS,IAAI;SACjE,MAAM,aAAa,OAAO,iBAAiB,KAAA,MAAc,IAAI,gBAAgB,GAAA,CAAI,KAAK,MAAM;SAC5F,OAAO,OAAO,aAAa;UAAE;UAAM,cAAc,MAAM;SAAa,IAAI,EAAE,KAAK,CAAC;QAClF;OACD,CAAA;OACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,WAAWA,yBAAI;QACf,OAAO,IAAI,gBAAgB;QAC3B,WAAA;QACA,aAAa,EAAE,0BAA0B;QACzC,cAAY,EAAE,eAAe;QAC7B,WAAU,UAAS;SAAE,OAAO,OAAO,EAAE,cAAc,MAAM,OAAO,MAAM,CAAC;QAAE;OAC1E,CAAA;OACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,yBAAI;QACf,cAAY,EAAE,iBAAiB,EAAE,MAAM,IAAI,KAAK,CAAC;QACjD,eAAe;SAAE,SAAS,KAAK,QAAQ,GAAG,aAAa,aAAa,KAAK,CAAC;QAAE;kBAC7E;OAEO,CAAA;MACL;QA/B4B,KA+B5B,CACN;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MAAU,IAAI;gBACX,UAAU,KAAI,QAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAuB,OAAO,IAAI,KAAO,GAA5B,IAAI,IAAwB,CAAC;KACxD,CAAA;KACV,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,yBAAI,cAAc,MAAMA,yBAAI;MACvC,UAAU,KAAK,UAAA;MACf,eAAe;OAAE,SAAS,CAAC,GAAG,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC;MAAE;gBAJrD,CAKC,MACI,EAAE,YAAY,CACX;;IACL;;EAET;;;;;EAMA,SAAgB,UAAU,MAAqC;GAC7D,OAAO,cAAc,IAAI,KAAK,CAAC;EACjC;;;;;;;;;EC1MA,MAAM,kBAAkB;;EAGxB,SAAS,iBAAsC;GAC7C,IAAI;IACF,OAAO,WAAW;GACpB,QAAQ;IACN;GACF;EACF;;EAGA,SAAgB,yBAAyB,UAAgD,eAAe,GAAW;GACjH,IAAI;IACF,OAAO,SAAS,QAAQ,eAAe,KAAK;GAC9C,QAAQ;IAEN,OAAO;GACT;EACF;;EAGA,SAAgB,0BAA0B,OAAe,UAAgD,eAAe,GAAS;GAC/H,IAAI;IACF,SAAS,QAAQ,iBAAiB,KAAK;GACzC,QAAQ,CAER;EACF;;;;;;;;ECGA,SAAgB,aAAa,EAAE,YAAY,SAAS,aAAa,oBAAoB,oBAAoB,cAAiC;GACxI,MAAM,cAAc,gBAAgB,KAAA;GACpC,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,aAAa,SAAS,EAAE;GAC3D,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,aAAa,eAAe,EAAE;GAC7E,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,aAAa,UAAU,EAAE;GAM9D,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,aAAa,eAAe,YAAY,eAAe,sBAAsB,EAAE;GAC9H,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAoB,aAAa,QAAQ,YAAY,QAAQ,EAAE;GAC5E,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA0B,aAAa,cAAc,EAAE;GAC1E,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,aAAa,SAAS,YAAY,SAAS,EAAE;GAChF,MAAM,sBAAsB,eAAe,KAAA,IAAY,KAAA,IAAY,wBAAwB,UAAU;GACrG,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,aAAa,gBAAgB,KAAK;GACnF,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,SAAA,CAA+B,aAAa,UAAU,WAAW,KAAK;GAC9F,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,aAAa,UAAU,QAAQ,EAAE;GAClF,MAAM,CAAC,eAAe,qBAAA,GAAA,MAAA,SAAA,CAAiD,KAAA,CAAS;GAChF,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA0B,EAAE;GAC/C,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA+C,KAAA,CAAS;GAC5E,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CACnB,aAAa,UAAU,eAAe,KAAA,IAAY,YAAY,SAAS,WAAW,KAAK,IAAI,IAAI,EACjG;GACA,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAA+B,aAAa,QAAQ,CAAC,CAAC;GACnE,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,SAAA,CAA+B,IAAI;GAC3D,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyC,KAAA,CAAS;GAChE,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAC5C,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,WAAW,YAAY,CAAC,CAAC,gBAAgB;GAGhF,MAAM,CAAC,aAAA,GAAA,MAAA,SAAA,CAAqB,WAAW,YAAY,CAAC,CAAC,iBAAiB,IAAI;GAC1E,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAyB,EAAE;GAG7C,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,OAAgC,yBAAyB,CAAC;GAC7E,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,KAAK;GACtD,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA8C,KAAA,CAAS;GAC1E,MAAM,cAAA,GAAA,MAAA,OAAA,CAAiD,KAAA,CAAS;GAChE,MAAM,cAAc,QAAQ,UAAU,CAAC;GAKvC,MAAM,iBAAiB,gBAAgB,MAAM,QAAQ,WAAW,MAAK,SAAQ,KAAK,gBAAgB,WAAW;GAC7G,MAAM,YAAY,SAAS,MAAM,QAAQ,QAAQ,MAAK,SAAQ,KAAK,OAAO,IAAI;GAC9E,MAAM,aAAa,UAAU,MAAM,YAAY,MAAK,SAAQ,KAAK,OAAO,KAAK;GAI7E,CAAA,GAAA,MAAA,UAAA,OACQ,WAAW,gBAAgB,WAAW,WAAW,YAAY,CAAC,CAAC,gBAAgB,CAAC,GACtF,CAAC,UAAU,CACb;GAKA,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,eAAe,MAAM,YAAY,WAAW,GAAG;IACnD,IAAI,YAAY,MAAK,WAAU,OAAO,OAAO,UAAU,GAAG;IAC1D,cAAc,EAAE;IAChB,0BAA0B,EAAE;GAC9B,GAAG,CAAC,YAAY,QAAQ,MAAM,CAAC;GAE/B,MAAM,WAAW,YAA2B;IAC1C,MAAM,OAAO,UAAU,KAAK;IAC5B,IAAI,SAAS,IAAI;KACf,cAAc,EAAE,kBAAkB,CAAC;KACnC;IACF;IACA,MAAM,QAAQ,IAAI,gBAAgB;IAClC,WAAW,UAAU;IACrB,gBAAgB,IAAI;IACpB,cAAc,KAAA,CAAS;IACvB,IAAI;KACF,MAAM,QAAQ,MAAM,WAAW,eAAe;MAAE;MAAM,GAAI,eAAe,KAAK,CAAC,IAAI,EAAE,OAAO,WAAW;KAAG,GAAG,MAAM,MAAM;KACzH,SAAS,MAAM,KAAK;KACpB,eAAe,MAAM,WAAW;KAChC,UAAU,MAAM,MAAM;IACxB,SAAS,cAAc;KAErB,IAAI,CAAC,MAAM,OAAO,SAAS,cAAc,wBAAwB,QAAQ,aAAa,UAAU,OAAO,YAAY,CAAC;IACtH,UAAU;KACR,WAAW,UAAU,KAAA;KACrB,gBAAgB,KAAK;IACvB;GACF;;;;;;;GAQA,MAAM,SAAS,OAAO,mBAA2C;IAC/D,IAAI,iBAAiB;KACnB,MAAM,OAAO,aAAa,KAAK;KAC/B,IAAI,SAAS,MAAM,CAAC,YAAY,IAAI,GAAG;MACrC,iBAAiB,EAAE,yBAAyB,CAAC;MAC7C;KACF;IACF;IAIA,IAAI,SAAyE,KAAA;IAC7E,IAAI,WAAW,KAAK,MAAM,IAAI;KAC5B,MAAM,SAAS,mBAAmB,UAAU;KAC5C,IAAI,CAAC,OAAO,IAAI;MACd,eAAe,OAAO,MAAM,OAAO;MACnC;KACF;KACA,SAAS;MAAE,GAAG,OAAO;MAAU,GAAI,OAAO,SAAS,SAAS,UAAU,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;KAAG;IACrG;IAGA,MAAM,aAAa,aAAa,MAAM,IAAI,CAAC,CAAC,KAAI,SAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,QAAO,SAAQ,SAAS,EAAE;IAC/F,MAAM,WAAW,WAAW,WAAW,IAAI,KAAA,IAAY;KACrD;KACA,aAAa,gBAAgB,KAAK,KAAA,IAAY;KAC9C,MAAM,SAAS,KAAK,KAAA,IAAY;KAChC,YAAY,eAAe,KAAK,KAAA,IAAY;IAC9C;IAGA,MAAM,UAAU,UAAU,IAAI;IAC9B,WAAW,IAAI;IACf,MAAM,OAAO,MAAM,WAAW,oBAAoB;KAChD;KACA;KACA;KACA,GAAI,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,WAAW,GAAG;KAC9D;KACA;KACA,aAAa,gBAAgB,KAAK,KAAA,IAAY;KAC9C,MAAM,SAAS,KAAK,KAAA,IAAY;KAChC,YAAY,eAAe,KAAK,KAAA,IAAY;KAC5C,OAAO,UAAU,KAAK,KAAA,IAAY;KAClC,GAAI,eAAe,EAAE,cAAc,KAAK,IAAI,CAAC;KAC7C,GAAI,QAAQ,SAAS,IAAI,EAAE,MAAM,QAAQ,IAAI,CAAC;KAC9C,UAAU,kBAAkB;MAAE,SAAS;MAAM,MAAM,aAAa,KAAK;KAAE,IAAI,KAAA;IAC7E,CAAC;IACD,IAAI,SAAS,KAAA,GAAW;KACtB,WAAW,KAAK;KAChB,SAAS,WAAW,YAAY,CAAC,CAAC,kBAAkB,EAAE,cAAc,CAAC;KACrE;IACF;IACA,IAAI,eAAe,mBAAmB,gBAAgB,KAAA,GACpD,IAAI,uBAAuB,KAAA,GACzB,MAAM,mBAAmB,YAAY,EAAE;SAEvC,MAAM,WAAW,YAAY,YAAY,EAAE;IAG/C,IAAI;SAME,CAAC,MADiB,WAAW,QAAQ,KAAK,EAAE,GAClC,WAAW,SAAS,KAAK,EAAE;IAAA;IAE3C,QAAQ;GACV;;GAGA,MAAM,kBAAkB,mBAAmB,aAAa,KAAK,MAAM,MAAM,YAAY,YAAY,IAC7F,YAAY,cAAc,KAAK,IAAI,CAAC,IACpC,KAAA;GAEJ,MAAM,aAAa,eAAe,KAAA,IAC9B,EAAE,kBAAkB,IACpB,cAAc,EAAE,oBAAoB,IAAI,EAAE,WAAW;GAEzD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,YAAD;IACE,WAAW;IACX,OAAO;IACA;IACE;IACT,aAAa,EAAE,YAAY;IAC3B,gBAAgB;KAAE,OAAY,KAAK;IAAE;IAC5B;IACT,iBAAiB;KAAE,OAAO,EAAE,kBAAkB;KAAG,gBAAgB;MAAE,OAAY,IAAI;KAAE;IAAE;cARzF;KAUG,YACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;MAAS,WAAWC,yBAAI;MAAS,iBAAc;gBAA/C;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;kBAAa,EAAE,aAAa;OAAQ,CAAA;OACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAG,WAAWA,yBAAI;kBAAY,EAAE,iBAAiB;OAAK,CAAA;OACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;QACE,WAAWA,yBAAI;QACf,MAAM;QACN,OAAO;QACP,aAAa,EAAE,wBAAwB;QACvC,YAAY;QACZ,WAAU,UAAS;SAAE,aAAa,MAAM,OAAO,KAAK;SAAG,cAAc,KAAA,CAAS;QAAE;OACjF,CAAA;OACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAAK,WAAWA,yBAAI;kBAApB,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SACE,WAAWA,yBAAI;SACf,OAAO;SACP,cAAY,EAAE,kBAAkB;SAChC,WAAU,UAAS;UACjB,cAAc,MAAM,OAAO,KAAK;UAChC,0BAA0B,MAAM,OAAO,KAAK;SAC9C;mBAPF,CASE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAQ,OAAM;oBAAI,EAAE,oBAAoB;SAAU,CAAA,GACjD,YAAY,KAAI,WACf,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAwB,OAAO,OAAO;oBAAK,OAAO,QAAQ,OAAO;SAAW,GAA/D,OAAO,EAAwD,CAC7E,CACK;YACP,eAEG,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,yBAAI;SAAa,eAAe;UAAE,WAAW,SAAS,MAAM;SAAE;mBAC5F,EAAE,mBAAmB;QAChB,CAAA,IAGR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,yBAAI;SACf,UAAU,UAAU,KAAK,MAAM;SAC/B,eAAe;UAAE,SAAc;SAAE;mBAEhC,EAAE,gBAAgB;QACb,CAAA,CAET;;OACJ,eAAe,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAG,WAAWA,yBAAI;kBAAY;OAAc,CAAA;MAClE;;KAGV,eAAe,KAAA,KACd,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;MAAY,iBAAc;gBAA5C;OACG,EAAE,eAAe;OAAE;OAAG,WAAW;OAAM;OAAI,EAAE,oBAAoB;MACjE;;KAGL,iBAAA,GAAA,kBAAA,IAAA,CAAC,mBAAD;MACS;MACM;MACL;MACR,gBAAe,UAAS;OAAE,SAAS,KAAK;OAAG,SAAS,KAAA,CAAS;MAAE;MAC/D,qBAAqB;MACrB,gBAAgB;KACjB,CAAA;KAED,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;MAAqB;MAAM,WAAW,iBAAiB,WAAW,YAAY,CAAC,CAAC,KAAK;MAAG,UAAU;KAAU,CAAA;KAE1G,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,YAAY;MAAQ,CAAA,GACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;OACE,WAAWA,yBAAI;OACf,MAAM;OACN,OAAO;OACP,aAAa,EAAE,uBAAuB;OACtC,YAAY;OACZ,WAAU,UAAS;QAAE,cAAc,MAAM,OAAO,KAAK;QAAG,eAAe,KAAA,CAAS;OAAE;MACnF,CAAA,CACI;;KACN,gBAAgB,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAY;KAAe,CAAA;KAE3E,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,cAAc;MAAQ,CAAA,GAC1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;OACE,WAAWA,yBAAI;OACf,MAAM;OACN,OAAO;OACP,aAAa,EAAE,yBAAyB;OACxC,YAAY;OACZ,WAAU,UAAS;QAAE,gBAAgB,MAAM,OAAO,KAAK;OAAE;MAC1D,CAAA,CACI;;KAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,eAAe;MAAQ,CAAA,GAC3D,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,WAAU,UAAS;QAAE,eAAe,MAAM,OAAO,KAAK;OAAE;iBAH1D;QAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,OAAM;mBAAI,EAAE,uBAAuB;QAAU,CAAA;QACpD,CAAC,kBAAkB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,OAAO;mBAAf,CAA6B,aAAa,EAAE,mBAAmB,CAAU;;QAC5F,QAAQ,WAAW,KAAI,cACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAoC,OAAO,UAAU;mBAAc,UAAU;QAAc,GAA9E,UAAU,WAAoE,CAC5F;OACK;QACH;;KAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,UAAU;MAAQ,CAAA,GACtD,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,WAAU,UAAS;QAAE,QAAQ,MAAM,OAAO,KAAK;OAAE;iBAHnD;QAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,OAAM;mBAAI,EAAE,mBAAmB;QAAU,CAAA;QAChD,CAAC,aAAa,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,OAAO;mBAAf,CAAsB,MAAM,EAAE,mBAAmB,CAAU;;QACzE,QAAQ,QAAQ,KAAI,WACnB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAwB,OAAO,OAAO;SAAI,UAAU,OAAO,WAAW,KAAA;mBAAtE;UACG,OAAO,QAAQ,OAAO;UACtB,OAAO,YAAY,EAAE,yBAAyB,IAAI;UAClD,OAAO,WAAW,KAAA,IAAY,EAAE,wBAAwB,IAAI;SACvD;WAJK,OAAO,EAIZ,CACT;OACK;QACH;;KAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,gBAAgB;MAAQ,CAAA,GAC5D,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,WAAU,UAAS;QAAE,cAAc,MAAM,OAAO,KAAK;OAAE;iBAHzD,CAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,OAAM;kBAAI,wBAAwB,KAAA,IACtC,EAAE,yBAAyB,IAC3B,EAAE,iCAAiC,EAAE,YAAY,EAAE,mBAAmB,qBAAqC,EAAE,CAAC;OAAU,CAAA,GAC3H,iBAAiB,KAAI,OACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAiB,OAAO;kBAAK,EAAE,mBAAmB,IAAoB;OAAU,GAAnE,EAAmE,CACjF,CACK;QACH;;KAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,WAAW;MAAQ,CAAA,GACvD,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,WAAU,UAAS;QAAE,SAAS,MAAM,OAAO,KAAK;OAAE;iBAHpD;QAKE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,OAAM;mBAAI,EAAE,oBAAoB;QAAU,CAAA;QACjD,CAAC,cAAc,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,OAAO;mBAAf,CAAuB,OAAO,EAAE,oBAAoB,CAAU;;QAC7E,QAAQ,QAAQ,KAAI,SACnB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAsB,OAAO,KAAK;mBAAK,KAAK,QAAQ,KAAK;QAAW,GAAvD,KAAK,EAAkD,CACrE;OACK;QACH;;KAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OACE,MAAK;OACL,SAAS;OACT,WAAU,UAAS;QAAE,gBAAgB,MAAM,OAAO,OAAO;OAAE;MAC5D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,mBAAmB,EAAQ,CAAA,CAC/B;;KACP,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,uBAAuB;KAAK,CAAA;KAE7D,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;MAAS,WAAWA,yBAAI;gBAAxB;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,iBAAiB,EAAM,CAAA;OAC9B,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;QAAO,WAAWA,yBAAI;kBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SACE,MAAK;SACL,SAAS;SACT,WAAU,UAAS;UACjB,mBAAmB,MAAM,OAAO,OAAO;UACvC,IAAI,CAAC,MAAM,OAAO,SAAS,iBAAiB,KAAA,CAAS;SACvD;QACD,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,wBAAwB,EAAQ,CAAA,CACpC;;OACN,mBACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;QACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,yBAAI;mBAApB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UACE,WAAW,GAAGA,yBAAI,MAAM,GAAGA,yBAAI,gBAAgB,kBAAkB,KAAA,IAAY,IAAIA,yBAAI,yBAAyB;UAC9G,OAAO;UACP,aAAY;UACZ,YAAY;UACZ,cAAY,EAAE,sBAAsB;UACpC,WAAU,UAAS;WAAE,gBAAgB,MAAM,OAAO,KAAK;WAAG,iBAAiB,KAAA,CAAS;UAAE;SACvF,CAAA,GACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;UACE,WAAWA,yBAAI;UACf,OAAM;UACN,cAAY,EAAE,yBAAyB;UACvC,WAAU,UAAS;WACjB,IAAI,MAAM,OAAO,UAAU,IAAI;WAC/B,gBAAgB,MAAM,OAAO,KAAK;WAClC,iBAAiB,KAAA,CAAS;UAC5B;oBARF,CAUE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;WAAQ,OAAM;qBAAd,CAAkB,EAAE,yBAAyB,GAAE,GAAS;cACvD,iBAAiB,KAAI,WACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAA0B,OAAO,OAAO;qBAAO,EAAE,OAAO,KAAK;UAAU,GAA1D,OAAO,IAAmD,CACxE,CACK;WACL;;QACJ,kBAAkB,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAWA,yBAAI;mBAAY;QAAiB,CAAA;QAC9E,kBAAkB,KAAA,KAAa,oBAAoB,KAAA,KAClD,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAWA,yBAAI;mBAAlB;UACG,EAAE,yBAAyB;UAAE;UAAE,IAAI,KAAK,eAAe,CAAC,CAAC,eAAe;SACxE;;OAEL,EAAA,CAAA;MAEG;;KACR,eACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;MAAe,OAAO,EAAE,WAAW,OAAO;gBAAhE,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OACE,MAAK;OACL,SAAS;OACT,WAAU,UAAS;QAAE,mBAAmB,MAAM,OAAO,OAAO;OAAE;MAC/D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,qBAAqB,EAAQ,CAAA,CACjC;;IAED;;EAEhB;;;;EC7bA,MAAa,aAA+C;GAC1D,SAAS;GACT,MAAM;GACN,SAAS;GACT,MAAM;GACN,QAAQ;EACV;;;;;;;;;;;;;ECMA,SAAgB,oBAAoB,IAAY,UAA2B;GACzE,IAAI;IACF,OAAO,IAAI,KAAK,eAAe,KAAA,GAAW;KACxC,WAAW;KACX,WAAW;KACX,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;IAC/C,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;GACxB,QAAQ;IACN,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,YAAY;GAClC;EACF;EAEA,SAAgB,WAAW,IAAY,UAA2B;GAChE,MAAM,OAAO,IAAI,KAAK,EAAE;GAExB,MAAM,UAAU,KAAK,OADT,KAAK,IACa,IAAI,MAAM,GAAK;GAC7C,IAAI,UAAU,GAAG,OAAO,EAAE,cAAc;GACxC,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;GACpC,IAAI,UAAU,MAAS,OAAO,GAAG,KAAK,MAAM,UAAU,EAAE,EAAE;GAC1D,IAAI,aAAa,KAAA,GAAW,OAAO,oBAAoB,IAAI,QAAQ;GACnE,OAAO,GAAG,KAAK,YAAY,EAAE,GAAG,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;EACxH;EAEA,SAAS,cAAc,EACrB,MACA,SACA,UACA,SACA,eAAe,GACf,YAAY,OACZ,eAAe,GACf,kBAAkB,GAClB,iBAAiB,KAgBhB;GACD,MAAM,SAAS,KAAK,WAAW,KAAK,WAAW,SAAS;GACxD,MAAM,OAAO,KAAK,WAAW;GAC7B,MAAM,WAAW,KAAK,eAAe,KAAA;GACrC,MAAM,cAAc,CAAC,YAAY,KAAK,WAAW,aAAa,CAAC;GAE/D,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IACE,MAAK;IACL,WAAWC,yBAAI;IACf,eAAa,WAAW,aAAa,KAAK;IAC1C,iBAAc;IACd,gBAAc,WAAW,KAAA;IACzB,WAAW;IACX,aAAa,eAAe,UAAU;KACpC,MAAM,aAAa,QAAQ,cAAc,KAAK,EAAE;KAChD,MAAM,aAAa,gBAAgB;IACrC,IAAI,KAAA;IACK;IACT,OAAO,KAAK,gBAAgB,KAAK,KAAK,cAAc,KAAK;cAZ3D;KAcE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAY,KAAK;KAAY,CAAA;KACjD,KAAK,SAAS,KAAA,KAAa,KAAK,KAAK,SAAS,KAC7C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAClB,KAAK,KAAK,KAAI,QACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAEE,WAAWA,yBAAI;OACf,iBAAe,QAAQ,IAAI,IAAI;OAC/B,iBAAc;OACd,iBAAe,IAAI,iBAAiB,KAAA,IAAY,KAAA,IAAY,IAAI;OAChE,OAAO,IAAI,iBAAiB,KAAA,IAAY,IAAI,OAAO,IAAI;iBAEtD,IAAI;MACD,GARC,IAAI,IAQL,CACP;KACG,CAAA;KAEP,KAAK,gBAAgB,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAc,KAAK;KAAkB,CAAA;KACtF,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAArB;OACG,aACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;QAAa,iBAAc;kBAAiB,EAAE,cAAc;OAAQ,CAAA;OAE1F,eAAe,KAId,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;QACE,WAAWA,yBAAI;QACf,iBAAc;QACd,aAAW,iBAAiB,IAAI,WAAW,kBAAkB,IAAI,YAAY,iBAAiB,eAAe,SAAS,KAAA;QACtH,OAAO,EAAE,0BAA0B;SACjC,OAAO,OAAO,YAAY;SAC1B,MAAM,OAAO,YAAY;SACzB,SAAS,OAAO,eAAe;SAC/B,QAAQ,OAAO,cAAc;QAC/B,CAAC;kBATH;SAWG,EAAE,iBAAiB,EAAE,OAAO,OAAO,YAAY,EAAE,CAAC;SAClD,iBAAiB,IAAI,QAAQ,EAAE,uBAAuB,EAAE,OAAO,OAAO,cAAc,EAAE,CAAC,IAAI;SAC3F,mBAAmB,KAAK,kBAAkB,IAAI,QAAQ,EAAE,wBAAwB,EAAE,OAAO,OAAO,eAAe,EAAE,CAAC,IAAI;QACnH;;OAER,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;kBAArB;SAAgC,EAAE,eAAe;SAAE;SAAE,WAAW,KAAK,SAAS;QAAQ;;OACrF,KAAK,WAAW,KAAA,KACf,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;QAAc,OAAO,KAAK,OAAO;kBAAO,EAAE,aAAa;OAAQ,CAAA;OAErF,CAAC,YAAY,KAAK,UAAU,YAAY,QACvC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QACE,WAAWA,yBAAI;QACf,OAAO,KAAK,SAAS,cAAc,KAAA,IAC/B,GAAG,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,KAAK,SAAS,WAAW,QAAQ,MACjF,EAAE,gBAAgB;kBAErB,EAAE,gBAAgB;OACf,CAAA;OAEP,WAAW,KAAA,KACV,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;QAAS,eAAa,WAAW,KAAA,IAAY,OAAO;kBAAzE;SACG;SAAK;SAAE,EAAE,YAAY;QAClB;;OAEP,QAAQ,cAAc,KAAA,KACrB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;QAAa,OAAO,OAAO;kBAAW;OAAO,CAAA;OAEnE,CAAC,aAAa,KAAK,WAAW,aAAa,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;QAAa,eAAY;OAAQ,CAAA;MAC1G;;KACL,CAAC,YAAY,WAAW,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAArB,CAAwC,EAAE,eAAe,GAAE,GAAO;;KAC1F,CAAC,YAAY,WAAW,KAAA,KAAa,eAAe,MAAM,MAAM,aAC/D,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAArB,CACG,OAAO,cAAc,KAAA,IAAY,EAAE,uBAAuB,IAAI,EAAE,yBAAyB,GAAE,GACxF;;IAEF;;EAEZ;;EAGA,MAAa,YAAA,GAAA,MAAA,KAAA,CAAgB,aAAa;;;;;;;EChJ1C,SAAgB,cAAc,EAAE,OAAO,SAAS,cAAc,QAAQ,UAAU,aAAiC;GAC/G,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWC,yBAAI;IAAe,cAAa,UAAS;KAAE,IAAI,MAAM,WAAW,MAAM,eAAe,SAAS;IAAE;cAC9G,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,yBAAI;KAAO,MAAK;KAAc,cAAY;eAA1D;MACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;OAAI,WAAWA,yBAAI;iBAAa;MAAU,CAAA;MAC1C,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,yBAAI;iBAAiB;MAAW,CAAA;MAC9C,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OAAQ,WAAWA,yBAAI;iBAAvB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,yBAAI;QAAa,SAAS;kBACxD,EAAE,eAAe;OACZ,CAAA,GACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,SAASA,yBAAI,eAAeA,yBAAI;QAC3C,SAAS;kBAER;OACK,CAAA,CACF;;KACL;;GACF,CAAA;EAET;;;;;;;;;;;ECzBA,SAAgB,cAAc,EAAE,YAAY,MAAM,WAAmF;GACnI,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,KAAK,KAAK;GAC7C,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,KAAK,WAAW;GAC/D,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,KAAK,MAAM;GAChD,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAA+B,KAAK,QAAQ,CAAC,CAAC;GAC3D,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyC,KAAA,CAAS;GAChE,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAE5C,MAAM,SAAS,YAA2B;IACxC,IAAI,MAAM,KAAK,MAAM,IAAI;KACvB,SAAS,EAAE,cAAc,CAAC;KAC1B;IACF;IACA,WAAW,IAAI;IAMf,MAAM,UAAU,UAAU,IAAI;IAC9B,MAAM,QAAQ;KACZ;KACA;KACA;KACA,GAAI,QAAQ,SAAS,IAAI,EAAE,MAAM,QAAQ,IAAK,KAAK,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,KAAK;IAC5F;IACA,IAAI,MAAM,WAAW,WAAW,KAAK,IAAI,KAAK,GAAG;KAC/C,QAAQ;KACR;IACF;IACA,WAAW,KAAK;IAChB,SAAS,WAAW,YAAY,CAAC,CAAC,kBAAkB,EAAE,cAAc,CAAC;GACvE;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,YAAD;IACE,WAAW,EAAE,YAAY;IACzB,OAAO,EAAE,YAAY;IACd;IACE;IACT,aAAa,EAAE,WAAW;IAC1B,gBAAgB;KAAE,OAAY;IAAE;IACvB;cAPX,CASE,iBAAA,GAAA,kBAAA,IAAA,CAAC,mBAAD;KACS;KACM;KACL;KACR,gBAAe,UAAS;MAAE,SAAS,KAAK;MAAG,SAAS,KAAA,CAAS;KAAE;KAC/D,qBAAqB;KACrB,gBAAgB;IACjB,CAAA,GAED,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;KAAqB;KAAM,WAAW,iBAAiB,WAAW,YAAY,CAAC,CAAC,KAAK;KAAG,UAAU;IAAU,CAAA,CAClG;;EAEhB;;EAGA,SAAgB,cAAc,EAAE,YAAY,MAAM,WAAmF;GACnI,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAA+B,KAAK,QAAQ,CAAC,CAAC;GAC3D,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyC,KAAA,CAAS;GAChE,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAE5C,MAAM,SAAS,YAA2B;IACxC,WAAW,IAAI;IACf,MAAM,UAAU,UAAU,IAAI;IAC9B,MAAM,QAAQ,EACZ,MAAM,QAAQ,SAAS,IAAI,UAAU,KACvC;IACA,IAAI,MAAM,WAAW,WAAW,KAAK,IAAI,KAAK,GAAG;KAC/C,QAAQ;KACR;IACF;IACA,WAAW,KAAK;IAChB,SAAS,WAAW,YAAY,CAAC,CAAC,kBAAkB,EAAE,cAAc,CAAC;GACvE;GAEA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;IACE,WAAW,EAAE,iBAAiB;IAC9B,OAAO,EAAE,iBAAiB;IACnB;IACE;IACT,aAAa,EAAE,WAAW;IAC1B,gBAAgB;KAAE,OAAY;IAAE;IACvB;cAET,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;KAAqB;KAAM,WAAW,iBAAiB,WAAW,YAAY,CAAC,CAAC,KAAK;KAAG,UAAU;IAAU,CAAA;GAClG,CAAA;EAEhB;;;;;;;;;;EClFA,SAAgB,iBAAiB,EAAE,YAAY,QAAQ,WAAkC;GACvF,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAC5C,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyC,KAAA,CAAS;GAChE,MAAM,WAAW,WAAW,YAAY;GACxC,MAAM,QAAQ,SAAS,MAAM,mBAAA;GAG7B,MAAM,aAAa,SAAS,MAAM,QAAO,SACvC,KAAK,eAAe,KAAA,KAGjB,KAAK,WAAW,aAChB,KAAK,aAAa,KAAA,KAClB,KAAK,OAAO,OAAO,MACnB,gBAAgB,SAAS,OAAO,KAAK,IAAI,OAAO,IAAI,KAAK,CAAC,CAAC,EAChE;GACA,MAAM,OAAO,OAAO,WAAkC;IACpD,WAAW,IAAI;IACf,SAAS,KAAA,CAAS;IAClB,IAAI,MAAM,WAAW,UAAU,QAAQ,OAAO,EAAE,GAAG;KACjD,QAAQ;KACR;IACF;IACA,WAAW,KAAK;IAChB,SAAS,WAAW,YAAY,CAAC,CAAC,kBAAkB,EAAE,cAAc,CAAC;GACvE;GACA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWC,yBAAI;IAAe,cAAa,UAAS;KAAE,IAAI,MAAM,WAAW,MAAM,eAAe,QAAQ;IAAE;cAC7G,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,yBAAI;KAAO,MAAK;KAAS,cAAY,EAAE,oBAAoB;eAA3E;MACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;OAAI,WAAWA,yBAAI;iBAAa,EAAE,oBAAoB;MAAM,CAAA;MAC5D,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,yBAAI;iBAAY,EAAE,mBAAmB;MAAK,CAAA;MACvD,WAAW,WAAW,IACnB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,yBAAI;iBAAa,EAAE,oBAAoB;MAAK,CAAA,IAE1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;OAAI,WAAWA,yBAAI;iBAChB,WAAW,KAAI,SACd,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;QAAkB,WAAWA,yBAAI;kBAAjC;SACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,yBAAI;oBAAY,KAAK;SAAY,CAAA;SAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,yBAAI;UAAa,eAAa,KAAK;oBAAS,EAAE,WAAW,KAAK,OAAO;SAAQ,CAAA;SAC9F,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WAAE,KAAU,KAAK,EAAE;UAAE;oBAEnC,EAAE,sBAAsB;SACnB,CAAA;QACN;UAXK,KAAK,EAWV,CACL;MACC,CAAA;MAEP,UAAU,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,yBAAI;iBAAY;MAAS,CAAA;MAC/D,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,WAAWA,yBAAI;iBACrB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,yBAAI;QAAa,SAAS;kBAAU,EAAE,YAAY;OAAU,CAAA;MACvF,CAAA;KACL;;GACF,CAAA;EAET;;;;;;;;;;ECzDA,MAAM,aAA2E;GAC/E,WAAW;GACX,QAAQ;GACR,WAAW;EACb;;EAGA,SAAS,aAAa,EAAE,WAAW,UAAU,UAAkG;GAC7I,MAAM,SAAS,UAAU;GACzB,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAWC,yBAAI;IAAc,eAAa;cAA9C;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;MAAgB,eAAa;gBAC/C,WAAW,KAAA,IAAY,EAAE,uBAAuB,IAAI,EAAE,WAAW,OAAO;KACrE,CAAA;KACN,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAArB;OACG,EAAE,yBAAyB;OAAE;OAAE,WAAW,UAAU,WAAW,QAAQ;OACvE,UAAU,YAAY,KAAA,KAAa,MAAM,EAAE,uBAAuB,EAAE,GAAG,WAAW,UAAU,SAAS,QAAQ;MAC1G;;KACL,UAAU,gBAAgB,KAAA,KACzB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;MAAgB,OAAO,UAAU;gBACnD,EAAE,8BAA8B,EAAE,SAAS,UAAU,YAAY,CAAC;KAC/D,CAAA;KAEP,UAAU,cAAc,KAAA,KACvB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,yBAAI;MACf,eAAe;OAAE,OAAO,UAAU,SAAmB;MAAE;MACvD,OAAO,UAAU;gBAJnB,CAMG,EAAE,oBAAoB,GAAE,IACnB;;KAET,UAAU,UAAU,KAAA,KAAa,UAAU,UAAU,MACpD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,yBAAI;gBAAiB,UAAU;KAAY,CAAA;IAE5D;;EAER;;EAGA,SAAS,yBAAyB,EAAE,YAAY,MAAM,WAAgF;GACpI,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,WAAW,YAAY,CAAC,CAAC,gBAAgB;GAGhF,MAAM,uBAAgC,WAAW,YAAY,CAAC,CAAC,MAAM,qBAAqB;GAC1F,MAAM,CAAC,kBAAkB,wBAAA,GAAA,MAAA,SAAA,CAAgC,eAAe,CAAC;GACzE,CAAA,GAAA,MAAA,UAAA,OACQ,WAAW,gBAAgB;IAC/B,MAAM,WAAW,WAAW,YAAY;IACxC,WAAW,SAAS,gBAAgB;IACpC,oBAAoB,SAAS,MAAM,qBAAqB,IAAI;GAC9D,CAAC,GACD,CAAC,UAAU,CACb;GACA,MAAM,cAAc,KAAK,eAAe;GACxC,MAAM,OAAO,KAAK,QAAQ;GAC1B,MAAM,aAAa,KAAK,cAAc;GACtC,MAAM,QAAQ,KAAK,SAAS;GAI5B,MAAM,iBAAiB,gBAAgB,MAAM,QAAQ,WAAW,MAAK,SAAQ,KAAK,gBAAgB,WAAW;GAC7G,MAAM,YAAY,SAAS,MAAM,QAAQ,QAAQ,MAAK,SAAQ,KAAK,OAAO,IAAI;GAC9E,MAAM,aAAa,UAAU,OAAO,QAAQ,UAAU,CAAC,EAAA,CAAG,MAAK,SAAQ,KAAK,OAAO,KAAK;GACxF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAWA,yBAAI;cAAxB;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,0BAA0B,EAAM,CAAA;KACvC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,WAAW;KAAK,CAAA;KACjD,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,eAAe;MAAQ,CAAA,GAC3D,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,UAAU;OACV,WAAU,UAAS;QAAE,WAAW,WAAW,KAAK,IAAI,EAAE,aAAa,MAAM,OAAO,MAAM,CAAC;OAAE;iBAJ3F;QAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,OAAM;mBAAI,EAAE,uBAAuB;QAAU,CAAA;QACpD,CAAC,kBAAkB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,OAAO;mBAAf,CAA6B,aAAa,EAAE,mBAAmB,CAAU;;QAC5F,QAAQ,WAAW,KAAI,cACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAoC,OAAO,UAAU;mBAAc,UAAU;QAAc,GAA9E,UAAU,WAAoE,CAC5F;OACK;QACH;;KACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,UAAU;MAAQ,CAAA,GACtD,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,UAAU;OACV,WAAU,UAAS;QAAE,WAAW,WAAW,KAAK,IAAI,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;OAAE;iBAJpF;QAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,OAAM;mBAAI,EAAE,mBAAmB;QAAU,CAAA;QAChD,CAAC,aAAa,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,OAAO;mBAAf,CAAsB,MAAM,EAAE,mBAAmB,CAAU;;QACzE,QAAQ,QAAQ,KAAI,WACnB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAwB,OAAO,OAAO;SAAI,UAAU,OAAO,WAAW,KAAA;mBAAtE;UACG,OAAO,QAAQ,OAAO;UACtB,OAAO,YAAY,EAAE,yBAAyB,IAAI;UAClD,OAAO,WAAW,KAAA,IAAY,EAAE,wBAAwB,IAAI;SACvD;WAJK,OAAO,EAIZ,CACT;OACK;QACH;;KACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,gBAAgB;MAAQ,CAAA,GAC5D,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,UAAU;OACV,WAAU,UAAS;QAAE,WAAW,WAAW,KAAK,IAAI,EAAE,YAAY,MAAM,OAAO,UAAU,KAAK,KAAA,IAAY,MAAM,OAAO,MAAwB,CAAC;OAAE;iBAJpJ,CAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,OAAM;kBAAI,EAAE,yBAAyB;OAAU,CAAA,GACtD,iBAAiB,KAAI,OACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAiB,OAAO;kBAAK,EAAE,mBAAmB,IAAoB;OAAU,GAAnE,EAAmE,CACjF,CACK;QACH;;KACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,yBAAI;iBAAa,EAAE,WAAW;MAAQ,CAAA,GACvD,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAO;OACP,UAAU;OACV,WAAU,UAAS;QAAE,WAAW,WAAW,KAAK,IAAI,EAAE,OAAO,MAAM,OAAO,UAAU,KAAK,KAAA,IAAY,MAAM,OAAO,MAAM,CAAC;OAAE;iBAJ7H;QAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,OAAM;mBAAI,EAAE,oBAAoB;QAAU,CAAA;QACjD,CAAC,cAAc,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,OAAO;mBAAf,CAAuB,OAAO,EAAE,oBAAoB,CAAU;;QAC7E,QAAQ,QAAQ,KAAI,SACnB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAsB,OAAO,KAAK;mBAAK,KAAK,QAAQ,KAAK;QAAW,GAAvD,KAAK,EAAkD,CACrE;OACK;QACH;;KACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OACE,MAAK;OACL,SAAS,KAAK,iBAAiB;OAC/B,UAAU;OACV,WAAU,UAAS;QAAE,WAAW,WAAW,KAAK,IAAI,EAAE,cAAc,MAAM,OAAO,QAAQ,CAAC;OAAE;MAC7F,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,mBAAmB,EAAQ,CAAA,CAC/B;;KACP,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,uBAAuB;KAAK,CAAA;KAC7D,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OACE,MAAK;OACL,SAAS,KAAK,YAAY;OAC1B,UAAU,WAAW,CAAC;OACtB,WAAU,UAAS;QAAE,WAAW,WAAW,KAAK,IAAI,EAAE,SAAS,MAAM,OAAO,QAAQ,CAAC;OAAE;MACxF,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,cAAc,EAAQ,CAAA,CAC1B;;KACP,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,mBAAmB,EAAE,kBAAkB,IAAI,EAAE,yBAAyB;KAAK,CAAA;IACnG;;EAEb;;EAGA,SAAS,gBAAgB,EAAE,YAAY,MAAM,WAAgF;GAC3H,MAAM,WAAW,KAAK;GACtB,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAoB,UAAU,QAAQ,WAAW;GAC9D,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,UAAU,WAAW,KAAK;GACjE,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAA6C,UAAU,SAAS;GAClF,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,SAAA,CAAmD,UAAU,eAAe;GACpG,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyC,KAAA,CAAS;GAChE,MAAM,WAAW,WAAW,YAAY,CAAC,CAAC,MAAM,UAAU;GAI1D,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,QAAQ,UAAU,QAAQ,WAAW;IACrC,WAAW,UAAU,WAAW,KAAK;IACrC,aAAa,UAAU,SAAS;IAChC,mBAAmB,UAAU,eAAe;IAC5C,SAAS,KAAA,CAAS;GACpB,GAAG;IAAC,KAAK;IAAI,UAAU;IAAS,UAAU;IAAM,UAAU;IAAW,UAAU;GAAe,CAAC;;GAG/F,MAAM,YAAY,UAAwB;IACxC,MAAM,UAAU,MAAM,KAAK;IAC3B,QAAQ,OAAO;IACf,IAAI,YAAY,MAAM,CAAC,YAAY,OAAO,GAAG;KAC3C,SAAS,EAAE,yBAAyB,CAAC;KACrC;IACF;IACA,SAAS,KAAA,CAAS;IAClB,WAAW,YAAY,KAAK,IAAI,EAAE,MAAM,QAAQ,CAAC;GACnD;;GAGA,MAAM,iBAAiB,SAAwB;IAC7C,MAAM,UAAU,KAAK,KAAK;IAC1B,IAAI,SAAS,YAAY,MAAM,CAAC,YAAY,OAAO,IAAI;KACrD,SAAS,EAAE,yBAAyB,CAAC;KACrC;IACF;IACA,SAAS,KAAA,CAAS;IAKlB,IAJkB,WAAW,YAAY,KAAK,IAAI;KAChD,SAAS;KACT,GAAI,QAAQ,YAAY,UAAU,OAAO,EAAE,MAAM,QAAQ,IAAI,CAAC;IAChE,CACY,KAAK,CAAC,WAAW,aAAa,GAAG,WAAW,IAAI;GAC9D;GAEA,MAAM,eAAe,WAAyB;IAC5C,IAAI,WAAW,IAAI;IACnB,QAAQ,MAAM;IACd,SAAS,KAAA,CAAS;IAClB,WAAW,YAAY,KAAK,IAAI,EAAE,MAAM,OAAO,CAAC;GAClD;GAEA,MAAM,YAAY,CAAC,WAAW,cAAc,KAAA,IACxC,EAAE,8BAA8B,IAChC,aAAa,KAAK,IAAI,IACpB,EAAE,yBAAyB,IAC3B,oBAAoB,WAAW,QAAQ;GAC7C,MAAM,YAAY,oBAAoB,KAAA,IAAY,MAAM,oBAAoB,iBAAiB,QAAQ;GAErG,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAWA,yBAAI;cAAxB;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,iBAAiB,EAAM,CAAA;KAC9B,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;MAAO,WAAWA,yBAAI;gBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU;OACV,WAAU,UAAS;QAAE,cAAc,MAAM,OAAO,OAAO;OAAE;MAC1D,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,wBAAwB,EAAQ,CAAA,CACpC;;KACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;gBAApB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OACE,WAAW,GAAGA,yBAAI,MAAM,GAAGA,yBAAI,gBAAgB,UAAU,KAAA,IAAY,IAAIA,yBAAI,yBAAyB;OACtG,OAAO;OACP,UAAU;OACV,aAAY;OACZ,YAAY;OACZ,cAAY,EAAE,sBAAsB;OACpC,WAAU,UAAS;QAAE,QAAQ,MAAM,OAAO,KAAK;QAAG,SAAS,KAAA,CAAS;OAAE;OACtE,cAAc;QAAE,SAAS,IAAI;OAAE;OAC/B,YAAW,UAAS;QAAE,IAAI,MAAM,QAAQ,SAAS,SAAS,IAAI;OAAE;MACjE,CAAA,GACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OACE,WAAWA,yBAAI;OACf,OAAM;OACN,UAAU;OACV,cAAY,EAAE,yBAAyB;OACvC,WAAU,UAAS;QAAE,YAAY,MAAM,OAAO,KAAK;OAAE;iBALvD,CAOE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,OAAM;kBAAd,CAAkB,EAAE,yBAAyB,GAAE,GAAS;WACvD,iBAAiB,KAAI,WACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAA0B,OAAO,OAAO;kBAAO,EAAE,OAAO,KAAK;OAAU,GAA1D,OAAO,IAAmD,CACxE,CACK;QACL;;KACJ,UAAU,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAY;KAAS,CAAA;KAC/D,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAlB;OACG,EAAE,yBAAyB;OAAE;OAAE;OAC/B;OAAO,EAAE,+BAA+B;OAAE;OAAE;MAC5C;;IACI;;EAEb;;;;;;EAOA,SAAS,eAAe,EAAE,YAAY,MAAM,SAAS,YAKlD;GACD,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwB,WAAW,YAAY,CAAC;GACjE,CAAA,GAAA,MAAA,UAAA,OACQ,WAAW,gBAAgB,YAAY,WAAW,YAAY,CAAC,CAAC,GACtE,CAAC,UAAU,CACb;GACA,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAC5C,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwB,KAAK;GAC9C,MAAM,QAAQ,SAAS;GACvB,MAAM,SAAS,KAAK,aAAa,KAAA,IAAY,KAAA,IAAY,MAAM,MAAK,cAAa,UAAU,OAAO,KAAK,QAAQ;GAC/G,MAAM,WAAW,eAAe,OAAO,KAAK,EAAE;GAC9C,MAAM,QAAQ,SAAS,MAAM,mBAAA;GAE7B,MAAM,cAAc,UAAU,OAAO,KAAK,EAAE,IAAI,KAAK;GACrD,MAAM,WAAW,CAAC,YAAY,CAAC;GAC/B,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAWA,yBAAI;IAAe,iBAAc;cAArD;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,iBAAiB,EAAM,CAAA;KAC7B,WAAW,KAAA,KACV,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAlB;OACG,EAAE,eAAe;OAAE;OAAE;OACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,yBAAI;QACf,OAAO,EAAE,oBAAoB;QAC7B,eAAe;SAAE,WAAW,SAAS,OAAO,EAAE;QAAE;kBAE/C,OAAO;OACF,CAAA;MACP;;KAEJ,SAAS,WAAW,IACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,uBAAuB;KAAK,CAAA,IAE7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;MAAI,WAAWA,yBAAI;gBAChB,SAAS,KAAI,UACZ,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;OAAmB,WAAWA,yBAAI;iBAAlC;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,yBAAI;SACf,eAAe;UAAE,WAAW,SAAS,MAAM,EAAE;SAAE;mBAE9C,MAAM;QACD,CAAA;QACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,yBAAI;SAAa,eAAa,MAAM;mBAAS,EAAE,WAAW,MAAM,OAAO;QAAQ,CAAA;QAC/F,CAAC,YACA,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,yBAAI;SACf,UAAU,WAAW,MAAM,WAAW;SACtC,OAAO,MAAM,WAAW,YAAY,EAAE,6BAA6B,IAAI,KAAA;SACvE,eAAe;UAAE,WAAgB,UAAU,MAAM,IAAI,IAAI;SAAE;mBAE1D,EAAE,wBAAwB;QACrB,CAAA;OAER;SApBK,MAAM,EAoBX,CACL;KACC,CAAA;KAEP,SAAS,SAAS,KACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,2BAA2B,EAAE,OAAO,OAAO,SAAS,MAAM,EAAE,CAAC;KAAK,CAAA;KAEpG,CAAC,aAAa,cACV,WAAW,aAAa,IAEvB,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;gBAApB,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,yBAAI;OAAa,UAAU,CAAC;OAAU,eAAe;QAAE,WAAW,IAAI;OAAE;iBAAzG,CAA4G,MACvG,EAAE,qBAAqB,CACpB;UACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,yBAAI;OAAa,UAAU,CAAC;OAAU,eAAe;QAAE,YAAY,IAAI;OAAE;iBACvG,EAAE,sBAAsB;MACnB,CAAA,CACL;UAEL,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,0BAA0B;KAAK,CAAA,IAClE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,yBAAI;gBAAa,EAAE,8BAA8B,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;KAAK,CAAA;KAC/F,WACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MAA0B;MAAY,YAAY;MAAM,eAAe;OAAE,WAAW,KAAK;MAAE;KAAI,CAAA;KAEhG,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD;MAA8B;MAAY,QAAQ;MAAM,eAAe;OAAE,YAAY,KAAK;MAAE;KAAI,CAAA;IAE3F;;EAEb;;EAGA,SAAgB,WAAW,EAAE,YAAY,QAA2D;GAClG,MAAM,CAAC,eAAe,qBAAA,GAAA,MAAA,SAAA,CAA6B,KAAK;GACxD,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwB,KAAK;GAC9C,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,KAAK;GACtD,MAAM,CAAC,eAAe,qBAAA,GAAA,MAAA,SAAA,CAA6B,KAAK;GAGxD,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,IAAI;GACzC,CAAA,GAAA,MAAA,UAAA,OAAgB;IAAE,UAAU,IAAI;GAAE,GAAG,CAAC,IAAI,CAAC;GAE3C,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,YAAY,KAAK;IACjB,gBAAgB,KAAK;IACrB,iBAAiB,KAAK;GACxB,GAAG,CAAC,KAAK,EAAE,CAAC;GACZ,MAAM,UAAU;GAChB,MAAM,WAAW,WAAW,YAAY;GACxC,MAAM,UAAU,QAAQ,WAAW;GACnC,MAAM,WAAW,QAAQ,eAAe,KAAA;GACxC,MAAM,UAAU,SAAS,eAAe,SAAS,QAAQ,EAAE;GAC3D,MAAM,iBAAiB,SAAS;GAChC,MAAM,WAAW,SAAS,MAAM,UAAU;GAC1C,MAAM,oBAAoB,+BAA+B,SAAS,SAAS,MAAM,wBAAwB;GACzG,MAAM,kBAAkB,eAAe,SAAS,OAAO,QAAQ,EAAE;GAEjE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,yBAAI;IAAe,cAAa,UAAS;KAAE,IAAI,MAAM,WAAW,MAAM,eAAe,WAAW,UAAU;IAAE;cAA5H;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;MAAQ,MAAK;MAAS,cAAY,EAAE,cAAc;gBAAtE;OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,WAAWA,yBAAI;kBAAvB;SACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;UAAI,WAAWA,yBAAI;oBAAc,QAAQ;SAAU,CAAA;SACnD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,yBAAI;UAAa,eAAa,WAAW,aAAa,QAAQ;oBAC5E,WAAW,EAAE,eAAe,IAAI,EAAE,WAAW,QAAQ,OAAO;SACzD,CAAA;SACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,cAAY,EAAE,cAAc;UAC5B,eAAe;WAAE,WAAW,UAAU;UAAE;oBACzC;SAEO,CAAA;QACF;;OAER,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAAK,WAAWA,yBAAI;kBAApB;SACG,mBAAmB,KAAA,KAClB,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;UAAK,WAAWA,yBAAI;oBAApB;WACG,EAAE,mBAAmB,EAAE,OAAO,eAAe,CAAC;WAAG;WAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;YAAQ,MAAK;YAAS,WAAWA,yBAAI;YAAY,eAAe;aAAE,WAAgB,cAAc;YAAE;sBAC/F,EAAE,iBAAiB;WACd,CAAA;UACL;;SAEP,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;oBAAxB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,oBAAoB,EAAM,CAAA,GACjC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;WAAG,WAAWA,yBAAI;qBAAa,QAAQ,gBAAgB,KAAK,QAAQ,cAAc;UAAO,CAAA,CAClF;;SAET,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;UAA4B;UAAY,MAAM;UAAkB;UAAmB;SAAW,CAAA;SAE7F,QAAQ,SAAS,KAAA,KAAa,QAAQ,KAAK,SAAS,KACnD,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;UAAe,iBAAc;oBAArD,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,UAAU,EAAM,CAAA,GACvB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;WAAK,WAAWA,yBAAI;qBACjB,QAAQ,KAAK,KAAI,QAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;YAEE,WAAWA,yBAAI;YACf,iBAAe,QAAQ,IAAI,IAAI;YAC/B,iBAAc;YACd,iBAAe,IAAI,iBAAiB,KAAA,IAAY,KAAA,IAAY,IAAI;YAChE,OAAO,IAAI,iBAAiB,KAAA,IAAY,IAAI,OAAO,IAAI;sBAEtD,IAAI;WACD,GARC,IAAI,IAQL,CACP;UACE,CAAA,CACE;;SAGV,QAAQ,WAAW,KAAA,KAClB,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;UAAe,iBAAc;oBAArD;WACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,eAAe,EAAM,CAAA;WAC3B,QAAQ,OAAO,aAAa,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAY,EAAE,wBAAwB;WAAK,CAAA;WAClG,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,EAAE,oBAAoB,EAAU,CAAA;WAAI,CAAA;WAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;YAAK,WAAWA,yBAAI;sBAAc,QAAQ,OAAO;WAAU,CAAA;WAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,EAAE,wBAAwB,EAAU,CAAA;WAAI,CAAA;WAC/E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;YAAK,WAAWA,yBAAI;sBAAc,QAAQ,OAAO;WAAc,CAAA;WAC/D,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,EAAE,oBAAoB,EAAU,CAAA;WAAI,CAAA;WAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;YAAK,WAAWA,yBAAI;sBAAc,QAAQ,OAAO;WAAU,CAAA;WAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAa,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,QAAQ,OAAO,UAAU,QAAQ,EAAE,CAAC;WAAK,CAAA;WAC/H,QAAQ,OAAO,aAAa,KAAA,KAC3B,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAa,EAAE,0BAA0B,EAAE,SAAS,QAAQ,OAAO,SAAS,CAAC;WAAK,CAAA;UAE/F;;SAGV,QAAQ,aAAa,KAAA,KACpB,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;UAAe,iBAAc;oBAArD;WACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,iBAAiB,EAAM,CAAA;WAC9B,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAlB;aACG,EAAE,eAAe;aAAE;aAAG,QAAQ,SAAS,eAAe,EAAE,uBAAuB;aAC/E;aAAO,EAAE,UAAU;aAAE;aAAG,QAAQ,SAAS,QAAQ,EAAE,mBAAmB;aACtE;aAAO,EAAE,gBAAgB;aAAE;aAAG,QAAQ,SAAS,eAAe,KAAA,IAAY,EAAE,yBAAyB,IAAI,EAAE,mBAAmB,QAAQ,SAAS,YAA4B;YAC3K;;WACH,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,EAAE,4BAA4B,EAAU,CAAA;WAAI,CAAA;WACnF,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;YAAI,WAAWA,yBAAI;sBAChB,QAAQ,SAAS,WAAW,KAAK,WAAW,UAG3C,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;aAAkC,WAAWA,yBAAI;uBAAc,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,UAAgB,CAAA;YAAK,GAAlF,GAAG,UAAU,GAAG,OAAkE,CAC5F;WACC,CAAA;WACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;YAAG,WAAWA,yBAAI;sBAAa,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,QAAQ,SAAS,WAAW,QAAQ,EAAE,CAAC;WAAK,CAAA;UAC/H;;SAGV,qBACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;UAAe,iBAAc;oBAArD,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;WAAG,WAAWA,yBAAI;qBAAY,EAAE,4BAA4B,EAAE,YAAY,EAAE,mBAAmB,QAAQ,UAAU,cAAc,QAAQ,YAA4B,EAAE,CAAC;UAAK,CAAA,GAC3K,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,yBAAI;WAAe,UAAU;WAAS,eAAe;YAAE,WAAgB,kBAAkB,QAAQ,EAAE;WAAE;qBACnI,EAAE,0BAA0B;UACvB,CAAA,CACD;;SAEV,QAAQ,0BAA0B,KAAA,KACjC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;UAAG,WAAWA,yBAAI;oBAAa,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,QAAQ,uBAAuB,QAAQ,EAAE,CAAC;SAAK,CAAA;SAG5I,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;oBAAxB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,eAAe,EAAM,CAAA,GAC5B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;WAAK,WAAWA,yBAAI;qBAAc,QAAQ,WAAW,KAAK,QAAQ,SAAS,QAAQ;UAAW,CAAA,CACvF;;SAER,CAAC,YACA,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,0BAAD;UAAsC;UAAY,MAAM;UAAkB;SAAU,CAAA,GACpF,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAD;UAA6B;UAAY,MAAM;UAAkB;SAAU,CAAA,CAC3E,EAAA,CAAA;SAGJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;oBAAxB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,kBAAkB,EAAM,CAAA,GAC9B,QAAQ,WAAW,WAAW,IAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;WAAG,WAAWA,yBAAI;qBAAa,EAAE,oBAAoB;UAAK,CAAA,IAE1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;WAAI,WAAWA,yBAAI;qBAChB,CAAC,GAAG,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAI,cACrC,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;YAEa;YACD;YACV,SAAQ,cAAa;aAAE,WAAW,YAAY,SAAS;YAAE;WAC1D,GAJM,UAAU,EAIhB,CACF;UACC,CAAA,CAEC;;SAER,CAAC,YACA,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;UAAS,WAAWA,yBAAI;oBAAxB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,EAAE,cAAc,EAAM,CAAA,GAC3B,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;WAAK,WAAWA,yBAAI;qBACjB,gBAAgB,KAAI,WACnB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;YAEE,MAAK;YACL,WAAWA,yBAAI;YACf,UAAU,QAAQ,WAAW,UAAU,WAAW;YAClD,eAAe;aAAE,WAAW,SAAS,QAAQ,IAAI,MAAM;YAAE;sBAExD,EAAE,eAAe,QAAwB;WACpC,GAPD,MAOC,CACT;UACE,CAAA,CACE;;QAER;;OAEL,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,WAAWA,yBAAI;kBAAvB;SACG,CAAC,YAAY,WAAW,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;UAAM,WAAWA,yBAAI;oBAArB,CAAkC,EAAE,eAAe,GAAE,GAAO;;SACpF,CAAC,YAAY,mBAAmB,OAAO,KACtC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WAAE,YAAY,IAAI;UAAE;oBAElC,EAAE,aAAa;SACV,CAAA;SAET,CAAC,YAAY,CAAC,mBAAmB,OAAO,KAAK,QAAQ,WAAW,aAC/D,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WAAE,gBAAgB,IAAI;UAAE;oBAEtC,EAAE,iBAAiB;SACd,CAAA;SAET,CAAC,YACA,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WAAE,iBAAiB,IAAI;UAAE;UACxC,OAAO,mBAAmB,OAAO,IAAI,EAAE,kBAAkB,IAAI,EAAE,yBAAyB;oBAEvF,mBAAmB,OAAO,IAAI,EAAE,kBAAkB,IAAI,EAAE,yBAAyB;SAC5E,CAAA;SAET,CAAC,YACA,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU,WAAW;UACrB,OAAO,gBAAgB,SAAS,IAC5B,EAAE,2BAA2B,EAAE,OAAO,OAAO,gBAAgB,MAAM,EAAE,CAAC,IACtE,KAAA;UACJ,eAAe;WACb,WAAgB,UAAU,QAAQ,EAAE,CAAC,CAAC,WAAW;YAC/C,IAAI,WAAW,YAAY,CAAC,CAAC,mBAAmB,KAAA,GAAW,WAAW,UAAU;WAClF,CAAC;UACH;oBAEC,QAAQ,WAAW,WAAW,IAAI,EAAE,YAAY,IAAI,EAAE,cAAc;SAC/D,CAAA;SAET,WACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WACb,WAAW,YAAY,QAAQ,EAAE;UACnC;oBAEC,EAAE,gBAAgB;SACb,CAAA,KAEP,QAAQ,WAAW,UAAU,QAAQ,WAAW,aAC/C,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WACb,WAAW,YAAY,QAAQ,EAAE;UACnC;oBAEC,EAAE,gBAAgB;SACb,CAAA;SAGZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,yBAAI;UACf,UAAU;UACV,eAAe;WAAE,iBAAiB,IAAI;UAAE;oBAEvC,EAAE,eAAe;SACZ,CAAA;SACR,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;UAAM,WAAWA,yBAAI;oBAArB;WACG,EAAE,eAAe;WAAE;WAAE,WAAW,QAAQ,WAAW,QAAQ;WAC3D,YAAY,MAAM,EAAE,qBAAqB,EAAE,MAAM,WAAW,QAAQ,YAAa,QAAQ,EAAE,CAAC;UACzF;;QACA;;MACL;;KAEJ,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;MACE,OAAO,EAAE,cAAc;MACvB,SAAS,EAAE,kBAAkB,EAAE,MAAM,QAAQ,MAAM,CAAC;MACpD,cAAc,EAAE,WAAW;MAC3B,QAAA;MACA,gBAAgB;OAAE,iBAAiB,KAAK;MAAE;MAC1C,iBAAiB;OACf,iBAAiB,KAAK;OACtB,WAAW,WAAW,QAAQ,EAAE;MAClC;KACD,CAAA;KAGF,YAAY,CAAC,YAAY,mBAAmB,OAAO,KAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;MAA2B;MAAY,MAAM;MAAS,eAAe;OAAE,YAAY,KAAK;MAAE;KAAI,CAAA;KAG/F,gBAAgB,CAAC,YAAY,QAAQ,WAAW,aAC/C,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;MAA2B;MAAY,MAAM;MAAS,eAAe;OAAE,gBAAgB,KAAK;MAAE;KAAI,CAAA;KAGnG,iBAAiB,CAAC,YACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MACc;MACZ,aAAa;MACb,eAAe;OAAE,iBAAiB,KAAK;MAAE;MACzC,oBAAoB,OAAO,aAAa;OACtC,MAAM,WAAW,YAAY,QAAQ;OACrC,WAAW,UAAU;MACvB;KACD,CAAA;IAEA;;EAET;;EC7pBA,SAAgB,cAAc,MAAkB,QAAyB;GACvE,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO;GACjC,MAAM,SAAS,OAAO,KAAK,CAAC,CAAC,YAAY;GACzC,MAAM,YAAY;IAAC,KAAK;IAAO,KAAK;IAAa,IAAI,KAAK,QAAQ,CAAC,EAAA,CAAG,KAAI,QAAO,IAAI,IAAI;GAAC;GAC1F,IAAI,KAAK,WAAW,KAAA,GAAW,UAAU,KAAK,KAAK,OAAO,MAAM,KAAK,OAAO,UAAU,KAAK,OAAO,IAAI;GACtG,OAAO,UAAU,MAAK,SAAQ,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC;EACnE;;;;;;;EAQA,SAAgB,iBAAiB,MAAkB,UAAsC;GACvF,IAAI,SAAS,WAAW,GAAG,OAAO;GAClC,MAAM,QAAQ,IAAI,KAAK,KAAK,QAAQ,CAAC,EAAA,CAAG,KAAI,QAAO,IAAI,IAAI,CAAC;GAC5D,OAAO,SAAS,OAAM,SAAQ,MAAM,IAAI,IAAI,CAAC;EAC/C;;;;;;;EAQA,MAAM,gBAAA,GAAA,MAAA,KAAA,CAAoB,SAAS,aAAa,EAAE,MAAM,SAAS,UAAU,QAAQ,cAAc,WAAW,cAAc,iBAAiB,kBAUxI;GAED,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IACQ;IACG;IACC;IACV,UAAA,GAAA,MAAA,YAAA,OAN8B;KAAE,OAAO,KAAK,EAAE;IAAE,GAAG,CAAC,KAAK,IAAI,MAAM,CAMpD;IACD;IACH;IACG;IACG;IACD;GACjB,CAAA;EAEL,CAAC;;EAGD,SAAgB,UAAU,EAAE,cAA+C;GACzE,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwB,WAAW,YAAY,CAAC;GACjE,CAAA,GAAA,MAAA,UAAA,OACQ,WAAW,gBAAgB,YAAY,WAAW,YAAY,CAAC,CAAC,GACtE,CAAC,UAAU,CACb;GACA,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,EAAE;GACvC,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAmC,CAAC,CAAC;GAKvD,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,IAAI;GACrD,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAG5C,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAyB,EAAE;GAC7C,MAAM,CAAC,gBAAgB,sBAAA,GAAA,MAAA,SAAA,CAA8B,KAAK;GAC1D,MAAM,CAAC,gBAAgB,sBAAA,GAAA,MAAA,SAAA,CAA8B,EAAE;GACvD,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,SAAA,CAAmD,KAAA,CAAS;GACpF,MAAM,CAAC,mBAAmB,yBAAA,GAAA,MAAA,SAAA,CAAiC,KAAK;GAChE,MAAM,WAAW,eAAe,QAAQ;GACxC,MAAM,cAAc,SAAS;GAG7B,MAAM,YAAY,iBAAiB,SAAS,KAAK;GAEjD,MAAM,UAAU,SAAS,MAAM,QAAO,SACpC,cAAc,KAAK,eAAe,KAAA,IAAY,KAAK,eAAe,KAAA,CACpE;GAGA,MAAM,gCAAgB,IAAI,IAAoB;GAC9C,MAAM,gCAAgB,IAAI,IAA+D;GACzF,KAAK,MAAM,QAAQ,SAAS;IAC1B,IAAI,KAAK,aAAa,KAAA,GAAW;IACjC,cAAc,IAAI,KAAK,WAAW,cAAc,IAAI,KAAK,QAAQ,KAAK,KAAK,CAAC;IAC5E,MAAM,SAAS,cAAc,IAAI,KAAK,QAAQ,KAAK;KAAE,MAAM;KAAG,SAAS;KAAG,QAAQ;IAAE;IACpF,IAAI,KAAK,WAAW,QAAQ,OAAO,QAAQ;SACtC,IAAI,KAAK,WAAW,WAAW,OAAO,WAAW;SACjD,IAAI,KAAK,WAAW,UAAU,OAAO,UAAU;IACpD,cAAc,IAAI,KAAK,UAAU,MAAM;GACzC;GACA,MAAM,cAAc,cAAc,OAAO;GACzC,MAAM,eAAe,OAAO,KAAK,MAAM,MAAM,UAAU,SAAS;GAChE,MAAM,iBAAiB,gBAAgB,CAAC;GACxC,MAAM,UAAU,QAAQ,QAAO,UAC5B,cAAc,MAAM,KAAK,gBAAgB,eACtC,CAAC,kBAAkB,KAAK,aAAa,KAAA,MACtC,cAAc,MAAM,MAAM,KAC1B,iBAAiB,MAAM,SAAS,CACrC;GACA,MAAM,WAAW,SAAS,iBAAiB;GAC3C,MAAM,mBAAmB,SAAS,uBAAuB;GACzD,MAAM,mBAAmB,YAA2B;IAClD,MAAM,OAAO,eAAe,KAAK;IACjC,IAAI,SAAS,IAAI;IACjB,qBAAqB,IAAI;IACzB,mBAAmB,KAAA,CAAS;IAC5B,IAAI;KACF,MAAM,UAAU,MAAM,WAAW,gBAAgB,IAAI;KACrD,aAAa,QAAQ,WAAW;KAChC,kBAAkB,KAAK;KACvB,kBAAkB,EAAE;IACtB,SAAS,OAAO;KACd,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;IAC3E,UAAU;KACR,qBAAqB,KAAK;IAC5B;GACF;GACA,MAAM,aAAA,GAAA,MAAA,YAAA,EAAyB,SAAuB;IACpD,cAAa,YAAW,QAAQ,SAAS,IAAI,IACzC,QAAQ,QAAO,UAAS,UAAU,IAAI,IACtC,CAAC,GAAG,SAAS,IAAI,CAAC;GACxB,GAAG,CAAC,CAAC;GACL,MAAM,YAAA,GAAA,MAAA,YAAA,EAAwB,OAAqB;IAAE,WAAW,SAAS,EAAE;GAAE,GAAG,CAAC,UAAU,CAAC;GAE5F,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,yBAAI;IAAO,4BAAyB;IAAG,mBAAgB;cAAvE;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MAAQ,WAAWA,yBAAI;gBAAvB;OAEE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,GAAGA,yBAAI,YAAY,GAAGA,yBAAI;QACrC,6BAA0B;QAC1B,cAAY,EAAE,aAAa;QAC3B,eAAe;SAAE,WAAW,WAAW;QAAE;kBAL3C,CAOE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,eAAY;mBAAO;QAAO,CAAA,GAChC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,aAAa,EAAQ,CAAA,CACxB;;OACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;QAAI,WAAWA,yBAAI;kBAAa,EAAE,aAAa;OAAM,CAAA;OACpD,SAAS,SAAS,KAAA,KACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;kBAClB,EAAE,kBAAkB;SACnB,UAAU,OAAO,SAAS,KAAK,QAAQ;SACvC,UAAU,SAAS,KAAK,UAAU;QACpC,CAAC;OACG,CAAA;QAEN,SAAS,SAAS,KAAK,qBACvB,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;QAAO,WAAWA,yBAAI;kBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,yBAAI;mBAAqB,EAAE,eAAe;QAAQ,CAAA,GACnE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SACE,WAAWA,yBAAI;SACf,iBAAc;SACd,OAAO;SACP,cAAY,EAAE,eAAe;SAC7B,WAAU,UAAS;UACjB,MAAM,QAAQ,MAAM,OAAO;UAC3B,IAAI,UAAA,uBAA6B;WAC/B,mBAAmB,KAAA,CAAS;WAC5B,kBAAkB,IAAI;WACtB;UACF;UACA,aAAa,KAAK;SACpB;mBAbF;UAeE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,OAAM;qBAAI,EAAE,kBAAkB;UAAU,CAAA;UAC/C,SAAS,KAAI,YACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAkC,OAAO,QAAQ;qBAAc,QAAQ;UAAc,GAAxE,QAAQ,WAAgE,CACtF;UACA,oBAAoB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,OAAA;qBAA2B,EAAE,kBAAkB;UAAU,CAAA;SAChF;UACH;;OAET,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,WAAWA,yBAAI;QACf,MAAK;QACL,aAAa,EAAE,cAAc;QAC7B,OAAO;QACP,WAAU,UAAS;SAAE,UAAU,MAAM,OAAO,KAAK;QAAE;QACnD,cAAY,EAAE,cAAc;OAC7B,CAAA;OACA,eACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,iBAAiBA,yBAAI,gBAAgBA,yBAAI;QACpD,iBAAc;QACd,gBAAc;QACd,OAAO,EAAE,yBAAyB;QAClC,eAAe;SAAE,iBAAgB,UAAS,CAAC,KAAK;QAAE;kBAEjD,iBAAiB,EAAE,oBAAoB,IAAI,EAAE,oBAAoB;OAC5D,CAAA;OAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAW,cAAcA,yBAAI,gBAAgBA,yBAAI;QACjD,eAAe;SAAE,WAAW,kBAAkB;QAAE;kBAE/C,cACG,EAAE,mBAAmB,IACrB,EAAE,qBAAqB,EAAE,OAAO,OAAO,SAAS,MAAM,QAAO,SAAQ,KAAK,eAAe,KAAA,CAAS,CAAC,CAAC,MAAM,EAAE,CAAC;OAC3G,CAAA;OACR,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,yBAAI;QACf,eAAe;SAAE,WAAW,IAAI;QAAE;kBAHpC,CAIC,MACI,EAAE,WAAW,CACV;;MACF;;KAEP,kBACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;MAAe,iBAAc;gBAAjD;OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;QAAO,WAAWA,yBAAI;kBAAtB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,yBAAI;mBAAa,EAAE,sBAAsB;QAAQ,CAAA,GAClE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SACE,WAAWA,yBAAI;SACf,OAAO;SACP,aAAa,EAAE,iCAAiC;SAChD,YAAY;SACZ,WAAU,UAAS;UAAE,kBAAkB,MAAM,OAAO,KAAK;UAAG,mBAAmB,KAAA,CAAS;SAAE;QAC3F,CAAA,CACI;;OACN,oBAAoB,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAG,WAAWA,yBAAI;kBAAY,EAAE,6BAA6B,EAAE,OAAO,gBAAgB,CAAC;OAAK,CAAA;OAC9H,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAAK,WAAWA,yBAAI;kBAApB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,yBAAI;SACf,eAAe;UAAE,kBAAkB,KAAK;UAAG,mBAAmB,KAAA,CAAS;SAAE;mBAExE,EAAE,YAAY;QACT,CAAA,GACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,yBAAI;SACf,UAAU,qBAAqB,eAAe,KAAK,MAAM;SACzD,eAAe;UAAE,iBAAsB;SAAE;mBAExC,EAAE,qBAAqB;QAClB,CAAA,CACL;;MACF;;KAGN,CAAC,eAAe,UAAU,SAAS,KAClC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;MAAW,iBAAc;gBAA7C;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,yBAAI;kBAAiB,EAAE,iBAAiB;OAAQ,CAAA;OAChE,UAAU,KAAI,QAAO;QACpB,MAAM,SAAS,UAAU,SAAS,IAAI,IAAI;QAC1C,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAEE,MAAK;SACL,WAAWA,yBAAI;SACf,iBAAc;SACd,iBAAe,QAAQ,IAAI,IAAI;SAC/B,eAAa,SAAS,SAAS,KAAA;SAC/B,gBAAc;SACd,OAAO,IAAI,iBAAiB,KAAA,IAAY,IAAI,OAAO,IAAI;SACvD,eAAe;UAAE,UAAU,IAAI,IAAI;SAAE;mBAEpC,IAAI;QACC,GAXD,IAAI,IAWH;OAEZ,CAAC;OACA,UAAU,SAAS,KAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,yBAAI;QAAY,eAAe;SAAE,aAAa,CAAC,CAAC;QAAE;kBAChF,EAAE,sBAAsB;OACnB,CAAA;MAEP;;KAGN,SAAS,mBAAmB,KAAA,KAC3B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;gBAApB;OACG,EAAE,mBAAmB,EAAE,OAAO,SAAS,eAAe,CAAC;OAAG;OAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAWA,yBAAI;QAAY,eAAe;SAAE,WAAgB,cAAc;QAAE;kBAC/F,EAAE,iBAAiB;OACd,CAAA;MACL;;KAGP,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,yBAAI;gBACjB,cACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;OAAS,WAAWA,yBAAI;OAAQ,eAAY;OAAW,iBAAc;iBAArE,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,WAAWA,yBAAI;kBAAvB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;SAAI,WAAWA,yBAAI;mBAAc,EAAE,eAAe;QAAM,CAAA,GACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,yBAAI;mBAAc,QAAQ;QAAa,CAAA,CAClD;WACR,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAAK,WAAWA,yBAAI;kBAApB,CACG,QAAQ,KAAI,SACX,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;SAEQ;SACN,SAAS,SAAS,eAAe,SAAS,KAAK,EAAE;SACjD,UAAU,SAAS,MAAM,UAAU;SACnC,QAAQ;SACR,cAAc,cAAc,IAAI,KAAK,EAAE,KAAK;SAC5C,WAAW,KAAK,aAAa,KAAA;SAC7B,cAAc,cAAc,IAAI,KAAK,EAAE,CAAC,EAAE,QAAQ;SAClD,iBAAiB,cAAc,IAAI,KAAK,EAAE,CAAC,EAAE,WAAW;SACxD,gBAAgB,cAAc,IAAI,KAAK,EAAE,CAAC,EAAE,UAAU;QACvD,GAVM,KAAK,EAUX,CACF,GACA,QAAQ,WAAW,KAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,yBAAI;mBAAc,UAAU,SAAS,IAAI,EAAE,gBAAgB,IAAI,EAAE,eAAe;QAAO,CAAA,CAEtG;SACE;WAET,QAAQ,KAAI,WAAU;OACpB,MAAM,QAAQ,QAAQ,QAAO,SAAQ,KAAK,WAAW,OAAO,MAAM;OAClE,MAAM,qBAAqB,OAAO,WAAW,aAAa,OAAO,WAAW;OAC5E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;QAEE,WAAWA,yBAAI;QACf,eAAa,OAAO;QACpB,iBAAc;QACd,YAAY,sBAAsB,UAAU;SAC1C,MAAM,eAAe;SACrB,MAAM,aAAa,aAAa;QAClC,IAAI,KAAA;QACJ,QAAQ,sBAAsB,UAAU;SACtC,MAAM,eAAe;SACrB,MAAM,SAAS,MAAM,aAAa,QAAQ,YAAY;SACtD,IAAI,CAAC,QAAQ;SACb,MAAM,UAAU,SAAS,MAAM,MAAK,MAAK,EAAE,OAAO,MAAM;SACxD,IAAI,WAAW,gBAAgB,QAAQ,QAAQ,OAAO,MAAM,KAAK,QAAQ,WAAW,OAAO,QACzF,WAAW,SAAS,QAAQ,OAAO,MAAM;QAE7C,IAAI,KAAA;kBAjBN,CAmBE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,WAAWA,yBAAI;mBAAvB;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,yBAAI;WAAW,eAAa,OAAO;WAAQ,eAAY;UAAQ,CAAA;UAChF,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;WAAI,WAAWA,yBAAI;qBAAc,EAAE,WAAW,OAAO,OAAO;UAAM,CAAA;UAClE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,yBAAI;qBAAc,MAAM;UAAa,CAAA;SAChD;YACR,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,yBAAI;mBAApB,CACG,MAAM,KAAI,SACT,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;UAEQ;UACN,SAAS,SAAS,eAAe,SAAS,KAAK,EAAE;UACjD,UAAU,SAAS,MAAM,UAAU;UACnC,QAAQ;UACR,cAAc,cAAc,IAAI,KAAK,EAAE,KAAK;UAC5C,WAAW,KAAK,aAAa,KAAA;UAC7B,cAAc,cAAc,IAAI,KAAK,EAAE,CAAC,EAAE,QAAQ;UAClD,iBAAiB,cAAc,IAAI,KAAK,EAAE,CAAC,EAAE,WAAW;UACxD,gBAAgB,cAAc,IAAI,KAAK,EAAE,CAAC,EAAE,UAAU;SACvD,GAVM,KAAK,EAUX,CACF,GACA,MAAM,WAAW,KAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;UAAK,WAAWA,yBAAI;oBAAc,UAAU,SAAS,IAAI,EAAE,gBAAgB,IAAI,EAAE,aAAa;SAAO,CAAA,CAEpG;UACE;UA1CF,OAAO,MA0CL;MAEb,CAAC;KAEA,CAAA;KAEJ,aAAa,KAAA,KACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;MAAwB;MAAY,MAAM;KAAW,CAAA;KAEtD,WACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MACc;MACZ,GAAK,cAAc,KAAK,CAAC,IAAI,EAAE,oBAAoB,UAAU;MAC7D,eAAe;OAAE,WAAW,KAAK;MAAE;KACpC,CAAA;IAEA;;EAET;;;;ECtWA,MAAM,UAAU,OAAO,IAAI,2BAA2B;EACtD,MAAM,oBAAoB,OAAO,IAAI,oCAAoC;EAGzE,SAAS,aAAa,aAAgE;GACpF,KAAK,MAAM,YAAY,aACrB,IAAI,CAAE,SAAwB,oBAAoB,OAAO;GAE3D,OAAO;EACT;;;;;;EAOA,SAAgB,2BAA2B,YAAoC;GAC7E,MAAM,iBAA6B;IAAE,WAAW;GAAE;GAClD,SAAS,qBAAqB;GAC9B,OAAO,uBAAuB,QAAQ;EACxC;;;;;;;;EASA,SAAgB,uBAAuB,YAA6D;GAClG,IAAI,OAAO,eAAe,eAAe,OAAO,aAAa,aAAa,aAAa,CAAC;GACxF,IAAI,OAAO,qBAAqB,YAAY,aAAa,CAAC;GAC1D,MAAM,WAAW;GACjB,IAAI,MAAM,SAAS;GACnB,IAAI,QAAQ,KAAA,GAAW;IACrB,MAAM,8BAAc,IAAI,IAAyC;IACjE,MAAM,UAA2B;KAC/B,UAAU,KAAA;KACV;KACA,SAAS,CAAC;KACV,WAAW;IACb;IACA,MAAM,cAAoB;KACxB,QAAQ,QAAQ,KAAA;KAChB,QAAQ,YAAY;KACpB,MAAM,QAAQ,QAAQ;KACtB,QAAQ,UAAU,CAAC;KACnB,KAAK,MAAM,YAAY,CAAC,GAAG,WAAW,GAAG;MACvC,IAAI,CAAC,YAAY,IAAI,QAAQ,GAAG;MAChC,IAAI;OACF,SAAS,KAAK;MAChB,QAAQ,CAER;KACF;IACF;IACA,MAAM,iBAAuB;KAC3B,IAAI,QAAQ,WAAW;KACvB,QAAQ,YAAY;KACpB,IAAI,OAAO,0BAA0B,YAAY,QAAQ,QAAQ,sBAAsB,KAAK;UACvF,MAAM;IACb;IACA,QAAQ,WAAW,IAAI,kBAAkB,YAAY;KACnD,IAAI,aAAa,WAAW,GAC1B,KAAK,MAAM,UAAU,SAAS,QAAQ,QAAQ,KAAK,MAAM;KAE3D,SAAS;IACX,CAAC;IACD,QAAQ,SAAS,QAAQ,SAAS,QAAQ,SAAS,iBAAiB;KAAE,WAAW;KAAM,SAAS;IAAK,CAAC;IACtG,SAAS,WAAW;IACpB,MAAM;GACR;GACA,MAAM,SAAS;GACf,OAAO,YAAY,IAAI,UAAU;GACjC,IAAI,aAAa;GACjB,aAAa;IACX,IAAI,CAAC,YAAY;IACjB,aAAa;IACb,OAAO,YAAY,OAAO,UAAU;IACpC,IAAI,CAAC,aAAa,OAAO,WAAW,GAAG,OAAO,UAAU,CAAC;IACzD,IAAI,OAAO,YAAY,SAAS,KAAK,SAAS,aAAa,QAAQ;KACjE,OAAO,SAAS,WAAW;KAC3B,IAAI,OAAO,UAAU,KAAA,KAAa,OAAO,yBAAyB,YAAY,qBAAqB,OAAO,KAAK;KAC/G,OAAO,QAAQ,KAAA;KACf,OAAO,UAAU,CAAC;KAClB,OAAO,YAAY;KACnB,OAAO,SAAS;IAClB;GACF;EACF;;;;;;;;;;;;;;;;;;;;;;;EChFA,MAAM,+BAA+B;;EAErC,MAAM,iBAAiB;EAKvB,MAAM,uBAAuB;;EAG7B,SAAS,qBAA8C;GACrD,OAAO,SAAS,cAA2B,4BAA4B,KAAK,KAAA;EAC9E;;;;;;EAOA,SAAgB,iBAAiB,SAA8C;GAC7E,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;IACF,oBAAoB,QAAQ,QAAQ,gBAAgB;KAClD,IAAI,SAAS,KAAA,GAAW,QAAQ,OAAO,IAAI;IAC7C,CAAC;GACH,QAAQ,CAA4E;GAEpF,MAAM,eAAqB;IACzB,IAAI,cAAc,KAAA,KAAa,CAAC,UAAU,aAAa;KAErD,MAAM,QAAQ;KACd,OAAO,KAAA;KACP,UAAU,OAAO;KACjB,YAAY,KAAA;IACd;IACA,IAAI,cAAc,KAAA,GAAW;KAC3B,MAAM,SAAS,mBAAmB;KAClC,IAAI,WAAW,KAAA,GAAW;KAC1B,YAAY,SAAS,cAAc,KAAK;KACxC,UAAU,QAAQ,QAAQ,kBAAkB;KAC5C,UAAU,QAAQ,YAAY,QAAQ;KACtC,UAAU,YAAY,QAAQ;KAC9B,OAAO,YAAY,SAAS;IAC9B;IAGA,IAAI,SAAS,KAAA,KAAa,CAAC,QAAQ,OAAO,GAAG;IAC7C,QAAA,GAAA,iBAAA,WAAA,CAAkB,SAAS;IAC3B,QAAQ,OAAO,IAAI;GACrB;GAMA,MAAM,kBAAkB,iCAAiC;IAAE,OAAO;GAAE,CAAC;GAErE,MAAM,oBAA0B;IAC9B,IAAI,QAAQ,OAAO,GAAG;KACpB,OAAO;KAKP,SAAS,gBAAgB,gBAAgB,QAAQ,sBAAsB;KACvE,SAAS,gBAAgB,aAAa,QAAQ,iBAAiB,EAAE;KACjE,SAAS,cAAc,IAAI,YAAY,gBAAgB,EAAE,QAAQ,QAAQ,UAAU,CAAC,CAAC;IACvF,OACE,SAAS,gBAAgB,gBAAgB,QAAQ,eAAe;GAEpE;GACA,MAAM,mBAAmB,UAAuB;IAC9C,IAAK,MAAsB,WAAW,QAAQ,oBAAoB,QAAQ,OAAO,GAC/E,QAAQ,MAAM;GAElB;GACA,MAAM,qBAAqB,UAA4B;IACrD,IAAI,CAAC,QAAQ,OAAO,GAAG;IACvB,MAAM,SAAS,MAAM;IACrB,IAAI,WAAW,MAAM;IACrB,IAAI,OAAO,QAAQ,oBAAoB,MAAM,MAAM,QAAQ,MAAM;GACnE;GACA,SAAS,iBAAiB,SAAS,mBAAmB,IAAI;GAC1D,SAAS,iBAAiB,gBAAgB,eAAe;GACzD,MAAM,cAAc,QAAQ,UAAU,WAAW;GACjD,YAAY;GACZ,OAAO;GAEP,aAAa;IACX,SAAS,oBAAoB,SAAS,mBAAmB,IAAI;IAC7D,SAAS,oBAAoB,gBAAgB,eAAe;IAC5D,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,SAAS,gBAAgB,gBAAgB,QAAQ,eAAe;IAChE,MAAM,QAAQ;IACd,OAAO,KAAA;IACP,WAAW,OAAO;IAClB,YAAY,KAAA;GACd;EACF;;;;;;;;;;;EC/HA,SAAgB,WAAW,YAA6B,QAA0C;GAChG,OAAO,iBAAiB;IACtB,SAAQ,SAAQ,KAAK,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD,EAAuB,WAAa,CAAA,CAAC;IACjE,gBAAgB;IAChB,YAAY;IACZ,eAAeC,yBAAI;IACnB,iBAAiB;IACjB,wBAAwB;IACxB,WAAW;IACX,kBAAkB;IAClB,cAAc,WAAW,YAAY,CAAC,CAAC;IACvC,aAAa,WAAW,WAAW;IACnC,YAAW,aAAY,WAAW,UAAU,QAAQ;IACpD;GACF,CAAC;EACH;;;;;;;;;;;;;;;;;;;ECwBA,SAAS,cAAuC;GAC9C,MAAM,SAAS,SAAS,cAA2B,kDAA8C;GACjG,IAAI,WAAW,MAAM,OAAO,KAAA;GAK5B,OADkB,OAAO,cAA2B,sBAAoB,CAAC,EAAE,iBACtD,OAAO;EAC9B;;EAGA,SAAS,iBAAiB,MAAkD;GAC1E,MAAM,SAAS,KAAK,cAAiC,+BAA6B;GAClF,IAAI,WAAW,MAAM,OAAO;GAC5B,KAAK,MAAM,SAAS,KAAK,UACvB,IAAI,MAAM,YAAY,UAAU,OAAO;EAG3C;;EAGA,SAAS,YAAY,SAA8E;GACjG,MAAM,QAAQ,SAAS,cAAc,QAAQ;GAC7C,MAAM,OAAO;GACb,MAAM,aAAa,QAAQ,cAAc,EAAE;GAC3C,IAAI,QAAQ,WAAW,KAAA,GAAW;IAChC,MAAM,aAAa,mBAAmB,QAAQ,MAAM;IACpD,MAAM,aAAa,iBAAiB,eAAe;GACrD;GACA,MAAM,YAAY,QAAQ,IAAI,YAAY;GAC1C,MAAM,YAAY,SAAS,cAAc,MAAM;GAC/C,UAAU,YAAY,QAAQ,IAAI,iBAAiB;GACnD,MAAM,WAAW,SAAS,cAAc,MAAM;GAC9C,SAAS,YAAY,QAAQ,IAAI,gBAAgB;GACjD,SAAS,YAAY,QAAQ;GAC7B,MAAM,OAAO,UAAU,SAAS;GAChC,MAAM,mBAAyB;IAC7B,MAAM,aAAa,cAAc,QAAQ,MAAM,CAAC;IAChD,IAAI,QAAQ,YAAY,KAAA,GAAW,MAAM,aAAa,SAAS,QAAQ,QAAQ,CAAC;IAChF,UAAU,cAAc,QAAQ,MAAM;GACxC;GACA,WAAW;GACX,MAAM,iBAAiB,SAAS,QAAQ,QAAQ;GAChD,OAAO;IAAE;IAAO;GAAW;EAC7B;;EAGA,SAAS,WAAW,MAAmB,OAAoB,SAAuC;GAChG,MAAM,SAAS,iBAAiB,IAAI;GACpC,IAAI,WAAW,KAAA,GAAW,OAAO;GACjC,IAAI,MAAM,kBAAkB,MAAM;IAQhC,MAAM,MAAM,OAAO,QAAQ,sBAAoB;IAC/C,MAAM,OAAQ,QAAQ,QAAQ,IAAI,kBAAkB,OAAQ,MAAM;IAClE,MAAM,SAAS,MAAM,KAAK,KAAK,QAAQ,CAAC,CAAC,QACtC,OAA0B,cAAc,eAAe,GAAG,QAAQ,QAAQ,gBAAgB,KAAK,IAAI,CAAC,CACvG;IACA,MAAM,SAAS,QAAQ,aAAa,WAC/B,OAAO,SAAS,IAAI,OAAO,KAAK,KAAK,qBACrC,OAAO,SAAS,IAAI,OAAO,OAAO,SAAS,EAAE,CAAE,qBAAqB,KAAK;IAC9E,KAAK,aAAa,OAAO,MAAM;GACjC;GACA,OAAO;EACT;;;;;;;EAQA,SAAgBC,oBAAkB,SAA0C;GAK1E,IAAI,OAAO,aAAa,eAAe,SAAS,cAAc,QAAQ,WAAW,MAAM,MACrF,aAAa,CAAC;GAEhB,MAAM,EAAE,OAAO,eAAe,YAAY,OAAO;GACjD,IAAI;GACJ,IAAI,SAAS;GACb,IAAI;GACJ,IAAI,QAAQ,YAAY,KAAA,GACtB,IAAI;IACF,qBAAqB,QAAQ,QAAQ,UAAU,UAAU;GAC3D,QAAQ,CAGR;GAGF,MAAM,iBAAuB;IAC3B,IAAI,SAAS,KAAA,KAAa,CAAC,KAAK,aAAa;KAI3C,aAAa,WAAW;KACxB,OAAO,KAAA;KACP,SAAS;IACX;IACA,IAAI,QAAQ;KAEV,IAAI,SAAS,KAAK,SAAS,KAAK,GAAG;KAEnC,aAAa,WAAW;KACxB,OAAO,KAAA;KACP,SAAS;IACX;IACA,SAAS,YAAY;IACrB,IAAI,SAAS,KAAA,GAAW;IACxB,SAAS,WAAW,MAAM,OAAO,OAAO;IACxC,IAAI,QACF,aAAa,QAAQ,MAAM;KAAE,WAAW;KAAM,SAAS;IAAK,CAAC;GAEjE;GAYA,MAAM,kBAAkB,iCAAiC;IAAE,SAAS;GAAE,CAAC;GAIvE,MAAM,eAAe,IAAI,uBAAuB;IAC9C,IAAI,SAAS,KAAA,KAAa,CAAC,KAAK,aAAa;KAC3C,SAAS;KACT,SAAS;KACT;IACF;IACA,IAAI,CAAC,KAAK,SAAS,KAAK,GACtB,SAAS,WAAW,MAAM,OAAO,OAAO;GAE5C,CAAC;GAKD,MAAM,oBAAoB,QAAQ,WAAW,KAAA,IAAY,KAAA,WAAmB;IAC1E,MAAM,mBAAyB;KAC7B,IAAI,QAAQ,OAAQ,OAAO,GAAG,MAAM,QAAQ,SAAS;UAChD,OAAO,MAAM,QAAQ;IAC5B;IACA,MAAM,cAAc,QAAQ,OAAO,UAAU,UAAU;IACvD,WAAW;IACX,OAAO;GACT,EAAA,CAAG;GAEH,SAAS;GAET,aAAa;IACX,gBAAgB;IAChB,aAAa,WAAW;IACxB,qBAAqB;IACrB,oBAAoB;IACpB,MAAM,OAAO;GACf;EACF;;;;ECzNA,MAAa,iBAAiB;;EAG9B,MAAM,OAAO;;;;;;;;;EAab,SAAgB,kBAAkB,YAA6B,QAA0C;GACvG,OAAOC,oBAAwB;IAC7B,cAAc;IACd,aAAa;IACb,QAAQ;IACR,MAAM;IACN,KAAA;IACA,aAAa,EAAE,aAAa;IAC5B,SAAS,WAAW,KAAA,IAAY,KAAA,IAAY,EAAE,YAAY,aAAa,OAAO,UAAU,QAAQ,EAAE;IAClG,gBAAgB;KAAE,WAAW,YAAY;IAAE;IAC3C,UAAU;IACV,iBAAiB,CAAC,8BAA8B,sBAAsB;IACtE,QAAQ;KACN,YAAY,aAAa,WAAW,UAAU,QAAQ;KACtD,cAAc,WAAW,YAAY,CAAC,CAAC;IACzC;GACF,CAAC;EACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC2BA,SAAgB,mBAAiD,OAAsC;GACrG,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAoB,MAAM,eAAe,IAAI;GAC1D,MAAM,EAAE,OAAO,eAAe;GAC9B,IAAI,CAAC,MAAM,WAAW,OAAO;GAC7B,MAAM,QAAQ,MAAM,EAAE,MAAM,QAAQ;GACpC,MAAM,cAAc,MAAM,EAAE,MAAM,cAAc;GAChD,MAAM,UAAU,CAAC,MAAM,SAAS,MAAM,WAAW,MAAM;GACvD,MAAM,WAAW,eAAe,QAAQ;GACxC,MAAM,YAAY,WAAW,GAAGC,iCAAI,SAAS,GAAGA,iCAAI,SAASA,iCAAI;GAGjE,MAAM,SAAS,eAAe,OAE1B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,iCAAI;cAApB,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAWA,iCAAI;eAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;MAAa;gBAAQ;KAAY,CAAA,GACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;MAAa,OAAO;gBAAc,MAAM,mBAAmB;KAAkB,CAAA,CAC9F;QACL,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAWA,iCAAI;KAAS,OAAO,MAAM,EAAE,kBAAkB;eAAI,MAAM,EAAE,kBAAkB;IAAQ,CAAA,IAAI,IACrH;QAGL,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IACE,MAAK;IACL,WAAWA,iCAAI;IACf,iBAAe;IACf,cAAY,GAAG,MAAM,EAAE,OAAO,sBAAsB,iBAAiB,EAAE,IAAI;IAC3E,eAAe;KAAE,QAAQ,CAAC,IAAI;IAAE;cALlC;KAOE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;gBAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;OAAa;iBAAQ;MAAY,CAAA,GACtD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;OAAa,OAAO;iBAAc,MAAM,mBAAmB;MAAkB,CAAA,CAC9F;;KACL,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;MAAS,OAAO,MAAM,EAAE,kBAAkB;gBAAI,MAAM,EAAE,kBAAkB;KAAQ,CAAA,IAAI;KACxH,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MACE,OAAM;MACN,QAAO;MACP,SAAQ;MACR,MAAK;MACL,OAAM;MACN,WAAW,OAAO,GAAGA,iCAAI,QAAQ,GAAGA,iCAAI,gBAAgBA,iCAAI;gBAE5D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OACE,GAAE;OACF,MAAK;MACN,CAAA;KACE,CAAA;IACC;;GAMZ,IAAI,CAAC,MAAM,WAAW,MAAM,iCAAiC,MAAM;IACjE,MAAM,aAAa,MAAM,yBAAyB;IAClD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;KAAI,WAAW;eAAf,CACG,QACA,WAEG,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,iCAAI;gBACjB,aAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,iCAAI;OAAY,MAAK;iBAAU,MAAM,EAAE,qBAAqB;MAAK,CAAA,IAAI;KAC9F,CAAA,IAEL,IACF;;GAER;GACA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAW;cAAf,CACG,QACA,WAEG,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,iCAAI;eAApB;MACG,CAAC,MAAM,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,iCAAI;OAAU,MAAK;iBAAU,MAAM,EAAE,mBAAmB;MAAK,CAAA,IAAI;MACjG,MAAM;MACN,MAAM,eAAe,OAClB,OAEJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;iBAApB;QACG,MAAM,SAEH,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAQ,MAAK;mBAA/B,CACG,MAAM,EAAE,qBAAqB,GAAG,MAAM,eAAe,QAAQ,MAAM,eAAe,EAClF;aAEH;QACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,iCAAI;SACf,UAAU,CAAC,MAAM,SAAS,MAAM;SAChC,SAAS,MAAM;mBAEd,MAAM,EAAE,kBAAkB;QACrB,CAAA;QACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,iCAAI;SACf,UAAU;SACV,SAAS,MAAM;mBAEd,MAAM,EAAE,CAAC,MAAM,SAAS,kBAAkB,iBAAiB;QACtD,CAAA;OACL;;KAEF;SAEL,IACF;;EAER;EA2EA,MAAM,wCAAwB,IAAI,IAAI,CAAC,iBAAiB,qBAAqB,CAAC;EAE9E,SAAS,eAAwB;GAG/B,OAFoB,OAAO,KAAK,SAAS,KAAK,OACnB,CAAC,CAAC,MAAK,QAAO,IAAI,WAAW,KAAK,KAAK,CAAC,sBAAsB,IAAI,GAAG,CAClF;EAChB;EAOA,MAAM,kBAAkB;;;;;;;;;;EAWxB,SAAgB,YAAY,OAOzB;GACD,MAAM,EAAE,IAAI,SAAS,UAAU;GAC/B,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAoB,KAAK;GACtC,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAuB,KAAK;GAC5C,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyC,SAAS;GAChE,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,CAAC;GAChD,MAAM,cAAA,GAAA,MAAA,OAAA,CAA+D,KAAA,CAAS;GAC9E,MAAM,WAAA,GAAA,MAAA,OAAA,CAAwC,IAAI;GAClD,MAAM,YAAA,GAAA,MAAA,OAAA,CAAyC,IAAI;GAEnD,MAAM,qBAAqB;IACzB,MAAM,QAAQ,QAAQ,WAAU,WAAU,OAAO,UAAU,KAAK;IAChE,OAAO,SAAS,IAAI,QAAQ;GAC9B;GAEA,MAAM,SAAA,GAAA,MAAA,YAAA,OAA0B;IAC9B,IAAI,WAAW,YAAY,KAAA,GAAW,aAAa,WAAW,OAAO;IACrE,WAAW,IAAI;IACf,WAAW,UAAU,iBAAiB;KACpC,WAAW,KAAK;KAChB,QAAQ,KAAK;IACf,GAAG,eAAe;GACpB,GAAG,CAAC,CAAC;GAEL,MAAM,kBAAkB;IACtB,IAAI,WAAW,YAAY,KAAA,GAAW,aAAa,WAAW,OAAO;IACrE,eAAe,aAAa,CAAC;IAC7B,SAAS,SAAS;IAClB,WAAW,KAAK;IAChB,QAAQ,IAAI;GACd;GAEA,MAAM,UAAU,UAAkB;IAChC,MAAM,SAAS,QAAQ;IACvB,IAAI,QAAQ,MAAM,OAAO,OAAO,KAAK;IACrC,MAAM;GACR;GAEA,MAAM,uBAAuB;IAC3B,IAAI,MAAM,UAAU;IACpB,IAAI,QAAQ,CAAC,SAAS,MAAM;SACvB,UAAU;GACjB;GAEA,MAAM,aAAa,UAA4C;IAC7D,IAAI,MAAM,UAAU;IACpB,MAAM,QAAQ,QAAQ;IACtB,QAAQ,MAAM,KAAd;KACE,KAAK;KACL,KAAK;KACL,KAAK;KACL,KAAK;MACH,MAAM,eAAe;MACrB,IAAI,CAAC,MACH,UAAU;WACL,IAAI,CAAC,SACV,IAAI,MAAM,QAAQ,aAAa,gBAAe,WAAU,QAAQ,KAAK,KAAK;WACrE,IAAI,MAAM,QAAQ,WAAW,gBAAe,WAAU,QAAQ,IAAI,SAAS,KAAK;WAChF,OAAO,WAAW;MAEzB;KACF,KAAK;MACH,IAAI,MAAM;OACR,MAAM,eAAe;OACrB,MAAM,gBAAgB;OACtB,MAAM;MACR;MACA;KACF,KAAK;MACH,IAAI,MAAM,MAAM;MAChB;IACJ;GACF;GAEA,CAAA,GAAA,MAAA,UAAA,aAAsB;IACpB,IAAI,WAAW,YAAY,KAAA,GAAW,aAAa,WAAW,OAAO;GACvE,GAAG,CAAC,CAAC;GACL,CAAA,GAAA,MAAA,gBAAA,OAAsB;IACpB,IAAI,QAAQ,CAAC,WAAW,UAAU,WAAW;KAC3C,SAAc,SAAS;KACvB,SAAS,MAAM;IACjB;GACF,GAAG;IAAC;IAAM;IAAS;GAAK,CAAC;GAEzB,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,CAAC,MAAM;IACX,MAAM,iBAAiB,UAAwB;KAC7C,MAAM,SAAS,MAAM;KACrB,IAAI,kBAAkB,QAAQ,CAAC,QAAQ,SAAS,SAAS,MAAM,GAAG,MAAM;IAC1E;IACA,SAAS,iBAAiB,eAAe,aAAa;IACtD,aAAa,SAAS,oBAAoB,eAAe,aAAa;GACxE,GAAG,CAAC,MAAM,KAAK,CAAC;GAEhB,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,MAAM,YAAY,MAAM,MAAM;GACpC,GAAG;IAAC,MAAM;IAAU;IAAM;GAAK,CAAC;GAGhC,IAAI,aAAa,GACf,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IACM;IACJ,WAAWA,iCAAI;IACR;IACP,UAAU,MAAM;IAChB,WAAW,UAAU;KAAE,MAAM,OAAO,MAAM,OAAO,KAAK;IAAE;cAEvD,QAAQ,KAAI,WACX,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KAA2B,OAAO,OAAO;eAAQ,OAAO;IAAc,GAAzD,OAAO,KAAkD,CACvE;GACK,CAAA;GAIZ,MAAM,QAAQ,QAAQ,MAAK,WAAU,OAAO,UAAU,KAAK,CAAC,EAAE,SAAS;GACvE,MAAM,aAAa,UACf,GAAGA,iCAAI,YAAY,GAAGA,iCAAI,qBAC1B,UAAU,SACR,GAAGA,iCAAI,YAAY,GAAGA,iCAAI,oBAC1BA,iCAAI;GACV,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,iCAAI;IAAY,KAAK;cAArC,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;KACE,MAAK;KACD;KACJ,WAAW,GAAGA,iCAAI,OAAO,GAAGA,iCAAI;KAChC,UAAU,MAAM;KAChB,iBAAc;KACd,iBAAe;KACf,yBAAuB,OAAO,GAAG,GAAG,IAAI,gBAAgB,KAAA;KACxD,gBAAc,MAAM,WAAW,KAAA;KAC/B,SAAS;KACE;eAVb,CAYE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,iCAAI;gBAAc;KAAY,CAAA,GAC/C,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MACE,OAAM;MACN,QAAO;MACP,SAAQ;MACR,MAAK;MACL,OAAM;MACN,WAAW,OAAO,GAAGA,iCAAI,cAAc,GAAGA,iCAAI,sBAAsBA,iCAAI;MACxE,eAAY;gBAEZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OACE,GAAE;OACF,MAAK;MACN,CAAA;KACE,CAAA,CACC;QACP,OAEG,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAW;KAAY,MAAK;KAAU,KAAK;eAC7C,QAAQ,KAAK,QAAQ,UACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAEE,IAAI,GAAG,GAAG,IAAI;MACd,MAAK;MACL,iBAAe,OAAO,UAAU;MAChC,WAAW,GAAGA,iCAAI,eAAe,OAAO,UAAU,QAAQ,IAAIA,iCAAI,yBAAyB,KAAK,UAAU,eAAe,CAAC,UAAU,IAAIA,iCAAI,uBAAuB;MACnK,eAAe;OAAE,OAAO,KAAK;MAAE;gBAE9B,OAAO;KACL,GARE,OAAO,KAQT,CACN;IACE,CAAA,IAEL,IACD;;EAET;;EAGA,SAAgB,aAAa,OAO1B;GACD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,iCAAI;cAApB;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,iCAAI;gBAApB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OAAO,WAAWA,iCAAI;OAAO,SAAS,MAAM;iBAAK,MAAM;MAAa,CAAA,GACnE,MAAM,aAEH,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;iBAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;kBAAQ,MAAM;OAAsB,CAAA,GACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,iCAAI;QACf,UAAU,MAAM;QAChB,SAAS,MAAM;kBAEd,MAAM;OACD,CAAA,CACJ;WAEN,IACD;;KACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MACE,IAAI,MAAM;MACV,SAAS;OACP;QAAE,OAAO;QAAI,OAAO,MAAM;OAAa;OACvC;QAAE,OAAO;QAAQ,OAAO,MAAM;OAAQ;OACtC;QAAE,OAAO;QAAS,OAAO,MAAM;OAAS;MAC1C;MACA,OAAO,MAAM;MACb,UAAU,MAAM;MAChB,SAAS,MAAM;MACf,QAAQ,MAAM;KACf,CAAA;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,iCAAI;gBAAO,MAAM;KAAQ,CAAA;IACpC;;EAET;;EAGA,SAAgB,YAAY,OAKzB;GACD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,iCAAI;cAApB;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,iCAAI;gBAApB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OAAO,WAAWA,iCAAI;OAAO,SAAS,MAAM;iBAAK,MAAM;MAAa,CAAA,GACnE,MAAM,aAEH,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;OAAM,WAAWA,iCAAI;iBAArB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;kBAAQ,MAAM;OAAsB,CAAA,GACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,iCAAI;QACf,UAAU,MAAM;QAChB,SAAS,MAAM;kBAEd,MAAM;OACD,CAAA,CACJ;WAEN,IACD;;KACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MACE,IAAI,MAAM;MACV,SAAS,CAAC;OAAE,OAAO;OAAI,OAAO,MAAM;MAAa,GAAG,GAAG,MAAM,OAAO;MACpE,OAAO,MAAM;MACb,UAAU,MAAM;MAChB,SAAS,MAAM;MACf,QAAQ,MAAM;KACf,CAAA;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAW,MAAM,UAAUA,iCAAI,UAAUA,iCAAI;gBAC7C,MAAM,UAAU,MAAM,eAAe,MAAM;KAC3C,CAAA;IACA;;EAET;;;;;;;;;;;;;;;;;EC3XA,SAAgB,aAAa,OAA0B;GACrD,OAAO;IACL;IACA,SAAQ,UAAS,OAAO,UAAU,YAAY,OAAO,KAAK,IAAI;IAC9D,QAAQ,SAAS;KACf,MAAM,UAAU,KAAK,KAAK;KAC1B,IAAI,YAAY,IAAI,OAAO,EAAE,MAAM,QAAQ;KAC3C,IAAI,YAAY,QAAQ,OAAO;MAAE,MAAM;MAAO,OAAO;KAAK;KAC1D,IAAI,YAAY,SAAS,OAAO;MAAE,MAAM;MAAO,OAAO;KAAM;IAE9D;GACF;EACF;;;;;;;;;EAsBA,IAAa,WAAb,MAAyB;GAaJ;GAZnB;GACA,yBAA0B,IAAI,IAAwB;GACtD,4BAA6B,IAAI,IAAgB;;GAEjD;GACA,WAAmB;GACnB,SAAiB;GACjB,SAAiB;GACjB;;GAGA,YACE,OACA,OACA;IAFiB,KAAA,QAAA;IAGjB,KAAK,QAAQ,IAAI,IAAI,MAAM,KAAI,SAAQ,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC;IAC1D,KAAK,cAAc,MAAM,gBAAgB;KAAE,KAAK,QAAQ;IAAE,CAAC;GAC7D;;;;;GAMA,UAAgB;IACd,IAAI,KAAK,UAAU;IACnB,KAAK,WAAW;IAChB,KAAK,YAAY;IACjB,KAAK,UAAU,MAAM;GACvB;;GAGA,KAAQ,SAAoC;IAC1C,MAAM,QAAQ,oBAAoB,QAAQ,CAAC;IAC3C,KAAK,UAAU,UAAU;KAAE,MAAM,IAAI,QAAQ,CAAC;IAAE,CAAC;IACjD,OAAO;GACT;;GAGA,QAAmB;IACjB,MAAM,WAAW,KAAK,MAAM,YAAY;IACxC,MAAM,OAAO,KAAK,KAAK;IACvB,OAAO;KACL,WAAW,SAAS,WAAW;KAC/B,SAAS,SAAS,WAAW;KAC7B,UAAU,SAAS;KACnB,OAAO,KAAK,SAAS;KACrB,SAAS,KAAK,MAAK,SAAQ,KAAK,UAAU,KAAA,CAAS;KACnD,QAAQ,KAAK;KACb,QAAQ,KAAK;KACb,GAAG,KAAK,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,aAAa;IAC9E;GACF;;GAGA,MAAM,OAA2B;IAC/B,MAAM,OAAO,KAAK,OAAO,KAAK;IAC9B,MAAM,SAAS,KAAK,OAAO,IAAI,KAAK;IACpC,IAAI,WAAW,KAAA,GACb,OAAO;KAAE,MAAM,KAAK,OAAO,KAAK,aAAa,KAAK,CAAC;KAAG,YAAY,KAAK,OAAO,KAAK;KAAG,SAAS;IAAM;IAEvG,MAAM,QAAQ,OAAO,QAAQ,EAAE,MAAM,QAAiB,IAAI,KAAK,MAAM,OAAO,IAAI;IAChF,OAAO;KACL,MAAM,OAAO;KACb,YAAY,OAAO,SAAS;KAC5B,SAAS,UAAU,KAAA;IACrB;GACF;;GAGA,UAAuB;IACrB,OAAO;KACL,OAAO,OAAO,SAAS;MAAE,KAAK,MAAM,OAAO;OAAE;OAAM,OAAO;MAAM,CAAC;KAAE;KACnE,aAAa,UAAU;MACrB,KAAK,MAAM,OAAO;OAAE,MAAM,KAAK,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,UAAU,KAAK,CAAC;OAAG,OAAO;MAAK,CAAC;KAC3F;KACA,YAAY;MAAE,KAAU,KAAK;KAAE;KAC/B,eAAe;MACb,IAAI,KAAK,OAAO,SAAS,KAAK,CAAC,KAAK,QAAQ;MAC5C,KAAK,OAAO,MAAM;MAClB,KAAK,SAAS;MACd,KAAK,eAAe,KAAA;MACpB,KAAK,QAAQ;KACf;IACF;GACF;;;;;;;;;;;;;;;;;GAkBA,MAAM,OAAsB;IAC1B,MAAM,OAAO,KAAK,KAAK;IACvB,MAAM,QAAQ,KAAK,QAAQ,SAA0D,KAAK,UAAU,KAAA,CAAS;IAC7G,IAAI,KAAK,WAAW,KAAK,KAAK,UAAU,MAAM,WAAW,KAAK,QAAQ;IAItE,MAAM,0BAAU,IAAI,IAAoC;IACxD,KAAK,MAAM,QAAQ,MAAM,QAAQ,IAAI,KAAK,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,CAAC;IAC5E,KAAK,SAAS;IACd,KAAK,SAAS;IACd,KAAK,eAAe,KAAA;IACpB,KAAK,QAAQ;IAIb,MAAM,MAAgH,MAAM,KAAI,SAAQ,KAAK,GAAG,OAAO,QACnJ;KAAE,IAAI;KAAO,MAAM,CAAC,KAAK,KAAK;KAAG,OAAQ,KAAK,GAA4C;IAAM,IAChG;KAAE,IAAI;KAAS,MAAM,CAAC,KAAK,KAAK;IAAE,CAAC;IACvC,IAAI;IACJ,IAAI,WAAW;IACf,IAAI;KACF,WAAW,MAAM,KAAK,MAAM,OAAO,GAAG;IACxC,SAAS,OAAO;KACd,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IACtE;IAMA,MAAM,SAAS,YAAY,iBAAiB,KAAA,KAAa,MAAM,OAAM,SAAQ,KAAK,MAAM,CAAC;IACzF,KAAK,MAAM,CAAC,OAAO,WAAW,SAC5B,IAAI,UAAU,KAAK,OAAO,IAAI,KAAK,MAAM,QAAQ,KAAK,OAAO,OAAO,KAAK;IAE3E,KAAK,SAAS;IACd,KAAK,SAAS,CAAC;IAIf,KAAK,eAAe;IACpB,KAAK,QAAQ;GACf;;;;;;;;GASA,OAA+B;IAC7B,MAAM,OAAuB,CAAC;IAC9B,KAAK,MAAM,CAAC,OAAO,WAAW,KAAK,QAAQ;KACzC,MAAM,OAAO,KAAK,OAAO,KAAK;KAC9B,IAAI,OAAO,OAAO;MAChB,IAAI,KAAK,OAAO,KAAK,GAAG,KAAK,KAAK;OAAE;OAAO,IAAI;QAAE;QAAO,IAAI;OAAQ;OAAG,aAAa,KAAK,YAAY,KAAK;MAAE,CAAC;MAC7G;KACF;KACA,IAAI,OAAO,SAAS,KAAK,OAAO,KAAK,aAAa,KAAK,CAAC,GAAG;KAC3D,MAAM,QAAQ,KAAK,MAAM,OAAO,IAAI;KACpC,IAAI,UAAU,KAAA,GAAW,KAAK,KAAK;MAAE;MAAO,IAAI;OAAE;OAAO,IAAI;MAAQ;MAAG,OAAO,KAAA;KAAU,CAAC;UACrF,IAAI,MAAM,SAAS,SAAS,KAAK,KAAK;MAAE;MAAO,IAAI;OAAE;OAAO,IAAI;MAAQ;MAAG,aAAa,KAAK,YAAY,KAAK;KAAE,CAAC;UACjH,KAAK,KAAK;MAAE;MAAO,IAAI;OAAE;OAAO,IAAI;OAAO,OAAO,MAAM;MAAM;MAAG,aAAa,KAAK,UAAU,OAAO,MAAM,KAAK;KAAE,CAAC;IACzH;IACA,OAAO;GACT;;;;;GAMA,UAAkB,OAAe,OAAyB;IAMxD,IAAI,KAAK,OAAO,KAAK,CAAC,CAAC,QAAQ,OAAO;IACtC,OAAO,KAAK,UAAU,CAAC,GAAG,WAAW;GACvC;;;;;GAMA,YAAoB,OAAwB;IAC1C,OAAO,CAAC,KAAK,OAAO,KAAK;GAC3B;GAEA,MAAc,OAAe,MAAwB;IACnD,KAAK,OAAO,IAAI,OAAO,IAAI;IAC3B,KAAK,SAAS;IACd,KAAK,eAAe,KAAA;IACpB,KAAK,QAAQ;GACf;GAEA,OAAe,OAA0B;IACvC,MAAM,OAAO,KAAK,MAAM,IAAI,KAAK;IAGjC,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,8BAA8B,OAAO;IAC7E,OAAO;GACT;GAEA,aAA4C;IAC1C,OAAO,KAAK,MAAM,YAAY;GAChC;GAEA,aAAqB,OAAwB;IAC3C,OAAQ,KAAK,WAAW,CAAC,CAAC,QAAgD;GAC5E;GAEA,UAAkB,OAAwB;IACxC,OAAQ,KAAK,WAAW,CAAC,CAAC,OAA+C;GAC3E;GAEA,YAAyD;IACvD,OAAO,KAAK,WAAW,CAAC,CAAC;GAC3B;GAEA,OAAe,OAAwB;IACrC,MAAM,OAAO,KAAK,UAAU;IAC5B,OAAO,SAAS,KAAA,KAAa,OAAO,OAAO,MAAM,KAAK;GACxD;GAEA,UAAwB;IACtB,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS;GAClD;EACF;;;;ECzaA,MAAM,wBAA2C,MAAM,KACrD,EAAE,QAAA,EAAkD,IACnD,GAAG,UAAU,OAAA,IAA2B,KAAK,CAChD;;;;;;;EAQA,SAAS,oBAA+B;GACtC,OAAO;IACL,OAAO;IACP,SAAQ,UAAS,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK,IAAI;IACxF,QAAQ,SAAS;KACf,MAAM,UAAU,KAAK,KAAK;KAC1B,IAAI,YAAY,IAAI,OAAO,EAAE,MAAM,QAAQ;KAC3C,OAAO,sBAAsB,SAAS,OAAO,IAAI;MAAE,MAAM;MAAO,OAAO,OAAO,OAAO;KAAE,IAAI,KAAA;IAC7F;GACF;EACF;;EAmCA,IAAa,kCAAb,MAA6C;GAC3C;GACA;;GAGA,YAAY,OAAsC;IAChD,KAAK,OAAO,IAAI,SAAS,OAAO;KAC9B,aAAa,SAAS;KACtB,aAAa,iBAAiB;KAC9B,aAAa,kBAAkB;KAC/B,kBAAkB;IACpB,CAAC;IACD,KAAK,QAAQ,KAAK,KAAK,WAAW,KAAK,WAAW,CAAC;GACrD;GAEA,aAAiD;IAC/C,OAAO;KACL,GAAG,KAAK,KAAK,MAAM;KACnB,SAAS,KAAK,KAAK,MAAM,SAAS;KAClC,iBAAiB,KAAK,KAAK,MAAM,iBAAiB;KAClD,kBAAkB,KAAK,KAAK,MAAM,kBAAkB;KACpD,iBAAiB,KAAK,KAAK,MAAM,iBAAiB;IACpD;GACF;;;;;GAMA,SAAoC;IAClC,OAAO;KAAE,OAAO,EAAE,uBAAuB,KAAK,MAAM;KAAG,GAAG,KAAK,KAAK,QAAQ;IAAE;GAChF;;;;;GAMA,UAAgB;IACd,KAAK,KAAK,QAAQ;GACpB;EACF;;;;;;EAaA,SAAgB,sBAAsB,OAAmC;GACvE,MAAM,EAAE,MAAM;GACd,MAAM,QAAQ,MAAM,0BAAyB,aAAY,QAAQ;GACjE,MAAM,WAAW,CAAC,MAAM;GACxB,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAyD;GACvE,CAAA,GAAA,MAAA,UAAA,OAAgB;IAId,IAAI,OAAO;IACX,MAAM,SAAS,IAAI,YAAY,uBAAuB;IACtD,OAAO,aAAa,YAAwC;KAC1D,IAAI;MACF,MAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI;MACrC,IAAI,MAAM,UAAU,KAAA,KAAa,MAAM,SAAS,MAAM,KAAK;KAC7D,QAAQ,CAER;IACF;IACA,aAAa;KAAE,OAAO;KAAO,OAAO,MAAM;IAAE;GAC9C,GAAG,CAAC,CAAC;GACL,MAAM,aAAa;IACjB,iBAAiB,EAAE,qBAAqB;IACxC,YAAY,EAAE,gBAAgB;IAC9B,cAAc,EAAE,wBAAwB;IACxC;GACF;GACA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,oBAAD;IACK;IACH,UAAS;IACT,gBAAe;IACf,aAAa;IACN;IACP,8BAAA;IACA,sBAAA;IACA,QAAQ,MAAM;IACd,WAAW,MAAM;cATnB;KAWE,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MACE,IAAG;MACH,OAAO,EAAE,kBAAkB;MAC3B,MAAM,EAAE,sBAAsB;MAC9B,cAAc,EAAE,kBAAkB;MAClC,SAAS,EAAE,aAAa;MACxB,UAAU,EAAE,cAAc;MAC1B,GAAI;MACJ,GAAI,MAAM;MACV,SAAS,SAAS;OAAE,MAAM,KAAK,WAAW,IAAI;MAAE;MAChD,eAAe;OAAE,MAAM,WAAW,SAAS;MAAE;KAC9C,CAAA;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MACE,IAAG;MACH,OAAO,EAAE,0BAA0B;MACnC,MAAM,EAAE,8BAA8B;MACtC,cAAc,EAAE,kBAAkB;MAClC,SAAS,EAAE,aAAa;MACxB,UAAU,EAAE,cAAc;MAC1B,GAAI;MACJ,GAAI,MAAM;MACV,SAAS,SAAS;OAAE,MAAM,KAAK,mBAAmB,IAAI;MAAE;MACxD,eAAe;OAAE,MAAM,WAAW,iBAAiB;MAAE;KACtD,CAAA;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;MACE,IAAG;MACH,OAAO,EAAE,2BAA2B;MACpC,MAAM,EAAE,+BAA+B;MACvC,cAAc,EAAE,kBAAkB;MAClC,SAAS,EAAE,aAAa;MACxB,UAAU,EAAE,cAAc;MAC1B,GAAI;MACJ,GAAI,MAAM;MACV,SAAS,SAAS;OAAE,MAAM,KAAK,oBAAoB,IAAI;MAAE;MACzD,eAAe;OAAE,MAAM,WAAW,kBAAkB;MAAE;KACvD,CAAA;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;MACE,IAAG;MACH,OAAO,EAAE,0BAA0B;MACnC,MAAM,EAAE,8BAA8B;MACtC,cAAc,EAAE,kBAAkB;MAClC,SAAS,sBAAsB,KAAI,WAAU;OAC3C;OACA,OAAO,EAAE,kCAAkC,EAAE,OAAO,MAAM,CAAC;MAC7D,EAAE;MACF,GAAI;MACJ,GAAI,MAAM;MACV,SAAS,SAAS;OAAE,MAAM,KAAK,mBAAmB,IAAI;MAAE;MACxD,eAAe;OAAE,MAAM,WAAW,iBAAiB;MAAE;KACtD,CAAA;KACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD,EAAA,UACG,EAAE,wBAAwB;MACzB,UAAU,OAAO,YAAY,EAAE,uBAAuB;MACtD,OAAO,OAAO,SAAS,EAAE,uBAAuB;MAChD,SAAS,OAAO,OAAO,mBAAmB,CAAC;MAC3C,WAAW,OAAO,OAAO,kBAAkB,CAAC;KAC9C,CAAC,EACA,CAAA;KACH,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD,EAAA,UAAI,EAAE,wBAAwB,EAAK,CAAA;KAClC,OAAO,cAAc,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD,EAAA,UAAI,EAAE,uBAAuB,EAAE,OAAO,MAAM,UAAU,CAAC,EAAK,CAAA;IAC7E;;EAExB;;;ECtNA,MAAa,wBAAwB;;EA6ErC,SAAgB,iBAAiB,OAA8C;GAC7E,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;GACxD,MAAM,SAAS;GACf,OAAO,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,gBAAgB,YAAY,OAAO,OAAO,WAAW;EAChH;;;;;;;;;;;ECxEA,MAAM,oBAAoB,sBAAsB,MAAM,CAAC;EAEvD,MAAM,gBAAgB;EACtB,MAAM,aAAa;EACnB,MAAM,qBAAqB;EAC3B,MAAM,qBAAqB;;EAE3B,MAAM,yBAAyB;;EAE/B,MAAM,6BAA6B;;EAYnC,IAAa,eAAb,cAAkC,MAAM;GACjB;GAAmD;GAAxE,YAAY,SAAkC,SAAiB,QAA0B;IACvF,MAAM,OAAO;IADM,KAAA,UAAA;IAAmD,KAAA,SAAA;IAEtE,KAAK,OAAO;GACd;EACF;EAEA,SAAS,OAAe;GACtB,OAAO,WAAW,QAAQ,aAAa,KAAK,WAAW,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;EACtH;;;;;;EAOA,eAAe,SAAY,UAAgC;GACzD,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,IAAI;GACJ,IAAI,WAAW;GACf,IAAI,KAAK,KAAK,MAAM,IAClB,IAAI;IACF,SAAS,KAAK,MAAM,IAAI;IACxB,WAAW;GACb,QAAQ;IACN,WAAW;GACb;GAEF,MAAM,YAAY,YAAY,OAAO,WAAW,YAAY,WAAW,QAAQ,OAAQ,OAA+B,UAAU,WAC3H,OAA6B,QAC9B,KAAA;GACJ,IAAI,SAAS,IAAI;IACf,IAAI,CAAC,UAAU,MAAM,IAAI,aAAa,cAAc,EAAE,8BAA8B,EAAE,QAAQ,OAAO,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,MAAM;IACzI,OAAO;GACT;GACA,IAAI,cAAc,KAAA,GAAW;IAI3B,IAAI,cAAc,aAAa,MAAM,IAAI,aAAa,gBAAgB,EAAE,8BAA8B,GAAG,SAAS,MAAM;IACxH,IAAI,SAAS,WAAW,OAAO,QAAQ,KAAK,SAAS,GACnD,MAAM,IAAI,aAAa,UAAU,EAAE,0BAA0B,EAAE,QAAQ,UAAU,CAAC,GAAG,SAAS,MAAM;IAEtG,MAAM,IAAI,aAAa,YAAY,WAAW,SAAS,MAAM;GAC/D;GACA,IAAI,SAAS,WAAW,KAAK,MAAM,IAAI,aAAa,eAAe,EAAE,4BAA4B,GAAG,GAAG;GACvG,IAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,aAAa,gBAAgB,EAAE,8BAA8B,GAAG,SAAS,MAAM;GACjJ,MAAM,IAAI,aAAa,cAAc,EAAE,8BAA8B,EAAE,QAAQ,OAAO,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,MAAM;EAC5H;EAWA,IAAa,6BAAb,MAA0E;GAC3C;GAA7B,YAAY,UAA6E,WAAW,cAAc;IAArF,KAAA,UAAA;GAAsF;GAEnH,MAAM,UAAU,QAA2D;IACzE,MAAM,UAAU,MAAM,KAAK,MAAM;IACjC,MAAM,WAAW,QAAQ,UAAU;IACnC,IAAI,OAAO,SAAS,KAAK,aAAa,KAAA,KAAa,KAAK,SAAS,QAAQ,aAAa,MAAM,UAAU;KACpG,IAAI,WAAW,KAAK,SAAS,QAAQ,UAAU;KAC/C,IAAI,aAAa,QAAQ,aAAa,KAAA,KAAa,aAAa,IAAI;MAClE,WAAW,KAAK;MAChB,KAAK,SAAS,QAAQ,YAAY,QAAQ;KAC5C;KACA,IAAI,YAAY,KAAK,SAAS,QAAQ,kBAAkB;KACxD,IAAI,cAAc,QAAQ,cAAc,KAAA,KAAa,cAAc,IAAI;MACrE,YAAY,KAAK;MACjB,KAAK,SAAS,QAAQ,oBAAoB,SAAS;KACrD;KACA,MAAM,WAAW,MAAM,KAAK,KAAK,WAAW;MAAE,MAAM;MAAU;MAAU,OAAO,CAAC,GAAG,MAAM;KAAE,CAAC;KAC5F,KAAK,SAAS,QAAQ,eAAe,SAAS,UAAU,YAAY,QAAQ;KAC5E,OAAO;IACT;IACA,OAAO;GACT;GAEA,MAAM,QAAoC;IACxC,OAAO,MAAM,KAAK,QAAQ,GAAG,kBAAkB,SAAS,EAAE,OAAO,WAAW,CAAC;GAC/E;GAEA,MAAM,OAAO,QAAyB,WAAgD;IACpF,OAAO,MAAM,KAAK,KAAK,KAAK,GAAG,QAAQ,SAAS;GAClD;GAEA,MAAc,KAAK,WAAmB,QAAyB,WAAgD;IAC7G,MAAM,WAAoC;KAAE;KAAW;KAAQ,GAAI,cAAc,KAAA,KAAa,cAAc,KAAK,CAAC,IAAI,EAAE,UAAU;IAAG;IACrI,OAAO,MAAM,KAAK,QAAQ,GAAG,kBAAkB,UAAU;KACvD,QAAQ;KACR,SAAS,EAAE,gBAAgB,mBAAmB;KAC9C,MAAM,KAAK,UAAU,QAAQ;IAC/B,CAAC;GACH;GAEA,MAAc,QAAQ,KAAa,MAA+C;IAChF,MAAM,aAAa,IAAI,gBAAgB;IACvC,MAAM,UAAU,WAAW,iBAAiB;KAAE,WAAW,MAAM;IAAE,GAAG,kBAAkB;IACtF,IAAI;KACF,OAAO,MAAM,SAA4B,MAAM,MAAM,KAAK;MAAE,GAAG;MAAM,QAAQ,WAAW;KAAO,CAAC,CAAC;IACnG,SAAS,OAAO;KACd,IAAI,iBAAiB,cAAc,MAAM;KACzC,IAAI,WAAW,OAAO,SAAS,MAAM,IAAI,aAAa,WAAW,EAAE,2BAA2B,EAAE,SAAS,OAAO,qBAAqB,GAAK,EAAE,CAAC,CAAC;KAG9I,MAAM,IAAI,aAAa,eAAe,EAAE,6BAA6B,CAAC;IACxE,UAAU;KACR,WAAW,aAAa,OAAO;IACjC;GACF;;;;;;GAOA,MAAM,WAAW,SAAgC,QAAoD;IACnG,IAAI;IACJ,IAAI;KACF,WAAW,MAAM,MAAM,GAAG,kBAAkB,SAAS;MACnD,QAAQ;MACR,SAAS,EAAE,gBAAgB,mBAAmB;MAC9C,MAAM,KAAK,UAAU,OAAO;MAC5B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;KAC3C,CAAC;IACH,QAAQ;KAGN,MAAM,IAAI,aAAa,eAAe,EAAE,6BAA6B,CAAC;IACxE;IACA,MAAM,OAAO,MAAM,SAAS,KAAK;IACjC,IAAI;IACJ,IAAI,WAAW;IACf,IAAI,KAAK,KAAK,MAAM,IAClB,IAAI;KACF,SAAS,KAAK,MAAM,IAAI;KACxB,WAAW;IACb,QAAQ;KACN,WAAW;IACb;IAEF,MAAM,SAAS,YAAY,OAAO,WAAW,YAAY,WAAW,OAChE,SACA,KAAA;IACJ,IAAI,SAAS,IAAI;KACf,IAAI,WAAW,KAAA,KAAa,iBAAiB,OAAO,KAAK,GAAG,OAAO,OAAO;KAC1E,MAAM,IAAI,aAAa,cAAc,EAAE,qBAAqB,EAAE,OAAO,EAAE,8BAA8B,EAAE,QAAQ,OAAO,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,MAAM;IAC/J;IACA,IAAI,SAAS,WAAW,KAAK,MAAM,IAAI,aAAa,eAAe,EAAE,wBAAwB,GAAG,GAAG;IACnG,IAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,aAAa,gBAAgB,EAAE,8BAA8B,GAAG,SAAS,MAAM;IACjJ,MAAM,OAAO,OAAO,QAAQ,SAAS,WAAW,OAAO,OAAO,KAAA;IAC9D,IAAI,SAAS,YAAY,MAAM,IAAI,aAAa,YAAY,EAAE,oBAAoB,GAAG,SAAS,MAAM;IACpG,IAAI,SAAS,WAAW,MAAM,IAAI,aAAa,WAAW,EAAE,sBAAsB,EAAE,SAAS,OAAO,0BAA0B,EAAE,CAAC,GAAG,SAAS,MAAM;IAEnJ,MAAM,IAAI,aAAa,YAAY,EAAE,qBAAqB,EAAE,OAD7C,OAAO,QAAQ,UAAU,YAAY,OAAO,UAAU,KAAK,OAAO,QAAQ,OAAO,SAAS,MAAM,EACrC,CAAC,GAAG,SAAS,MAAM;GAC/F;GAEA,UAAU,UAA+D;IACvE,MAAM,SAAS,IAAI,YAAY,GAAG,kBAAkB,QAAQ;IAC5D,IAAI,wBAAwB;IAC5B,OAAO,aAAa,YAAwC;KAC1D,IAAI;MACF,MAAM,SAAS,KAAK,MAAM,QAAQ,IAAI;MACtC,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,OAAO,OAAO,aAAa,UAAU,MAAM,IAAI,MAAM,qBAAqB;MAC/H,SAAS,MAAM;KACjB,QAAQ;MACN,SAAS;KACX;IACF;IAIA,OAAO,gBAAsB;KAC3B,MAAM,MAAM,KAAK,IAAI;KACrB,IAAI,MAAM,wBAAwB,wBAAwB;KAC1D,wBAAwB;KACxB,SAAS;IACX;IACA,MAAM,kBAAwB;KAAE,IAAI,SAAS,oBAAoB,WAAW,SAAS;IAAE;IACvF,SAAS,iBAAiB,oBAAoB,SAAS;IACvD,aAAa;KACX,SAAS,oBAAoB,oBAAoB,SAAS;KAC1D,OAAO,MAAM;IACf;GACF;EACF;;;EChNA,MAAM,cAAc;EACpB,MAAM,iBAAiB;EACvB,MAAM,WAAW;;EAOjB,SAAS,eAAmC;GAC1C,IAAI;IACF,OAAA;GAGF,QAAQ;IACN;GACF;EACF;;EAGA,SAAS,YAA2B;GAClC,IAAI;IACF,MAAM,WAAW,aAAa,QAAQ,WAAW;IACjD,IAAI,YAAY,yBAAyB,KAAK,QAAQ,GAAG,OAAO;IAChE,MAAM,QAAQ,OAAO,WAAW,CAAC,CAAC,WAAW,KAAK,EAAE;IACpD,aAAa,QAAQ,aAAa,KAAK;IACvC,OAAO;GACT,QAAQ;IAEN,OAAO;GACT;EACF;;EAGA,SAAS,aAAa,OAAqB;GACzC,IAAI;IACF,KAAK,IAAI,QAAQ,aAAa,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;KAChE,MAAM,MAAM,aAAa,IAAI,KAAK;KAClC,IAAI,QAAQ,QAAQ,IAAI,WAAW,cAAc,KAAK,QAAQ,iBAAiB,OAC7E,aAAa,WAAW,GAAG;IAE/B;GACF,QAAQ,CAAoB;EAC9B;;;;;;EAOA,SAAgB,qBAAqB,OAAuC;GAC1E,IAAI;IACF,IAAI,MAAM,WAAW,GAAG;IACxB,MAAM,yBAAQ,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;IAGlD,IAAI,UAAU,WAAW;IACzB,IAAI,aAAa,QAAQ,iBAAiB,KAAK,MAAM,MAAM;IAC3D,MAAM,UAAU,UAAU;IAC1B,IAAI,YAAY,MAAM;IACtB,aAAa,KAAK;IAClB,MAAM,eAAe,MAAM,KAAK,SAAS;KACvC,MAAM,MAA8B,EAAE,MAAM,KAAK,KAAK;KACtD,MAAM,UAAU,KAAK,WAAW,aAAa;KAC7C,IAAI,YAAY,KAAA,GAAW,IAAI,UAAU;KACzC,IAAI,KAAK,YAAY,KAAA,GAAW,IAAI,UAAU,KAAK;KACnD,OAAO;IACT,CAAC;IACD,MAAM,OAAO,KAAK,UAAU;KAAE,MAAM;KAAa;KAAS,OAAO;IAAa,CAAC;IAC/E,MAAW,UAAU;KACnB,QAAQ;KACR,SAAS,EAAE,gBAAgB,mBAAmB;KAC9C;KACA,WAAW;IACb,CAAC,CAAC,CAAC,MAAM,aAAa;KAGpB,IAAI,SAAS,IAAI,aAAa,QAAQ,iBAAiB,OAAO,GAAG;IACnE,CAAC,CAAC,CAAC,YAAY,CAA0C,CAAC;GAC5D,QAAQ,CAA+C;EACzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC9DA,MAAa,0BAA0B;;EAGvC,MAAa,4BAA4B;;EAGzC,MAAa,uBAAuB;;;;;;EAuDpC,SAAgB,kBAAkB,KAAiC;GACjE,MAAM,MAAM,IAAI;GAChB,IAAI,OAAO,QAAQ,YAAY,OAAO;GACtC,IAAI;IACF,OAAO,IAAI,KAAK,KAAK,oBAAoB,MAAM,KAAA;GACjD,QAAQ;IAGN,OAAO;GACT;EACF;;EAGA,SAAS,gBAAgB,MAAc,OAAsB;GAC3D,IAAI;IACF,QAAQ,KAAK,4CAA4C,KAAK,0CAA0C,KAAK;GAC/G,QAAQ,CAER;EACF;;;;;;;;EASA,SAAgB,kBAAkB,KAAwB,MAA4B;GACpF,MAAM,QAAQ,IAAI;GAClB,MAAM,YAAY,KAAK;GACvB,MAAM,SAAS,KAAK;GAEpB,IAAI;GACJ,IAAI;;;;;;;GAOJ,IAAI,cAAc;;GAGlB,MAAM,kBAAwB;IAC5B,IAAI,aAAa;IACjB,MAAM,SAAS,kBAAkB,GAAG,IAAI,0BAA0B;IAClE,IAAI,YAAY,QAAQ;IACxB,cAAc;IACd,MAAM,WAAW;IACjB,UAAU,KAAA;IACV,UAAU,KAAA;IACV,WAAW;IACX,IAAI;KACF,UAAU,MAAM,SAAU,WAAA,uBACtB;MACA,MAAM;MACN,IAAI,KAAK;MACT,GAAI,KAAK,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;MACxD,GAAI,KAAK,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;MACxD,QAAQ,KAAK;MACb,GAAI,KAAK,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;KAChD,IACE;MACA,MAAM;MACN,KAAK,KAAK;MACV,QAAQ,KAAK;MACb,GAAI,KAAK,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;KAChD,GAAa,SAAS;KACxB,UAAU;IACZ,SAAS,OAAO;KACd,gBAAgB,QAAQ,KAAK;IAC/B,UAAU;KACR,cAAc;IAChB;GACF;GAEA,IAAI,OAAO,IAAI,OAAO,YACpB,IAAI;IACF,IAAI,GAAG,uBAAuB;KAAE,UAAU;IAAE,CAAC;GAC/C,QAAQ,CAGR;GAIF,UAAU;EACZ;;;;ECxJA,MAAM,KAAK;;EAGX,MAAM,gBAAgB;;;;;;;EAQtB,MAAM,qBAAqB;;;;;;;EAQ3B,MAAM,uBAA0C;GAAC;GAAoB;GAAiB;EAAa;;;;;;;;;EAoEnG,MAAa,SAAS;GAAC;GAAS;GAAY;GAAc;GAAc;GAAe;GAAU;GAAU;GAAkB;EAAa;;;;;EAsD1I,SAAgB,MAAM,KAA0B;GAG9C,qBAAqB,CAAC,EAAE,MAAM,sCAAsC,CAAC,CAAC;GAKtE,IAAI,CAAC,oBAAoB,GAAG;GAK5B,IAAI,aAAa,uBAAuB,yBAAyB;GAEjE,IAAI,aAAa;IACf,IAAI;KACF,OAAO,IAAI,OAAO,SAAS,IAAI;MAAE;MAAI;KAAG,CAAC;IAC3C,QAAQ;KACN,aAAa,CAAC;IAChB;GACF,GAAG,0BAA0B;GAM7B,IAAI;IAAE,oBAAoB,IAAI,OAAO,KAAK,EAAE,CAAC;GAAE,QAAQ,CAAyD;GAKhH,MAAM,eAAe,iBAAiB,GAAG;GACzC,MAAM,eAAe,IAAI,gCAAgC,YAAY;GACrE,kBAAkB,KAAK;IACrB,QAAQ;IACR,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,cAAc,aAAa,OAAO;IAClC,WAAW;GACb,CAAC;GACD,IAAI,mBAAmB;IAAE,aAAa,QAAQ;GAAE,GAAG,2BAA2B;GAM9E,IAAI;GACJ,MAAM,gBAAsB;IAC1B,IAAI,eAAe,KAAA,GAAW;IAI9B,MAAM,WAAW,IAAI,IAAI,UAAU;IACnC,MAAM,aAAa,IAAI,IAAI,YAAY;IACvC,MAAM,SAAS,IAAI,IAAI,QAAQ;IAI/B,MAAM,aAAa,IAAI,gBAAgB;KACrC,OAAA,IAFgB,sBAEZ;KACJ,WAAW,IAAI,2BAA2B;KAC1C,UAAU;MAIR,eAAe,kBAAkB,SAAS,KAAK,YAAY,CAAC,CAAC,IAAI;MACjE,OAAM,OAAM,IAAI,YAAY,YAAY,EAAW;MACnD,YAAW,OAAM,SAAS,KAAK,UAAU,EAAE;KAC7C;IACF,CAAC;IACD,WAAW,MAAM;IAEjB,MAAM,YAA+B,CAAC;IAOtC,MAAM,6BAAmC;KACvC,MAAM,WAAW,WAAW,KAAK,YAAY;KAC7C,WAAW,oBAAoB,EAC7B,YAAY,SAAS,MAAM,KAAI,UAAS;MACtC,aAAa,KAAK;MAClB,OAAO,KAAK,UAAU,KAAK,KAAK,QAAQ,KAAK;KAC/C,EAAE,EACJ,CAAC;IACH;IACA,qBAAqB;IACrB,UAAU,KAAK,WAAW,KAAK,UAAU,oBAAoB,CAAC;IAI9D,WAAW,oBAAoB,OAAM,SAAQ;KAE3C,OAAO,EAAE,cAAa,MADA,WAAW,OAAO,EAAE,KAAK,CAAC,EAAA,CAClB,YAAY;IAC5C,CAAC;IAoBD,MAAM,mBAAmB,YAA2B;KAClD,IAAI;MACF,IAAI,SAAkE,CAAC;MACvE,IAAI;MACJ,IAAI;OACF,gBAAiB,OAAiC;MACpD,QAAQ;OACN,gBAAgB,KAAA;MAClB;MACA,IAAI,OAAO,eAAe,iBAAiB,YAAY;OACrD,MAAM,MAAM,MAAM,cAAc,aAAa;OAC7C,IAAI,IAAI,MAAM,MAAM,QAAQ,IAAI,OAAO,MAAM,GAC3C,KAAK,MAAM,KAAK,IAAI,MAAM,QAAQ;QAChC,MAAM,WAAY,EAAyC,MAAO,EAAyC;QAC3G,KAAK,MAAM,KAAK,EAAE,UAAU,CAAC,GAAG;SAC9B,MAAM,cAAc,WAAW,GAAG,SAAS,GAAG,EAAE,OAAO,EAAE;SACzD,OAAO,KAAK;UAAE,IAAI;UAAa,MAAM,EAAE,QAAQ,EAAE;UAAI;SAAS,CAAC;QACjE;OACF;MAEJ;MACA,IAAI,OAAO,WAAW,GAAG;OACvB,MAAM,OAAO,IAAI,IAAI,YAAY;OAOjC,IAAI,MAAM,KAAK;QACb,IAAI,OAAO,KAAK,IAAI,KAAK,mBAAmB,YAAY;SAEtD,MAAM,QAAO,MADK,KAAK,IAAI,IAAI,eAAe,EAAA,EAC5B,QAAQ,OAAO;SACjC,IAAI,MAAM,QAAQ,IAAI,GACpB,SAAS,KAAK,KAAI,OAAM;UAAE,IAAI,EAAE;UAAI,MAAM,EAAE;SAAK,EAAE;QAEvD;QACA,MAAM,YAAY,OAAO,KAAK,IAAI,SAAS,iBAAiB,aACxD,KAAK,IAAI,QAAQ,eACjB,OAAO,KAAK,IAAI,UAAU,iBAAiB,aACzC,KAAK,IAAI,SAAS,eAClB,KAAA;QACN,IAAI,OAAO,WAAW,KAAK,cAAc,KAAA,GAAW;SAElD,MAAM,UAAS,MADG,UAAU,EAAA,EACR,QAAQ,OAAO;SACnC,IAAI,MAAM,QAAQ,MAAM,GACtB,KAAK,MAAM,KAAK,QAAQ;UACtB,MAAM,WAAW,EAAE,MAAM,EAAE;UAC3B,KAAK,MAAM,KAAK,EAAE,UAAU,CAAC,GAAG;WAC9B,MAAM,cAAc,WAAW,GAAG,SAAS,GAAG,EAAE,OAAO,EAAE;WACzD,OAAO,KAAK;YAAE,IAAI;YAAa,MAAM,EAAE,QAAQ,EAAE;YAAI;WAAS,CAAC;UACjE;SACF;QAEJ;OACF;MACF;MACA,IAAI,OAAO,SAAS,GAClB,WAAW,oBAAoB,EAAE,OAAO,CAAC;KAE7C,SAAS,OAAO;MACd,QAAQ,MAAM,8CAA8C,KAAK;KACnE;IACF;IACA,iBAAsB;IACtB,UAAU,KAAK,IAAI,GAAG,0BAA0B;KAAE,iBAAsB;IAAE,CAAC,CAAC;IAC5E,IAAI;KACF,UAAU,KAAK,kBAAkB,YAAY,IAAI,MAAM,CAAC;KACxD,UAAU,KAAK,WAAW,YAAY,IAAI,MAAM,CAAC;IACnD,SAAS,OAAO;KAEd,QAAQ,MAAM,kCAAkC,KAAK;IACvD;IAEA,mBAAmB;KACjB,KAAK,MAAM,WAAW,UAAU,OAAO,CAAC,GAAG,QAAQ;KACnD,WAAW,QAAQ;KACnB,aAAa,KAAA;IACf;GACF;GACA,MAAM,oBAA0B;IAC9B,MAAM,WAAW,aAAa,YAAY;IAI1C,IAHgB,SAAS,WAAW,UAChC,SAAS,OAAO,WAAW,OAC3B,SAAS,WAAW,eACX,QAAQ;SAChB,aAAa;GACpB;GACA,MAAM,sBAAsB,aAAa,UAAU,WAAW;GAO9D,IAAI,mBAAmB;IACrB,oBAAoB;IACpB,aAAa;GACf,GAAG,0BAA0B;GAC7B,YAAY;EACd;;;;;;;;;;;;;EAcA,SAAgB,iBAAiB,KAAmD;GAClF,MAAM,SAAS,IAAI,IAAI,eAAe;GACtC,IAAI,WAAW,KAAA,KAAa,OAAO,OAAO,SAAS,YACjD,OAAO,OAAO,KAAwB,EAAE,WAAW,cAAc,CAAC;GAEpE,OAAO,IAAI,YAAY,IAAuB,cAAc,IAAI,WAAW,CAAC;EAC9E;;;;;;;;;;;;;EAcA,SAAS,cAAc,OAA4B;GACjD,IAAI;GACJ,IAAI;IACF,SAAS,MAAM,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,WAAW,KAAI,SAAQ,KAAK,EAAE;GAC9E,QAAQ;IACN,SAAS,KAAA;GACX;GACA,IAAI,WAAW,KAAA,GAAW,OAAO;GACjC,OAAO,qBAAqB,MAAK,OAAM,OAAO,SAAS,EAAE,CAAC,KAAK;EACjE"}
|