dsh-session-bridge 0.3.2-alpha.1 → 0.3.2-alpha.2

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 CHANGED
@@ -131,10 +131,13 @@ That checkout frequently lags the harness the plugin is loaded into, so a green
131
131
  `build.sh` does **not** prove the plugin works on the running DSH — `build.sh`
132
132
  warns when the two versions differ. Use `npm run check:compat` for that: it
133
133
  type-checks `src/` against the `lib/types/*.d.ts` shipped inside the installed
134
- DSH package, which is the exact API surface the plugin loads against.
134
+ DSH package, then reads the built `lib/index.js.map` to verify the
135
+ self-contained bundle actually inlined that same DSH version. (Type-checking
136
+ alone is not enough — a stale checkout type-checks green while the artifact
137
+ ships old DSH code.)
135
138
 
136
139
  The GitHub Actions CI (`ci.yml`) instead resolves the `@deepseek-ai/dsh-*`
137
- prereleases from the registry — pinned to the `0.1.6-alpha.1` line, which is
140
+ prereleases from the registry — pinned to the `0.1.6-alpha.2` line, which is
138
141
  the DSH API surface this code targets — then runs `pnpm typecheck` and
139
142
  `pnpm build:client` (the self-contained `tsdown` bundle). Bump that pin
140
143
  together with the code when you migrate to a newer DSH API.
@@ -276,6 +279,19 @@ scripts/
276
279
  build.sh type-check + link types against the DSH checkout
277
280
  ```
278
281
 
282
+ ## Lifecycle and unloading
283
+
284
+ DSH ≥ 0.1.6 mounts and **unloads plugins at runtime** (Settings → Plugins, and
285
+ the injector's hot reload). This plugin unloads cleanly: it registers no
286
+ loader-level state, its tools are disposed with the plugin fiber, and the
287
+ monitor's timer is released through `ctx.effect` on unload.
288
+
289
+ One consequence of that ownership model: sessions created by
290
+ `session_bridge_create` are owned by the plugin fiber (the agent is created
291
+ under the plugin's context), so **unloading or reloading the plugin stops their
292
+ live agents**. The sessions themselves are persisted and show as offline; bring
293
+ one back with `session_bridge_resume`. Monitor watchdogs also stop on unload.
294
+
279
295
  ## License
280
296
 
281
297
  MIT
package/README.zh.md CHANGED
@@ -224,6 +224,17 @@ scripts/
224
224
  build.sh 类型检查 + 链接 DSH checkout 类型
225
225
  ```
226
226
 
227
+ ## 生命周期与卸载
228
+
229
+ DSH ≥ 0.1.6 支持**运行时挂载/卸载**插件(设置 → 插件页开关、注入器热重载)。
230
+ 本插件可干净卸载:不注册 loader 级状态,工具随插件 fiber 一并释放,监控定时器
231
+ 经 `ctx.effect` 在卸载时清理。
232
+
233
+ 该所有权模型带来一个后果:`session_bridge_create` 创建的会话归插件 fiber 所有
234
+ (agent 在插件上下文下创建),因此**卸载/重载插件会停止这些会话的活动 agent**。
235
+ 会话本身已持久化并显示为离线,可用 `session_bridge_resume` 重新上线;守护循环
236
+ 同样在卸载时停止。
237
+
227
238
  ## License
228
239
 
229
240
  MIT
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-session-bridge",
3
- "version": "0.3.2-alpha.1",
3
+ "version": "0.3.2-alpha.2",
4
4
  "main": "./lib/index.js",
5
5
  "description": "会话桥:创建主会话 / 向任意会话发消息 / 等待回复 / 读取消息 / 按名或 id 查找会话(支持跨工作区);另含监控/调度主任务与归档会话。",
6
6
  "engines": {
package/lib/index.js CHANGED
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
4
4
  import { dirname, join, resolve } from "node:path";
5
5
  import { appendFileSync, mkdirSync } from "node:fs";
6
6
  import { randomUUID } from "node:crypto";
7
- //#region node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js
7
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js
8
8
  /**
9
9
  * Shared filesystem path helpers for DeepSeek Harness user data.
10
10
  *
@@ -2200,7 +2200,7 @@ var Service = class Service {
2200
2200
  }
2201
2201
  };
2202
2202
  //#endregion
2203
- //#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
2203
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
2204
2204
  /** The one Remote failure class shared by owners, the Gateway, and consumers. */
2205
2205
  /**
2206
2206
  * One Remote call failure: a real Error carrying its stable code and typed
@@ -2345,7 +2345,7 @@ function validateName(subject, value) {
2345
2345
  if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`);
2346
2346
  }
2347
2347
  //#endregion
2348
- //#region node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-values/lib/index.js
2348
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-values/lib/index.js
2349
2349
  /** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */
2350
2350
  /**
2351
2351
  * Mark an unreachable closed-union branch.
@@ -2557,7 +2557,7 @@ function deepFreeze(value) {
2557
2557
  return value;
2558
2558
  }
2559
2559
  //#endregion
2560
- //#region node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-crypto/lib/index.js
2560
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-crypto/lib/index.js
2561
2561
  /**
2562
2562
  * Random v4 UUID, minted from `crypto.getRandomValues`.
2563
2563
  * @returns the UUID string.
@@ -2570,7 +2570,7 @@ function randomUUID$1() {
2570
2570
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
2571
2571
  }
2572
2572
  //#endregion
2573
- //#region node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-brand/lib/index.js
2573
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-brand/lib/index.js
2574
2574
  /**
2575
2575
  * Duplicate-install-safe nominal primitive helpers.
2576
2576
  *
@@ -3187,11 +3187,11 @@ defineMethod("transform", [
3187
3187
  "preserve"
3188
3188
  ], ({ inner }, isInner) => inner.toString(isInner));
3189
3189
  //#endregion
3190
- //#region node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-timeout/lib/index.js
3190
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-timeout/lib/index.js
3191
3191
  /** Largest delay Node schedules without clamping it to one millisecond. */
3192
3192
  const MAX_TIMER_DELAY_MS = 2147483647;
3193
3193
  //#endregion
3194
- //#region node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-llm/lib/index.js
3194
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-llm/lib/index.js
3195
3195
  /**
3196
3196
  * Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}.
3197
3197
  * @param summary - the producer's one-line account, of any length.
@@ -3957,7 +3957,8 @@ var LlmError = class extends HarnessError {
3957
3957
  id: model.id,
3958
3958
  ...model.name === void 0 ? {} : { name: model.name },
3959
3959
  ...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow },
3960
- ...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens }
3960
+ ...model.maxTokens === void 0 ? {} : { maxTokens: model.maxTokens },
3961
+ ...model.inputModalities === void 0 ? {} : { inputModalities: [...model.inputModalities] }
3961
3962
  });
3962
3963
  }
3963
3964
  return models;
@@ -9080,7 +9081,7 @@ function superRefine(fn, params) {
9080
9081
  return /* @__PURE__ */ _superRefine(fn, params);
9081
9082
  }
9082
9083
  //#endregion
9083
- //#region node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-storage/lib/index.js
9084
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-storage/lib/index.js
9084
9085
  /**
9085
9086
  * Backend-facing vocabulary of the storage hub: a backend owns one medium
9086
9087
  * (a file-tree root, a database file) and exposes operation groups over it.
@@ -9091,7 +9092,7 @@ function superRefine(fn, params) {
9091
9092
  /** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */
9092
9093
  const UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/;
9093
9094
  //#endregion
9094
- //#region node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+ds_404bb44176e435660710548cd6a4e0aa/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js
9095
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2_@deepseek-ai+ds_5fa439225de576bdb2338dd42cd57e82/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js
9095
9096
  /**
9096
9097
  * Domain declaration vocabulary. A spec object is the single source of a
9097
9098
  * domain's identity, layout, and record schemas: the owning package defines
@@ -9214,11 +9215,19 @@ Service.init;
9214
9215
  */
9215
9216
  /**
9216
9217
  * 兼容读取不同 dsh-session 版本上的会话事件:
9217
- * - 旧版 `Session` 暴露 `get events(): readonly SessionEvent[]`;
9218
- * - 新版(如宿主实际运行的 0.1.2-rc.x)将 `get events` 改为
9219
- * `snapshotEvents(fromSeq?, toSeqExclusive?)` 方法——`.events` 直接读取会
9220
- * 得到 `undefined`,对 for...of 迭代即抛 `events is not iterable`。
9218
+ * - 旧版 \`Session\` 暴露 \`get events(): readonly SessionEvent[]\`;
9219
+ * - 新版将 \`get events\` 改为 \`snapshotEvents(fromSeq?, toSeqExclusive?)\` 方法——
9220
+ * \`.events\` 直接读取会得到 \`undefined\`,对 for...of 迭代即抛
9221
+ * \`events is not iterable\`。
9221
9222
  * 两者都读不到(或 session 不存在)时回退为空数组,绝不抛迭代错误。
9223
+ *
9224
+ * 注意:dsh 0.1.6-alpha.1 起 \`snapshotEvents()\`(连同 \`eventAt()\` /
9225
+ * \`ownEvents()\`)已标记 @deprecated —— 官方策略是"现有逻辑可暂不迁移,但禁止
9226
+ * 新增调用";其替代不是同步读,而是(a)恢复后读取 Session 投影/派生状态,或
9227
+ * (b)按需异步分页读取历史窗口(见 dsh 决策
9228
+ * 2026-09-09-deprecate-synchronous-session-event-reads)。本函数的调用方
9229
+ * (foldMessages / segmentsSince / wait 基线)仍依赖完整同步快照,故按该决定暂缓
9230
+ * 迁移;将来官方补齐分页读后,只需改造这一个入口。
9222
9231
  */
9223
9232
  function sessionEvents(session) {
9224
9233
  const s = session;
@@ -10041,7 +10050,7 @@ var SessionMonitor = class {
10041
10050
  }
10042
10051
  };
10043
10052
  //#endregion
10044
- //#region node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-invaria_eaf7046112a9b60866fe7f69bc8f6f64/node_modules/@deepseek-ai/dsh-scope/lib/index.js
10053
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-invaria_8802cbeca2a66ef97a5b4e663664f4cd/node_modules/@deepseek-ai/dsh-scope/lib/index.js
10045
10054
  /**
10046
10055
  * Shared insertion-ordered storage and effect ownership for scope-aware registries.
10047
10056
  *
@@ -10320,7 +10329,7 @@ function scopeTarget(base, key) {
10320
10329
  return carrier;
10321
10330
  }
10322
10331
  //#endregion
10323
- //#region node_modules/.pnpm/@deepseek-ai+dsh-sandbox@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-llm@0_1d3a97f96d2766469566ca2b01247bfa/node_modules/@deepseek-ai/dsh-sandbox/lib/index.js
10332
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-sandbox@0.1.6-alpha.2_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-llm@0_5328c6913d63e98a7878ca36cab93ca2/node_modules/@deepseek-ai/dsh-sandbox/lib/index.js
10324
10333
  /**
10325
10334
  * The escalation vocabulary and choreography shared by every sandbox-enforcing
10326
10335
  * tool family (`@deepseek-ai/dsh-tool-bash`, `@deepseek-ai/dsh-tool-fs`): the
@@ -10371,21 +10380,18 @@ function validateEscalationArgs(sandboxPermissions, justification) {
10371
10380
  if (justification !== void 0 && justification.trim().length === 0) throw new Error("invalid justification: expected a non-empty sentence");
10372
10381
  }
10373
10382
  /**
10374
- * Resolve a sandbox-escalation request BEFORE anything executes: check strict
10375
- * widening against the call's effective mode, then resolve the approval
10376
- * channel, then map every outcome the ordered fail-closed sequence both
10377
- * enforcing families share. Returns the granted mode to stamp onto exactly
10378
- * this call; throws the distinct verbatim text for every other path (a
10379
- * non-widening request, a missing approval service, an agent-less execution,
10380
- * a rejection, a cancellation, an unanswerable ask) — the tool registry turns
10381
- * the throw into the call's isError result, and nothing has run. A
10382
- * non-widening request never prompts a human.
10383
+ * Resolve a sandbox permission request before execution. Repeating the call's
10384
+ * effective mode returns it without approval. A strictly wider mode requires
10385
+ * approval and applies only to this call. Narrower or unsupported targets,
10386
+ * missing approval services or agents for widening, and non-grant outcomes
10387
+ * throw before execution.
10383
10388
  * @param request - the escalation to judge (see {@link EscalationRequest}).
10384
10389
  * @param approval - the approval ingredients the tool holds (see {@link EscalationApproval}).
10385
10390
  * @returns the granted mode, consumed by the one call that asked.
10386
10391
  */
10387
10392
  async function approveEscalation(request, approval) {
10388
10393
  const { requestedMode: mode, effectiveMode, justification, subject } = request;
10394
+ if (mode === effectiveMode) return effectiveMode;
10389
10395
  if (!(WIDER_MODES[effectiveMode] ?? []).includes(mode)) throw new Error(`sandbox escalation to "${mode}" is not strictly wider than this call's current "${effectiveMode}" mode`);
10390
10396
  if (approval.approver === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but no approval service is composed`);
10391
10397
  if (approval.agent === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but the call has no agent to route it through`);
@@ -10405,7 +10411,7 @@ async function approveEscalation(request, approval) {
10405
10411
  }
10406
10412
  }
10407
10413
  //#endregion
10408
- //#region node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.6-alpha.1_e89197212305e1b19bd6df05221bc44b/node_modules/@deepseek-ai/dsh-tools/lib/index.js
10414
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.6-alpha.2_e8d664b8446198a3dac4043bd11091d7/node_modules/@deepseek-ai/dsh-tools/lib/index.js
10409
10415
  /**
10410
10416
  * Enforced JSON Schema subset shared by tool outputs, generated PTC mode
10411
10417
  * types, subagents, and workflows. The subset accepts any JSON root, an
@@ -14018,7 +14024,7 @@ function toolAbortedBeforeDispatchResult(prior) {
14018
14024
  };
14019
14025
  }
14020
14026
  //#endregion
14021
- //#region node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.6-alpha.1_ce40d13c69e7e1ce48818baba37665e1/node_modules/@deepseek-ai/dsh-agent/lib/index.js
14027
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.6-alpha.2_44110910133b3cc261ea9dfdcaed39ee/node_modules/@deepseek-ai/dsh-agent/lib/index.js
14022
14028
  /**
14023
14029
  * Agent-scoped model selection shared by runtime entry points.
14024
14030
  * @module @deepseek-ai/dsh-agent/model-selection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-session-bridge",
3
- "version": "0.3.2-alpha.1",
3
+ "version": "0.3.2-alpha.2",
4
4
  "description": "会话桥(dsh-session-bridge):通过提示词创建新的主会话(顶层 UI 会话)、向任意会话发送消息、等待会话的下一条回复、读取会话消息,并按会话名或 id 跨工作区查找会话;此外支持监控/调度主任务与归档会话。",
5
5
  "private": false,
6
6
  "type": "module",
@@ -118,6 +118,44 @@ function dshVersionOf(scopeDir) {
118
118
  return undefined
119
119
  }
120
120
 
121
+ /**
122
+ * Inspect the built tsdown bundle's source map for the DSH version it INLINED.
123
+ *
124
+ * `check:compat` type-checks src/ against the installed harness, but src/ is not
125
+ * what loads: lib/index.js is a self-contained bundle that inlines every
126
+ * @deepseek-ai/* import. A stale checkout therefore type-checks green while the
127
+ * artifact ships old DSH code (observed: checkout 0.1.5-alpha.2 / host
128
+ * 0.1.6-alpha.2). This reads the map's sources — a checkout path names the root
129
+ * whose package.json carries the version; a .pnpm path encodes it.
130
+ *
131
+ * @returns { versions: Set<string>, roots: Set<string> } or undefined when no map exists.
132
+ */
133
+ function artifactProvenance() {
134
+ const mapPath = join(ROOT, 'lib', 'index.js.map')
135
+ if (!existsSync(mapPath)) return undefined
136
+ let map
137
+ try { map = JSON.parse(readFileSync(mapPath, 'utf8')) } catch { return undefined }
138
+ const versions = new Set()
139
+ const roots = new Set()
140
+ for (const source of Array.isArray(map.sources) ? map.sources : []) {
141
+ if (typeof source !== 'string') continue
142
+ // Source checkout: <root>/packages/... or <root>/vendor/... (relative to the map in lib/).
143
+ const checkout = source.match(/^(.*?)[/\\](?:packages|vendor)[/\\]/)
144
+ if (checkout !== null) { roots.add(resolve(ROOT, 'lib', checkout[1])); continue }
145
+ // Registry install: .../.pnpm/@deepseek-ai+<name>@<version>[_hash]/node_modules/...
146
+ const registry = source.match(/[\\/]\.pnpm[\\/]@deepseek-ai\+[a-z0-9-]+@([^\\/]+)[\\/]node_modules/)
147
+ if (registry !== null) {
148
+ const version = registry[1].replace(/_.*$/, '')
149
+ if (/^\d/.test(version)) versions.add(version)
150
+ }
151
+ }
152
+ for (const root of roots) {
153
+ const manifest = readJson(join(root, 'package.json'))
154
+ if (typeof manifest?.version === 'string') versions.add(manifest.version)
155
+ }
156
+ return { versions, roots }
157
+ }
158
+
121
159
  const dshVersion = dshVersionOf(scope) ?? '(unknown)'
122
160
 
123
161
  // Every DSH package src/ imports, plus the plain `cordis` specifier that
@@ -170,4 +208,18 @@ if (failure !== undefined) {
170
208
  const status = typeof failure.status === 'number' ? ' (tsc exit ' + failure.status + ')' : ''
171
209
  fail('src/ does NOT type-check against installed dsh ' + dshVersion + status + ' — this is a real incompatibility with the running harness.')
172
210
  }
173
- console.log('check-dsh-compat: OK — src/ type-checks against installed dsh ' + dshVersion)
211
+ console.log('check-dsh-compat: OK — src/ type-checks against installed dsh ' + dshVersion)
212
+
213
+ const provenance = artifactProvenance()
214
+ if (provenance === undefined) {
215
+ console.log('check-dsh-compat: no lib/index.js.map — skipping bundle provenance check (run pnpm build:client to enable it)')
216
+ } else if (provenance.versions.size === 0) {
217
+ console.log('check-dsh-compat: bundle provenance not resolvable from the source map — skipped')
218
+ } else {
219
+ const inlined = [...provenance.versions].sort().join(', ')
220
+ console.log('check-dsh-compat: lib/index.js inlined DSH ' + inlined + ' (from ' + provenance.roots.size + ' checkout(s) / registry entries)')
221
+ if (dshVersion !== '(unknown)' && !(provenance.versions.size === 1 && provenance.versions.has(dshVersion))) {
222
+ fail('the built lib/index.js inlines DSH ' + inlined + ' but the installed harness is ' + dshVersion
223
+ + ' — rebuild the bundle against the running harness (a stale checkout type-checks green while shipping old DSH code).')
224
+ }
225
+ }
package/src/core.ts CHANGED
@@ -64,11 +64,19 @@ export interface BridgeFindItem {
64
64
 
65
65
  /**
66
66
  * 兼容读取不同 dsh-session 版本上的会话事件:
67
- * - 旧版 `Session` 暴露 `get events(): readonly SessionEvent[]`;
68
- * - 新版(如宿主实际运行的 0.1.2-rc.x)将 `get events` 改为
69
- * `snapshotEvents(fromSeq?, toSeqExclusive?)` 方法——`.events` 直接读取会
70
- * 得到 `undefined`,对 for...of 迭代即抛 `events is not iterable`。
67
+ * - 旧版 \`Session\` 暴露 \`get events(): readonly SessionEvent[]\`;
68
+ * - 新版将 \`get events\` 改为 \`snapshotEvents(fromSeq?, toSeqExclusive?)\` 方法——
69
+ * \`.events\` 直接读取会得到 \`undefined\`,对 for...of 迭代即抛
70
+ * \`events is not iterable\`。
71
71
  * 两者都读不到(或 session 不存在)时回退为空数组,绝不抛迭代错误。
72
+ *
73
+ * 注意:dsh 0.1.6-alpha.1 起 \`snapshotEvents()\`(连同 \`eventAt()\` /
74
+ * \`ownEvents()\`)已标记 @deprecated —— 官方策略是"现有逻辑可暂不迁移,但禁止
75
+ * 新增调用";其替代不是同步读,而是(a)恢复后读取 Session 投影/派生状态,或
76
+ * (b)按需异步分页读取历史窗口(见 dsh 决策
77
+ * 2026-09-09-deprecate-synchronous-session-event-reads)。本函数的调用方
78
+ * (foldMessages / segmentsSince / wait 基线)仍依赖完整同步快照,故按该决定暂缓
79
+ * 迁移;将来官方补齐分页读后,只需改造这一个入口。
72
80
  */
73
81
  export function sessionEvents(session: unknown): readonly SessionEvent[] {
74
82
  const s = session as {