@linxin666/dsh-client-ui-task-board 0.4.3 → 0.4.5
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.i18n.yaml +2 -2
- package/README.md +56 -18
- package/README.zh.md +56 -18
- package/lib/client.js +6242 -958
- package/lib/client.js.map +1 -1
- package/lib/index.js +3475 -234
- package/lib/types/client/PluginSettingsCard.d.ts +7 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +19 -3
- package/lib/types/client/board/ClampedMarkdown.d.ts +3 -0
- package/lib/types/client/board/ConfirmDialog.d.ts +4 -1
- package/lib/types/client/board/EditTaskModal.d.ts +5 -2
- package/lib/types/client/board/LinkSubtaskModal.d.ts +5 -2
- package/lib/types/client/board/NewTaskModal.d.ts +4 -1
- package/lib/types/client/board/TagManagerModal.d.ts +26 -0
- package/lib/types/client/board/TaskBoard.d.ts +10 -1
- package/lib/types/client/board/TaskCard.d.ts +14 -1
- package/lib/types/client/board/TaskDetail.d.ts +3 -1
- package/lib/types/client/board/TaskForm.d.ts +23 -2
- package/lib/types/client/board/VerificationReport.d.ts +23 -0
- package/lib/types/client/board/card-view.d.ts +113 -0
- package/lib/types/client/board/icons.d.ts +32 -0
- package/lib/types/client/board/overlay.d.ts +69 -0
- package/lib/types/client/board/preset-label.d.ts +22 -0
- package/lib/types/client/board/status-key.d.ts +15 -0
- package/lib/types/client/board/task-markdown.d.ts +19 -0
- package/lib/types/client/board-card-seat.d.ts +34 -0
- package/lib/types/client/host-api.d.ts +24 -1
- package/lib/types/client/index.d.ts +19 -0
- package/lib/types/client/locales.d.ts +141 -3
- package/lib/types/client/native-panel.d.ts +6 -20
- package/lib/types/client/schedule-zone.d.ts +47 -0
- package/lib/types/client/seats.d.ts +18 -0
- package/lib/types/client/service.d.ts +32 -0
- package/lib/types/client/settings-form.d.ts +16 -0
- package/lib/types/core/controller.d.ts +38 -1
- package/lib/types/core/degraded-reason.d.ts +46 -0
- package/lib/types/core/extension.d.ts +283 -0
- package/lib/types/core/handover.d.ts +13 -1
- package/lib/types/core/issue-form.d.ts +16 -0
- package/lib/types/core/package-name.d.ts +9 -0
- package/lib/types/core/schedule.d.ts +95 -20
- package/lib/types/core/subtask.d.ts +30 -11
- package/lib/types/core/tasks.d.ts +110 -5
- package/lib/types/core/use-cases/task-create.d.ts +2 -1
- package/lib/types/core/use-cases/task-schedule.d.ts +8 -4
- package/lib/types/core/use-cases/task-tag.d.ts +48 -0
- package/lib/types/core/use-cases/task-update.d.ts +5 -3
- package/lib/types/core/verification.d.ts +386 -0
- package/lib/types/core/workspace-target.d.ts +41 -0
- package/lib/types/host/agent-tools.d.ts +1 -1
- package/lib/types/host/extension-registry.d.ts +111 -0
- package/lib/types/host/llm-dispatch.d.ts +63 -0
- package/lib/types/host/verification-gate.d.ts +71 -0
- package/lib/types/host/verification-runner.d.ts +108 -0
- package/lib/types/host/workspace-evidence.d.ts +53 -0
- package/lib/types/host-ledger.d.ts +107 -11
- package/lib/types/host-runner.d.ts +99 -4
- package/lib/types/host-service.d.ts +114 -2
- package/lib/types/index.d.ts +80 -26
- package/lib/types/protocol.d.ts +53 -3
- package/lib/types/tool-surface.d.ts +71 -0
- package/package.json +27 -26
- package/src/client/PluginSettingsCard.tsx +9 -0
- package/src/client/TaskBoardSettingsCard.tsx +304 -65
- package/src/client/board/ClampedMarkdown.tsx +69 -0
- package/src/client/board/ConfirmDialog.tsx +7 -3
- package/src/client/board/EditTaskModal.tsx +5 -2
- package/src/client/board/LinkSubtaskModal.tsx +30 -15
- package/src/client/board/NewTaskModal.tsx +288 -151
- package/src/client/board/TagManagerModal.tsx +235 -0
- package/src/client/board/TaskBoard.tsx +259 -103
- package/src/client/board/TaskCard.tsx +238 -86
- package/src/client/board/TaskDetail.tsx +154 -59
- package/src/client/board/TaskForm.tsx +61 -6
- package/src/client/board/VerificationReport.tsx +203 -0
- package/src/client/board/card-view.ts +220 -0
- package/src/client/board/icons.tsx +89 -0
- package/src/client/board/overlay.tsx +189 -0
- package/src/client/board/preset-label.ts +44 -0
- package/src/client/board/status-key.ts +27 -0
- package/src/client/board/task-markdown.module.css +137 -0
- package/src/client/board/task-markdown.tsx +106 -0
- package/src/client/board-card-seat.ts +102 -0
- package/src/client/board-settings.module.css +66 -0
- package/src/client/board.module.css +602 -68
- package/src/client/host-api.ts +109 -6
- package/src/client/index.ts +48 -6
- package/src/client/locales.ts +290 -12
- package/src/client/native-panel.tsx +18 -2
- package/src/client/schedule-zone.ts +135 -0
- package/src/client/seats.tsx +58 -0
- package/src/client/service.ts +94 -0
- package/src/client/settings-card.module.css +31 -5
- package/src/client/settings-form.ts +27 -1
- package/src/core/controller.ts +101 -5
- package/src/core/degraded-reason.ts +81 -0
- package/src/core/extension.ts +376 -0
- package/src/core/freeze-snapshot.ts +2 -2
- package/src/core/handover.ts +16 -1
- package/src/core/issue-form.ts +19 -0
- package/src/core/package-name.ts +9 -0
- package/src/core/schedule.ts +211 -55
- package/src/core/store.ts +26 -1
- package/src/core/subtask.ts +77 -22
- package/src/core/tasks.ts +138 -10
- package/src/core/use-cases/task-create.ts +14 -2
- package/src/core/use-cases/task-parent.ts +3 -2
- package/src/core/use-cases/task-schedule.ts +17 -6
- package/src/core/use-cases/task-tag.ts +110 -0
- package/src/core/use-cases/task-update.ts +13 -4
- package/src/core/verification.ts +826 -0
- package/src/core/workspace-target.ts +59 -0
- package/src/host/agent-tools.ts +58 -24
- package/src/host/extension-registry.ts +509 -0
- package/src/host/llm-dispatch.ts +87 -0
- package/src/host/verification-gate.ts +331 -0
- package/src/host/verification-runner.ts +535 -0
- package/src/host/workspace-evidence.ts +176 -0
- package/src/host-ai.ts +15 -9
- package/src/host-ledger.ts +342 -51
- package/src/host-routes.ts +15 -2
- package/src/host-runner.ts +219 -20
- package/src/host-service.ts +346 -26
- package/src/index.ts +204 -16
- package/src/protocol.ts +122 -9
- package/src/tool-surface.ts +95 -0
- package/lib/types/host/run-guarded.d.ts +0 -39
- package/src/host/run-guarded.ts +0 -76
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label manager: the board's label row can only shrink through here.
|
|
3
|
+
*
|
|
4
|
+
* The filter row is the union of every label in use across the ledger, so a
|
|
5
|
+
* label created once — by an experiment, a pasted task, an import — stayed on
|
|
6
|
+
* the board forever: there was no way to rename a typo, merge two labels that
|
|
7
|
+
* mean the same thing, or remove one nobody uses. This dialog is that way out.
|
|
8
|
+
* It lists the labels with their usage counts and offers the two ledger-wide
|
|
9
|
+
* transitions, both of which go through the controller so the Host ledger stays
|
|
10
|
+
* the authority (and a shared board stays consistent for everyone watching it).
|
|
11
|
+
*
|
|
12
|
+
* Renaming onto a name already in use merges the two labels; the dialog says so
|
|
13
|
+
* before the edit is submitted. Deleting is confirmed first, and the
|
|
14
|
+
* confirmation names how many tasks the label is removed from.
|
|
15
|
+
*/
|
|
16
|
+
import { useMemo, useState } from 'react'
|
|
17
|
+
import type { BoardController } from '../../core/controller.ts'
|
|
18
|
+
import { TAG_NAME_MAX_LENGTH, collectKnownTags, type TaskRecord } from '../../core/tasks.ts'
|
|
19
|
+
import { t } from '../locales.ts'
|
|
20
|
+
import css from '../board.module.css'
|
|
21
|
+
import { ConfirmDialog } from './ConfirmDialog.tsx'
|
|
22
|
+
import { IconClose } from './icons.tsx'
|
|
23
|
+
import { useDialog, usePresence, type OverlayPhase } from './overlay.tsx'
|
|
24
|
+
|
|
25
|
+
/** One label as the manager lists it: its definition plus how many tasks carry it. */
|
|
26
|
+
export interface TagUsage {
|
|
27
|
+
name: string
|
|
28
|
+
promptPrefix?: string
|
|
29
|
+
/** Tasks carrying the label right now. */
|
|
30
|
+
count: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Labels in use, in board order (first occurrence wins, exactly like the
|
|
35
|
+
* filter row), each with its usage count.
|
|
36
|
+
* @param tasks - the whole ledger (board and archive).
|
|
37
|
+
* @returns one row per label.
|
|
38
|
+
*/
|
|
39
|
+
export function tagUsage(tasks: readonly TaskRecord[]): TagUsage[] {
|
|
40
|
+
const counts = new Map<string, number>()
|
|
41
|
+
for (const task of tasks) {
|
|
42
|
+
for (const tag of task.tags ?? []) counts.set(tag.name, (counts.get(tag.name) ?? 0) + 1)
|
|
43
|
+
}
|
|
44
|
+
return collectKnownTags(tasks).map(tag => ({
|
|
45
|
+
name: tag.name,
|
|
46
|
+
...(tag.promptPrefix === undefined ? {} : { promptPrefix: tag.promptPrefix }),
|
|
47
|
+
count: counts.get(tag.name) ?? 0,
|
|
48
|
+
}))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Label-manager overlay props. */
|
|
52
|
+
export interface TagManagerModalProps {
|
|
53
|
+
controller: BoardController
|
|
54
|
+
onClose: () => void
|
|
55
|
+
/** Which leg of the enter/exit motion pair the surface is on. */
|
|
56
|
+
phase?: OverlayPhase
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Label-manager overlay. */
|
|
60
|
+
export function TagManagerModal({ controller, onClose, phase = 'open' }: TagManagerModalProps) {
|
|
61
|
+
/** The label whose row is being renamed, and the draft name. */
|
|
62
|
+
const [editing, setEditing] = useState<string | undefined>(undefined)
|
|
63
|
+
const [draft, setDraft] = useState('')
|
|
64
|
+
const [busy, setBusy] = useState(false)
|
|
65
|
+
const [error, setError] = useState<string | undefined>(undefined)
|
|
66
|
+
const [confirmDelete, setConfirmDelete] = useState<string | undefined>(undefined)
|
|
67
|
+
const confirmPresence = usePresence(confirmDelete !== undefined)
|
|
68
|
+
// Escape and a backdrop press peel one layer at a time: an open row editor
|
|
69
|
+
// first, then the dialog — so a half-typed rename is never lost to the same
|
|
70
|
+
// key that closes the surface under it.
|
|
71
|
+
const dismiss = (): void => {
|
|
72
|
+
if (editing !== undefined) {
|
|
73
|
+
setEditing(undefined)
|
|
74
|
+
setError(undefined)
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
onClose()
|
|
78
|
+
}
|
|
79
|
+
const dialog = useDialog<HTMLDivElement>(dismiss, phase)
|
|
80
|
+
const snapshot = controller.getSnapshot()
|
|
81
|
+
const rows = useMemo(() => tagUsage(snapshot.tasks), [snapshot.tasks])
|
|
82
|
+
const deleting = rows.find(row => row.name === confirmDelete)
|
|
83
|
+
/** The label the typed name would merge into, when it is already in use. */
|
|
84
|
+
const mergesInto = editing === undefined ? undefined : rows.find(row => row.name === draft.trim() && row.name !== editing)
|
|
85
|
+
|
|
86
|
+
const startRename = (row: TagUsage): void => {
|
|
87
|
+
setEditing(row.name)
|
|
88
|
+
setDraft(row.name)
|
|
89
|
+
setError(undefined)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const submitRename = async (from: string): Promise<void> => {
|
|
93
|
+
const to = draft.trim()
|
|
94
|
+
if (to === '' || to === from) {
|
|
95
|
+
setEditing(undefined)
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
setBusy(true)
|
|
99
|
+
setError(undefined)
|
|
100
|
+
const accepted = await controller.renameTag(from, to)
|
|
101
|
+
setBusy(false)
|
|
102
|
+
if (accepted) {
|
|
103
|
+
setEditing(undefined)
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
setError(controller.getSnapshot().transportError ?? t('tags.renameFailed'))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const remove = async (name: string): Promise<void> => {
|
|
110
|
+
setBusy(true)
|
|
111
|
+
setError(undefined)
|
|
112
|
+
const accepted = await controller.deleteTag(name)
|
|
113
|
+
setBusy(false)
|
|
114
|
+
if (!accepted) setError(controller.getSnapshot().transportError ?? t('tags.deleteFailed'))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<div className={css.modalBackdrop} data-state={phase} onMouseDown={dialog.onMouseDown}>
|
|
120
|
+
<div
|
|
121
|
+
ref={dialog.attach}
|
|
122
|
+
className={css.modal}
|
|
123
|
+
role="dialog"
|
|
124
|
+
aria-modal="true"
|
|
125
|
+
aria-label={t('tags.title')}
|
|
126
|
+
tabIndex={-1}
|
|
127
|
+
>
|
|
128
|
+
<header className={css.modalHeader}>
|
|
129
|
+
<h2 className={css.modalTitle}>{t('tags.title')}</h2>
|
|
130
|
+
<button
|
|
131
|
+
type="button"
|
|
132
|
+
className={css.iconButton}
|
|
133
|
+
aria-label={t('detail.close')}
|
|
134
|
+
title={t('detail.close')}
|
|
135
|
+
onClick={onClose}
|
|
136
|
+
>
|
|
137
|
+
<IconClose size={16} />
|
|
138
|
+
</button>
|
|
139
|
+
</header>
|
|
140
|
+
|
|
141
|
+
<div className={css.modalBody}>
|
|
142
|
+
<p className={css.fieldHint}>{t('tags.hint')}</p>
|
|
143
|
+
{rows.length === 0
|
|
144
|
+
? <p className={css.detailText}>{t('tags.empty')}</p>
|
|
145
|
+
: (
|
|
146
|
+
<ul className={css.tagManageList}>
|
|
147
|
+
{rows.map(row => (
|
|
148
|
+
<li key={row.name} className={css.tagManageRow}>
|
|
149
|
+
{editing === row.name
|
|
150
|
+
? (
|
|
151
|
+
<>
|
|
152
|
+
<input
|
|
153
|
+
className={css.input + ' ' + css.tagManageInput}
|
|
154
|
+
value={draft}
|
|
155
|
+
maxLength={TAG_NAME_MAX_LENGTH}
|
|
156
|
+
spellCheck={false}
|
|
157
|
+
aria-label={t('tags.renameLabel', { name: row.name })}
|
|
158
|
+
onChange={event => { setDraft(event.target.value); setError(undefined) }}
|
|
159
|
+
onKeyDown={event => {
|
|
160
|
+
if (event.key === 'Enter') void submitRename(row.name)
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
<button
|
|
164
|
+
type="button"
|
|
165
|
+
className={css.primaryButton}
|
|
166
|
+
disabled={busy || draft.trim() === ''}
|
|
167
|
+
onClick={() => { void submitRename(row.name) }}
|
|
168
|
+
>
|
|
169
|
+
{t('tags.save')}
|
|
170
|
+
</button>
|
|
171
|
+
<button
|
|
172
|
+
type="button"
|
|
173
|
+
className={css.ghostButton}
|
|
174
|
+
disabled={busy}
|
|
175
|
+
onClick={() => { setEditing(undefined); setError(undefined) }}
|
|
176
|
+
>
|
|
177
|
+
{t('new.cancel')}
|
|
178
|
+
</button>
|
|
179
|
+
</>
|
|
180
|
+
)
|
|
181
|
+
: (
|
|
182
|
+
<>
|
|
183
|
+
<span className={css.tagManageName}>{row.name}</span>
|
|
184
|
+
<span className={css.tagManageCount}>{t('tags.usage', { count: String(row.count) })}</span>
|
|
185
|
+
<button
|
|
186
|
+
type="button"
|
|
187
|
+
className={css.ghostButton}
|
|
188
|
+
disabled={busy}
|
|
189
|
+
onClick={() => { startRename(row) }}
|
|
190
|
+
>
|
|
191
|
+
{t('tags.rename')}
|
|
192
|
+
</button>
|
|
193
|
+
<button
|
|
194
|
+
type="button"
|
|
195
|
+
className={css.ghostButton}
|
|
196
|
+
disabled={busy}
|
|
197
|
+
onClick={() => { setConfirmDelete(row.name) }}
|
|
198
|
+
>
|
|
199
|
+
{t('tags.delete')}
|
|
200
|
+
</button>
|
|
201
|
+
</>
|
|
202
|
+
)}
|
|
203
|
+
{editing === row.name && mergesInto !== undefined && (
|
|
204
|
+
<span className={css.tagManageMerge}>{t('tags.mergeHint', { name: mergesInto.name })}</span>
|
|
205
|
+
)}
|
|
206
|
+
</li>
|
|
207
|
+
))}
|
|
208
|
+
</ul>
|
|
209
|
+
)}
|
|
210
|
+
{error !== undefined && <p className={css.formError}>{error}</p>}
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<footer className={css.modalFooter}>
|
|
214
|
+
<button type="button" className={css.ghostButton} onClick={onClose}>{t('tags.done')}</button>
|
|
215
|
+
</footer>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
{confirmPresence.mounted && deleting !== undefined && (
|
|
220
|
+
<ConfirmDialog
|
|
221
|
+
title={t('tags.deleteTitle')}
|
|
222
|
+
message={t('tags.deleteConfirm', { name: deleting.name, count: String(deleting.count) })}
|
|
223
|
+
confirmLabel={t('tags.deleteOk')}
|
|
224
|
+
danger
|
|
225
|
+
phase={confirmPresence.phase}
|
|
226
|
+
onCancel={() => { setConfirmDelete(undefined) }}
|
|
227
|
+
onConfirm={() => {
|
|
228
|
+
setConfirmDelete(undefined)
|
|
229
|
+
void remove(deleting.name)
|
|
230
|
+
}}
|
|
231
|
+
/>
|
|
232
|
+
)}
|
|
233
|
+
</>
|
|
234
|
+
)
|
|
235
|
+
}
|