@linxin666/dsh-client-ui-task-board 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +6 -2
- package/README.zh.md +6 -2
- package/lib/client.js +437 -187
- package/lib/client.js.map +1 -1
- package/lib/index.js +45 -9
- package/lib/types/client/PluginSettingsCard.d.ts +2 -0
- package/lib/types/client/board/EditTaskModal.d.ts +8 -0
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/locales.d.ts +3 -0
- package/lib/types/client/settings-form.d.ts +1 -1
- package/lib/types/client/telemetry.d.ts +26 -0
- package/lib/types/core/controller.d.ts +9 -1
- package/lib/types/core/use-cases/task-update.d.ts +19 -3
- package/lib/types/http.d.ts +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/loopback.d.ts +1 -1
- package/lib/types/mount-once.d.ts +1 -1
- package/package.json +2 -4
- package/src/client/PluginSettingsCard.tsx +4 -2
- package/src/client/board/EditTaskModal.tsx +94 -0
- package/src/client/board/TaskBoard.tsx +1 -1
- package/src/client/board/TaskDetail.tsx +19 -0
- package/src/client/index.ts +6 -1
- package/src/client/locales.ts +6 -0
- package/src/client/settings-card.module.css +5 -0
- package/src/client/settings-form.ts +1 -1
- package/src/client/telemetry.ts +105 -0
- package/src/core/controller.ts +11 -3
- package/src/core/use-cases/task-update.ts +33 -3
- package/src/dsh-home.ts +9 -3
- package/src/host-ledger.ts +9 -1
- package/src/http.ts +1 -1
- package/src/index.ts +1 -1
- package/src/loopback.ts +1 -1
- package/src/mount-once.ts +2 -2
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["applyScheduleRollForward","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/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/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/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/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 */\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\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/** 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 * 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\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/** 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 }\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): { 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 }\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' ? '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 { isTaskPermission, normalizeTargetId, type TaskRecord, type TaskPermission } from '../tasks.ts'\n\n/** Editable fields on a task (the update patch surface). */\nexport type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission'>>\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 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, ...patch, updatedAt: now }\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. It also closes the\n * board whenever the user navigates to a session.\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 action(action: TaskBoardAction): 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\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'>\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\n/** Read the current selection off a session-list snapshot (structural). */\nfunction currentOf(sessions: SessionsControllerFace): string | undefined {\n return sessions.list.getSnapshot().current\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'> | 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 // Baseline the selection the board opened against: the board stays open\n // until the user navigates (selection changes), never on mere status\n // updates of the already-selected session.\n this.lastCurrent = currentOf(this.deps.sessions)\n this.boardOpen = true\n this.notify()\n }\n\n closeBoard(): void {\n if (!this.boardOpen) return\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 updateTask(id: string, patch: TaskUpdatePatch): void {\n if (this.deps.transport !== undefined) {\n void this.commitRemote({ kind: 'update', taskId: id, patch }, id)\n return\n }\n this.tasks = [...applyUpdateTask(this.tasks, id, patch, this.now())]\n this.persistAndNotify()\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.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)\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)\n }\n\n // --- internals ---------------------------------------------------------------\n\n /** Close the board when the user navigates to another session. */\n private onSessionsChanged(): void {\n if (!this.boardOpen) return\n const current = currentOf(this.deps.sessions)\n if (current !== this.lastCurrent) this.closeBoard()\n this.lastCurrent = current\n }\n\n private lastCurrent: string | undefined = undefined\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): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n if (taskId === undefined) return await this.performRemote(action)\n const previous = this.taskQueues.get(taskId) ?? Promise.resolve()\n const operation = previous.catch(() => {}).then(async () => await this.performRemote(action))\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): 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))\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 * 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 TaskRecord, type TaskPermission, type TaskStatus } from './tasks.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 }\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/** 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 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 'detail.title': '任务详情',\n 'detail.close': '关闭',\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.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 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',\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 'detail.title': 'Task Detail',\n 'detail.close': 'Close',\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.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 dsh-host-apiproxy\\'s WEB_SETTINGS_NAMESPACES 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/** Translate a key with optional {name} template params. */\nexport function t(key: TaskBoardKey, params?: Record<string, string>): string {\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 * 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 { TASK_PERMISSIONS, type TaskPermission } from '../../core/tasks.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\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 [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 setPending(true)\n const task = await controller.createTaskConfirmed({\n title,\n description,\n prompt,\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 <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onClose() }}>\n <form\n className={css.modal}\n role=\"dialog\"\n aria-label={t('board.new')}\n onSubmit={event => { event.preventDefault(); void submit() }}\n >\n <h2 className={css.modalTitle}>{t('board.new')}</h2>\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 => { setTitle(event.target.value); setError(undefined) }}\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 => { setDescription(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 => { setPrompt(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\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 {t('new.submit')}\n </button>\n </footer>\n </form>\n </div>\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\n/** One card in a column. */\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 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 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 {!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 * 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 { 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 { 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.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\n // Keep the overlay in sync if the task record changes underneath.\n const [latest, setLatest] = useState(task)\n useEffect(() => { setLatest(task) }, [task])\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\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 <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 && (\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 </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, 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 match. */\nfunction matchesFilter(task: TaskRecord, filter: string): boolean {\n if (filter.trim() === '') return true\n const needle = filter.trim().toLowerCase()\n return task.title.toLowerCase().includes(needle) || task.description.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-ui-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 return (\n <section key={column.status} className={css.column} data-status={column.status} data-dsh-part=\"column\">\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 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 * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountBoard(controller: BoardController): () => void {\n let root: Root | undefined\n let container: HTMLDivElement | undefined\n\n const ensure = (): void => {\n if (container !== undefined) return\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 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 /** 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): HTMLButtonElement {\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 entry.setAttribute('aria-label', options.label())\n if (options.tooltip !== undefined) entry.setAttribute('title', options.tooltip())\n entry.innerHTML = '<span class=\"' + (options.css['entryIcon'] ?? '') + '\">' + options.icon\n + '</span><span class=\"' + (options.css['entryLabel'] ?? '') + '\">' + options.label() + '</span>'\n entry.addEventListener('click', options.onToggle)\n return entry\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 = createEntry(options)\n let root: HTMLElement | undefined\n let placed = false\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 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/**\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 * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(controller: BoardController): () => 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 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 /** 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}>{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}>{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, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\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 field lands when the scope\n * reports the write succeeded (its secret-set marker under the bridge), so\n * a successful secret save is not misreported as failed.\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 official apiproxy settings\n * allowlist omits third-party namespaces): 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, described for a batched scope. */\n op: BatchedWrite\n /** Perform the write and report whether the Host holds the staged value afterwards. */\n run: (() => Promise<boolean>) | undefined\n}\n\n/** One durable write a batched settings scope performs. */\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/** Per-field outcome of one batched scope write. */\nexport interface BatchedFieldResult {\n /** Field this entry writes. */\n field: string\n /** Whether the Host accepted this field's write (per the read-back view). */\n landed: boolean\n}\n\n/**\n * Result of a batched scope write. The bridge scope posts every planned write\n * in one /mutate so the Host validate hook judges baseURL+model together; a\n * batched refusal fails the whole save rather than per-field.\n */\nexport interface BatchResult {\n /** Whether the whole mutate was accepted. */\n ok: boolean\n /** Per-field success, in the request order (always present when ok). */\n fields: BatchedFieldResult[]\n /** Host rejection code (mutate refused). */\n code?: string\n /** Host rejection message (mutate refused). */\n message?: string\n}\n\n/** The optional batch surface the bridge scope adds over the SettingsScope contract. */\ninterface BatchedSettingsScope {\n /** Write every operation in one scope mutation, reporting per-field success. */\n mutate: (writes: BatchedWrite[]) => Promise<BatchResult>\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 and relies on the scope\n * reporting the write landed.\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.run === 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, then re-seed from what the Host accepted.\n *\n * When the scope carries the optional batch surface (the dsh-web-ui\n * bridge scope), every planned write rides one mutation so cross-field\n * validate hooks (baseURL+model) judge the batch as a unit instead of\n * deadlocking on per-field writes. Otherwise the per-field loop runs.\n * A field lands only when the Host reports it held the staged value; a\n * landed field's draft is dropped, a failed one stays staged for the user.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter(item => item.run !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n const plannedWrites = valid.map(item => item.op)\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 const landed = new Set<string>()\n const batch = this.batchedScope()\n if (batch !== undefined) {\n const result = await batch.mutate(plannedWrites)\n if (result.ok) {\n for (const field of result.fields) {\n if (field.landed) landed.add(field.field)\n }\n } else {\n this.failedReason = result.message\n }\n } else {\n for (const item of valid) {\n if (await item.run!()) landed.add(item.field)\n }\n }\n for (const [field, before] of pending) {\n if (landed.has(field) && this.staged.get(field) === before) this.staged.delete(field)\n }\n this.saving = false\n this.failed = landed.size !== pending.size\n this.publish()\n }\n\n /** The scope's batch surface when it supports one; undefined conservatively otherwise. */\n private batchedScope(): BatchedSettingsScope | undefined {\n const candidate = this.scope as unknown as BatchedSettingsScope | undefined\n return typeof candidate?.mutate === 'function' ? candidate : undefined\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' }, run: () => this.clear(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' }, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n // A redacted secret never appears in the user layer read-back; judging it\n // by value would misreport a successful secret save as failed. The bridge\n // reports secret writes through its secret-set markers (batch path); on\n // the per-field path the scope resolved, so the write is landed.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\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 { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/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 TaskRecord, type TaskStatus } from './core/tasks.ts'\nimport { parseLedger } from './core/store.ts'\n\nexport const TASK_BOARD_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}\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\nexport interface TaskBoardActionEnvelope {\n requestId: string\n action: TaskBoardAction\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 }\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 })),\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 }\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'])) 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.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'])) return false\n for (const key of ['title', 'description', 'prompt', 'workspaceId', 'mode'] as const) {\n if (!optionalString(patch[key])) return false\n }\n return patch.permission === undefined || isTaskPermission(patch.permission)\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 envelope = record(value)\n if (envelope === undefined || !exactKeys(envelope, ['requestId', 'action'])) return undefined\n if (typeof envelope.requestId !== 'string' || envelope.requestId.trim() === '' || envelope.requestId.length > 256) 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 return typeof action.id === 'string' && action.id !== '' && createInput(action.input)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'create' }> }\n : undefined\n case 'update':\n if (!exactKeys(action, ['kind', 'taskId', 'patch'])) return undefined\n return taskId !== undefined && updatePatch(action.patch)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'update' }> }\n : undefined\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 '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): 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): Promise<TaskBoardSnapshot> {\n return await this.post(uuid(), action)\n }\n\n private async post(requestId: string, action: TaskBoardAction): Promise<TaskBoardSnapshot> {\n const envelope: TaskBoardActionEnvelope = { requestId, action }\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","/**\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 { ClientContext, ISessions, IWorkspaces, SessionId, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/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, type TaskBoardKey } from './locales.ts'\nimport { HttpTaskBoardHostTransport } from './host-api.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-ui-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/** Required services (fiber inject waiting — the runtime must be up first). */\nexport const inject = ['slots', 'sessions', 'workspaces', 'connection', 'settingsScope', 'locale', 'remote']\n\n/**\n * Mount the task board.\n * @param ctx - client root context (services: sessions, workspaces).\n */\nexport function apply(ctx: ClientContext): void {\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 // 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 connection = ctx.get('connection') as ConnectionHandle\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 SessionId),\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 response = await connection.api.agentPresets.list({})\n if (!response.result.ok) return\n controller.setExecutionOptions({\n presets: response.result.value.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))\n disposers.push(mountBoard(controller))\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/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/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 */\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\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/** 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 * 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\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/** 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 }\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): { 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 }\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' ? '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 an execution-target field\n * (the task falls back to the runtime default); content fields are trimmed\n * and never cleared. An unknown permission string is ignored so stale UI\n * can never persist a value the execution service rejects.\n */\nimport { isTaskPermission, normalizeTargetId, type TaskRecord, type TaskPermission } from '../tasks.ts'\n\n/** Editable fields on a task (the update patch surface). */\nexport type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission'>>\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 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, ...patch, 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 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. It also closes the\n * board whenever the user navigates to a session.\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 action(action: TaskBoardAction): 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\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'>\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\n/** Read the current selection off a session-list snapshot (structural). */\nfunction currentOf(sessions: SessionsControllerFace): string | undefined {\n return sessions.list.getSnapshot().current\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'> | 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 // Baseline the selection the board opened against: the board stays open\n // until the user navigates (selection changes), never on mere status\n // updates of the already-selected session.\n this.lastCurrent = currentOf(this.deps.sessions)\n this.boardOpen = true\n this.notify()\n }\n\n closeBoard(): void {\n if (!this.boardOpen) return\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.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)\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)\n }\n\n // --- internals ---------------------------------------------------------------\n\n /** Close the board when the user navigates to another session. */\n private onSessionsChanged(): void {\n if (!this.boardOpen) return\n const current = currentOf(this.deps.sessions)\n if (current !== this.lastCurrent) this.closeBoard()\n this.lastCurrent = current\n }\n\n private lastCurrent: string | undefined = undefined\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): Promise<boolean> {\n const transport = this.deps.transport\n if (transport === undefined) return true\n if (taskId === undefined) return await this.performRemote(action)\n const previous = this.taskQueues.get(taskId) ?? Promise.resolve()\n const operation = previous.catch(() => {}).then(async () => await this.performRemote(action))\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): 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))\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 * 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 TaskRecord, type TaskPermission, type TaskStatus } from './tasks.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 }\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/** 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 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 '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.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 直接配置,或为 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES 白名单补充本命名空间后重启。',\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 '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.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 dsh-host-apiproxy\\'s WEB_SETTINGS_NAMESPACES 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/** Translate a key with optional {name} template params. */\nexport function t(key: TaskBoardKey, params?: Record<string, string>): string {\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 * 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 { TASK_PERMISSIONS, type TaskPermission } from '../../core/tasks.ts'\nimport { t, type TaskBoardKey } from '../locales.ts'\nimport { SCHEDULE_PRESETS } from '../schedule-presets.ts'\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 [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 setPending(true)\n const task = await controller.createTaskConfirmed({\n title,\n description,\n prompt,\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 <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onClose() }}>\n <form\n className={css.modal}\n role=\"dialog\"\n aria-label={t('board.new')}\n onSubmit={event => { event.preventDefault(); void submit() }}\n >\n <h2 className={css.modalTitle}>{t('board.new')}</h2>\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 => { setTitle(event.target.value); setError(undefined) }}\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 => { setDescription(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 => { setPrompt(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\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 {t('new.submit')}\n </button>\n </footer>\n </form>\n </div>\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\n/** One card in a column. */\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 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 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 {!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 css from '../board.module.css'\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 <div className={css.modalBackdrop} onMouseDown={event => { if (event.target === event.currentTarget) onClose() }}>\n <form\n className={css.modal}\n role=\"dialog\"\n aria-label={t('edit.title')}\n onSubmit={event => { event.preventDefault(); void submit() }}\n >\n <h2 className={css.modalTitle}>{t('edit.title')}</h2>\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 => { setTitle(event.target.value); setError(undefined) }}\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 => { setDescription(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 => { setPrompt(event.target.value) }}\n />\n </label>\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 {t('edit.save')}\n </button>\n </footer>\n </form>\n </div>\n )\n}\n","/**\n * Task detail: the full view of one task — content, prompt, execution\n * history — and the only place execution can be triggered. Also offers\n * delete (with confirmation), manual status moves, and a jump to the\n * execution's session transcript.\n */\nimport { useEffect, useState } from 'react'\nimport type { BoardController } from '../../core/controller.ts'\nimport { isValidCron } from '../../core/schedule.ts'\nimport { MANUAL_STATUSES, TASK_PERMISSIONS, type ExecutionRecord, type TaskPermission, type TaskRecord } from '../../core/tasks.ts'\nimport { canEditTaskContent } from '../../core/use-cases/task-update.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.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\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 <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, 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 match. */\nfunction matchesFilter(task: TaskRecord, filter: string): boolean {\n if (filter.trim() === '') return true\n const needle = filter.trim().toLowerCase()\n return task.title.toLowerCase().includes(needle) || task.description.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 return (\n <section key={column.status} className={css.column} data-status={column.status} data-dsh-part=\"column\">\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 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 * @returns disposer unmounting the tree and restoring the column.\n */\nexport function mountBoard(controller: BoardController): () => void {\n let root: Root | undefined\n let container: HTMLDivElement | undefined\n\n const ensure = (): void => {\n if (container !== undefined) return\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 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 /** 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): HTMLButtonElement {\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 entry.setAttribute('aria-label', options.label())\n if (options.tooltip !== undefined) entry.setAttribute('title', options.tooltip())\n entry.innerHTML = '<span class=\"' + (options.css['entryIcon'] ?? '') + '\">' + options.icon\n + '</span><span class=\"' + (options.css['entryLabel'] ?? '') + '\">' + options.label() + '</span>'\n entry.addEventListener('click', options.onToggle)\n return entry\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 = createEntry(options)\n let root: HTMLElement | undefined\n let placed = false\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 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/**\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 * @returns disposer removing the entry and its observers.\n */\nexport function mountSidebarEntry(controller: BoardController): () => 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 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, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\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 field lands when the scope\n * reports the write succeeded (its secret-set marker under the bridge), so\n * a successful secret save is not misreported as failed.\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 official apiproxy settings\n * allowlist omits third-party namespaces): 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, described for a batched scope. */\n op: BatchedWrite\n /** Perform the write and report whether the Host holds the staged value afterwards. */\n run: (() => Promise<boolean>) | undefined\n}\n\n/** One durable write a batched settings scope performs. */\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/** Per-field outcome of one batched scope write. */\nexport interface BatchedFieldResult {\n /** Field this entry writes. */\n field: string\n /** Whether the Host accepted this field's write (per the read-back view). */\n landed: boolean\n}\n\n/**\n * Result of a batched scope write. The bridge scope posts every planned write\n * in one /mutate so the Host validate hook judges baseURL+model together; a\n * batched refusal fails the whole save rather than per-field.\n */\nexport interface BatchResult {\n /** Whether the whole mutate was accepted. */\n ok: boolean\n /** Per-field success, in the request order (always present when ok). */\n fields: BatchedFieldResult[]\n /** Host rejection code (mutate refused). */\n code?: string\n /** Host rejection message (mutate refused). */\n message?: string\n}\n\n/** The optional batch surface the bridge scope adds over the SettingsScope contract. */\ninterface BatchedSettingsScope {\n /** Write every operation in one scope mutation, reporting per-field success. */\n mutate: (writes: BatchedWrite[]) => Promise<BatchResult>\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 and relies on the scope\n * reporting the write landed.\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.run === 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, then re-seed from what the Host accepted.\n *\n * When the scope carries the optional batch surface (the dsh-web\n * bridge scope), every planned write rides one mutation so cross-field\n * validate hooks (baseURL+model) judge the batch as a unit instead of\n * deadlocking on per-field writes. Otherwise the per-field loop runs.\n * A field lands only when the Host reports it held the staged value; a\n * landed field's draft is dropped, a failed one stays staged for the user.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n const valid = plan.filter(item => item.run !== undefined)\n if (plan.length === 0 || this.saving || valid.length !== plan.length) return\n const plannedWrites = valid.map(item => item.op)\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 const landed = new Set<string>()\n const batch = this.batchedScope()\n if (batch !== undefined) {\n const result = await batch.mutate(plannedWrites)\n if (result.ok) {\n for (const field of result.fields) {\n if (field.landed) landed.add(field.field)\n }\n } else {\n this.failedReason = result.message\n }\n } else {\n for (const item of valid) {\n if (await item.run!()) landed.add(item.field)\n }\n }\n for (const [field, before] of pending) {\n if (landed.has(field) && this.staged.get(field) === before) this.staged.delete(field)\n }\n this.saving = false\n this.failed = landed.size !== pending.size\n this.publish()\n }\n\n /** The scope's batch surface when it supports one; undefined conservatively otherwise. */\n private batchedScope(): BatchedSettingsScope | undefined {\n const candidate = this.scope as unknown as BatchedSettingsScope | undefined\n return typeof candidate?.mutate === 'function' ? candidate : undefined\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' }, run: () => this.clear(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' }, run: undefined })\n else if (write.kind === 'clear') plan.push({ field, op: { field, op: 'unset' }, run: () => this.clear(field) })\n else plan.push({ field, op: { field, op: 'set', value: write.value }, run: () => this.store(field, write.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value)\n // A redacted secret never appears in the user layer read-back; judging it\n // by value would misreport a successful secret save as failed. The bridge\n // reports secret writes through its secret-set markers (batch path); on\n // the per-field path the scope resolved, so the write is landed.\n if (this.specOf(field).secret) return true\n return this.userLayer()?.[field] === value\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 { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/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 TaskRecord, type TaskStatus } from './core/tasks.ts'\nimport { parseLedger } from './core/store.ts'\n\nexport const TASK_BOARD_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}\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\nexport interface TaskBoardActionEnvelope {\n requestId: string\n action: TaskBoardAction\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 }\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 })),\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 }\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'])) 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.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'])) return false\n for (const key of ['title', 'description', 'prompt', 'workspaceId', 'mode'] as const) {\n if (!optionalString(patch[key])) return false\n }\n return patch.permission === undefined || isTaskPermission(patch.permission)\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 envelope = record(value)\n if (envelope === undefined || !exactKeys(envelope, ['requestId', 'action'])) return undefined\n if (typeof envelope.requestId !== 'string' || envelope.requestId.trim() === '' || envelope.requestId.length > 256) 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 return typeof action.id === 'string' && action.id !== '' && createInput(action.input)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'create' }> }\n : undefined\n case 'update':\n if (!exactKeys(action, ['kind', 'taskId', 'patch'])) return undefined\n return taskId !== undefined && updatePatch(action.patch)\n ? { requestId: envelope.requestId, action: action as unknown as Extract<TaskBoardAction, { kind: 'update' }> }\n : undefined\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 '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): 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): Promise<TaskBoardSnapshot> {\n return await this.post(uuid(), action)\n }\n\n private async post(requestId: string, action: TaskBoardAction): Promise<TaskBoardSnapshot> {\n const envelope: TaskBoardActionEnvelope = { requestId, action }\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 { ClientContext, ISessions, IWorkspaces, SessionId, SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/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, 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/** Required services (fiber inject waiting — the runtime must be up first). */\nexport const inject = ['slots', 'sessions', 'workspaces', 'connection', 'settingsScope', 'locale', 'remote']\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 // 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 connection = ctx.get('connection') as ConnectionHandle\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 SessionId),\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 response = await connection.api.agentPresets.list({})\n if (!response.result.ok) return\n controller.setExecutionOptions({\n presets: response.result.value.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))\n disposers.push(mountBoard(controller))\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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"}
|