dsh-kingdom 0.6.0 → 0.8.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.
Files changed (64) hide show
  1. package/README.md +6 -3
  2. package/lib/adapter/contract.js +2 -0
  3. package/lib/adapter/contract.js.map +1 -0
  4. package/lib/adapter/dsh-backend.js +277 -0
  5. package/lib/adapter/dsh-backend.js.map +1 -0
  6. package/lib/adapter/session-store.js +76 -0
  7. package/lib/adapter/session-store.js.map +1 -0
  8. package/lib/capability/dsh-enforcement.js +241 -0
  9. package/lib/capability/dsh-enforcement.js.map +1 -0
  10. package/lib/capability/resolver.js +66 -0
  11. package/lib/capability/resolver.js.map +1 -0
  12. package/lib/capability/service.js +117 -0
  13. package/lib/capability/service.js.map +1 -0
  14. package/lib/core/binding.js +27 -12
  15. package/lib/core/binding.js.map +1 -1
  16. package/lib/core/db.js +991 -28
  17. package/lib/core/db.js.map +1 -1
  18. package/lib/core/execution.js +8 -3
  19. package/lib/core/execution.js.map +1 -1
  20. package/lib/core/governed.js +540 -0
  21. package/lib/core/governed.js.map +1 -0
  22. package/lib/core/kingdom.js +4 -1
  23. package/lib/core/kingdom.js.map +1 -1
  24. package/lib/core/task-service.js +173 -36
  25. package/lib/core/task-service.js.map +1 -1
  26. package/lib/core/territory.js +67 -13
  27. package/lib/core/territory.js.map +1 -1
  28. package/lib/dispatch/evidence.js +128 -0
  29. package/lib/dispatch/evidence.js.map +1 -0
  30. package/lib/dispatch/reconcile.js +38 -0
  31. package/lib/dispatch/reconcile.js.map +1 -0
  32. package/lib/dispatch/service.js +95 -0
  33. package/lib/dispatch/service.js.map +1 -0
  34. package/lib/gui/contract.js.map +1 -1
  35. package/lib/gui/snapshot.js +88 -0
  36. package/lib/gui/snapshot.js.map +1 -1
  37. package/lib/index.js +193 -6
  38. package/lib/index.js.map +1 -1
  39. package/lib/types/adapter/contract.d.ts +137 -0
  40. package/lib/types/adapter/dsh-backend.d.ts +81 -0
  41. package/lib/types/adapter/session-store.d.ts +55 -0
  42. package/lib/types/capability/dsh-enforcement.d.ts +94 -0
  43. package/lib/types/capability/resolver.d.ts +40 -0
  44. package/lib/types/capability/service.d.ts +48 -0
  45. package/lib/types/core/binding.d.ts +9 -4
  46. package/lib/types/core/db.d.ts +319 -10
  47. package/lib/types/core/execution.d.ts +4 -1
  48. package/lib/types/core/governed.d.ts +164 -0
  49. package/lib/types/core/kingdom.d.ts +6 -0
  50. package/lib/types/core/task-service.d.ts +8 -5
  51. package/lib/types/core/territory.d.ts +20 -10
  52. package/lib/types/dispatch/evidence.d.ts +49 -0
  53. package/lib/types/dispatch/reconcile.d.ts +31 -0
  54. package/lib/types/dispatch/service.d.ts +56 -0
  55. package/lib/types/gui/contract.d.ts +68 -1
  56. package/lib/types/gui/snapshot.d.ts +5 -1
  57. package/lib/types/index.d.ts +14 -0
  58. package/lib/types/worker/executor-factory.d.ts +30 -0
  59. package/lib/types/worker/governed-executor.d.ts +63 -0
  60. package/lib/worker/executor-factory.js +42 -0
  61. package/lib/worker/executor-factory.js.map +1 -1
  62. package/lib/worker/governed-executor.js +118 -0
  63. package/lib/worker/governed-executor.js.map +1 -0
  64. package/package.json +2 -2
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  **在 DeepSeek Harness 里,装一个插件,拥有一个自己的 Agent 王国。**
6
6
 
7
7
  [![CI](https://github.com/lusblead/dsh-Kingdom/actions/workflows/ci.yml/badge.svg)](https://github.com/lusblead/dsh-Kingdom/actions/workflows/ci.yml)
8
- [![Version](https://img.shields.io/badge/version-0.6.0-blue)](https://github.com/lusblead/dsh-Kingdom/releases)
8
+ [![Version](https://img.shields.io/badge/version-0.8.0-blue)](https://github.com/lusblead/dsh-Kingdom/releases)
9
9
  [![License](https://img.shields.io/badge/license-BSD--3--Clause-green)](LICENSE)
10
10
  [![DSH](https://img.shields.io/badge/DSH-0.1.0--rc.5-orange)](#compatibility)
11
11
  [![Node](https://img.shields.io/badge/Node-%3E%3D22.19-339933)](#requirements)
@@ -47,6 +47,9 @@ DSH:任务 CREATED → ASSIGNED → RUNNING → REVIEW → DONE ✅
47
47
  | 🔄 **换届与会话归属**(v0.4) | `kingdom_unbind_role` 解绑 / `kingdom_bind_session` 把角色绑到**独立会话**;`session-bound` 模式下只有被绑定会话能行使职权 |
48
48
  | 🪪 **会话身份预留字段**(v0.4) | 角色可携带 `model_name` / `agent_name` / `session_meta`(JSON 扩展槽)——现在不必填,未来完整会话逐步填满 |
49
49
  | 🎭 **GUI 就绪**(可选) | 结构化快照 + 本地数据网关(默认关闭),前端页面由 GUI 部署方提供 |
50
+ | 👑 **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 裁定链不变) |
51
+ | 🛡️ **Fail-closed 能力治理**(v0.8) | 无自授 / 超 Ceiling / scope 外 / 部分 policy 一律拒绝;approval=never 禁扩权;workspace 外写真实拒绝;RECOVERING 状态如实显示,禁止显示成 Done |
52
+ | 🧩 **Legacy 兼容**(v0.8) | 旧 one-shot 路径继续 `LEGACY_COMPAT` 工作,回归全绿 |
50
53
 
51
54
  ---
52
55
 
@@ -68,10 +71,10 @@ dsh plugin --profile web add dsh-kingdom
68
71
 
69
72
  **方式 B:从 GitHub Releases 下载 tgz**
70
73
 
71
- 从 [Releases](https://github.com/lusblead/dsh-Kingdom/releases) 下载 `dsh-kingdom-0.6.0.tgz`,然后:
74
+ 从 [Releases](https://github.com/lusblead/dsh-Kingdom/releases) 下载 `dsh-kingdom-0.7.0.tgz`,然后:
72
75
 
73
76
  ```bash
74
- dsh plugin --profile web add ./dsh-kingdom-0.6.0.tgz
77
+ dsh plugin --profile web add ./dsh-kingdom-0.7.0.tgz
75
78
  ```
76
79
 
77
80
  > 安装时会打印 5 条 peer dependency warning——**这是预期的**(这些包由 DSH 运行时提供),不是失败。
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/adapter/contract.ts"],"names":[],"mappings":""}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * dsh-kingdom — v0.8 DSH Persistent Session Backend(M3-S3,RuntimeAdapter 的 DSH 实现)。
3
+ *
4
+ * 依 M3-S3 Thin Spec §2(DSH Mapping,seam 均 @ 00b7102f1d 源码核实):
5
+ * - createSession → AgentRegistry.create(meta.cwd=territory.workspace_path;setup 装配 preset)
6
+ * - resumeSession → AgentRegistry.resume(resumeSessionId=session_ref,恢复同一长期会话)
7
+ * - dispatch → agent.followup(完整 UserMessage)(C-007 负知识:禁裸 text block)
8
+ * - observeExecution → session.events 事件链重建(turn/start → turn/end → assistant/message,C-006/C-010)
9
+ * - reconcile → 两维独立(execution 事件链 / session live+persistence)
10
+ *
11
+ * 结构型局部类型(同 dsh-subagent.ts 模式):不 import dsh 类型、不新增 peer dep。
12
+ * 缺 seam 诚实返回:S4 未实现的 enforcement 面一律 CANNOT_ENFORCE(fail-closed)。
13
+ */
14
+ import { randomUUID } from 'node:crypto';
15
+ import { cleanupDshEnforcement, materializeDshEnforcement, readEnforceableSet, } from '../capability/dsh-enforcement.js';
16
+ import { terminalOutcomeOf } from '../dispatch/evidence.js';
17
+ function asAgents(value) {
18
+ return value;
19
+ }
20
+ function asPersistence(value) {
21
+ return value;
22
+ }
23
+ function asPresets(value) {
24
+ return value;
25
+ }
26
+ /** 完整 UserMessage(C-007:followup 必须收完整消息,否则毒化会话)。 */
27
+ function buildUserMessage(text) {
28
+ return {
29
+ id: randomUUID(),
30
+ role: 'user',
31
+ content: [{ type: 'text', text }],
32
+ source: { kind: 'user' },
33
+ };
34
+ }
35
+ /**
36
+ * 事件链重建 execution 观测(S3 粗粒度;S5 evidence.ts 细化到 splice/turn 边界)。
37
+ * 以「我们的消息 id 在事件流中出现之后」为起点:
38
+ * - 未见 turn/start → QUEUED(Intent 已持久、Runtime 未开工)
39
+ * - 有 turn/start 无 turn/end → RUNNING
40
+ * - ★ fail-closed(STABILITY-FINDINGS §4.2):仅当 turn/end.reason.kind=='completed'
41
+ * **且** 有 assistant/message 才 TERMINAL;interrupted/aborted/error/blocked/max-tokens
42
+ * 或缺失 → UNKNOWN(不得判 TERMINAL,绝不写 COMPLETED)
43
+ * - 无法判定 → UNKNOWN
44
+ */
45
+ export function reconstructExecutionObservation(session, sinceDispatchRef) {
46
+ try {
47
+ const events = session.events;
48
+ const startIndex = events.findIndex((event) => JSON.stringify(event.data ?? {}).includes(sinceDispatchRef) || event.type === 'user/message' && JSON.stringify(event).includes(sinceDispatchRef));
49
+ if (startIndex === -1)
50
+ return 'UNKNOWN'; // 消息不在本 session 日志(可能未落库)
51
+ const tail = events.slice(startIndex);
52
+ const turnStarts = tail.filter(e => e.type === 'turn/start').length;
53
+ if (turnStarts === 0)
54
+ return 'QUEUED';
55
+ const lastTurnStart = [...tail].reverse().find(e => e.type === 'turn/start');
56
+ const lastTurnEnd = [...tail].reverse().find(e => e.type === 'turn/end');
57
+ const startTurn = lastTurnStart?.data?.turn;
58
+ const endTurn = lastTurnEnd?.data?.turn;
59
+ const endReason = (() => {
60
+ const data = lastTurnEnd?.data ?? {};
61
+ const fromReason = data.reason !== null && typeof data.reason === 'object'
62
+ ? data.reason.kind
63
+ : undefined;
64
+ return typeof fromReason === 'string' ? fromReason : (typeof data.kind === 'string' ? data.kind : null);
65
+ })();
66
+ const hasAssistant = tail.some(e => e.type === 'assistant/message');
67
+ const outcome = lastTurnEnd && (startTurn === undefined || endTurn === undefined || endTurn >= startTurn) ? terminalOutcomeOf(endReason) : null;
68
+ if (lastTurnEnd && outcome === 'COMPLETED' && hasAssistant)
69
+ return 'TERMINAL';
70
+ if (lastTurnEnd && (outcome === 'FAILED' || outcome === 'ABORTED'))
71
+ return 'TERMINAL'; // 明确终止 reason(aborted/blocked/error/max-tokens)
72
+ if (lastTurnEnd)
73
+ return 'UNKNOWN'; // completed 无 assistant / interrupted / 缺失 → 证据不足(fail-closed)
74
+ if (lastTurnStart)
75
+ return 'RUNNING';
76
+ return 'UNKNOWN';
77
+ }
78
+ catch {
79
+ return 'UNKNOWN';
80
+ }
81
+ }
82
+ /** DSH RuntimeAdapter 实现。 */
83
+ export class DshRuntimeAdapter {
84
+ runtimeType = 'dsh';
85
+ deps;
86
+ constructor(deps) {
87
+ this.deps = {
88
+ runtimeInstanceRef: deps.runtimeInstanceRef,
89
+ provider: deps.provider,
90
+ model: deps.model ?? null,
91
+ agents: asAgents(deps.agents),
92
+ sessionPersistence: asPersistence(deps.sessionPersistence),
93
+ presets: asPresets(deps.presets),
94
+ policy: {
95
+ permission: deps.permission,
96
+ sandboxPolicy: deps.sandboxPolicy,
97
+ approval: deps.approval,
98
+ },
99
+ };
100
+ }
101
+ identify() {
102
+ return { runtimeType: this.runtimeType, runtimeInstanceRef: this.deps.runtimeInstanceRef };
103
+ }
104
+ agentOptions() {
105
+ return { provider: this.deps.provider, ...(this.deps.model ? { model: this.deps.model } : {}) };
106
+ }
107
+ composeSetup(agentPreset) {
108
+ if (!agentPreset || !this.deps.presets)
109
+ return undefined;
110
+ return async (agentCtx) => {
111
+ await this.deps.presets.mount(agentCtx, agentPreset);
112
+ };
113
+ }
114
+ async createSession(input) {
115
+ const sessionId = randomUUID();
116
+ const handle = await this.deps.agents.create({
117
+ sessionId,
118
+ meta: { cwd: input.cwd, ...(input.agentPreset ? { agentPreset: input.agentPreset } : {}) },
119
+ agentOptions: { provider: input.provider ?? this.deps.provider, ...(input.model ?? this.deps.model ? { model: input.model ?? this.deps.model } : {}) },
120
+ setup: this.composeSetup(input.agentPreset),
121
+ });
122
+ return this.toHandle(handle);
123
+ }
124
+ async resumeSession(input) {
125
+ const handle = await this.deps.agents.resume({
126
+ resumeSessionId: input.sessionRef,
127
+ agentOptions: { provider: input.provider ?? this.deps.provider, ...(input.model ?? this.deps.model ? { model: input.model ?? this.deps.model } : {}) },
128
+ setup: undefined, // resume 的 enforcement 装配由 S4 提供(Enforcement Plan → setup)
129
+ });
130
+ return this.toHandle(handle);
131
+ }
132
+ /**
133
+ * v0.8(Owner V0.8 PRODUCTION-PATH CLOSURE B):同进程 live Session 复用。
134
+ * session 已在 live registry → 返回其 handle(**不** resume);否则 null。
135
+ * DSH seam(真实 E2E 实证):`agents.resume` 对 live session 抛
136
+ * `cannot prepare ... while it is live`(PersistenceCoordinator.prepare);
137
+ * 因此「已有 current affinity 且 session 仍 live」时必须复用同一 live handle——
138
+ * 同一 session_ref = 同一持久 Session = 同一 Worker / Territory affinity。
139
+ */
140
+ getLiveHandle(sessionRef) {
141
+ const agent = this.deps.agents.get(sessionRef);
142
+ if (!agent)
143
+ return null;
144
+ return {
145
+ refs: {
146
+ runtimeType: this.runtimeType,
147
+ runtimeInstanceRef: this.deps.runtimeInstanceRef,
148
+ sessionRef: agent.id,
149
+ },
150
+ agent,
151
+ session: agent.session,
152
+ dispose: async () => {
153
+ // live agent 生命周期由宿主(AgentRegistry)管理;退役走 retireSession
154
+ },
155
+ };
156
+ }
157
+ toHandle(handle) {
158
+ const agent = handle.agent;
159
+ return {
160
+ refs: {
161
+ runtimeType: this.runtimeType,
162
+ runtimeInstanceRef: this.deps.runtimeInstanceRef,
163
+ sessionRef: agent.id,
164
+ },
165
+ agent,
166
+ session: agent.session,
167
+ dispose: () => handle.dispose(),
168
+ };
169
+ }
170
+ async observeSession(handle) {
171
+ const agent = handle.agent;
172
+ if (!agent || !agent.status)
173
+ return 'gone';
174
+ return agent.status === 'idle' ? 'idle' : 'running';
175
+ }
176
+ async retireSession(handle) {
177
+ await handle.dispose();
178
+ }
179
+ // ── Capability(S4:context-bound 集合 + preflight/materialize/cleanup)────────
180
+ /**
181
+ * context-bound Runtime Enforceable Set:回答「这次 Session 下**能** enforce 什么」。
182
+ * - tools:A∩B(A=真实 `tools.schemas()` Runtime inventory;B=preset 声明面,回退 session 装配面)——
183
+ * Owner S4 seam 裁决(A+B 组合),见 `readEnforceableSet`;
184
+ * - sandboxMode:有 confining 后端(sandboxPolicy 或 permission preset)→ 'workspace-write';
185
+ * - approvalPolicy:有禁扩权机制(approval 或 permission preset)→ 'never'。
186
+ */
187
+ async capabilities(context) {
188
+ const ctx = context;
189
+ const tools = ctx?.agent?.session ? (await readEnforceableSet(ctx, { presets: this.deps.presets })).tools : [];
190
+ const hasSandbox = Boolean(this.deps.policy.sandboxPolicy || this.deps.policy.permission);
191
+ const hasApproval = Boolean(this.deps.policy.approval || this.deps.policy.permission);
192
+ return {
193
+ tools,
194
+ sandboxMode: hasSandbox ? 'workspace-write' : null,
195
+ approvalPolicy: hasApproval ? 'never' : null,
196
+ presetId: null,
197
+ };
198
+ }
199
+ /** preflight:纯检查、零副作用(M3-S1 Stage 3)。 */
200
+ async preflight(request, context) {
201
+ const reasons = [];
202
+ const ctx = context;
203
+ if (request.approvalPolicy !== 'never') {
204
+ reasons.push('governed Execution 要求 approvalPolicy=never(禁扩权);收到 ' + request.approvalPolicy);
205
+ }
206
+ if (!ctx?.agent?.ctx?.tools?.restrict || !ctx.agent.ctx.tools.guard) {
207
+ reasons.push('agent.ctx.tools 无 restrict/guard(工具面不可 enforce)');
208
+ }
209
+ if (!request.presetId && !this.deps.policy.sandboxPolicy) {
210
+ reasons.push('sandboxPolicy 缺失且未指定 permission preset(领地写边界不可 enforce)');
211
+ }
212
+ if (!request.presetId && !this.deps.policy.approval) {
213
+ reasons.push('approval 服务缺失且未指定 permission preset(禁扩权不可 enforce)');
214
+ }
215
+ if (request.sandboxMode === 'workspace-write' && !request.territoryPath) {
216
+ reasons.push('workspace-write 要求 territoryPath(领地写边界无锚点)');
217
+ }
218
+ return { ok: reasons.length === 0, reasons };
219
+ }
220
+ /** materialize:把 EnforcementRequest 应用到 live session;失败 → DENIED + zero execution。 */
221
+ async materialize(request, context) {
222
+ const ctx = context;
223
+ if (!ctx?.agent?.session)
224
+ return { ok: false, evidenceJson: null, reasons: ['materialize: 缺少 live session context'] };
225
+ return materializeDshEnforcement(this.deps.policy, ctx, request);
226
+ }
227
+ /** cleanup:拆除 per-execution guard/restrict(session 级政策保留)。 */
228
+ async cleanup(_request, context) {
229
+ const ctx = context;
230
+ if (!ctx?.agent?.session)
231
+ return { ok: false, evidenceJson: null };
232
+ return cleanupDshEnforcement(ctx);
233
+ }
234
+ // ── Dispatch / Evidence / Reconcile ────────────────────────────────────────
235
+ async dispatch(input) {
236
+ const agent = this.deps.agents.get(input.sessionRef);
237
+ if (!agent)
238
+ throw new Error(`dsh dispatch: session ${input.sessionRef} 不在 live registry(无法 dispatch)`);
239
+ const message = buildUserMessage(input.text);
240
+ agent.followup(message); // 持久 splice 插入即「已接受」
241
+ return {
242
+ refs: {
243
+ runtimeType: this.runtimeType,
244
+ runtimeInstanceRef: this.deps.runtimeInstanceRef,
245
+ sessionRef: input.sessionRef,
246
+ runtimeDispatchRef: message.id,
247
+ },
248
+ acceptedAt: new Date().toISOString(),
249
+ };
250
+ }
251
+ async observeExecution(refs, session) {
252
+ const live = session;
253
+ if (!live || !Array.isArray(live.events) || !refs.runtimeDispatchRef)
254
+ return 'UNKNOWN';
255
+ return reconstructExecutionObservation(live, refs.runtimeDispatchRef);
256
+ }
257
+ async reconcile(kingdomDispatchId, refs) {
258
+ // session 维:live registry 或持久可恢复 → AVAILABLE;否则 UNKNOWN(GONE 需显式删除证据,S5 细化)
259
+ const live = this.deps.agents.get(refs.sessionRef);
260
+ let sessionObservation = 'UNKNOWN';
261
+ if (live)
262
+ sessionObservation = 'AVAILABLE';
263
+ else if (this.deps.sessionPersistence?.has?.(refs.sessionRef) === true)
264
+ sessionObservation = 'AVAILABLE';
265
+ // execution 维:live 会话事件链;不可判定 → UNKNOWN(fail-closed,不盲发、不 ABORT)
266
+ let executionObservation = 'UNKNOWN';
267
+ if (live && refs.runtimeDispatchRef) {
268
+ executionObservation = reconstructExecutionObservation(live.session, refs.runtimeDispatchRef);
269
+ }
270
+ return {
271
+ executionObservation,
272
+ sessionObservation,
273
+ evidence: { kingdomDispatchId, runtimeDispatchRef: refs.runtimeDispatchRef ?? null, observedAt: new Date().toISOString() },
274
+ };
275
+ }
276
+ }
277
+ //# sourceMappingURL=dsh-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh-backend.js","sourceRoot":"","sources":["../../src/adapter/dsh-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { establishAffinity, retireAffinity, } from '../core/governed.js';
2
+ /** 建立/恢复 Worker 的长期 Session 并落受治理 affinity(§20)。 */
3
+ export async function ensureWorkerSession(store, adapter, input) {
4
+ const current = store.getCurrentAffinityForWorker(input.kingdomId, input.workerBindingId);
5
+ if (current) {
6
+ // v0.8(Owner V0.8 PRODUCTION-PATH CLOSURE B):session 仍 live → 复用同一 live handle。
7
+ // DSH 的 agents.resume 对 live session 抛 `cannot prepare ... while it is live`;
8
+ // 禁止 live 时强行 resume、禁止因 resume 失败新建第二个 session(same session_ref / Worker / Territory)。
9
+ const live = adapter.getLiveHandle(current.session_ref);
10
+ if (live) {
11
+ return {
12
+ handle: live,
13
+ created: false,
14
+ affinity: { affinityId: current.affinity_id, territoryId: current.territory_id, sessionRef: current.session_ref },
15
+ };
16
+ }
17
+ // session 不 live、但可恢复 → resume persistent session_ref
18
+ const handle = await adapter.resumeSession({
19
+ sessionRef: current.session_ref,
20
+ provider: input.provider,
21
+ model: input.model,
22
+ });
23
+ return {
24
+ handle,
25
+ created: false,
26
+ affinity: { affinityId: current.affinity_id, territoryId: current.territory_id, sessionRef: current.session_ref },
27
+ };
28
+ }
29
+ // 无 current Session → 创建 → 绑定 affinity → 更新 current projection
30
+ const handle = await adapter.createSession({
31
+ cwd: input.cwd,
32
+ agentPreset: input.agentPreset,
33
+ provider: input.provider,
34
+ model: input.model,
35
+ });
36
+ const session = {
37
+ runtimeType: adapter.runtimeType,
38
+ runtimeInstanceRef: adapter.identify().runtimeInstanceRef,
39
+ sessionRef: handle.refs.sessionRef,
40
+ };
41
+ const affinity = bindWorkerSession(store, {
42
+ kingdomId: input.kingdomId,
43
+ workerBindingId: input.workerBindingId,
44
+ session,
45
+ territoryId: input.territoryId,
46
+ });
47
+ return {
48
+ handle,
49
+ created: true,
50
+ affinity: { affinityId: affinity.affinityId, territoryId: affinity.territoryId, sessionRef: session.sessionRef },
51
+ };
52
+ }
53
+ /** 落 affinity Ledger + 更新 role_binding current projection(v3 模型)。 */
54
+ export function bindWorkerSession(store, input) {
55
+ const affinity = establishAffinity(store, {
56
+ kingdomId: input.kingdomId,
57
+ workerBindingId: input.workerBindingId,
58
+ session: input.session,
59
+ territoryId: input.territoryId,
60
+ });
61
+ store.updateBindingProfile(input.workerBindingId, { sessionId: input.session.sessionRef }, new Date().toISOString());
62
+ return { affinityId: affinity.affinity_id, territoryId: affinity.territory_id, sessionRef: input.session.sessionRef };
63
+ }
64
+ /**
65
+ * 跨 Territory 迁移:retire 旧 Session(留历史证据)→ 返回后由调用方 create 新 Session 并绑定新 territory。
66
+ * 禁止 UPDATE affinity(v6 trigger 权威强制;本层显式走 retire 路径)。
67
+ */
68
+ export function retireWorkerSession(store, input) {
69
+ const current = store.getCurrentAffinityForWorker(input.kingdomId, input.workerBindingId);
70
+ if (!current)
71
+ return;
72
+ retireAffinity(store, current.affinity_id);
73
+ // current projection 清空(历史归属仍可查 affinity Ledger;Current Projection ≠ History)
74
+ store.updateBindingProfile(input.workerBindingId, { sessionId: null }, new Date().toISOString());
75
+ }
76
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/adapter/session-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * 真实工具面 shape 归一化(Owner S4 seam 裁决 · A/B 组合)。
3
+ * 接受:字符串数组 / `[{name, description, parameters}, …]`(真实 `tools.schemas()` 实证 shape)/
4
+ * 对象含 `tools`/`toolSurface`/`name` 字段(preset/mountable 声明 shape)。
5
+ * 解析失败 → 空数组(fail-closed,不默认放行)。
6
+ */
7
+ export function normalizeToolInventory(value) {
8
+ const names = new Set();
9
+ const walk = (node, isElement, depth) => {
10
+ if (depth > 3)
11
+ return;
12
+ if (typeof node === 'string') {
13
+ if (node.length > 0)
14
+ names.add(node);
15
+ return;
16
+ }
17
+ if (Array.isArray(node)) {
18
+ for (const item of node)
19
+ walk(item, true, depth + 1);
20
+ return;
21
+ }
22
+ if (node && typeof node === 'object') {
23
+ const record = node;
24
+ // 仅数组元素提取 name(schemas() 的 [{name,description,parameters}] 形态);
25
+ // 顶层/嵌套对象自身的 name(如 preset 元信息 {id,name,description})**不**作为工具名。
26
+ if (isElement && typeof record.name === 'string') {
27
+ names.add(record.name);
28
+ return;
29
+ }
30
+ // 常见声明容器字段(tools 数组 / toolSurface·toolNames 映射)
31
+ for (const key of ['tools', 'toolSurface', 'toolNames', 'allow']) {
32
+ if (record[key] !== undefined) {
33
+ const value = record[key];
34
+ if (Array.isArray(value)) {
35
+ for (const item of value)
36
+ walk(item, true, depth + 1);
37
+ }
38
+ else if (value && typeof value === 'object') {
39
+ // 工具名映射形态:{ toolName: definition }
40
+ for (const name of Object.keys(value))
41
+ names.add(name);
42
+ }
43
+ else {
44
+ walk(value, false, depth + 1);
45
+ }
46
+ return;
47
+ }
48
+ }
49
+ }
50
+ };
51
+ walk(value, false, 0);
52
+ return [...names];
53
+ }
54
+ /** preset/mountable 面解析:resolveMountable 返回值 → 工具名集(无法解析 → 空)。 */
55
+ function presetSurfaceOf(value) {
56
+ if (value === undefined || value === null)
57
+ return [];
58
+ return normalizeToolInventory(value);
59
+ }
60
+ export const ENFORCEMENT_EVIDENCE_TYPE = 'DshEnforcementEvidence/v1';
61
+ export const TEARDOWN_EVIDENCE_TYPE = 'DshEnforcementTeardownEvidence/v1';
62
+ /** per-session disposer 注册表(materialize 注册、cleanup 消费;避免把 disposer 塞进 Core 类型)。 */
63
+ const disposerRegistry = new WeakMap();
64
+ function sessionKey(context) {
65
+ return context.agent.session;
66
+ }
67
+ /**
68
+ * 从真实 DSH API 重建 context-bound RuntimeEnforceableSet(Owner S4 seam 裁决:A∩B)。
69
+ *
70
+ * - A = **Runtime Tool Inventory**:`tools.schemas()`(实证返回 `[{name,description,parameters}]`);
71
+ * - B = **Actual Agent Preset / Session Tool Surface**:仅用 `context.agentPresetId`(真实 agent preset:
72
+ * standard/code/minimal/…)调 `presets.resolveMountable(agentPresetId)`(await + catch,**禁止未处理
73
+ * rejection 泄漏**——BLOCKER #2 根因);`permission/preset` 事件值是 PermissionPresetService 的预设名
74
+ * (workspace-write 等),**绝不**传给 agentPresets(概念严格分离)。preset 无法解析 → 回退 session 装配面;
75
+ * - **Runtime Enforceable Tool Set = A ∩ B**;任一来源无法证明 → 空(fail-closed,不默认放行)。
76
+ */
77
+ export async function readEnforceableSet(context, deps) {
78
+ const events = context.agent.session.events;
79
+ const sandboxEvents = events.filter(e => e.type === 'sandbox/mode');
80
+ const approvalEvents = events.filter(e => e.type === 'approval/policy');
81
+ const presetEvents = events.filter(e => e.type === 'permission/preset');
82
+ const lastSandboxRaw = sandboxEvents.length > 0 ? sandboxEvents[sandboxEvents.length - 1]?.data?.mode : undefined;
83
+ const lastApprovalRaw = approvalEvents.length > 0 ? approvalEvents[approvalEvents.length - 1]?.data?.policy : undefined;
84
+ const lastPresetRaw = presetEvents.length > 0 ? presetEvents[presetEvents.length - 1]?.data?.preset : undefined;
85
+ const lastSandbox = lastSandboxRaw === 'read-only' || lastSandboxRaw === 'workspace-write' || lastSandboxRaw === 'danger-full-access' ? lastSandboxRaw : null;
86
+ const lastApproval = lastApprovalRaw === 'never' || lastApprovalRaw === 'ask' ? lastApprovalRaw : null;
87
+ // permission/preset 事件值 = PermissionPresetService 预设名(materialize 的 permission.set 用);非 agentPresetId
88
+ const lastPermissionPreset = typeof lastPresetRaw === 'string' ? lastPresetRaw : null;
89
+ // A:Runtime Tool Inventory(真实 schemas API;解析失败 → 空 → fail-closed)
90
+ const inventory = normalizeToolInventory(context.agent.ctx.tools?.schemas?.());
91
+ // B:Actual Agent Preset / Session Tool Surface
92
+ // 仅用 context.agentPresetId(真实 agent preset);await + try/catch 消费一切 rejection(BLOCKER #2 修复)
93
+ let surface = [];
94
+ const agentPresetId = context.agentPresetId;
95
+ if (agentPresetId && deps?.presets?.resolveMountable) {
96
+ try {
97
+ const resolved = await deps.presets.resolveMountable(agentPresetId);
98
+ surface = presetSurfaceOf(resolved);
99
+ }
100
+ catch {
101
+ // resolveMountable rejection/throw → 已消费,不泄漏;B 面视为无法证明 → 回退(fail-closed)
102
+ surface = [];
103
+ }
104
+ }
105
+ if (surface.length === 0) {
106
+ // preset 声明面无法证明(无 agentPresetId / 解析失败 / 空面)→ 回退当前 session 装配面(live schemas 实证)
107
+ surface = inventory;
108
+ }
109
+ // Enforceable = A ∩ B
110
+ const tools = inventory.filter(name => surface.includes(name));
111
+ return {
112
+ tools,
113
+ sandboxMode: lastSandbox ?? null,
114
+ approvalPolicy: lastApproval ?? null,
115
+ presetId: lastPermissionPreset ?? null,
116
+ };
117
+ }
118
+ /**
119
+ * materialize:把 EnforcementRequest 应用到一个 **live** session。
120
+ * 失败即返回 {ok:false, reasons}(调用方负责 DENIED + zero execution)。
121
+ */
122
+ export async function materializeDshEnforcement(deps, context, request) {
123
+ const reasons = [];
124
+ const disposers = [];
125
+ const applied = [];
126
+ const toolsApi = context.agent.ctx.tools;
127
+ // 1) 工具面:restrict(允许清单)+ guard(单调拒绝,body 不执行)
128
+ if (!toolsApi?.restrict || !toolsApi?.guard) {
129
+ reasons.push('agent.ctx.tools 无 restrict/guard(工具面无法 enforce)');
130
+ }
131
+ else {
132
+ try {
133
+ const d1 = toolsApi.restrict({ allow: [...request.tools] });
134
+ disposers.push(d1);
135
+ applied.push(`restrict:allow=[${request.tools.join(',')}]`);
136
+ const d2 = toolsApi.guard((exec) => {
137
+ // dsh ToolGuard 运行时契约:仅 `undefined` 放行;`null` 会被当作拒绝 reason(实测
138
+ // `Error: null`——正式入口 E2E seam)。允许 → 必须返回 undefined。
139
+ return request.tools.includes(exec.name) ? undefined : `capability not granted: ${exec.name}`;
140
+ });
141
+ disposers.push(d2);
142
+ applied.push('guard:monotonic-deny');
143
+ }
144
+ catch (error) {
145
+ reasons.push(`工具面应用失败: ${error instanceof Error ? error.message : String(error)}`);
146
+ }
147
+ }
148
+ // 2) 领地写边界 + 禁扩权:一键 preset 或逐 knob
149
+ if (request.presetId && deps.permission) {
150
+ try {
151
+ deps.permission.set(context.agent.session, request.presetId);
152
+ applied.push(`permission:preset=${request.presetId}`);
153
+ }
154
+ catch (error) {
155
+ reasons.push(`permission preset 应用失败: ${error instanceof Error ? error.message : String(error)}`);
156
+ }
157
+ }
158
+ else {
159
+ if (!deps.sandboxPolicy) {
160
+ reasons.push('sandboxPolicy 缺失(领地写边界无法 enforce)');
161
+ }
162
+ else {
163
+ try {
164
+ deps.sandboxPolicy.setSandboxMode(context.agent.session, request.sandboxMode);
165
+ applied.push(`sandbox:mode=${request.sandboxMode}`);
166
+ }
167
+ catch (error) {
168
+ reasons.push(`sandbox 应用失败: ${error instanceof Error ? error.message : String(error)}`);
169
+ }
170
+ }
171
+ if (!deps.approval) {
172
+ reasons.push('approval 服务缺失(禁扩权无法 enforce)');
173
+ }
174
+ else {
175
+ try {
176
+ deps.approval.setApprovalPolicy(context.agent.session, request.approvalPolicy);
177
+ applied.push(`approval:policy=${request.approvalPolicy}`);
178
+ }
179
+ catch (error) {
180
+ reasons.push(`approval 应用失败: ${error instanceof Error ? error.message : String(error)}`);
181
+ }
182
+ }
183
+ }
184
+ // 3) 证据核验:策略事件必须落到持久 session 日志(typed evidence 的诚实基础)
185
+ const types = new Set(context.agent.session.events.map(e => e.type));
186
+ if (request.sandboxMode !== 'read-only' && !types.has('sandbox/mode')) {
187
+ reasons.push('sandbox/mode 事件缺失(无法证明领地写边界已生效)');
188
+ }
189
+ if (!types.has('approval/policy')) {
190
+ reasons.push('approval/policy 事件缺失(无法证明禁扩权已生效)');
191
+ }
192
+ const evidenceEvents = ['sandbox/mode', 'approval/policy', 'permission/preset'].filter(t => types.has(t));
193
+ if (evidenceEvents.length > 0)
194
+ applied.push(`events=[${evidenceEvents.join(',')}]`);
195
+ if (reasons.length > 0) {
196
+ for (const dispose of disposers) {
197
+ try {
198
+ dispose();
199
+ }
200
+ catch { /* 忽略 */ }
201
+ }
202
+ return { ok: false, evidenceJson: null, reasons };
203
+ }
204
+ disposerRegistry.set(sessionKey(context), disposers);
205
+ const evidenceJson = JSON.stringify({
206
+ type: ENFORCEMENT_EVIDENCE_TYPE,
207
+ payload: {
208
+ presetId: request.presetId ?? null,
209
+ sandboxMode: request.sandboxMode,
210
+ approvalPolicy: request.approvalPolicy,
211
+ tools: request.tools,
212
+ guards: disposers.length,
213
+ sessionRef: context.sessionRef,
214
+ applied,
215
+ verifiedAt: new Date().toISOString(),
216
+ },
217
+ });
218
+ return { ok: true, evidenceJson, reasons };
219
+ }
220
+ /** cleanup:拆除 per-execution guard/restrict(session 级政策保留,由下一 plan 重设)。 */
221
+ export async function cleanupDshEnforcement(context) {
222
+ const key = sessionKey(context);
223
+ const disposers = disposerRegistry.get(key) ?? [];
224
+ disposerRegistry.delete(key);
225
+ let disposed = 0;
226
+ for (const dispose of disposers) {
227
+ try {
228
+ dispose();
229
+ disposed++;
230
+ }
231
+ catch { /* 忽略单个失败 */ }
232
+ }
233
+ return {
234
+ ok: true,
235
+ evidenceJson: JSON.stringify({
236
+ type: TEARDOWN_EVIDENCE_TYPE,
237
+ payload: { disposed, sessionRef: context.sessionRef, at: new Date().toISOString() },
238
+ }),
239
+ };
240
+ }
241
+ //# sourceMappingURL=dsh-enforcement.js.map