dsh-manage-session 2.0.3 → 2.0.4

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.ja.md +33 -33
  2. package/CHANGELOG.ko.md +33 -33
  3. package/CHANGELOG.md +33 -33
  4. package/INSTALL.ja.md +164 -164
  5. package/INSTALL.ko.md +164 -164
  6. package/INSTALL.md +164 -164
  7. package/INSTALL.zh.md +164 -164
  8. package/LICENSE +21 -21
  9. package/README.en.md +76 -62
  10. package/README.ja.md +53 -39
  11. package/README.ko.md +52 -38
  12. package/README.md +18 -4
  13. package/cordis.patch.yml +19 -19
  14. package/dsh.plugin.json +2 -2
  15. package/locale/de.json +6 -6
  16. package/locale/en.json +6 -6
  17. package/locale/es.json +6 -6
  18. package/locale/fr.json +6 -6
  19. package/locale/it.json +6 -6
  20. package/locale/ja.json +6 -6
  21. package/locale/ko.json +6 -6
  22. package/locale/ru.json +6 -6
  23. package/locale/zh.json +6 -6
  24. package/package.json +9 -9
  25. package/screenshots.json +3 -3
  26. package/src/client/bridge-scope.ts +202 -202
  27. package/src/client/card.tsx +154 -154
  28. package/src/client/host-api.ts +61 -61
  29. package/src/client/index.ts +594 -594
  30. package/src/client/locales.ts +893 -893
  31. package/src/client/manage-locales.ts +178 -178
  32. package/src/client/manage.tsx +430 -430
  33. package/src/client/panel.tsx +131 -131
  34. package/src/config.ts +43 -43
  35. package/src/host/health/attribution.ts +118 -118
  36. package/src/host/health/lossless.ts +128 -128
  37. package/src/host/health/source-kind.ts +350 -350
  38. package/src/host/history/archive-source.ts +250 -250
  39. package/src/host/history/archive.ts +249 -249
  40. package/src/host/history/favorites.ts +71 -71
  41. package/src/host/history/purge.ts +370 -370
  42. package/src/host/registry/archive-registry.ts +317 -317
  43. package/src/host/settings-bridge.ts +222 -222
@@ -1,154 +1,154 @@
1
- /**
2
- * 设置卡(插件配置行):一个可折叠抽屉 —— 会话历史文件 / 健康检查。
3
- *
4
- * **chrome 必须自己渲染**:宿主不为贡献卡提供任何外壳,标题、说明、
5
- * 展开/收起全归插件自己所有。早期版本只渲染裸行,与同分区其它插件
6
- * 的抽屉形态不一致,还让 `card.title` / `card.desc` 成为死文案。
7
- *
8
- * 读写走 configForms(`configForms.get(STEWARD_ENTRY_ID)`,以本插件 entry 为键;
9
- * 旧宿主回退 settingsScope 绑定)的显式 `set`。0.1.7 起本卡挂在插件族共用
10
- * 设置节(`dsh-family.tab`,dsh-thinking-levels 顶级「起子插件设置」节声明)里,
11
- * 与同节其它抽屉一样默认展开。
12
- */
13
- import { createElement, useState, useSyncExternalStore, type JSX } from 'react'
14
- import { DEFAULT_CONFIG, type StewardConfig } from '../config.ts'
15
- import { translate, type LocaleKey } from './locales.ts'
16
-
17
- /** 卡片字典面。 */
18
- export type CardTranslate = (key: LocaleKey, params?: Record<string, unknown>) => string
19
-
20
- /** 设置 scope 面(结构化镜像,与 toggle 的 SwitchCardScope 同形状)。 */
21
- export interface StewardCardScope {
22
- getSnapshot(): {
23
- status: 'ready' | 'loading' | 'unavailable'
24
- value: StewardConfig | undefined
25
- revision?: number
26
- writable: boolean
27
- }
28
- subscribe(listener: () => void): () => void
29
- set(field: string, value: unknown): Promise<void>
30
- }
31
-
32
- /** 卡片入参。 */
33
- export interface StewardCardProps {
34
- t?: CardTranslate
35
- scope: StewardCardScope
36
- }
37
-
38
- /** 一行设置项。 */
39
- function Row(props: { title: string; desc?: string; control: JSX.Element }): JSX.Element {
40
- return createElement('div', { className: 'dms_setRow' }, [
41
- createElement('div', { key: 'text', className: 'dms_setText' }, [
42
- createElement('span', { key: 't', className: 'dms_setTitle' }, props.title),
43
- props.desc !== undefined && createElement('span', { key: 'd', className: 'dms_setDesc' }, props.desc),
44
- ]),
45
- createElement('div', { key: 'ctl' }, props.control),
46
- ])
47
- }
48
-
49
- /** 一个布尔开关(原生 checkbox 语义,样式由本插件 CSS 提供)。 */
50
- function Toggle(props: { checked: boolean; disabled?: boolean; onChange: (checked: boolean) => void }): JSX.Element {
51
- return createElement('label', { className: `dms_toggle${props.checked ? ' dms_toggleOn' : ''}` }, [
52
- createElement('input', {
53
- key: 'i',
54
- type: 'checkbox',
55
- checked: props.checked,
56
- disabled: props.disabled === true,
57
- onChange: (event: { target: { checked: boolean } }) => { props.onChange(event.target.checked) },
58
- }),
59
- createElement('span', { key: 's', className: 'dms_toggleTrack' }, createElement('span', { className: 'dms_toggleKnob' })),
60
- ])
61
- }
62
-
63
- /** 抽屉头:标题 + 说明 + chevron,整块可点。 */
64
- function Header(props: { t?: CardTranslate; open: boolean; onToggle: () => void }): JSX.Element {
65
- return createElement('button', {
66
- key: 'head',
67
- type: 'button',
68
- className: 'dms_setHead',
69
- 'aria-expanded': props.open,
70
- onClick: props.onToggle,
71
- }, [
72
- createElement('span', { key: 'text', className: 'dms_setHeadText' }, [
73
- createElement('span', { key: 't', className: 'dms_setCardTitle' }, translate(props.t, 'card.title')),
74
- createElement('span', { key: 'd', className: 'dms_setCardDesc' }, translate(props.t, 'card.desc')),
75
- ]),
76
- createElement('svg', {
77
- key: 'chev',
78
- className: 'dms_setChev',
79
- width: 16,
80
- height: 16,
81
- viewBox: '0 0 16 16',
82
- 'aria-hidden': true,
83
- }, createElement('path', {
84
- d: 'M4 6l4 4 4-4',
85
- fill: 'none',
86
- stroke: 'currentColor',
87
- strokeWidth: 1.5,
88
- strokeLinecap: 'round',
89
- strokeLinejoin: 'round',
90
- })),
91
- ])
92
- }
93
-
94
- /** 插件设置卡主体(抽屉)。默认展开,family 设置节内直接呈现完整面板。 */
95
- export function StewardSettingsCard({ t, scope }: StewardCardProps): JSX.Element {
96
- const snapshot = useSyncExternalStore(
97
- (listener) => scope.subscribe(listener),
98
- () => scope.getSnapshot(),
99
- )
100
- const [open, setOpen] = useState(true)
101
- const value: Partial<StewardConfig> = snapshot.value ?? {}
102
- const writable = snapshot.writable
103
-
104
- const rows: JSX.Element[] = []
105
- if (snapshot.status === 'unavailable') {
106
- // 拿不到设置服务:抽屉仍要在(否则这个插件在分区里彻底消失),只是里面说明原因。
107
- rows.push(createElement('div', { key: 'unavailable', className: 'dms_setDesc' }, translate(t, 'card.unavailable')))
108
- } else {
109
- rows.push(
110
- createElement(Row, {
111
- key: 'enabled',
112
- title: translate(t, 'card.enabled'),
113
- desc: translate(t, 'card.enabled.desc'),
114
- control: createElement(Toggle, {
115
- checked: value.enabled ?? DEFAULT_CONFIG.enabled,
116
- disabled: !writable,
117
- onChange: (checked) => { void scope.set('enabled', checked) },
118
- }),
119
- }),
120
- // 2026-10-20 养老院页签退场:historyFiles 开关不再暴露(配置字段保留,
121
- // 宿主侧历史文件能力/路由不动)。
122
- createElement(Row, {
123
- key: 'health',
124
- title: translate(t, 'card.health'),
125
- desc: translate(t, 'card.health.desc'),
126
- control: createElement(Toggle, {
127
- checked: value.healthCheck ?? DEFAULT_CONFIG.healthCheck,
128
- disabled: !writable,
129
- onChange: (checked) => { void scope.set('healthCheck', checked) },
130
- }),
131
- }),
132
- // 直接删除入口(功能①,2026-10-20 用户定标):缺省关——破坏性入口
133
- // 不默认铺开;开启后搜索面板行内出删除按钮(同款两步确认)。
134
- createElement(Row, {
135
- key: 'directDelete',
136
- title: translate(t, 'card.directDelete'),
137
- desc: translate(t, 'card.directDelete.desc'),
138
- control: createElement(Toggle, {
139
- checked: value.directDelete ?? DEFAULT_CONFIG.directDelete,
140
- disabled: !writable,
141
- onChange: (checked) => { void scope.set('directDelete', checked) },
142
- }),
143
- }),
144
- )
145
- if (!writable) rows.push(createElement('div', { key: 'ro', className: 'dms_setDesc' }, translate(t, 'card.readonly')))
146
- }
147
-
148
- return createElement('div', {
149
- className: `dms_setCard${open ? ' dms_setCardOpen' : ''}`,
150
- }, [
151
- createElement(Header, { key: 'head', t, open, onToggle: () => { setOpen(current => !current) } }),
152
- open && createElement('div', { key: 'body', className: 'dms_setBody' }, rows),
153
- ])
154
- }
1
+ /**
2
+ * 设置卡(插件配置行):一个可折叠抽屉 —— 会话历史文件 / 健康检查。
3
+ *
4
+ * **chrome 必须自己渲染**:宿主不为贡献卡提供任何外壳,标题、说明、
5
+ * 展开/收起全归插件自己所有。早期版本只渲染裸行,与同分区其它插件
6
+ * 的抽屉形态不一致,还让 `card.title` / `card.desc` 成为死文案。
7
+ *
8
+ * 读写走 configForms(`configForms.get(STEWARD_ENTRY_ID)`,以本插件 entry 为键;
9
+ * 旧宿主回退 settingsScope 绑定)的显式 `set`。0.1.7 起本卡挂在插件族共用
10
+ * 设置节(`dsh-family.tab`,dsh-thinking-levels 顶级「起子插件设置」节声明)里,
11
+ * 与同节其它抽屉一样默认展开。
12
+ */
13
+ import { createElement, useState, useSyncExternalStore, type JSX } from 'react'
14
+ import { DEFAULT_CONFIG, type StewardConfig } from '../config.ts'
15
+ import { translate, type LocaleKey } from './locales.ts'
16
+
17
+ /** 卡片字典面。 */
18
+ export type CardTranslate = (key: LocaleKey, params?: Record<string, unknown>) => string
19
+
20
+ /** 设置 scope 面(结构化镜像,与 toggle 的 SwitchCardScope 同形状)。 */
21
+ export interface StewardCardScope {
22
+ getSnapshot(): {
23
+ status: 'ready' | 'loading' | 'unavailable'
24
+ value: StewardConfig | undefined
25
+ revision?: number
26
+ writable: boolean
27
+ }
28
+ subscribe(listener: () => void): () => void
29
+ set(field: string, value: unknown): Promise<void>
30
+ }
31
+
32
+ /** 卡片入参。 */
33
+ export interface StewardCardProps {
34
+ t?: CardTranslate
35
+ scope: StewardCardScope
36
+ }
37
+
38
+ /** 一行设置项。 */
39
+ function Row(props: { title: string; desc?: string; control: JSX.Element }): JSX.Element {
40
+ return createElement('div', { className: 'dms_setRow' }, [
41
+ createElement('div', { key: 'text', className: 'dms_setText' }, [
42
+ createElement('span', { key: 't', className: 'dms_setTitle' }, props.title),
43
+ props.desc !== undefined && createElement('span', { key: 'd', className: 'dms_setDesc' }, props.desc),
44
+ ]),
45
+ createElement('div', { key: 'ctl' }, props.control),
46
+ ])
47
+ }
48
+
49
+ /** 一个布尔开关(原生 checkbox 语义,样式由本插件 CSS 提供)。 */
50
+ function Toggle(props: { checked: boolean; disabled?: boolean; onChange: (checked: boolean) => void }): JSX.Element {
51
+ return createElement('label', { className: `dms_toggle${props.checked ? ' dms_toggleOn' : ''}` }, [
52
+ createElement('input', {
53
+ key: 'i',
54
+ type: 'checkbox',
55
+ checked: props.checked,
56
+ disabled: props.disabled === true,
57
+ onChange: (event: { target: { checked: boolean } }) => { props.onChange(event.target.checked) },
58
+ }),
59
+ createElement('span', { key: 's', className: 'dms_toggleTrack' }, createElement('span', { className: 'dms_toggleKnob' })),
60
+ ])
61
+ }
62
+
63
+ /** 抽屉头:标题 + 说明 + chevron,整块可点。 */
64
+ function Header(props: { t?: CardTranslate; open: boolean; onToggle: () => void }): JSX.Element {
65
+ return createElement('button', {
66
+ key: 'head',
67
+ type: 'button',
68
+ className: 'dms_setHead',
69
+ 'aria-expanded': props.open,
70
+ onClick: props.onToggle,
71
+ }, [
72
+ createElement('span', { key: 'text', className: 'dms_setHeadText' }, [
73
+ createElement('span', { key: 't', className: 'dms_setCardTitle' }, translate(props.t, 'card.title')),
74
+ createElement('span', { key: 'd', className: 'dms_setCardDesc' }, translate(props.t, 'card.desc')),
75
+ ]),
76
+ createElement('svg', {
77
+ key: 'chev',
78
+ className: 'dms_setChev',
79
+ width: 16,
80
+ height: 16,
81
+ viewBox: '0 0 16 16',
82
+ 'aria-hidden': true,
83
+ }, createElement('path', {
84
+ d: 'M4 6l4 4 4-4',
85
+ fill: 'none',
86
+ stroke: 'currentColor',
87
+ strokeWidth: 1.5,
88
+ strokeLinecap: 'round',
89
+ strokeLinejoin: 'round',
90
+ })),
91
+ ])
92
+ }
93
+
94
+ /** 插件设置卡主体(抽屉)。默认展开,family 设置节内直接呈现完整面板。 */
95
+ export function StewardSettingsCard({ t, scope }: StewardCardProps): JSX.Element {
96
+ const snapshot = useSyncExternalStore(
97
+ (listener) => scope.subscribe(listener),
98
+ () => scope.getSnapshot(),
99
+ )
100
+ const [open, setOpen] = useState(true)
101
+ const value: Partial<StewardConfig> = snapshot.value ?? {}
102
+ const writable = snapshot.writable
103
+
104
+ const rows: JSX.Element[] = []
105
+ if (snapshot.status === 'unavailable') {
106
+ // 拿不到设置服务:抽屉仍要在(否则这个插件在分区里彻底消失),只是里面说明原因。
107
+ rows.push(createElement('div', { key: 'unavailable', className: 'dms_setDesc' }, translate(t, 'card.unavailable')))
108
+ } else {
109
+ rows.push(
110
+ createElement(Row, {
111
+ key: 'enabled',
112
+ title: translate(t, 'card.enabled'),
113
+ desc: translate(t, 'card.enabled.desc'),
114
+ control: createElement(Toggle, {
115
+ checked: value.enabled ?? DEFAULT_CONFIG.enabled,
116
+ disabled: !writable,
117
+ onChange: (checked) => { void scope.set('enabled', checked) },
118
+ }),
119
+ }),
120
+ // 2026-10-20 养老院页签退场:historyFiles 开关不再暴露(配置字段保留,
121
+ // 宿主侧历史文件能力/路由不动)。
122
+ createElement(Row, {
123
+ key: 'health',
124
+ title: translate(t, 'card.health'),
125
+ desc: translate(t, 'card.health.desc'),
126
+ control: createElement(Toggle, {
127
+ checked: value.healthCheck ?? DEFAULT_CONFIG.healthCheck,
128
+ disabled: !writable,
129
+ onChange: (checked) => { void scope.set('healthCheck', checked) },
130
+ }),
131
+ }),
132
+ // 直接删除入口(功能①,2026-10-20 用户定标):缺省关——破坏性入口
133
+ // 不默认铺开;开启后搜索面板行内出删除按钮(同款两步确认)。
134
+ createElement(Row, {
135
+ key: 'directDelete',
136
+ title: translate(t, 'card.directDelete'),
137
+ desc: translate(t, 'card.directDelete.desc'),
138
+ control: createElement(Toggle, {
139
+ checked: value.directDelete ?? DEFAULT_CONFIG.directDelete,
140
+ disabled: !writable,
141
+ onChange: (checked) => { void scope.set('directDelete', checked) },
142
+ }),
143
+ }),
144
+ )
145
+ if (!writable) rows.push(createElement('div', { key: 'ro', className: 'dms_setDesc' }, translate(t, 'card.readonly')))
146
+ }
147
+
148
+ return createElement('div', {
149
+ className: `dms_setCard${open ? ' dms_setCardOpen' : ''}`,
150
+ }, [
151
+ createElement(Header, { key: 'head', t, open, onToggle: () => { setOpen(current => !current) } }),
152
+ open && createElement('div', { key: 'body', className: 'dms_setBody' }, rows),
153
+ ])
154
+ }
@@ -188,13 +188,13 @@ export interface SourceMigrateResponse {
188
188
  * 兼容别名:合并包时代的 `callSteward` 与 `callHostAny` 同实现(同一 fenced
189
189
  * 路由、同一返回形状),保留调用面不迁移。
190
190
  */
191
- export const callSteward = callHostAny
192
-
193
- /** POST 到 items 形状的 fenced 方法(管理台语料 session-catalog 用)。 */
194
- export async function callStewardItems<T>(method: string, body: unknown): Promise<{ ok: boolean; items: T[]; error?: string }> {
195
- const res = await callHostAny<{ items?: T[] }>(method, body)
196
- if (res.ok === true && Array.isArray(res.items)) return { ok: true, items: res.items }
197
- return { ok: false, items: [], error: res.error ?? '请求失败' }
191
+ export const callSteward = callHostAny
192
+
193
+ /** POST 到 items 形状的 fenced 方法(管理台语料 session-catalog 用)。 */
194
+ export async function callStewardItems<T>(method: string, body: unknown): Promise<{ ok: boolean; items: T[]; error?: string }> {
195
+ const res = await callHostAny<{ items?: T[] }>(method, body)
196
+ if (res.ok === true && Array.isArray(res.items)) return { ok: true, items: res.items }
197
+ return { ok: false, items: [], error: res.error ?? '请求失败' }
198
198
  }
199
199
 
200
200
  /** 状态响应。 */
@@ -205,57 +205,57 @@ export interface HealthStatusResponse {
205
205
  healthMethods?: string[]
206
206
  home?: string
207
207
  error?: string
208
- }
209
-
210
- /** One session listed by `session-catalog` (active + archived in one table). */
211
- export interface HostSessionItem {
212
- sessionId: string
213
- title: string
214
- cwd: string
215
- updatedAt: number
216
- /** 归档标记(合表语义):缺省字段按「活跃」对待。 */
217
- archived?: boolean
218
- }
219
-
220
- /**
221
- * 直接删除入口开关(`manage-session.directDelete`,缺省关)。
222
- * 由 `session-health-status` 的 switches 面读取;旧宿主半无该字段 → false
223
- * (破坏性入口不出现是安全方向)。
224
- */
225
- export async function probeDirectDelete(): Promise<boolean> {
226
- const res = await callHostAny<HealthStatusResponse>('session-health-status', {})
227
- return res.ok === true && res.switches?.directDelete === true
228
- }
229
-
230
- /**
231
- * The client sessions service face. Host lines before 0.1.7 exposed session
232
- * navigation here as `open`; the 0.1.7 contract dropped it ("navigation
233
- * belongs to view owners") — kept only as the legacy fallback of
234
- * `openSessionThrough`.
235
- */
236
- export interface SwitchSessionsService {
237
- open(id: string): void
238
- }
239
-
240
- /**
241
- * The client ui-workspace face: session navigation has been owned by this
242
- * service since host 0.1.7 (`openSession`; a bare session id is accepted).
243
- */
244
- export interface SwitchUiWorkspaceService {
245
- openSession(target: string): void
246
- }
247
-
248
- /**
249
- * Open a session through whichever face the running host offers:
250
- * `uiWorkspace.openSession` first (0.1.7+), the pre-0.1.7 `sessions.open` as
251
- * fallback. Neither present → silent no-op.
252
- */
253
- export function openSessionThrough(get: (name: string) => unknown, sessionId: string): void {
254
- const uiWorkspace = get('uiWorkspace') as SwitchUiWorkspaceService | undefined
255
- if (uiWorkspace !== undefined && typeof uiWorkspace.openSession === 'function') {
256
- uiWorkspace.openSession(sessionId)
257
- return
258
- }
259
- const sessions = get('sessions') as SwitchSessionsService | undefined
260
- if (sessions !== undefined && typeof sessions.open === 'function') sessions.open(sessionId)
261
- }
208
+ }
209
+
210
+ /** One session listed by `session-catalog` (active + archived in one table). */
211
+ export interface HostSessionItem {
212
+ sessionId: string
213
+ title: string
214
+ cwd: string
215
+ updatedAt: number
216
+ /** 归档标记(合表语义):缺省字段按「活跃」对待。 */
217
+ archived?: boolean
218
+ }
219
+
220
+ /**
221
+ * 直接删除入口开关(`manage-session.directDelete`,缺省关)。
222
+ * 由 `session-health-status` 的 switches 面读取;旧宿主半无该字段 → false
223
+ * (破坏性入口不出现是安全方向)。
224
+ */
225
+ export async function probeDirectDelete(): Promise<boolean> {
226
+ const res = await callHostAny<HealthStatusResponse>('session-health-status', {})
227
+ return res.ok === true && res.switches?.directDelete === true
228
+ }
229
+
230
+ /**
231
+ * The client sessions service face. Host lines before 0.1.7 exposed session
232
+ * navigation here as `open`; the 0.1.7 contract dropped it ("navigation
233
+ * belongs to view owners") — kept only as the legacy fallback of
234
+ * `openSessionThrough`.
235
+ */
236
+ export interface SwitchSessionsService {
237
+ open(id: string): void
238
+ }
239
+
240
+ /**
241
+ * The client ui-workspace face: session navigation has been owned by this
242
+ * service since host 0.1.7 (`openSession`; a bare session id is accepted).
243
+ */
244
+ export interface SwitchUiWorkspaceService {
245
+ openSession(target: string): void
246
+ }
247
+
248
+ /**
249
+ * Open a session through whichever face the running host offers:
250
+ * `uiWorkspace.openSession` first (0.1.7+), the pre-0.1.7 `sessions.open` as
251
+ * fallback. Neither present → silent no-op.
252
+ */
253
+ export function openSessionThrough(get: (name: string) => unknown, sessionId: string): void {
254
+ const uiWorkspace = get('uiWorkspace') as SwitchUiWorkspaceService | undefined
255
+ if (uiWorkspace !== undefined && typeof uiWorkspace.openSession === 'function') {
256
+ uiWorkspace.openSession(sessionId)
257
+ return
258
+ }
259
+ const sessions = get('sessions') as SwitchSessionsService | undefined
260
+ if (sessions !== undefined && typeof sessions.open === 'function') sessions.open(sessionId)
261
+ }