DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

dashi666666-zxp /

dashi666666-zxp/dsh-court

Verified

三省六部 · 朝堂(DeepSeek Harness 插件):圣旨 → 太子分拣 → 中书拟敕 → 门下审覆 → 尚书都省派工 → 六部与二十四司并行办案 → 御史台按劾 ∥ 都省覆核 → 奏疏;长线子 agent 可直连问对、内侍监 token 计度与红线、断点续跑,硬约束由代码强制(fail-closed)

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@9d156dfa

dsh-court · 三省六部 · 朝堂

DSH 插件:把一件大任务当作圣旨交下来,朝堂自动走完 太子分拣 → 中书拟敕 → 门下审覆(可封驳退回重拟)→ 尚书派工 → 六部并行办案(六部尚书把本部敕令下发给本部四司·二十四官吏)→ 御史台按劾 ∥ 都省覆核 → 奏疏待御批。

多智能体并行由 DSH 原生 ctx.subagents 驱动,零外部依赖(不 import 任何 npm 包)。v0.8.0 起默认走长线子智能体口径:每个节点(太子/中书/门下/尚书/六部/二十四司/御史台)各养一位常任 agent(startContinuable + sendMessage,阶段之间不 dispose),面板点节点弹出的「问对」直连当事人本人,退朝即散场时统一退班(drainContinuableChildren)。宿主缺这些原语就自动退回「每阶段一个一次性 agent」的老口径并留痕。

制度与工程口径参照 cft0808/edict(三省六部制 · OpenClaw 多 Agent 编排):太子分拣、九态状态机、停滞「重试→升级→回滚」、奏折归档、官员总览与旨库。差别也写清楚:edict 是常驻多 Agent 服务(看板派发 + Redis EventBus),本插件跑在 DSH 的 subagents 原语上,一场朝议即一次函数调用链,故状态机用于校验 + 观测 + 停滞处理,不做跨进程派发。


安装

本插件是 host-plane 编排器(注册 court_* 六个工具 + /court/api 面板路由),必须落在 profile 的 host 组合里 (cordis.patch.yml 的 insert 块),不要塞进 agent preset。

从 GitHub 取源码:

git clone https://github.com/dashi666666-zxp/dsh-court.git

桌面 profile(本机 pnpm 不可用、dsh plugin add 走不通)装法是手工 link 三件事,与 dsh-arch 同机制:

# 需在 danger-full-access 下执行(要写会话工作区之外的 profile)
# 1) profile package.json 的 dependencies 加: "dsh-court": "link:<本仓路径>"
# 2) 同文件 dsh.profile.bundles 追加 "dsh-court"
# 3) profiles\desktop\node_modules\dsh-court 建 junction 指向本仓路径

改完由 DSH 配置热加载自动建 loader entry,无需重启。v0.11.0 起朝堂默认关闭,装好后要先去面板「朝堂」页拨开总开关 (或 court_control { action: "power", on: true })才能 court_hold 下旨。

复跑测试:

node tests/host-smoke.mjs              # 引擎/工具/协议
node tests/client-smoke.mjs --offline  # 面板静态断言(不打真 HTTP)
node tests/preview.mjs                 # 面板离线预览

一、工具

工具 作用
court_hold 下旨开朝。前置:总开关要开着(v0.11.0 起朝堂默认关闭——关着时本工具直接回绝并告知怎么开)。参数:edict(必填)、context、workspace、ministries(限定若干部)、draftCount(廷议 1-3 稿并行)、reviewRounds(门下最多审几轮)、rescript(auto 回执 / human 弹真人朱批)、background、si(是否令六部下发本部四司,默认 true)、taizi(是否先由太子分拣,默认 true)、tokenBudget(本场 token 限额,v0.6.0:0/不传=只计度不禁支;v0.9.0 起运行中可调)、longLine(v0.8.0:是否走长线子智能体口径,默认 true)、quotas(v0.9.0:各部 token 分额,如 {"兵部":400000};分额用尽则该部不再派新差事)、redlines(v0.9.0:各部/御前 token 红线,如 {"兵部":120000,"_run":50000};可用额度跌破即上奏)
court_status 查朝堂。参数:id(留空=列近期朝议,含奏折阁存档)、detail(brief=摘要,奏疏截前 1200 字;full 或省略=完整奏疏,含敕令/六部回报/二十四司承差/御史台按劾/都省覆核/内侍监结账/待御批)
court_ministries 六部职权名录 + 二十四司名册 + 三省与御史台与御前内侍监的权力线 + 朝议状态机 + 旨库(无参数;写圣旨前先看)
court_control 朝议控制:power 总开关(v0.11.0:on:true 开启 / on:false 关闭;朝堂默认关闭,这是关闭态唯一还能用的动作,否则关了就没路再打开;关闭当场收场——在办的叫停、在朝 agent 退班) / stop 叫停(中止当前阶段,已产出的部分保留)/ resume 续办(已有敕令不重拟,只补没办完的部;若是「内侍监告匮而止」的场次,须同传 tokenBudget 加限,否则一续就再停)/ reopen 重开(v0.6.0:散场/退朝过的场次照原旨另起一场,原场存档不动,内侍监并账) / budget 内侍监调额(v0.9.0:限额 / 分部额度 quotas / 各部红线 redlines 运行中皆可加可减,传 0 即撤掉那一项) / dismiss 散朝。参数:id(power 不需要)、action、on(power 必填)、tokenBudget(resume 加限 / reopen 新场限额 / budget 新限额)、quotas、redlines
court_dismiss 退朝(散朝):中止正在进行的朝议并当场散场——长线子 agent(本场各衙的长驻 agent)一律退班释放,面板上官员退班、连线转灰、树收成一栏散场条(v0.8.0)。叫停过(stopped,可续办)的场次也点得动:只收场散班,状态仍留「可续办」,续办会重新点卯。参数:id,或显式 all:true;两者都不给则驳回(防误散全朝)。已退朝/已散场的场次不再改写状态,也不绕过状态机
court_templates 旨库:九条圣旨模板(全面体检/代码审查/功能落地/疑难排障/结构改造/性能优化/文档补齐/并行调研/发布准备),填好占位即可下旨

court_hold 默认最多等 waitMs(120s),超时返回朝议 id,之后用 court_status 续查。

总开关(v0.11.0):朝堂默认关闭——装好之后不主动占宿主的子 agent 名额。要在会话里下旨,先去面板「朝堂」页把总开关拨开(或 court_control { action: "power", on: true });关闭期间面板照旧只读(历史案卷、树、文书都翻得到),只是 court_hold / 续办 / 重开 / 问对会被回绝。详见第二十六节。

什么时候该用:一件任务需要多角度专业分工、且各分片互相独立可并行(全面体检、多方向并行调研、大规模改造+验证)。 什么时候别用:单文件小改、一问一答、强串行依赖的细碎任务——那些直接自己做更快。

闲谈/寒暄会被太子挡在门外(declined,一场朝议都不开);若你确实要开朝而太子判成闲谈,传 taizi:false 跳过它。


二、权力线(制度即约束)

角色 权力 边界(三重落地:PERSONA 提示词 + 运行期护栏 + 工具白名单)
皇帝(调用方 / 真人) 最终裁决、御批 不经中书、门下,不成其为敕
内侍监(御前计度线) 传宣、计度与限额(token) 立于皇帝与太子之间,直接对接御前;不派 agent、不办案、不估算——数字只取 DSH tokenUsage 会话投影的实测值,取不到就如实记「未报」;到限额停派新差事,判词随奏疏并呈。v0.9.0:额度运行中可调(限额/分部额度/各部红线),可用额度跌破红线即上奏皇帝与内侍监(只奏不停;某部分额用尽才不再给它派新差事)
中书省(中书舍人) 出令:取旨拟敕 只拟不办;敕草未经门下审覆不得下行
门下省(给事中) 审覆、封驳(封还/涂归) 只审不办;不得代拟,只能驳与议
尚书省(左仆射 / 都省) 奉行、派工、勾检稽核 不得改敕;发现不可行须覆奏。覆核工具白名单为只读(CENTRAL_TOOLS)
六部(尚书) 在本部职权内办案 越部须覆奏;不得自开朝议——由 court_hold 的 sessionId 护栏运行期驳回
御史台(侍御史) 独立监察、按劾 只察不办;不属六部

落地方式说明(勿以为「写进提示词」就完事):PERSONA(lib/protocol.js)负责让模型知道边界;越权的兜底另有两条——① 尚书省/中书的工具白名单只有只读工具(CENTRAL_TOOLS);② 朝议子会话调用 court_hold 直接被 sessionId 护栏驳回(lib/engine.js isCourtChild + lib/index.js 前置检查)。POWER_LINES 只用于面板与 court_ministries 展示,它本身不是护栏。

六部现代职能映射(史实职掌见 docs/history-sansheng-liubu.md):

  • 吏部 人事与编排(铨选·考课)——分工、职责边界、验收标准
  • 户部 资源与成本(度支·仓部)——预算、耗时、依赖、可持续性
  • 礼部 对外与文档(贡举·主客)——文档、接口契约、体例、兼容
  • 兵部 攻坚与执行(军籍·驿传)——构建、运行、测试、修复
  • 刑部 审查与校验(刑法·勾覆)——安全、边界、反例、证据链
  • 工部 工程与实现(百工·水部)——代码实现、结构改造、批处理

三、界面

v0.4.0 起面板是一张真正的「自上而下的树状图」(组织架构式)——不再是「一路缩进的卡片列表」: 干线一列居中(皇帝 → 太子 → 中书省 → 门下省 → 尚书省,牌与牌之间是金箭线)→ 尚书省之下一条横总线分叉出六部(六个并列的列,从总线上垂下来)→ 每部之下用 ├─/└─ 肘线挂四司(二十四司一眼看全)→ 御史台走虚线旁支(不属六部,独立监察线)。 连线全部由 CSS 伪元素的 border 画出(无图库、无 SVG、缩放不糊)。每枚方牌是「官称·品级 / 名 / 职权 / 状态药丸 / 用时」, 右上角两枚极小控件 文(看该节点文书)、问(在该节点朝堂问对):点任一个 → 该节点的文书与对话在树下方那一格里就地展开(不跳转、不新开页;收起即无)。 v0.1.5 起底色与 DSH 对话面板同源(.ct-root 自身 background:transparent,颜色走 --dsw-alias-* 主题令牌,dark 下 = --dsw-alias-bg-base = #151517)——不再自带一块 #0d1117;骨架仍沿用 GitHub Primer(Dark) 的尺寸层级(1px 描边、6px 圆角、药丸标签、Counter、BlankSlate、btn/btn-sm、表格),调色板是项目自己的四色—— 主色 = 黑(跟随 DSH 主题底 + --dsw-alias-bg-layer-1/2 的卡面)+ 金(#e3b341:在朝、准奏、主按钮、干线箭线); 副色 = 灰(取自 --dsw-alias-label-secondary,dark 下 #a2a4a6:次要文字、中性状态、描边)+ 红(#f85149:封驳、失手、危险操作)。 状态口径三色闭环:金 = 在进行 | 灰白 = 已办完 | 红 = 出问题。底色跟随所在面板(深色对话面板 → 同色;设置弹窗那种浅底 → 也跟着浅),金/红 accent 不变。 样式全部 scope 在 .ct-root 之下(选择器一律以 .ct-root 开头,连状态类也是)——不会碰到别的插件、也不会碰 DSH 自身的 UI;有断言逐条扫描样式表把关(client-smoke「样式零外泄」)。

  • 树状图(v0.4.0):一场朝议 = 一棵自上而下的树
                   ┌──────────────────────────┐
                   │      皇帝 · 圣旨(敕)      │   ← 根
                   └────────────┬─────────────┘
                                │ 〇 拣
                          ┌─────▼─────┐
                          │   太子     │          分拣:闲谈直接回 / 旨意才开朝
                          └─────┬─────┘
                                │ 一 拟
         ┌──────────┐     ┌─────▼─────┐    ┌──────────┐
         │  御史台   │ ┊ ┊ │  中书省    │    │  门下省   │   二 审 → 三 行
         └──────────┘     └─────┬─────┘    └──────────┘
                                │ 三 行
                          ┌─────▼─────┐
                          │   尚书省   │
                          └─────┬─────┘
          ┌───────┬───────┬─────┴─────┬───────┬───────┐
        ┌─▼─┐   ┌─▼─┐   ┌─▼─┐       ┌─▼─┐   ┌─▼─┐   ┌─▼─┐
        │吏部│   │户部│   │礼部│  ...  │兵部│   │刑部│   │工部│
        └─┬─┘   └─┬─┘   └─┬─┘       └─┬─┘   └─┬─┘   └─┬─┘
         ├─吏部司  ├─户部司  ├─礼部司      ├─兵部司  ├─刑部司  ├─工部司
         ├─司封    ├─度支    ├─祠部        ├─职方    ├─都官    ├─屯田
         ├─司勋    ├─金部    ├─膳部        ├─驾部    ├─比部    ├─虞部
         └─考功    └─仓部    └─主客        └─库部    └─司门    └─水部
    
    (上图是结构示意:真实面板里干线是「一列居中、牌间竖箭线」,六部是并列的列从横总线上垂下来,四司用 ├─/└─ 肘线挂在部下面,御史台在最右侧走虚线旁支。皇帝牌上是圣旨原文,点 文 看全文。)
    • 官称与品级依《唐六典》卷八·卷九与《新唐书·百官志》:中书令/侍中正三品、尚书令正二品、六部尚书并正三品;二十四司的长官是郎中(从五品上),叶子牌上标「水部郎中 · 从五品上」(依据 docs/tang-liubu-ershisi-si-kaoju.md)。
    • 尊卑的分量差:干线牌最重(衬线大字、居中),部牌次之,司叶子最小最沉(inset 底色)——层级不只靠位置,也靠分量。
    • 每个节点右上的 文 / 问:文 展该节点文书(中书敕草全文 / 门下逐轮涂归 / 尚书敕令分派+奏疏 / 部承办敕令+回报+「下发二十四司:N 司领差」/ 司的差事+本司回报 / 御史台按劾),问 在该节点就地开朝堂对话。两者都渲染在树下方那一格里,收起即无(不占版面)。
    • 二十四司始终可见:本轮没派工的司也以叶子列出并标「未派差事」;没开 si 时四司仍列出(书志层级),只是没有文书可问。
    • 面板底部三折:敕令清单 / 都省注记 / 奏折活动流;再往下是全页共用的 官员总览 与 旨库。
    • 二十四司(v0.2.0 起是活的承办层级):六部尚书把本部敕令下发给本部四司(二十四官吏),四司并行承差,尚书覆核四司回报后才成本部回报。面板上「二十四司」不再是静态书志折叠,而是挂在部之下的四个司节点(d3):司名(水部)+ 长官官称与品级(水部郎中·从五品上)+ 本司史实职掌 + 下发到本司的差事 + 本司回报原文 + 本司自己那一格「朝堂对话」(scope = si:工部:水部)。尚书没派到的那几司照样列出(「未派差事」)——二十四司看得见全貌;关掉 si 就退回 v0.1.x 的静态书志折叠。依据 docs/tang-liubu-ershisi-si-kaoju.md(《唐六典》卷二—卷七、《旧唐书》卷四三「尚書省領二十四司。六尚書,各分領四司」)。
    • 太子(v0.3.0):树的最上一层多一格「〇 拣 太子 · 分拣权」,显示分拣判定(旨意/闲谈)、提炼的标题、紧急度与验收口径;闲谈则整棵树只到太子为止(面板给出「未开朝」与太子该回的话)。
    • 自上而下(v0.1.4):树容器是纵向列(flex-direction:column),节点自御座往下依次排开(d0 → d1×3 → d2×6 → d1);每块折叠区都在它自己的节点内往下长,不横着铺、不弹到别处。
    • 古代朝堂质感:匾额式页头(金线 + 回纹牙子)、朱印(敕 / 准 / 驳 / 问)、官名用衬线字(宋体一系)、事实栏做成简牍式方格(用时 / 敕令 / 回报的部 / 门下审覆 / 御史台)。
  • 朝堂对话(v0.1.4:就在各节点里折叠展开,且不跳转):每个节点自带一块「朝堂对话」——默认收起只占一行(御座那格 = 整场,三省 / 六部 / 御史台各是自己那块);点节点页脚的 问对(展开后变 收起)或那一行标题,就在该节点内往下展开:分支回话、输入框、止 全在那一格里。卡头的 朝堂问对 是御座那格的快捷入口。链路:
    1. GET /court/api/branch?id=<朝议 id>&scope=<范围> → host 生成一份自洽的问对文书(抬头写明「这是从朝堂另起的分支、先读后等令」+ 圣旨 / 敕草 / 涂归 / 敕令 / 六部回报 / 按劾 / 奏疏 / 注记);
    2. ctx.sessions.fork({ sessionId, increaseTitle: true }) 从当前对话另起分支(与 DSH 自带分支同一原语);
    3. retain(child) → session.prompt([{type:'text', text: 文书 + 【朕的垂询】+ 你的问题}], 'queue'):分支里的 agent 拿到全部朝堂文书后真的开始办事(它是一整个会话,能读文件、跑命令、返工);
    4. 就地回话:面板订阅该分支的 eventSource,只取 fork 之后的新事件(seq > 基线,不把父会话旧history倒进来),把 朕 / 对 / 办 三种行实时渲染在树下方那一格里(每 scope 一格,点哪个节点就换哪一格,互不串台)——全程不调用 uiWorkspace.openSession,不跳转,视线不离开面板。
    5. 后续追问只发问题本身(文书已在分支上下文里);止 可停掉当前这一轮;分支会话同时留在左侧会话列表(标题「朝堂分支 …」),想跟到底也可以自己进去看。
    • scope ∈ all / taizi / zhongshu / menxia / shangshu / censor / 吏部…工部,以及每司的动态 scope si:<部>:<司>(如 si:工部:水部)与整部四司的 si:<部>;单省单部只带该块(不夹带无关文书),shangshu 会连六部回报与二十四司摘要一起带(都省覆核的对象就是它们),单部的分支会把该部四司的派工与回报原文一并带上。
    • 文书由 host 统一生成(体例一致、截断口径唯一、纯函数可单测):单段上限 6000 字、总上限 40000 字,超出留「已截断」字样。
    • 前置条件:当前对话至少有一轮已完成——这是 DSH 原生 fork 的限制(空对话会返回 session/fork-unavailable),面板会把原因显示成可读文案而不是静默失败;sessions 服务缺失时按钮直接禁用并说明缺什么。
  • 设置页「三省六部」(settings.section 插槽,order 60):职官与权力线表 + 六部史实职掌,六部同样各自一张边框卡。
  • 面板取数(客户端实际调用):GET /court/api/state(轻量列表 + 官员总览 stats + 旨库 templates + 状态机 states + roster(含二十四司差遣))→ 展开最新一场时再取 GET /court/api/run?id=(全文:敕草 / 涂归 / 各部回报 / 二十四司回报 / 按劾 / 奏疏 / 内侍监结账);分支走 GET /court/api/branch?id=&scope=;散朝走 POST /court/api/dismiss?id=;叫停/续办/重开走 POST /court/api/control?id=&action=stop|resume|reopen;奏折阁浏览走 GET /court/api/memorials。
  • 奏折时间线 + 活动流(v0.3.0):每场朝议在事实栏下有一条时间线(状态机每一跳 + 该段耗时),底部折叠「奏折活动流」(流转 / 领差 / 回报 / 停滞,逐条带时刻)。停滞时卡头出现红色/金色徽记「停滞·升级N级」,鼠标悬停给出重试次数与是否已回滚。
  • 叫停 / 续办(v0.3.0)/ 重开(v0.6.0):在办的朝议右上多一个 叫停(中止当前阶段、保留已产出),被叫停的显示 续办(已有准敕令不重走太子/中书/门下,只补没办完的部;若上一场是内侍监告匮而止,续办会自动加限)。散朝不可续,但已散场的场次给 重开(照原旨另起一场、原场存档不动、内侍监并账);叫停的场次不给重开——那一路的正解是「续办」。终态后这一场收成一栏散场条(朱印「散」+ 因何收场 + 本场用度 + 并账累计 + 「展开朝堂图」),朝堂图默认收起,展开即回到原样。
  • 官员总览 / 旨库(v0.3.0):页面底部两块折叠。官员总览按角色统计出场次数、平均用时、已成/带疑/失手;旨库列九条圣旨模板并可一键复制(下旨仍由用户在对话里发起——面板不假装能替用户下旨)。
  • POST /court/api/dismiss 与工具同一授权口径:不带 id 必须显式 all=1,否则 400 拒绝(该路由无鉴权,故自守)。
  • 面板路由可自愈:apply 期 webServer 未就绪(启动加载顺序)或热重载交叠导致路由丢失时,自动重试补挂(panelRetryMs,见第九节 #8);异常路径落盘 ~/.dsh/super-injector/dsh-court-apply.log 与插件包目录(#9)。若面板显示「/court/api 不可达」,先看这两个日志文件。

四、配置(插件 config)

写在 profile 的 patch 条目上(cordis.patch.yml 的 config:);下表 29 行 = 29 键(引擎 26 键 + 入口级 3 键 waitMs/promptSection/panelRetryMs),一项一行(有断言核对「引擎认的每个键,入口都得真的转发」):

键 默认 说明
enabled false 总开关(v0.11.0):朝堂默认关闭——court_hold / 续办 / 重开 / 问对一律拒绝(查阅不受影响),直到在面板「朝堂」页拨开,或 court_control { action: "power", on: true }。写 true 即「装好就是开的」。见第二十六节
settingsPath ~/.dsh/court/settings.json(DSH_COURT_SETTINGS 可改) 总开关落盘位置:面板拨过就活过重启;创建引擎时定死。文件被写坏/读不动时退回「关闭」(安全侧)
settings true false = 总开关只在内存里(测试口径:别去读写用户家目录)
waitMs 120000(毫秒,即 120s) court_hold 同步等待上限;超时返回 id
reviewRounds 2 门下省最多审几轮,每轮封驳退回中书重拟
draftCount 1 中书拟敕稿数(>1 为廷议并行多稿)
censor true 是否设御史台(台省并立,与都省覆核并行)
maxParallel 6 六部并行上限
si true 六部尚书是否把本部敕令下发给本部四司(二十四官吏)并行承差;false=退回「一部一个 agent」的省算口径
siMaxPerDept 4 每部最多下发几个司(二十四司之四)
siMaxParallel 2 二十四司承差的全局并发上限(6 部 × 4 司 = 24,不限流会一口气全拉起;v0.10.0 由 8 降到 2——原值与宿主的子 agent 名额上限撞在一起)
siTimeoutMs 600000 单司承差的阶段超时
crewLimit 8 在朝常任子 agent 名额上限(v0.10.0,=宿主实测上限);0=不设名额
crewReserve 2 名额里留给场外的余量(面板问对 / 别的插件 / Agent Teams 共用同一个池子)
crewWaitMs 20000 领不到名额时最多等多久;到点仍没有 ⇒ 该阶段降级为一次性 agent(照办,不判失败)
crewTickMs 250 等名额的轮询周期
crewDrainIdle true 用毕即退班:太子分拣毕 / 司承差毕 / 部覆核毕当场退班还名额(名额只进不出的话,二十四司必然撞上限)
taizi true 是否先由太子分拣(闲谈直接回、不开朝;旨意提炼标题与验收口径)
stallThresholdSec 180 单阶段多久没动静算「停滞」(秒;可为小数,测试用小值演练)
scanIntervalMs 20000 停滞扫描周期(毫秒);0=关掉扫描
maxStallRetry 1 每个阶段停滞时先自动重开该阶段几次(按每一次尝试定位,不误伤并行的其它阶段)
escalationMax 2 重试无效后升级几级(1=门下省协调,2=尚书都省协调),再无效则中止该阶段并回滚
archive true 奏折阁:朝议落盘存档(重启/热重载后仍能翻到)
archiveLimit 50 奏折阁保留份数(超出删最早的)
archiveDir ~/.dsh/court/memorials(DSH_COURT_ARCHIVE_DIR 可改) 存档目录;创建引擎时就定死,不在写入时读 env
stageTimeoutMs 600000 单阶段(每个子 agent)超时;超时该阶段记 warn 并保留已产出部分
reconcileTimeoutMs 300000 都省收官阶段超时(据御史台按劾重出终稿),短于普通阶段以免拖着不退朝
totalTimeoutMs 1800000 整场朝议超时
model 空 子 agent 模型覆盖;空=继承调用方
provider spawn 子 agent provider;spawn 时不覆盖 agentOptions.provider(即默认继承)
historyLimit 30 内存中保留的朝议记录数(奏折阁的存档另算)
ministerMaxDepth 1 子 agent 深度上限:1=可办案但不得再开府(防递归);不设默认值时由引擎补 1
tokenBudget 0 本场累计 token 限额(0=只计度不禁支)。court_hold 的 tokenBudget 参数按场覆盖它;到限额即停派新差事并在跑的差事一并叫停(v0.7.0),按「可续办的叫停」收场
tokenWarnRatio 0.8 用度到限额的这个比例时内侍监先呈报一次(余量不足)
budgetTickMs 5000 内侍监预算巡检周期(毫秒,v0.7.0):勘合只在派新差事时做,在跑的差事靠这个周期巡检才掐得住;调小=更贴限额,调大=超支幅度更大
longLine true 长线子智能体(v0.8.0):一节点一常任 agent(startContinuable),阶段之间复用同一个人、退朝时统一退班;false=每阶段一个一次性 agent(省内存,但节点之间互不相识)。宿主缺 startContinuable/sendMessage/sessions 时自动退回一次性口径并留痕,不判失败
talkTimeoutMs 300000 长线 agent 一轮的等待上限(毫秒,含面板弹窗的「问对」):到点 interrupt 这一轮(人不散),按停滞重开处理
schemaRepair true 回报契约补问(v0.12.0):每阶段 JSON 回报按 RESULT_CONTRACT 校验,缺关键字段时补问一次格式(只补字段、不改结论);false=只记账不补问
schemaRepairTimeoutMs 120000 格式补问的单阶段超时(只补 JSON,不该重新办案,故短于普通阶段)
unsandboxedFallback false 无过滤降级开关(v0.12.0):默认禁止第三档 spawn(不给 toolFilter)——宿主两次都不接受白名单时该阶段判失败交人裁决,而不是放一个可改文件/可调 court_* 的 agent 出去;仅在对 provider 兼容性有把握时设 true
runRedline 0 御前余量红线(v0.9.0):本场可用额度(限额 − 全场已用)跌破它即上奏;0=不设。下旨时 redlines._run 可按场覆盖
deptRedline 0 各部默认红线(v0.9.0):下旨未逐一给 redlines 时,六部各按此值立一条;0=不设(想只给某几部立线,就在 redlines 里逐部写)
promptSection false 是否向系统提示注入一行朝堂说明
panelRetryMs 500 面板路由自愈重试间隔(apply 期拿不到 webServer 时启用,最多重试 120 次;测试会调小它)
DSH_COURT_DOCTRINE(环境变量,不是 config 键) 1(开) 作业条规开关:=0 时三省、六部与二十四司的承办提示词里不再出现条规(对比实验 / 出问题时的一键卸力)。见第十六节
DSH_COURT_SKILLS_DIR(环境变量,不是 config 键) ~/.agents/skills(回落 ~/.dsh/skills) 条规里「技能全文在哪」的根目录;多个用 ; 分隔

五、文件结构

dsh-court/
├── package.json          # main=lib/index.js;dsh.client.platform=web
├── cordis.patch.yml      # bundle 装配:insert id/name = dsh-court
├── lib/index.js          # 插件入口:6 个工具 + 服务 ctx.court(ctx.provide)+ /court/api
├── lib/engine.js         # 朝议引擎:阶段编排、并行扇出、都省收官、超时/中止、快照(轻量/全文两档)
├── lib/protocol.js       # 职官/权力线/六部定义、persona、提示词、JSON 容错解析、分支文书 branchSeed
├── lib/client.js         # 朝堂面板(__ModuleLoader__ CJS 包装,React;黑金灰红 Primer 风格 + 另起分支对话)
├── tests/host-smoke.mjs  # host 半边冒烟(22 项,零依赖,不拉 LLM;含分支种子、面板路由与热重载交叠回归)
├── tests/client-smoke.mjs# client 半边冒烟(20 项带真实 HTTP 探针;14 项 --offline:UI 骨架 + 分支调用序列)
├── tests/preview.mjs     # 面板静态预览生成器(`npm run preview`):无浏览器也能看面板长相
├── evidence/             # 端到端实跑的原始快照与奏疏(e2e-court-run.json);panel-preview.html 是设计预览
└── docs/history-sansheng-liubu.md   # 史料考:制度与权力线(唯一依据)

六、已知限制

  1. provider 的 maxDepth 限制 / 降级阶梯:spawn provider 把「子本身」算作 depth 1,传 maxDepth: 0 会被拒(「subagent depth 1 exceeds maxDepth 0」)。引擎默认发 maxDepth: 1(= 六部可办案、不得再开府),并带降级重试:完整(白名单+深度)→ 去深度(保留工具白名单)→ 默认止步。第三档「无过滤」自 v0.12.0 起默认禁止(unsandboxedFallback:false):toolFilter 是工具面唯一护栏,宿主两次都不接受时宁可让该阶段失败交人裁决;只有显式设 true 才会走无过滤 spawn。另:court_* 六个工具对朝议子会话统一拦(sessionId 护栏,不只 court_hold)——即便走了无过滤降级,子会话也调不动查看/散朝/调额。
  2. 改源码会热重载插件、清空朝议:DSH 会监视插件文件,编辑 lib/*.js 会重建 fiber,在跑的朝议随之丢失(实测踩到)。要改代码请等退朝,或接受朝议中断。
  3. 朝议不跟随工具调用取消:court_hold 刻意不接 exec.signal——否则工具一到 waitMs 返回就会把仍在办案的六部全部 abort(实测:六部齐刷刷 stopReason=aborted)。朝议只由 court_dismiss / 阶段超时 / 总超时结束;所以 background:true 与超时续查是可靠的。
  4. court_dismiss 与面板散朝路由都需显式授权:工具必须给 id 或显式 all:true;POST /court/api/dismiss 必须给 id 或 all=1,否则 400。本工具全局可见(任何会话的 agent 都能调),不带参数即散掉全部朝议的设计太危险,故驳回。
  5. 朝议记录在内存:进程重启后 court_status 的历史清空(正在跑的朝议会随进程结束而中止,面板也随之清空)。
  6. 封驳不过则止:门下省在 reviewRounds 内未准奏,该场朝议以 rejected 结束、不施行——按「封驳不过则止」处理,不自动放行。
  7. 六部默认可写可执行:各部工具白名单含写入与命令执行(工部/兵部/户部/刑部可 pwsh)。这是设计意图(真办案),在生产仓库上使用前请确认圣旨范围。
  8. 面板 API 无鉴权:/court/api 走本机 webserver 前缀路由,与 DSH 其它本地面板同样不做额外鉴权(故散朝路由自守,见第 4 条)。
  9. 单阶段超时会截断重活:stageTimeoutMs 默认 600s 是每个子 agent 的上限。实测一场重审计里刑部/礼部双双击穿 600s,状态记 warn,已写出的产物保留、报告可能不完整。重活请调大 stageTimeoutMs,或把圣旨范围切小。
  10. 都省覆核分两阶段:御史台与都省初稿并立同办,按劾出来后再由都省收官重出终稿(reconcileTimeoutMs)。收官失败时奏疏退回初稿,御史台按劾原文仍并呈——此时奏疏可能残留「请补呈按劾」一类措辞,看的时候留意 都省收官 未成 标记。
  11. 首次注入的历史包袱:若插件曾被注入到一个非运行 profile(如 profiles/web),loader 会留下一个 [no-fiber] 幽灵 entry(实测 profiles/web/node_modules/dsh-court 有 junction 残留、其配置无对应条目);它不影响运行。正确装法是 dev_install_package { profile: 'desktop' }(或 dsh plugin add)。
  12. 面板路由的残余风险:自愈只在本 fiber 活着时生效(定时重试 + 只摘自己那条)。若 webserver 服务整个被卸载重装(self-heal.log 里那种路由表清洗),重试窗口(120×panelRetryMs≈60s)之后不会再补;此时重载插件即可(dev_reload_package dsh-court),或直接看 #9 的落盘日志确认。
  13. log() 是空操作:本机 profile 没有 logger 服务,ctx.get('logger') 为 undefined,常规日志不落任何地方;只有异常路径走 note() 落盘(见 #9)。排查问题请看那两个文件,不要指望 DSH 主日志里有 [dsh-court]。
  14. 另起分支对话的三个前提:① 当前对话至少有一轮已完成——DSH 原生 sessions.fork 对空对话返回 session/fork-unavailable(面板把它转成可读文案,不是静默失败);② 页面提供 sessions 与 uiWorkspace 服务(缺失时按钮禁用并写明缺什么,面板其余功能不受影响);③ 投喂是把文书作为分支的第一条消息发出去,所以新分支会自动跑一轮回复(文书抬头已写明「先读完、等我指令再动手」,避免它凭材料自行开工)。文书默认单段 6000 字、总 40000 字上限,超长截断并留「已截断」字样。
  15. 面板强制深色:黑金灰红是产品要求的配色,面板不随 DSH 浅色主题切换(不用 --dsw-* 令牌,颜色写死在自己的 .ct-root 变量里)。
  16. 分支文书是快照:投喂进分支的是点击那一刻的朝议状态。朝议之后又走了新阶段(比如都省收官出终稿),分支里拿到的还是旧的——要最新文书就再点一次分支,或回原会话看面板。

七、史料依据

制度不是装饰:每个角色的权力与边界都取自原始文献(《唐六典》卷八/卷九/卷一/卷二、《资治通鉴》卷一九三与卷二〇四、顾炎武《日知录》卷九、《新唐书·百官志》、司马光《传家集》等),逐条出处见 docs/history-sansheng-liubu.md。 其中两处常被误引者已显式辨证:《唐六典》给事中条并无「封还」「涂归」二词(「涂归」成词首见《新唐书·百官志》);「三省六部一台」是现代概括语,非唐人称谓。


八、交付与实测记录(2026-10-05)

装载:dev_install_package { profile: 'desktop' } → 桌面 profile 的 dependencies 加 link、bundles 加 dsh-court、node_modules junction + loader entry。回执:host ✓ / client ✓。重启后由 bundles 列表正常装配(双路径一致)。

第 1 场实跑(court-muvbnq4g-1,约 11 分钟,后台模式):

阶段 实测
中书拟敕 4 稿(12.3s / 37.7s / 82.8s 重拟 + 并稿)
门下审覆 3 审:第 1、2 稿封驳(附逐条涂归意见),第 3 稿准奏(7 条敕令)——46.1s / 43.8s / 32.8s
尚书派工 7 条敕令分派 2 部
六部并行 刑部 192.8s ∥ 工部 56.4s,2/2 有回报
御史台 ∥ 都省覆核 御史台 220.9s 出 6 条按劾 + 无异议清单;都省 49.4s 出奏疏
奏疏 53,348 字,原始快照存 evidence/e2e-court-run.json

第 2 场实跑 · 插件自审(court-muvc83gi-1,1000s,六部派 3 部:工部/刑部/礼部;圣旨=「对 dsh-court 做宣称 vs 实现独立审计」):

阶段 实测
中书拟敕 3 稿(43.1s / 26.7s 重拟)
门下审覆 2 审:第 1 稿封驳 → 第 2 稿准奏(5 条敕令)
六部并行 工部 done 195s;刑部/礼部 击穿 600s 单阶段超时记 warn(产物已在盘上:court-audit/dept-*.md)
御史台 252s,产出按劾(其中「工部无异议、刑部 6 条虚报/无据/擅改、礼部多处不一致」)
都省覆核 202s 出奏疏(29,282 字),原始快照存 court-audit/run-muvc83gi-1.json

这一场真抓出了本插件的毛病(审计报告在 court-audit/,逐条带文件:行号)——已据此修完(见第九节),未修的照实留在限制里。

面板 API:GET /court/api/state → 200 ok=true version=0.1.0 六部 6 条,live/runs 随朝议实时变化;GET /court/api/run?id= → 全文;GET /court/api/nope → 404;POST /court/api/dismiss 无 id 无 all → 400。

UI 注册(浏览器侧实测,非「应该能行」):client Inspect 的 Slots 实时注册表里,conversation.view 有 {registrant: dsh-court, id: dsh-court, order: 40, active: true},settings.section 有 {registrant: dsh-court, id: dsh-court-roster, order: 60, active: true}——这两行是页面里跑出来的,说明 client bundle 已被加载执行;若面板上看不到「朝堂」,刷新一次页面即可。

第 3 场实跑 · 复核修复(court-muvd1dkk-1,1079s,派 2 部):工部 435s ∥ 刑部 379s(未再击穿超时);御史台 171.9s;都省收官真实跑起来(reconcile=done/258.7s,面板 phase 出现 都省收官:并呈御史按劾),终稿 9,528 字含「按劾处置」与采信/部分采信/不采信,无「请补呈御史台按劾」残留。复核报告 court-audit/verify-fixes.md:5 项修复 4 项判「一致」、第 4 项标「本场采样时未走到,活证据未取得」(该缺口由本场收官阶段的完成态补齐),并抓出下面第 6、7 条新问题。

第 4 场实跑 · 复核补修(court-muvds3rh-1,派 1 部,收官 reconcile=done/250.5s):报告 court-audit/verify-fixes2.md——config 透传、detail:'brief'、测试套件三项判「一致」;第 4 项 HTTP 实测判「不一致」,原因是复核方按敕令去取 court-muvd1dkk-1 的 /run,而该场记录已被修复时的热重载清空(内存历史,见第六节第 2、5 条)→ 得 404。这是已知行为,不是接口缺陷;同一时刻当前场 court-muvds3rh-1 的 /run 实测 200,全文齐备(各部 5,609 / 按劾 4,637 / 都省终稿 11,206 字,奏疏 25,489 字)。

自动化测试:node tests/host-smoke.mjs 13 项 + node tests/client-smoke.mjs 10 项,退出码均 0(client 那套含真实 HTTP 探针,会打本机 /court/api;host 那套含「引擎每个 config 键都必须被入口转发」的结构性断言)。

实测行为特征:门下省显著偏严——三场测试的第 1 稿全部被封驳,末轮才收敛;reviewRounds 建议 ≥3。中书也倾向过度拆分(小任务出 7 条敕令),正由门下以「无法验收」驳回纠偏,这一对冲正是制度设计意图。


九、自审发现并已修的问题(2026-10-05)

第 2 场朝议就是拿本插件开刀,工部/刑部/礼部按 README 逐条核对实现,发现并已修:

# 问题(谁发现) 修法
1 面板「逐部展开回报原文」是空头支票:/state 快照只有 brief,客户端却读 text,成功阶段一律显示「(无回报)/(无)」(礼部) 快照分两档:snapshot() 轻量、snapshot(run,{full:true}) 带全文;新增客户端 getRun() 走 /court/api/run?id= 取最新一场全文,取不到退 brief。测试:host 侧断言两档差异,client 侧断言 /state 无 text 而 /run 有
2 court_status 的 detail 是空转参数:brief/full/省略三种给同一串(工部) detail:"brief" 真给摘要(截 1200 字 + 提示),其余给完整奏疏;参数写进 README
3 POST /court/api/dismiss 无授权护栏:不带 id 会把全部在跑朝议散掉(礼部) 与工具同口径:无 id 必须显式 all=1,否则 400;测试里加了这条探针
4 都省覆核看不到御史台按劾原文(引擎只传占位说明),导致奏疏里出现「请补呈御史台按劾」这种荒唐请求(都省自陈 + 第 2 场实测) 新增都省收官二阶段:台省并立跑完后,把按劾原文交回都省重出终稿(reconcileTimeoutMs,失败则退回初稿并留标记)
5 ctx.set('court', api) 缺 provide,每次装配抛 cannot set property "court" without provide(日志实测) 改 ctx.provide('court', api) 并写明缘由
6 README 承诺 reconcileTimeoutMs 可配置,但入口 config 透传块漏了这一键(第 3 场复核抓到) 补上透传;并加结构性测试:从 engine.js 的 cfg 默认块抓键,断言 index.js 逐个转发——以后再漏键测试直接红
7 detail:"brief" 两处边角:奏疏短于 1200 字仍加「已截断」提示;非 done 状态忽略 brief(第 3 场复核抓到) 只在真的截断时加提示;brief 判断提到状态判断之前,任何状态都生效
8 面板路由会静默消失(交付后实测:/court/api/state 404,而四个工具、ctx.court 服务全好,插件在 loader 里也显示 active)——两个窗口:① apply 期 webServer 还没起来,那次 register 没人接;② 热重载交叠,新 fiber 先挂上、旧 fiber 的 dispose 随后按同路径摘掉 面板挂载改为可自愈:拿不到服务就定时重试(panelRetryMs);挂上后记住「路由表里那条是不是我挂的」,卸载时只摘自己那条,不是自己的连 dispose 都不调(它按路径无条件删)。新增 3 项确定性回归测试(就绪即挂 / 晚到重试 / 旧 fiber 不得摘新的)
9 上述失效之所以查了半天,是因为日志根本没有出口:本机 profile 里 ctx.get('logger') 是 undefined,log() 全是空操作,异常路径也没落盘 新增 note()/writeDiag():异常路径(晚到挂载、挂载失败)一律落盘 ~/.dsh/super-injector/dsh-court-apply.log 与插件包目录,正常流水不写;DSH_COURT_DIAG_DIR 可改道(测试用,避免污染包目录)。测试断言「留痕」这件事本身

同轮更正的口径:README 原写「边界写进 persona」,实为三重落地(persona + 只读白名单 + sessionId 护栏),POWER_LINES 只供展示;「拦 court_*」收窄为「拦 court_hold」;配置表由「10 行/12 键」改为 13 行 13 键(一项一行)。


十、v0.1.2:面板按 GitHub 设计重做 + 朝堂信息另起分支对话(2026-10-06)

需求四条:① 参照 GitHub 的项目设计 UI;② 主色黑金、副色灰红;③ 新增「朝堂信息另起分支对话」;④ 三省六部各有边框。

需求 落地 机器判据(哪条测试在钉它)
参照 GitHub 设计 照 Primer(Dark) 的骨架与尺寸层级:1px 描边 + 6px 圆角卡片、药丸 Label、Counter、BlankSlate 空态、btn/btn-sm、Primer 表格;页头底部描边 client-smoke「配色与骨架」断言 .ct-card{border:1px solid …;border-radius:6px}、.ct-counter、.ct-blankslate、.ct-btn、border-radius:2em 等规则存在
主色黑金 黑=画布 #0d1117 / 面板 #161b22;金=#e3b341(在朝、准奏、主按钮、边框 hover 转金、官署名) 同上,逐色断言
副色灰红 灰=#8b949e(次要文字、中性状态、描边);红=#f85149(封驳、失手、危险操作按钮) 同上,逐色断言
三省六部各有边框 中书省/门下省/尚书省 3 张 + 吏户礼兵刑工 6 张 + 御史台 1 张 = 10 张独立边框卡(.ct-office,整圈 1px + 左侧 3px 状态色条),每张带状态药丸、职权行、摘要、展开原文、⎇ 分支 client-smoke 渲染 RunCard 后断言卡数=10、官署名与顺序、每卡恰好 1 枚状态药丸、点击回调的 scope 序列
三省卡有内容可看 /run 全文快照补 drafts[].text 与 reviews[].opinions/concur——原先只有 brief,中书/门下两张卡必然空 host-smoke 断言轻量档无 text/opinions、全文档有;client-smoke 真实 HTTP 探针断言 /run 每稿带 text
朝堂信息另起分支对话 GET /court/api/branch?id=&scope=(host 出文书)→ sessions.fork({sessionId, increaseTitle:true}) → retain + session.prompt(文书,'queue') → uiWorkspace.openSession(child);scope ∈ 整场/三省/御史台/六部名 client-smoke 断言调用序列 fork→retain→prompt→release→openSession、fork 参数、投喂 mode=queue、scope 取数 URL、四条失败路径文案;host-smoke 断言种子内容与裁剪口径

为什么分支文书由 host 出、而不是面板拼:① 体例只有一处,分支里的 agent 读到的格式稳定;② 截断口径唯一(单段 6000 / 总 40000);③ 纯函数可直接单测——面板拼装的话这段逻辑在 host 侧无法验证。

真实数据抓出的一个缺陷(已修):/branch?scope=shangshu 的奏疏段原先取 run.memorial.text——那是都省那一次输出的原始 JSON(实测 5,653 字),而「呈御前的完整奏疏」是 engine 的 memorialText(实测 17,766 字,含圣旨/敕令/六部回报/按劾/终稿,也正是 court_status 给用户看的那一份)。两者在真实朝议里差 3 倍,等于把「都省分支」喂成残卷。现改为优先 memorialText,并加断言钉死(shangshu 必须含「奏疏(呈御前)」、且不得出现都省原始 JSON)。 发现方式:tests/capture-branch-evidence.mjs 拿真实朝议逐个 scope 核对取舍——构造数据的单测不会暴露这个问题,因为构造数据里这两份文本本来就没差别。同轮还修掉两处只有渲染出来才看得见的瑕疵:官署卡左侧状态色条恒灰(--oc 没在任何状态类里赋值,等于没生效)、阶段文案与状态药丸重复显示(phase='退朝' + status=done 各显示一遍「退朝」)。

实测(2026-10-06,本机):host-smoke 22 项 + client-smoke 20 项(含真实 HTTP 探针)退出码均 0;热重载后线上 GET /court/api/state → version=0.1.2;client Inspect 实时注册表里 conversation.view 有 {registrant: dsh-court, id: dsh-court, order: 40, active: true}、settings.section 有 {registrant: dsh-court, id: dsh-court-roster, order: 60, active: true}。

两场真实朝议端到端(node tests/capture-branch-evidence.mjs 逐个 scope 核对取舍,原始数据存 evidence/branch-source-*.json、branch-seeds-*.json):

场次 结果
court-muvg8jeu-1(修复前) 11 个 scope 里 shangshu 核对失败(奏疏段给的是都省原始 JSON)→ 据此修掉该缺陷
court-muvgg1a4-1(修复后) 11 个 scope 全部通过:整场 25,583 字 | 中书 9,631 | 门下 4,251 | 尚书 9,929(含呈御前奏疏)| 御史 2,755 | 单部 343–454 字——「点哪块带哪块」在真实数据上成立

静态设计预览:npm run preview 生成 evidence/panel-preview.html(无浏览器也能看面板长相;数据是样例,不含交互)。


十一、v0.1.3:树状朝堂 + 朝堂问对(有实际作用、不跳转)(2026-10-06)

需求四条:① UI 呈树状图,有尊卑井井有条的感觉;② 参照 GitHub 的项目设计 UI,主色黑金、副色灰红(沿用);③ 朝堂对话有实际作用且别跳转;④ 别动别的插件的 UI。

需求 落地 机器判据(哪条测试在钉它)
树状图 一场朝议渲染成一棵树:皇帝(圣旨)d0 → 三省 d1 → 六部 d2(挂在尚书省之下,退让一格) → 御史台 d1 走虚线独立轨道;层级靠 .ct-rail 轨道 + 折角横线表达,末枝在折角处收住 client-smoke「树状图:皇帝为根…」断言深度集合 = {0,1,2}、根唯一、三省/御史台 = d1、六部 = d2、官署名与顺序;「层级靠连线表达」断言每个 d>0 节点恰有 1 条轨道、末枝有 is-last、虚线轨道唯一且属于御史台,并断言对应的 CSS 规则存在(d1 缩进 14 / d2 缩进 34 / 折角 14px / is-dashed 虚线)
尊卑井井有条 官称 + 品级徽(中书令·侍中正三品、尚书令正二品、六部尚书正三品,依《唐六典》卷八·卷九与《新唐书·百官志》);省一级字号/底色坐实,部一级退半格;主脉金线、支脉灰线 client-smoke「尊卑有据」逐条断言 10 个徽的文案与顺序(御史台不著品级,故只写官署名);CSS 断言 .ct-node.d2 .ct-office 有独立的字号/底色规则
参照 GitHub + 黑金灰红 骨架仍照 Primer(Dark);主色黑 #0d1117/#161b22 + 金 #e3b341;副色灰 #8b949e + 红 #f85149;另加古代质感:匾额页头(金线 + 回纹牙子)、朱印、衬线官名、简牍式事实栏 client-smoke「配色与骨架」逐色 + Primer 骨架断言;--c-serif 与 .ct-seal 存在性断言
朝堂对话有实际作用 问对 = 真 fork 一个会话,把该 scope 的朝堂文书 + 垂询一起投喂(queue),分支里的 agent 拿到全部文书后真办事(能读文件、跑命令、返工);后续追问只发问题本身;止 停当前一轮 client-smoke「问对链路」断言 fork→retain→prompt 序列、increaseTitle、retain 白名单 source、queue、prompt 内含文书抬头 + 【朕的垂询】 + 问题、scope 取数 URL;「后续垂询」断言只发问题且 asked 递增、cancel 可调
别跳转 面板订阅分支的 eventSource,只取 fork 之后的新事件(seq > 基线)就地渲染成 朕 / 对 / 办 三种行;可执行代码里没有 openSession / uiWorkspace client-smoke「不跳转」——去掉注释后扫描源码不得出现 openSession / uiWorkspace;「问对链路」再断言调用序列里没有 openSession;「就地回话」用一段含父会话历史的假事件窗口,断言旧history被基线过滤、四类事件分类正确、种子文书显示时被折叠成垂询
别动别的插件的 UI 样式表里每一条选择器都以 .ct-root 开头(含状态类 .st-* 与 @keyframes ct-pulse),零全局选择器、零全局状态类 client-smoke「样式零外泄」逐条解析 STYLE 的选择器并断言全部以 .ct-root 开头(@ 规则与 keyframe 步进除外),并断言动画名带 ct- 前缀

实测(2026-10-06,本机):node --check lib/client.js 0;host-smoke 22 项 + client-smoke 25 项(含真实 HTTP 探针)退出码均 0;热重载后线上 GET /court/api/state → version=0.1.3;client Inspect 实时注册表里 conversation.view 仍是 {registrant: dsh-court, id: dsh-court, order: 40, active: true}。

肉眼复核(这轮特意做了):npm run preview → evidence/panel-preview.html → 无头 Edge 截图 evidence/panel-preview.png。截图当场抓出一个真问题:预览页当初没把内容包进 .ct-root,于是整页"只有按钮有样式、其余全黑"——一眼看像面板坏了。这正是「样式全部 scope 在 .ct-root 之下」的副作用,预览壳必须跟着改(已修)。这类问题单测永远抓不到:preview.mjs 的存在价值就在这里。

本轮另装了三个 GitHub 上的 Agent Skills(用 skill 工具加载,装到 ~/.agents/skills/):

  • frontend-design(anthropics/skills)——按它的判据自检并据此改了几处:去掉「A · B · C」式的 meta 串烧(改成简牍式事实栏)、不再给每块内容套同一套圆角卡片(改为层级树)、把"重音"只花在一处(朱印 + 御座)、三省才编号(因为那确实是先后次序);
  • webapp-testing(anthropics/skills)——本地 web 应用的 Playwright 验证套路;本轮实际用的是它同一个思路的手工版(无头 Edge 截图);
  • theme-factory(anthropics/skills)——主题 token 参考。

同轮修掉的渲染/工程瑕疵:TreeNode 的 <span class="ct-node-tip"> 飘在节点右上角离官名太远(改成节点行内的「一 拟 / 二 审 / 三 行」);写这段嵌套结构时括号对不上(node --check 报 Unexpected token ')'),改用「按行号整块替换」的确定性补丁器定位并修好(该补丁器的教训:手写深层嵌套 JSX 时不要用肉眼数括号,用 node --check 当门禁)。


十二、v0.1.4:自上而下 + 各部对话折叠 + 二十四司(2026-10-06)

改的是同一棵树,不是重画一棵。

要求 实现 断言
朝堂对话直接显示在朝堂面板里 撤回「面板底部一块共享对话区」的做法:每个节点自带一格「朝堂对话」,分支回话 / 输入框 / 止 全在该节点内 client-smoke「对话就地」:11 块(御座 + 三省 + 六部 + 御史台),每块 data-scope 对应一个 scope,默认全收起;「不跳转」照旧扫描 openSession / uiWorkspace
树状图 沿用 v0.1.3 的轨道 + 折角连线(三省金线主脉、六部灰线支脉、御史台虚线) 「树状图」「层级靠连线表达」断言不变
各部对话折叠可展开 节点页脚一枚 问对(展开后变 收起),折叠时只占一行;那一行标题也可点开;展开态在该节点内往下长 「对话入口」断言 10 枚 问对 + 卡头 朝堂问对;「对话就地」断言默认无 is-open
自上而下 树容器 flex-direction:column;御座 d0 → 三省 d1 → 六部 d2 → 御史台 d1 依次向下;每块折叠区都往下长 新断言「自上而下」:主节点深度序列 [0,1,1,1,2,2,2,2,2,2,1] + 三条 CSS 规则存在性
三省六部二十四司 六部各带一行折叠「二十四司 · 本部下四司」(吏部司/司封/司勋/考功 … 工部司/屯田/虞部/水部),展开列出四司与职掌 新断言「三省六部二十四司」:6 部 × 4 司 = 24、每部司名逐个比对、每司有职掌说明、树上恰 6 个折叠开关、默认收起

口径:二十四司是书志层级(依据 docs/tang-liubu-ershisi-si-kaoju.md:《唐六典》卷二—卷七 + 《旧唐书》卷四三)——朝议仍只派工到部、不派到司;面板只是把「部下有哪四司」摆出来,不假造一层执行单位。

实测(2026-10-06,本机):node --check 四个 lib 文件全 0;host-smoke 22 项 + client-smoke 28 项(含真实 HTTP 探针)退出码均 0;热重载后线上 GET /court/api/state → version=0.1.4;tests/preview.mjs 重新生成 evidence/panel-preview.html(13 个树节点 / 轨道 12 条 / 10 张官署 / 11 枚状态药丸),无头 Edge 截图 evidence/panel-preview.png 肉眼复核:御座在最上、六部逐级退让、每节点带「二十四司」与「朝堂对话」折叠行、展开态两格对话(整场 / 工部)显示 朕/对/办 与「递牌子」。

一处顺带修的体验:折叠态那一行标题原本不可点(只有页脚按钮能开),现在整行可点(.ct-talk-hd.is-clickable,hover 微微提亮)——「折叠可展开」的东西,用户会本能地点那一行。

踩记:这轮改 lib/client.js 又触发了热重载,把当时正在跑的那场朝议(court-muvhe50g-1,用来复核「别的插件 UI 消失」)清空了——这是本项目第 3 次踩同一个坑:改 client 前先确认没有在跑的朝议,或先 court_status 收下结论。


十三、v0.1.5:底色与对话面板同源 + 收起态压成一行 + 一次「复现不出来」的排查(2026-10-06)

1. 底色不再自带「另一块黑」

原来 .ct-root 自己铺 #0d1117(Primer 画布色),而 DSH 深色对话面板的底是 #151517 —— 两块黑差一档,面板像贴在对话区上的一张纸。v0.1.5 起:

  • .ct-root 不再自己画底(background:transparent),直接透出所在面板的底色;
  • 颜色一律取自 DSH 自己的主题令牌(由 cordis_inspect_query 的 client/Theme listTokens 给清单,值从 dsh-client-ui-theme 的 dark 块取):--dsw-alias-bg-base(dark = #151517)、--dsw-alias-bg-layer-1/2(#232324 / #2c2c2e)、--dsw-alias-border-l1/l2(#ffffff0f / #ffffff1f)、--dsw-alias-label-primary/secondary、--dsw-alias-state-error-primary;取不到才退回内置深色值(每个都写成「先常量、再 color-mix() 覆盖」两行,老浏览器也吃得住);
  • 金 #e3b341 / 红 #f85149 / 灰(label-secondary)仍作 accent —— 项目口径「黑金主色、灰红副色」不变,只是「黑」跟着 DSH 走;顺带把散在样式里的 7 处硬编码色(#c9d1d9/#eef3f8/#dbe3ec/#d7dee6/#171c24 等)一并收进令牌。

实测(真浏览器):无头 Edge + CDP 打开会话视图 → 朝堂,getComputedStyle 得 .ct-root = rgba(0,0,0,0)、所在容器 Dc7zOa_root = rgb(21,21,23),中间整条祖先链全透明 —— 面板与对话面板同一个底色。设置页那一格同理(设置 → 三省六部 首次实测:6 节点 6 轨道;设置弹窗是浅底,面板也跟着浅,不再是一块突兀的黑)。

2. 收起态压成一行

.ct-talk:not(.is-open) .ct-talk-hd{flex-wrap:nowrap;overflow:hidden} + 标题/说明 nowrap + text-overflow:ellipsis(说明 flex:1 1 auto;min-width:0):窄了也只占一行,长句变省略号;展开态保持 wrap(那一行还要放「已递 N 次 / 分支 id / 收起」)。

实测:11 个折叠行高度 36,31,31,31,32,31,31,31,31,31,31(真折两行会到 ~50px),其中唯一 flex-wrap:wrap 的那个正是被点开的那格。

3. 「不能正常运行」的排查(结论:本机复现不出来,附证据)

四条线逐条验,全部通过:

线 查法 结果
host 路由 GET /court/api/state 200,version=0.1.5
工具 cordis_inspect_query host/Tool court_hold / court_status / court_ministries / court_dismiss 四件在册
端到端 court_hold {background:true} 真开一场(court-muvkisqs-1)→ 面板实时画到「六部并行(5 部)」→ court_dismiss 通过(跑完即散朝)
真浏览器 CDP:朝堂 = 12 轨道 / 13 节点 / 11 折叠行;点 刷新、点折叠行、点 朝堂问对 均无 JS 异常(页面只有 memory-evolve 那 7 条既有 404,与本插件无关) 通过
数据面 把真朝议快照做成夹具(court-audit/build-fixture.mjs → fixture/)喂进面板 树/奏疏/按劾/二十四司全画得出

最像「不能运行」的两种正常情形:① 面板是会话视图里的标签页(与 对话/轨迹/记忆… 并列),不在对话流里,得点 朝堂 才看到;② 朝议历史只在内存,热重载/重启后归零 —— 看到「尚无朝议」不是坏了,是还没有朝议(court_hold 下旨即可)。另:面板头部现在会显示版本号,看到 v0.1.5 才说明浏览器吃到了新包,否则按一次 Ctrl+R。

排查工具(可复用,落在工作区 court-audit/):live-ui-probe.mjs(无头 Edge + CDP:抓 console/异常、量 DOM、截图;支持 FIXTURE_DIR= 注入夹具、CLICKS=/CLICK_SELECTORS= 点进去)、build-fixture.mjs(真朝议快照 → 面板夹具)、ui-incident/tools/dsh-fetch.mjs(铸 DSH 会话 cookie,带鉴权取 shell HTML / bundle)。坑:本机受限沙箱里无头 Edge 起不来(exit 13),需要一次性 danger-full-access 才出得来图。


十三、v0.1.5:底色与对话面板同源 + 收起态压成一行 + 一次「查不出 bug」的排查(2026-10-06)

1. 底色不再自带「另一块黑」

原来 .ct-root 自己铺 #0d1117(GitHub Primer 的画布色),而 DSH 深色对话面板的底是 #151517 —— 两块黑差一档,面板像贴在对话区上的一张纸。v0.1.5 起:

  • .ct-root 不再自己画底(background:transparent),直接透出所在面板的底色;
  • 所有颜色取自 DSH 自己的主题令牌(cordis_inspect_query 的 client/Theme listTokens 给出清单):--dsw-alias-bg-base(dark = #151517)、--dsw-alias-bg-layer-1/2、--dsw-alias-border-l1/l2、--dsw-alias-label-primary/secondary、--dsw-alias-state-error-primary,取不到才退回内置深色值(每个都写成「先给 fallback 常量、再用 color-mix() 覆盖」两行,老浏览器也吃得住);
  • 金 #e3b341 / 红 #f85149 / 灰(label-secondary)仍作 accent —— 项目口径的「黑金主色、灰红副色」不变,只是「黑」跟着 DSH 走。

实测(真浏览器):无头 Edge + CDP 打开会话视图 → 朝堂标签页,getComputedStyle:.ct-root = rgba(0,0,0,0),其所在容器 Dc7zOa_root = rgb(21,21,23);整条祖先链(viewArea / scrollBody / body)全透明 —— 也就是面板与对话面板同一个底色。设置页那一格同理(设置弹窗是浅底,面板也跟着浅,不再出现一块突兀的黑)。

2. 收起态压成一行

.ct-talk:not(.is-open) .ct-talk-hd{flex-wrap:nowrap;overflow:hidden} + 标题/说明 nowrap + text-overflow:ellipsis(说明 flex:1 1 auto;min-width:0)——窄了也只占一行,长句变省略号;展开态保持 wrap(那一行要放「已递 N 次/分支 id/收起」)。

实测:11 个折叠行的实测高度 36,31,31,31,32,31,31,31,31,31,31(两行会到 ~50),其中唯一 flex-wrap:wrap 的那个正是被点开的那格。

3. 「不能正常运行」的排查(结论:本机复现不出来,附证据)

按「面板/工具/路由/交互」四条线逐条验,全部通过:

线 查法 结果
host 路由 GET /court/api/state 200,version=0.1.5
工具 cordis_inspect_query host/Tool court_hold / court_status / court_ministries / court_dismiss 四件在册
端到端 court_hold {background:true} 真开一场(court-muvkisqs-1)→ 面板实时画到「六部并行(5 部)」→ court_dismiss 通过(跑完即散朝)
真浏览器 CDP:朝堂标签页 = 12 轨道 / 13 节点 / 11 折叠行;点 刷新、点折叠行、点 朝堂问对 均无 JS 异常(页面上只有 memory-evolve 那 7 条既有 404,与本插件无关);设置 → 三省六部 那一格首次验证:6 节点 6 轨道正常 通过
数据面 用真朝议快照当夹具(court-audit/fixture/,由 build-fixture.mjs 生成)喂进面板 树/奏疏/按劾/二十四司全画得出

最可能的一种「看起来不能运行」:面板是会话视图里的标签页(与 对话/轨迹/记忆 … 并列),不在对话流里;且历史朝议只在内存 —— 热重载/重启后 court_status 与面板都归零,只剩「尚无朝议」空态。若看到的是空态,那不是坏了,是还没有朝议:court_hold 下旨即可,或点 刷新。

排查工具(可复用,落在 court-audit/):live-ui-probe.mjs(无头 Edge + CDP:抓 console/异常、量 DOM、截图;支持 FIXTURE_DIR 注入夹具、CLICKS/CLICK_SELECTORS 点进去)、build-fixture.mjs(真朝议快照 → 面板夹具)、ui-incident/tools/dsh-fetch.mjs(铸 DSH 会话 cookie 以便带鉴权取 shell HTML/bundle)。注意:本机受限沙箱里无头 Edge 起不来(exit 13),要一次性 danger-full-access。


第二十七节 · v0.12.0:回报契约 · 权限降级收口 · 阶段分级(2026-11-09)

三处低风险结构改进,均不改变任何控制语义,只在「回报是否可信」「降级后还剩多少护栏」「失败算哪一类」三处收紧。

1. 回报契约(lib/protocol.js 的 RESULT_CONTRACT)

parseJson 成功 ≠ 契约成立:模型可能给出合法 JSON 却缺关键字段(典型:门下省只回 {"理由":"可行"},缺 准奏——下游会把「缺字段」读成「封驳」)。现在每阶段有最小字段契约:

契约 阶段 必需字段
taizi 太子分拣 判 / kind / verdict 任一
edict 中书拟敕 敕令 / orders 非空数组
review 门下审覆 准奏 / accept(false 也算在场)
memorial 都省覆核 奏疏 / memorial / 总述
censor 御史台 弹劾 / 按劾 / 无异议的部 / 总评
minister 六部办案 办案 / 本部小结 / 部
si 二十四司承差 承差 / 本司小结 / 司

不合格时补问一次格式(repairTask:只补字段、结论不得改;原文截 4000 字),仍不合格则保留原回报、记账,交阶段分级裁量——不把「写漏字段」升级成整场失败。统计进 run.schema(checked/failed/repaired/repairedFailed),随快照与奏疏外露。尚书「下发二十四司」不设契约(既有「派工不可用 ⇒ 本部自理」降级路径优先)。

2. 权限降级收口(cfg.unsandboxedFallback + 统一子会话护栏)

  • spawn 降级阶梯的第三档(不给 toolFilter)默认禁止:宿主两次都不接受白名单时该阶段判失败交人裁决。只有显式 unsandboxedFallback:true 才保留旧行为。
  • court_* 六个工具对朝议子会话统一拦(此前只有 court_hold 挂护栏)——子 agent 调 court_status / court_ministries / court_dismiss / court_control / court_templates 一律驳回。

3. 阶段分级 + 机读完整性(integrityOf)

  • critical:太子分拣失手(无 JSON 且阶段 error)⇒ 直接判 failed;门下审覆全无裁定 ⇒ failed(与制度性的「封驳不过则止」rejected 区分开,reviews[].jsonOk 记录每一轮到底有没有裁定)。
  • best-effort:六部办案、御史台、都省收官仍是 warn/失败可入奏,不阻断整场。
  • 快照新增 integrity = { decree, ministers:{reported,failed,total}, censor, reconcile, schema, partial };奏疏加一行人读「完整性:…」与文末机读行 INTEGRITY {json}——面板、下游 agent、离线审计都能直接读缺件,不再靠人翻注记。

复跑

node tests/host-smoke.mjs            # 引擎/工具/协议(本版新增契约、补问、降级、护栏、完整性断言)
node tests/client-smoke.mjs --offline  # 面板静态断言(--offline 不打真 HTTP,避免污染在办朝议)
node --check lib/engine.js && node --check lib/protocol.js && node --check lib/index.js
—/ 5

No ratings yet

Verified DSH bundle

Commit 9d156dfacb04

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout