@goodandready/dsh-kanban 0.1.15 → 0.1.17
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/README.md +118 -400
- package/README.ru.md +173 -0
- package/README.zh.md +173 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,455 +1,173 @@
|
|
|
1
|
-
# dsh-kanban
|
|
1
|
+
# 📦 @goodandready/dsh-kanban
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<h3>Visual Kanban Board & Task Agent Session Dispatcher for DeepSeek Harness</h3>
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **Держать доску в порядке.** Счётчик ждущих ответа в шапке, сортировка по дате, отбор по автору, групповые действия над выбранными и остановка агента прямо с карточки.
|
|
14
|
-
- **Показывать задачу в чате.** В сессии, поднятой с доски, в шапке виден чип задачи с текущей колонкой.
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@goodandready/dsh-kanban"><img src="https://img.shields.io/npm/v/@goodandready/dsh-kanban.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-kanban.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
|
|
10
|
+
<a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
|
|
11
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
|
|
12
|
+
</p>
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://goodandready.app/"><img src="https://img.shields.io/badge/All_Author_Projects-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="All Author Projects"></a>
|
|
16
|
+
</p>
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
dsh plugin --profile web add file:/путь/к/dsh-kanban
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Перезапустите веб-интерфейс и обновите страницу с очисткой кэша.
|
|
29
|
-
|
|
30
|
-
Других плагинов не требует: клиент Gitea у канбана свой. Пока адрес инстанса не задан, доска работает, а импорт честно объясняет, чего не хватает.
|
|
31
|
-
|
|
32
|
-
## Настройка
|
|
33
|
-
|
|
34
|
-
**Настройки → Плагины**, карточка **Канбан**.
|
|
35
|
-
|
|
36
|
-
| Поле | Что задаёт |
|
|
37
|
-
|---|---|
|
|
38
|
-
| Адрес инстанса | `https://gitea.example.com`. Пусто — импорт недоступен. |
|
|
39
|
-
| Имя учётной записи | ИМЯ учётной записи DSH с токеном, по умолчанию `GITEA_TOKEN`. Сам токен сюда не вводить. |
|
|
40
|
-
| Корень проектов | Где лежат рабочие копии. Пусто — рабочая папка харнесса. |
|
|
41
|
-
| Шаблон первого сообщения | Текст, с которого начинается сессия. Пусто — встроенный. Подстановки: `{repo}`, `{issueNumber}`, `{title}`, `{body}`, `{issueUrl}`. |
|
|
42
|
-
| Пределы колонок | Предел числа карточек. Ноль — без предела. |
|
|
43
|
-
|
|
44
|
-
Токен в настройках **не хранится**: там только ИМЯ учётной записи, а сам секрет лежит в хранилище учётных данных DSH. Наружу значение не отдаётся никогда, включая сообщения об ошибках. Если у вас уже настроен `GITEA_TOKEN` для других плагинов, достаточно вписать адрес инстанса.
|
|
45
|
-
|
|
46
|
-
Все поля настроек скалярные. Это не упрощение, а требование: клиентский API настроек пишет только скаляры, и словарь или массив сделал бы карточку нередактируемой. Доски поэтому живут в хранилище задач, а не в настройках.
|
|
47
|
-
|
|
48
|
-
## Колонки
|
|
49
|
-
|
|
50
|
-
| Колонка | Признак входа |
|
|
51
|
-
|---|---|
|
|
52
|
-
| Backlog | issue есть, никто не взял |
|
|
53
|
-
| В работе | сессия поднята, в issue есть стартовый комментарий с планом и веткой |
|
|
54
|
-
| Ревью | PR снят с WIP, ревьюер даёт PASS/FAIL |
|
|
55
|
-
| Deploy | PR влит в `main`, ждём согласованный deploy и production-проверку |
|
|
56
|
-
| Cleanup | ветка в Gitea, worktree и локальная ветка ещё не удалены |
|
|
57
|
-
| Done | issue закрыт **и** cleanup записан в итоговом комментарии |
|
|
58
|
-
|
|
59
|
-
Колонка `cleanup` не лишняя: по воркфлоу задача не завершена, пока cleanup не сделан и не записан. Доска, отправляющая карточку в `done` по merge, врёт ровно там, где копятся забытые ветки.
|
|
60
|
-
|
|
61
|
-
WIP PR **не** двигает карточку в «Ревью»: он открывается рано и означает «работа идёт», а не «смотрите».
|
|
62
|
-
|
|
63
|
-
Превышение предела колонки подсвечивается, но перенос не запрещает: предел — ориентир, а не преграда.
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="README.md"><b>🇬🇧 English</b></a> •
|
|
20
|
+
<a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
|
|
21
|
+
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
22
|
+
</p>
|
|
64
23
|
|
|
65
|
-
|
|
24
|
+
</div>
|
|
66
25
|
|
|
67
|
-
|
|
68
|
-
- **Не пишет стартовый комментарий в issue.** Его пишет агент после preflight, потому что до preflight ветка и план неизвестны.
|
|
69
|
-
- **Не подсказывает имя ветки** в первом сообщении: его выбирает агент.
|
|
70
|
-
- Ветка и worktree на карточке — **наблюдение**, а не намерение.
|
|
71
|
-
- Не трогает Hermes Kanban. Это другая система.
|
|
26
|
+
---
|
|
72
27
|
|
|
73
|
-
##
|
|
28
|
+
## ⚡ Overview & Problem Solved
|
|
74
29
|
|
|
75
|
-
|
|
30
|
+
Managing concurrent software tasks across multiple autonomous AI agents easily leads to context drift, lost pull request handoffs, and untracked branch lifecycles. Without a dedicated visual board, users must manually juggle disparate chat windows and verify issue states on remote VCS trackers.
|
|
76
31
|
|
|
77
|
-
|
|
32
|
+
**`@goodandready/dsh-kanban`** introduces an interactive **Kanban Board** embedded natively into DeepSeek Harness. Every card represents a concrete development task linked to its own **dedicated agent session**. Moving a card between workflow columns automatically dispatches lifecycle instructions directly to the agent (e.g. implementing, opening PRs, deploying, or cleaning up worktrees), with continuous **2-way Gitea/Forgejo synchronization**.
|
|
78
33
|
|
|
79
|
-
|
|
34
|
+
---
|
|
80
35
|
|
|
81
|
-
|
|
36
|
+
## 🏗️ Architecture
|
|
82
37
|
|
|
83
|
-
|
|
38
|
+
```mermaid
|
|
39
|
+
graph LR
|
|
40
|
+
subgraph UI ["DeepSeek Harness Web UI"]
|
|
41
|
+
Board["Interactive Kanban Board<br/>(Backlog, In Progress, Review, Deploy, Cleanup, Done)"]
|
|
42
|
+
Intake["Task Intake Modal<br/>(Model Picker & Worktree Path)"]
|
|
43
|
+
HeaderChip["Kanban Header Chip<br/>(Active Tasks & Quick Jump)"]
|
|
44
|
+
end
|
|
84
45
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
| issue закрыт, ветка ещё есть | Cleanup |
|
|
91
|
-
| issue закрыт, ветки нет | Done |
|
|
46
|
+
subgraph Core ["dsh-kanban Engine"]
|
|
47
|
+
Dispatcher["Session Dispatcher<br/>(Dispatches commands via agent.followup)"]
|
|
48
|
+
Store["SQLite Task Store<br/>(State, History & Session Links)"]
|
|
49
|
+
SyncEngine["2-Way Sync Engine<br/>(Issues, PRs, Branches, Webhooks)"]
|
|
50
|
+
end
|
|
92
51
|
|
|
93
|
-
|
|
52
|
+
subgraph Agents ["Autonomous Agent Sessions"]
|
|
53
|
+
Agent1["Agent: Task #42<br/>(Coding in Worktree)"]
|
|
54
|
+
Agent2["Agent: Task #53<br/>(PR Review)"]
|
|
55
|
+
end
|
|
94
56
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| Доска | Колонки | Для чего |
|
|
102
|
-
|---|---|---|
|
|
103
|
-
| Проектная | бэклог · в работе · ревью · deploy · cleanup · выполнено | задачи из issue |
|
|
104
|
-
| Простая | бэклог · в работе · проверка · выполнено | свободные задачи |
|
|
105
|
-
|
|
106
|
-
`review`, `deploy` и `cleanup` осмысленны только там, где за задачей стоит issue: у свободной заметки нет ни ветки, ни PR, и Gitea о ней ничего не скажет. Три колонки, которые никогда не заполнятся, — не запас на будущее, а помеха.
|
|
107
|
-
|
|
108
|
-
Импорт issue на простую доску не предлагается и отвергается сервером. Вид доски — её явное свойство, а не вывод из содержимого: доска, меняющая число колонок от того, что на неё положили, ведёт себя непредсказуемо.
|
|
109
|
-
|
|
110
|
-
Прежняя единственная доска СТАНОВИТСЯ проектной вместе со всеми задачами — вторая заводится рядом, а не вместо неё. Смены вида у доски с задачами пока нет: карточки из `deploy` и `cleanup` на простой доске девать некуда.
|
|
111
|
-
|
|
112
|
-
### Чип задачи в чате
|
|
113
|
-
|
|
114
|
-
В шапке чата, поднятого с доски, виден чип задачи с текущей колонкой. Он умеет три вещи:
|
|
115
|
-
|
|
116
|
-
- **перенести в колонку** — то же, что перенос на доске, со всеми последствиями;
|
|
117
|
-
- **перейти к карточке** — открывает доску и сразу окно этой задачи, переключая доску, если карточка лежит на другой;
|
|
118
|
-
- **оставить заметку** — дописывает текст в тело задачи.
|
|
119
|
-
|
|
120
|
-
Заметка меняет тело, а тело уходит агенту первым сообщением при запуске. Значит заметка, оставленная до запуска, попадёт в работу, а после запуска — нет; это написано подсказкой рядом с полем, иначе поведение выглядит случайным.
|
|
121
|
-
|
|
122
|
-
Дописывает заметку сервер, а не браузер: чип держит копию задачи, и склейка у него потеряла бы всё, что тело нажило с момента её получения.
|
|
123
|
-
|
|
124
|
-
### Создание задачи: проект или не проект
|
|
57
|
+
subgraph VCS ["Gitea / Forgejo Instance"]
|
|
58
|
+
GiteaIssues["Issues & Milestones"]
|
|
59
|
+
GiteaPRs["Pull Requests & Branches"]
|
|
60
|
+
Webhook["Event Webhook (/dsh-kanban/webhook)"]
|
|
61
|
+
end
|
|
125
62
|
|
|
63
|
+
Board -->|User Moves Card| Dispatcher
|
|
64
|
+
Dispatcher -->|Sends Stage Instruction| Agent1
|
|
65
|
+
Dispatcher -->|Cancels on Backlog| Agent2
|
|
66
|
+
Board <-->|CRUD State| Store
|
|
67
|
+
SyncEngine <-->|Polls / Webhooks| VCS
|
|
68
|
+
SyncEngine -->|Reconciles State| Store
|
|
69
|
+
Store -->|Updates UI Live| Board
|
|
126
70
|
```
|
|
127
|
-
Новая задача
|
|
128
|
-
○ Проект → репозиторий: выбрать из Gitea либо ввести имя нового
|
|
129
|
-
○ Не проект → уходит на простую доску
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Проект** заводит issue в Gitea, и карточка сразу к нему привязана. Репозиторий выбирается из существующих либо создаётся: приватный и пустой, без README и заготовок. Создание репозитория необратимо, и окно говорит об этом до нажатия, а не после.
|
|
133
|
-
|
|
134
|
-
**Не проект** — заметка, не относящаяся ни к какому репозиторию: живёт на простой доске и в Gitea не попадает.
|
|
135
|
-
|
|
136
|
-
Правило без исключений: **есть issue — проектная доска, нет — простая.** Помнить, где вы её завели, не нужно.
|
|
137
|
-
|
|
138
|
-
Порядок при создании неслучаен: сперва репозиторий, потом issue, потом карточка. Обрыв на середине не оставляет карточку привязанной к репозиторию без issue — лучше не завести её вовсе и сказать об этом. Созданный репозиторий при этом не удаляется: убирать чужое добро из-за своей неудачи хуже, чем оставить лишний пустой репозиторий.
|
|
139
|
-
|
|
140
|
-
**Инструмента заведения issue у агента нет и не будет.** У соседнего плагина `dsh-gitea` уже есть `gitea_issue_create`, и второй способ делать то же самое разошёлся бы с первым. Агент зовёт свой инструмент, а карточка приезжает подхватом.
|
|
141
71
|
|
|
142
|
-
|
|
72
|
+
---
|
|
143
73
|
|
|
144
|
-
|
|
74
|
+
## ✨ Full Feature Breakdown
|
|
145
75
|
|
|
146
|
-
|
|
76
|
+
### 1. Interactive Visual Kanban Board in Web UI
|
|
147
77
|
|
|
148
|
-
|
|
78
|
+
* **Workflow Columns**:
|
|
79
|
+
* **Project Board Mode**: `Backlog` ➔ `In Progress` ➔ `Review` ➔ `Deploy` ➔ `Cleanup` ➔ `Done`.
|
|
80
|
+
* **Simple Board Mode**: `Backlog` ➔ `In Progress` ➔ `Review` ➔ `Done`.
|
|
81
|
+
* **Drag-and-Drop Lifecycle Transitions**: Moving a card immediately executes the underlying stage trigger.
|
|
82
|
+
* **Top Navigation Chip**: Live summary in the chat header showing active in-progress tasks with 1-click jump to board or active session.
|
|
83
|
+
* **Rich Task Cards**: Shows task title, issue index (`#42`), assigned LLM model, target worktree, branch name, PR review status, and uncommitted diff markers.
|
|
149
84
|
|
|
150
|
-
|
|
85
|
+
---
|
|
151
86
|
|
|
152
|
-
|
|
87
|
+
### 2. Task-to-Agent Session Dispatcher
|
|
153
88
|
|
|
154
|
-
|
|
89
|
+
Unlike passive task boards, `dsh-kanban` actively drives the agents:
|
|
155
90
|
|
|
156
|
-
|
|
91
|
+
| Column Moved To | Action Taken by Dispatcher | Instruction Sent to Agent Session |
|
|
92
|
+
|:---|:---|:---|
|
|
93
|
+
| **`Backlog`** | 🛑 **Stops Active Turn** | `agent.cancel({ kind: 'user' })` — stops agent execution immediately |
|
|
94
|
+
| **`In Progress`** | ⚡ **Dispatches Turn** | *"Start or continue implementing this task according to standard workflow."* |
|
|
95
|
+
| **`Review`** | 🔍 **Dispatches Turn** | *"Prepare work for review: mark PR ready and request human code inspection."* |
|
|
96
|
+
| **`Deploy`** | 🚀 **Dispatches Turn** | *"Merge pull request and deploy. Moving card to Deploy is explicit user approval."* |
|
|
97
|
+
| **`Cleanup`** | 🧹 **Dispatches Turn** | *"Clean up: delete remote/local branches, prune worktrees, log summary to issue."* |
|
|
98
|
+
| **`Done`** | 🔒 **Human / VCS Only** | Closed automatically upon issue closure or user confirmation |
|
|
157
99
|
|
|
158
|
-
|
|
100
|
+
---
|
|
159
101
|
|
|
160
|
-
|
|
102
|
+
### 3. Continuous 2-Way Gitea / Forgejo Sync
|
|
161
103
|
|
|
162
|
-
|
|
104
|
+
* **Bi-directional Reconciliation**: Polling and Webhook receiver (`/dsh-kanban/webhook`) sync issue descriptions, comments, PR status, labels, and closed states.
|
|
105
|
+
* **Conflict Resolution**: Timestamp-based merge logic ensures manual edits in Gitea and board moves resolve cleanly without state clobbering.
|
|
106
|
+
* **Automatic Issue Linking**: New tasks created on the board can automatically spawn corresponding issues and branch worktrees on Gitea.
|
|
163
107
|
|
|
164
|
-
|
|
108
|
+
---
|
|
165
109
|
|
|
166
|
-
###
|
|
110
|
+
### 4. Agent Tools & Human Governance Safety
|
|
167
111
|
|
|
168
|
-
|
|
112
|
+
| Tool Name | Scope | Purpose | Safety Rules |
|
|
113
|
+
|:---|:---|:---|:---|
|
|
114
|
+
| `board_move` | Board | Lets agent report progress and transition card to next stage | ⚠️ Cannot transition to `done` (closed by fact/human only) |
|
|
115
|
+
| `board_plan` | Board | Saves structured step-by-step implementation plan to task card | - |
|
|
169
116
|
|
|
170
|
-
|
|
117
|
+
---
|
|
171
118
|
|
|
172
|
-
|
|
119
|
+
## 📦 Installation
|
|
173
120
|
|
|
174
|
-
|
|
121
|
+
Install via DeepSeek Harness CLI:
|
|
175
122
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
| `сверено 2 мин назад` | всё в порядке; точное время в подсказке |
|
|
179
|
-
| `сверяемся с Gitea…` | проход идёт прямо сейчас |
|
|
180
|
-
| `сверки с Gitea ещё не было` | харнесс только поднялся |
|
|
181
|
-
| **`сверка не проходит`** | выделено; в подсказке место, причина и время последней удачной сверки |
|
|
182
|
-
|
|
183
|
-
Причина называется словами — «репозиторий не найден», «токен не подошёл», — а не прячется в журнал харнесса. Доска, переставшая обновляться, не имеет права молчать: отличить «ничего не изменилось» от «мы ослепли» иначе нечем.
|
|
184
|
-
|
|
185
|
-
**Неудача не затирает время последнего успеха.** Иначе теряется ответ на главный вопрос: когда доска в последний раз видела правду.
|
|
186
|
-
|
|
187
|
-
Состояние живёт в памяти процесса, а не в базе: это положение текущего запуска. После перезапуска честнее сказать «сверки ещё не было», чем показать вчерашний успех как сегодняшний.
|
|
188
|
-
|
|
189
|
-
Повторных попыток и починки здесь нет — задача показать, а не вылечить.
|
|
190
|
-
|
|
191
|
-
### Свои названия колонок
|
|
192
|
-
|
|
193
|
-
Настройка «Свои названия колонок» — пары `идентификатор=Название` через запятую, например `backlog=Идеи, review=Проверка`. Пусто — обычные названия.
|
|
194
|
-
|
|
195
|
-
Одно поле на все колонки, а не шесть отдельных: переименовывают их раз в жизни, а шесть полей засорили бы карточку настроек навсегда. Своё название приходит с сервера — там конфиг; перевод остаётся в браузере — там языки.
|
|
196
|
-
|
|
197
|
-
### Как разложена колонка
|
|
198
|
-
|
|
199
|
-
Внутри колонки задачи сгруппированы по проектам: заголовок со счётчиком, щелчок сворачивает группу. Крупные проекты идут первыми — с двадцатью задачами проект не должен теряться под однозадачными. Заголовки появляются, только когда проектов в колонке больше одного.
|
|
200
|
-
|
|
201
|
-
Внутри группы наверх поднимается идущая работа: **сперва ждущие человека, затем идущие, затем остановившиеся**, дальше всё прочее в прежнем порядке. Ждущие впереди идущих намеренно: идущая работа идёт сама, а ждущая стоит из-за вас.
|
|
202
|
-
|
|
203
|
-
Ручной порядок при этом не теряется — подъём работает поверх него, внутри каждой ступени порядок прежний.
|
|
204
|
-
|
|
205
|
-
Порядок задаёт сервер, а браузер рисует заголовок при смене проекта: повторять правила во второй раз значило бы завести вторую их редакцию.
|
|
206
|
-
|
|
207
|
-
### Языки
|
|
208
|
-
|
|
209
|
-
Плагин несёт два словаря — английский и китайский: это встроенные локали ядра. Русский приезжает языковым пакетом `@goodandready/dsh-russian-lang`, который регистрирует `ru` для пространства `dsh-kanban` извне. Свой `ru` внутри плагина мешал бы пакету: повторная регистрация локали падает, и пакет такие пространства пропускает.
|
|
210
|
-
|
|
211
|
-
Без службы локализации (например, до её появления в сборке) доска говорит по-английски — это запасной перевод, а не выбор.
|
|
212
|
-
|
|
213
|
-
### Отбор видно
|
|
214
|
-
|
|
215
|
-
Когда что-нибудь отобрано или введён поиск, рядом с отборами появляется «показано 12 из 81». На нетронутой доске этой строки нет — она была бы шумом. Без неё при восьмидесяти карточках легко решить, что отбор сломан, когда он просто строгий.
|
|
216
|
-
|
|
217
|
-
### Что на карточке
|
|
218
|
-
|
|
219
|
-
Шапка карточки отвечает на два вопроса раньше заголовка — чей это проект и что за работа:
|
|
220
|
-
|
|
221
|
-
```
|
|
222
|
-
memory-brain#1369 [type/feature]
|
|
223
|
-
BudgetTracker concurrent reservations: детерминированный max-cost…
|
|
224
|
-
3 из 7 · пишу тесты
|
|
225
|
-
перенести · в работе · здесь 2 дн
|
|
123
|
+
```bash
|
|
124
|
+
dsh plugin --profile web add @goodandready/dsh-kanban
|
|
226
125
|
```
|
|
227
126
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
Метки покрашены **цветами из Gitea** — теми же, что вы видите в самом issue. Цвет текста поверх выбирается по яркости фона, как это делает Gitea: иначе бледная метка на светлом становится нечитаемой.
|
|
231
|
-
|
|
232
|
-
На карточке видна **дата заведения задачи**, а не время в колонке: «здесь 34 минуты» у задачи, приехавшей подхватом полчаса назад, не значит ничего — это возраст карточки на доске, а спрашивают про возраст задачи. Год показывается, только если он не нынешний.
|
|
233
|
-
|
|
234
|
-
У задачи с сессией рядом с отметкой «в работе» стоит **переход в чат**: «идёт» без пути к тому, что идёт, — сведение, которым нельзя воспользоваться.
|
|
235
|
-
|
|
236
|
-
Счётчик колонки — залитая плашка цвета своей колонки, а при превышении предела красная. Серым на сером он не читался.
|
|
127
|
+
Restart DSH Web UI and perform a hard-refresh (`Ctrl+F5` or `Cmd+Shift+R`).
|
|
237
128
|
|
|
238
|
-
|
|
129
|
+
---
|
|
239
130
|
|
|
240
|
-
|
|
131
|
+
## ⚙️ Configuration
|
|
241
132
|
|
|
242
|
-
|
|
133
|
+
Navigate to **Settings -> Plugins -> Kanban**:
|
|
243
134
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
135
|
+
```yaml
|
|
136
|
+
# config.yaml
|
|
137
|
+
dsh-kanban:
|
|
138
|
+
boardKind: "project"
|
|
139
|
+
giteaUrl: "https://gitea.yourcompany.com"
|
|
140
|
+
giteaTokenEnv: "GITEA_TOKEN"
|
|
141
|
+
giteaOwner: "my-team"
|
|
142
|
+
giteaRepo: "main-app"
|
|
143
|
+
syncIntervalMs: 30000
|
|
144
|
+
webhookSecret: ""
|
|
250
145
|
```
|
|
251
146
|
|
|
252
|
-
|
|
253
|
-
|---|---|
|
|
254
|
-
| между пространствами | **и** — «срочные баги» это `priority/high` и `type/bug` |
|
|
255
|
-
| внутри пространства | **или** — срочность у задачи одна, и «и» всегда давало бы пусто |
|
|
256
|
-
|
|
257
|
-
Пространства собираются из меток, которые реально лежат на карточках: всё до первой `/` — пространство, всё после — значение. Список не зашит, поэтому заведённое в Gitea новое пространство появится само, без правки кода и без релиза. Порядок задан для известных, незнакомые дописываются в конец по алфавиту.
|
|
258
|
-
|
|
259
|
-
Метки без пространства (`epic`, `hotfix`) своего отбора не получают — список из двух значений ради двух меток был бы мебелью. На карточках они видны и находятся поиском.
|
|
147
|
+
### Settings Reference Table
|
|
260
148
|
|
|
261
|
-
|
|
149
|
+
| Key | Type | Default | Description |
|
|
150
|
+
|:---|:---|:---|:---|
|
|
151
|
+
| `boardKind` | `string` | `"project"` | Board workflow mode: `"project"` (6 columns) or `"simple"` (4 columns) |
|
|
152
|
+
| `giteaUrl` | `string` | `""` | Base URL of Gitea/Forgejo instance for task synchronization |
|
|
153
|
+
| `giteaTokenEnv` | `string` | `"GITEA_TOKEN"` | DSH Credential name containing the Gitea API access token |
|
|
154
|
+
| `giteaOwner` | `string` | `""` | Default organization or username for synced repositories |
|
|
155
|
+
| `giteaRepo` | `string` | `""` | Default repository name for issue/task sync |
|
|
156
|
+
| `syncIntervalMs` | `number` | `30000` | Background synchronization polling interval in milliseconds |
|
|
157
|
+
| `webhookSecret` | `string` | `""` | Optional secret for validating incoming Gitea webhook signatures |
|
|
262
158
|
|
|
263
|
-
|
|
159
|
+
---
|
|
264
160
|
|
|
265
|
-
|
|
161
|
+
## 🧪 Testing & Verification
|
|
266
162
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
### Окно задачи
|
|
270
|
-
|
|
271
|
-
```
|
|
272
|
-
[memory-brain#1368] [type/feature] [Закрыть]
|
|
273
|
-
Same-turn memory write-back contract
|
|
274
|
-
заведена 2 дня назад · изменена 5 мин назад · issue ↗
|
|
275
|
-
|
|
276
|
-
<описание, размеченное>
|
|
277
|
-
<план агента, если есть>
|
|
278
|
-
<журнал, если есть>
|
|
279
|
-
<запуск: провайдер, модель, сообщение>
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
**Описание разбирается разметкой**: заголовки, списки, выделение, `код`, блоки кода, цитаты и ссылки. Всё непонятое остаётся текстом как есть — полноценный markdown доска не тянет и не притворяется.
|
|
283
|
-
|
|
284
|
-
Разбор идёт на сервере и приезжает **деревом**, а браузер собирает его элементами. Тело задачи пишет кто угодно, и вставлять его строкой HTML значило бы дать issue выполнить что угодно в вашем интерфейсе; при сборке элементами подстановка невозможна по построению, а не по бдительности. Ссылки открываются только `http` и `https` — `javascript:` в теле остаётся видимым текстом, а не превращается в ссылку.
|
|
285
|
-
|
|
286
|
-
Пустые разделы не рисуются вовсе.
|
|
287
|
-
|
|
288
|
-
### Карточка открывается окном
|
|
289
|
-
|
|
290
|
-
Панель справа в 420 пикселей вмещала описание и журнал, но не план с отметками. Теперь карточка открывается окном поверх доски: описание, метки, ссылка на issue, план агента, журнал переходов, время, пусковая полоса. Закрывается крестиком, щелчком по затемнению и клавишей Escape.
|
|
291
|
-
|
|
292
|
-
Окно живёт внутри экрана доски, а не поверх всего интерфейса: доска сама лежит в колонке разговора, и выход за её пределы наложился бы на чужие части оболочки. Снизу оставлен запас — поверх интерфейса висят плавающие виджеты соседних плагинов.
|
|
293
|
-
|
|
294
|
-
### Время на доске
|
|
295
|
-
|
|
296
|
-
| Где | Что видно |
|
|
297
|
-
|---|---|
|
|
298
|
-
| карточка | сколько стоит в этой колонке — `здесь 3 дн` |
|
|
299
|
-
| карточка с сессией | когда её последний раз трогали; после порога молчания отметка становится тревожной |
|
|
300
|
-
| окно задачи | когда заведена и когда менялась в последний раз |
|
|
301
|
-
|
|
302
|
-
Формат относительный, потому что «третий день» читается мгновенно, а точная дата требует сравнения с сегодняшним числом; сама дата — в подсказке при наведении. Время в колонке считается по отметке, которую ставит перенос: перестановка внутри колонки её не сбрасывает, задача в ревью третий день там и остаётся.
|
|
303
|
-
|
|
304
|
-
Порог молчания настраивается (`staleAfterMin`, по умолчанию час) и считается на хосте: отдавать браузеру ещё и порог значило бы отдавать ему решение. Отдельного опроса живости сессий нет — это был бы второй источник правды и лишняя нагрузка.
|
|
305
|
-
|
|
306
|
-
**Открыть чат.** У задачи с сессией в окне есть кнопка возврата в её чат. Без неё задача, идущая вторые сутки, ищется в общем списке по имени вида `kanban-9e84cae6-…`.
|
|
307
|
-
|
|
308
|
-
### Сворачивание колонок
|
|
309
|
-
|
|
310
|
-
Шесть колонок по 220 пикселей не помещаются на ноутбуке. Поэтому пустая колонка сама сжимается до вертикальной полоски с названием, а щелчок по названию сворачивает и разворачивает любую, включая непустую. Решение человека сильнее автоматики в обе стороны: развёрнутая им пустая колонка не схлопнется у него на глазах.
|
|
311
|
-
|
|
312
|
-
Свёрнутая показывает число карточек — колонка с работой, выглядящая пустой, хуже любой тесноты. Целью переноса она остаётся: карточку можно бросить в неё, не разворачивая.
|
|
313
|
-
|
|
314
|
-
Колонки не прячутся совсем. `cleanup` пуст ровно до того момента, когда в нём появляется забытая ветка; спрятав его, мы спрятали бы тот самый сигнал, ради которого его завели.
|
|
315
|
-
|
|
316
|
-
### Ручной перенос — это команда агенту
|
|
317
|
-
|
|
318
|
-
Карточку двигают не ради учёта. Человек перетащил — значит просит запустить тот этап, куда перетащил, и команда уходит в чат задачи отдельным сообщением. При отпускании карточки доска показывает окно с описанием последствий; отмена оставляет карточку на месте.
|
|
319
|
-
|
|
320
|
-
| Куда перенесли | Что происходит |
|
|
321
|
-
|---|---|
|
|
322
|
-
| Backlog | работа останавливается: идущий ход агента прерывается |
|
|
323
|
-
| В работе | агент начинает или продолжает реализацию |
|
|
324
|
-
| Ревью | агент снимает с PR пометку черновика и запрашивает проверку |
|
|
325
|
-
| Deploy | агент вливает PR и выкатывает |
|
|
326
|
-
| Cleanup | агент удаляет ветку, worktree и локальную ветку |
|
|
327
|
-
| Done | завершение; сюда переносит только человек |
|
|
328
|
-
|
|
329
|
-
**Перенос в Deploy и есть явное «ок» на выкатку.** Воркфлоу требует разрешения человека перед deploy, и это разрешение дано движением, а не словом в чате — второй раз агент не спрашивает.
|
|
330
|
-
|
|
331
|
-
Инструменту агента переход в `done` закрыт и даже не предлагается в перечислении. Его путь к завершению — закрыть issue и удалить ветку; сверка с Gitea сама увидит закрытый issue без ветки. Карточка двигается фактом, а не заявлением.
|
|
332
|
-
|
|
333
|
-
### План агента на карточке
|
|
334
|
-
|
|
335
|
-
Агент публикует план своим инструментом `board_plan` — доска не разбирает его сообщения, потому что разбор это гадание, и не опирается на чужой `todo_list`, потому что это была бы зависимость от соседнего плагина.
|
|
336
|
-
|
|
337
|
-
Список пунктов шлётся один раз, дальше агент двигает только номер текущего: гонять весь план ради одного числа незачем. Всё, что до текущего пункта, считается сделанным.
|
|
338
|
-
|
|
339
|
-
На карточке видно `3 из 7 · пишу тесты`, в окне задачи — весь план: сделанное зачёркнуто, идущий пункт выделен. Плана из одного пункта и плана из двадцати это касается одинаково — на карточку едут только числа и текущий пункт.
|
|
340
|
-
|
|
341
|
-
| Состояние | Откуда известно |
|
|
342
|
-
|---|---|
|
|
343
|
-
| в работе | у живого агента идёт ход |
|
|
344
|
-
| ждёт пользователя | запрос разрешения или вопрос |
|
|
345
|
-
| остановился | сессия у задачи записана, а живого агента за ней нет |
|
|
346
|
-
|
|
347
|
-
«Остановился» — не догадка по тишине, а факт: так выглядит работа, прерванная перезапуском харнесса. Порога тишины в настройках нет и не будет: он был бы догадкой там, где есть точный признак.
|
|
348
|
-
|
|
349
|
-
**Признак «нужен человек».** Колонки «Блокировано» в наборе нет, поэтому запрос разрешения или вопрос агента не двигают карточку, а поднимают на ней оранжевую точку. Признак снимается сам, когда ход возобновляется.
|
|
350
|
-
|
|
351
|
-
**Инструмент агента** `board_move` выключен по умолчанию: скилл `gitea-project-workflow` пока запрещает этому CLI трогать канбан.
|
|
352
|
-
|
|
353
|
-
Определение инструмента живёт в `lib/board-tool.js` отдельно от обвязки cordis и
|
|
354
|
-
следует контракту `defineTool` из `@deepseek-ai/dsh-tools` **не ниже 0.1.0-rc.8**:
|
|
355
|
-
`output` обязателен, а `parameters` — карта «имя -> схема значения», а не JSON
|
|
356
|
-
Schema с корнем `type: 'object'`. Пропущенный `output` роняет не инструмент, а
|
|
357
|
-
загрузку всего профиля, поэтому форма закреплена тестами `test/board-tool.test.mjs`.
|
|
358
|
-
|
|
359
|
-
### Пачка задач одной сессией
|
|
360
|
-
|
|
361
|
-
Флажок на карточке отмечает задачу, в шапке появляется «Выбрано N» и «Запустить выбранные». Вся пачка уезжает в **одну** сессию: провайдер и модель спрашиваются один раз, рабочая папка берётся у первой задачи и называется в окне подтверждения.
|
|
362
|
-
|
|
363
|
-
Задачи приходят агенту **по очереди** — по сообщению на каждую, а не одним списком. Выбора «отдать разом» нет намеренно: правило выпуска релизов всё равно не даёт делать десять задач сразу, а десять карточек в «В работе», из которых делается одна, лгут о состоянии доски и лишают предел колонки смысла.
|
|
364
|
-
|
|
365
|
-
В «В работе» переезжает только первая. Остальные остаются на месте с отметкой «в очереди · 2», «в очереди · 3» и так далее — номер считается по порядку постановки внутри сессии.
|
|
366
|
-
|
|
367
|
-
Каждое сообщение называет свой номер и общее число: «Задача 2 из 5». Без этого агент, получив первую из пяти, объявит работу законченной и приберёт за собой — удалит ветку и закроет issue.
|
|
368
|
-
|
|
369
|
-
**Инструменты при нескольких задачах в сессии.** `board_move` обязан назвать, какую карточку двигает; не назвал — отказ с перечислением, а не догадка: подвинутую не ту карточку заметят нескоро. При одной задаче называть нечего, поведение прежнее. `board_plan` пишет один план на сессию — это план работы над пачкой, — и кладёт его всем её задачам.
|
|
370
|
-
|
|
371
|
-
### Очередь к идущей работе
|
|
372
|
-
|
|
373
|
-
В меню карточки — «в очередь…»: выбор из **живых** сессий доски. Задача привязывается к выбранной сессии, сообщение уходит туда же, и агент возьмёт его, закончив текущий ход.
|
|
374
|
-
|
|
375
|
-
Своей очереди плагин не заводит. Она уже есть у ядра: `followup` кладёт сообщение, агент забирает его на границе шага. Вторая очередь рядом с настоящей разошлась бы с ней при первой же заминке, и разбираться, какая права, пришлось бы человеку.
|
|
376
|
-
|
|
377
|
-
Сессия без живого агента в список не попадает: предлагать её значило бы предлагать очередь, из которой никто ничего не возьмёт.
|
|
378
|
-
|
|
379
|
-
«Снять с очереди» отвязывает задачу и пишет в её журнал, что **отозвать уже отданное сообщение нечем** — агент может дойти до задачи и увидеть карточку, которая его не ждёт.
|
|
380
|
-
|
|
381
|
-
### Чем запускать: профиль агента и уровень доступа
|
|
382
|
-
|
|
383
|
-
В окне задачи рядом с провайдером и моделью — **профиль агента** и **уровень доступа**. Оба списка приходят от харнесса: профили из `agentPresets`, уровни из `permissionPresets` (обычно `read-only`, `workspace-write`, `danger-full-access`). Свой словарь уровней доска не заводит и пояснения к ним берёт у ядра: собственные слова разошлись бы с тем, что уровень значит на самом деле.
|
|
384
|
-
|
|
385
|
-
Профиль едет в создание сессии (`meta.agentPreset`) — это факт создания, у идущей сессии его не сменить. Поэтому при «Продолжить» поле профиля не показывается: показывать поле, которое ничего не меняет, значит врать.
|
|
386
|
-
|
|
387
|
-
**Выбрали уровень доступа, а поставить его нечем — задача не запускается.** Сессия иначе пошла бы с правами по умолчанию, то есть, возможно, бо́льшими, чем просили; поднятая сессия при этом убирается за собой. Молчаливое расширение прав хуже отказа.
|
|
388
|
-
|
|
389
|
-
Обе службы у ядра необязательны: если развёртывание их не собирает, списки приходят пустыми и поля не рисуются вовсе. Сломанный профиль в список не попадает — сессия на нём не соберётся, а отказ прилетел бы уже после запуска.
|
|
390
|
-
|
|
391
|
-
При групповом запуске поля те же и стоят в том же окне: пачка идёт одной сессией, значит профиль и доступ у неё один.
|
|
392
|
-
|
|
393
|
-
### Что видно в шапке доски
|
|
394
|
-
|
|
395
|
-
**«Ждут ответа: 2»** — задачи, где агент задал вопрос или просит разрешения. Щелчок оставляет на доске только их, повторный снимает. Когда таких задач нет, счётчика нет вовсе: ноль в шапке — мебель, за которой перестают следить.
|
|
396
|
-
|
|
397
|
-
**Порядок задач** — «как разложено» (ручной порядок плюс живое вперёд), «сначала старые», «сначала новые». Сортировка идёт в браузере поверх присланного порядка и ничего не записывает: это взгляд на доску, а не свойство задач. Группировку по проектам она не ломает — карточки переставляются внутри своего проекта, а идущая работа остаётся наверху группы.
|
|
398
|
-
|
|
399
|
-
**Отбор по автору** стоит в одном ряду с метками. Задачи без автора — свои, заведённые на доске — собираются под значением `—`: «никто» тоже ответ на вопрос «кто завёл», и по нему тоже отбирают.
|
|
400
|
-
|
|
401
|
-
### Остановить, не двигая карточку
|
|
402
|
-
|
|
403
|
-
Раньше прервать агента можно было только перетащив карточку в «Бэклог», то есть отменив заодно и этап. В меню карточки есть «остановить»: прерывается ход, колонка остаётся. Пункт виден только у идущей задачи — останавливать нечего у того, кто не идёт.
|
|
404
|
-
|
|
405
|
-
«Агент не работал» и «остановлено» — разные ответы, и доска не выдаёт второй за первый.
|
|
406
|
-
|
|
407
|
-
### Пачку видно на карточках
|
|
408
|
-
|
|
409
|
-
У карточки, чья сессия несёт больше одной задачи, стоит «пачка 2 из 5» — тот же порядок, в котором агент их берёт. Наведение подсвечивает остальные карточки той же сессии. Одиночная задача отметки не получает: «1 из 1» ничего не сообщает.
|
|
410
|
-
|
|
411
|
-
### Групповые действия
|
|
412
|
-
|
|
413
|
-
В полосе выбора кроме «Запустить выбранные» — «В архив», «Снять с очереди», «Перенести…». Отдельного группового маршрута нет: это те же действия, что для одной задачи, применённые по очереди.
|
|
414
|
-
|
|
415
|
-
**Итог называется числом.** Часть задач может отказать — архивировать можно только из «Выполнено», снять с очереди можно только стоящую в ней, — и доска говорит «сделано у 7 из 10, остальные отказали». Молчаливо съеденный отказ означал бы карточку, про которую человек уверен, что она в архиве.
|
|
416
|
-
|
|
417
|
-
### Доска помнит, чем запускали
|
|
418
|
-
|
|
419
|
-
Провайдер, модель, профиль агента и уровень доступа подставляются те же, что в прошлый раз на этой доске. Память живёт в браузере у человека, а не в настройках плагина: это привычка одного, а не свойство доски.
|
|
420
|
-
|
|
421
|
-
Подставляется только то, что ядро всё ещё предлагает: исчезнувшая модель или уровень доступа заменяются умолчанием. Тихо подставить несуществующий уровень значило бы запустить задачу не с теми правами.
|
|
422
|
-
|
|
423
|
-
## Синхронизация
|
|
424
|
-
|
|
425
|
-
**Gitea → канбан.** Опрос с настраиваемым промежутком плюс вебхук для мгновенной сверки. Вебхук — ускорение, а не замена: он может быть не настроен, недоступен снаружи или потерян, и опрос остаётся всегда.
|
|
426
|
-
|
|
427
|
-
Маршрут вебхука `/dsh-kanban/webhook`, подпись проверяется общим секретом. **Без секрета вебхук не принимается вовсе** — иначе карточки двигал бы кто угодно снаружи.
|
|
428
|
-
|
|
429
|
-
**Канбан → Gitea.** Доска сообщает Gitea ровно одно: **закрытие issue**, когда карточка доходит до «Выполнено». Меток колонок она не ставит — стадия и так видна по ветке и pull request, а метка лишь пересказывала бы то, что уже написано рядом. Заодно доска не трогает чужую разметку вовсе: `bug`, `feat`, `hotfix` принадлежат процессу, и стирать их доска права не имеет.
|
|
430
|
-
|
|
431
|
-
Отправка идёт очередью: перенос карточки не ждёт сети, доска работает и при недоступном Gitea. Неудачная отправка повторяется, а исчерпав попытки — попадает в журнал задачи, а не исчезает.
|
|
432
|
-
|
|
433
|
-
**Конфликты.** Если обе стороны изменились с последней сверки, побеждает более позднее изменение, а проигравшее **называется в журнале задачи**. Синхронизация, тихо отменяющая правку человека, хуже отсутствующей: расхождение остаётся, а узнать о нём неоткуда.
|
|
434
|
-
|
|
435
|
-
До первой сверки «изменилось с прошлого раза» смысла не имеет — прошлого раза не было, — поэтому первая сверка принимает положение дел, а не спорит с ним.
|
|
436
|
-
|
|
437
|
-
## Ограничения
|
|
438
|
-
|
|
439
|
-
- Точного «работа идёт прямо сейчас» инстанс не знает. Порядок репозиториев и вывод колонок — приближение по открытым задачам, веткам и времени правки.
|
|
440
|
-
- Клиент Gitea покрывает только нужное доске: issue, PR, ветки, метки, поиск репозиториев.
|
|
441
|
-
- Неполное наблюдение считается отсутствующим: репозиторий, который не прочитался целиком, пропускается до следующей сверки. Иначе непрочитанные PR выглядели бы как их отсутствие и утаскивали карточку назад.
|
|
442
|
-
|
|
443
|
-
## Разработка
|
|
163
|
+
Run the comprehensive 520+ unit and integration test suite:
|
|
444
164
|
|
|
445
165
|
```bash
|
|
446
166
|
npm test
|
|
447
167
|
```
|
|
448
168
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
Тестовая матрица — в [index.md](index.md). План выпуска — в [docs/plans](docs/plans).
|
|
169
|
+
---
|
|
452
170
|
|
|
453
|
-
##
|
|
171
|
+
## 📄 License
|
|
454
172
|
|
|
455
|
-
MIT
|
|
173
|
+
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
package/README.ru.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# 📦 @goodandready/dsh-kanban
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<h3>Интерактивная Канбан-доска и диспетчер сессий агентов для DeepSeek Harness</h3>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@goodandready/dsh-kanban"><img src="https://img.shields.io/npm/v/@goodandready/dsh-kanban.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-kanban.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
|
|
10
|
+
<a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
|
|
11
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://goodandready.app/"><img src="https://img.shields.io/badge/Все_проекты_автора-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="Все проекты автора"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="README.md"><b>🇬🇧 English</b></a> •
|
|
20
|
+
<a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
|
|
21
|
+
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ⚡ Обзор и решаемая проблема
|
|
29
|
+
|
|
30
|
+
При ведении параллельной разработки силами нескольких автономных AI-агентов легко потерять контроль над статусом задач, проверкой пулл-реквестов (PR) и ветками в репозитории. Без наглядной доски разработчику приходится переключаться между десятками вкладок чата и вручную сверять тикеты в трекере.
|
|
31
|
+
|
|
32
|
+
**`@goodandready/dsh-kanban`** встраивает полноценную **Канбан-доску** прямо в Web UI DeepSeek Harness. Каждая карточка на доске связана со своей **выделенной сессией агента**. Перемещение карточки между колонками автоматически отправляет агенту целевую инструкцию (разработка, передача на ревью, деплой или очистка воркдеревьев), поддерживая непрерывную **двустороннюю синхронизацию с Gitea / Forgejo**.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🏗️ Архитектура
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
graph LR
|
|
40
|
+
subgraph UI ["Интерфейс DSH Web UI"]
|
|
41
|
+
Board["Канбан-доска<br/>(Backlog, In Progress, Review, Deploy, Cleanup, Done)"]
|
|
42
|
+
Intake["Форма создания задачи<br/>(Выбор модели и Worktree)"]
|
|
43
|
+
HeaderChip["Чип в шапке чата<br/>(Счётчик активных задач)"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
subgraph Core ["Ядро dsh-kanban"]
|
|
47
|
+
Dispatcher["Диспетчер сессий<br/>(Команды через agent.followup)"]
|
|
48
|
+
Store["База SQLite задач<br/>(История переходов и связи)"]
|
|
49
|
+
SyncEngine["Двусторонняя сверка<br/>(Issues, PR, Ветки, Webhooks)"]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
subgraph Agents ["Сессии агентов"]
|
|
53
|
+
Agent1["Агент: Задача #42<br/>(Кодинг в Worktree)"]
|
|
54
|
+
Agent2["Агент: Задача #53<br/>(Ревью PR)"]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
subgraph VCS ["Сервер Gitea / Forgejo"]
|
|
58
|
+
GiteaIssues["Задачи и Вехи"]
|
|
59
|
+
GiteaPRs["Пулл-реквесты и Ветки"]
|
|
60
|
+
Webhook["Вебхук-приёмник (/dsh-kanban/webhook)"]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Board -->|Перенос карточки| Dispatcher
|
|
64
|
+
Dispatcher -->|Инструкция по этапу| Agent1
|
|
65
|
+
Dispatcher -->|Отмена при переносе в бэклог| Agent2
|
|
66
|
+
Board <-->|CRUD операции| Store
|
|
67
|
+
SyncEngine <-->|Опрос / Вебхуки| VCS
|
|
68
|
+
SyncEngine -->|Сверка статусов| Store
|
|
69
|
+
Store -->|Обновление интерфейса| Board
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## ✨ Исчерпывающий разбор возможностей
|
|
75
|
+
|
|
76
|
+
### 1. Интерактивная Канбан-доска в Web UI
|
|
77
|
+
|
|
78
|
+
* **Режимы колонок**:
|
|
79
|
+
* **Режим Project (6 колонок)**: `Backlog` ➔ `In Progress` ➔ `Review` ➔ `Deploy` ➔ `Cleanup` ➔ `Done`.
|
|
80
|
+
* **Режим Simple (4 колонки)**: `Backlog` ➔ `In Progress` ➔ `Review` ➔ `Done`.
|
|
81
|
+
* **Drag-and-Drop управление этапами**: простое перетаскивание карточки мгновенно запускает соответствующий рабочий шаг.
|
|
82
|
+
* **Чип в шапке чата**: живой индикатор текущих задач с переходом на доску или сразу в чат задачи в 1 клик.
|
|
83
|
+
* **Информативные карточки**: отображение номера тикета (`#42`), выбранной LLM-модели, ветки Git, статуса PR и незакоммиченных правок.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### 2. Диспетчер команд и сессий агентов
|
|
88
|
+
|
|
89
|
+
Доска не просто отображает задачи, а напрямую управляет исполнением агентов:
|
|
90
|
+
|
|
91
|
+
| Колонка назначения | Действие диспетчера | Инструкция в чат задачи |
|
|
92
|
+
|:---|:---|:---|
|
|
93
|
+
| **`Backlog`** | 🛑 **Остановка хода** | `agent.cancel({ kind: 'user' })` — прерывает работу агента без потери контекста |
|
|
94
|
+
| **`In Progress`** | ⚡ **Запуск разработки** | *«Начни или продолжи реализацию этой задачи по стандартному воркфлоу.»* |
|
|
95
|
+
| **`Review`** | 🔍 **Запрос проверки** | *«Доведи работу до ревью: сними с PR пометку черновика и запроси проверку.»* |
|
|
96
|
+
| **`Deploy`** | 🚀 **Деплой и слияние** | *«Влей pull request и выкати. Перенос в Deploy — это явное согласие на выкатку.»* |
|
|
97
|
+
| **`Cleanup`** | 🧹 **Очистка окружения** | *«Прибери за задачей: удали ветку в Gitea, worktree и локальную ветку, запиши итог.»* |
|
|
98
|
+
| **`Done`** | 🔒 **Только человек / факт** | Автоматически закрывается по факту закрытия issue в Gitea |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### 3. Непрерывная 2-сторонняя синхронизация с Gitea / Forgejo
|
|
103
|
+
|
|
104
|
+
* **Двусторонняя сверка**: фоновый опрос и вебхуки (`/dsh-kanban/webhook`) синхронизируют заголовки, метки, PR и закрытие тикетов.
|
|
105
|
+
* **Разрешение конфликтов**: алгоритм с учётом таймстемпов предотвращает перезапись изменений при одновременных правках на сервере и доске.
|
|
106
|
+
* **Автосоздание задач**: новая карточка на доске может автоматически создавать задачу и ветку воркдерева в репозитории.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 4. Инструменты агента и безопасность
|
|
111
|
+
|
|
112
|
+
| Инструмент | Категория | Назначение | Контроль безопасности |
|
|
113
|
+
|:---|:---|:---|:---|
|
|
114
|
+
| `board_move` | Доска | Перемещение карточки на следующий этап | ⚠️ Перевод в `done` агенту запрещён (закрывается только по факту) |
|
|
115
|
+
| `board_plan` | Доска | Сохранение структурированного плана реализации на карточку | - |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 📦 Установка
|
|
120
|
+
|
|
121
|
+
Установка через консольный клиент DeepSeek Harness:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
dsh plugin --profile web add @goodandready/dsh-kanban
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Перезапустите Web UI DSH и обновите вкладку в браузере с очисткой кэша (`Ctrl+F5` или `Cmd+Shift+R`).
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## ⚙️ Конфигурация
|
|
132
|
+
|
|
133
|
+
Откройте **Настройки -> Плагины -> Kanban**:
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
# config.yaml
|
|
137
|
+
dsh-kanban:
|
|
138
|
+
boardKind: "project"
|
|
139
|
+
giteaUrl: "https://gitea.yourcompany.com"
|
|
140
|
+
giteaTokenEnv: "GITEA_TOKEN"
|
|
141
|
+
giteaOwner: "my-team"
|
|
142
|
+
giteaRepo: "main-app"
|
|
143
|
+
syncIntervalMs: 30000
|
|
144
|
+
webhookSecret: ""
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Таблица параметров конфигурации
|
|
148
|
+
|
|
149
|
+
| Параметр | Тип | По умолчанию | Описание |
|
|
150
|
+
|:---|:---|:---|:---|
|
|
151
|
+
| `boardKind` | `string` | `"project"` | Режим колонок: `"project"` (6 колонок) или `"simple"` (4 колонки) |
|
|
152
|
+
| `giteaUrl` | `string` | `""` | URL инстанса Gitea/Forgejo для синхронизации задач |
|
|
153
|
+
| `giteaTokenEnv` | `string` | `"GITEA_TOKEN"` | Имя DSH Credential с токеном доступа к Gitea API |
|
|
154
|
+
| `giteaOwner` | `string` | `""` | Организация или логин владельца репозитория |
|
|
155
|
+
| `giteaRepo` | `string` | `""` | Имя репозитория для связки задач |
|
|
156
|
+
| `syncIntervalMs` | `number` | `30000` | Интервал фоновой периодической сверки (мс) |
|
|
157
|
+
| `webhookSecret` | `string` | `""` | Секретный ключ для проверки входящих вебхуков от Gitea |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🧪 Тестирование и верификация
|
|
162
|
+
|
|
163
|
+
Запуск полного набора из более чем 520 юнит- и интеграционных тестов:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm test
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 📄 Лицензия
|
|
172
|
+
|
|
173
|
+
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# 📦 @goodandready/dsh-kanban
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<h3>面向 DeepSeek Harness 的可视化看板与任务智能体独立会话调度引擎</h3>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@goodandready/dsh-kanban"><img src="https://img.shields.io/npm/v/@goodandready/dsh-kanban.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-kanban.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
|
|
10
|
+
<a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
|
|
11
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://goodandready.app/"><img src="https://img.shields.io/badge/作者全部项目-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="作者全部项目"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="README.md"><b>🇬🇧 English</b></a> •
|
|
20
|
+
<a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
|
|
21
|
+
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ⚡ 核心定位与解决痛点
|
|
29
|
+
|
|
30
|
+
当多个自主 AI 智能体并行执行复杂研发任务时,极易发生上下文混乱、PR 审查脱节及分支生命周期失控。若缺少统一的可视化看板,开发者只能在数十个聊天窗口与代码托管平台之间来回切换与人工对齐状态。
|
|
31
|
+
|
|
32
|
+
**`@goodandready/dsh-kanban`** 为 DeepSeek Harness 提供了原生集成的**交互式看板系统**。看板上的每张卡片均绑定**专属独立的智能体执行会话**。卡片在工作流泳道之间的拖拽移动会自动向智能体派发针对性的阶段指令(如开始编码、提交审查、部署上线或清理环境),并全程与 **Gitea / Forgejo 保持毫秒级双向同步**。
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🏗️ 架构设计
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
graph LR
|
|
40
|
+
subgraph UI ["DeepSeek Harness Web UI 界面"]
|
|
41
|
+
Board["交互式看板<br/>(Backlog, In Progress, Review, Deploy, Cleanup, Done)"]
|
|
42
|
+
Intake["任务创建弹窗<br/>(LLM 模型与 Worktree 选择)"]
|
|
43
|
+
HeaderChip["聊天头部状态胶囊<br/>(活跃任务计数与快速直达)"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
subgraph Core ["dsh-kanban 核心引擎"]
|
|
47
|
+
Dispatcher["会话调度派发器<br/>(通过 agent.followup 发送阶段指令)"]
|
|
48
|
+
Store["SQLite 任务存储库<br/>(状态机、流转日志与会话关联)"]
|
|
49
|
+
SyncEngine["双向同步引擎<br/>(Issue、PR、分支与 Webhook)"]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
subgraph Agents ["智能体独立执行会话"]
|
|
53
|
+
Agent1["智能体: 任务 #42<br/>(Worktree 编码开发)"]
|
|
54
|
+
Agent2["智能体: 任务 #53<br/>(PR 审查中)"]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
subgraph VCS ["私有 Gitea / Forgejo 实例"]
|
|
58
|
+
GiteaIssues["Issue 任务与里程碑"]
|
|
59
|
+
GiteaPRs["Pull Request 与分支"]
|
|
60
|
+
Webhook["事件通知 (/dsh-kanban/webhook)"]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Board -->|用户拖拽卡片| Dispatcher
|
|
64
|
+
Dispatcher -->|派发阶段指令| Agent1
|
|
65
|
+
Dispatcher -->|移回 Backlog 时安全取消| Agent2
|
|
66
|
+
Board <-->|CRUD 读写| Store
|
|
67
|
+
SyncEngine <-->|轮询 / Webhook| VCS
|
|
68
|
+
SyncEngine -->|状态对齐| Store
|
|
69
|
+
Store -->|实时刷新 UI| Board
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## ✨ 核心特性深度解析
|
|
75
|
+
|
|
76
|
+
### 1. Web UI 原生交互式看板
|
|
77
|
+
|
|
78
|
+
* **两种工作流模式**:
|
|
79
|
+
* **Project 专业模式(6 泳道)**:`Backlog` ➔ `In Progress` ➔ `Review` ➔ `Deploy` ➔ `Cleanup` ➔ `Done`。
|
|
80
|
+
* **Simple 敏捷模式(4 泳道)**:`Backlog` ➔ `In Progress` ➔ `Review` ➔ `Done`。
|
|
81
|
+
* **拖拽即触发工作流**:卡片拖入新列立即触发底层智能体的对应阶段任务。
|
|
82
|
+
* **顶部导航状态胶囊**:在聊天头部实时展示正在进行的任务数,支持一键呼出看板或跳转专属会话。
|
|
83
|
+
* **信息高密度卡片**:展示关联 Issue 编号(`#42`)、所用模型、绑定 Worktree 路径、Git 分支及未提交代码变更。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### 2. 任务到智能体专属会话调度器
|
|
88
|
+
|
|
89
|
+
看板不仅是视觉展示,更是智能体的指令调度中枢:
|
|
90
|
+
|
|
91
|
+
| 目标泳道 | 调度器触发动作 | 发送给智能体专属会话的指令 |
|
|
92
|
+
|:---|:---|:---|
|
|
93
|
+
| **`Backlog`** | 🛑 **停止当前轮次** | `agent.cancel({ kind: 'user' })` — 优雅暂停智能体执行,保留上下文 |
|
|
94
|
+
| **`In Progress`** | ⚡ **启动开发** | *“按照标准流程开始或继续该任务的编码实现。”* |
|
|
95
|
+
| **`Review`** | 🔍 **请求代码审查** | *“将工作推进至审查阶段:解除 PR 草稿状态并请求人工复核。”* |
|
|
96
|
+
| **`Deploy`** | 🚀 **合并部署上线** | *“合并 Pull Request 并上线。移入 Deploy 泳道即代表用户明确许可。”* |
|
|
97
|
+
| **`Cleanup`** | 🧹 **清理分支环境** | *“清理任务环境:删除远端与本地分支、移除 Worktree,并在 Issue 记录总结。”* |
|
|
98
|
+
| **`Done`** | 🔒 **仅人工 / 事实关闭** | 在 Gitea Issue 关闭后自动归档完成 |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### 3. 与 Gitea / Forgejo 持续双向同步
|
|
103
|
+
|
|
104
|
+
* **实时对齐机制**:后台定时轮询与 Webhook 接收器(`/dsh-kanban/webhook`)无缝同步 Issue 标题、标签、PR 状态及关闭事件。
|
|
105
|
+
* **时间戳冲突解决**:精准的时间戳仲裁逻辑,杜绝在网页端与代码仓库同时编辑时的状态覆盖问题。
|
|
106
|
+
* **一键生成关联任务**:在看板新建任务可自动在 Gitea 创建 Issue 与独立的 Git Worktree 隔离分支。
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 4. 智能体专属工具与安全防护
|
|
111
|
+
|
|
112
|
+
| 工具名称 | 作用域 | 功能描述 | 安全约束 |
|
|
113
|
+
|:---|:---|:---|:---|
|
|
114
|
+
| `board_move` | 看板 | 允许智能体自主汇报进度并推进卡片至下一阶段 | ⚠️ 严禁移动至 `done`(必须由人工或事实关闭) |
|
|
115
|
+
| `board_plan` | 看板 | 将结构化分步实施计划持久化写入任务卡片 | - |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 📦 快速安装
|
|
120
|
+
|
|
121
|
+
通过 DeepSeek Harness 命令行一键安装:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
dsh plugin --profile web add @goodandready/dsh-kanban
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
重启 DSH Web UI 并强制刷新浏览器页面(`Ctrl+F5` 或 `Cmd+Shift+R`)。
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## ⚙️ 配置指南
|
|
132
|
+
|
|
133
|
+
在 Web UI 中打开 **设置 -> 插件 -> Kanban**:
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
# config.yaml
|
|
137
|
+
dsh-kanban:
|
|
138
|
+
boardKind: "project"
|
|
139
|
+
giteaUrl: "https://gitea.yourcompany.com"
|
|
140
|
+
giteaTokenEnv: "GITEA_TOKEN"
|
|
141
|
+
giteaOwner: "my-team"
|
|
142
|
+
giteaRepo: "main-app"
|
|
143
|
+
syncIntervalMs: 30000
|
|
144
|
+
webhookSecret: ""
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 配置参数速查表
|
|
148
|
+
|
|
149
|
+
| 配置项 | 数据类型 | 默认值 | 功能说明 |
|
|
150
|
+
|:---|:---|:---|:---|
|
|
151
|
+
| `boardKind` | `string` | `"project"` | 看板模式:`"project"`(6 泳道)或 `"simple"`(4 泳道) |
|
|
152
|
+
| `giteaUrl` | `string` | `""` | 用于同步任务的 Gitea / Forgejo 实例基础地址 |
|
|
153
|
+
| `giteaTokenEnv` | `string` | `"GITEA_TOKEN"` | 存储 Gitea API Token 的 DSH 凭据键名 |
|
|
154
|
+
| `giteaOwner` | `string` | `""` | 默认同步的仓库所属组织或用户名 |
|
|
155
|
+
| `giteaRepo` | `string` | `""` | 默认绑定的代码仓库名称 |
|
|
156
|
+
| `syncIntervalMs` | `number` | `30000` | 后台轮询同步的时间间隔(毫秒) |
|
|
157
|
+
| `webhookSecret` | `string` | `""` | 用于校验 Gitea Webhook 请求签名的可选密钥 |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🧪 测试与校验
|
|
162
|
+
|
|
163
|
+
运行超过 520 个完整的单元测试与集成测试:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm test
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 📄 开源许可证
|
|
172
|
+
|
|
173
|
+
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-kanban",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Kanban board for DeepSeek Harness: Gitea-backed tasks, workflow columns, and a dedicated agent session per task.",
|
|
3
|
+
"version": "0.1.17",
|
|
4
|
+
"description": "Visual Kanban board for DeepSeek Harness: Gitea-backed tasks, workflow columns, and a dedicated agent session per task.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"dsh-plugin",
|
|
25
25
|
"kanban",
|
|
26
26
|
"gitea",
|
|
27
|
-
"tasks"
|
|
27
|
+
"tasks",
|
|
28
|
+
"agents",
|
|
29
|
+
"deepseek-harness"
|
|
28
30
|
],
|
|
29
31
|
"repository": {
|
|
30
32
|
"type": "git",
|