From 72abfe5ee11146e2d7edb2b4e4ce75d34d21987b Mon Sep 17 00:00:00 2001 From: JaJa Date: Wed, 9 Sep 2026 19:49:29 +0300 Subject: [PATCH 1/3] feat: add localized task templates --- lib/client.js | 38 +++---- lib/host/execution.js | 3 + lib/host/execution.js.map | 2 +- lib/host/locale.js | 17 +++ lib/host/locale.js.map | 1 + lib/host/routes.js | 28 ++++- lib/host/routes.js.map | 2 +- lib/host/scheduler.js | 2 + lib/host/scheduler.js.map | 2 +- lib/host/session-sync.js | 3 + lib/host/session-sync.js.map | 2 +- lib/host/templates.js | 86 ++------------- lib/host/templates.js.map | 2 +- lib/shared/builtin-templates.js | 155 +++++++++++++++++++++++++++ lib/shared/builtin-templates.js.map | 1 + lib/shared/protocol.js.map | 2 +- src/client/board/TaskBoard.tsx | 27 +++-- src/client/board/TaskDetail.tsx | 26 ++++- src/client/board/TemplateManager.tsx | 32 ++++-- src/client/i18n/en.ts | 10 ++ src/client/i18n/templates.ts | 25 +++++ src/client/i18n/zh.ts | 10 ++ src/host/execution.ts | 3 + src/host/locale.ts | 44 ++++++++ src/host/routes.ts | 30 +++++- src/host/scheduler.ts | 2 + src/host/session-sync.ts | 3 + src/host/templates.ts | 67 ++---------- src/shared/builtin-templates.ts | 153 ++++++++++++++++++++++++++ src/shared/protocol.ts | 19 ++++ tests/host-locale.spec.ts | 42 ++++++++ tests/i18n.spec.ts | 73 +++++++++++++ tests/templates.spec.ts | 14 +++ 33 files changed, 727 insertions(+), 199 deletions(-) create mode 100644 lib/host/locale.js create mode 100644 lib/host/locale.js.map create mode 100644 lib/shared/builtin-templates.js create mode 100644 lib/shared/builtin-templates.js.map create mode 100644 src/client/i18n/templates.ts create mode 100644 src/host/locale.ts create mode 100644 src/shared/builtin-templates.ts create mode 100644 tests/host-locale.spec.ts diff --git a/lib/client.js b/lib/client.js index 6a6dc2a..9955307 100644 --- a/lib/client.js +++ b/lib/client.js @@ -5,8 +5,8 @@ window.__ModuleLoader__.load({ var exports = module.exports; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("react-dom/client"),n=require("react/jsx-runtime"),r=require("react-dom");async function i(e){let t=await e,n=await t.json().catch(()=>null);if(n===null)throw Error(`taskboard: HTTP ${t.status}`);if(!n.ok)throw Error(`taskboard: ${n.error.code}: ${n.error.message}`);return n.value}const a=1e4;async function o(e){return i(fetch(e,{signal:AbortSignal.timeout(a)}))}async function s(e,t){return i(await fetch(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t),signal:AbortSignal.timeout(a)}))}function c(){return{state:()=>o(`/dsh-taskboard/state`),workspaces:()=>o(`/dsh-taskboard/workspaces`),create:e=>s(`/dsh-taskboard/tasks`,e),get:e=>o(`/dsh-taskboard/tasks/${encodeURIComponent(e)}`),update:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/update`,t),move:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/move`,t),reject:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/reject`,t),comment:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/comment`,{body:t}),remove:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/delete`,t),run:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/run`,t??{}),cancel:e=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/cancel`,{}),mergeBranch:e=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/merge`,{}),worktreeRemove:(e,t)=>s(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/worktree-remove`,t),diagnostics:()=>o(`/dsh-taskboard/diagnostics`),worktreeCleanup:(e,t)=>s(`/dsh-taskboard/worktree-cleanup`,{workspaceId:e,taskId:t}),diff:(e,t)=>{let n=new URLSearchParams({execution:t.execution});return t.commit!==void 0&&n.set(`commit`,t.commit),t.path!==void 0&&n.set(`path`,t.path),t.repo!==void 0&&n.set(`repo`,t.repo),o(`/dsh-taskboard/tasks/${encodeURIComponent(e)}/diff?${n.toString()}`)},importPreview:e=>s(`/dsh-taskboard/import/preview`,e),importCommit:(e,t)=>s(`/dsh-taskboard/import`,{mode:e,ledger:t}),templates:()=>o(`/dsh-taskboard/templates`),templateUpsert:e=>s(`/dsh-taskboard/templates`,e),templateDelete:e=>s(`/dsh-taskboard/templates/delete`,{id:e}),settings:()=>o(`/dsh-taskboard/settings`),updateSettings:e=>s(`/dsh-taskboard/settings/update`,e),promptCompletions:()=>o(`/dsh-taskboard/prompt-completions`),modelCatalog:()=>o(`/dsh-taskboard/model-catalog`),stream(e,t){let n=new EventSource(`/dsh-taskboard/events`),r;return n.addEventListener(`hello`,e=>{let n;try{n=JSON.parse(e.data)}catch{return}r!==void 0&&n.revision!==r&&t(),r=n.revision}),n.addEventListener(`change`,n=>{let i;try{i=JSON.parse(n.data)}catch{return}r!==void 0&&i.revision!==r+1&&t(),r=i.revision,e(i)}),n.onerror=()=>{},()=>{n.close()}}}}const l=[`backlog`,`todo`,`in_progress`,`in_review`,`done`],u=[`canceled`,`archived`];[...l,...u];const d={backlog:[`todo`,`canceled`],todo:[`in_progress`,`backlog`,`canceled`],in_progress:[`in_review`,`todo`,`canceled`],in_review:[`in_progress`,`todo`,`done`,`canceled`],done:[`archived`],canceled:[`archived`,`todo`],archived:[]};function f(e,t){return d[e].includes(t)}function p(e){if(typeof e!=`string`)return`workspace-write`;let t=e.trim();if(t===`workspace-write`||t===`workspaceWrite`)return`workspace-write`;if(t===`read-only`||t===`readOnly`)return`read-only`;if(t===`danger-full-access`||t===`fullAccess`)return`danger-full-access`;throw Error(`permission must be 'workspace-write', 'read-only', or 'danger-full-access'`)}function m(e){return e?.defaultIsolation??`none`}function h(e){return e?.syncExternalSessions??!1}function g(e){return e?.defaultPermission??`workspace-write`}function _(e){let t=e.trim().split(/\s+/);if(t.length!==5)return null;let n=[[0,59],[0,23],[1,31],[1,12],[0,7]],r=[];for(let e=0;e<5;e++){let[i,a]=n[e],o=new Set;if(!v(t[e],i,a,o))return null;r.push(o)}let i=new Set;for(let e of r[4])i.add(e===7?0:e);return{minutes:r[0],hours:r[1],days:r[2],months:r[3],weekdays:i}}function v(e,t,n,r){for(let i of e.split(`,`)){let[e,a]=i.split(`/`),o=a===void 0?1:Number.parseInt(a,10);if(!Number.isInteger(o)||o<1)return!1;let s,c;if(e===void 0||e===``)return!1;if(e===`*`)s=t,c=n;else if(e.includes(`-`)){let[t,n]=e.split(`-`);if(s=Number.parseInt(t??``,10),c=Number.parseInt(n??``,10),!Number.isInteger(s)||!Number.isInteger(c))return!1}else{if(s=Number.parseInt(e,10),!Number.isInteger(s))return!1;c=a===void 0?s:n}if(sn||s>c)return!1;for(let e=s;e<=c;e+=o)r.add(e)}return r.size>0}function y(e,t){let n=new Date(t);n.setSeconds(0,0),n.setMinutes(n.getMinutes()+1);let r=t+4*366*24*60*60*1e3,i=n.getTime();for(;i<=r;){let t=new Date(i);if(e.months.has(t.getMonth()+1)&&e.days.has(t.getDate())&&e.weekdays.has(t.getDay())&&e.hours.has(t.getHours())&&e.minutes.has(t.getMinutes()))return i;i+=6e4}return null}function b(){return{schemaVersion:1,revision:0,tasks:[]}}function x(e){let t=e.checklist??[];return{done:t.filter(e=>e.checked).length,total:t.length}}const S={zh:{"shared.close":`关闭`,"shared.cancel":`取消`,"shared.loading":`读取中…`,"shared.blocked":`受阻`,"shared.permission":`权限`,"shared.confirmDelete":`确认删除`,"shared.current":`(当前:{name})`,"shared.entry.aria":`Agent 任务看板`,"shared.entry.label":`任务看板`,"shared.stats.title":`待办 {todo} | 进行中 {doing} | 待验收 {review}(待办|进行中|待验收)`,"shared.duplicate.suffix":`(副本)`,"status.column.backlog":`待规划`,"status.column.todo":`待办`,"status.column.in_progress":`进行中`,"status.column.in_review":`待验收`,"status.column.done":`已完成`,"status.column.canceled":`已取消`,"status.column.archived":`已归档`,"status.pill.backlog":`待规划`,"status.pill.todo":`待办`,"status.pill.in_progress":`进行中`,"status.pill.in_review":`待验收`,"status.pill.done":`完成`,"status.pill.canceled":`取消`,"status.pill.archived":`归档`,"status.move.backlog":`待规划`,"status.move.todo":`待办`,"status.move.in_progress":`进行中`,"status.move.in_review":`待验收`,"status.move.done":`完成`,"status.move.canceled":`取消`,"status.move.archived":`归档`,"urgency.urgent":`紧急`,"urgency.normal":`一般`,"urgency.relaxed":`不急`,"outcome.running":`执行中`,"outcome.succeeded":`成功`,"outcome.failed":`失败`,"outcome.cancelled":`已取消`,"board.title":`Agent 任务看板`,"board.count.tasks":`{n} 任务 · rev {rev}`,"board.action.newTask":`+ 新建任务 ▼`,"board.action.blankTask":`空白任务`,"board.action.manageTemplates":`⌗ 管理模板…`,"board.search.placeholder":`搜索标题 / ID…`,"board.filter.allProjects":`全部项目`,"board.sort.title":`列内排序`,"board.sort.default":`默认排序`,"board.sort.updated":`最近更新`,"board.sort.urgency":`按紧急度`,"board.sort.created":`创建时间`,"board.sort.byTitle":`按标题`,"board.action.backToBoard":`返回看板`,"board.action.otherTasks":`其它任务`,"board.action.settingsTitle":`看板设置:新建任务的默认执行隔离等`,"board.action.settings":`🛠 设置`,"board.action.diagTitle":`健康诊断:遗留 worktree、台账基本项`,"board.action.diag":`⚙ 诊断`,"board.action.importTitle":`从 JSON 备份文件导入台账(预览后合并或整册替换)`,"board.action.import":`⬆ 导入`,"board.action.exportTitle":`导出台账:完整 JSON 备份或任务清单 CSV`,"board.action.export":`⬇ 导出 ▼`,"board.export.jsonTitle":`完整台账备份(含执行历史与看板设置),可用于导入恢复`,"board.export.json":`完整台账(JSON)`,"board.export.csvTitle":`任务清单表格(Excel 可直接打开,中文已加 BOM)`,"board.export.csv":`任务清单(CSV)`,"board.drag.forbidden":`无法从「{from}」拖至「{to}」`,"board.empty":`无任务`,"board.secondary.empty":`无已取消 / 已归档 / 已删除任务`,"board.group.trashed":`已删除`,"diag.title":`健康诊断`,"diag.subtitle":`台账基本项与 worktree 遗留清理`,"diag.revision":`台账修订号`,"diag.tasks":`任务总数`,"diag.running":`执行中`,"diag.orphans":`遗留 worktree`,"diag.orphans.heading":`遗留 worktree(台账无主但目录存在)`,"diag.orphans.none":`无遗留 — 各项目 .dsh-worktrees 目录干净`,"diag.orphans.cleanup":`清理`,"diag.orphans.hint":`提示:有未提交修改的遗留目录会被拒绝清理,请先手动处理其内容。live 任务的 worktree 请在任务详情页删除。`,"diag.gitignore.heading":`gitignore 建议`,"diag.gitignore.none":`无待办 — 各 git 项目已忽略 .dsh-worktrees 目录`,"diag.gitignore.suggestA":`建议在 .gitignore 加入一行`,"diag.gitignore.suggestB":`(不会自动修改)`,"card.drag.running":`该任务正由会话执行中({title}),不能拖动`,"card.badge.stale":`⏱ 认领超时`,"card.badge.modelTitle":`固定模型: {model}`,"card.badge.modelEffort":` · 思考强度: {effort}`,"card.badge.checklistReview":`待验收:清单未全部勾选`,"card.badge.checklist":`验收清单进度`,"card.badge.pendingPurge":`待清除`,"card.session.jumpTitle":`点击一键跳转到会话:{id}`,"card.session.missing":`该会话已被删除({id}),无法打开`,"card.session.archived":`该会话已归档({id}),已从会话列表隐藏`,"card.session.unavailable":`会话导航不可用,会话 ID:{id}`,"card.reject.placeholder":`退回原因(可选,agent 开工前会读)…`,"card.reject.confirm":`退回待办`,"card.action.doneTitle":`验收完成:移至已完成`,"card.action.done":`✓ 完成`,"card.action.rejectTitle":`退回待办,可附退回原因`,"card.action.reject":`✗ 退回`,"alert.ok":`知道了`,"diff.commit":`提交 {hash}`,"diff.file":`文件 {path}`,"diff.truncated":`⚠ 内容过长已截断`,"diff.failed":`获取失败(原因见看板顶部错误条;对象可能已随 worktree 删除丢失)`,"checklist.title":`验收清单(DoD)`,"checklist.unchecked":` · {n} 项未完成`,"checklist.allDone":` · 全部完成`,"checklist.byUser":`👤 用户`,"checklist.uncheckedItem":`未完成`,"checklist.evidence":`证据:{note}`,"report.title":`执行报告`,"report.submitted":`由执行会话提交 · {time}`,"report.changedFiles":`改动文件`,"report.checks":`自验情况`,"report.artifacts":`产物`,"report.risk":`剩余风险`,"iso.title":`执行隔离`,"iso.none":`📁 原目录执行`,"iso.worktreeTitle":`执行隔离 · Worktree`,"iso.branch":`🌿 分支`,"iso.baseline":`基线 {base} → {head}`,"iso.changed":`改动 {n} 个文件`,"iso.commit.openTitle":`点击展开该提交的 diff`,"iso.commits.more":`… 共 {n} 个提交`,"iso.nocommit":`该次执行没有产生提交(改动可能未提交,见下方警告)`,"iso.dirty.toggle":`⚠ 有 {n} 处未提交修改(合并前请让 agent 提交,或手动处理)`,"iso.dirty.expand":` ▼ 查看文件`,"iso.dirty.collapse":` ▲`,"iso.dirty.openTitle":`点击查看该文件的未提交 diff`,"iso.dirty.more":`… 共 {n} 处(完整列表见任务台账)`,"iso.hint.running":`执行中 — 结束后可合并或清理`,"iso.merge.confirm":`将分支以 --no-ff 合并到主工作区?`,"iso.merge.go":`确认合并`,"iso.merge.title":`在主工作区 git merge --no-ff 该任务分支(要求主区干净;冲突会原样报告)`,"iso.merge.button":`⇥ 合并到主工作区`,"iso.merge.failed":`合并失败:{error}`,"iso.merge.noop":`该分支没有领先主工作区的新提交,无需合并(可退回续跑或直接清理)`,"iso.merge.done":`已按仓库合并(--no-ff):{summary}`,"iso.merge.partial":`部分仓库合并失败:{summary} - {error}`,"iso.repo.root":`根仓库`,"iso.remove.wt":`🗑 删除 worktree`,"iso.remove.wtTitle":`git worktree remove(有未提交修改时拒绝)`,"iso.remove.wtb":`🗑 删 worktree + 分支`,"iso.remove.wtbTitle":`删除 worktree 并删除任务分支(有未提交修改时拒绝)`,"iso.remove.confirmWt":`删除 worktree 目录?`,"iso.remove.confirmWtb":`删除 worktree 并删除分支?`,"iso.remove.failed":`删除失败:{error}`,"iso.remove.branchFailed":`worktree 已删除,但分支删除失败:{error}`,"iso.hint.keep":`分支与 worktree 保留中 — 可退回继续修改`,"detail.session.jumpTitle":`一键跳转到对应会话:{id}`,"detail.session.jump":`🤖 跳转会话 ↗`,"detail.action.edit":`✎ 编辑`,"detail.action.duplicateTitle":`复制此任务的全部配置为一张新卡(待办列)`,"detail.action.duplicate":`⧉ 复制`,"detail.action.saveTplTitle":`把此任务的配置(含清单)保存为模板,新建任务时可用`,"detail.action.saveTplDone":`已存为模板(新建任务 ▼ 下拉可用,可在模板管理中改名)`,"detail.action.saveTpl":`⌗ 存为模板`,"detail.action.reuseTitle":`续跑:保留现有 worktree 与分支(上次的改动和提交都在原处),在其上继续执行;默认「立即执行」会重置为全新基线`,"detail.action.reuse":`↻ 续跑`,"detail.action.runTitleModel":`新会话执行({model})`,"detail.action.runTitleDefault":`新会话执行(默认模型)`,"detail.action.run":`▶ 立即执行`,"detail.action.stopConfirm":`停止该执行会话?`,"detail.action.stop":`停止`,"detail.action.stopTitle":`停止执行会话 {id}(任务回到待办)`,"detail.action.stopExec":`■ 停止执行`,"detail.chip.nextRun":`{cron} · 下次 {time}`,"detail.chip.checklist":`清单 {done}/{total}`,"detail.chip.isolated":`Worktree 隔离`,"detail.chip.holderTitle":`点击跳转至该会话:{id}`,"detail.chip.holderStale":`认领超时 · `,"detail.chip.holderBy":`由 `,"detail.chip.holderSuffix":` 持有 ↗`,"detail.chip.trashed":`已删除待清除`,"detail.sub.line":`更新 {time} · 最近操作 {who}`,"detail.updatedBy.system":`⚙️ 系统`,"detail.updatedBy.user":`👤 用户`,"detail.field.description":`描述`,"detail.field.prompt":`执行 Prompt`,"detail.move.to":`移至→{status}`,"detail.move.confirmDoneUnchecked":`仍有 {n} 项清单未勾选,确认完成?`,"detail.move.confirmDone":`确认完成?`,"detail.move.confirm":`确认`,"detail.blocked.unmark":`✓ 解除受阻`,"detail.blocked.mark":`⛔ 标记受阻`,"detail.release.title":`释放 {id} 的认领:任务回到待办(持有会话可能仍在工作,确认它已停止后再释放)`,"detail.release.button":`🔓 释放认领`,"detail.comments.title":`评论`,"detail.comments.empty":`暂无评论 — agent 交接时会在这里汇报改动与验证结果`,"detail.comments.user":`用户`,"detail.composer.placeholder":`以用户身份留言(agent 开工前会读)…`,"detail.composer.send":`发表`,"detail.exec.title":`执行记录`,"detail.exec.prunedTitle":`更早的 {n} 条执行记录已按保留上限清理`,"detail.exec.pruned":`+{n} 已清理`,"detail.exec.trigger.manual":`手动`,"detail.exec.trigger.scheduled":`定时`,"detail.exec.openTitle":`点击打开该执行会话:{id}`,"detail.danger.delete":`🗑 删除(标记待清除)`,"detail.danger.purgeConfirm":`物理清除不可恢复`,"detail.danger.purgeGo":`确认清除`,"detail.danger.purge":`🔥 物理清除(需确认)`,"form.title.create":`新建任务`,"form.title.edit":`编辑任务`,"form.subtitle.create":`推入看板,项目内会话可认领执行`,"form.subtitle.edit":`调整任务内容与执行配置`,"form.field.title":`标题`,"form.field.titlePlaceholder":`一句话说清要做什么`,"form.field.project":`项目`,"form.field.model":`模型(默认 = 会话默认模型)`,"form.field.modelDefault":`默认模型`,"form.model.option":`{name}({provider})`,"form.field.effort":`思考强度(Reasoning Effort)`,"form.field.effortTitle":`设置模型的思考强度(如 low/medium/high);默认 = 跟随模型/提供商默认`,"form.effort.follow":`跟随模型默认`,"form.effort.low":`低 (low)`,"form.effort.medium":`中 (medium)`,"form.effort.high":`高 (high)`,"form.effort.none":`关闭思考 (none)`,"form.field.preset":`执行模式(preset)`,"form.field.presetTitle":`执行会话按该 preset 组合(决定工具集与人设);默认 = 部署默认 preset`,"form.preset.follow":`跟随部署默认`,"form.preset.defaultTag":`(部署默认)`,"form.field.urgency":`紧急度`,"form.urgency.urgent":`紧急`,"form.urgency.urgentHint":`优先处理`,"form.urgency.normal":`一般`,"form.urgency.normalHint":`正常排期`,"form.urgency.relaxed":`不急`,"form.urgency.relaxedHint":`有空再做`,"form.field.description":`描述`,"form.field.descriptionOptional":`描述(可选)`,"form.desc.placeholder":`需求细节、背景说明、验收标准…`,"form.field.prompt":`执行 Prompt(实际 Prompt = 标题+任务描述+Prompt)`,"form.field.promptOptional":`执行 Prompt(可选;实际 Prompt = 标题+任务描述+Prompt)`,"form.prompt.placeholder":`追加在「标题+任务描述」之后发给执行会话的补充指令。支持模板变量:{{lastExecution}}(上次执行结果)、{{lastComments}}(最近 3 条评论)`,"form.field.mode":`执行方式`,"form.mode.claim":`🤝 认领制`,"form.mode.claimHint":`项目内会话认领`,"form.mode.scheduled":`⏰ 定时执行`,"form.mode.scheduledHint":`到点自动开跑`,"form.field.cron":`Cron 表达式`,"form.cron.placeholder":`分 时 日 月 周`,"form.cron.daily":`每天 09:00`,"form.cron.hourly":`每小时`,"form.cron.every10min":`每 10 分钟`,"form.cron.weekly":`每周一 09:00`,"form.cron.next":`下次 {time}`,"form.field.isolation":`执行隔离`,"form.iso.locked":`任务已有执行记录,隔离方式已锁定`,"form.iso.lockedShort":`已锁定(执行开始后不可更改)`,"form.iso.nonGit":`当前项目非 git 仓库`,"form.iso.worktree":`🌿 Worktree 隔离`,"form.iso.worktreeTitle":`每次执行在独立 worktree 分支上进行`,"form.iso.worktreeHint":`独立分支 task/标题+ID,互不污染`,"form.iso.none":`📁 原目录执行`,"form.iso.noneTitle":`直接在项目目录执行(不使用 git)`,"form.iso.noneHintNonGit":`当前项目非 git 仓库,将在原目录执行`,"form.iso.noneHint":`不使用 git,直接在项目目录工作`,"form.iso.nonGitNote":`当前项目非 git 仓库,将在原目录执行(任务仍按默认配置创建,运行时自动降级)`,"form.iso.mirrorNote":`多仓库工作区:Worktree 隔离将自动整区镜像 {n} 个仓库——每仓库独立任务分支,验收按仓库合并`,"form.field.checklist":`验收清单(DoD)`,"form.field.checklistOptional":`验收清单(DoD,可选)`,"form.check.itemPlaceholder":`验收项 {n}(完成标准)`,"form.check.removeTitle":`删除该验收项`,"form.check.add":`+ 添加验收项`,"form.check.checkedTitle":`勾选状态随保存保留(当前勾选人:{who})`,"form.check.notCheckedYet":`未勾选`,"form.check.hintCreate":`共 {n} 项,执行会话按清单干活并逐项勾选,未完成项验收时高亮`,"form.check.hintEdit":`已勾选 {checked}/{total}(保存将整体覆盖清单,勾选状态保留)`,"form.hint.needTitle":`请填写标题`,"form.hint.needProject":`请选择项目`,"form.hint.cronBad":`Cron 表达式无效(分 时 日 月 周)`,"form.hint.nextRun":`下次运行 {time}`,"form.hint.saveVersion":`保存后版本 v{v} → v{next}`,"form.hint.createClaim":`创建后项目内会话可认领执行`,"form.action.runBlockedTitle":`任务正在执行中,不能重复发起`,"form.action.runBusyTitle":`正在提交…`,"form.action.runTitle":`保存后立即发起执行(新会话)`,"form.action.run":`⚡ 立即执行`,"form.action.save":`保存修改`,"form.action.create":`创建任务`,"tpl.aria":`管理模板`,"tpl.title":`任务模板`,"tpl.subtitle":`新建任务 ▼ 下拉的模板:改名 / 删除 / 直接使用;任务详情页「存为模板」可新增`,"tpl.empty":`暂无模板 — 在任务详情页点「存为模板」把常用配置沉淀下来`,"tpl.name.aria":`模板名 {name}`,"tpl.builtin":`内置`,"tpl.custom":`自建`,"tpl.meta.checklist":` · 清单 {n} 项`,"tpl.rename.title":`保存改名`,"tpl.rename.button":`改名`,"tpl.use.title":`用此模板打开新建表单`,"tpl.use.button":`用此新建`,"tpl.delete.title":`删除该模板`,"tpl.renamed":`模板已改名`,"tpl.foot.hint":`模板随台账一同保存在 DSH 主目录,升级不丢`,"imp.aria":`导入台账`,"imp.title":`导入台账`,"imp.subtitle":`选择导出的 JSON 备份文件:先预览、再合并或整册替换`,"imp.parseError":`文件不是合法 JSON`,"imp.note":`⬇ JSON 导出的文件即为同格式备份,可直接导入恢复;导入文件的 schemaVersion 必须与当前版本一致。`,"imp.previewing":`预览中…`,"imp.stat.create":`新增`,"imp.stat.overwrite":`覆盖(同 id)`,"imp.stat.invalid":`无效(跳过)`,"imp.sec.create":`新增任务`,"imp.sec.overwrite":`覆盖任务(整卡替换,含执行历史与评论)`,"imp.sec.invalid":`无效条目(不会导入)`,"imp.noId":`(无 id)`,"imp.mode.merge":`⊕ 合并`,"imp.mode.mergeHint":`新增 + 按 id 覆盖,其余不动`,"imp.mode.replace":`💣 整册替换`,"imp.mode.replaceHint":`清空当前台账,以导入文件为准(先自动备份)`,"imp.result.replace":`整册替换完成:导入 {n} 张(原 {total} 张已整册备份)`,"imp.result.merge":`合并完成:新增 {n} 张、覆盖 {m} 张`,"imp.foot.replaceConfirm":`⚠ 再次点击确认执行整册替换(不可撤销,已自动备份)`,"imp.foot.replaceNeedConfirm":`整册替换需要二次确认`,"imp.foot.mergeHint":`合并只写入预览中列出的任务`,"imp.action.run":`执行导入`,"imp.action.confirmReplace":`确认整册替换`,"set.aria":`看板设置`,"set.title":`看板设置`,"set.subtitle":`新建任务与会话同步的全局默认值`,"set.iso.heading":`默认执行隔离`,"set.iso.noneHint":`不使用 git,直接在项目目录工作(出厂默认)`,"set.iso.worktreeHint":`每次执行在独立 worktree 分支上进行(task/标题+ID),互不污染;多仓库工作区自动整区镜像(每仓库独立分支)`,"set.iso.current":`当前保存的默认:{current}。仅影响之后新建的任务;已有任务保持创建时的选择,非 git 项目运行时仍自动降级原目录。`,"set.sync.heading":`自动同步工作区会话`,"set.sync.off.name":`🚫 关闭同步`,"set.sync.off.title":`仅管理在任务看板中创建和触发的任务`,"set.sync.off.hint":`仅管理看板任务(出厂默认)`,"set.sync.on.name":`🔄 自动纳入会话`,"set.sync.on.title":`各工作区直接新建的会话也会在看板展示,运行中进入「进行中」,完成后自动进入「待验收」`,"set.sync.on.hint":`跟踪运行并在完成后进入待验收`,"set.sync.stateOn":`已开启:工作区直接新建并执行的会话将自动在看板生成任务卡片,并在完成后流转至「待验收」列。`,"set.sync.stateOff":`已关闭:仅在看板内部创建与触发执行的任务会出现在看板上。`,"set.foot.dirty":`有未保存的修改`,"set.foot.clean":`与看板当前设置一致`,"set.action.save":`保存设置`,"form.field.permission":`执行权限`,"form.perm.write":`可写入工作区`,"form.perm.writeHint":`可读写工作区及临时目录(推荐默认)`,"form.perm.readOnly":`仅可查看`,"form.perm.readOnlyHint":`只读查看与检索,禁止修改文件或执行外部命令`,"form.perm.fullAccess":`完全权限`,"form.perm.fullAccessHint":`完全无限制权限,可访问全盘及执行外部命令`,"form.perm.defaultTag":`(默认)`,"set.perm.heading":`默认执行权限`,"set.perm.writeName":`📁 可写入工作区(出厂默认)`,"set.perm.writeHint":`可读写工作区及临时目录,写操作无需二次确认`,"set.perm.readOnlyName":`🔒 仅可查看`,"set.perm.readOnlyHint":`仅允许只读查看与检索,禁止修改文件或破坏性命令`,"set.perm.fullName":`⚡ 完全权限`,"set.perm.fullHint":`完全无限制权限,可访问全盘及执行系统外部命令`,"set.perm.current":`当前保存的默认:{current}。新建任务时预设的执行权限。`,"card.badge.permReadOnly":`🔒 仅查看`,"card.badge.permReadOnlyTitle":`权限:仅可查看`,"card.badge.permFull":`⚡ 全权限`,"card.badge.permFullTitle":`权限:完全权限`,"detail.chip.permReadOnly":`仅可查看`,"detail.chip.permFull":`完全权限`,"detail.chip.permWrite":`可写入工作区`,"tpl.meta.permReadOnly":`仅查看`,"tpl.meta.permFull":`全权限`,"md.imageAlt":`图片 {n}`,"md.imageTitle":`点击查看大图 ({alt})`,"md.lightboxAlt":`大图预览`,"md.closePreview":`关闭预览`,"slash.aria":`快捷命令与技能`,"slash.title":`快捷命令与技能补全`,"slash.hint":`↑↓ 选择 · Enter / Tab 确认 · Esc 关闭`,"slash.badge.command":`⚡ 命令`,"slash.badge.skill":`🧩 技能`,"slash.tipA":`💡 输入`,"slash.tipB":`可快速补全 Slash 命令与 Agent 技能`,"slash.cmd.goal.desc":`自主完成长期目标任务,持续深度推进`,"slash.cmd.goal.hint":`<目标描述>`,"slash.cmd.schedule.desc":`设置一次性定时或周期性 Cron 调度`,"slash.cmd.schedule.hint":`<时间/表达式>`,"slash.cmd.plan.desc":`在行动前制定分步实施计划并由用户确认`,"slash.cmd.browser.desc":`启动网页浏览器交互与实时页面检索`,"slash.cmd.grill-me.desc":`通过多轮单题访谈深入对齐需求与设计意图`,"slash.cmd.teamwork-preview.desc":`多智能体协作与团队工作流预览`,"slash.cmd.learn.desc":`沉淀解决经验与新规则到知识库`,"slash.cmd.review.desc":`多维度代码审查(正确性、架构与安全)`,"slash.cmd.security.desc":`安全加固与代码漏洞扫描`,"slash.cmd.permission.desc":`切换当前会话权限级别 (read-only / workspace-write / full-access)`,"slash.cmd.permission.hint":``,"slash.skill.frontend-ui-engineering":`构建生产级、可访问的高品质前端界面与组件`,"slash.skill.api-and-interface-design":`设计稳定契约、清晰边界的 REST / RPC 接口`,"slash.skill.test-driven-development":`测试驱动开发(TDD),编写单元与集成测试`,"slash.skill.debugging-and-error-recovery":`系统化定位 Bug 根因并恢复错误`,"slash.skill.performance-optimization":`前后端性能调优、减少渲染开销与查询优化`,"slash.skill.ci-cd-and-automation":`自动化构建、CI/CD 流水线与质量门禁`,"slash.skill.code-review-and-quality":`多轴向代码审查与重构指导`,"slash.skill.code-simplification":`精简复杂逻辑,提升可读性与可维护性`,"slash.skill.context-engineering":`优化上下文结构与提示词工程`,"slash.skill.doubt-driven-development":`以怀疑驱动的对抗式审查,确保核心逻辑正确`,"slash.skill.git-workflow-and-versioning":`Git 工作流、分支管理、语义化版本与变更日志`,"slash.skill.idea-refine":`通过发散与收敛思维细化方案与假设检验`,"slash.skill.incremental-implementation":`小步快跑、增量交付多文件变更`,"slash.skill.interview-me":`深度访谈挖掘真实意图`,"slash.skill.memory-leak-debugging":`排查诊断 JavaScript/Node.js 内存泄漏`,"slash.skill.observability-and-instrumentation":`添加日志、指标打点与链路追踪`,"slash.skill.planning-and-task-breakdown":`将复杂需求拆解为有序可执行任务`,"slash.skill.security-and-hardening":`防御安全漏洞、输入过滤与鉴权加固`,"slash.skill.shipping-and-launch":`生产发布前检查清单与回滚策略`,"slash.skill.source-driven-development":`基于权威官方文档与源码进行设计实现`,"slash.skill.spec-driven-development":`在编码前制定清晰的技术规范`,"slash.skill.using-agent-skills":`发现并动态调用智能体各项专业技能`},en:{"shared.close":`Close`,"shared.cancel":`Cancel`,"shared.loading":`Loading…`,"shared.blocked":`Blocked`,"shared.permission":`Permission`,"shared.confirmDelete":`Delete`,"shared.current":` (current: {name})`,"shared.entry.aria":`Agent task board`,"shared.entry.label":`Task board`,"shared.stats.title":`To do {todo} | In progress {doing} | In review {review} (todo | in progress | in review)`,"shared.duplicate.suffix":` (copy)`,"status.column.backlog":`Backlog`,"status.column.todo":`To do`,"status.column.in_progress":`In progress`,"status.column.in_review":`In review`,"status.column.done":`Done`,"status.column.canceled":`Canceled`,"status.column.archived":`Archived`,"status.pill.backlog":`Planned`,"status.pill.todo":`To do`,"status.pill.in_progress":`In progress`,"status.pill.in_review":`In review`,"status.pill.done":`Done`,"status.pill.canceled":`Canceled`,"status.pill.archived":`Archived`,"status.move.backlog":`Backlog`,"status.move.todo":`To do`,"status.move.in_progress":`In progress`,"status.move.in_review":`In review`,"status.move.done":`Done`,"status.move.canceled":`Canceled`,"status.move.archived":`Archived`,"urgency.urgent":`Urgent`,"urgency.normal":`Normal`,"urgency.relaxed":`Relaxed`,"outcome.running":`Running`,"outcome.succeeded":`Succeeded`,"outcome.failed":`Failed`,"outcome.cancelled":`Canceled`,"board.title":`Agent Task Board`,"board.count.tasks":`{n} tasks · rev {rev}`,"board.action.newTask":`+ New Task ▼`,"board.action.blankTask":`Blank task`,"board.action.manageTemplates":`⌗ Manage templates…`,"board.search.placeholder":`Search title / ID…`,"board.filter.allProjects":`All projects`,"board.sort.title":`Sort within columns`,"board.sort.default":`Default order`,"board.sort.updated":`Recently updated`,"board.sort.urgency":`By urgency`,"board.sort.created":`Creation time`,"board.sort.byTitle":`By title`,"board.action.backToBoard":`Back to board`,"board.action.otherTasks":`Other tasks`,"board.action.settingsTitle":`Board settings: default execution isolation for new tasks, etc.`,"board.action.settings":`🛠 Settings`,"board.action.diagTitle":`Health diagnostics: orphan worktrees, ledger basics`,"board.action.diag":`⚙ Diagnostics`,"board.action.importTitle":`Import the ledger from a JSON backup (preview, then merge or replace)`,"board.action.import":`⬆ Import`,"board.action.exportTitle":`Export the ledger: full JSON backup or task-list CSV`,"board.action.export":`⬇ Export ▼`,"board.export.jsonTitle":`Full ledger backup (execution history and board settings included); import it to restore`,"board.export.json":`Full ledger (JSON)`,"board.export.csvTitle":`Task-list spreadsheet (opens directly in Excel; BOM added for CJK text)`,"board.export.csv":`Task list (CSV)`,"board.drag.forbidden":`Cannot drag from "{from}" to "{to}"`,"board.empty":`No tasks`,"board.secondary.empty":`No canceled / archived / deleted tasks`,"board.group.trashed":`Deleted`,"diag.title":`Health diagnostics`,"diag.subtitle":`Ledger basics and orphan-worktree cleanup`,"diag.revision":`Ledger revision`,"diag.tasks":`Total tasks`,"diag.running":`Running`,"diag.orphans":`Orphan worktrees`,"diag.orphans.heading":`Orphan worktrees (no owning task, directory still present)`,"diag.orphans.none":`None — every project’s .dsh-worktrees directory is clean`,"diag.orphans.cleanup":`Clean up`,"diag.orphans.hint":`Note: orphan directories with uncommitted changes are refused; handle their contents manually first. Remove a live task’s worktree from its task detail pane.`,"diag.gitignore.heading":`gitignore suggestions`,"diag.gitignore.none":`Nothing to do — every git project already ignores .dsh-worktrees`,"diag.gitignore.suggestA":`suggests adding one line to .gitignore:`,"diag.gitignore.suggestB":`(no automatic edits)`,"card.drag.running":`This task is being executed by a session ({title}) and cannot be dragged`,"card.badge.stale":`⏱ Claim stale`,"card.badge.modelTitle":`Pinned model: {model}`,"card.badge.modelEffort":` · reasoning effort: {effort}`,"card.badge.checklistReview":`In review: checklist has unchecked items`,"card.badge.checklist":`Acceptance checklist progress`,"card.badge.pendingPurge":`Pending purge`,"card.session.jumpTitle":`Click to jump to the session: {id}`,"card.session.missing":`The session has been deleted ({id}) and cannot be opened`,"card.session.archived":`The session is archived ({id}) and hidden from the session list`,"card.session.unavailable":`Session navigation unavailable; session id: {id}`,"card.reject.placeholder":`Reason for sending back (optional; the agent reads it before starting)…`,"card.reject.confirm":`Send back to todo`,"card.action.doneTitle":`Accept and complete: move to Done`,"card.action.done":`✓ Done`,"card.action.rejectTitle":`Send back to todo, optionally with a reason`,"card.action.reject":`✗ Send back`,"alert.ok":`Got it`,"diff.commit":`Commit {hash}`,"diff.file":`File {path}`,"diff.truncated":`⚠ Content truncated (too long)`,"diff.failed":`Failed to fetch (see the error bar at the top of the board; the object may be gone with a removed worktree)`,"checklist.title":`Acceptance checklist (DoD)`,"checklist.unchecked":` · {n} unchecked`,"checklist.allDone":` · all done`,"checklist.byUser":`👤 User`,"checklist.uncheckedItem":`Unchecked`,"checklist.evidence":`Evidence: {note}`,"report.title":`Execution report`,"report.submitted":`Submitted by the execution session · {time}`,"report.changedFiles":`Changed files`,"report.checks":`Self-verification`,"report.artifacts":`Artifacts`,"report.risk":`Remaining risks`,"iso.title":`Execution isolation`,"iso.none":`📁 Run in the original directory`,"iso.worktreeTitle":`Execution isolation · Worktree`,"iso.branch":`🌿 Branch`,"iso.baseline":`Baseline {base} → {head}`,"iso.changed":`{n} files changed`,"iso.commit.openTitle":`Click to expand this commit’s diff`,"iso.commits.more":`… {n} commits in total`,"iso.nocommit":`This execution produced no commits (changes may be uncommitted — see the warning below)`,"iso.dirty.toggle":`⚠ {n} uncommitted changes (have the agent commit before merging, or handle them manually)`,"iso.dirty.expand":` ▼ view files`,"iso.dirty.collapse":` ▲`,"iso.dirty.openTitle":`Click to view the uncommitted diff of this file`,"iso.dirty.more":`… {n} in total (full list in the task ledger)`,"iso.hint.running":`Running — merge or clean up after it ends`,"iso.merge.confirm":`Merge the branch into the main worktree with --no-ff?`,"iso.merge.go":`Merge`,"iso.merge.title":`git merge --no-ff the task branch into the main worktree (requires a clean main worktree; conflicts are reported as-is)`,"iso.merge.button":`⇥ Merge into main worktree`,"iso.merge.failed":`Merge failed: {error}`,"iso.merge.noop":`The branch has no commits ahead of the main worktree — nothing to merge (send it back to continue running, or clean it up)`,"iso.merge.done":`Merged per repo (--no-ff): {summary}`,"iso.merge.partial":`Some repos failed to merge: {summary} - {error}`,"iso.repo.root":`Root repo`,"iso.remove.wt":`🗑 Remove worktree`,"iso.remove.wtTitle":`git worktree remove (refused when uncommitted changes exist)`,"iso.remove.wtb":`🗑 Remove worktree + branch`,"iso.remove.wtbTitle":`Remove the worktree and delete the task branch (refused when uncommitted changes exist)`,"iso.remove.confirmWt":`Remove the worktree directory?`,"iso.remove.confirmWtb":`Remove the worktree and delete the branch?`,"iso.remove.failed":`Removal failed: {error}`,"iso.remove.branchFailed":`Worktree removed, but branch deletion failed: {error}`,"iso.hint.keep":`Branch and worktree kept — send back to continue editing`,"detail.session.jumpTitle":`Jump to the corresponding session: {id}`,"detail.session.jump":`🤖 Jump to session ↗`,"detail.action.edit":`✎ Edit`,"detail.action.duplicateTitle":`Duplicate this task’s full configuration as a new card (todo column)`,"detail.action.duplicate":`⧉ Duplicate`,"detail.action.saveTplTitle":`Save this task’s configuration (checklist included) as a template for new tasks`,"detail.action.saveTplDone":`Saved as a template (available in the New Task ▼ menu; rename it in template management)`,"detail.action.saveTpl":`⌗ Save as template`,"detail.action.reuseTitle":`Reuse-run: keep the existing worktree and branch (last run’s changes and commits stay in place) and continue on top of them; the default "Run" resets to a fresh baseline`,"detail.action.reuse":`↻ Reuse-run`,"detail.action.runTitleModel":`Run in a new session ({model})`,"detail.action.runTitleDefault":`Run in a new session (default model)`,"detail.action.run":`▶ Run`,"detail.action.stopConfirm":`Stop this execution session?`,"detail.action.stop":`Stop`,"detail.action.stopTitle":`Stop execution session {id} (the task returns to todo)`,"detail.action.stopExec":`■ Stop execution`,"detail.chip.nextRun":`{cron} · next {time}`,"detail.chip.checklist":`Checklist {done}/{total}`,"detail.chip.isolated":`Worktree isolation`,"detail.chip.holderTitle":`Click to jump to the session: {id}`,"detail.chip.holderStale":`Claim stale · `,"detail.chip.holderBy":`Held by `,"detail.chip.holderSuffix":` ↗`,"detail.chip.trashed":`Deleted, pending purge`,"detail.sub.line":`Updated {time} · last change by {who}`,"detail.updatedBy.system":`⚙️ System`,"detail.updatedBy.user":`👤 User`,"detail.field.description":`Description`,"detail.field.prompt":`Execution prompt`,"detail.move.to":`Move to → {status}`,"detail.move.confirmDoneUnchecked":`{n} checklist items are still unchecked — confirm done?`,"detail.move.confirmDone":`Confirm done?`,"detail.move.confirm":`Confirm`,"detail.blocked.unmark":`✓ Unblock`,"detail.blocked.mark":`⛔ Mark blocked`,"detail.release.title":`Release {id}’s claim: the task returns to todo (the holding session may still be working — make sure it has stopped first)`,"detail.release.button":`🔓 Release claim`,"detail.comments.title":`Comments`,"detail.comments.empty":`No comments yet — the agent reports changes and verification here at handoff`,"detail.comments.user":`User`,"detail.composer.placeholder":`Leave a comment as the user (the agent reads it before starting)…`,"detail.composer.send":`Post`,"detail.exec.title":`Executions`,"detail.exec.prunedTitle":`{n} older execution records were pruned at the retention cap`,"detail.exec.pruned":`+{n} pruned`,"detail.exec.trigger.manual":`Manual`,"detail.exec.trigger.scheduled":`Scheduled`,"detail.exec.openTitle":`Click to open the execution session: {id}`,"detail.danger.delete":`🗑 Delete (mark for purge)`,"detail.danger.purgeConfirm":`Physical purge is irreversible`,"detail.danger.purgeGo":`Purge`,"detail.danger.purge":`🔥 Purge physically (confirm required)`,"form.title.create":`New task`,"form.title.edit":`Edit task`,"form.subtitle.create":`Push onto the board; sessions in the project can claim and run it`,"form.subtitle.edit":`Adjust the task content and execution configuration`,"form.field.title":`Title`,"form.field.titlePlaceholder":`One line: what should be done`,"form.field.project":`Project`,"form.field.model":`Model (default = session default model)`,"form.field.modelDefault":`Default model`,"form.model.option":`{name} ({provider})`,"form.field.effort":`Reasoning effort`,"form.field.effortTitle":`Set the model’s reasoning effort (e.g. low/medium/high); default = follow the model/provider default`,"form.effort.follow":`Follow model default`,"form.effort.low":`Low (low)`,"form.effort.medium":`Medium (medium)`,"form.effort.high":`High (high)`,"form.effort.none":`Off (none)`,"form.field.preset":`Execution preset`,"form.field.presetTitle":`The execution session is composed from this preset (tool set and persona); default = the deployment default preset`,"form.preset.follow":`Follow deployment default`,"form.preset.defaultTag":` (deployment default)`,"form.field.urgency":`Urgency`,"form.urgency.urgent":`Urgent`,"form.urgency.urgentHint":`Handle first`,"form.urgency.normal":`Normal`,"form.urgency.normalHint":`Normal scheduling`,"form.urgency.relaxed":`Relaxed`,"form.urgency.relaxedHint":`When there is time`,"form.field.description":`Description`,"form.field.descriptionOptional":`Description (optional)`,"form.desc.placeholder":`Requirement details, background, acceptance criteria…`,"form.field.prompt":`Execution prompt (the actual prompt = title + description + prompt)`,"form.field.promptOptional":`Execution prompt (optional; the actual prompt = title + description + prompt)`,"form.prompt.placeholder":`Extra instructions appended after "title + task description" and sent to the execution session. Template variables: {{lastExecution}} (last execution result), {{lastComments}} (latest 3 comments)`,"form.field.mode":`Execution mode`,"form.mode.claim":`🤝 Claim-based`,"form.mode.claimHint":`Sessions in the project claim it`,"form.mode.scheduled":`⏰ Scheduled`,"form.mode.scheduledHint":`Starts automatically on schedule`,"form.field.cron":`Cron expression`,"form.cron.placeholder":`min hour day month weekday`,"form.cron.daily":`Daily 09:00`,"form.cron.hourly":`Hourly`,"form.cron.every10min":`Every 10 minutes`,"form.cron.weekly":`Mondays 09:00`,"form.cron.next":`Next {time}`,"form.field.isolation":`Execution isolation`,"form.iso.locked":`The task has execution history; isolation is locked`,"form.iso.lockedShort":`Locked (cannot change once execution has started)`,"form.iso.nonGit":`This project is not a git repository`,"form.iso.worktree":`🌿 Worktree isolation`,"form.iso.worktreeTitle":`Each execution runs on its own worktree branch`,"form.iso.worktreeHint":`Isolated branch task/title+ID, no cross-contamination`,"form.iso.none":`📁 Run in the project directory`,"form.iso.noneTitle":`Run directly in the project directory (no git)`,"form.iso.noneHintNonGit":`Not a git repository; will run in the project directory`,"form.iso.noneHint":`No git; works directly in the project directory`,"form.iso.nonGitNote":`This project is not a git repository; the task will run in its directory (still created with the default configuration; the runtime degrades automatically)`,"form.iso.mirrorNote":`Multi-repo workspace: worktree isolation automatically mirrors all {n} repos — one task branch each, merged per repo at acceptance`,"form.field.checklist":`Acceptance checklist (DoD)`,"form.field.checklistOptional":`Acceptance checklist (DoD, optional)`,"form.check.itemPlaceholder":`Checklist item {n} (definition of done)`,"form.check.removeTitle":`Remove this checklist item`,"form.check.add":`+ Add checklist item`,"form.check.checkedTitle":`Checked state is preserved on save (currently checked by: {who})`,"form.check.notCheckedYet":`not checked yet`,"form.check.hintCreate":`{n} items; the execution session works through them and checks each off; unfinished items are highlighted at review`,"form.check.hintEdit":`{checked}/{total} checked (saving replaces the whole list; checked state is preserved)`,"form.hint.needTitle":`Enter a title`,"form.hint.needProject":`Select a project`,"form.hint.cronBad":`Invalid cron expression (min hour day month weekday)`,"form.hint.nextRun":`Next run {time}`,"form.hint.saveVersion":`On save: v{v} → v{next}`,"form.hint.createClaim":`After creation, sessions in the project can claim and run it`,"form.action.runBlockedTitle":`The task is running; cannot start another`,"form.action.runBusyTitle":`Submitting…`,"form.action.runTitle":`Save, then immediately start an execution (new session)`,"form.action.run":`⚡ Run now`,"form.action.save":`Save changes`,"form.action.create":`Create task`,"tpl.aria":`Manage templates`,"tpl.title":`Task templates`,"tpl.subtitle":`Templates from the New Task ▼ menu: rename / delete / use directly; "Save as template" in the task detail pane adds new ones`,"tpl.empty":`No templates yet — click "Save as template" in a task detail pane to capture a common configuration`,"tpl.name.aria":`Template name {name}`,"tpl.builtin":`Built-in`,"tpl.custom":`Custom`,"tpl.meta.checklist":` · {n} checklist items`,"tpl.rename.title":`Save rename`,"tpl.rename.button":`Rename`,"tpl.use.title":`Open the new-task form with this template`,"tpl.use.button":`Use`,"tpl.delete.title":`Delete this template`,"tpl.renamed":`Template renamed`,"tpl.foot.hint":`Templates are stored with the ledger in the DSH home directory and survive upgrades`,"imp.aria":`Import ledger`,"imp.title":`Import ledger`,"imp.subtitle":`Pick an exported JSON backup: preview first, then merge or replace everything`,"imp.parseError":`The file is not valid JSON`,"imp.note":`The ⬇ JSON export is a same-format backup and can be imported to restore; the file’s schemaVersion must match the current version.`,"imp.previewing":`Previewing…`,"imp.stat.create":`New`,"imp.stat.overwrite":`Overwrite (same id)`,"imp.stat.invalid":`Invalid (skipped)`,"imp.sec.create":`New tasks`,"imp.sec.overwrite":`Overwritten tasks (whole-card replacement, execution history and comments included)`,"imp.sec.invalid":`Invalid entries (not imported)`,"imp.noId":`(no id)`,"imp.mode.merge":`⊕ Merge`,"imp.mode.mergeHint":`Adds new + overwrites by id; everything else untouched`,"imp.mode.replace":`💣 Replace all`,"imp.mode.replaceHint":`Clears the current ledger and adopts the imported file (automatic backup first)`,"imp.result.replace":`Replace complete: imported {n} tasks ({total} former tasks backed up)`,"imp.result.merge":`Merge complete: {n} added, {m} overwritten`,"imp.foot.replaceConfirm":`⚠ Click again to confirm the full replacement (irreversible; a backup has been taken)`,"imp.foot.replaceNeedConfirm":`Full replacement requires a second confirmation`,"imp.foot.mergeHint":`Merge writes only the tasks listed in the preview`,"imp.action.run":`Import`,"imp.action.confirmReplace":`Confirm replace`,"set.aria":`Board settings`,"set.title":`Board settings`,"set.subtitle":`Global defaults for new tasks and session sync`,"set.iso.heading":`Default execution isolation`,"set.iso.noneHint":`No git; works directly in the project directory (factory default)`,"set.iso.worktreeHint":`Each execution runs on its own worktree branch (task/title+ID), isolated from the others; multi-repo workspaces are mirrored whole (one branch per repo)`,"set.iso.current":`Currently saved default: {current}. Affects only tasks created hereafter; existing tasks keep their creation-time choice, and non-git projects still degrade to the project directory at run time.`,"set.sync.heading":`Auto-sync workspace sessions`,"set.sync.off.name":`🚫 Sync off`,"set.sync.off.title":`Manage only tasks created and triggered in the task board`,"set.sync.off.hint":`Board tasks only (factory default)`,"set.sync.on.name":`🔄 Auto-include sessions`,"set.sync.on.title":`Sessions created directly in workspaces also appear on the board: In progress while running, In review automatically when done`,"set.sync.on.hint":`Tracks runs and enters review on completion`,"set.sync.stateOn":`On: sessions created and run directly in workspaces automatically become board cards and flow to the "In review" column when done.`,"set.sync.stateOff":`Off: only tasks created and triggered inside the board appear on the board.`,"set.foot.dirty":`Unsaved changes`,"set.foot.clean":`Matches the current board settings`,"set.action.save":`Save settings`,"form.field.permission":`Execution permission`,"form.perm.write":`Workspace write`,"form.perm.writeHint":`Read-write access to the workspace and temp directories (recommended default)`,"form.perm.readOnly":`Read-only`,"form.perm.readOnlyHint":`View and search only; no file changes or external commands`,"form.perm.fullAccess":`Full access`,"form.perm.fullAccessHint":`Unrestricted: whole-disk access and external commands`,"form.perm.defaultTag":` (default)`,"set.perm.heading":`Default execution permission`,"set.perm.writeName":`📁 Workspace write (factory default)`,"set.perm.writeHint":`Read-write access to the workspace and temp directories; writes need no extra confirmation`,"set.perm.readOnlyName":`🔒 Read-only`,"set.perm.readOnlyHint":`Read-only viewing and search only; no file changes or destructive commands`,"set.perm.fullName":`⚡ Full access`,"set.perm.fullHint":`Unrestricted: whole-disk access and external system commands`,"set.perm.current":`Currently saved default: {current}. The execution permission preset applied to new tasks.`,"card.badge.permReadOnly":`🔒 Read-only`,"card.badge.permReadOnlyTitle":`Permission: read-only`,"card.badge.permFull":`⚡ Full access`,"card.badge.permFullTitle":`Permission: full access`,"detail.chip.permReadOnly":`Read-only`,"detail.chip.permFull":`Full access`,"detail.chip.permWrite":`Workspace write`,"tpl.meta.permReadOnly":`read-only`,"tpl.meta.permFull":`full access`,"md.imageAlt":`Image {n}`,"md.imageTitle":`Click to view full size ({alt})`,"md.lightboxAlt":`Full-size preview`,"md.closePreview":`Close preview`,"slash.aria":`Quick commands and skills`,"slash.title":`Quick command and skill completion`,"slash.hint":`↑↓ navigate · Enter / Tab pick · Esc close`,"slash.badge.command":`⚡ command`,"slash.badge.skill":`🧩 skill`,"slash.tipA":`💡 Type`,"slash.tipB":`to autocomplete slash commands and agent skills`,"slash.cmd.goal.desc":`Autonomously drive long-horizon goals to completion`,"slash.cmd.goal.hint":``,"slash.cmd.schedule.desc":`Set one-off or recurring cron schedules`,"slash.cmd.schedule.hint":`