dsh-manage-session 0.4.8 → 0.5.3

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 (43) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.en.md +4 -0
  3. package/README.md +4 -0
  4. package/cordis.patch.yml +6 -1
  5. package/dsh.plugin.json +22 -22
  6. package/lib/client.js +3848 -202
  7. package/lib/index.d.ts +759 -29
  8. package/lib/index.js +2604 -93
  9. package/locale/de.json +6 -0
  10. package/locale/en.json +6 -0
  11. package/locale/es.json +6 -0
  12. package/locale/fr.json +6 -0
  13. package/locale/it.json +6 -0
  14. package/locale/ja.json +6 -0
  15. package/locale/ko.json +6 -0
  16. package/locale/ru.json +6 -0
  17. package/locale/zh.json +6 -0
  18. package/package.json +43 -32
  19. package/src/client/bridge-scope.ts +213 -0
  20. package/src/client/index.ts +154 -26
  21. package/src/client/locales.ts +857 -223
  22. package/src/client/panel.tsx +139 -118
  23. package/src/client/search/card.tsx +563 -0
  24. package/src/client/search/host-api.ts +208 -0
  25. package/src/client/search/locales.ts +780 -0
  26. package/src/client/search/manage.tsx +400 -0
  27. package/src/client/search/panel.tsx +815 -0
  28. package/src/client/search/platform.ts +136 -0
  29. package/src/config.ts +54 -5
  30. package/src/host/history/archive-source.ts +48 -0
  31. package/src/host/history/archive.ts +56 -1
  32. package/src/host/history/favorites.ts +71 -0
  33. package/src/host/index/archive-source.ts +90 -0
  34. package/src/host/index/engine.ts +571 -0
  35. package/src/host/index/extract.ts +272 -0
  36. package/src/host/index/peers.ts +62 -0
  37. package/src/host/index/rebuild.ts +368 -0
  38. package/src/host/index/schema.ts +136 -0
  39. package/src/host/index/snapshot.ts +135 -0
  40. package/src/host/index/sync.ts +286 -0
  41. package/src/host/registry/archive-registry.ts +317 -0
  42. package/src/host/settings-bridge.ts +237 -0
  43. package/src/index.ts +1421 -532
package/locale/de.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Sitzungs-Verwalter",
4
+ "description": "Sitzungsverlaufsdateien (Archivansicht und Bereinigung) und Sitzungs-Health-Check (Untersuchung → Rezept → Entlassung); keine Eingriffe in Sitzungsprotokolle, nur umkehrbare Vorgänge."
5
+ }
6
+ }
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Session Steward",
4
+ "description": "Session history files (archive browsing & cleanup) and session health checks (checkup → prescription → discharge) — reversible operations only, no touching of session logs."
5
+ }
6
+ }
package/locale/es.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Mayordomo de sesión",
4
+ "description": "Archivos de historial de sesión (visualización y limpieza del archivo) y comprobación de salud de las sesiones (revisión → receta → alta); no toca los registros de sesión, solo operaciones reversibles."
5
+ }
6
+ }
package/locale/fr.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Intendant de session",
4
+ "description": "Fichiers d'historique de session (consultation et nettoyage des archives) et contrôle de santé des sessions (examen → ordonnance → sortie) ; aucune modification des journaux de session, opérations réversibles uniquement."
5
+ }
6
+ }
package/locale/it.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Amministratore di sessione",
4
+ "description": "File della cronologia delle sessioni (consultazione e pulizia degli archivi) e controllo di salute delle sessioni (visita → prescrizione → dimissione); non tocca i log di sessione, solo operazioni reversibili."
5
+ }
6
+ }
package/locale/ja.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "セッションスチュワード",
4
+ "description": "セッション履歴ファイル(アーカイブの閲覧とクリーンアップ)とセッションのヘルスチェック(健診 → 処方 → 退院)。セッションログには触れず、可逆的な操作のみを行います。"
5
+ }
6
+ }
package/locale/ko.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "세션 스튜어드",
4
+ "description": "세션 기록 파일(아카이브 탐색 및 정리)과 세션 건강 점검(진료 → 처방 → 퇴원). 세션 로그는 건드리지 않으며 되돌릴 수 있는 작업만 수행합니다."
5
+ }
6
+ }
package/locale/ru.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Распорядитель сессий",
4
+ "description": "Файлы истории сессий (просмотр и очистка архивов) и проверка здоровья сессий (осмотр → рецепт → выписка); не затрагивает журналы сессий, только обратимые операции."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "会话管家",
4
+ "description": "会话历史文件(归档浏览与清理)与会话健康检查(体检 → 处方 → 出院),不碰会话日志、只做可逆处置。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,18 +1,24 @@
1
1
  {
2
2
  "name": "dsh-manage-session",
3
- "version": "0.4.8",
3
+ "version": "0.5.3",
4
4
  "publishConfig": {
5
- "tag": "dsh-0.1.7"
5
+ "registry": "https://registry.npmjs.org",
6
+ "tag": "latest",
7
+ "access": "public"
6
8
  },
7
- "description": "DSH Web 插件(DSH 0.1.5 专线):会话管家 —— 会话历史文件(归档浏览与清理)与会话健康检查(体检 → 处方 → 出院),不碰会话日志、只做可逆处置",
9
+ "description": "DSH Web 插件:会话管家(合并包)—— 会话历史文件(归档浏览与清理)与健康检查(体检 → 处方 → 出院),外加独立 FTS5 会话内容搜索索引(标题/内容双模式、增量同步、非破坏性整理与快照导入导出)。不碰会话日志、只做可逆处置。",
8
10
  "keywords": [
11
+ "archive",
9
12
  "deepseek-harness",
13
+ "doctor",
10
14
  "dsh",
11
15
  "dsh-plugin",
12
- "session",
13
- "archive",
16
+ "fts5",
14
17
  "health",
15
- "doctor"
18
+ "index",
19
+ "search",
20
+ "session",
21
+ "sqlite"
16
22
  ],
17
23
  "repository": {
18
24
  "type": "git",
@@ -30,6 +36,7 @@
30
36
  "default": "./lib/client.js"
31
37
  },
32
38
  "./cordis.patch.yml": "./cordis.patch.yml",
39
+ "./locale/*.json": "./locale/*.json",
33
40
  "./package.json": "./package.json"
34
41
  },
35
42
  "dsh": {
@@ -47,46 +54,47 @@
47
54
  },
48
55
  "scripts": {
49
56
  "build": "node -e \"require('fs').rmSync('lib',{recursive:true,force:true})\" && tsc -b && tsdown",
50
- "prepublishOnly": "npm run build",
57
+ "prepack": "npm run build",
58
+ "prepublishOnly": "npm run build && node scripts/check-release.mjs",
51
59
  "typecheck": "tsc -b --pretty false",
52
60
  "test": "vitest run",
53
- "release:015": "npm publish --tag dsh-0.1.5"
61
+ "test:client": "node tests/client-store.test.mjs && node tests/client-panel-key.test.mjs && node tests/client-styles.test.mjs && node --import tsx tests/client-platform.test.mjs && node --import tsx tests/client-host-api.test.mjs && node --import tsx tests/client-locales.test.mjs && node --import tsx tests/client-open-session.test.mjs",
62
+ "test:release": "node scripts/check-release.mjs"
54
63
  },
55
64
  "files": [
56
- "lib/index.js",
57
- "lib/index.d.ts",
58
- "lib/client.js",
59
- "src",
60
- "cordis.patch.yml",
61
- "dsh.plugin.json",
62
- "screenshots.json",
63
- "README.md",
65
+ "CHANGELOG.ja.md",
66
+ "CHANGELOG.ko.md",
67
+ "CHANGELOG.md",
68
+ "INSTALL.ja.md",
69
+ "INSTALL.ko.md",
70
+ "INSTALL.md",
71
+ "INSTALL.zh.md",
72
+ "LICENSE",
64
73
  "README.en.md",
65
74
  "README.ja.md",
66
75
  "README.ko.md",
67
- "INSTALL.md",
68
- "INSTALL.zh.md",
69
- "INSTALL.ja.md",
70
- "INSTALL.ko.md",
71
- "CHANGELOG.md",
72
- "CHANGELOG.ja.md",
73
- "CHANGELOG.ko.md",
74
- "LICENSE"
76
+ "README.md",
77
+ "cordis.patch.yml",
78
+ "dsh.plugin.json",
79
+ "lib",
80
+ "locale",
81
+ "screenshots.json",
82
+ "src"
75
83
  ],
76
84
  "engines": {
77
85
  "node": ">=20",
78
- "dsh": ">=0.1.7-rc.1 <0.1.8-0"
86
+ "dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1"
79
87
  },
80
88
  "license": "MIT",
81
89
  "peerDependencies": {
82
90
  "@deepseek-ai/cordis": "^4.0.1",
83
- "@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.1 <0.1.8-0",
84
- "@deepseek-ai/dsh-client-ui-settings": ">=0.1.7-rc.1 <0.1.8-0",
85
- "@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.7-rc.1 <0.1.8-0",
86
- "@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.1 <0.1.8-0",
91
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1",
92
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1",
93
+ "@deepseek-ai/dsh-client-ui-settings-general": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1",
94
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1",
87
95
  "@deepseek-ai/schemastery": "^3.18.4",
88
96
  "react": "^18.2.0",
89
- "@deepseek-ai/dsh-session": ">=0.1.7-rc.1 <0.1.8-0"
97
+ "@deepseek-ai/dsh-session": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1"
90
98
  },
91
99
  "peerDependenciesMeta": {
92
100
  "@deepseek-ai/dsh-client-locale": {
@@ -107,7 +115,7 @@
107
115
  },
108
116
  "devDependencies": {
109
117
  "@deepseek-ai/cordis": "^4.0.1",
110
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.7-rc.1",
118
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.1",
111
119
  "@deepseek-ai/schemastery": "^3.18.4",
112
120
  "@types/node": "^24.0.0",
113
121
  "@types/react": "~18.3.1",
@@ -120,6 +128,9 @@
120
128
  "typescript": "^5.6.0",
121
129
  "vite-tsconfig-paths": "^6.1.1",
122
130
  "vitest": "^4.1.1",
123
- "@deepseek-ai/dsh-session": "^0.1.7-rc.1"
131
+ "@deepseek-ai/dsh-session": "0.2.1-rc.1"
132
+ },
133
+ "optionalDependencies": {
134
+ "better-sqlite3": "12.11.1"
124
135
  }
125
136
  }
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Legacy 设置桥 scope(客户端半身,≤0.1.5 专用)。
3
+ *
4
+ * 为什么存在:旧宿主的 `settingsScope.bind()` 是数据死路(台账 A2——scope
5
+ * status 永远 'unavailable',永不就绪),卡在老线上只剩「不可用」空壳。本
6
+ * 模块把卡片数据面改走自家 webServer 桥(`settings-describe`/`settings-mutate`,
7
+ * 宿主半落在 legacy settings 租约上,context-compression 六格实证的持久化
8
+ * 写路径)。0.1.7+ 不走此路——client/index.ts 的回退链里 configForms 原生
9
+ * 句柄优先,桥只是 legacy 兜底。
10
+ *
11
+ * 形状纪律:快照对象只在状态真正变化时更换引用(useSyncExternalStore 的
12
+ * getSnapshot 缓存语义);describe 在首个 subscribe 时才发起(bundle 级
13
+ * 无头测试只调 getSnapshot、不 subscribe,绝不触发 fetch)。
14
+ */
15
+ import type { StewardConfig } from '../config.ts'
16
+ import type { SwitchSearchConfig } from '../config.ts'
17
+ import { callHostAny } from './host-api.ts'
18
+
19
+ /** 与宿主 settings-bridge.ts 的命名空间键一致(存储键稳定承诺)。 */
20
+ const STEWARD_NS = 'session-steward'
21
+ const SEARCH_NS = 'switch-search'
22
+
23
+ /** 单视图快照(StewardCardScope / SwitchCardScope 的结构交集)。 */
24
+ export interface BridgeSnapshot<V> {
25
+ status: 'loading' | 'ready' | 'unavailable'
26
+ value: V | undefined
27
+ revision: number | undefined
28
+ writable: boolean
29
+ }
30
+
31
+ /** 卡片 scope 面(两张卡各自的结构化镜像的交集)。 */
32
+ export interface BridgeScope<V> {
33
+ getSnapshot(): BridgeSnapshot<V>
34
+ subscribe(listener: () => void): () => void
35
+ set(field: string, value: unknown): Promise<void>
36
+ }
37
+
38
+ /** 共享文档仓:两视图读同一份 describe/mutate 结果。 */
39
+ interface SharedDoc {
40
+ steward: Record<string, unknown>
41
+ search: Record<string, unknown>
42
+ status: 'loading' | 'ready' | 'unavailable'
43
+ writable: boolean
44
+ revision: number | undefined
45
+ }
46
+
47
+ const shared: SharedDoc = {
48
+ steward: {},
49
+ search: {},
50
+ status: 'loading',
51
+ writable: false,
52
+ revision: undefined,
53
+ }
54
+
55
+ const listeners = new Set<() => void>()
56
+ let describeInFlight: Promise<void> | undefined
57
+
58
+ function notify(): void {
59
+ for (const listener of [...listeners]) {
60
+ try {
61
+ listener()
62
+ } catch {
63
+ /* 单个订阅者异常绝不破坏其余通知 */
64
+ }
65
+ }
66
+ }
67
+
68
+ function replaceDoc(next: Partial<SharedDoc>): void {
69
+ Object.assign(shared, next)
70
+ notify()
71
+ }
72
+
73
+ /** 首个订阅触发一次 describe;并发调用共享同一 in-flight promise。 */
74
+ function ensureDescribe(): Promise<void> {
75
+ if (describeInFlight !== undefined) return describeInFlight
76
+ describeInFlight = callHostAny<{ ok?: boolean; writable?: boolean; revision?: number; namespaces?: Record<string, Record<string, unknown>>; error?: string }>(
77
+ 'settings-describe',
78
+ {},
79
+ )
80
+ .then((res) => {
81
+ if (res.ok === true && res.namespaces !== null && typeof res.namespaces === 'object') {
82
+ replaceDoc({
83
+ steward: res.namespaces[STEWARD_NS] ?? {},
84
+ search: res.namespaces[SEARCH_NS] ?? {},
85
+ status: 'ready',
86
+ writable: res.writable === true,
87
+ revision: typeof res.revision === 'number' ? res.revision : undefined,
88
+ })
89
+ } else {
90
+ replaceDoc({ status: 'unavailable', writable: false })
91
+ }
92
+ })
93
+ .catch(() => {
94
+ replaceDoc({ status: 'unavailable', writable: false })
95
+ })
96
+ .finally(() => {
97
+ describeInFlight = undefined
98
+ })
99
+ return describeInFlight
100
+ }
101
+
102
+ /** 组装一个视图 scope。`ns` 决定读/写哪个命名空间文档。 */
103
+ function makeBridgeScope<V extends object>(
104
+ ns: string,
105
+ keyOf: (doc: SharedDoc) => Record<string, unknown>,
106
+ ): BridgeScope<V> {
107
+ let snapshot: BridgeSnapshot<V> = { status: 'loading', value: undefined, revision: undefined, writable: false }
108
+
109
+ const refresh = (): void => {
110
+ const next: BridgeSnapshot<V> = {
111
+ status: shared.status,
112
+ value: (shared.status === 'ready' ? { ...keyOf(shared) } : undefined) as V | undefined,
113
+ revision: shared.revision,
114
+ writable: shared.writable,
115
+ }
116
+ const changed =
117
+ next.status !== snapshot.status ||
118
+ next.writable !== snapshot.writable ||
119
+ next.revision !== snapshot.revision ||
120
+ JSON.stringify(next.value ?? null) !== JSON.stringify(snapshot.value ?? null)
121
+ if (changed) {
122
+ snapshot = next
123
+ }
124
+ }
125
+
126
+ return {
127
+ getSnapshot: () => {
128
+ // 每次读取都先对账共享仓再回缓存(引用稳定性由 refresh 的变更检测保证);
129
+ // 裸读(无 subscribe)只重算缓存,绝不触发 fetch。
130
+ refresh()
131
+ return snapshot
132
+ },
133
+ subscribe: (listener) => {
134
+ listeners.add(listener)
135
+ void ensureDescribe()
136
+ return () => {
137
+ listeners.delete(listener)
138
+ }
139
+ },
140
+ set: async (field, value) => {
141
+ if (shared.status !== 'ready' || shared.writable === false) {
142
+ throw new Error('设置桥不可写(describe 未就绪或宿主只读)')
143
+ }
144
+ const before = keyOf(shared)[field]
145
+ // 乐观回显:开关即时翻转,权威值由 mutate 响应修正。
146
+ keyOf(shared)[field] = value
147
+ refresh()
148
+ const res = await callHostAny<{ ok?: boolean; revision?: number; namespaces?: Record<string, Record<string, unknown>>; error?: string }>(
149
+ 'settings-mutate',
150
+ { ns, fields: { [field]: value } },
151
+ )
152
+ if (res.ok === true && res.namespaces !== null && typeof res.namespaces === 'object') {
153
+ replaceDoc({
154
+ steward: res.namespaces[STEWARD_NS] ?? shared.steward,
155
+ search: res.namespaces[SEARCH_NS] ?? shared.search,
156
+ revision: typeof res.revision === 'number' ? res.revision : shared.revision,
157
+ })
158
+ } else {
159
+ // 失败回滚:开关弹回 = 用户可见的失败信号。
160
+ keyOf(shared)[field] = before
161
+ refresh()
162
+ throw new Error(res.error ?? '设置写入失败')
163
+ }
164
+ },
165
+ }
166
+ }
167
+
168
+ let stewardScope: BridgeScope<StewardConfig> | undefined
169
+ let searchScope: BridgeScope<SwitchSearchConfig> | undefined
170
+
171
+ /** 管家卡/管家入口的桥 scope(命名空间 session-steward)。 */
172
+ export function stewardBridgeScope(): BridgeScope<StewardConfig> {
173
+ stewardScope ??= makeBridgeScope<StewardConfig>(STEWARD_NS, (doc) => doc.steward)
174
+ return stewardScope
175
+ }
176
+
177
+ /** 搜索卡/搜索入口的桥 scope(命名空间 switch-search)。 */
178
+ export function searchBridgeScope(): BridgeScope<SwitchSearchConfig> {
179
+ searchScope ??= makeBridgeScope<SwitchSearchConfig>(SEARCH_NS, (doc) => doc.search)
180
+ return searchScope
181
+ }
182
+
183
+ /**
184
+ * 原生句柄 + 桥的合成 scope:原生快照**在任意时刻**观测到 unavailable(出生
185
+ * 死或 loading→死,0.1.7 上 steward 条目的 configForms 实测后者)就地读桥,
186
+ * 不做 apply 期时序猜测。写侧同理:原生 unavailable 即走桥(桥在无 legacy
187
+ * settings 服务的宿主上 set 会显式拒绝,卡片保持只读真值)。双订阅:桥的
188
+ * describe 全页一次(模块单例),代价可忽略。
189
+ */
190
+ export function withBridgeFallback<V extends object>(
191
+ native: BridgeScope<V> | undefined,
192
+ bridge: BridgeScope<V>,
193
+ ): BridgeScope<V> {
194
+ if (native === undefined) return bridge
195
+ return {
196
+ getSnapshot: () => {
197
+ const snap = native.getSnapshot()
198
+ return snap.status === 'unavailable' ? bridge.getSnapshot() : snap
199
+ },
200
+ subscribe: (listener) => {
201
+ const offNative = native.subscribe(listener)
202
+ const offBridge = bridge.subscribe(listener)
203
+ return () => {
204
+ offNative()
205
+ offBridge()
206
+ }
207
+ },
208
+ set: async (field, value) => {
209
+ if (native.getSnapshot().status === 'unavailable') return bridge.set(field, value)
210
+ return native.set(field, value)
211
+ },
212
+ }
213
+ }