dsh-multi-chat 0.6.8 → 1.0.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 (63) hide show
  1. package/README.md +20 -21
  2. package/README.zh.md +20 -21
  3. package/bin/dsh-multi-chat.mjs +5 -9
  4. package/lib/client.js +778 -0
  5. package/lib/client.js.map +1 -0
  6. package/{plugin/dsh-client-ui-multi-wall/lib → lib}/index.js +57 -69
  7. package/lib/tsconfig.tsbuildinfo +1 -0
  8. package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/client/WallToggle.d.ts +1 -1
  9. package/lib/types/client/WallToggle.d.ts.map +1 -0
  10. package/lib/types/client/WallToggle.js +36 -0
  11. package/lib/types/client/WallToggle.js.map +1 -0
  12. package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/client/WallView.d.ts +1 -1
  13. package/lib/types/client/WallView.d.ts.map +1 -0
  14. package/lib/types/client/WallView.js +218 -0
  15. package/lib/types/client/WallView.js.map +1 -0
  16. package/lib/types/client/index.d.ts.map +1 -0
  17. package/lib/types/client/index.js +59 -0
  18. package/lib/types/client/index.js.map +1 -0
  19. package/lib/types/client/locales.d.ts.map +1 -0
  20. package/lib/types/client/locales.js +96 -0
  21. package/lib/types/client/locales.js.map +1 -0
  22. package/lib/types/client/store.d.ts.map +1 -0
  23. package/lib/types/client/store.js +27 -0
  24. package/lib/types/client/store.js.map +1 -0
  25. package/lib/types/client/wall-injected.d.ts.map +1 -0
  26. package/lib/types/client/wall-injected.js +76 -0
  27. package/lib/types/client/wall-injected.js.map +1 -0
  28. package/lib/types/gateway.d.ts +57 -0
  29. package/lib/types/gateway.d.ts.map +1 -0
  30. package/lib/types/gateway.js +566 -0
  31. package/lib/types/gateway.js.map +1 -0
  32. package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/index.d.ts +1 -16
  33. package/lib/types/index.d.ts.map +1 -0
  34. package/lib/types/index.js +550 -0
  35. package/lib/types/index.js.map +1 -0
  36. package/lib/types/invariant.d.ts.map +1 -0
  37. package/lib/types/invariant.js +26 -0
  38. package/lib/types/invariant.js.map +1 -0
  39. package/package.json +41 -17
  40. package/scripts/install-plugin.ps1 +6 -9
  41. package/src/client/WallToggle.module.css +26 -0
  42. package/src/client/WallToggle.tsx +52 -0
  43. package/src/client/WallView.module.css +190 -0
  44. package/src/client/WallView.tsx +406 -0
  45. package/src/client/index.ts +103 -0
  46. package/src/client/locales.ts +100 -0
  47. package/src/client/store.ts +40 -0
  48. package/src/client/wall-injected.ts +123 -0
  49. package/src/css-modules.d.ts +5 -0
  50. package/src/gateway.ts +627 -0
  51. package/src/index.ts +618 -0
  52. package/src/invariant.ts +34 -0
  53. package/plugin/dsh-client-ui-multi-wall/README.md +0 -26
  54. package/plugin/dsh-client-ui-multi-wall/README.zh.md +0 -26
  55. package/plugin/dsh-client-ui-multi-wall/cordis.patch.yml +0 -7
  56. package/plugin/dsh-client-ui-multi-wall/lib/client.js +0 -781
  57. package/plugin/dsh-client-ui-multi-wall/lib/invariant.js +0 -27
  58. package/plugin/dsh-client-ui-multi-wall/package.json +0 -88
  59. /package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/client/index.d.ts +0 -0
  60. /package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/client/locales.d.ts +0 -0
  61. /package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/client/store.d.ts +0 -0
  62. /package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/client/wall-injected.d.ts +0 -0
  63. /package/{plugin/dsh-client-ui-multi-wall/lib → lib}/types/invariant.d.ts +0 -0
package/package.json CHANGED
@@ -1,18 +1,23 @@
1
1
  {
2
2
  "name": "dsh-multi-chat",
3
- "version": "0.6.8",
4
- "description": "DSH 多对话:在官�?DeepSeek Harness Web 界面里以多窗口网格并排运行、监控多个对话实例,一屏盯住所�?Agent 的实时进度;内置带口令认证的局域网网关,手�?平板也能看。npx dsh-multi-chat install|start|stop|gateway",
3
+ "version": "1.0.0",
4
+ "description": "DSH 多窗口墙:在官方 DeepSeek Harness Web 界面里以多窗口网格并排运行、监控多个对话实例,一屏盯住所有 Agent 的实时进度;内置带口令认证的局域网网关,手机/平板也能看。",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "main": "plugin/dsh-client-ui-multi-wall/lib/index.js",
7
+ "main": "./lib/index.js",
8
+ "types": "./lib/types/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
- "types": "./plugin/dsh-client-ui-multi-wall/lib/types/index.d.ts",
11
- "default": "./plugin/dsh-client-ui-multi-wall/lib/index.js"
11
+ "types": "./lib/types/index.d.ts",
12
+ "default": "./lib/index.js"
12
13
  },
13
14
  "./client": {
14
- "types": "./plugin/dsh-client-ui-multi-wall/lib/types/client/index.d.ts",
15
- "default": "./plugin/dsh-client-ui-multi-wall/lib/client.js"
15
+ "types": "./lib/types/client/index.d.ts",
16
+ "default": "./lib/client.js"
17
+ },
18
+ "./invariant": {
19
+ "types": "./lib/types/invariant.d.ts",
20
+ "default": "./lib/invariant.js"
16
21
  },
17
22
  "./package.json": "./package.json"
18
23
  },
@@ -20,8 +25,20 @@
20
25
  "bundle": {
21
26
  "patch": "./cordis.patch.yml"
22
27
  },
28
+ "client": {
29
+ "platform": "web",
30
+ "inject": [
31
+ "@deepseek-ai/dsh-client-runtime",
32
+ "@deepseek-ai/dsh-client-locale",
33
+ "@deepseek-ai/dsh-client-ui-layout",
34
+ "@deepseek-ai/dsh-client-ui-sidebar",
35
+ "@deepseek-ai/dsh-client-ui-primitives"
36
+ ]
37
+ },
23
38
  "marketplace": {
24
- "profiles": ["web"],
39
+ "profiles": [
40
+ "web"
41
+ ],
25
42
  "requiresRestart": true,
26
43
  "manualSteps": false,
27
44
  "requiresBuildApproval": false
@@ -55,22 +72,29 @@
55
72
  "scripts/",
56
73
  "patches/",
57
74
  "assets/",
75
+ "lib/",
76
+ "src/",
58
77
  "cordis.patch.yml",
59
78
  "README.md",
60
79
  "README.zh.md",
61
- "plugin/dsh-client-ui-multi-wall/package.json",
62
- "plugin/dsh-client-ui-multi-wall/README.md",
63
- "plugin/dsh-client-ui-multi-wall/README.zh.md",
64
- "plugin/dsh-client-ui-multi-wall/cordis.patch.yml",
65
- "plugin/dsh-client-ui-multi-wall/lib/index.js",
66
- "plugin/dsh-client-ui-multi-wall/lib/invariant.js",
67
- "plugin/dsh-client-ui-multi-wall/lib/client.js",
68
- "plugin/dsh-client-ui-multi-wall/lib/types/**/*.d.ts"
80
+ "LICENSE"
69
81
  ],
70
82
  "scripts": {
71
- "test": "cd harness-src && npx vitest run packages/client/ui-multi-wall"
83
+ "build": "tsc -b tsconfig.json && tsdown",
84
+ "clean": "rm -rf lib",
85
+ "test": "vitest run"
86
+ },
87
+ "devDependencies": {
88
+ "@types/node": "^26.2.0",
89
+ "lightningcss": "^1.33.0",
90
+ "tsdown": "^0.11.13",
91
+ "typescript": "^5.9.3",
92
+ "vitest": "^2.1.9"
72
93
  },
73
94
  "engines": {
74
95
  "node": ">=20"
96
+ },
97
+ "dependencies": {
98
+ "clsx": "^2.1.1"
75
99
  }
76
100
  }
@@ -4,7 +4,7 @@
4
4
  把多窗口墙插件装进 DSH web profile 并启用(官方声明式 bundle 形态)。
5
5
 
6
6
  .DESCRIPTION
7
- 1) 将 plugin/dsh-client-ui-multi-wall 打包为 tarball;
7
+ 1) 将 dsh-multi-chat 打包为 tarball;
8
8
  2) 用 `dsh plugin --profile web add` 装进 profile;
9
9
  3) DSH 自动调和 dsh.profile.bundles:插件包声明了 dsh.bundle.patch
10
10
  (指向包内自带 cordis.patch.yml),DSH 启动时自动挂载该 bundle 层,
@@ -13,7 +13,7 @@
13
13
  侧边栏底部会出现「多窗口墙」按钮)。
14
14
 
15
15
  卸载(一条命令,无需手动删 patch 或文件):
16
- dsh plugin --profile <Profile> remove @deepseek-ai/dsh-client-ui-multi-wall
16
+ dsh plugin --profile <Profile> remove dsh-multi-chat
17
17
 
18
18
  .PARAMETER Profile
19
19
  profile 名,默认 web。
@@ -27,13 +27,10 @@ param(
27
27
 
28
28
  $ErrorActionPreference = "Stop"
29
29
  $root = Split-Path -Parent $PSScriptRoot
30
- $pluginDir = Join-Path $root "plugin\dsh-client-ui-multi-wall"
31
30
 
32
- if (-not (Test-Path $pluginDir)) { throw "未找到插件目录:$pluginDir" }
33
-
34
- # 1) pack tarball
35
- $tarball = Join-Path $root "dsh-client-ui-multi-wall.tgz"
36
- Push-Location $pluginDir
31
+ # 1) pack tarball from root directory
32
+ $tarball = Join-Path $root "dsh-multi-chat.tgz"
33
+ Push-Location $root
37
34
  npm pack --pack-destination $root | Out-Null
38
35
  Pop-Location
39
36
  if (-not (Test-Path $tarball)) { throw "npm pack 失败,未生成 $tarball" }
@@ -49,4 +46,4 @@ Write-Host ""
49
46
  Write-Host "完成。重启 dsh web 生效:"
50
47
  Write-Host " dsh web --port <n>"
51
48
  Write-Host "打开后侧边栏底部应出现「多窗口墙」按钮。"
52
- Write-Host "卸载:dsh plugin --profile $Profile remove @deepseek-ai/dsh-client-ui-multi-wall"
49
+ Write-Host "卸载:dsh plugin --profile $Profile remove dsh-multi-chat"
@@ -0,0 +1,26 @@
1
+ .row {
2
+ box-sizing: border-box;
3
+ display: flex;
4
+ align-items: center;
5
+ gap: 8px;
6
+ width: calc(100% + 8px);
7
+ height: 34px;
8
+ margin: 4px -4px;
9
+ padding: 6px 2px 6px 10px;
10
+ border: none;
11
+ border-radius: 12px;
12
+ background: none;
13
+ color: var(--dsw-alias-label-secondary);
14
+ cursor: pointer;
15
+ font: inherit;
16
+ overflow: hidden;
17
+ }
18
+ .row:hover {
19
+ background: var(--dsw-alias-interactive-bg-hover);
20
+ color: var(--dsw-alias-label-primary);
21
+ }
22
+ .label {
23
+ overflow: hidden;
24
+ text-overflow: ellipsis;
25
+ white-space: nowrap;
26
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * WallToggle: the sidebar-foot shortcut. Clicking it opens the wall view —
3
+ * the `conversation.view` ring switches to the 'multi-wall' entry, which the
4
+ * header renders as the "多窗口" tab. The click is a plain user-equivalent
5
+ * activation: it finds the header's view-ring tab for this plugin's label and
6
+ * clicks it, so the official view-ring state machine (the chat store's active
7
+ * view field) performs the switch. No store is declared: the ring decides
8
+ * what renders, so this row owns no state.
9
+ *
10
+ * Session-scoped by design: the view ring (and its header tabs) only renders
11
+ * with an active session, so the shortcut is inert on the empty-hero screen —
12
+ * the user first opens or creates a session (the official flow), after which
13
+ * the tab is present and the click lands.
14
+ */
15
+ import { IconFullscreenOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
16
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
17
+ import css from './WallToggle.module.css'
18
+
19
+ /** Composed props: sidebar column state + locale. */
20
+ export type WallToggleProps =
21
+ & PropsRuntime<'sidebar.footer.action'>
22
+ & PropsLocale<'multiWall'>
23
+
24
+ /**
25
+ * Render the wall shortcut row (icon; label only in the wide column).
26
+ * @param props - composed slot props.
27
+ * @returns the shortcut row.
28
+ */
29
+ export function WallToggle({ wide, t }: WallToggleProps) {
30
+ return (
31
+ <button
32
+ type="button"
33
+ className={css.row}
34
+ aria-label={t('toggle.aria')}
35
+ title={t('toggle')}
36
+ onClick={() => {
37
+ // The official view ring renders the active entry through
38
+ // `only: <active id>`; the only sanctioned way to move it is the
39
+ // header tab's click handler (actions.setView). Trigger that same
40
+ // element instead of reaching into the chat store from the root
41
+ // scope. No tab (no active session) is a no-op.
42
+ const label = t('view.multiWall')
43
+ const tab = Array.from(document.querySelectorAll<HTMLButtonElement>('[role="tab"]'))
44
+ .find(el => el.textContent?.trim() === label)
45
+ tab?.click()
46
+ }}
47
+ >
48
+ <IconFullscreenOutline16 size={wide ? 16 : 18} />
49
+ {wide && <span className={css.label}>{t('toggle')}</span>}
50
+ </button>
51
+ )
52
+ }
@@ -0,0 +1,190 @@
1
+ /* Wall view: toolbar over a horizontally-filled pane grid. All colors ride
2
+ the official --dsw-alias-* token sheet; controls are official primitives
3
+ (Button/Input/Menu/StateDot), so the surface matches the app chrome. */
4
+
5
+ /* When the wall view is active, hide the conversation composer seat (the
6
+ input bar and its stats band) so the wall owns the full column height.
7
+ The seat is the official layout's bottom slot ([data-composer-seat] inside
8
+ [data-conversation-scroll]); :has() scopes the rule to the wall being
9
+ present. Pure presentation — no official logic is touched. */
10
+ :global([data-conversation-scroll]:has([data-wall-view]) [data-composer-seat]) {
11
+ display: none;
12
+ }
13
+
14
+ .wall {
15
+ display: flex;
16
+ flex-direction: column;
17
+ flex: 1;
18
+ min-width: 0;
19
+ min-height: 0;
20
+ background: var(--dsw-alias-bg-base);
21
+ color: var(--dsw-alias-label-primary);
22
+ }
23
+
24
+ .toolbar {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 12px;
28
+ padding: 8px 14px;
29
+ border-bottom: 1px solid var(--dsw-alias-border-l2);
30
+ background: var(--dsw-alias-bg-layer-2);
31
+ flex: none;
32
+ flex-wrap: wrap;
33
+ }
34
+
35
+ .title {
36
+ font-size: 14px;
37
+ font-weight: 600;
38
+ }
39
+
40
+ /* Phone-access link bar: shown under the toolbar after fetching /multi/api/link. */
41
+ .linkBar {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 10px;
45
+ padding: 6px 14px;
46
+ border-bottom: 1px solid var(--dsw-alias-border-l2);
47
+ background: var(--dsw-alias-bg-layer-1);
48
+ flex: none;
49
+ flex-wrap: wrap;
50
+ }
51
+
52
+ .linkText {
53
+ font-size: 12px;
54
+ color: var(--dsw-alias-label-secondary);
55
+ flex: 1;
56
+ min-width: 160px;
57
+ overflow-wrap: anywhere;
58
+ }
59
+
60
+ .status {
61
+ font-size: 12px;
62
+ color: var(--dsw-alias-label-secondary);
63
+ flex: 1;
64
+ min-width: 120px;
65
+ }
66
+
67
+ .controls {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 8px;
71
+ flex-wrap: wrap;
72
+ }
73
+
74
+ .field {
75
+ display: inline-flex;
76
+ align-items: center;
77
+ gap: 6px;
78
+ font-size: 12px;
79
+ color: var(--dsw-alias-label-secondary);
80
+ }
81
+
82
+ /* The official Input primitive renders a wrapper span; keep the number
83
+ steppers compact inside the toolbar field. */
84
+ .field > span {
85
+ width: 76px;
86
+ }
87
+
88
+ /* Pane grid: default fills the row with equal columns, wraps only when the
89
+ row is full — no single-column vertical stacking by default. */
90
+ .grid {
91
+ flex: 1;
92
+ overflow: auto;
93
+ padding: 8px;
94
+ display: grid;
95
+ gap: 8px;
96
+ grid-auto-rows: minmax(280px, 1fr);
97
+ align-content: start;
98
+ }
99
+ .grid[data-cols='auto'] { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
100
+ .grid[data-cols='1'] { grid-template-columns: 1fr; }
101
+ .grid[data-cols='2'] { grid-template-columns: repeat(2, 1fr); }
102
+ .grid[data-cols='3'] { grid-template-columns: repeat(3, 1fr); }
103
+ .grid[data-cols='4'] { grid-template-columns: repeat(4, 1fr); }
104
+ .grid[data-cols='6'] { grid-template-columns: repeat(6, 1fr); }
105
+
106
+ .pane {
107
+ display: flex;
108
+ flex-direction: column;
109
+ border: 1px solid var(--dsw-alias-border-l2);
110
+ border-radius: 8px;
111
+ overflow: hidden;
112
+ min-width: 0;
113
+ min-height: 0;
114
+ background: var(--dsw-alias-bg-layer-1);
115
+ }
116
+ .pane.zoomed {
117
+ grid-column: 1 / -1;
118
+ grid-row: 1 / -1;
119
+ }
120
+
121
+ .paneHead {
122
+ display: flex;
123
+ align-items: center;
124
+ gap: 8px;
125
+ padding: 4px 8px;
126
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
127
+ background: var(--dsw-alias-bg-layer-2);
128
+ flex: none;
129
+ }
130
+
131
+ .dot {
132
+ flex: none;
133
+ }
134
+
135
+ .paneTitle {
136
+ font-size: 12px;
137
+ overflow: hidden;
138
+ text-overflow: ellipsis;
139
+ white-space: nowrap;
140
+ }
141
+
142
+ .paneActions {
143
+ margin-left: auto;
144
+ display: flex;
145
+ gap: 2px;
146
+ flex: none;
147
+ }
148
+
149
+ .action {
150
+ border: none;
151
+ background: none;
152
+ color: var(--dsw-alias-label-secondary);
153
+ cursor: pointer;
154
+ padding: 2px 6px;
155
+ border-radius: 4px;
156
+ line-height: 1;
157
+ white-space: nowrap;
158
+ }
159
+ .action:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
160
+ .action.danger:hover { color: var(--dsw-static-amber-600); }
161
+ .action.danger.confirm {
162
+ background: var(--dsw-static-amber-500);
163
+ color: var(--dsw-static-neutral-00);
164
+ font-size: 11px;
165
+ padding: 2px 8px;
166
+ }
167
+ .action.danger.confirm:hover { background: var(--dsw-static-amber-600); color: var(--dsw-static-neutral-00); }
168
+
169
+ .paneBody {
170
+ flex: 1;
171
+ min-height: 0;
172
+ position: relative;
173
+ }
174
+ .paneBody iframe {
175
+ width: 100%;
176
+ height: 100%;
177
+ border: none;
178
+ display: block;
179
+ }
180
+
181
+ .empty {
182
+ grid-column: 1 / -1;
183
+ display: flex;
184
+ flex-direction: column;
185
+ align-items: center;
186
+ justify-content: center;
187
+ gap: 6px;
188
+ color: var(--dsw-alias-label-secondary);
189
+ }
190
+ .empty .hint { font-size: 12px; }