@fonlan/dsh-task-kanban 0.1.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 +21 -0
- package/README.md +45 -0
- package/cordis.patch.yml +3 -0
- package/lib/client.js +1128 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +1514 -0
- package/lib/types/index.d.ts +14 -0
- package/lib/types/server/git.d.ts +16 -0
- package/lib/types/server/models.d.ts +4 -0
- package/lib/types/server/prompts.d.ts +7 -0
- package/lib/types/server/rpc.d.ts +4 -0
- package/lib/types/server/runner.d.ts +84 -0
- package/lib/types/server/settings.d.ts +27 -0
- package/lib/types/server/task-store.d.ts +27 -0
- package/lib/types/server/tools.d.ts +11 -0
- package/lib/types/shared/card.d.ts +86 -0
- package/lib/types/shared/lanes.d.ts +9 -0
- package/lib/types/shared/plan.d.ts +12 -0
- package/package.json +105 -0
- package/src/client/api.ts +42 -0
- package/src/client/board.css +361 -0
- package/src/client/board.tsx +516 -0
- package/src/client/index.tsx +47 -0
- package/src/client/kanban-state.ts +104 -0
- package/src/client/locales.ts +127 -0
- package/src/client/sections.tsx +209 -0
- package/src/client/slot-augment.d.ts +15 -0
- package/src/index.ts +34 -0
- package/src/server/git.ts +68 -0
- package/src/server/models.ts +20 -0
- package/src/server/prompts.ts +54 -0
- package/src/server/rpc.ts +167 -0
- package/src/server/runner.ts +834 -0
- package/src/server/settings.ts +69 -0
- package/src/server/task-store.ts +128 -0
- package/src/server/tools.ts +131 -0
- package/src/shared/card.ts +115 -0
- package/src/shared/lanes.ts +43 -0
- package/src/shared/plan.ts +54 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/* @fonlan/dsh-task-kanban board styles (kb- prefixed, plain CSS) */
|
|
2
|
+
.kb-board {
|
|
3
|
+
height: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
padding: 12px 16px;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
color: var(--dsh-fg, #e6e6e6);
|
|
10
|
+
background: var(--dsh-bg, #141418);
|
|
11
|
+
font: 14px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
|
12
|
+
}
|
|
13
|
+
.kb-empty {
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
}
|
|
17
|
+
.kb-empty-text { opacity: 0.6; }
|
|
18
|
+
.kb-board-header {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
gap: 12px;
|
|
23
|
+
padding-bottom: 10px;
|
|
24
|
+
border-bottom: 1px solid rgba(128, 128, 128, 0.25);
|
|
25
|
+
flex: 0 0 auto;
|
|
26
|
+
}
|
|
27
|
+
.kb-board-actions { display: flex; gap: 8px; align-items: center; flex: none; }
|
|
28
|
+
.kb-board-actions .kb-btn { flex: none; }
|
|
29
|
+
.kb-ws-select {
|
|
30
|
+
max-width: 320px;
|
|
31
|
+
min-width: 0;
|
|
32
|
+
flex: 0 1 auto;
|
|
33
|
+
padding: 6px 10px;
|
|
34
|
+
border-radius: 6px;
|
|
35
|
+
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
36
|
+
background: rgba(128, 128, 128, 0.12);
|
|
37
|
+
color: inherit;
|
|
38
|
+
font-size: 14px;
|
|
39
|
+
}
|
|
40
|
+
.kb-btn {
|
|
41
|
+
padding: 6px 14px;
|
|
42
|
+
border-radius: 6px;
|
|
43
|
+
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
44
|
+
background: rgba(128, 128, 128, 0.12);
|
|
45
|
+
color: inherit;
|
|
46
|
+
font-size: 13px;
|
|
47
|
+
white-space: nowrap;
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
}
|
|
50
|
+
.kb-btn:hover { background: rgba(128, 128, 128, 0.22); }
|
|
51
|
+
.kb-btn:disabled { opacity: 0.5; cursor: default; }
|
|
52
|
+
.kb-btn-primary { background: #3b82f6; border-color: #3b82f6; color: #fff; }
|
|
53
|
+
.kb-btn-primary:hover { background: #2f6fe0; }
|
|
54
|
+
.kb-btn-danger { background: rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.5); color: #f87171; }
|
|
55
|
+
.kb-btn-small { padding: 2px 8px; font-size: 12px; }
|
|
56
|
+
.kb-lanes {
|
|
57
|
+
flex: 1 1 auto;
|
|
58
|
+
display: flex;
|
|
59
|
+
gap: 12px;
|
|
60
|
+
overflow-x: auto;
|
|
61
|
+
overflow-y: hidden;
|
|
62
|
+
padding-top: 10px;
|
|
63
|
+
min-height: 0;
|
|
64
|
+
}
|
|
65
|
+
.kb-lane {
|
|
66
|
+
flex: 1 1 0;
|
|
67
|
+
min-width: 220px;
|
|
68
|
+
max-width: 320px;
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
background: rgba(128, 128, 128, 0.07);
|
|
72
|
+
border-radius: 8px;
|
|
73
|
+
border: 1px solid rgba(128, 128, 128, 0.12);
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
}
|
|
76
|
+
.kb-lane-drop { border-style: dashed; border-color: rgba(59, 130, 246, 0.45); }
|
|
77
|
+
.kb-lane-head {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: space-between;
|
|
81
|
+
padding: 8px 10px;
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
font-size: 13px;
|
|
84
|
+
color: var(--dsh-fg-soft, #b8b8c0);
|
|
85
|
+
border-bottom: 1px solid rgba(128, 128, 128, 0.12);
|
|
86
|
+
flex: 0 0 auto;
|
|
87
|
+
}
|
|
88
|
+
.kb-lane-count {
|
|
89
|
+
background: rgba(128, 128, 128, 0.18);
|
|
90
|
+
border-radius: 10px;
|
|
91
|
+
padding: 0 8px;
|
|
92
|
+
font-size: 12px;
|
|
93
|
+
}
|
|
94
|
+
.kb-lane-body {
|
|
95
|
+
flex: 1 1 auto;
|
|
96
|
+
overflow-y: auto;
|
|
97
|
+
padding: 8px;
|
|
98
|
+
display: flex;
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
gap: 8px;
|
|
101
|
+
}
|
|
102
|
+
.kb-card {
|
|
103
|
+
background: rgba(128, 128, 128, 0.1);
|
|
104
|
+
border: 1px solid rgba(128, 128, 128, 0.2);
|
|
105
|
+
border-radius: 8px;
|
|
106
|
+
padding: 8px 10px;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
user-select: none;
|
|
109
|
+
}
|
|
110
|
+
.kb-card:hover { border-color: rgba(128, 128, 128, 0.45); }
|
|
111
|
+
.kb-card[draggable='true'] { cursor: grab; }
|
|
112
|
+
.kb-card-running { border-color: rgba(59, 130, 246, 0.6); }
|
|
113
|
+
.kb-card-error { border-color: rgba(239, 68, 68, 0.6); }
|
|
114
|
+
.kb-card-title { font-weight: 600; font-size: 13px; margin-bottom: 6px; word-break: break-all; }
|
|
115
|
+
.kb-card-meta { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; font-size: 12px; }
|
|
116
|
+
.kb-card-badge {
|
|
117
|
+
background: rgba(128, 128, 128, 0.2);
|
|
118
|
+
border-radius: 4px;
|
|
119
|
+
padding: 1px 6px;
|
|
120
|
+
}
|
|
121
|
+
.kb-card-running .kb-card-badge { background: rgba(59, 130, 246, 0.3); }
|
|
122
|
+
.kb-card-error .kb-card-badge { background: rgba(239, 68, 68, 0.3); }
|
|
123
|
+
.kb-card-phase { opacity: 0.8; }
|
|
124
|
+
.kb-card-model { opacity: 0.55; }
|
|
125
|
+
.kb-card-error-text { margin-top: 6px; font-size: 12px; color: #f87171; word-break: break-all; }
|
|
126
|
+
.kb-card-worktree { margin-top: 4px; font-size: 11px; opacity: 0.5; word-break: break-all; }
|
|
127
|
+
.kb-toast {
|
|
128
|
+
position: fixed;
|
|
129
|
+
left: 50%;
|
|
130
|
+
bottom: 24px;
|
|
131
|
+
transform: translateX(-50%);
|
|
132
|
+
background: rgba(30, 30, 36, 0.95);
|
|
133
|
+
border: 1px solid rgba(128, 128, 128, 0.4);
|
|
134
|
+
color: #eee;
|
|
135
|
+
padding: 8px 16px;
|
|
136
|
+
border-radius: 8px;
|
|
137
|
+
font-size: 13px;
|
|
138
|
+
z-index: 2147483000;
|
|
139
|
+
max-width: 70vw;
|
|
140
|
+
}
|
|
141
|
+
.kb-modal-backdrop {
|
|
142
|
+
position: fixed;
|
|
143
|
+
inset: 0;
|
|
144
|
+
background: rgba(0, 0, 0, 0.5);
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
z-index: 2147482900;
|
|
149
|
+
}
|
|
150
|
+
.kb-modal {
|
|
151
|
+
width: 460px;
|
|
152
|
+
max-width: 90vw;
|
|
153
|
+
max-height: 85vh;
|
|
154
|
+
overflow-y: auto;
|
|
155
|
+
background: #1c1c22;
|
|
156
|
+
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
157
|
+
border-radius: 12px;
|
|
158
|
+
padding: 18px;
|
|
159
|
+
color: #e6e6e6;
|
|
160
|
+
}
|
|
161
|
+
.kb-modal-wide { width: 640px; }
|
|
162
|
+
/* Task-detail bottom panel: docks at the bottom of the board page, fills the
|
|
163
|
+
full board width and exactly half of the board height (the lanes column
|
|
164
|
+
above flexes to the remaining space). */
|
|
165
|
+
.kb-detail-panel {
|
|
166
|
+
flex: 0 0 50%;
|
|
167
|
+
min-height: 0;
|
|
168
|
+
display: flex;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
margin-top: 10px;
|
|
171
|
+
background: #1c1c22;
|
|
172
|
+
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
173
|
+
border-radius: 12px;
|
|
174
|
+
overflow: hidden;
|
|
175
|
+
color: #e6e6e6;
|
|
176
|
+
}
|
|
177
|
+
.kb-detail-panel-head {
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
justify-content: space-between;
|
|
181
|
+
gap: 10px;
|
|
182
|
+
padding: 10px 14px;
|
|
183
|
+
border-bottom: 1px solid rgba(128, 128, 128, 0.2);
|
|
184
|
+
flex: 0 0 auto;
|
|
185
|
+
}
|
|
186
|
+
.kb-detail-panel-head .kb-modal-title { margin-bottom: 0; }
|
|
187
|
+
.kb-detail-panel-body {
|
|
188
|
+
flex: 1 1 auto;
|
|
189
|
+
min-height: 0;
|
|
190
|
+
overflow-y: auto;
|
|
191
|
+
padding: 14px;
|
|
192
|
+
}
|
|
193
|
+
.kb-detail-close {
|
|
194
|
+
flex: none;
|
|
195
|
+
width: 28px;
|
|
196
|
+
height: 28px;
|
|
197
|
+
display: inline-flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
justify-content: center;
|
|
200
|
+
border: 1px solid transparent;
|
|
201
|
+
border-radius: 6px;
|
|
202
|
+
background: transparent;
|
|
203
|
+
color: inherit;
|
|
204
|
+
font-size: 15px;
|
|
205
|
+
line-height: 1;
|
|
206
|
+
opacity: 0.75;
|
|
207
|
+
cursor: pointer;
|
|
208
|
+
}
|
|
209
|
+
.kb-detail-close:hover { background: rgba(128, 128, 128, 0.18); opacity: 1; }
|
|
210
|
+
.kb-modal-title { font-size: 16px; font-weight: 700; margin-bottom: 14px; display: flex; align-items: center; gap: 10px; }
|
|
211
|
+
.kb-field { display: block; margin-bottom: 12px; }
|
|
212
|
+
.kb-field > span { display: block; font-size: 12px; opacity: 0.75; margin-bottom: 4px; }
|
|
213
|
+
.kb-field-row { display: flex; align-items: center; gap: 10px; justify-content: space-between; }
|
|
214
|
+
.kb-input {
|
|
215
|
+
width: 100%;
|
|
216
|
+
box-sizing: border-box;
|
|
217
|
+
padding: 7px 10px;
|
|
218
|
+
border-radius: 6px;
|
|
219
|
+
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
220
|
+
background: rgba(128, 128, 128, 0.1);
|
|
221
|
+
color: inherit;
|
|
222
|
+
font-size: 13px;
|
|
223
|
+
}
|
|
224
|
+
.kb-input-number { width: 90px; }
|
|
225
|
+
.kb-textarea { min-height: 110px; resize: vertical; font-family: inherit; }
|
|
226
|
+
.kb-modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
|
|
227
|
+
.kb-detail-section { margin-bottom: 12px; }
|
|
228
|
+
.kb-detail-label { font-size: 12px; opacity: 0.65; margin-bottom: 4px; }
|
|
229
|
+
.kb-detail-text { white-space: pre-wrap; word-break: break-all; font-size: 13px; }
|
|
230
|
+
.kb-detail-error .kb-detail-text { color: #f87171; }
|
|
231
|
+
.kb-detail-status {
|
|
232
|
+
font-size: 12px;
|
|
233
|
+
font-weight: 600;
|
|
234
|
+
border-radius: 4px;
|
|
235
|
+
padding: 1px 8px;
|
|
236
|
+
background: rgba(128, 128, 128, 0.2);
|
|
237
|
+
}
|
|
238
|
+
.kb-status-running, .kb-status-merging { background: rgba(59, 130, 246, 0.3) !important; }
|
|
239
|
+
.kb-status-error { background: rgba(239, 68, 68, 0.3) !important; color: #f87171; }
|
|
240
|
+
.kb-status-merged { background: rgba(34, 197, 94, 0.3) !important; }
|
|
241
|
+
.kb-plan-summary { font-size: 13px; margin-bottom: 10px; }
|
|
242
|
+
.kb-plan-phases { margin: 0; padding-left: 20px; }
|
|
243
|
+
.kb-plan-phase { margin-bottom: 10px; }
|
|
244
|
+
.kb-plan-phase-current .kb-plan-phase-title { color: #60a5fa; }
|
|
245
|
+
.kb-plan-phase-head { display: flex; gap: 8px; align-items: baseline; }
|
|
246
|
+
.kb-plan-phase-title { font-weight: 600; font-size: 13px; }
|
|
247
|
+
.kb-plan-phase-id { font-size: 11px; opacity: 0.5; }
|
|
248
|
+
.kb-plan-phase-goal { font-size: 12px; opacity: 0.85; margin: 2px 0 6px; white-space: pre-wrap; }
|
|
249
|
+
.kb-session-links { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
250
|
+
.kb-session-attempt { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
|
|
251
|
+
.kb-session-summary { font-size: 12px; opacity: 0.75; }
|
|
252
|
+
.kb-settings { display: flex; flex-direction: column; gap: 12px; max-width: 420px; }
|
|
253
|
+
.kb-settings-saved { font-size: 12px; color: #4ade80; }
|
|
254
|
+
.kb-footer-action {
|
|
255
|
+
display: inline-flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
justify-content: center;
|
|
258
|
+
gap: 6px;
|
|
259
|
+
width: 32px;
|
|
260
|
+
height: 32px;
|
|
261
|
+
border-radius: 6px;
|
|
262
|
+
border: none;
|
|
263
|
+
background: transparent;
|
|
264
|
+
/* same foreground as the settings trigger (its trigger css uses this var) */
|
|
265
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
266
|
+
cursor: pointer;
|
|
267
|
+
}
|
|
268
|
+
.kb-footer-action:hover { background: rgba(128, 128, 128, 0.18); }
|
|
269
|
+
.kb-footer-action-active { background: rgba(59, 130, 246, 0.25); }
|
|
270
|
+
/* Wide mode borrows the settings trigger's metrics (34px tall, 14px label,
|
|
271
|
+
18px icon) so both controls read as siblings on the same line. */
|
|
272
|
+
.kb-footer-action-wide {
|
|
273
|
+
width: auto;
|
|
274
|
+
height: 34px;
|
|
275
|
+
padding: 0 8px;
|
|
276
|
+
border-radius: 12px;
|
|
277
|
+
font-size: 14px;
|
|
278
|
+
}
|
|
279
|
+
.kb-footer-action-wide .kb-footer-label {
|
|
280
|
+
font-size: 14px;
|
|
281
|
+
line-height: 22px;
|
|
282
|
+
}
|
|
283
|
+
@media (prefers-color-scheme: light) {
|
|
284
|
+
.kb-board { color: #1c1c22; background: #f5f5f7; }
|
|
285
|
+
.kb-modal { background: #ffffff; color: #1c1c22; }
|
|
286
|
+
.kb-detail-panel { background: #ffffff; color: #1c1c22; }
|
|
287
|
+
}
|
|
288
|
+
/* Same-line placement WITHOUT moving any DOM: the sidebar foot area becomes
|
|
289
|
+
a reversed flex row, so its LAST child (the settings area) renders on the
|
|
290
|
+
LEFT and the FIRST child (footer actions = the kanban button) on the RIGHT
|
|
291
|
+
— exactly "settings, then kanban". The settings trigger flexes to fill the
|
|
292
|
+
remaining width; the button keeps its content width. */
|
|
293
|
+
.kb-foot-row {
|
|
294
|
+
display: flex;
|
|
295
|
+
flex-direction: row-reverse;
|
|
296
|
+
align-items: stretch;
|
|
297
|
+
gap: 4px;
|
|
298
|
+
}
|
|
299
|
+
.kb-foot-row > div:first-child {
|
|
300
|
+
flex: none;
|
|
301
|
+
width: auto;
|
|
302
|
+
min-width: 0;
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: center;
|
|
305
|
+
}
|
|
306
|
+
.kb-foot-row > div:last-child {
|
|
307
|
+
flex: 1;
|
|
308
|
+
min-width: 0;
|
|
309
|
+
}
|
|
310
|
+
/* Rail (collapsed sidebar): column-reverse stacks the settings circle on top
|
|
311
|
+
and the kanban icon below it, both centered; the kanban button borrows the
|
|
312
|
+
settings trigger's rail chrome (36px circle) so the two match. */
|
|
313
|
+
.kb-foot-rail {
|
|
314
|
+
flex-direction: column-reverse;
|
|
315
|
+
align-items: center;
|
|
316
|
+
}
|
|
317
|
+
.kb-foot-rail .kb-footer-action {
|
|
318
|
+
width: 36px;
|
|
319
|
+
height: 36px;
|
|
320
|
+
border-radius: 50%;
|
|
321
|
+
margin: 8px 0 10px;
|
|
322
|
+
}
|
|
323
|
+
.kb-footer-label {
|
|
324
|
+
max-width: 110px;
|
|
325
|
+
overflow: hidden;
|
|
326
|
+
text-overflow: ellipsis;
|
|
327
|
+
white-space: nowrap;
|
|
328
|
+
}
|
|
329
|
+
/* Narrow screens (mobile drawer / auto-collapse breakpoint): the drawer's
|
|
330
|
+
foot area is ~256-280px but the footer actions row carries the kanban
|
|
331
|
+
button PLUS mobile-nav's drawer actions (Files / session log), which
|
|
332
|
+
together exceed the row and squeeze the settings trigger to zero width
|
|
333
|
+
(row-reverse overflows left, clipping the button). Below the shell's
|
|
334
|
+
auto-collapse breakpoint, stack the settings row above the actions and
|
|
335
|
+
let the actions wrap so nothing is squeezed or clipped. */
|
|
336
|
+
@media (max-width: 1023px) {
|
|
337
|
+
.kb-foot-row {
|
|
338
|
+
flex-direction: column-reverse;
|
|
339
|
+
align-items: stretch;
|
|
340
|
+
}
|
|
341
|
+
.kb-foot-row > div:first-child {
|
|
342
|
+
flex: none;
|
|
343
|
+
width: 100%;
|
|
344
|
+
display: flex;
|
|
345
|
+
flex-wrap: wrap;
|
|
346
|
+
justify-content: flex-start;
|
|
347
|
+
gap: 4px;
|
|
348
|
+
padding-top: 4px;
|
|
349
|
+
}
|
|
350
|
+
.kb-foot-row > div:last-child {
|
|
351
|
+
flex: none;
|
|
352
|
+
width: 100%;
|
|
353
|
+
}
|
|
354
|
+
/* The footer-actions entries are display:contents wrappers, so the kanban
|
|
355
|
+
button itself is a flex item of the wrapping actions row; pull it to the
|
|
356
|
+
first wrap position so it sits directly below the settings row (the
|
|
357
|
+
mobile-nav drawer actions follow on their own wrapped line). */
|
|
358
|
+
.kb-foot-row .kb-footer-action {
|
|
359
|
+
order: -1;
|
|
360
|
+
}
|
|
361
|
+
}
|