dsh-session-guard 0.3.0 → 0.4.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/CHANGELOG.ja.md +39 -0
- package/CHANGELOG.ko.md +39 -0
- package/CHANGELOG.md +41 -0
- package/INSTALL.ja.md +5 -2
- package/INSTALL.ko.md +5 -2
- package/INSTALL.md +5 -2
- package/INSTALL.zh.md +5 -2
- package/README.en.md +26 -7
- package/README.ja.md +3 -1
- package/README.ko.md +3 -1
- package/README.md +21 -7
- package/dsh.plugin.json +4 -1
- package/package.json +8 -8
- package/src/index.js +10 -2
- package/src/pause-gate.js +58 -6
package/CHANGELOG.ja.md
CHANGED
|
@@ -6,6 +6,45 @@
|
|
|
6
6
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
7
7
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
8
8
|
|
|
9
|
+
## 3.0.0 — 2026-09-14
|
|
10
|
+
|
|
11
|
+
### 変更
|
|
12
|
+
|
|
13
|
+
- **DSH v0.1.5-rc.2 専用ライン(`compat/0.1.5`)。** `engines.dsh` と `dsh-client-*` の peer
|
|
14
|
+
範囲を `>=0.1.5-rc.2 <0.2.0-0` に狭めました(semver のプレリリース規則上、旧
|
|
15
|
+
`>=0.1.0-rc.7` は `0.1.5-rc.2` に一致しません)。`dsh.plugin.json` に `engines.dsh` を追加。
|
|
16
|
+
旧ホスト向けには `main` 上の 2.x / 0.2.x ラインが継続します。
|
|
17
|
+
- **`session.events` → `snapshotEvents()`。** DSH 0.1.5 で `session.events` 配列アクセサが
|
|
18
|
+
削除されたため(compatibility-guide §20.3)、`pause-gate.js` はデュアルパスのヘルパーで
|
|
19
|
+
セッションイベントを読みます:まず `snapshotEvents()`、防御的に旧 `events` 配列へフォール
|
|
20
|
+
バック、どちらも無ければ `null`(fail-open)。対象は `findToolOutcome` と `lastUserPrompt`
|
|
21
|
+
のみで、イベント型のマッチングは不変です。
|
|
22
|
+
|
|
23
|
+
### 変更なし
|
|
24
|
+
|
|
25
|
+
- その他の接続面は一切変更なし:自前の webServer prefix ルート(`/session-guard/rpc`)、
|
|
26
|
+
`settings.register`、`settings.plugin.item` スロット、クライアント注入、
|
|
27
|
+
`llm.listConfigurableProviders()` は公開済み 0.1.5-rc.2 バンドルに対して検証済み
|
|
28
|
+
(`tools/check-api-drift.ps1`、必須アサーション 12/12)。
|
|
29
|
+
|
|
30
|
+
### 未実施
|
|
31
|
+
|
|
32
|
+
- 実機 DSH 0.1.5-rc.2 ホストでのライブスモーク(perm-gate の 0.1.5 ラインと同じ状態)。
|
|
33
|
+
|
|
34
|
+
## 0.2.0-beta.2 — 2026-09-13
|
|
35
|
+
|
|
36
|
+
### 修正(DSH 0.1.5 互換 — `compat/0.1.5` ブランチ)
|
|
37
|
+
|
|
38
|
+
- **レジューム入隊のデュアルパス。** DSH 0.1.5 では Inbox が agent-loop の読み取り専用
|
|
39
|
+
投影に変わるため、`agent.followup` が存在しない可能性があります。レジューム時は
|
|
40
|
+
`agent.followup` → `agent.send` → warn 降級(例外は投げない)の順で試行します。
|
|
41
|
+
- **レジュームメッセージの `source` に `form: 'instructions'` を追加**(0.1.5 の
|
|
42
|
+
`ContextFormed` 契約。旧バージョンは未知フィールドを無視します)。
|
|
43
|
+
- **`webServer.register` を try/catch で保護**:ルート登録の失敗はログのみで、
|
|
44
|
+
`apply` から例外を投げてホストのプラグイン読み込みを壊しません。
|
|
45
|
+
- 0.1.5-rc.2 ソースに対し `WebRoute`(exact/prefix + SSE)契約が不変であることを確認。
|
|
46
|
+
クライアントの `fetch('/session-guard/...')` に `/api` プレフィックスは不要です。
|
|
47
|
+
|
|
9
48
|
## 0.2.0-beta.1 — 2026-09-10
|
|
10
49
|
|
|
11
50
|
### 追加
|
package/CHANGELOG.ko.md
CHANGED
|
@@ -6,6 +6,45 @@
|
|
|
6
6
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
7
7
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
8
8
|
|
|
9
|
+
## 3.0.0 — 2026-09-14
|
|
10
|
+
|
|
11
|
+
### 변경
|
|
12
|
+
|
|
13
|
+
- **DSH v0.1.5-rc.2 전용 라인(`compat/0.1.5`).** `engines.dsh`와 `dsh-client-*` peer 범위를
|
|
14
|
+
`>=0.1.5-rc.2 <0.2.0-0`으로 좁혔습니다(semver 프리릴리스 규칙상 기존 `>=0.1.0-rc.7`은
|
|
15
|
+
`0.1.5-rc.2`와 일치하지 않음). `dsh.plugin.json`에 `engines.dsh`를 추가했습니다. 구버전
|
|
16
|
+
호스트용으로는 `main`의 2.x / 0.2.x 라인이 계속 유지됩니다.
|
|
17
|
+
- **`session.events` → `snapshotEvents()`.** DSH 0.1.5에서 `session.events` 배열 접근자가
|
|
18
|
+
제거됨에 따라(compatibility-guide §20.3) `pause-gate.js`는 듀얼 패스 헬퍼로 세션 이벤트를
|
|
19
|
+
읽습니다: 우선 `snapshotEvents()`, 방어적으로 구 `events` 배열로 폴백, 둘 다 없으면 `null`
|
|
20
|
+
(fail-open). 대상은 `findToolOutcome`과 `lastUserPrompt` 두 곳뿐이며 이벤트 타입 매칭은
|
|
21
|
+
불변입니다.
|
|
22
|
+
|
|
23
|
+
### 변경 없음
|
|
24
|
+
|
|
25
|
+
- 나머지 연동면은 전부 무변경: 자체 webServer prefix 라우트(`/session-guard/rpc`),
|
|
26
|
+
`settings.register`, `settings.plugin.item` 슬롯, 클라이언트 주입,
|
|
27
|
+
`llm.listConfigurableProviders()`는 공개된 0.1.5-rc.2 번들 기준으로 검증 완료
|
|
28
|
+
(`tools/check-api-drift.ps1`, 필수 어설션 12/12).
|
|
29
|
+
|
|
30
|
+
### 보류
|
|
31
|
+
|
|
32
|
+
- 실제 DSH 0.1.5-rc.2 호스트에서의 라이브 스모크(perm-gate 0.1.5 라인과 동일 상태).
|
|
33
|
+
|
|
34
|
+
## 0.2.0-beta.2 — 2026-09-13
|
|
35
|
+
|
|
36
|
+
### 수정 (DSH 0.1.5 호환 — `compat/0.1.5` 브랜치)
|
|
37
|
+
|
|
38
|
+
- **재개 큐잉 듀얼 경로.** DSH 0.1.5에서는 Inbox가 agent-loop의 읽기 전용 프로젝션으로
|
|
39
|
+
바뀌어 `agent.followup`이 존재하지 않을 수 있습니다. 재개 시 `agent.followup` →
|
|
40
|
+
`agent.send` → warn 강등(예외 없음) 순으로 시도합니다.
|
|
41
|
+
- **재개 메시지 `source`에 `form: 'instructions'` 추가** (0.1.5 `ContextFormed` 계약;
|
|
42
|
+
구버전은 알 수 없는 필드를 무시합니다).
|
|
43
|
+
- **`webServer.register` try/catch 보호**: 라우트 등록 실패는 로그만 남기고 `apply`에서
|
|
44
|
+
예외를 던져 호스트 플러그인 로딩을 깨뜨리지 않습니다.
|
|
45
|
+
- 0.1.5-rc.2 소스 기준 `WebRoute`(exact/prefix + SSE) 계약이 불변임을 확인했습니다.
|
|
46
|
+
클라이언트 `fetch('/session-guard/...')`에 `/api` 접두사는 불필요합니다.
|
|
47
|
+
|
|
9
48
|
## 0.2.0-beta.1 — 2026-09-10
|
|
10
49
|
|
|
11
50
|
### 추가
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,47 @@ All notable changes to `dsh-session-guard` are recorded here. Versions follow se
|
|
|
6
6
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
7
7
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
8
8
|
|
|
9
|
+
## 3.0.0 — 2026-09-14
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **DSH v0.1.5-rc.2 dedicated line (`compat/0.1.5`).** `engines.dsh` and the `dsh-client-*`
|
|
14
|
+
peer ranges narrow to `>=0.1.5-rc.2 <0.2.0-0` (strict-semver prerelease matching means the
|
|
15
|
+
old `>=0.1.0-rc.7` range never matches `0.1.5-rc.2`); `dsh.plugin.json` gains `engines.dsh`.
|
|
16
|
+
The 2.x / 0.2.x line on `main` keeps serving DSH 0.1.0-rc.7 … 0.1.2-rc.1.
|
|
17
|
+
- **`session.events` → `snapshotEvents()`.** DSH 0.1.5 removed the `session.events` array
|
|
18
|
+
accessor (compatibility-guide §20.3). `pause-gate.js` now reads session events through a
|
|
19
|
+
dual-path helper: `snapshotEvents()` first, the legacy `events` array as a defensive
|
|
20
|
+
fallback, `null` (fail-open) when neither exists. Affects `findToolOutcome` and
|
|
21
|
+
`lastUserPrompt` only; event-type matching is unchanged.
|
|
22
|
+
|
|
23
|
+
### Unchanged
|
|
24
|
+
|
|
25
|
+
- Zero changes on every other integration seam: the self-held webServer prefix route
|
|
26
|
+
(`/session-guard/rpc`), `settings.register`, the `settings.plugin.item` card slot,
|
|
27
|
+
client injections, and `llm.listConfigurableProviders()` are all verified intact against
|
|
28
|
+
the published 0.1.5-rc.2 bundle (`tools/check-api-drift.ps1`, 12/12 required assertions).
|
|
29
|
+
|
|
30
|
+
### Pending
|
|
31
|
+
|
|
32
|
+
- Live smoke on a real DSH 0.1.5-rc.2 host (same status as the perm-gate 0.1.5 line).
|
|
33
|
+
|
|
34
|
+
## 0.2.0-beta.2 — 2026-09-13
|
|
35
|
+
|
|
36
|
+
### Fixed (DSH 0.1.5 compat — `compat/0.1.5` branch)
|
|
37
|
+
|
|
38
|
+
- **Dual-path resume enqueue.** DSH 0.1.5 turns the Inbox into an agent-loop read-only
|
|
39
|
+
projection, so `agent.followup` may no longer exist. The resume flow now tries
|
|
40
|
+
`agent.followup` first, falls back to `agent.send`, and degrades to a warn (never throws)
|
|
41
|
+
when neither is available — a failed enqueue can no longer break resume.
|
|
42
|
+
- **Resume messages carry `source.form: 'instructions'`** per the 0.1.5 `ContextFormed`
|
|
43
|
+
message-source contract (`kind: 'plugin'` is a built-in kind; older DSH versions ignore
|
|
44
|
+
the extra field).
|
|
45
|
+
- **`webServer.register` is wrapped in try/catch**: a failed route registration now logs an
|
|
46
|
+
error instead of throwing out of `apply` and breaking host plugin loading.
|
|
47
|
+
- Verified against the 0.1.5-rc.2 source: the `WebRoute` contract (exact/prefix + SSE) is
|
|
48
|
+
unchanged, so client `fetch('/session-guard/...')` paths need no `/api` prefix.
|
|
49
|
+
|
|
9
50
|
## 0.2.0-beta.1 — 2026-09-10
|
|
10
51
|
|
|
11
52
|
### Added
|
package/INSTALL.ja.md
CHANGED
|
@@ -22,9 +22,12 @@ dsh --version
|
|
|
22
22
|
## 1. インストール
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
25
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5#compat/0.1.5
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`compat/0.1.5` は DSH `0.1.5-rc.x` 専用ライン(3.x、`engines.dsh: >=0.1.5-rc.2 <0.2.0-0`)。`main` は
|
|
29
|
+
引き続き DSH `0.1.0-rc.7` – `0.1.2-rc.1`(2.x / 0.2.x)を担当します。
|
|
30
|
+
|
|
28
31
|
dsh web を再起動し、ページをリフレッシュ。
|
|
29
32
|
|
|
30
33
|
## 2. 検証
|
|
@@ -52,7 +55,7 @@ npm test
|
|
|
52
55
|
|
|
53
56
|
```bash
|
|
54
57
|
dsh plugin --profile web remove dsh-session-guard
|
|
55
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
58
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
dsh web を再起動しページをリフレッシュ。設定は `$DSH_HOME/settings.yaml` の `session-guard`
|
package/INSTALL.ko.md
CHANGED
|
@@ -22,9 +22,12 @@ dsh --version
|
|
|
22
22
|
## 1. 설치
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
25
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5#compat/0.1.5
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`compat/0.1.5`는 DSH `0.1.5-rc.x` 전용 라인(3.x, `engines.dsh: >=0.1.5-rc.2 <0.2.0-0`)입니다. `main`은
|
|
29
|
+
계속 DSH `0.1.0-rc.7` – `0.1.2-rc.1`(2.x / 0.2.x)을 담당합니다.
|
|
30
|
+
|
|
28
31
|
dsh web을 재시작하고 페이지를 새로고침.
|
|
29
32
|
|
|
30
33
|
## 2. 검증
|
|
@@ -52,7 +55,7 @@ npm test
|
|
|
52
55
|
|
|
53
56
|
```bash
|
|
54
57
|
dsh plugin --profile web remove dsh-session-guard
|
|
55
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
58
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
dsh web을 재시작하고 페이지를 새로고침. 설정은 `$DSH_HOME/settings.yaml`의 `session-guard`
|
package/INSTALL.md
CHANGED
|
@@ -24,9 +24,12 @@ dsh --version
|
|
|
24
24
|
## 1. Install
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
27
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
`compat/0.1.5` is the DSH `0.1.5-rc.x` line (3.x, `engines.dsh: >=0.1.5-rc.2 <0.2.0-0`); `main` keeps
|
|
31
|
+
serving DSH `0.1.0-rc.7` – `0.1.2-rc.1` (2.x / 0.2.x).
|
|
32
|
+
|
|
30
33
|
Restart dsh web and refresh the page.
|
|
31
34
|
|
|
32
35
|
## 2. Verify
|
|
@@ -55,7 +58,7 @@ npm test
|
|
|
55
58
|
|
|
56
59
|
```bash
|
|
57
60
|
dsh plugin --profile web remove dsh-session-guard
|
|
58
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
61
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
59
62
|
```
|
|
60
63
|
|
|
61
64
|
Restart dsh web and refresh the page. Settings live in `$DSH_HOME/settings.yaml` under the
|
package/INSTALL.zh.md
CHANGED
|
@@ -22,9 +22,12 @@ dsh --version
|
|
|
22
22
|
## 1. 安装
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
25
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5#compat/0.1.5
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`compat/0.1.5` 是 DSH `0.1.5-rc.x` 专线(3.x,`engines.dsh: >=0.1.5-rc.2 <0.2.0-0`);`main` 继续服务
|
|
29
|
+
DSH `0.1.0-rc.7` – `0.1.2-rc.1`(2.x / 0.2.x)。
|
|
30
|
+
|
|
28
31
|
重启 dsh web 并刷新页面。
|
|
29
32
|
|
|
30
33
|
## 2. 验证
|
|
@@ -52,7 +55,7 @@ npm test
|
|
|
52
55
|
|
|
53
56
|
```bash
|
|
54
57
|
dsh plugin --profile web remove dsh-session-guard
|
|
55
|
-
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
|
|
58
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
重启 dsh web 并刷新页面。设置在 `$DSH_HOME/settings.yaml` 的 `session-guard` 命名空间下,升级不会丢;
|
package/README.en.md
CHANGED
|
@@ -30,22 +30,38 @@
|
|
|
30
30
|
>
|
|
31
31
|
> | DSH version | Load | Settings registration | Session events / gate | Client half |
|
|
32
32
|
> | --- | --- | --- | --- | --- |
|
|
33
|
-
> | 0.1.0-rc.7 ~ 0.1.1-rc.x | ✅ | `ctx.settings.register(ns, schema, { base })` | ✅ same shape | ✅ no platform value imports |
|
|
34
|
-
> | 0.1.2-alpha.2+ / 0.1.2-rc.1 | ✅ | `register` still present (`installSection` added) | ✅ same shape | ✅ no platform value imports |
|
|
35
|
-
> | 0.1.3
|
|
33
|
+
> | 0.1.0-rc.7 ~ 0.1.1-rc.x | ✅ (2.x / 0.2.x line) | `ctx.settings.register(ns, schema, { base })` | ✅ same shape | ✅ no platform value imports |
|
|
34
|
+
> | 0.1.2-alpha.2+ / 0.1.2-rc.1 | ✅ (2.x / 0.2.x line) | `register` still present (`installSection` added) | ✅ same shape | ✅ no platform value imports |
|
|
35
|
+
> | **0.1.5-rc.2** | ✅ (**3.x dedicated line `compat/0.1.5`**) | `register` unchanged (string namespaces) | ✅ events read via `snapshotEvents()` dual path | ✅ |
|
|
36
36
|
>
|
|
37
|
-
>
|
|
37
|
+
> **3.x is the 0.1.5 dedicated line**: engines/peers narrow to `>=0.1.5-rc.2 <0.2.0-0`;
|
|
38
|
+
> 0.1.0-rc.7~0.1.2 hosts should stay on the 2.x / 0.2.x line (`main`).
|
|
39
|
+
> **0.1.5 adaptation (compat/0.1.5 branch, v3.0.0)**:
|
|
40
|
+
> ① dual-path resume enqueue — 0.1.5 turns Inbox into an agent-loop read-only projection;
|
|
41
|
+
> if `agent.followup` is gone the plugin falls back to `agent.send`, and degrades to a warn
|
|
42
|
+
> (never throws) when neither exists; ② resume messages now carry
|
|
43
|
+
> `source.form: 'instructions'` (0.1.5 ContextFormed contract; older versions ignore it);
|
|
44
|
+
> ③ `webServer.register` is wrapped in try/catch so a failed registration only logs instead
|
|
45
|
+
> of breaking host loading; ④ 0.1.5 removes the `session.events` array accessor — events are
|
|
46
|
+
> now read via `snapshotEvents()` (legacy array kept as fallback), affecting only the
|
|
47
|
+
> `findToolOutcome` / `lastUserPrompt` helper paths.
|
|
48
|
+
> Verified that 0.1.5 `WebRoute` (exact/prefix + SSE) contract is
|
|
49
|
+
> unchanged — client `fetch('/session-guard/...')` needs no `/api` prefix.
|
|
50
|
+
> The 2.x-line table (one artifact, both versions) is kept below. `session/event`, `agent.cancel`, `goals.pause`,
|
|
38
51
|
> `agent.followup`, `commands.register`, `timer.interval`, `webServer.register`,
|
|
39
52
|
> `agent/request`, `llm.listConfigurableProviders` and `settings.register/get`
|
|
40
53
|
> are signature-identical between `dsh-v0.1.1-rc.2` and `dsh-v0.1.2-rc.1`
|
|
41
|
-
> (verified
|
|
54
|
+
> (3.x verified against `dsh-v0.1.5-rc.2`). The one
|
|
42
55
|
> seam that needs a dual read is the `tool/result` call id (`content[].toolCallId`
|
|
43
56
|
> first, `source.callId` as fallback) — both forms appear in replay logs of both
|
|
44
57
|
> versions. It now lives in `src/tool-call-id.js` with unit tests.
|
|
58
|
+
> Since 0.1.5 the `session.events` array accessor is removed; 3.x reads events
|
|
59
|
+
> through `snapshotEvents()` (with the legacy array as fallback), affecting only
|
|
60
|
+
> the `findToolOutcome` / `lastUserPrompt` helper paths.
|
|
45
61
|
> The `model/selection` event exists **only on 0.1.2+** and is feature-probed; the
|
|
46
62
|
> settings surface uses only the `register` + `get` intersection (never
|
|
47
63
|
> `installSection`, never the removed `installSettingsSection`). Drift guard:
|
|
48
|
-
> `tools/check-api-drift.ps1
|
|
64
|
+
> `tools/check-api-drift.ps1` (3.x defaults to asserting against `dsh-v0.1.5-rc.2`).
|
|
49
65
|
|
|
50
66
|
> Automatically pause running sessions during peak pricing hours and resume during off-peak/weekend; pair with input-traffic's freeze button for **per-session** locking; backend **auto-retry** yields during freeze/gate. Core based on a custom session gate (`agent.cancel keepInbox + goals.pause + session/event safe boundary + followup resume`), no longer depending on dsh-task-control.
|
|
51
67
|
|
|
@@ -66,9 +82,12 @@ A cordis plugin assembled via the `dsh plugin` command and a bundle patch — no
|
|
|
66
82
|
## Installation
|
|
67
83
|
|
|
68
84
|
```bash
|
|
69
|
-
dsh plugin --profile web add github
|
|
85
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
70
86
|
```
|
|
71
87
|
|
|
88
|
+
`compat/0.1.5` is the DSH `0.1.5-rc.x` line (3.x); `main` keeps serving DSH `0.1.0-rc.7` – `0.1.2-rc.1`
|
|
89
|
+
(2.x / 0.2.x).
|
|
90
|
+
|
|
72
91
|
Restart dsh web and refresh the page after installation.
|
|
73
92
|
|
|
74
93
|
## Settings (Settings → Plugins → session-guard, simple toggles)
|
package/README.ja.md
CHANGED
|
@@ -45,9 +45,11 @@
|
|
|
45
45
|
## インストール
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
dsh plugin --profile web add github
|
|
48
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
`compat/0.1.5` は DSH `0.1.5-rc.x` 専用ライン(3.x)。`main` は引き続き DSH `0.1.0-rc.7` – `0.1.2-rc.1`(2.x / 0.2.x)を担当します。
|
|
52
|
+
|
|
51
53
|
インストール後 dsh web を再起動し、ページをリフレッシュ。
|
|
52
54
|
|
|
53
55
|
## 設定(設定 → プラグイン → session-guard)
|
package/README.ko.md
CHANGED
|
@@ -45,9 +45,11 @@
|
|
|
45
45
|
## 설치
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
dsh plugin --profile web add github
|
|
48
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
`compat/0.1.5`는 DSH `0.1.5-rc.x` 전용 라인(3.x)입니다. `main`은 계속 DSH `0.1.0-rc.7` – `0.1.2-rc.1`(2.x / 0.2.x)을 담당합니다.
|
|
52
|
+
|
|
51
53
|
설치 후 dsh web을 재시작하고 페이지를 새로고침.
|
|
52
54
|
|
|
53
55
|
## 설정 (설정 → 플러그인 → session-guard)
|
package/README.md
CHANGED
|
@@ -32,19 +32,31 @@
|
|
|
32
32
|
>
|
|
33
33
|
> | DSH 版本 | 加载 | 设置注册 | 会话事件 / 会话门 | 客户端半 |
|
|
34
34
|
> | --- | --- | --- | --- | --- |
|
|
35
|
-
> | 0.1.0-rc.7 ~ 0.1.1-rc.x |
|
|
36
|
-
> | 0.1.2-alpha.2+ / 0.1.2-rc.1 |
|
|
37
|
-
> | 0.1.3
|
|
35
|
+
> | 0.1.0-rc.7 ~ 0.1.1-rc.x | ✅(2.x / 0.2.x 线) | `ctx.settings.register(ns, schema, { base })` | ✅ 形状一致 | ✅ 无平台值导入 |
|
|
36
|
+
> | 0.1.2-alpha.2+ / 0.1.2-rc.1 | ✅(2.x / 0.2.x 线) | `register` 仍保留(另加 `installSection`) | ✅ 形状一致 | ✅ 无平台值导入 |
|
|
37
|
+
> | **0.1.5-rc.2** | ✅(**3.x 专线 `compat/0.1.5`**) | `register` 仍在(字符串命名空间) | ✅ 事件经 `snapshotEvents()` 双路径读取 | ✅ |
|
|
38
38
|
>
|
|
39
|
-
>
|
|
39
|
+
> **3.x 为 0.1.5 专线**:engines/peer 收窄为 `>=0.1.5-rc.2 <0.2.0-0`,0.1.0-rc.7~0.1.2 宿主请继续使用 2.x / 0.2.x 线(`main`)。
|
|
40
|
+
> **0.1.5 适配(compat/0.1.5 分支,v3.0.0)**:
|
|
41
|
+
> ① `agent.followup` 双路径——0.1.5 将 Inbox 改为 agent-loop 只读投影,若 `followup`
|
|
42
|
+
> 不再存在则回退 `agent.send`,两者皆无时 warn 降级不抛错(恢复续跑的兜底);
|
|
43
|
+
> ② 恢复消息 `source` 补 `form: 'instructions'`(0.1.5 ContextFormed 契约,旧版本忽略);
|
|
44
|
+
> ③ `webServer.register` 包 try/catch,注册失败仅记日志不炸宿主加载;
|
|
45
|
+
> ④ 0.1.5 移除 `session.events` 数组访问器,事件读取改为 `snapshotEvents()` 主路径 +
|
|
46
|
+
> 旧数组回退(仅影响 `findToolOutcome` / `lastUserPrompt` 两条辅助路径,事件类型匹配不变)。
|
|
47
|
+
> 已核实 0.1.5 的 `WebRoute`(exact/prefix + SSE)契约不变,客户端
|
|
48
|
+
> `fetch('/session-guard/...')` 无需改 `/api` 前缀。
|
|
49
|
+
> 2.x 线的旧表(一份产物双版本)保留如下。`session/event`、`agent.cancel`、`goals.pause`、
|
|
40
50
|
> `agent.followup`、`commands.register`、`timer.interval`、`webServer.register`、
|
|
41
51
|
> `agent/request`、`llm.listConfigurableProviders`、`settings.register/get` 在
|
|
42
|
-
> `dsh-v0.1.1-rc.2` 与 `dsh-v0.1.2-rc.1`
|
|
52
|
+
> `dsh-v0.1.1-rc.2` 与 `dsh-v0.1.2-rc.1` 之间签名一致(3.x 已核到 `dsh-v0.1.5-rc.2`);
|
|
43
53
|
> 唯一需要双读的是 `tool/result` 记录的调用 id 形态(`content[].toolCallId` 优先、
|
|
44
54
|
> `source.callId` 回退),已抽到 `src/tool-call-id.js` 并配单测——两版本的回放日志都可能出现这两种形态。
|
|
55
|
+
> 0.1.5 起 `session.events` 数组访问器被移除,3.x 经 `snapshotEvents()`(保留旧数组回退)读取,
|
|
56
|
+
> 只影响 `findToolOutcome` / `lastUserPrompt` 两条辅助路径。
|
|
45
57
|
> `model/selection` 事件**仅 0.1.2+**,只做切模型加速且必须特性探测;设置面只用
|
|
46
58
|
> `register` + `get` 交集(不碰 `installSection` / 已移除的 `installSettingsSection`)。
|
|
47
|
-
> 漂移守卫脚本:`tools/check-api-drift.ps1
|
|
59
|
+
> 漂移守卫脚本:`tools/check-api-drift.ps1`(3.x 默认对 `dsh-v0.1.5-rc.2` 断言必需接口存在)。
|
|
48
60
|
|
|
49
61
|
> 高峰时段自动暂停运行中的会话、低峰/周末自动续跑;配合 input-traffic 的冻结按钮做到**会话级**锁定;后端**自动重试**在冻结/门控期间让路。核心基于**自研会话门**(`agent.cancel keepInbox + goals.pause + session/event 安全边界 + followup 续跑`),不再依赖 dsh-task-control。
|
|
50
62
|
|
|
@@ -74,9 +86,11 @@
|
|
|
74
86
|
## 安装
|
|
75
87
|
|
|
76
88
|
```bash
|
|
77
|
-
dsh plugin --profile web add github
|
|
89
|
+
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
|
|
78
90
|
```
|
|
79
91
|
|
|
92
|
+
`compat/0.1.5` 是 DSH `0.1.5-rc.x` 专线(3.x);`main` 继续服务 DSH `0.1.0-rc.7` – `0.1.2-rc.1`(2.x / 0.2.x)。
|
|
93
|
+
|
|
80
94
|
装后重启 dsh web 并刷新页面。
|
|
81
95
|
|
|
82
96
|
## 设置(设置 → 插件 → session-guard,简单开关)
|
package/dsh.plugin.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-session-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "高峰自动会话门:step 级门控 + 周末模式 + 高峰自动暂停 + 官方源二维判定 + 会话级冻结 + 后端自动重试。",
|
|
6
|
+
"engines": {
|
|
7
|
+
"dsh": ">=0.1.5-rc.2 <0.2.0-0"
|
|
8
|
+
},
|
|
6
9
|
"contributes": {
|
|
7
10
|
"tools": [],
|
|
8
11
|
"skills": []
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org",
|
|
6
6
|
"access": "public",
|
|
7
|
-
"tag": "dsh-0.1.
|
|
7
|
+
"tag": "dsh-0.1.5"
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
10
|
"description": "高峰自动会话门:周末模式 + 高峰自动暂停 + 官方源二维判定 + 会话级冻结 + 后端自动重试。",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/drscrewdriver/session-guard.git"
|
|
26
|
+
"url": "git+https://github.com/drscrewdriver/dsh-session-guard.git"
|
|
27
27
|
},
|
|
28
|
-
"homepage": "https://github.com/drscrewdriver/session-guard",
|
|
28
|
+
"homepage": "https://github.com/drscrewdriver/dsh-session-guard",
|
|
29
29
|
"main": "src/index.js",
|
|
30
30
|
"exports": {
|
|
31
31
|
".": "./src/index.js",
|
|
@@ -70,16 +70,16 @@
|
|
|
70
70
|
},
|
|
71
71
|
"engines": {
|
|
72
72
|
"node": ">=20",
|
|
73
|
-
"dsh": ">=0.1.
|
|
73
|
+
"dsh": ">=0.1.5-rc.2 <0.2.0-0"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
79
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
80
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.
|
|
81
|
-
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.
|
|
82
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.
|
|
80
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.2 <0.2.0-0",
|
|
81
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.5-rc.2 <0.2.0-0",
|
|
82
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.2 <0.2.0-0"
|
|
83
83
|
},
|
|
84
84
|
"peerDependenciesMeta": {
|
|
85
85
|
"@deepseek-ai/cordis": {
|
package/src/index.js
CHANGED
|
@@ -220,8 +220,12 @@ export function apply(ctx) {
|
|
|
220
220
|
tick()
|
|
221
221
|
|
|
222
222
|
// ── HTTP 路由 ──
|
|
223
|
+
// 0.1.5 compat:注册失败只记日志,不让 apply 抛错炸掉宿主插件加载(#5926 教训)。
|
|
224
|
+
// webServer.register 前缀路由 + SSE 在 0.1.5 契约不变(packages/host/webserver WebRoute)。
|
|
223
225
|
if (ctx.webServer && typeof ctx.webServer.register === 'function') {
|
|
224
|
-
ctx.effect(() =>
|
|
226
|
+
ctx.effect(() => {
|
|
227
|
+
try {
|
|
228
|
+
return ctx.webServer.register({
|
|
225
229
|
kind: 'prefix',
|
|
226
230
|
path: '/session-guard',
|
|
227
231
|
handler: async (req, res) => {
|
|
@@ -400,6 +404,10 @@ export function apply(ctx) {
|
|
|
400
404
|
res.end(JSON.stringify({ ok: false, error: String(e && e.message || e) }))
|
|
401
405
|
}
|
|
402
406
|
},
|
|
403
|
-
|
|
407
|
+
})
|
|
408
|
+
} catch (e) {
|
|
409
|
+
ctx.logger?.error?.(`[session-guard] webServer.register failed (routes disabled): ${String(e && e.message || e)}`)
|
|
410
|
+
}
|
|
411
|
+
}, 'session-guard: routes')
|
|
404
412
|
}
|
|
405
413
|
}
|
package/src/pause-gate.js
CHANGED
|
@@ -46,6 +46,36 @@ export function createPluginUserMessage({ content, source }) {
|
|
|
46
46
|
return { id, role: 'user', content, source }
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* 恢复消息入队(0.1.5 compat 双路径)。
|
|
51
|
+
*
|
|
52
|
+
* 0.1.5 把 Inbox 从独立服务改为 agent-loop 只读投影(消息入队走 session 事件),
|
|
53
|
+
* `agent.followup` 是否保留无法静态确认,因此运行时检测:
|
|
54
|
+
* 1. `agent.followup(msg)` —— ≤0.1.4 与(若保留的)0.1.5 首选路径;
|
|
55
|
+
* 2. `agent.send(msg)` —— followup 被移除时的回退;
|
|
56
|
+
* 3. 两者皆无 —— 记 warn 并返回 false,绝不让 resume 因入队失败而抛错。
|
|
57
|
+
* @param {object} agent 目标 agent(live agent)
|
|
58
|
+
* @param {{id: string, role: 'user', content: unknown, source: object}} message 本地构造的 user 消息
|
|
59
|
+
* @param {object} [ctx] host context(仅用于 logger)
|
|
60
|
+
* @returns {boolean} 是否成功入队
|
|
61
|
+
*/
|
|
62
|
+
export function enqueueFollowup(agent, message, ctx) {
|
|
63
|
+
if (typeof agent.followup === 'function') {
|
|
64
|
+
agent.followup(message)
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
if (typeof agent.send === 'function') {
|
|
68
|
+
agent.send(message)
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
ctx?.logger?.warn?.('[session-guard] agent has no followup/send; resume message dropped')
|
|
73
|
+
} catch {
|
|
74
|
+
/* logger 不可用时静默 */
|
|
75
|
+
}
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
49
79
|
/**
|
|
50
80
|
* @param {object} deps
|
|
51
81
|
* @param {object} deps.ctx host context(含 agents.get / get / logger,可选 goals)
|
|
@@ -132,11 +162,31 @@ export function createPauseGate({ ctx, pauseStore, pluginId = 'session-guard', m
|
|
|
132
162
|
* 两种形态在 DSH 0.1.1-rc.2 与 0.1.2-rc.1 的回放日志里都保留,勿改成单读。
|
|
133
163
|
*/
|
|
134
164
|
|
|
165
|
+
/**
|
|
166
|
+
* 读取会话事件数组。DSH 0.1.5 移除了 `session.events` 数组访问器,改为
|
|
167
|
+
* `snapshotEvents()`(compatibility-guide §20.3 实测表);本专线以
|
|
168
|
+
* snapshotEvents() 为主,events 数组仅作回退防御,两者皆缺时返回 null
|
|
169
|
+
* (fail-open,与既有防御语义一致)。
|
|
170
|
+
*/
|
|
171
|
+
function readSessionEvents(session) {
|
|
172
|
+
if (!session) return null
|
|
173
|
+
if (typeof session.snapshotEvents === 'function') {
|
|
174
|
+
try {
|
|
175
|
+
const events = session.snapshotEvents()
|
|
176
|
+
return Array.isArray(events) ? events : null
|
|
177
|
+
} catch {
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return Array.isArray(session.events) ? session.events : null
|
|
182
|
+
}
|
|
183
|
+
|
|
135
184
|
/** 在 session log 查一个中断工具的实际结果(kernel 会 drain 已启动工具到 tool/result)。 */
|
|
136
185
|
function findToolOutcome(agent, callId) {
|
|
137
|
-
|
|
186
|
+
const events = readSessionEvents(agent?.session)
|
|
187
|
+
if (!events) return null
|
|
138
188
|
let outcome = null
|
|
139
|
-
for (const event of
|
|
189
|
+
for (const event of events) {
|
|
140
190
|
if (event.type === 'tool/result') {
|
|
141
191
|
const message = event.data?.message ?? {}
|
|
142
192
|
const block = (Array.isArray(message.content) ? message.content : []).find((b) => b?.type === 'tool-result')
|
|
@@ -162,9 +212,10 @@ export function createPauseGate({ ctx, pauseStore, pluginId = 'session-guard', m
|
|
|
162
212
|
}
|
|
163
213
|
|
|
164
214
|
function lastUserPrompt(agent) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
215
|
+
const events = readSessionEvents(agent?.session)
|
|
216
|
+
if (!events) return null
|
|
217
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
218
|
+
const event = events[index]
|
|
168
219
|
if (event.type !== 'user/message') continue
|
|
169
220
|
if (event.data?.source?.kind !== 'user') continue
|
|
170
221
|
return event.data.content ?? null
|
|
@@ -286,7 +337,8 @@ export function createPauseGate({ ctx, pauseStore, pluginId = 'session-guard', m
|
|
|
286
337
|
state.pendingPause.delete(sessionId)
|
|
287
338
|
const current = currentPause(sessionId)
|
|
288
339
|
if (!current.paused) return { kind: 'success', text: 'no paused task to resume' }
|
|
289
|
-
|
|
340
|
+
// 0.1.5 compat:source 补 form: 'instructions'(0.1.5 ContextFormed 契约;旧版本忽略未知字段)
|
|
341
|
+
const followup = (blocks) => enqueueFollowup(agent, makeFollowupMessage({ content: blocks, source: { kind: 'plugin', plugin: pluginId, form: 'instructions' } }), ctx)
|
|
290
342
|
|
|
291
343
|
if (current.forced) {
|
|
292
344
|
const tool = current.interruptedTool
|