@yadsh/dsh-draft-sessions 0.2.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/LICENSE +22 -0
- package/README.md +207 -0
- package/README.ru.md +192 -0
- package/README.zh-CN.md +207 -0
- package/SPEC.md +102 -0
- package/compatibility.json +10 -0
- package/cordis.patch.yml +4 -0
- package/docs/images/draft-sessions-actions.png +0 -0
- package/docs/images/draft-sessions-hero.png +0 -0
- package/docs/images/draft-sessions-stock-fallback.jpg +0 -0
- package/lib/client.js +6197 -0
- package/lib/constants-vAKitj5i.js +11 -0
- package/lib/index.js +292 -0
- package/lib/remote.js +71 -0
- package/lib/schema-BkmWuQBa.js +33 -0
- package/lib/shared/types.js +13 -0
- package/lib/types/client/composer.d.ts +46 -0
- package/lib/types/client/draft-sidebar-view.d.ts +22 -0
- package/lib/types/client/index.d.ts +32 -0
- package/lib/types/client/lifecycle.d.ts +69 -0
- package/lib/types/client/shortcut.d.ts +40 -0
- package/lib/types/client/sidebar.d.ts +40 -0
- package/lib/types/client/workspace-contribution.d.ts +25 -0
- package/lib/types/host/errors.d.ts +7 -0
- package/lib/types/host/schema.d.ts +40 -0
- package/lib/types/host/store.d.ts +28 -0
- package/lib/types/index.d.ts +33 -0
- package/lib/types/remote.d.ts +20 -0
- package/lib/types/shared/constants.d.ts +9 -0
- package/lib/types/shared/types.d.ts +70 -0
- package/package.json +140 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-draft-sessions contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# dsh-draft-sessions
|
|
2
|
+
|
|
3
|
+
[](https://github.com/xarleyn/dsh-plugins/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@yadsh/dsh-draft-sessions)
|
|
5
|
+
[](https://www.npmjs.com/package/@yadsh/dsh-draft-sessions)
|
|
6
|
+
[](package.json)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
Persistent, unsent future conversations for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
10
|
+
|
|
11
|
+
`dsh-draft-sessions` is building the Cursor-like workflow where you can prepare several independent tasks, leave them unsent, and return to each task later without starting an agent.
|
|
12
|
+
|
|
13
|
+
[Русский](README.ru.md) · [简体中文](README.zh-CN.md) · [Specification](SPEC.md) · [Architecture](docs/architecture.md) · [Roadmap](ROADMAP.md)
|
|
14
|
+
|
|
15
|
+
## See it in action
|
|
16
|
+
|
|
17
|
+
### With `@michengai/dsh-automation`
|
|
18
|
+
|
|
19
|
+
Automation provides the optional cooperative tab host. When it is installed and active, Draft Sessions detects `__dshNativeTabs@1` and inserts `Drafts` between `Tasks` and `Scheduled`. There is no hard dependency on Automation and no load-order requirement.
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="docs/images/draft-sessions-hero.png" alt="Three independent draft sessions in a cooperative DeepSeek Harness sidebar tab" />
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p align="center"><em>With Automation installed, unsent tasks live in their own Drafts tab while Tasks and Scheduled keep their existing views.</em></p>
|
|
26
|
+
|
|
27
|
+
### On stock DeepSeek Harness
|
|
28
|
+
|
|
29
|
+
Without Automation or another compatible tab host, the standard workspace and session browser stays unchanged. Draft Sessions adds a footer action instead; clicking it opens the same draft list in a popover.
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="docs/images/draft-sessions-stock-fallback.jpg" alt="Draft Sessions footer action and popover on stock DeepSeek Harness" />
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p align="center"><em>The fallback uses the public sidebar footer slot and does not replace the stock workspace browser.</em></p>
|
|
36
|
+
|
|
37
|
+
### Draft actions
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="docs/images/draft-sessions-actions.png" width="360" alt="Draft session actions rendered above the sidebar without clipping or extra scrolling" />
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center"><em>Create a distinct draft with <code>+</code>, then rename, duplicate, or delete it from the row menu.</em></p>
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
Install the published npm package by name:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
dsh plugin --profile web add @yadsh/dsh-draft-sessions
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or build and install the package from a local monorepo checkout:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm --filter @yadsh/dsh-draft-sessions build
|
|
57
|
+
dsh plugin --profile web add ./plugins/dsh-draft-sessions
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The published npm package is recommended when you do not need to modify the source.
|
|
61
|
+
|
|
62
|
+
To remove the plugin:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
dsh plugin --profile web remove @yadsh/dsh-draft-sessions
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## The intended experience
|
|
69
|
+
|
|
70
|
+
The original goal was to reproduce Cursor's inline draft experience: unsent tasks and ordinary sessions living together in one workspace tree.
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
my-project
|
|
74
|
+
├─ ● Fix auth middleware
|
|
75
|
+
├─ ◌ Add Grafana dashboards Draft
|
|
76
|
+
├─ ◌ Refactor docker entrypoint Draft
|
|
77
|
+
└─ ● Implement notifications
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
That exact layout could not be reproduced through DSH's current public sidebar APIs without replacing the stock workspace browser. Draft Sessions keeps the important behavior—independent unsent tasks, exact text restoration, and conversion on the first accepted prompt—but exposes drafts in a cooperative `Drafts` tab when one is available, or through the stock sidebar footer popover otherwise.
|
|
81
|
+
|
|
82
|
+
Each draft owns a real blank DSH Session, but its unsent text is stored separately on the Host. If that blank Session disappears after a restart, a new shell can be created and rebound without losing the task.
|
|
83
|
+
|
|
84
|
+
```mermaid
|
|
85
|
+
flowchart LR
|
|
86
|
+
UI["Sidebar draft row"] --> Composer["Standard DSH composer"]
|
|
87
|
+
Composer --> Draft["DraftRecord — text authority"]
|
|
88
|
+
Draft --> Session["Real blank DSH Session"]
|
|
89
|
+
Session -->|"first prompt accepted"| Normal["Normal DSH Session"]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## What works now
|
|
93
|
+
|
|
94
|
+
- Host-backed JSON persistence under `$DSH_HOME/storages/dsh-draft-sessions/drafts.json`.
|
|
95
|
+
- Strict typed `draftSessions.list/create/update/delete/rebind` Remote methods.
|
|
96
|
+
- Independent workspace ordering and a configurable per-workspace limit.
|
|
97
|
+
- Optimistic revisions that reject stale browser writes.
|
|
98
|
+
- Atomic same-directory writes and strict durable-file validation.
|
|
99
|
+
- Distinct blank Session creation with the id persisted only after success.
|
|
100
|
+
- Missing Session detection and recovery rebinding without changing draft text.
|
|
101
|
+
- Accepted-Send observation with finalization only after `blank: false`.
|
|
102
|
+
- Rejected Send and blank slash-command preservation.
|
|
103
|
+
- Exact composer restore through the official per-session InputHub facade.
|
|
104
|
+
- Debounced optimistic autosave with a mandatory pre-switch flush.
|
|
105
|
+
- Draft creation from the Drafts `+` action or `Ctrl/Cmd + Shift + N`; both flush the active draft before opening a distinct one.
|
|
106
|
+
- A cooperative `Drafts` tab when the active sidebar host exposes `__dshNativeTabs@1`.
|
|
107
|
+
- A stock `sidebar.footer.action` trigger and popover when the tab protocol is absent.
|
|
108
|
+
- Portaled row menus, inline rename, duplicate, confirmed delete, keyboard navigation, and bounded drag reorder.
|
|
109
|
+
- Safe active-draft deletion with a final autosave flush and recovery after a rejected delete.
|
|
110
|
+
- Optional native-tab session filtering that hides draft shells without changing ordinary Sessions.
|
|
111
|
+
- No registration in the single-slot `sidebar.workspaces`; stock UI, Archive Manager, and other browser owners keep full control.
|
|
112
|
+
- Unit and DOM coverage for persistence, concurrency, lifecycle, composer, and sidebar behavior.
|
|
113
|
+
|
|
114
|
+
The current implementation deliberately does not send prompts, modify ordinary Session history, or delete blank Sessions.
|
|
115
|
+
|
|
116
|
+
## Requirements
|
|
117
|
+
|
|
118
|
+
- Node.js `^22.19.0` or `>=24.0.0`
|
|
119
|
+
- pnpm 10.4.1 for development
|
|
120
|
+
- DeepSeek Harness `>=0.1.1-rc.2 <0.2.0` with the public `sidebar.footer.action` list slot
|
|
121
|
+
|
|
122
|
+
The published rc.2 client is supported without patches. Sidebar tab hosts are detected through the optional versioned `__dshNativeTabs@1` cooperation protocol; the plugin falls back to the stock footer action instead of replacing the workspace browser.
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
From the monorepo root:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm install --frozen-lockfile
|
|
130
|
+
pnpm --filter @yadsh/dsh-draft-sessions check
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Build and link the checkout into a Web profile:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pnpm --filter @yadsh/dsh-draft-sessions build
|
|
137
|
+
dsh plugin --profile web add ./plugins/dsh-draft-sessions
|
|
138
|
+
dsh --profile web --dump-config
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Releases
|
|
142
|
+
|
|
143
|
+
This package uses independent Nx Version Plans from the monorepo. Add a plan with `pnpm release:plan`; maintainers publish verified tarballs through the shared [release workflow](../../docs/RELEASING.md).
|
|
144
|
+
|
|
145
|
+
## Configuration
|
|
146
|
+
|
|
147
|
+
The bundle inserts the `dsh-draft-sessions` Cordis row. Override it from the profile patch when needed:
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
- id: dsh-draft-sessions
|
|
151
|
+
config:
|
|
152
|
+
# Blank uses $DSH_HOME/storages/dsh-draft-sessions/drafts.json
|
|
153
|
+
storagePath: ""
|
|
154
|
+
maxDraftsPerWorkspace: 50
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Current API
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
await ctx.remote.draftSessions.list({ workspaceId });
|
|
161
|
+
|
|
162
|
+
await ctx.draftSessionLifecycle.create({
|
|
163
|
+
workspaceId,
|
|
164
|
+
text: "",
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await ctx.draftSessionLifecycle.ensureShell(draft);
|
|
168
|
+
|
|
169
|
+
await ctx.draftComposerBridge.open(draft);
|
|
170
|
+
await ctx.draftComposerBridge.flush();
|
|
171
|
+
|
|
172
|
+
await ctx.draftShortcutController.create(workspaceId);
|
|
173
|
+
|
|
174
|
+
await ctx.remote.draftSessions.update({
|
|
175
|
+
id,
|
|
176
|
+
expectedRevision: 4,
|
|
177
|
+
text: "Add OTEL export",
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
await ctx.remote.draftSessions.rebind({
|
|
181
|
+
id,
|
|
182
|
+
expectedRevision: 5,
|
|
183
|
+
sessionId: replacementSessionId,
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The lifecycle service owns blank Session creation and recovery. The lower-level Remote methods remain available for storage operations; all mutations return the next `revision`, and a stale `expectedRevision` is rejected instead of silently overwriting another browser's edit.
|
|
188
|
+
|
|
189
|
+
## Design boundaries
|
|
190
|
+
|
|
191
|
+
- Draft text is authoritative in `DraftStore`; a blank Session is only an execution shell.
|
|
192
|
+
- Creating a draft must never make a model request.
|
|
193
|
+
- The first accepted prompt, not the Send button click, is the conversion boundary.
|
|
194
|
+
- Ordinary DSH Sessions remain owned entirely by DSH.
|
|
195
|
+
- Attachments are out of scope for v1; text and textual `@file` references come first.
|
|
196
|
+
- Draft rows compose beside the single workspace-browser occupant; the plugin never disables or embeds `ui-workspace`.
|
|
197
|
+
- Backing blank Sessions are excluded only from the workspace-browser slot, so the standard composer still receives the real current Session.
|
|
198
|
+
|
|
199
|
+
See [SPEC.md](SPEC.md) for acceptance criteria and [docs/architecture.md](docs/architecture.md) for the lifecycle.
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
Issues and focused pull requests are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) and run the package check before submitting a change.
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
[MIT](LICENSE). This is an independent community project and is not affiliated with or endorsed by DeepSeek.
|
package/README.ru.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# dsh-draft-sessions
|
|
2
|
+
|
|
3
|
+
[](https://github.com/xarleyn/dsh-plugins/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@yadsh/dsh-draft-sessions)
|
|
5
|
+
[](https://www.npmjs.com/package/@yadsh/dsh-draft-sessions)
|
|
6
|
+
[](package.json)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
Постоянные неотправленные будущие диалоги для [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
10
|
+
|
|
11
|
+
Цель плагина — дать привычный по Cursor UX: можно подготовить несколько независимых задач, уйти из них без отправки и позже продолжить каждую с сохранённым текстом.
|
|
12
|
+
|
|
13
|
+
[English](README.md) · [简体中文](README.zh-CN.md) · [Спецификация](SPEC.md) · [Архитектура](docs/architecture.md) · [План](ROADMAP.md)
|
|
14
|
+
|
|
15
|
+
## Как это выглядит
|
|
16
|
+
|
|
17
|
+
### С `@michengai/dsh-automation`
|
|
18
|
+
|
|
19
|
+
Automation предоставляет опциональный host для совместных вкладок. Когда плагин установлен и активен, Draft Sessions обнаруживает `__dshNativeTabs@1` и добавляет `Drafts` между `Tasks` и `Scheduled`. Жёсткой зависимости от Automation и требований к порядку загрузки нет.
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="docs/images/draft-sessions-hero.png" alt="Три независимых черновика в отдельной вкладке DeepSeek Harness" />
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
### На штатном DeepSeek Harness
|
|
26
|
+
|
|
27
|
+
Без Automation или другого совместимого tab host штатный browser workspaces и sessions остаётся без изменений. Draft Sessions добавляет кнопку в footer; по нажатию тот же список черновиков открывается в popover.
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="docs/images/draft-sessions-stock-fallback.jpg" alt="Кнопка Draft Sessions и popover на штатном DeepSeek Harness" />
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
Меню строки работает одинаково в обоих режимах и отображается поверх sidebar без дополнительного скролла:
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<img src="docs/images/draft-sessions-actions.png" width="360" alt="Действия с черновиком поверх sidebar без обрезки и дополнительного скролла" />
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
## Установка
|
|
40
|
+
|
|
41
|
+
Установка опубликованного npm-пакета по имени:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
dsh plugin --profile web add @yadsh/dsh-draft-sessions
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Или сборка и установка пакета из локального checkout монорепозитория:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm --filter @yadsh/dsh-draft-sessions build
|
|
51
|
+
dsh plugin --profile web add ./plugins/dsh-draft-sessions
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Если изменять исходный код не требуется, рекомендуется опубликованный npm-пакет.
|
|
55
|
+
|
|
56
|
+
Удаление плагина:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
dsh plugin --profile web remove @yadsh/dsh-draft-sessions
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Задуманный сценарий
|
|
63
|
+
|
|
64
|
+
Изначальная цель — полностью повторить inline-черновики Cursor, где неотправленные задачи и обычные sessions находятся в одном дереве workspace.
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
my-project
|
|
68
|
+
├─ ● Fix auth middleware
|
|
69
|
+
├─ ◌ Add Grafana dashboards Draft
|
|
70
|
+
├─ ◌ Refactor docker entrypoint Draft
|
|
71
|
+
└─ ● Implement notifications
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Точно повторить эту компоновку через текущие публичные sidebar API DSH не удалось без замены штатного workspace browser. Поэтому Draft Sessions сохраняет главное поведение — независимые неотправленные задачи, точное восстановление текста и превращение в обычную Session после первого принятого prompt, — но показывает черновики в совместной вкладке `Drafts`, если она доступна, или в popover штатного sidebar footer.
|
|
75
|
+
|
|
76
|
+
Каждый draft связан с реальной blank Session DSH, а его неотправленный текст отдельно хранится на Host. Если blank Session исчезнет после перезапуска, плагин создаст новую оболочку и привяжет её к черновику без потери текста.
|
|
77
|
+
|
|
78
|
+
## Что уже реализовано
|
|
79
|
+
|
|
80
|
+
- Host-backed JSON-хранилище в `$DSH_HOME/storages/dsh-draft-sessions/drafts.json`.
|
|
81
|
+
- Строгие Remote-методы `draftSessions.list/create/update/delete/rebind`.
|
|
82
|
+
- Независимый порядок в workspace и настраиваемый лимит.
|
|
83
|
+
- Optimistic revision: устаревшая запись из второго браузера не затирает свежую.
|
|
84
|
+
- Атомарная запись файла и строгая проверка данных при загрузке.
|
|
85
|
+
- Создание отдельной blank Session с сохранением id только после успеха.
|
|
86
|
+
- Обнаружение исчезнувшей Session и recovery через замену без потери текста.
|
|
87
|
+
- Финализация только после принятого Send и подтверждённого `blank: false`.
|
|
88
|
+
- Сохранение draft при отклонённом Send и blank slash-командах.
|
|
89
|
+
- Точное восстановление текста через официальный per-session InputHub.
|
|
90
|
+
- Debounced optimistic autosave с обязательным flush перед переключением.
|
|
91
|
+
- Создание через `+` в секции Drafts или `Ctrl/Cmd + Shift + N`; оба действия сначала сохраняют активный draft, затем открывают отдельный новый.
|
|
92
|
+
- Отдельная вкладка `Drafts`, когда активный sidebar host предоставляет протокол `__dshNativeTabs@1`.
|
|
93
|
+
- Штатная кнопка и popover через `sidebar.footer.action`, когда протокола вкладок нет.
|
|
94
|
+
- Вынесенные поверх панелей row-меню, inline rename, duplicate, подтверждаемое удаление, клавиатурная навигация и ограниченный drag reorder.
|
|
95
|
+
- Безопасное удаление активного draft с финальным autosave flush и восстановлением после отказа.
|
|
96
|
+
- Опциональная фильтрация backing shell через протокол вкладок без изменения обычных Sessions.
|
|
97
|
+
- Плагин не регистрируется в single-slot `sidebar.workspaces`; штатный browser, Archive Manager и другие владельцы сохраняют полный контроль.
|
|
98
|
+
- Unit- и DOM-тесты persistence, concurrency, lifecycle, composer и sidebar.
|
|
99
|
+
|
|
100
|
+
Текущий код не отправляет prompt, не изменяет историю обычных Sessions и не удаляет blank Sessions.
|
|
101
|
+
|
|
102
|
+
## Требования
|
|
103
|
+
|
|
104
|
+
- Node.js `^22.19.0` или `>=24.0.0`
|
|
105
|
+
- pnpm 10.4.1 для разработки
|
|
106
|
+
- DeepSeek Harness `>=0.1.1-rc.2 <0.2.0` с публичным list-slot `sidebar.footer.action`
|
|
107
|
+
|
|
108
|
+
Опубликованный клиент rc.2 поддерживается без патчей. Sidebar host с вкладками определяется через опциональный версионированный протокол `__dshNativeTabs@1`; если его нет, плагин использует штатный footer action и не заменяет workspace browser.
|
|
109
|
+
|
|
110
|
+
## Локальная разработка
|
|
111
|
+
|
|
112
|
+
Из корня монорепозитория:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pnpm install --frozen-lockfile
|
|
116
|
+
pnpm --filter @yadsh/dsh-draft-sessions check
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Сборка и подключение checkout к Web profile:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pnpm --filter @yadsh/dsh-draft-sessions build
|
|
123
|
+
dsh plugin --profile web add ./plugins/dsh-draft-sessions
|
|
124
|
+
dsh --profile web --dump-config
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Релизы
|
|
128
|
+
|
|
129
|
+
Пакет использует независимые Nx Version Plans монорепозитория. План добавляется командой `pnpm release:plan`; maintainers публикуют проверенные tarball через общий [release workflow](../../docs/RELEASING.md).
|
|
130
|
+
|
|
131
|
+
## Настройки
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
- id: dsh-draft-sessions
|
|
135
|
+
config:
|
|
136
|
+
storagePath: ""
|
|
137
|
+
maxDraftsPerWorkspace: 50
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Пустой `storagePath` означает стандартный файл внутри `$DSH_HOME`.
|
|
141
|
+
|
|
142
|
+
## Текущий API
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
await ctx.remote.draftSessions.list({ workspaceId });
|
|
146
|
+
|
|
147
|
+
await ctx.draftSessionLifecycle.create({
|
|
148
|
+
workspaceId,
|
|
149
|
+
text: "",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await ctx.draftSessionLifecycle.ensureShell(draft);
|
|
153
|
+
|
|
154
|
+
await ctx.draftComposerBridge.open(draft);
|
|
155
|
+
await ctx.draftComposerBridge.flush();
|
|
156
|
+
|
|
157
|
+
await ctx.draftShortcutController.create(workspaceId);
|
|
158
|
+
|
|
159
|
+
await ctx.remote.draftSessions.update({
|
|
160
|
+
id,
|
|
161
|
+
expectedRevision: 4,
|
|
162
|
+
text: "Add OTEL export",
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await ctx.remote.draftSessions.rebind({
|
|
166
|
+
id,
|
|
167
|
+
expectedRevision: 5,
|
|
168
|
+
sessionId: replacementSessionId,
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Lifecycle service отвечает за создание и восстановление оболочки blank Session. Низкоуровневые Remote-методы остаются доступны для операций с хранилищем; каждая mutation возвращает следующую `revision`, а устаревшая `expectedRevision` отклоняется вместо тихого перезаписывания правок из другого browser.
|
|
173
|
+
|
|
174
|
+
## Главные границы дизайна
|
|
175
|
+
|
|
176
|
+
- Источник истины для неотправленного текста — `DraftStore`.
|
|
177
|
+
- Реальная blank Session служит execution shell для model/preset/permissions UI.
|
|
178
|
+
- Создание draft никогда не запускает модель.
|
|
179
|
+
- Draft превращается в обычную Session только после принятого первого prompt.
|
|
180
|
+
- Attachments отложены до v2.
|
|
181
|
+
- Draft-строки композируются рядом с single workspace-browser occupant; плагин не отключает и не встраивает `ui-workspace`.
|
|
182
|
+
- Backing blank Sessions исключаются только из slot workspace browser, поэтому стандартный composer по-прежнему получает настоящую текущую Session.
|
|
183
|
+
|
|
184
|
+
Полные критерии находятся в [SPEC.md](SPEC.md), последовательность следующих этапов — в [ROADMAP.md](ROADMAP.md).
|
|
185
|
+
|
|
186
|
+
## Участие в разработке
|
|
187
|
+
|
|
188
|
+
Issues и небольшие сфокусированные pull requests приветствуются. Перед отправкой изменений прочитайте [CONTRIBUTING.md](CONTRIBUTING.md) и запустите package check.
|
|
189
|
+
|
|
190
|
+
## Лицензия
|
|
191
|
+
|
|
192
|
+
[MIT](LICENSE). Это независимый community-проект, не связанный с DeepSeek и не одобренный компанией.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# dsh-draft-sessions
|
|
2
|
+
|
|
3
|
+
[](https://github.com/xarleyn/dsh-plugins/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@yadsh/dsh-draft-sessions)
|
|
5
|
+
[](https://www.npmjs.com/package/@yadsh/dsh-draft-sessions)
|
|
6
|
+
[](package.json)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 提供可持久保存、尚未发送的未来对话。
|
|
10
|
+
|
|
11
|
+
`dsh-draft-sessions` 致力于实现类似 Cursor 的工作流:你可以准备多个彼此独立的任务,暂时离开而不发送,并在之后回来继续编辑,而不会启动 agent。
|
|
12
|
+
|
|
13
|
+
[English](README.md) · [Русский](README.ru.md) · [规范](SPEC.md) · [架构](docs/architecture.md) · [路线图](ROADMAP.md)
|
|
14
|
+
|
|
15
|
+
## 效果展示
|
|
16
|
+
|
|
17
|
+
### 搭配 `@michengai/dsh-automation`
|
|
18
|
+
|
|
19
|
+
Automation 可作为可选的协作式标签页宿主。安装并启用后,Draft Sessions 会检测 `__dshNativeTabs@1`,并在 `Tasks` 与 `Scheduled` 之间插入 `Drafts`。Draft Sessions 不强制依赖 Automation,也不要求特定的加载顺序。
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="docs/images/draft-sessions-hero.png" alt="DeepSeek Harness 协作式侧边栏标签页中的三个独立草稿会话" />
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p align="center"><em>安装 Automation 后,未发送的任务会显示在独立的 Drafts 标签页中,Tasks 和 Scheduled 保持各自原有的视图。</em></p>
|
|
26
|
+
|
|
27
|
+
### 原生 DeepSeek Harness
|
|
28
|
+
|
|
29
|
+
如果没有 Automation 或其他兼容的标签页宿主,标准 workspace 和 session 浏览器不会改变。Draft Sessions 会在底部添加一个操作入口;点击后,同一个草稿列表会在浮层中打开。
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="docs/images/draft-sessions-stock-fallback.jpg" alt="原生 DeepSeek Harness 中的 Draft Sessions 底部入口和浮层" />
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p align="center"><em>该回退模式使用公开的侧边栏底部插槽,不会替换原生 workspace 浏览器。</em></p>
|
|
36
|
+
|
|
37
|
+
### 草稿操作
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="docs/images/draft-sessions-actions.png" width="360" alt="显示在侧边栏上方且不会被裁剪或引入额外滚动的草稿会话操作" />
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center"><em>使用 <code>+</code> 创建独立草稿,然后通过行菜单重命名、复制或删除。</em></p>
|
|
44
|
+
|
|
45
|
+
## 安装
|
|
46
|
+
|
|
47
|
+
按名称安装已发布的 npm 包:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
dsh plugin --profile web add @yadsh/dsh-draft-sessions
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
或者从本地 monorepo checkout 构建并安装:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm --filter @yadsh/dsh-draft-sessions build
|
|
57
|
+
dsh plugin --profile web add ./plugins/dsh-draft-sessions
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
如果不需要修改源码,建议使用已发布的 npm 包。
|
|
61
|
+
|
|
62
|
+
卸载插件:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
dsh plugin --profile web remove @yadsh/dsh-draft-sessions
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 预期体验
|
|
69
|
+
|
|
70
|
+
最初的目标是完整复现 Cursor 的行内草稿体验:未发送的任务与普通 session 一起显示在同一个 workspace 树中。
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
my-project
|
|
74
|
+
├─ ● Fix auth middleware
|
|
75
|
+
├─ ◌ Add Grafana dashboards Draft
|
|
76
|
+
├─ ◌ Refactor docker entrypoint Draft
|
|
77
|
+
└─ ● Implement notifications
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
通过 DSH 当前公开的侧边栏 API,无法在不替换原生 workspace 浏览器的前提下完全复现这一布局。Draft Sessions 保留了最重要的行为——彼此独立的未发送任务、准确恢复文本,以及在第一个 prompt 被接受后转换为普通 Session——但会在可用时把草稿显示在协作式 `Drafts` 标签页中,否则通过原生侧边栏底部浮层显示。
|
|
81
|
+
|
|
82
|
+
每个草稿都拥有一个真实的空白 DSH Session,但未发送的文本会单独存储在 Host 上。如果该空白 Session 在重启后消失,插件可以创建新的外壳并重新绑定,而不会丢失任务文本。
|
|
83
|
+
|
|
84
|
+
```mermaid
|
|
85
|
+
flowchart LR
|
|
86
|
+
UI["侧边栏草稿行"] --> Composer["标准 DSH 编辑器"]
|
|
87
|
+
Composer --> Draft["DraftRecord — 文本权威来源"]
|
|
88
|
+
Draft --> Session["真实的空白 DSH Session"]
|
|
89
|
+
Session -->|"第一个 prompt 被接受"| Normal["普通 DSH Session"]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 当前功能
|
|
93
|
+
|
|
94
|
+
- 在 `$DSH_HOME/storages/dsh-draft-sessions/drafts.json` 中使用 Host 端 JSON 持久化。
|
|
95
|
+
- 严格类型化的 `draftSessions.list/create/update/delete/rebind` Remote 方法。
|
|
96
|
+
- 各 workspace 独立排序,并支持配置每个 workspace 的数量上限。
|
|
97
|
+
- 通过乐观 revision 拒绝来自其他浏览器的过期写入。
|
|
98
|
+
- 同目录原子写入,并严格校验持久化文件。
|
|
99
|
+
- 创建彼此独立的空白 Session,且仅在成功后保存其 id。
|
|
100
|
+
- 检测丢失的 Session,并在不改变草稿文本的情况下恢复绑定。
|
|
101
|
+
- 观察已接受的 Send,且仅在确认 `blank: false` 后完成草稿转换。
|
|
102
|
+
- Send 被拒绝或执行空白 slash 命令时保留草稿。
|
|
103
|
+
- 通过官方的 per-session InputHub facade 精确恢复编辑器内容。
|
|
104
|
+
- 带防抖的乐观自动保存,切换前强制 flush。
|
|
105
|
+
- 可通过 Drafts 中的 `+` 或 `Ctrl/Cmd + Shift + N` 创建草稿;两者都会先 flush 当前草稿,再打开一个新的独立草稿。
|
|
106
|
+
- 当活动侧边栏宿主公开 `__dshNativeTabs@1` 时,提供协作式 `Drafts` 标签页。
|
|
107
|
+
- 如果没有标签页协议,则提供原生 `sidebar.footer.action` 入口和浮层。
|
|
108
|
+
- 行菜单通过 portal 显示,并支持行内重命名、复制、确认删除、键盘导航和受限拖拽排序。
|
|
109
|
+
- 安全删除活动草稿:先完成最终自动保存,并在删除被拒绝时恢复。
|
|
110
|
+
- 可选的原生标签页 session 过滤,可隐藏草稿外壳而不改变普通 Session。
|
|
111
|
+
- 不注册到单插槽 `sidebar.workspaces`;原生 UI、Archive Manager 和其他浏览器所有者仍保留完整控制权。
|
|
112
|
+
- persistence、concurrency、lifecycle、composer 和 sidebar 均有单元测试与 DOM 测试覆盖。
|
|
113
|
+
|
|
114
|
+
当前实现不会主动发送 prompt、修改普通 Session 历史记录或删除空白 Session。
|
|
115
|
+
|
|
116
|
+
## 要求
|
|
117
|
+
|
|
118
|
+
- Node.js `^22.19.0` 或 `>=24.0.0`
|
|
119
|
+
- pnpm 10.4.1(开发环境)
|
|
120
|
+
- DeepSeek Harness `>=0.1.1-rc.2 <0.2.0`,并提供公开的 `sidebar.footer.action` 列表插槽
|
|
121
|
+
|
|
122
|
+
已发布的 rc.2 客户端无需补丁即可支持。侧边栏标签页宿主通过可选且带版本的 `__dshNativeTabs@1` 协作协议检测;如果没有该协议,插件会回退到原生底部入口,而不会替换 workspace 浏览器。
|
|
123
|
+
|
|
124
|
+
## 开发
|
|
125
|
+
|
|
126
|
+
在 monorepo 根目录运行:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm install --frozen-lockfile
|
|
130
|
+
pnpm --filter @yadsh/dsh-draft-sessions check
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
构建项目并把当前 checkout 链接到 Web profile:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pnpm --filter @yadsh/dsh-draft-sessions build
|
|
137
|
+
dsh plugin --profile web add ./plugins/dsh-draft-sessions
|
|
138
|
+
dsh --profile web --dump-config
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 发布
|
|
142
|
+
|
|
143
|
+
该包使用 monorepo 的独立 Nx Version Plans。通过 `pnpm release:plan` 添加计划;维护者通过共享的[发布流程](../../docs/RELEASING.md)发布已验证的 tarball。
|
|
144
|
+
|
|
145
|
+
## 配置
|
|
146
|
+
|
|
147
|
+
bundle 会插入 `dsh-draft-sessions` Cordis 配置行。需要时可在 profile patch 中覆盖:
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
- id: dsh-draft-sessions
|
|
151
|
+
config:
|
|
152
|
+
# 留空时使用 $DSH_HOME/storages/dsh-draft-sessions/drafts.json
|
|
153
|
+
storagePath: ""
|
|
154
|
+
maxDraftsPerWorkspace: 50
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 当前 API
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
await ctx.remote.draftSessions.list({ workspaceId });
|
|
161
|
+
|
|
162
|
+
await ctx.draftSessionLifecycle.create({
|
|
163
|
+
workspaceId,
|
|
164
|
+
text: "",
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await ctx.draftSessionLifecycle.ensureShell(draft);
|
|
168
|
+
|
|
169
|
+
await ctx.draftComposerBridge.open(draft);
|
|
170
|
+
await ctx.draftComposerBridge.flush();
|
|
171
|
+
|
|
172
|
+
await ctx.draftShortcutController.create(workspaceId);
|
|
173
|
+
|
|
174
|
+
await ctx.remote.draftSessions.update({
|
|
175
|
+
id,
|
|
176
|
+
expectedRevision: 4,
|
|
177
|
+
text: "Add OTEL export",
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
await ctx.remote.draftSessions.rebind({
|
|
181
|
+
id,
|
|
182
|
+
expectedRevision: 5,
|
|
183
|
+
sessionId: replacementSessionId,
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
lifecycle 服务负责创建与恢复空白 Session 外壳。底层 Remote 方法仍可用于存储操作;所有 mutation 都会返回新的 `revision`,过期的 `expectedRevision` 会被拒绝,而不会静默覆盖另一个浏览器中的编辑。
|
|
188
|
+
|
|
189
|
+
## 设计边界
|
|
190
|
+
|
|
191
|
+
- `DraftStore` 中的草稿文本是权威来源;空白 Session 只是执行外壳。
|
|
192
|
+
- 创建草稿绝不能发起模型请求。
|
|
193
|
+
- 转换边界是第一个 prompt 被接受,而不是点击 Send 按钮。
|
|
194
|
+
- 普通 DSH Session 完全由 DSH 管理。
|
|
195
|
+
- 附件不在 v1 范围内;优先支持文本和文本形式的 `@file` 引用。
|
|
196
|
+
- 草稿行与单一 workspace-browser 占用者组合显示;插件不会禁用或嵌入 `ui-workspace`。
|
|
197
|
+
- 支撑草稿的空白 Session 只会从 workspace-browser 插槽中排除,因此标准编辑器仍会收到真实的当前 Session。
|
|
198
|
+
|
|
199
|
+
验收标准见 [SPEC.md](SPEC.md),生命周期说明见 [docs/architecture.md](docs/architecture.md)。
|
|
200
|
+
|
|
201
|
+
## 贡献
|
|
202
|
+
|
|
203
|
+
欢迎提交 issue 和范围明确的 pull request。提交前请阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 并运行 package check。
|
|
204
|
+
|
|
205
|
+
## 许可证
|
|
206
|
+
|
|
207
|
+
[MIT](LICENSE)。这是一个独立的社区项目,与 DeepSeek 无隶属关系,也未获得其官方认可。
|