dsh-kingdom 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -16
- package/docs/CURRENT-USER-GUIDE.md +106 -0
- package/docs/V3.3-RELEASE-NOTES.md +46 -0
- package/lib/core/owner-binding-intent.js +168 -11
- package/lib/core/owner-binding-intent.js.map +1 -1
- package/lib/gui/console-app.js +34 -30
- package/lib/gui/console-app.js.map +1 -1
- package/lib/gui/local-control.js +59 -3
- package/lib/gui/local-control.js.map +1 -1
- package/lib/gui/owner-ui.js +71 -8
- package/lib/gui/owner-ui.js.map +1 -1
- package/lib/gui/server.js +1 -1
- package/lib/gui/server.js.map +1 -1
- package/lib/gui/workbench-ui.js +179 -10
- package/lib/gui/workbench-ui.js.map +1 -1
- package/lib/index.js +29 -8
- package/lib/index.js.map +1 -1
- package/lib/types/core/owner-binding-intent.d.ts +26 -0
- package/lib/types/gui/console-app.d.ts +1 -1
- package/lib/types/gui/control-contract.d.ts +5 -3
- package/lib/types/gui/local-control.d.ts +14 -2
- package/lib/types/gui/owner-ui.d.ts +31 -0
- package/package.json +86 -84
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**在 DeepSeek Harness 里,装一个插件,拥有一个自己的 Agent 王国。**
|
|
6
6
|
|
|
7
7
|
[](https://github.com/lusblead/dsh-Kingdom/actions/workflows/ci.yml)
|
|
8
|
-
[](docs/V3.3-RELEASE-NOTES.md)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
[](#1-前置要求)
|
|
11
11
|
[](#1-前置要求)
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
## 这是什么?
|
|
18
18
|
|
|
19
|
+
**3.3.0 的日常工作台只有三个入口:运行总览、派发任务、主管设置。**先向 DSH 会话说明需求,再由 AI 核对实际任务、领地和角色。绑定或更换主管时,会话准备完整的人类管理窗口命令,你核对预览、确认并读回结果,无需编辑 JSON 或手查内部编号。先看 [当前使用指南](docs/CURRENT-USER-GUIDE.md) 和 [3.3 版本说明](docs/V3.3-RELEASE-NOTES.md)。
|
|
20
|
+
|
|
19
21
|
3.2.1 修复派发前关联、可靠接受回执与只读恢复对账,收紧受理/验收的换绑窗口,并明确资源占用后的重新请求要求。输入缺失仍为 UNKNOWN,不提供安全作废或自动重发。查看 [3.2.1 版本说明](docs/V3.2.1-RELEASE-NOTES.md)。
|
|
20
22
|
|
|
21
23
|
3.2.0 把**主管与领地完全绑定**:任命主管时必须同时指定它的领地,席位与领地主理在同一事务里原子写入(不再可能留下"有主管、没领地"的中间态);一个领地至多一个在任主理,一个主管席位只主理一个领地;退任主管时同时解除其领地主理。同一版还修掉了交付记录区的版面塌陷。查看 [3.2 版本说明](docs/V3.2-RELEASE-NOTES.md)。
|
|
@@ -45,19 +47,20 @@ DSH:任务 CREATED → ASSIGNED → RUNNING → REVIEW → DONE ✅
|
|
|
45
47
|
|
|
46
48
|
| 特性 | 说明 |
|
|
47
49
|
|---|---|
|
|
48
|
-
| 🚀
|
|
50
|
+
| 🚀 **随包交付** | 从官方 npm 或 GitHub 获取版本包;内置 GUI 随 `lib/**` 交付,无需独立前端 |
|
|
51
|
+
| 🧭 **三个日常入口**(3.3) | 运行总览查看任务、已登记会话、领地和状态;派发任务集中创建、指派与启动;主管设置由目标会话准备绑定或接替引导 |
|
|
49
52
|
| 🏛 **完整角色体系** | Owner / Chancellor / Supervisor / Worker,角色与 Session / 模型解耦 |
|
|
50
53
|
| 📋 **治理闭环语义** | 规划 → 分配 → 独立执行 → 验收,任务状态全程留痕 |
|
|
51
54
|
| ⚖️ **Claim ≠ Fact** | **Worker 说自己完成了 ≠ 任务完成**——完成权只在 Supervisor,代码强制,不是口头约定 |
|
|
52
55
|
| 🧭 **主管与领地完全绑定**(3.2) | 任命主管必须同时指定它的领地,席位与领地主理**同一事务**原子写入;一个领地至多一个在任主理,一个主管只主理一个领地;退任主管时同时解除其领地主理。存量"未隶属领地"的席位不会被自动归属,只在界面上标注待处理 |
|
|
53
56
|
| 👁️ **Owner 逐条知悉与提问**(3.0) | 交付摘要和细项独立呈现;知悉只记录 Owner 声明已知道该内容版本,不代替质量认可或任务完成;问题记在接受该交付的主管名下,待其主动读取并回复 |
|
|
54
57
|
| 🧾 **改动证据**(3.0) | 主管确认属于本交付的文件改动可展开查看,包括有界的未提交差异快照;标明证据级别,不把 Git 时间窗口误称为 Worker 作者证明 |
|
|
55
|
-
| 👷 **Persistent Governed Worker** |
|
|
58
|
+
| 👷 **Persistent Governed Worker** | canonical headless 路径使用 `kingdom_start_task_governed`:Worker 绑定长期 DSH Session,结果结构化返回并经 Capability/Lease 治理 |
|
|
56
59
|
| 🔁 **返工留痕** | governed REWORK 复用同一 Worker Persistent Session;每次尝试(attempt)都有独立 Lease/Execution 记录 |
|
|
57
|
-
| 💾 **持久化与恢复语义** | 状态写入本地 SQLite
|
|
60
|
+
| 💾 **持久化与恢复语义** | 状态写入本地 SQLite;无法确认原执行时保持恢复核对,由主管先对账,不自动重发 |
|
|
58
61
|
| 🔄 **换届与会话归属**(v0.4) | `kingdom_unbind_role` 解绑 / `kingdom_bind_session` 把角色绑到**独立会话**;`session-bound` 模式下只有被绑定会话能行使职权 |
|
|
59
62
|
| 🪪 **会话身份预留字段**(v0.4) | 角色可携带 `model_name` / `agent_name` / `session_meta`(JSON 扩展槽)——现在不必填,未来完整会话逐步填满 |
|
|
60
|
-
| 🎛 **内置本地 GUI**(v1.0) | 直接执行 `/kingdom gui` 打开操作台,进行会话绑定的任务规划、指派、持久治理执行与审查;Owner
|
|
63
|
+
| 🎛 **内置本地 GUI**(v1.0) | 直接执行 `/kingdom gui` 打开操作台,进行会话绑定的任务规划、指派、持久治理执行与审查;Owner 配置由人类直接命令或准确激活的管理窗口确认 |
|
|
61
64
|
| 👑 **Persistent Governed Worker**(v0.8) | Worker 拥有**长期 DSH Session**(REWORK 唤醒同一 Worker);Session ↔ Territory Affinity 不可改绑;每次执行经 **Capability Gate**(仅 GRANTED+ENFORCED 才 dispatch,Runtime 无法 enforce → **DENIED + zero execution**);**Execution Lease** 互斥 + **Dispatch Intent**(crash 可 reconcile,不盲发);terminal 证据来自事件链,**Runtime 跑完 ≠ Task DONE**(Claim → Supervisor 裁定链不变)。这是 canonical headless 路径 |
|
|
62
65
|
| 🛡️ **Fail-closed 能力治理**(v0.8) | 无自授 / 超 Ceiling / scope 外 / 部分 policy 一律拒绝;approval=never 禁扩权;workspace 外写真实拒绝;RECOVERING 状态如实显示,禁止显示成 Done |
|
|
63
66
|
| 🧩 **Legacy 兼容**(v0.8) | `kingdom_start_task` 仅在用户明确选择时作为 `LEGACY_COMPAT` one-shot 入口;不会作为默认路径、错误恢复建议或 persistent 失败 fallback |
|
|
@@ -72,15 +75,16 @@ DSH:任务 CREATED → ASSIGNED → RUNNING → REVIEW → DONE ✅
|
|
|
72
75
|
- **Node.js** ≥ `22.19`(内置 SQLite,插件零原生依赖)
|
|
73
76
|
- 一个可用的模型 API key(Worker 执行需要)
|
|
74
77
|
|
|
75
|
-
### 2. 安装 v3.
|
|
78
|
+
### 2. 安装 v3.3.0
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
从官方 [npm 3.3.0](https://www.npmjs.com/package/dsh-kingdom/v/3.3.0) 获取准确版本包,再安装到自己的 DSH Web profile:
|
|
78
81
|
|
|
79
82
|
```bash
|
|
80
|
-
|
|
83
|
+
npm pack dsh-kingdom@3.3.0 --registry=https://registry.npmjs.org
|
|
84
|
+
dsh plugin --profile web add ./dsh-kingdom-3.3.0.tgz
|
|
81
85
|
```
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
也可从 [GitHub v3.3.0 Release](https://github.com/lusblead/dsh-Kingdom/releases/tag/v3.3.0) 下载同名 tgz,执行第二条命令。安装或升级后重启原 Web profile,才会加载新包;使用其他 profile 时替换 `web`。升级前先核对未决执行并一致备份 SQLite。
|
|
84
88
|
|
|
85
89
|
内置 GUI 随 `lib/**` 包含在 tgz 中,不需要额外 GUI zip:
|
|
86
90
|
|
|
@@ -96,11 +100,15 @@ Worker 才使用真实 DSH caller session 的会话绑定(`session-bound`)
|
|
|
96
100
|
|
|
97
101
|
### 3. 用 GUI 完成最小治理闭环
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
先向 DSH 会话里的 AI 说明需求,完整步骤见 [当前使用指南](docs/CURRENT-USER-GUIDE.md)。历史版本指南保留供对应安装包参考。
|
|
104
|
+
|
|
105
|
+
1. 向 AI 说:“帮我查看 dsh-Kingdom 当前的王国、领地、角色和任务;先说明缺少哪些配置,再逐项引导我确认。”已有配置就继续使用;缺少配置时,由会话准备准确输入并说明人类确认步骤。
|
|
100
106
|
2. 在本地 DSH 会话直接键入 exact `/kingdom gui`;若本机浏览器完成带 ticket 的导航,一次性入口兑换后会重定向到干净的 `/console`。若本机打开请求失败,控制会话虽已激活,但命令只显示不含 ticket 的干净 `/console` 参考地址;该地址不能完成一次性兑换,不要手工拼接或复用启动值,直接重新执行 `/kingdom gui`。
|
|
101
|
-
3.
|
|
107
|
+
3. **运行总览**查看任务、已登记会话、领地和状态;**派发任务**集中创建、指派与启动;**主管设置**复制绑定或更换请求,再到希望接任的会话交给 AI 引导。宰相会话创建任务,任务领地的主管会话指派、启动和审查。网页选择名称不会切换身份;切换会话后从该会话重新打开工作台。
|
|
102
108
|
4. Worker 输出只会进入待审状态 `REVIEW`。Supervisor 选择接受 `ACCEPT` 后才进入 `DONE`;返工 `REWORK` 回到 `RUNNING` 并保留同一 Assignment,判定失败 `FAIL` 进入 `FAILED`。不用时执行 `/kingdom gui stop` 撤销控制会话并关闭本地 server。
|
|
103
109
|
|
|
110
|
+
绑定主管可直接向目标会话说“让当前会话负责「前端」”;更换时说“把「前端」主管换成当前会话”。AI 准备完整窗口命令,你直接复制执行,打开链接、核对预览并确认,成功后再读回绑定。更换沿用原席位;如果该席位关联多个领地,引导会列出全部影响,确认后这些领地会一起由新会话负责。只想接替其中一个时停止确认,先让会话说明调整安排。
|
|
111
|
+
|
|
104
112
|
Owner 专属 JSON Slash 命令只接受单个 object envelope;未知字段、额外 token、重复字段和
|
|
105
113
|
`OWNER.session_id` 改绑会在写入前拒绝。独立 GUI/HTTP 不能自行取得 Authority;只有 direct
|
|
106
114
|
`/kingdom gui` 激活闭包内的短期控制会话才可能执行日常角色操作,浏览器 payload 不能提交
|
|
@@ -108,13 +116,16 @@ principal/session/Owner capability。
|
|
|
108
116
|
|
|
109
117
|
---
|
|
110
118
|
|
|
111
|
-
## 🛠
|
|
119
|
+
## 🛠 高级工具参考
|
|
120
|
+
|
|
121
|
+
日常先向会话说明需求,不需要记住下表。工具调用仍受真实会话角色和领地范围检查;会话准备人类管理操作时使用只读引导工具,不自动取得 Owner 权限。
|
|
112
122
|
|
|
113
123
|
| 阶段 | 工具 |
|
|
114
124
|
|---|---|
|
|
115
125
|
| 王国基础 | **`/kingdom init`**(Owner direct)· `kingdom_status`(只读) |
|
|
116
126
|
| 领地 | **`/kingdom territory.* <JSON>`**(Owner direct)· `kingdom_list_territories`(只读) |
|
|
117
127
|
| 角色 | **`/kingdom role.* <JSON>`**(Owner direct)· `kingdom_list_bindings`(只读) |
|
|
128
|
+
| 会话引导 | `kingdom_draft_owner_binding_intent`(只读准备绑定或接替步骤,不写入) |
|
|
118
129
|
| 能力治理 | **`/kingdom ceiling <JSON>`**(Owner direct) |
|
|
119
130
|
| 任务治理 | `kingdom_plan_task` · `kingdom_assign_task` · **`kingdom_start_task_governed`(CANONICAL HEADLESS)** · `kingdom_review_task` · `kingdom_list_tasks` |
|
|
120
131
|
| 显式兼容 | `kingdom_start_task`(`LEGACY_COMPAT` one-shot;必须传 `legacy_opt_in=true`,仅用户明确选择,不自动 fallback) |
|
|
@@ -160,7 +171,7 @@ Worker 交回结果 ──→ 这是一条 Claim(自述),只进 REVIEW
|
|
|
160
171
|
| `~/.dsh/kingdom/kingdom.db` | 王国全部数据(SQLite,自包含) |
|
|
161
172
|
| Schema v4 | 在既有王国、领地、角色、任务、呈报、执行与事件之外,包含 Assignment、Affinity、Capability Decision、Lease 与 Dispatch 等治理账本 |
|
|
162
173
|
|
|
163
|
-
全新库或尚无王国数据的库可直接建立 v4;已有 v3 库默认保持 v3,不会自动迁移。只有经过 Formal DB Migration Gate 明确放行后才可迁移;未迁移时 GUI governed plan 与 governed start 均 fail-closed
|
|
174
|
+
全新库或尚无王国数据的库可直接建立 v4;已有 v3 库默认保持 v3,不会自动迁移。只有经过 Formal DB Migration Gate 明确放行后才可迁移;未迁移时 GUI governed plan 与 governed start 均 fail-closed。正式用户数据库迁移未在本版验证(`NOT_RUN`),不能据此声称任意旧库兼容或迁移通过。
|
|
164
175
|
|
|
165
176
|
---
|
|
166
177
|
|
|
@@ -176,11 +187,11 @@ GUI 已内置在插件中,不需要下载或启动第二个前端项目。直
|
|
|
176
187
|
|
|
177
188
|
### 操作台能力
|
|
178
189
|
|
|
179
|
-
-
|
|
180
|
-
-
|
|
190
|
+
- 3.3.0 默认进入“运行总览”,按任务与当前登记会话分别展示领地和状态;另有“派发任务”“主管设置”两个主入口,操作步骤见 [当前使用指南](docs/CURRENT-USER-GUIDE.md)。
|
|
191
|
+
- 王国地图、用量与账本保留为高级入口;四种主题和现有角色视觉保留。任务详情继续区分治理状态、执行观察和执行者自述;未提供会话运行观测时显示未知。
|
|
181
192
|
- 四类证据分别是治理事实(`GOVERNANCE_FACT`)、运行观察(`RUNTIME_OBSERVATION`)、执行者呈报(`WORKER_CLAIM`)与派生解释(`DERIVED_EXPLANATION`),不能压成一条“总体成功”。
|
|
182
193
|
- 日常主链是规划→指派→持久治理执行→呈报进入 `REVIEW`→Supervisor 裁决 `ACCEPT/REWORK/FAIL/HANDOFF`;持久路径失败不会自动降级到 `LEGACY_COMPAT`。
|
|
183
|
-
- Owner
|
|
194
|
+
- 日常工作台中的 Owner 写入动作不直接执行(`executable=false / DIRECT_SLASH_REQUIRED`);人类配置通过准确激活的独立管理窗口预览、确认。带状态 GET 需要有效本地控制 Cookie 或已配置 bearer;内部 `readContext` 来自 direct 激活时捕获的 Session,不接受浏览器自报,也不序列化到响应。
|
|
184
195
|
- 对 `GOVERNED_PERSISTENT`,暂停、恢复、终止当前都不可执行。合法生命周期候选在会话、Supervisor、scope、Host 与命令覆盖检查通过后,投影返回 `executable=false / GOVERNED_RUNTIME_CONTROL_UNAVAILABLE`;其他状态可能不列动作或先显示更早的拒绝原因。命令名称存在不代表可验证的 Runtime control seam 已实现。
|
|
185
196
|
- 未结算的持久治理 Execution 会在访问 Runtime/Session/Lease 前阻止新 attempt;对已有 Dispatch 关联的不可判定恢复路径,Dispatch、Lease、Execution 原子进入 `RECOVERING`,不改 Task、不自动重试或伪造终态。
|
|
186
197
|
- 事件与投影 payload 经过递归、有界脱敏,但这不是提交秘密的许可。
|
|
@@ -207,6 +218,7 @@ GUI 已内置在插件中,不需要下载或启动第二个前端项目。直
|
|
|
207
218
|
| 3.1.0 | DSH 0.1.7 兼容(peer 分线声明)、无 live Agent 会话可绑定席位、`session_evidence` 证据字段 | ✅ 已发布,然后是 3.2.0 |
|
|
208
219
|
| 3.2.0 | 主管与领地完全绑定、交付区版面修复 | 已发布 |
|
|
209
220
|
| 3.2.1 | 单次派发关联、可靠 Receipt、只读恢复对账、事务授权与占用诊断修复 | 发布状态见 [Releases](https://github.com/lusblead/dsh-Kingdom/releases) 与 npm |
|
|
221
|
+
| 3.3.0 | 三个日常入口、任务/会话运行总览、集中派发、会话引导绑定与接替主管 | [GitHub](https://github.com/lusblead/dsh-Kingdom/releases/tag/v3.3.0) · [npm](https://www.npmjs.com/package/dsh-kingdom/v/3.3.0) |
|
|
210
222
|
|
|
211
223
|
> 已发布版本与市场更新状态以 [Releases](https://github.com/lusblead/dsh-Kingdom/releases) 为准(发布流程见 [RELEASE.md](RELEASE.md))。
|
|
212
224
|
|
|
@@ -214,6 +226,9 @@ GUI 已内置在插件中,不需要下载或启动第二个前端项目。直
|
|
|
214
226
|
|
|
215
227
|
## 📖 文档
|
|
216
228
|
|
|
229
|
+
- [当前使用指南](docs/CURRENT-USER-GUIDE.md) — 3.3.0 三个日常入口、会话引导绑定/更换主管与派发步骤
|
|
230
|
+
- [3.3 版本说明](docs/V3.3-RELEASE-NOTES.md) — 简化工作台、会话引导和实际验证范围
|
|
231
|
+
- [3.2.1 版本说明](docs/V3.2.1-RELEASE-NOTES.md) — 派发关联、可靠 Receipt、只读恢复对账与事务授权修复
|
|
217
232
|
- [3.2 版本说明](docs/V3.2-RELEASE-NOTES.md) — 主管与领地完全绑定、原子写入与退任联动、交付区版面修复
|
|
218
233
|
- [3.1 版本说明](docs/V3.1-RELEASE-NOTES.md) — DSH 0.1.7 兼容范围与无 live Agent 会话的席位绑定
|
|
219
234
|
- [3.0 使用指南](docs/V3.0-USER-GUIDE.md) — 交付清单、知悉、查看改动与条目问答
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# dsh-Kingdom 3.3.0 使用指南
|
|
2
|
+
|
|
3
|
+
日常只用三个入口:**运行总览、派发任务、主管设置**。也可以直接向 DSH 会话里的 AI 说需求,让它调用已开放的工具。
|
|
4
|
+
|
|
5
|
+
本指南对应 3.3.0。安装要求见 [README](../README.md#-快速开始);正式下载入口为 [npm 3.3.0](https://www.npmjs.com/package/dsh-kingdom/v/3.3.0) 与 [GitHub v3.3.0](https://github.com/lusblead/dsh-Kingdom/releases/tag/v3.3.0)。通过官方 npm 下载并安装到 Web profile:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm pack dsh-kingdom@3.3.0 --registry=https://registry.npmjs.org
|
|
9
|
+
dsh plugin --profile web add ./dsh-kingdom-3.3.0.tgz
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
安装或升级后重启原 DSH profile;使用其他 profile 时替换 `web`。已安装 3.2.1 的用户升级到 3.3.0 后可使用这三个入口,原版派发和恢复修复见 [3.2.1 说明](V3.2.1-RELEASE-NOTES.md)。
|
|
13
|
+
|
|
14
|
+
## 第一次使用
|
|
15
|
+
|
|
16
|
+
先在一个可用的 DSH 会话中说:
|
|
17
|
+
|
|
18
|
+
> 帮我查看 dsh-Kingdom 当前的王国、领地、角色和任务。我要把当前项目交给它管理;先说明缺少哪些配置,再逐项引导我确认。
|
|
19
|
+
|
|
20
|
+
已有王国和领地就继续使用。尚未初始化时,由人类在 DSH 的直接命令入口执行 `/kingdom init`。创建领地、登记执行者、模型配置和允许使用的能力,仍需经过现有的人类管理入口;让 AI 根据实际情况说明步骤和准备准确输入,不需要自己查内部编号。
|
|
21
|
+
|
|
22
|
+
准备一个负责统筹的会话和一个负责具体领地的主管会话。角色来自真实会话绑定,在网页里选择名称不会切换角色权限。宰相创建任务,主管指派、启动和审查任务;执行者的长期会话由执行流程建立,不需要提前手工创建。
|
|
23
|
+
|
|
24
|
+
在统筹会话中说:
|
|
25
|
+
|
|
26
|
+
> 把当前会话设为宰相,并引导我完成确认。
|
|
27
|
+
|
|
28
|
+
在希望担任主管的会话中说:
|
|
29
|
+
|
|
30
|
+
> 把当前会话设为「前端」的主管,并引导我完成确认。
|
|
31
|
+
|
|
32
|
+
将「前端」替换为工作台里真实、完整的领地名称。现有会话绑定引导覆盖宰相、主管任命与会话接替;其他首次配置仍使用原有管理流程,不能把这两句话理解成已完成全部初始化。
|
|
33
|
+
|
|
34
|
+
## 绑定或更换主管
|
|
35
|
+
|
|
36
|
+
在工作台的**主管设置**中查看各领地的主管和脱敏会话标识。点击“复制绑定主管请求”或“复制更换主管请求”,到你希望负责该领地的 DSH 会话发给 AI。
|
|
37
|
+
|
|
38
|
+
也可以直接说:
|
|
39
|
+
|
|
40
|
+
> 让当前会话负责「前端」。
|
|
41
|
+
|
|
42
|
+
> 把「前端」主管换成当前会话。
|
|
43
|
+
|
|
44
|
+
AI 会用当前真实会话与王国数据准备操作,并返回步骤和完整的人类管理窗口命令。你按以下顺序操作:
|
|
45
|
+
|
|
46
|
+
1. 将 AI 提供的完整命令直接放到**当前 DSH 会话的命令入口**执行一次,不修改其中字段。
|
|
47
|
+
2. 打开返回的管理链接。窗口预选本次目标;核对领地、角色与目标会话,点击“查看变更预览”。
|
|
48
|
+
3. 预览正确后点击“确认应用此变更”。这一步才写入绑定;只复制请求、生成命令或打开页面都不会更换主管。
|
|
49
|
+
4. 成功后让 AI 重新查看当前绑定,或回到主管设置重新读取,确认目标领地对应新的脱敏会话。
|
|
50
|
+
|
|
51
|
+
更换主管采用接替现有席位的方式,保留该席位与任务历史。如果同一席位负责多个领地,引导和管理窗口会列出全部受影响领地;确认后它们会一起由新会话负责。只想更换一个领地时,先停止确认,让会话说明如何调整主管安排。若领地名称不唯一、当前会话无法确认、绑定已变化,或存在未结算工作,按 AI 或窗口提示先核对;不要自行解除主管来绕过阻止。
|
|
52
|
+
|
|
53
|
+
这条路径让 AI 准备准确目标和输入。你只需说明负责哪个领地、核对预览并确认,不需要学习角色编号、会话编号或编辑 JSON。人类确认仍由你完成,AI 不能代替。
|
|
54
|
+
|
|
55
|
+
## 查看任务和会话
|
|
56
|
+
|
|
57
|
+
在对应 DSH 会话的直接命令入口执行 `/kingdom gui`,按宿主提供的链接打开工作台。默认进入**运行总览**。
|
|
58
|
+
|
|
59
|
+
| 列表 | 看什么 |
|
|
60
|
+
|---|---|
|
|
61
|
+
| 任务 | 任务名称、领地、执行者、任务状态、本次执行状态;点击任务名称查看详情 |
|
|
62
|
+
| 会话 | 当前登记角色、脱敏会话标识、领地、关联任务、已提供的执行观察 |
|
|
63
|
+
|
|
64
|
+
任务状态和执行状态分别显示。例如,任务仍在处理中,但本次执行已经结束,可能需要主管审查、返工或核对恢复结果。
|
|
65
|
+
|
|
66
|
+
| 任务状态 | 下一步 |
|
|
67
|
+
|---|---|
|
|
68
|
+
| 已创建 `CREATED` | 主管指定执行者 |
|
|
69
|
+
| 已分配 `ASSIGNED` | 主管核对本次权限后启动 |
|
|
70
|
+
| 处理中 `RUNNING` | 看本次执行记录;返工决定本身不会自动启动下一次执行 |
|
|
71
|
+
| 待审 `REVIEW` | 主管检查执行者结果,再接受、返工或判定失败 |
|
|
72
|
+
| 完成 `DONE` | 主管已接受;人类可继续查看交付,不等于人类最终验收 |
|
|
73
|
+
| 失败 `FAILED` | 查看失败原因,由主管说明后续安排 |
|
|
74
|
+
|
|
75
|
+
会话表只展示王国已登记角色与当前 Worker 长期会话,不是 DSH 的全部会话。**已登记、关联任务和执行记录,都不等于模型此刻正在生成。**主管职责范围内有运行任务时,若没有该会话的模型运行观测,仍显示未知。缺少观测不会当成闲置或已结束。
|
|
76
|
+
|
|
77
|
+
待处理、异常和最近交付在首页折叠区。地图、用量、账本等可从主管设置的高级记录进入。
|
|
78
|
+
|
|
79
|
+
## 派发一条任务
|
|
80
|
+
|
|
81
|
+
先在宰相会话中说清目标、领地和验收。例如:
|
|
82
|
+
|
|
83
|
+
> 在「前端」创建任务:修复登录页的窄屏布局。范围是登录页;验收是 390 像素宽度下没有横向滚动、按钮可以操作。先核对草稿,再创建。
|
|
84
|
+
|
|
85
|
+
宰相只能在已有领地创建任务,不能替主管启动。需要网页操作时,从宰相会话打开 `/kingdom gui`,进入**派发任务**,填写任务、范围、验收条件与领地,再点击“创建任务”。一句话输入只帮助填入草稿,不调用模型规划,也不会直接派发。
|
|
86
|
+
|
|
87
|
+
随后到该领地的主管会话说:
|
|
88
|
+
|
|
89
|
+
> 查看「修复登录页的窄屏布局」这项任务,为它指定可用执行者,核对本次所需能力后启动;结果回来后检查验收条件并给出审查结论。
|
|
90
|
+
|
|
91
|
+
也可从主管会话重新打开 `/kingdom gui`,在派发任务页完成“指定执行者”和“启动执行”。界面使用宿主允许的模式和能力;无法满足任务需要时,先让主管说明缺少什么。任命主管不会自动授予额外执行权限。
|
|
92
|
+
|
|
93
|
+
任务开始后,在运行总览查看进展。执行者提交结果会进入待审;主管接受后才变成完成。查看具体任务的详情,可以读取呈报和历史,并进入当前会话有权限的审查或恢复操作。
|
|
94
|
+
|
|
95
|
+
## 遇到提示时
|
|
96
|
+
|
|
97
|
+
| 提示或现象 | 怎么处理 |
|
|
98
|
+
|---|---|
|
|
99
|
+
| 创建任务或启动按钮不可用 | 让当前会话的 AI 说明原因;创建任务使用宰相会话,指派、启动和审查使用任务领地的主管会话,然后从该会话重新打开工作台 |
|
|
100
|
+
| 主管还没绑定,或想改由新会话负责 | 在主管设置复制请求,到目标会话交给 AI 引导确认 |
|
|
101
|
+
| 能力检查被拒绝 | 让主管核对任务要求、现有允许能力和运行配置;任命主管本身不会解决能力限制 |
|
|
102
|
+
| 工作区被占用 | 等前序任务结算后重新请求;系统不会自动把本项加入队列 |
|
|
103
|
+
| 恢复核对 `RECOVERING` | 让主管核对原执行;不要重复启动。跨重启的只读观察不自动生成执行回执或完成事实 |
|
|
104
|
+
| 提交结果不明或页面断开 | 先重新读取并核对事实,再决定下一步;不要反复点击写入按钮 |
|
|
105
|
+
|
|
106
|
+
当前流程需要会话按需读取、启动和审查,不承诺无人值守自动推进。发布与实际验证范围见 [3.3 版本说明](V3.3-RELEASE-NOTES.md);功能回归通过不等于陌生用户能独立上手,真人上手验收仍未运行。
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# dsh-Kingdom 3.3.0
|
|
2
|
+
|
|
3
|
+
3.3.0 将日常工作台集中为**运行总览、派发任务、主管设置**,并让 DSH 会话准备主管绑定或接替的完整确认步骤。普通用户先说要做什么,再核对准确目标;无需手查角色/会话编号或编辑 JSON。本版延续 3.2.1 的派发关联、可靠回执和只读恢复对账,不增加数据库迁移。
|
|
4
|
+
|
|
5
|
+
正式包入口:[GitHub v3.3.0](https://github.com/lusblead/dsh-Kingdom/releases/tag/v3.3.0) · [npm 3.3.0](https://www.npmjs.com/package/dsh-kingdom/v/3.3.0)。安装和完整操作步骤见 [当前使用指南](CURRENT-USER-GUIDE.md)。
|
|
6
|
+
|
|
7
|
+
## 本版变化
|
|
8
|
+
|
|
9
|
+
- **运行总览。** 首页分别显示任务和当前登记会话的领地、角色、关联任务与状态。任务状态、执行记录与模型此刻是否正在生成分别呈现;缺少会话运行观测时显示未知,不把关联任务当作模型正在运行。
|
|
10
|
+
- **集中派发。** 创建任务、指定执行者和启动执行集中在派发入口。宰相会话创建任务,所属领地的主管会话指派、启动和审查;按钮会说明当前权限或前置条件。网页选择角色名称不改变真实会话身份。
|
|
11
|
+
- **会话引导主管设置。** 设置页按领地展示主管,并可复制绑定或更换请求。到希望担任主管的 DSH 会话说“让当前会话负责「前端」”或“把「前端」主管换成当前会话”,AI 用真实上下文准备准确范围的十分钟管理窗口命令。
|
|
12
|
+
- **确认后再读回。** 会话准备不会写入绑定。人类复制完整命令、打开管理链接、核对预览并确认提交,随后重新读取绑定。窗口只预填准确目标;失效、歧义或关系变化不提供旧命令,未结算工作仍由现有守卫阻止。
|
|
13
|
+
- **明确整个席位的影响。** 更换主管会话沿用原席位及任务历史。同一席位如关联多个领地,摘要、步骤与窗口列出全部范围;确认后这些领地会一起由新会话负责。只想更换一个领地应停止确认,不能静默缩小席位变更的影响。
|
|
14
|
+
- **保留高级记录。** 地图、用量、账本、交付与既有详情操作继续可用,日常主导航只呈现三个入口。
|
|
15
|
+
|
|
16
|
+
## 验证与边界
|
|
17
|
+
|
|
18
|
+
已通过的开发检查包括 TypeScript 类型检查、构建、隔离回归以及本机 loopback Tool→Owner 窗口预览→显式确认→结果读回。主管引导测试覆盖首次绑定、原席位接替、多领地全范围、关系漂移、失效/外来/歧义拒绝与零写入边界;相关测试和流程契约随源码交付。
|
|
19
|
+
|
|
20
|
+
这些检查使用隔离数据库及明确的 Runtime/授权 fixture。本机 HTTP 和 DOM double 不代替真实 DSH/Provider 执行,也不证明真人能独立上手。
|
|
21
|
+
|
|
22
|
+
| 验证项目 | 当前结果 |
|
|
23
|
+
|---|---|
|
|
24
|
+
| 类型检查、构建与隔离回归 | 通过;发布记录核对最终测试结果 |
|
|
25
|
+
| 本机 Tool→Owner 窗口确认与读回 | 通过,Runtime/授权为 fixture |
|
|
26
|
+
| 当前版本真实浏览器交互 | 内置浏览器隔离 fixture:总览/详情/派发选择/主管请求复制通过;四主题与 390px 窄屏检查 |
|
|
27
|
+
| 陌生用户独立上手 | `NOT_RUN` |
|
|
28
|
+
| 完整真实 Provider 受治理执行 | `NOT_RUN` |
|
|
29
|
+
| 正式用户数据库迁移、生产性能 | `NOT_RUN` |
|
|
30
|
+
|
|
31
|
+
任务 `DONE` 仍表示主管接受,不等于人类最终验收或发布批准。会话身份、领地范围、能力检查和 Owner 人类确认没有被界面便利操作替代。
|
|
32
|
+
|
|
33
|
+
## 安装与升级
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm pack dsh-kingdom@3.3.0 --registry=https://registry.npmjs.org
|
|
37
|
+
dsh plugin --profile web add ./dsh-kingdom-3.3.0.tgz
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
安装后重启原 DSH profile。升级前核对未决执行,并一致备份 SQLite;WAL 模式不能只复制主数据库。DSH 与 Node 要求见 [README](../README.md#1-前置要求)。本版仅发布 DSH 插件,不包括本地 Codex 候选。
|
|
41
|
+
|
|
42
|
+
## 保留缺口
|
|
43
|
+
|
|
44
|
+
首次初始化、创建领地、登记执行者、模型与能力配置仍使用原有的人类管理流程;现有会话引导不能代替完整首次配置。当前也不提供安全作废未派发意图、冷启动权限/Fence 清理重建、子目录 WRITE 并发、自动排队或无人值守自动审查。找不到原派发输入仍是未知,不能据此重复启动。
|
|
45
|
+
|
|
46
|
+
3.2.1 的修复与两条 DSH 兼容线的历史验证范围保留在 [3.2.1 版本说明](V3.2.1-RELEASE-NOTES.md),不能直接继承为本版完整模型执行或真人验收结果。
|
|
@@ -68,12 +68,25 @@ function actionPattern() {
|
|
|
68
68
|
}
|
|
69
69
|
function parseNaturalLanguage(value) {
|
|
70
70
|
const normalized = withoutTerminalPunctuation(normalizeInput(value));
|
|
71
|
+
const currentSession = '(?:当前|这个|该)\\s*会话';
|
|
72
|
+
const replacement = normalized.match(new RegExp(`^(?:把|将)\\s*(.+?)(?:的)?(?:主管|主理)\\s*(?:换成|更换为|改为)\\s*${currentSession}$`, 'u'));
|
|
73
|
+
if (replacement)
|
|
74
|
+
return parsedExactSupervisorTerritory(replacement[1]);
|
|
71
75
|
const subject = normalized.match(/^(?:把|将|让)?(?:当前|这个|该)\s*会话(?:的)?(.*)$/u);
|
|
72
76
|
if (!subject)
|
|
73
77
|
return null;
|
|
74
78
|
const remainder = subject[1].trim();
|
|
75
79
|
if (!remainder)
|
|
76
80
|
return null;
|
|
81
|
+
const responsible = remainder.match(/^负责\s*(.+)$/u);
|
|
82
|
+
if (responsible)
|
|
83
|
+
return parsedExactSupervisorTerritory(responsible[1]);
|
|
84
|
+
const successor = remainder.match(/^接替\s*(.+?)(?:的)?(?:主管|主理)$/u);
|
|
85
|
+
if (successor)
|
|
86
|
+
return parsedExactSupervisorTerritory(successor[1]);
|
|
87
|
+
const appointed = remainder.match(/^(?:设置为|设为|绑定为|任命为)\s*(.+?)(?:的)?(?:主管|主理)$/u);
|
|
88
|
+
if (appointed)
|
|
89
|
+
return parsedExactSupervisorTerritory(appointed[1]);
|
|
77
90
|
// Supervisor is checked first because its territory tail is meaningful.
|
|
78
91
|
const supervisorPattern = new RegExp(`^(?:${actionPattern()})?\\s*(?:角色\\s*)?(?:辖区\\s*)?(${SUPERVISOR_ALIASES.map(escapeRegExp).join('|')})(?:\\s*(?:负责|管理|统辖)?\\s*(.*))?$`, 'iu');
|
|
79
92
|
const supervisor = remainder.match(supervisorPattern);
|
|
@@ -93,6 +106,17 @@ function parseNaturalLanguage(value) {
|
|
|
93
106
|
return null;
|
|
94
107
|
return { role_type: alias.role_type, role_alias: alias.alias, territory_query: null };
|
|
95
108
|
}
|
|
109
|
+
function parsedExactSupervisorTerritory(value) {
|
|
110
|
+
let name = value.trim();
|
|
111
|
+
const quoted = name.match(/^(?:「([^「」]+)」|“([^“”]+)”|"([^"]+)")$/u);
|
|
112
|
+
if (quoted)
|
|
113
|
+
name = quoted[1] ?? quoted[2] ?? quoted[3];
|
|
114
|
+
else if (/[「」“”"]/u.test(name))
|
|
115
|
+
return null;
|
|
116
|
+
if (!name || name.length > 2000)
|
|
117
|
+
return null;
|
|
118
|
+
return { role_type: 'SUPERVISOR', role_alias: '主管', territory_query: name, territory_exact: true };
|
|
119
|
+
}
|
|
96
120
|
function ambiguityQuestion(code) {
|
|
97
121
|
switch (code) {
|
|
98
122
|
case 'REJECTION_UNSUPPORTED':
|
|
@@ -271,13 +295,15 @@ function resolveTerritorySupervisorBinding(territory, context) {
|
|
|
271
295
|
}
|
|
272
296
|
return bindingId;
|
|
273
297
|
}
|
|
274
|
-
function resolveTerritory(query, context) {
|
|
298
|
+
function resolveTerritory(query, context, exactName = false) {
|
|
275
299
|
if (!query || territoryIsPlaceholder(query))
|
|
276
300
|
return { ok: false, code: 'TERRITORY_REQUIRED', question: ambiguityQuestion('TERRITORY_REQUIRED') };
|
|
277
301
|
if (!context.territories)
|
|
278
302
|
return { ok: false, code: 'TERRITORY_UNRESOLVED', question: ambiguityQuestion('TERRITORY_UNRESOLVED') };
|
|
279
|
-
const wanted = normalizedTerritoryLabel(query);
|
|
303
|
+
const wanted = exactName ? normalizeInput(query) : normalizedTerritoryLabel(query);
|
|
280
304
|
const matches = context.territories.filter(row => {
|
|
305
|
+
if (exactName)
|
|
306
|
+
return normalizeInput(row.name) === wanted;
|
|
281
307
|
const labels = [row.name, ...(row.aliases ?? [])].map(normalizedTerritoryLabel);
|
|
282
308
|
return labels.includes(wanted);
|
|
283
309
|
});
|
|
@@ -387,7 +413,7 @@ function canonicalSteps(parsed, operation, territory, supervisorBindingId) {
|
|
|
387
413
|
// 因此不再需要第二步 `/kingdom territory.supervisor`(旧两步草案在新语法下第一步就会被拒)。
|
|
388
414
|
return [roleBindStep(operation)];
|
|
389
415
|
}
|
|
390
|
-
function readyDraft(normalizedInput, parsed, sessionRef, territory, operation, supervisorBindingId) {
|
|
416
|
+
function readyDraft(normalizedInput, parsed, sessionRef, territory, operation, supervisorBindingId, context) {
|
|
391
417
|
const draft = baseDraft(normalizedInput, {
|
|
392
418
|
role_type: parsed.role_type,
|
|
393
419
|
role_alias: parsed.role_alias,
|
|
@@ -402,9 +428,18 @@ function readyDraft(normalizedInput, parsed, sessionRef, territory, operation, s
|
|
|
402
428
|
draft.canonical_steps = steps;
|
|
403
429
|
draft.canonical_direct_slash = steps[0]?.canonical_direct_slash ?? null;
|
|
404
430
|
draft.confirmation = DIRECT_SLASH_CONFIRM_REQUIRED;
|
|
431
|
+
if (parsed.role_type === 'SUPERVISOR' && operation.kind === 'role.session') {
|
|
432
|
+
draft.affected_territories = snapshotAffectedSupervisorTerritories(operation.args.binding_id, context);
|
|
433
|
+
}
|
|
405
434
|
return draft;
|
|
406
435
|
}
|
|
407
|
-
function
|
|
436
|
+
function snapshotAffectedSupervisorTerritories(bindingId, context) {
|
|
437
|
+
return (context.territories ?? []).filter(row => row.supervisor_binding_id === bindingId)
|
|
438
|
+
.map(row => ({ territory_id: row.territory_id, name: row.name, supervisor_binding_id: bindingId,
|
|
439
|
+
status: row.status ?? null, kingdom_id: row.kingdom_id ?? null }))
|
|
440
|
+
.sort((left, right) => left.territory_id.localeCompare(right.territory_id));
|
|
441
|
+
}
|
|
442
|
+
function readyExactRoleSessionDraft(normalizedInput, sessionRef, bindingId, roleType, context) {
|
|
408
443
|
const draft = baseDraft(normalizedInput, {
|
|
409
444
|
role_type: roleType,
|
|
410
445
|
role_alias: canonicalRoleAlias(roleType),
|
|
@@ -423,6 +458,8 @@ function readyExactRoleSessionDraft(normalizedInput, sessionRef, bindingId, role
|
|
|
423
458
|
draft.canonical_steps = steps;
|
|
424
459
|
draft.canonical_direct_slash = steps[0].canonical_direct_slash;
|
|
425
460
|
draft.confirmation = DIRECT_SLASH_CONFIRM_REQUIRED;
|
|
461
|
+
if (roleType === 'SUPERVISOR')
|
|
462
|
+
draft.affected_territories = snapshotAffectedSupervisorTerritories(bindingId, context);
|
|
426
463
|
return draft;
|
|
427
464
|
}
|
|
428
465
|
function canonicalRoleAlias(roleType) {
|
|
@@ -539,7 +576,7 @@ function buildDraftFromExactBinding(normalizedInput, bindingId, roleTypeInput, r
|
|
|
539
576
|
if (roleTypeHint !== null && roleTypeHint !== binding.role_type) {
|
|
540
577
|
return ambiguousDraft(normalizedInput, intent, 'ROLE_BINDING_UNSAFE');
|
|
541
578
|
}
|
|
542
|
-
return readyExactRoleSessionDraft(normalizedInput, session.session_ref, bindingId, binding.role_type);
|
|
579
|
+
return readyExactRoleSessionDraft(normalizedInput, session.session_ref, bindingId, binding.role_type, context);
|
|
543
580
|
}
|
|
544
581
|
function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession, forcedBindingId, forcedTerritoryId) {
|
|
545
582
|
const parsedIntent = {
|
|
@@ -559,7 +596,7 @@ function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession
|
|
|
559
596
|
let territorySupervisorBindingId = null;
|
|
560
597
|
if (parsed.role_type === 'SUPERVISOR') {
|
|
561
598
|
const resolved = forcedTerritoryId === null
|
|
562
|
-
? resolveTerritory(parsed.territory_query, context)
|
|
599
|
+
? resolveTerritory(parsed.territory_query, context, parsed.territory_exact)
|
|
563
600
|
: resolveTerritoryById(forcedTerritoryId, context);
|
|
564
601
|
if (!resolved.ok)
|
|
565
602
|
return ambiguousDraft(normalizedInput, parsedIntent, resolved.code);
|
|
@@ -578,7 +615,7 @@ function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession
|
|
|
578
615
|
kind: 'role.session',
|
|
579
616
|
args: { binding_id: forcedBindingId, session_id: session.session_ref },
|
|
580
617
|
};
|
|
581
|
-
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId);
|
|
618
|
+
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId, context);
|
|
582
619
|
}
|
|
583
620
|
if (forceRoleSession) {
|
|
584
621
|
if (parsed.role_type === 'SUPERVISOR' && territorySupervisorBindingId !== null) {
|
|
@@ -586,7 +623,7 @@ function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession
|
|
|
586
623
|
kind: 'role.session',
|
|
587
624
|
args: { binding_id: territorySupervisorBindingId, session_id: session.session_ref },
|
|
588
625
|
};
|
|
589
|
-
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId);
|
|
626
|
+
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId, context);
|
|
590
627
|
}
|
|
591
628
|
const existingSingleton = resolveExistingSingleton(parsed.role_type, context);
|
|
592
629
|
if (existingSingleton && 'ok' in existingSingleton)
|
|
@@ -596,7 +633,7 @@ function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession
|
|
|
596
633
|
kind: 'role.session',
|
|
597
634
|
args: { binding_id: existingSingleton.binding_id, session_id: session.session_ref },
|
|
598
635
|
};
|
|
599
|
-
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId);
|
|
636
|
+
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId, context);
|
|
600
637
|
}
|
|
601
638
|
return ambiguousDraft(normalizedInput, parsedIntent, 'ROLE_BINDING_UNSAFE');
|
|
602
639
|
}
|
|
@@ -605,7 +642,7 @@ function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession
|
|
|
605
642
|
kind: 'role.session',
|
|
606
643
|
args: { binding_id: territorySupervisorBindingId, session_id: session.session_ref },
|
|
607
644
|
};
|
|
608
|
-
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId);
|
|
645
|
+
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId, context);
|
|
609
646
|
}
|
|
610
647
|
const existing = resolveExistingSingleton(parsed.role_type, context);
|
|
611
648
|
if (existing && 'ok' in existing)
|
|
@@ -615,7 +652,7 @@ function buildDraftFromParsed(normalizedInput, parsed, context, forceRoleSession
|
|
|
615
652
|
: { kind: 'role.bind', args: { role_type: parsed.role_type, role_name: canonicalRoleName(parsed.role_type), session_id: session.session_ref,
|
|
616
653
|
// 主管的领地归属是任命的一部分:Draft 必须与 direct Slash 语法一致,否则草案不可执行。
|
|
617
654
|
...(parsed.role_type === 'SUPERVISOR' && territory ? { territory_id: territory.territory_id } : {}) } };
|
|
618
|
-
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId);
|
|
655
|
+
return readyDraft(normalizedInput, parsed, session.session_ref, territory, operation, territorySupervisorBindingId, context);
|
|
619
656
|
}
|
|
620
657
|
/** Parse one bounded natural-language intent without performing any write. */
|
|
621
658
|
export function draftOwnerBindingIntent(input) {
|
|
@@ -718,4 +755,124 @@ export const parseOwnerBindingIntent = draftOwnerBindingIntent;
|
|
|
718
755
|
export function serializeOwnerBindingIntentDraft(draft) {
|
|
719
756
|
return stableJson(draft);
|
|
720
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* Explain a verified binding draft without making the user learn IDs or JSON.
|
|
760
|
+
* Prefer the management window: its preview/commit path also guards unsettled
|
|
761
|
+
* work. The legacy canonical_direct_slash stays intact for compatibility.
|
|
762
|
+
*/
|
|
763
|
+
export function buildOwnerBindingGuidance(draft, context = {}) {
|
|
764
|
+
const blocked = (summary) => ({
|
|
765
|
+
kind: 'OWNER_BINDING_GUIDANCE', status: 'NEEDS_CLARIFICATION', authority_source: 'NONE',
|
|
766
|
+
owner_authority: false, write_effect: 'ZERO_WRITE', summary,
|
|
767
|
+
steps: ['在希望担任主管的会话中说明准确领地名称;会话会重新核对并准备操作。'],
|
|
768
|
+
canonical_owner_gui: null,
|
|
769
|
+
});
|
|
770
|
+
if (draft.status !== 'DRAFT_READY' || !draft.operation || draft.steps.length !== 1) {
|
|
771
|
+
const code = draft.ambiguity?.code;
|
|
772
|
+
if (code?.startsWith('SESSION_'))
|
|
773
|
+
return blocked('无法确认当前会话有效,请在希望担任主管的会话中重新提出请求。');
|
|
774
|
+
if (code === 'TERRITORY_REQUIRED')
|
|
775
|
+
return blocked('请说明准确领地名称,例如:让当前会话负责「研发领」。');
|
|
776
|
+
if (code === 'TERRITORY_NOT_FOUND')
|
|
777
|
+
return blocked('没有找到这个领地名称,请先查看工作台里的领地名称,再重新提出请求。');
|
|
778
|
+
if (code === 'TERRITORY_MULTIPLE')
|
|
779
|
+
return blocked('这个名称对应多个领地,不能自动选择;请先在管理窗口区分同名领地。');
|
|
780
|
+
if (code === 'UNSUPPORTED_INPUT')
|
|
781
|
+
return blocked('请说明要任命还是接替,例如:让当前会话负责「研发领」,或把「研发领」主管换成当前会话。');
|
|
782
|
+
return blocked(draft.ambiguity?.question ?? '本次操作尚不能唯一确定,请先补齐会话和领地信息。');
|
|
783
|
+
}
|
|
784
|
+
if (draft.owner_authority !== false || draft.authority_source !== 'NONE' || draft.write_effect !== 'ZERO_WRITE') {
|
|
785
|
+
return blocked('本次草案不能作为管理授权,请重新准备。');
|
|
786
|
+
}
|
|
787
|
+
const session = resolveTargetSession(context);
|
|
788
|
+
if (!session.ok || session.session_ref !== draft.intent.target_session_ref
|
|
789
|
+
|| session.session_ref !== draft.operation.args.session_id) {
|
|
790
|
+
return blocked('当前会话已失效或发生变化,请在要担任角色的会话中重新提出请求。');
|
|
791
|
+
}
|
|
792
|
+
if (!isExactToken(context.kingdom_id))
|
|
793
|
+
return blocked('尚未确认当前王国,请先完成初始化后重新提出请求。');
|
|
794
|
+
const operation = draft.operation;
|
|
795
|
+
let roleType;
|
|
796
|
+
let territory = null;
|
|
797
|
+
let affectedTerritories = [];
|
|
798
|
+
const bindingIds = [];
|
|
799
|
+
if (operation.kind === 'role.bind') {
|
|
800
|
+
if (operation.args.role_type !== 'SUPERVISOR' && operation.args.role_type !== 'CHANCELLOR') {
|
|
801
|
+
return blocked('本次会话引导支持主管和宰相;执行者会话由正常执行流程建立。');
|
|
802
|
+
}
|
|
803
|
+
roleType = operation.args.role_type;
|
|
804
|
+
if (draft.intent.role_type !== roleType)
|
|
805
|
+
return blocked('角色信息发生变化,请重新准备操作。');
|
|
806
|
+
if (roleType === 'SUPERVISOR') {
|
|
807
|
+
if (!operation.args.territory_id)
|
|
808
|
+
return blocked('请说明要负责的准确领地名称。');
|
|
809
|
+
const resolved = resolveTerritoryById(operation.args.territory_id, context);
|
|
810
|
+
if (!resolved.ok || resolved.supervisor_binding_id !== null
|
|
811
|
+
|| draft.intent.territory?.territory_id !== resolved.territory.territory_id
|
|
812
|
+
|| draft.intent.territory?.name !== resolved.territory.name) {
|
|
813
|
+
return blocked('领地或现任主管发生变化,请重新提出任命或更换请求。');
|
|
814
|
+
}
|
|
815
|
+
territory = resolved.territory;
|
|
816
|
+
affectedTerritories = [territory];
|
|
817
|
+
}
|
|
818
|
+
else if (resolveExistingSingleton(roleType, context) !== null) {
|
|
819
|
+
return blocked('宰相席位已有变化,请重新提出接替请求。');
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
const resolved = resolveExactBindingForSession(operation.args.binding_id, context);
|
|
824
|
+
if (!resolved.ok || (resolved.role_type !== 'SUPERVISOR' && resolved.role_type !== 'CHANCELLOR')
|
|
825
|
+
|| resolved.role_type !== draft.intent.role_type
|
|
826
|
+
|| (context.kingdom_id && resolved.binding.kingdom_id && resolved.binding.kingdom_id !== context.kingdom_id)) {
|
|
827
|
+
return blocked('现任角色已变化或不可用,请重新准备接替操作。');
|
|
828
|
+
}
|
|
829
|
+
roleType = resolved.role_type;
|
|
830
|
+
bindingIds.push(operation.args.binding_id);
|
|
831
|
+
const related = snapshotAffectedSupervisorTerritories(operation.args.binding_id, context);
|
|
832
|
+
if (roleType === 'SUPERVISOR') {
|
|
833
|
+
if (!related.length || !draft.affected_territories
|
|
834
|
+
|| stableJson(draft.affected_territories) !== stableJson(related)) {
|
|
835
|
+
return blocked('主管负责的领地范围已变化或无法核对,请重新准备并确认全部受影响领地。');
|
|
836
|
+
}
|
|
837
|
+
for (const row of related) {
|
|
838
|
+
const resolvedTerritory = resolveTerritoryById(row.territory_id, context);
|
|
839
|
+
if (!resolvedTerritory.ok || resolvedTerritory.supervisor_binding_id !== operation.args.binding_id) {
|
|
840
|
+
return blocked('受影响领地已不可用、属于其他王国或关系发生变化,请先核对主管负责范围。');
|
|
841
|
+
}
|
|
842
|
+
affectedTerritories.push(resolvedTerritory.territory);
|
|
843
|
+
}
|
|
844
|
+
if (draft.intent.territory !== null && !affectedTerritories.some(row => row.territory_id === draft.intent.territory.territory_id
|
|
845
|
+
&& row.name === draft.intent.territory.name))
|
|
846
|
+
return blocked('被点名领地与主管关系发生变化,请重新提出接替请求。');
|
|
847
|
+
territory = draft.intent.territory ?? affectedTerritories[0];
|
|
848
|
+
}
|
|
849
|
+
else if (related.length)
|
|
850
|
+
return blocked('角色与领地关系不一致,请先核对现任角色。');
|
|
851
|
+
}
|
|
852
|
+
const input = {
|
|
853
|
+
kingdomId: context.kingdom_id,
|
|
854
|
+
actions: [operation.kind],
|
|
855
|
+
scope: { kingdomWide: false, territoryIds: affectedTerritories.map(row => row.territory_id), bindingIds,
|
|
856
|
+
roleTypes: [roleType], targetSessionIds: [session.session_ref], workspaceRoots: [] },
|
|
857
|
+
ttlMs: 600000,
|
|
858
|
+
};
|
|
859
|
+
const subject = territory ? `领地「${territory.name}」的主管` : '宰相';
|
|
860
|
+
const allTerritoryNames = affectedTerritories.map(row => `「${row.name}」`).join('、');
|
|
861
|
+
const seatScopeNotice = operation.kind === 'role.session' && roleType === 'SUPERVISOR'
|
|
862
|
+
? `本次更换的是同一主管席位的会话,会同时接替全部领地:${allTerritoryNames}。若只想接替其中一个领地,请停止确认,不执行此变更。`
|
|
863
|
+
: null;
|
|
864
|
+
return {
|
|
865
|
+
kind: 'OWNER_BINDING_GUIDANCE', status: 'READY', authority_source: 'NONE', owner_authority: false, write_effect: 'ZERO_WRITE',
|
|
866
|
+
summary: operation.kind === 'role.bind' ? `已准备让当前会话担任${subject};尚未变更。`
|
|
867
|
+
: `已准备让当前会话接替${subject};保留原席位及任务历史,尚未变更。${seatScopeNotice ?? ''}`,
|
|
868
|
+
steps: [
|
|
869
|
+
...(seatScopeNotice ? [seatScopeNotice] : []),
|
|
870
|
+
'复制下方完整命令,在当前 DSH 会话的直接命令入口执行一次,打开十分钟管理窗口。无需修改命令中的字段。',
|
|
871
|
+
'打开返回的管理链接;窗口会预选本次唯一目标。核对领地、角色和当前会话,点击「查看变更预览」。',
|
|
872
|
+
'确认预览准确后点击「确认应用此变更」。只有这一步会提交;仍有未结算工作时窗口会说明阻止原因。',
|
|
873
|
+
'收到成功结果后回到当前会话继续操作;若被拒绝或结果不明,先核对结果,不重复提交或自动解除现任主管。',
|
|
874
|
+
],
|
|
875
|
+
canonical_owner_gui: `/kingdom owner.gui ${stableJson(input)}`,
|
|
876
|
+
};
|
|
877
|
+
}
|
|
721
878
|
//# sourceMappingURL=owner-binding-intent.js.map
|