@linxin666/dsh-client-ui-task-board 0.3.12 → 0.3.14
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/lib/client.js +68 -43
- package/lib/client.js.map +1 -1
- package/lib/types/client/board-mount.d.ts +10 -0
- package/lib/types/client/panel-mount-core.d.ts +56 -0
- package/package.json +19 -19
- package/src/client/board-mount.tsx +22 -104
- package/src/client/panel-mount-core.ts +147 -0
- package/src/client/settings-card.module.css +14 -8
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/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/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/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/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/** 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 * 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 * 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/** Statuses a settled task may be archived from. */\nexport const ARCHIVABLE_STATUSES: readonly TaskStatus[] = ['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 /**\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\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 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 ...(input.freeze === undefined ? {} : { freeze: freezeOf(input.freeze, now) }),\n ...(input.handover === undefined ? {} : { handover: { ...input.handover, bundledAt: now } }),\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 settled (done/failed) task off the\n * main board and back. 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 settled statuses (done/failed) can be archived;\n * a running or not-yet-settled task stays on the board (its runner still\n * owns its lifecycle). Archiving disarms a schedule; already-archived tasks\n * are 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 high = Number(range)\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, normalizeTargetId, type TaskRecord, type TaskPermission } 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'>> & {\n freeze?: FreezeSnapshot & { redacted?: boolean } | null\n /** Replaces the handover bundle (restamping bundledAt); an explicit null clears it. */\n handover?: TaskHandoverInput | 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, ...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 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 // 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 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 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 { TaskBoardAction, TaskBoardEventPayload, TaskBoardSnapshot } 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\n/** The sessions face the controller needs for navigation awareness. */\nexport interface SessionsControllerFace {\n list: {\n getSnapshot(): { current: string | undefined }\n subscribe(fn: () => void): () => void\n }\n /** Select a session as current (navigates the conversation view). */\n open(id: string): void\n}\n\nfunction currentOf(sessions: SessionsControllerFace | undefined): string | undefined {\n return sessions?.list.getSnapshot().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/** 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/** The execution-target option sets the UI feeds into the controller. */\nexport interface ExecutionOptionsSnapshot {\n workspaces: readonly ExecutionWorkspaceOption[]\n presets: readonly ExecutionPresetOption[]\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 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: [] }\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.list.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.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 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 settled task (done/failed). Running or on-board-unsettled\n * tasks are refused so the runner keeps exclusive ownership of their\n * lifecycle.\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","/**\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, 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 (!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.freeze = normalizeFreeze(row.freeze)\n task.handover = normalizeHandover(row.handover)\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.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.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 'detail.permissionPending': '权限待确认:本卡有效权限({permission})高于会话默认,手动执行与定时调度都会被拒绝,需人工确认后才能运行。',\n 'detail.permissionConfirm': '确认权限绑定',\n 'detail.permissionConfirmed': '已确认权限绑定 · {time}',\n 'detail.title': '任务详情',\n 'detail.edit': '编辑',\n 'detail.close': '关闭',\n 'edit.title': '编辑任务',\n 'edit.save': '保存',\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 '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 '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.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.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 '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.close': 'Close',\n 'edit.title': 'Edit Task',\n 'edit.save': 'Save',\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 '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 '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 { t } from '../locales.ts'\nimport css from '../board.module.css'\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 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 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 <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 * 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, 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 { TASK_PERMISSIONS, type TaskPermission } from '../../core/tasks.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\nimport { ModalShell, TaskContentFields } from './TaskForm.tsx'\nimport css from '../board.module.css'\n\n/** New-task form overlay. */\nexport function NewTaskModal({ controller, onClose }: { controller: BoardController; onClose: () => void }) {\n const [title, setTitle] = useState('')\n const [description, setDescription] = useState('')\n const [prompt, setPrompt] = useState('')\n const [workspaceId, setWorkspaceId] = useState('')\n const [mode, setMode] = useState('')\n const [permission, setPermission] = useState('')\n const [scheduleEnabled, setScheduleEnabled] = useState(false)\n const [scheduleCron, setScheduleCron] = useState('')\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 const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n const [options, setOptions] = useState(controller.getSnapshot().executionOptions)\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 const submit = async (): 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 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 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 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 return (\n <ModalShell\n ariaLabel={t('board.new')}\n title={t('board.new')}\n error={error}\n pending={pending}\n submitLabel={t('new.submit')}\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 <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 <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 </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 } 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.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 type { TaskRecord } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport { ModalShell, TaskContentFields } 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 [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 if (await controller.updateTask(task.id, { title, description, prompt })) {\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 </ModalShell>\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, 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 } from './EditTaskModal.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 // 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 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 </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\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(() => { setShowEdit(false) }, [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.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 => (\n <li key={reference} 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 && (\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 </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, 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/** Case-insensitive title/description/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]\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 * 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 [showNew, setShowNew] = useState(false)\n const selected = selectedTaskOf(snapshot)\n const archiveView = snapshot.archiveView\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 && matchesFilter(task, filter),\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 <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 {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 && <div className={css.columnEmpty}>{t('archive.empty')}</div>}\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 && <div className={css.columnEmpty}>{t('board.empty')}</div>}\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 onClose={() => { setShowNew(false) }}\n />\n )}\n </div>\n )\n}\n","/**\n * Board view mounting.\n *\n * The `conversation` slot is single-occupant (ui-conversation) and external\n * plugins cannot declare slots, so the board takes over the center column at\n * the DOM level: a container is appended inside the center column\n * (`[class*=\"centerCol\"]`, the dsh 0.1.0-rc.6 AppFrame layout; previously\n * `[data-pane=\"conversation\"]` on older shells — the mount selector keeps both)\n * as an extra trailing child\n * React never manages, and a stylesheet\n * rule hides the conversation content while the board is active. Toggling is\n * a data attribute on <html> — no React involvement, so the conversation\n * subtree underneath stays mounted and stateful.\n */\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { BoardController } from '../core/controller.ts'\nimport { TaskBoard } from './board/TaskBoard.tsx'\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\nconst CONVERSATION_COLUMN_SELECTOR = '[data-pane=\"conversation\"], [class*=\"centerCol\"]'\nconst ACTIVE_ATTR = 'data-dsh-taskboard-active'\n/** The sibling panel's activation attribute (ssh), removed when this panel opens. */\nconst OTHER_ACTIVE_ATTR = 'data-dsh-ssh-active'\n/** Cross-plugin activation event; detail is the activating panel name. */\nconst ACTIVATE_EVENT = 'dsh-panel-activate'\nconst PANEL_NAME = 'taskboard'\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 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 let root: Root | undefined\n let container: HTMLDivElement | undefined\n let unsubscribeLocale: (() => void) | undefined\n try {\n unsubscribeLocale = locale?.subscribe(() => {\n if (root !== undefined) root.render(<TaskBoard controller={controller} />)\n })\n } catch { /* locale service absent: the board follows its next natural re-render */ }\n\n const ensure = (): void => {\n if (container !== undefined) {\n if (container.isConnected) return\n root?.unmount()\n root = undefined\n container.remove()\n container = undefined\n }\n const column = conversationColumn()\n if (column === undefined) return\n container = document.createElement('div')\n container.dataset.dshTaskboardView = ''\n container.dataset.dshPlugin = 'task-board'\n container.className = css.boardView\n column.appendChild(container)\n root = createRoot(container)\n root.render(<TaskBoard controller={controller} />)\n }\n\n // The frame mounts after boot settlement; watch for the column's arrival.\n const waitObserver = new MutationObserver(() => { ensure() })\n waitObserver.observe(document.body, { childList: true, subtree: true })\n\n const applyActive = (): void => {\n if (controller.getSnapshot().boardOpen) {\n // Single-occupant center column: opening this panel must evict the\n // sibling panel (ssh), both its html attribute and its controller\n // state, otherwise the two panels' visibility rules fight and the\n // second click appears dead.\n document.documentElement.removeAttribute(OTHER_ACTIVE_ATTR)\n document.documentElement.setAttribute(ACTIVE_ATTR, '')\n document.dispatchEvent(new CustomEvent(ACTIVATE_EVENT, { detail: PANEL_NAME }))\n } else {\n document.documentElement.removeAttribute(ACTIVE_ATTR)\n }\n }\n const onOtherActivate = (event: Event): void => {\n if ((event as CustomEvent).detail === 'ssh' && controller.getSnapshot().boardOpen) {\n controller.closeBoard()\n }\n }\n // Jump out on sidebar context clicks: clicking a session/workspace row\n // (including the already-current one, which produces no session-change\n // event) hands the center column back to the conversation. Capture phase,\n // so the panel closes before the shell processes the click.\n const SIDEBAR_ROW_SELECTOR = '[class*=\"sessionRow\"], [class*=\"projectRow\"], [class*=\"searchResultRow\"], [class*=\"searchResultWorkspace\"], [class*=\"newSession\"]'\n const onClickSidebarRow = (event: MouseEvent): void => {\n if (!controller.getSnapshot().boardOpen) return\n const target = event.target as HTMLElement | null\n if (target === null) return\n if (target.closest(SIDEBAR_ROW_SELECTOR) !== null) controller.closeBoard()\n }\n document.addEventListener('click', onClickSidebarRow, true)\n document.addEventListener(ACTIVATE_EVENT, onOtherActivate)\n const unsubscribe = controller.subscribe(applyActive)\n applyActive()\n ensure()\n\n return () => {\n document.removeEventListener('click', onClickSidebarRow, true)\n document.removeEventListener(ACTIVATE_EVENT, onOtherActivate)\n waitObserver.disconnect()\n unsubscribe()\n unsubscribeLocale?.()\n document.documentElement.removeAttribute(ACTIVE_ATTR)\n root?.unmount()\n root = undefined\n container?.remove()\n container = undefined\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 */\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 (a detached button; insert once the shell is up). */\nfunction createEntry(options: SidebarEntryOptions): { entry: HTMLButtonElement; 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: HTMLButtonElement, 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 is no\n // longer disconnected 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\n // instead of churning the full re-query.\n const waitObserver = new MutationObserver(() => { tryPlace() })\n waitObserver.observe(document.body, { childList: true, subtree: true })\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 waitObserver.disconnect()\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 18px navigation glyph size. */\nconst ICON = '<svg viewBox=\"0 0 16 16\" width=\"18\" height=\"18\" 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 /** 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) {\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p>\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 { SettingsScope, SettingsScopeSnapshot } 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 scope 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 scope subscription installed in the constructor; released by dispose(). */\n private readonly disposeScope: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound settings scope for this card's namespace. */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeScope = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the scope 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.disposeScope()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope 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 scope 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 0.1.2 scope contract never rejects a refused\n * mutation — the scope recovers with a fresh Host view and resolves — so\n * resolution alone proves nothing: the outcome is judged by reading the\n * settled snapshot back, one planned write at a time, and one missed write\n * fails the whole save. A scope that still rejects on refusal (the dsh-web\n * bridge scope) reports through the same failure path with its rejection\n * message. A save that did not land keeps its drafts, so the user can\n * 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 0.1.2 scope contract takes ordered\n // path 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 try {\n await this.scope.mutate(ops)\n } catch (error) {\n failedReason = error instanceof Error ? error.message : String(error)\n }\n // The 0.1.2 scope resolves even a refused mutation (it recovers with a\n // fresh view instead of throwing), so resolution alone proves nothing:\n // judge every planned write against the settled snapshot. The mutation is\n // atomic, so one missed write fails the whole save and keeps the drafts.\n const landed = 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 read-back failure carries no server reason: the card surfaces its\n // generic failure copy; a rejecting scope (the bridge) adds its 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 scope\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(): SettingsScopeSnapshot<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 { SettingsScope } 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` scope 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 settings scope for the `task-board` namespace. */\n constructor(scope: SettingsScope<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 scope 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 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, 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\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 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.archivedAt === undefined ? {} : { archivedAt: task.archivedAt }),\n ...(task.freeze === undefined ? {} : { freeze: task.freeze }),\n ...(task.handover === undefined ? {} : { handover: task.handover }),\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'])) 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)) return false\n if (input.permission !== undefined && !isTaskPermission(input.permission)) 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'])) return false\n for (const key of ['title', 'description', 'prompt', 'workspaceId', 'mode'] as const) {\n if (!optionalString(patch[key])) return false\n }\n if (patch.permission !== undefined && !isTaskPermission(patch.permission)) 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 {\n TASK_BOARD_API_PREFIX,\n type TaskBoardAction,\n type TaskBoardActionEnvelope,\n type TaskBoardEventPayload,\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\nfunction uuid(): string {\n return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n}\n\nasync function readJson<T>(response: Response): Promise<T> {\n const body = await response.json() as T & { error?: string }\n if (!response.ok) throw new Error(body.error ?? `task-board request failed: ${response.status}`)\n return body\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}\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 (controller.signal.aborted) throw new Error(`task-board Host request timed out after ${REQUEST_TIMEOUT_MS / 1_000}s`)\n throw error\n } finally {\n globalThis.clearTimeout(timeout)\n }\n }\n\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void {\n const events = new EventSource(`${TASK_BOARD_API_PREFIX}/events`)\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 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","/**\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 { SettingsScope, SettingsScopeSpec } 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 settings-surface Context merge (ctx.settingsScope).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { BoardController } from '../core/controller.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'\n\n/** Locale namespace this plugin owns. */\nconst NS = 'task-board'\n\n/** Settings namespace the settings card edits (the Host plugin registers it). */\nconst TASK_BOARD_NS = 'task-board'\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 instead of the top-level `settings.plugin.item` list.\n * Spelled here with the same shape so this package can register without\n * 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 rc.6 compatibility binder provided by dsh-web-settings;\n * absent when that group plugin is not installed, so callers fall back to\n * the official settings scope.\n */\n webUiSettings?: { bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S> }\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', 'settingsScope', 'locale', 'remote']\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 the Web UI plugin group.\n const binder = ctx.get('webUiSettings') ?? ctx.settingsScope\n const settingsScope = binder.bind<TaskBoardSettings>({ namespace: TASK_BOARD_NS })\n const settingsCard = new TaskBoardSettingsCardController(settingsScope)\n ctx.slots.inject('web-ui.plugin.item', () => {\n try {\n const unregister = ctx.slots.register({\n name: 'web-ui.plugin.item',\n id: 'task-board',\n order: 110,\n locale: NS,\n inject: () => settingsCard.inject(),\n }, TaskBoardSettingsCard)\n return () => {\n settingsCard.dispose()\n unregister()\n }\n } catch {\n return () => {}\n }\n })\n\n // The sidebar entry and board view mount once the settings scope settles;\n // while the scope is still loading, the composition default is unknown, so\n // nothing mounts yet. Only an unavailable scope (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 list: sessions.list,\n open: id => sessions.open(id as never),\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 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 void pushPresetOptions()\n disposers.push(ctx.on('connection/reset', () => { void pushPresetOptions() }))\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 = settingsScope.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 settingsScope.subscribe(syncEnabled)\n syncEnabled()\n}\n"],"mappings":"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"}
|
|
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/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/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/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/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/** 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 * 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 * 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/** Statuses a settled task may be archived from. */\nexport const ARCHIVABLE_STATUSES: readonly TaskStatus[] = ['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 /**\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\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 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 ...(input.freeze === undefined ? {} : { freeze: freezeOf(input.freeze, now) }),\n ...(input.handover === undefined ? {} : { handover: { ...input.handover, bundledAt: now } }),\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 settled (done/failed) task off the\n * main board and back. 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 settled statuses (done/failed) can be archived;\n * a running or not-yet-settled task stays on the board (its runner still\n * owns its lifecycle). Archiving disarms a schedule; already-archived tasks\n * are 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 high = Number(range)\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, normalizeTargetId, type TaskRecord, type TaskPermission } 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'>> & {\n freeze?: FreezeSnapshot & { redacted?: boolean } | null\n /** Replaces the handover bundle (restamping bundledAt); an explicit null clears it. */\n handover?: TaskHandoverInput | 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, ...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 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 // 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 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 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 { TaskBoardAction, TaskBoardEventPayload, TaskBoardSnapshot } 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\n/** The sessions face the controller needs for navigation awareness. */\nexport interface SessionsControllerFace {\n list: {\n getSnapshot(): { current: string | undefined }\n subscribe(fn: () => void): () => void\n }\n /** Select a session as current (navigates the conversation view). */\n open(id: string): void\n}\n\nfunction currentOf(sessions: SessionsControllerFace | undefined): string | undefined {\n return sessions?.list.getSnapshot().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/** 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/** The execution-target option sets the UI feeds into the controller. */\nexport interface ExecutionOptionsSnapshot {\n workspaces: readonly ExecutionWorkspaceOption[]\n presets: readonly ExecutionPresetOption[]\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 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: [] }\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.list.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.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 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 settled task (done/failed). Running or on-board-unsettled\n * tasks are refused so the runner keeps exclusive ownership of their\n * lifecycle.\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","/**\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, 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 (!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.freeze = normalizeFreeze(row.freeze)\n task.handover = normalizeHandover(row.handover)\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.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.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 'detail.permissionPending': '权限待确认:本卡有效权限({permission})高于会话默认,手动执行与定时调度都会被拒绝,需人工确认后才能运行。',\n 'detail.permissionConfirm': '确认权限绑定',\n 'detail.permissionConfirmed': '已确认权限绑定 · {time}',\n 'detail.title': '任务详情',\n 'detail.edit': '编辑',\n 'detail.close': '关闭',\n 'edit.title': '编辑任务',\n 'edit.save': '保存',\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 '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 '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.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.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 '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.close': 'Close',\n 'edit.title': 'Edit Task',\n 'edit.save': 'Save',\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 '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 '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 { t } from '../locales.ts'\nimport css from '../board.module.css'\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 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 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 <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 * 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, 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 { TASK_PERMISSIONS, type TaskPermission } from '../../core/tasks.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\nimport { ModalShell, TaskContentFields } from './TaskForm.tsx'\nimport css from '../board.module.css'\n\n/** New-task form overlay. */\nexport function NewTaskModal({ controller, onClose }: { controller: BoardController; onClose: () => void }) {\n const [title, setTitle] = useState('')\n const [description, setDescription] = useState('')\n const [prompt, setPrompt] = useState('')\n const [workspaceId, setWorkspaceId] = useState('')\n const [mode, setMode] = useState('')\n const [permission, setPermission] = useState('')\n const [scheduleEnabled, setScheduleEnabled] = useState(false)\n const [scheduleCron, setScheduleCron] = useState('')\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 const [error, setError] = useState<string | undefined>(undefined)\n const [pending, setPending] = useState(false)\n const [options, setOptions] = useState(controller.getSnapshot().executionOptions)\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 const submit = async (): 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 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 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 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 return (\n <ModalShell\n ariaLabel={t('board.new')}\n title={t('board.new')}\n error={error}\n pending={pending}\n submitLabel={t('new.submit')}\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 <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 <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 </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 } 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.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 type { TaskRecord } from '../../core/tasks.ts'\nimport { t } from '../locales.ts'\nimport { ModalShell, TaskContentFields } 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 [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 if (await controller.updateTask(task.id, { title, description, prompt })) {\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 </ModalShell>\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, 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 } from './EditTaskModal.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 // 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 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 </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\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(() => { setShowEdit(false) }, [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.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 => (\n <li key={reference} 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 && (\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 </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, 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/** Case-insensitive title/description/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]\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 * 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 [showNew, setShowNew] = useState(false)\n const selected = selectedTaskOf(snapshot)\n const archiveView = snapshot.archiveView\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 && matchesFilter(task, filter),\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 <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 {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 && <div className={css.columnEmpty}>{t('archive.empty')}</div>}\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 && <div className={css.columnEmpty}>{t('board.empty')}</div>}\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 onClose={() => { setShowNew(false) }}\n />\n )}\n </div>\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'\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 React tree into a root (initial mount, remount, 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) {\n if (container.isConnected) return\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 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 root = createRoot(container)\n options.render(root)\n }\n\n // The frame mounts after boot settlement; watch for the column's arrival.\n const waitObserver = new MutationObserver(() => { ensure() })\n waitObserver.observe(document.body, { childList: true, subtree: true })\n\n const applyActive = (): void => {\n if (options.isOpen()) {\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 waitObserver.disconnect()\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 */\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 (a detached button; insert once the shell is up). */\nfunction createEntry(options: SidebarEntryOptions): { entry: HTMLButtonElement; 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: HTMLButtonElement, 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 is no\n // longer disconnected 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\n // instead of churning the full re-query.\n const waitObserver = new MutationObserver(() => { tryPlace() })\n waitObserver.observe(document.body, { childList: true, subtree: true })\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 waitObserver.disconnect()\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 18px navigation glyph size. */\nconst ICON = '<svg viewBox=\"0 0 16 16\" width=\"18\" height=\"18\" 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 /** 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) {\n return (\n <li className={cardClass}>\n {header}\n {expanded\n ? (\n <div className={css.body}>\n <p className={css.notExposed} role=\"status\">{props.t('settings.notExposed')}</p>\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 { SettingsScope, SettingsScopeSnapshot } 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 scope 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 scope subscription installed in the constructor; released by dispose(). */\n private readonly disposeScope: () => void\n private disposed = false\n private saving = false\n private failed = false\n private failedReason: string | undefined\n\n /** @param scope - the bound settings scope for this card's namespace. */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: FieldSpec[],\n ) {\n this.specs = new Map(specs.map(spec => [spec.field, spec]))\n this.disposeScope = scope.subscribe(() => { this.publish() })\n }\n\n /**\n * Release the scope 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.disposeScope()\n this.listeners.clear()\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope 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 scope 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 0.1.2 scope contract never rejects a refused\n * mutation — the scope recovers with a fresh Host view and resolves — so\n * resolution alone proves nothing: the outcome is judged by reading the\n * settled snapshot back, one planned write at a time, and one missed write\n * fails the whole save. A scope that still rejects on refusal (the dsh-web\n * bridge scope) reports through the same failure path with its rejection\n * message. A save that did not land keeps its drafts, so the user can\n * 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 0.1.2 scope contract takes ordered\n // path 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 try {\n await this.scope.mutate(ops)\n } catch (error) {\n failedReason = error instanceof Error ? error.message : String(error)\n }\n // The 0.1.2 scope resolves even a refused mutation (it recovers with a\n // fresh view instead of throwing), so resolution alone proves nothing:\n // judge every planned write against the settled snapshot. The mutation is\n // atomic, so one missed write fails the whole save and keeps the drafts.\n const landed = 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 read-back failure carries no server reason: the card surfaces its\n // generic failure copy; a rejecting scope (the bridge) adds its 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 scope\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(): SettingsScopeSnapshot<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 { SettingsScope } 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` scope 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 settings scope for the `task-board` namespace. */\n constructor(scope: SettingsScope<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 scope 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 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, 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\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 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.archivedAt === undefined ? {} : { archivedAt: task.archivedAt }),\n ...(task.freeze === undefined ? {} : { freeze: task.freeze }),\n ...(task.handover === undefined ? {} : { handover: task.handover }),\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'])) 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)) return false\n if (input.permission !== undefined && !isTaskPermission(input.permission)) 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'])) return false\n for (const key of ['title', 'description', 'prompt', 'workspaceId', 'mode'] as const) {\n if (!optionalString(patch[key])) return false\n }\n if (patch.permission !== undefined && !isTaskPermission(patch.permission)) 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 {\n TASK_BOARD_API_PREFIX,\n type TaskBoardAction,\n type TaskBoardActionEnvelope,\n type TaskBoardEventPayload,\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\nfunction uuid(): string {\n return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n}\n\nasync function readJson<T>(response: Response): Promise<T> {\n const body = await response.json() as T & { error?: string }\n if (!response.ok) throw new Error(body.error ?? `task-board request failed: ${response.status}`)\n return body\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}\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 (controller.signal.aborted) throw new Error(`task-board Host request timed out after ${REQUEST_TIMEOUT_MS / 1_000}s`)\n throw error\n } finally {\n globalThis.clearTimeout(timeout)\n }\n }\n\n subscribe(listener: (event?: TaskBoardEventPayload) => void): () => void {\n const events = new EventSource(`${TASK_BOARD_API_PREFIX}/events`)\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 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","/**\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 { SettingsScope, SettingsScopeSpec } 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 settings-surface Context merge (ctx.settingsScope).\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { BoardController } from '../core/controller.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'\n\n/** Locale namespace this plugin owns. */\nconst NS = 'task-board'\n\n/** Settings namespace the settings card edits (the Host plugin registers it). */\nconst TASK_BOARD_NS = 'task-board'\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 instead of the top-level `settings.plugin.item` list.\n * Spelled here with the same shape so this package can register without\n * 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 rc.6 compatibility binder provided by dsh-web-settings;\n * absent when that group plugin is not installed, so callers fall back to\n * the official settings scope.\n */\n webUiSettings?: { bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S> }\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', 'settingsScope', 'locale', 'remote']\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 the Web UI plugin group.\n const binder = ctx.get('webUiSettings') ?? ctx.settingsScope\n const settingsScope = binder.bind<TaskBoardSettings>({ namespace: TASK_BOARD_NS })\n const settingsCard = new TaskBoardSettingsCardController(settingsScope)\n ctx.slots.inject('web-ui.plugin.item', () => {\n try {\n const unregister = ctx.slots.register({\n name: 'web-ui.plugin.item',\n id: 'task-board',\n order: 110,\n locale: NS,\n inject: () => settingsCard.inject(),\n }, TaskBoardSettingsCard)\n return () => {\n settingsCard.dispose()\n unregister()\n }\n } catch {\n return () => {}\n }\n })\n\n // The sidebar entry and board view mount once the settings scope settles;\n // while the scope is still loading, the composition default is unknown, so\n // nothing mounts yet. Only an unavailable scope (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 list: sessions.list,\n open: id => sessions.open(id as never),\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 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 void pushPresetOptions()\n disposers.push(ctx.on('connection/reset', () => { void pushPresetOptions() }))\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 = settingsScope.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 settingsScope.subscribe(syncEnabled)\n syncEnabled()\n}\n"],"mappings":"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"}
|