/** * Task-board copy: zh-first dictionaries with an English fallback, selected * by the document language. Kept dependency-free (no dsh locale service) so * the DOM-injected entry row and the standalone board tree share one tiny * lookup. */ /** zh dictionary (key-set source of truth). */ export const zh = { 'entry.label': '任务看板', 'board.title': '任务看板', 'board.close': '返回会话', 'board.new': '新建任务', 'board.search': '筛选任务…', 'board.empty': '这个状态还没有任务', 'board.filterAll': '全部', 'board.archive': '归档', 'board.archiveView': '归档 ({count})', 'board.backToBoard': '返回看板', 'archive.empty': '没有已归档的任务', 'board.status': '状态', 'board.status.backlog': '待规划', 'board.status.todo': '待办', 'board.status.running': '进行中', 'board.status.done': '已完成', 'board.status.failed': '已失败', 'board.runs': '次执行', 'board.pending': '正在提交', 'board.updated': '更新于', 'board.created': '创建于', 'board.hostError': 'Host 操作失败:{error}', 'board.hostError.notMounted': '任务看板的后台接口没有挂载:宿主可能没有加载该插件,也可能后台数据正被另一个 DSH 实例占用。重启 DSH 服务后再试', 'board.hostError.unauthorized': '登录状态已失效,请刷新页面后重试', 'board.hostError.locked': '任务看板的后台数据被占用:{detail}', 'board.hostError.timeout': '后台 {seconds} 秒内没有响应,请稍后重试', 'board.hostError.unreachable': '连接不上本机 DSH 服务,请确认它仍在运行', 'board.hostError.unexpected': '后台返回了无法识别的响应(HTTP {status})', 'board.project': '项目', 'board.projectAll': '全部项目', 'board.projectNew': '新建项目…', 'board.projectNewPath': '项目目录(宿主上的绝对路径)', 'board.projectNewPathPlaceholder': '例如 C:\\work\\my-project 或 /home/me/project', 'board.projectCreate': '创建项目', 'board.projectCreateFailed': '创建项目失败:{error}', 'new.aiParse': 'AI 解析', 'new.aiParseHint': '把从别处复制的一段话粘进来,让模型整理成标题、描述和执行 Prompt;解析结果只填进下面的表单,你可以先改再创建。', 'new.aiParsePlaceholder': '粘贴要变成任务的内容…', 'new.aiParseModel': '解析用模型', 'new.aiParseRun': '解析并填入', 'new.aiParseCancel': '取消解析', 'new.aiParseEmpty': '先粘贴一段内容再解析', 'new.aiParseNoModel': '这个部署还没有可用的模型,请先在 DSH 里配置模型提供商,或换一个模型再试', 'new.aiParseUnavailable': '后台没有解析接口可用,重启 DSH 服务后再试', 'new.aiParseTimeout': '模型 {seconds} 秒内没有返回结果,请重试或换一个更快的模型', 'new.aiParseFailed': '解析失败:{error}', 'board.retryHost': '重试连接 Host', 'board.hostMeta': 'Host 时区 {timeZone} · revision {revision}', 'new.title': '标题', 'new.titlePlaceholder': '一句话描述要做什么', 'new.description': '描述', 'new.descriptionPlaceholder': '补充背景、范围与验收(可选)', 'new.prompt': '执行 Prompt', 'new.promptPlaceholder': '发给 agent 的完整指令(留空则使用标题)', 'new.submit': '创建', 'new.createAndRun': '创建并执行', 'new.cancel': '取消', 'new.required': '标题不能为空', 'new.freeze': '冻结快照(可选)', 'new.freezePlaceholder': '粘贴会话输出的 <<>>FREEZE 冻结块,解析为目标/进度/下一步(可选)', 'detail.freeze': '冻结快照', 'detail.freeze.goal': '目标', 'detail.freeze.progress': '进度', 'detail.freeze.next': '下一步', 'detail.freeze.frozenAt': '冻结于 {time}', 'detail.freeze.frozenBy': '来源会话 {session}', 'detail.freeze.redacted': '冻结文本命中敏感模式,已自动替换为 [REDACTED];接手前请人工复核。', 'card.frozen': '冻结', 'new.handover': '交接包引用(可选)', 'new.handoverPlaceholder': '每行一个文档/脚本引用;填写后,上面选择的钉住三元组(工作区/模式/权限)会作为交接包附加到卡片', 'detail.handover': '交接包', 'detail.handover.bundledAt': '打包于 {time}', 'detail.handover.references': '引用', 'new.tags': '标签(可选)', 'new.tagsHint': '标签用于卡片徽章与顶栏筛选;填了「执行提示」的行会在每次执行前注入 Prompt,留空则只作展示。', 'new.tagName': '标签名', 'new.tagNamePlaceholder': '例如:工作', 'new.tagPrompt': '执行提示(可选)', 'new.tagPromptPlaceholder': '例如:产物归档到 02-工作/', 'new.tagAdd': '添加标签', 'new.tagRemove': '移除标签 {name}', 'board.tagFilter': '按标签筛选', 'board.tagFilterClear': '清除标签筛选', 'board.tagEmpty': '没有同时带这些标签的任务', 'detail.permissionPending': '权限待确认:本卡有效权限({permission})高于会话默认,手动执行与定时调度都会被拒绝,需人工确认后才能运行。', 'detail.permissionConfirm': '确认权限绑定', 'detail.permissionConfirmed': '已确认权限绑定 · {time}', 'detail.title': '任务详情', 'detail.edit': '编辑', 'detail.editTags': '编辑标签', 'detail.duplicate': '复制为新任务', 'detail.duplicateAndEdit': '修改并新建副本', 'detail.close': '关闭', 'edit.title': '编辑任务', 'edit.save': '保存', 'new.duplicateTitle': '新建任务(副本)', 'new.archiveOriginal': '创建后归档原任务', 'detail.prompt': '执行 Prompt', 'detail.description': '描述', 'detail.execution': '执行记录', 'detail.noExecution': '尚未执行', 'detail.run': '执行', 'detail.rerun': '重新执行', 'detail.delete': '删除', 'detail.archive': '归档', 'detail.restore': '恢复', 'detail.archivedAt': '已归档 · {time}', 'detail.viewSession': '查看会话', 'detail.noSession': '暂无会话', 'detail.executionStarted': '已启动', 'detail.execution.initiator': '发起会话 {session}', 'detail.executionEnded': '已结束', 'detail.result.succeeded': '成功', 'detail.result.failed': '失败', 'detail.result.cancelled': '已取消', 'detail.result.running': '进行中', 'delete.title': '删除任务', 'delete.confirm': '确定删除「{name}」吗?删除后不可恢复。', 'delete.ok': '删除', 'delete.cancel': '取消', 'status.move.backlog': '移到待规划', 'status.move.todo': '移到待办', 'exec.error.noWorkspace': '没有可用工作区,无法执行任务', 'exec.error.promptRejected': 'Prompt 被拒绝', 'run.failed': '执行失败:{error}', 'time.justNow': '刚刚', 'detail.schedule': '定时运行', 'detail.schedule.enable': '启用定时执行', 'detail.schedule.cron': 'Cron 表达式', 'detail.schedule.presets': '预设', 'detail.schedule.preset.daily9': '每天 09:00', 'detail.schedule.preset.hourly': '每小时', 'detail.schedule.preset.tenMin': '每 10 分钟', 'detail.schedule.preset.weeklyMon9': '每周一 09:00', 'detail.schedule.nextRun': '下次运行', 'detail.schedule.lastTriggered': '上次触发', 'detail.schedule.invalid': 'Cron 表达式无效', 'detail.schedule.notScheduled': '尚未排程', 'detail.schedule.dueSoon': '即将运行', 'card.scheduled': '定时', 'new.workspace': '工作区', 'new.mode': '模式', 'new.permission': '权限', 'new.model': '模型', 'exec.workspace.recent': '最近使用(默认)', 'exec.mode.default': '部署默认', 'exec.mode.defaultSuffix': '(默认)', 'exec.mode.brokenSuffix': '(不可用)', 'exec.mode.removed': '(已移除)', 'exec.permission.default': '会话默认', 'exec.permission.read-only': '只读', 'exec.permission.workspace-write': '工作区可写', 'exec.permission.danger-full-access': '完全访问', 'exec.model.default': '宿主默认(agent-default-model)', 'exec.model.unknown': '(未知模型/回退默认)', 'exec.reuseSession': '在同一对话继续', 'exec.reuseSessionHint': '开启后,本任务的后续执行在上一次会话里继续(该会话空闲且仍存在时),不再每次新建对话;每次复用时都会重新应用上面钉住的权限与模型。', 'detail.executionSettings': '执行设置', 'exec.hint': '执行时生效:工作区决定执行会话落在哪个工作区;模式决定会话的 agent 预设;权限经 /permission 命令应用到会话。留空则使用运行时默认。', // 插件设置卡片(settings.plugin.item 席位)。 'settings.title': '任务看板', 'settings.description': '控制 Host 任务看板、agent 播报与运行期间的系统空闲睡眠保护。', 'settings.enabled': '启用任务看板', 'settings.enabledHint': '关闭后隐藏侧边栏入口与看板视图。', 'settings.announceToAgent': '向 agent 播报任务看板', 'settings.announceToAgentHint': '开启:每条 agent 系统提示都会包含本看板的说明;关闭:不播报,agent 仅在用户主动提及时了解看板。', 'settings.preventIdleSleep': '阻止系统空闲睡眠', 'settings.preventIdleSleepHint': '默认关闭。开启后,只要存在运行中的 DSH 会话、已启用的定时任务或会话状态尚未确认,Host 就阻止整机因空闲睡眠;屏幕仍可自动关闭。', 'settings.powerStatus': '平台:{platform};保护状态:{phase};运行会话:{running};已启用计划:{schedules}', 'settings.powerBoundary': '这可能增加电池消耗。合盖、手动睡眠、休眠、关机、低电量或企业策略不在保证范围内,也不会唤醒已经睡眠的机器。', 'settings.powerUnknown': '未知', 'settings.powerError': '最近一次电源保护错误:{error}', 'settings.inherit': '继承', 'settings.on': '开', 'settings.off': '关', 'settings.overridden': '已覆盖', 'settings.reset': '恢复默认', 'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 ~/.dsh/settings.yaml 直接配置,或将本命名空间加入 Host 设置白名单后重启。', 'settings.readOnly': '当前部署的设置只读。', 'settings.expand': '展开设置', 'settings.collapse': '收起设置', 'settings.save': '保存', 'settings.saving': '保存中…', 'settings.discard': '放弃', 'settings.unsaved': '未保存', 'settings.saveFailed': '部署未接受这些值,已保留供你修改。', 'settings.invalidNumber': '请输入数字,留空则使用默认值。', } satisfies Record /** en dictionary, complete against the zh key set. */ export const en: Record = { 'entry.label': 'Task Board', 'board.title': 'Task Board', 'board.close': 'Back to chat', 'board.new': 'New Task', 'board.search': 'Filter tasks…', 'board.empty': 'No tasks in this column', 'board.filterAll': 'All', 'board.archive': 'Archive', 'board.archiveView': 'Archived ({count})', 'board.backToBoard': 'Back to board', 'archive.empty': 'No archived tasks', 'board.status': 'Status', 'board.status.backlog': 'Backlog', 'board.status.todo': 'To Do', 'board.status.running': 'In Progress', 'board.status.done': 'Done', 'board.status.failed': 'Failed', 'board.runs': 'runs', 'board.pending': 'Submitting', 'board.updated': 'Updated', 'board.created': 'Created', 'board.hostError': 'Host action failed: {error}', 'board.hostError.notMounted': 'The task board Host API is not mounted: the Host may not have loaded the plugin, or another DSH instance holds the ledger. Restart the DSH service and try again', 'board.hostError.unauthorized': 'This session is no longer signed in; reload the page and try again', 'board.hostError.locked': 'The task board ledger is locked: {detail}', 'board.hostError.timeout': 'The Host did not answer within {seconds}s; try again shortly', 'board.hostError.unreachable': 'Cannot reach the local DSH service; make sure it is still running', 'board.hostError.unexpected': 'The Host returned an unrecognized response (HTTP {status})', 'board.project': 'Project', 'board.projectAll': 'All projects', 'board.projectNew': 'New project…', 'board.projectNewPath': 'Project directory (absolute path on the Host)', 'board.projectNewPathPlaceholder': 'e.g. C:\\work\\my-project or /home/me/project', 'board.projectCreate': 'Create project', 'board.projectCreateFailed': 'Could not create the project: {error}', 'new.aiParse': 'Parse with AI', 'new.aiParseHint': 'Paste text copied from somewhere else and let a model turn it into a title, description, and run prompt; the result only fills the form below, so you can edit it before creating the task.', 'new.aiParsePlaceholder': 'Paste the content to turn into a task…', 'new.aiParseModel': 'Model used for parsing', 'new.aiParseRun': 'Parse and fill', 'new.aiParseCancel': 'Cancel parsing', 'new.aiParseEmpty': 'Paste something to parse first', 'new.aiParseNoModel': 'This deployment has no model available; configure a model provider in DSH or pick another model', 'new.aiParseUnavailable': 'The Host has no parse endpoint; restart the DSH service and try again', 'new.aiParseTimeout': 'The model did not answer within {seconds}s; try again or pick a faster model', 'new.aiParseFailed': 'Parsing failed: {error}', 'board.retryHost': 'Retry Host connection', 'board.hostMeta': 'Host time zone {timeZone} · revision {revision}', 'new.title': 'Title', 'new.titlePlaceholder': 'What should be done, in one line', 'new.description': 'Description', 'new.descriptionPlaceholder': 'Background, scope, acceptance criteria (optional)', 'new.prompt': 'Run Prompt', 'new.promptPlaceholder': 'The full instruction sent to the agent (title is used when blank)', 'new.submit': 'Create', 'new.createAndRun': 'Create and run', 'new.cancel': 'Cancel', 'new.required': 'Title is required', 'new.freeze': 'Frozen snapshot (optional)', 'new.freezePlaceholder': 'Paste a <<>>FREEZE block from a session; it parses into goal/progress/next (optional)', 'detail.freeze': 'Frozen snapshot', 'detail.freeze.goal': 'Goal', 'detail.freeze.progress': 'Progress', 'detail.freeze.next': 'Next', 'detail.freeze.frozenAt': 'Frozen at {time}', 'detail.freeze.frozenBy': 'Source session {session}', 'detail.freeze.redacted': 'Sensitive patterns were detected in the frozen text and replaced with [REDACTED]; review manually before resuming.', 'card.frozen': 'frozen', 'new.handover': 'Handover references (optional)', 'new.handoverPlaceholder': 'One doc/script reference per line; when filled, the pinned triplet picked above (workspace/mode/permission) is attached to the card as a handover bundle', 'detail.handover': 'Handover bundle', 'detail.handover.bundledAt': 'Bundled at {time}', 'detail.handover.references': 'References', 'new.tags': 'Tags (optional)', 'new.tagsHint': 'Tags drive the card badges and the board filter; a row with an execution hint is injected ahead of the prompt on every run, an empty one is display-only.', 'new.tagName': 'Tag name', 'new.tagNamePlaceholder': 'e.g. Work', 'new.tagPrompt': 'Execution hint (optional)', 'new.tagPromptPlaceholder': 'e.g. Archive artefacts under 02-work/', 'new.tagAdd': 'Add tag', 'new.tagRemove': 'Remove tag {name}', 'board.tagFilter': 'Filter by tag', 'board.tagFilterClear': 'Clear tag filter', 'board.tagEmpty': 'No task carries all of these tags', 'detail.permissionPending': 'Permission pending confirmation: this card\'s effective permission ({permission}) is above the session default; manual runs and cron are refused until a human confirms.', 'detail.permissionConfirm': 'Confirm permission binding', 'detail.permissionConfirmed': 'Permission confirmed · {time}', 'detail.title': 'Task Detail', 'detail.edit': 'Edit', 'detail.editTags': 'Edit tags', 'detail.duplicate': 'Duplicate Task', 'detail.duplicateAndEdit': 'Edit as New Copy', 'detail.close': 'Close', 'edit.title': 'Edit Task', 'edit.save': 'Save', 'new.duplicateTitle': 'New Task (Copy)', 'new.archiveOriginal': 'Archive original task upon creation', 'detail.prompt': 'Run Prompt', 'detail.description': 'Description', 'detail.execution': 'Execution History', 'detail.noExecution': 'Not executed yet', 'detail.run': 'Run', 'detail.rerun': 'Run Again', 'detail.delete': 'Delete', 'detail.archive': 'Archive', 'detail.restore': 'Restore', 'detail.archivedAt': 'Archived · {time}', 'detail.viewSession': 'View Session', 'detail.noSession': 'No session', 'detail.executionStarted': 'Started', 'detail.execution.initiator': 'Initiated by session {session}', 'detail.executionEnded': 'Ended', 'detail.result.succeeded': 'Succeeded', 'detail.result.failed': 'Failed', 'detail.result.cancelled': 'Cancelled', 'detail.result.running': 'Running', 'delete.title': 'Delete Task', 'delete.confirm': 'Delete "{name}"? This cannot be undone.', 'delete.ok': 'Delete', 'delete.cancel': 'Cancel', 'status.move.backlog': 'Move to Backlog', 'status.move.todo': 'Move to To Do', 'exec.error.noWorkspace': 'No workspace is available to run the task', 'exec.error.promptRejected': 'Prompt rejected', 'run.failed': 'Run failed: {error}', 'time.justNow': 'just now', 'detail.schedule': 'Scheduled Runs', 'detail.schedule.enable': 'Enable scheduled runs', 'detail.schedule.cron': 'Cron expression', 'detail.schedule.presets': 'Presets', 'detail.schedule.preset.daily9': 'Every day 09:00', 'detail.schedule.preset.hourly': 'Every hour', 'detail.schedule.preset.tenMin': 'Every 10 minutes', 'detail.schedule.preset.weeklyMon9': 'Every Monday 09:00', 'detail.schedule.nextRun': 'Next run', 'detail.schedule.lastTriggered': 'Last triggered', 'detail.schedule.invalid': 'Invalid cron expression', 'detail.schedule.notScheduled': 'Not scheduled yet', 'detail.schedule.dueSoon': 'Due soon', 'card.scheduled': 'scheduled', 'new.workspace': 'Workspace', 'new.mode': 'Mode', 'new.permission': 'Permission', 'new.model': 'Model', 'exec.workspace.recent': 'Most recent (default)', 'exec.mode.default': 'Deployment default', 'exec.mode.defaultSuffix': ' (default)', 'exec.mode.brokenSuffix': ' (unavailable)', 'exec.mode.removed': ' (removed)', 'exec.permission.default': 'Session default', 'exec.permission.read-only': 'Read-only', 'exec.permission.workspace-write': 'Workspace Write', 'exec.permission.danger-full-access': 'Full Access', 'exec.model.default': 'Host default (agent-default-model)', 'exec.model.unknown': ' (unknown / fallback to default)', 'exec.reuseSession': 'Continue in the same conversation', 'exec.reuseSessionHint': 'When on, later runs continue in the previous session (when that session is idle and still exists) instead of starting a new conversation each time; the pinned permission and model above are re-applied on every reuse.', 'detail.executionSettings': 'Execution Settings', '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.', // Plugin settings card (the `settings.plugin.item` seat). 'settings.title': 'Task Board', 'settings.description': 'Configure the Host task board, agent announcement, and idle-system-sleep protection while work is pending.', 'settings.enabled': 'Enable the task board', 'settings.enabledHint': 'When off, the sidebar entry and board view are hidden.', 'settings.announceToAgent': 'Announce the task board to agents', '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.', 'settings.preventIdleSleep': 'Prevent idle system sleep', '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.', 'settings.powerStatus': 'Platform: {platform}; protection: {phase}; running sessions: {running}; enabled schedules: {schedules}', '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.', 'settings.powerUnknown': 'unknown', 'settings.powerError': 'Latest power-protection error: {error}', 'settings.inherit': 'Inherit', 'settings.on': 'On', 'settings.off': 'Off', 'settings.overridden': 'Overridden', 'settings.reset': 'Reset to default', 'settings.notExposed': 'This DSH version does not expose this plugin\'s settings namespace to the configuration page, so the form is unavailable. Edit ~/.dsh/settings.yaml directly, or add the namespace to the Host settings allowlist and restart.', 'settings.readOnly': 'This deployment stores settings read-only.', 'settings.expand': 'Show settings', 'settings.collapse': 'Hide settings', 'settings.save': 'Save', 'settings.saving': 'Saving…', 'settings.discard': 'Discard', 'settings.unsaved': 'Unsaved', 'settings.saveFailed': 'The deployment did not accept these values; they were left for you to correct.', 'settings.invalidNumber': 'Enter a number, or leave blank to use the default.', } /** The dictionary key union. */ export type TaskBoardKey = keyof typeof zh /** The settings-card slice of the task-board dictionary. */ export type SettingsCardKey = TaskBoardKey /** Active dictionary, picked by the document language at call time. */ export function dictionary(): Record { const lang = typeof document !== 'undefined' ? document.documentElement.lang : 'zh' return lang.toLowerCase().startsWith('en') ? en : zh } /** * SDK translate seat wired by the browser apply() once ctx.locale is bound * (setRuntimeTranslate). When present it reads the ACTIVE locale at call * time, so plain-DOM surfaces (sidebar row, toggles) follow a runtime * language switch; the document-language pick above stays only as the * unwired fallback (locale service absent, module-scope early callers). */ let runtimeT: ((key: TaskBoardKey, params?: Record) => string) | undefined /** Wire the SDK translate seat; pass undefined to restore the document-language pick. */ export function setRuntimeTranslate(t: ((key: TaskBoardKey, params?: Record) => string) | undefined): void { runtimeT = t } /** Translate a key with optional {name} template params. */ export function t(key: TaskBoardKey, params?: Record): string { if (runtimeT !== undefined) return runtimeT(key, params) let text: string = dictionary()[key] if (params !== undefined) { for (const [name, value] of Object.entries(params)) { text = text.replaceAll(`{${name}}`, value) } } return text }