@fonlan/dsh-task-kanban 0.1.1 → 0.2.1
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 +12 -0
- package/lib/client.js +371 -122
- package/lib/client.js.map +1 -1
- package/lib/index.js +214 -24
- package/lib/types/server/models.d.ts +16 -0
- package/lib/types/server/runner.d.ts +39 -1
- package/lib/types/server/settings.d.ts +35 -7
- package/lib/types/shared/card.d.ts +12 -1
- package/package.json +5 -1
- package/src/client/api.ts +19 -1
- package/src/client/board.css +107 -16
- package/src/client/board.tsx +65 -29
- package/src/client/index.tsx +11 -9
- package/src/client/locales.ts +24 -4
- package/src/client/sections.tsx +244 -48
- package/src/server/models.ts +40 -0
- package/src/server/rpc.ts +33 -4
- package/src/server/runner.ts +168 -20
- package/src/server/settings.ts +52 -7
- package/src/shared/card.ts +13 -1
package/src/client/board.css
CHANGED
|
@@ -21,23 +21,29 @@
|
|
|
21
21
|
.kb-board-header {
|
|
22
22
|
display: flex;
|
|
23
23
|
align-items: center;
|
|
24
|
-
justify-content: space-between;
|
|
25
24
|
gap: 12px;
|
|
26
25
|
padding-bottom: 10px;
|
|
27
26
|
border-bottom: 1px solid rgba(128, 128, 128, 0.25);
|
|
28
27
|
flex: 0 0 auto;
|
|
29
28
|
}
|
|
30
|
-
|
|
31
|
-
.kb-board-
|
|
29
|
+
/* Left-aligned group: workspace selector + new-task button sit adjacent. */
|
|
30
|
+
.kb-board-title {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
gap: 8px;
|
|
34
|
+
min-width: 0;
|
|
35
|
+
flex: 0 1 auto;
|
|
36
|
+
}
|
|
37
|
+
.kb-board-title .kb-btn { flex: none; }
|
|
32
38
|
.kb-ws-select {
|
|
33
39
|
max-width: 320px;
|
|
34
40
|
min-width: 0;
|
|
35
41
|
flex: 0 1 auto;
|
|
36
42
|
padding: 6px 10px;
|
|
37
43
|
border-radius: 6px;
|
|
38
|
-
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
39
|
-
background: rgba(128, 128, 128, 0.12);
|
|
40
|
-
color: inherit;
|
|
44
|
+
border: 1px solid var(--dsw-alias-border-l2-darkmode-thin, var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35)));
|
|
45
|
+
background: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-1, rgba(128, 128, 128, 0.12)));
|
|
46
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
41
47
|
font-size: 14px;
|
|
42
48
|
}
|
|
43
49
|
.kb-btn {
|
|
@@ -266,17 +272,23 @@
|
|
|
266
272
|
text-overflow: ellipsis;
|
|
267
273
|
}
|
|
268
274
|
.kb-field-row { display: flex; align-items: center; gap: 10px; justify-content: space-between; }
|
|
275
|
+
/* Field labels in a row never wrap; selects get the remaining fixed width. */
|
|
276
|
+
.kb-field-row > span { white-space: nowrap; flex-shrink: 0; margin-bottom: 0; }
|
|
269
277
|
.kb-input {
|
|
270
278
|
width: 100%;
|
|
271
279
|
box-sizing: border-box;
|
|
272
280
|
padding: 7px 10px;
|
|
273
281
|
border-radius: 6px;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
282
|
+
/* Form controls follow the shell theme: DSH's input surface token plus a
|
|
283
|
+
theme-tuned border; the fallbacks cover shells without these tokens. */
|
|
284
|
+
border: 1px solid var(--dsw-alias-border-l2-darkmode-thin, var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35)));
|
|
285
|
+
background: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-1, rgba(128, 128, 128, 0.1)));
|
|
286
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
277
287
|
font-size: 13px;
|
|
278
288
|
}
|
|
279
289
|
.kb-input-number { width: 90px; }
|
|
290
|
+
/* All settings selects share one width so the column looks even. */
|
|
291
|
+
.kb-settings select.kb-input { width: 200px; flex: 0 0 200px; }
|
|
280
292
|
.kb-textarea { min-height: 110px; resize: vertical; font-family: inherit; }
|
|
281
293
|
.kb-modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
|
|
282
294
|
.kb-detail-section { margin-bottom: 12px; }
|
|
@@ -302,18 +314,97 @@
|
|
|
302
314
|
.kb-status-error { background: rgba(239, 68, 68, 0.3) !important; color: #f87171; }
|
|
303
315
|
.kb-status-merged { background: rgba(34, 197, 94, 0.3) !important; }
|
|
304
316
|
.kb-plan-summary { font-size: 13px; margin-bottom: 10px; }
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
.kb-plan-
|
|
317
|
+
/* Phase cards: each plan phase is a card with an ordered number (kept from the
|
|
318
|
+
parent <ol>) and three labeled sections (goal / sessions / conclusion) split
|
|
319
|
+
by section titles and thin divider lines. */
|
|
320
|
+
.kb-plan-phases { margin: 0; padding-left: 24px; }
|
|
321
|
+
.kb-plan-phase {
|
|
322
|
+
margin-bottom: 10px;
|
|
323
|
+
padding: 8px 10px;
|
|
324
|
+
background: rgba(128, 128, 128, 0.08);
|
|
325
|
+
border: 1px solid rgba(128, 128, 128, 0.2);
|
|
326
|
+
border-radius: 8px;
|
|
327
|
+
}
|
|
328
|
+
.kb-plan-phase-head {
|
|
329
|
+
display: flex;
|
|
330
|
+
gap: 8px;
|
|
331
|
+
align-items: baseline;
|
|
332
|
+
padding-bottom: 6px;
|
|
333
|
+
margin-bottom: 6px;
|
|
334
|
+
border-bottom: 1px solid rgba(128, 128, 128, 0.16);
|
|
335
|
+
}
|
|
309
336
|
.kb-plan-phase-title { font-weight: 600; font-size: 13px; }
|
|
310
337
|
.kb-plan-phase-id { font-size: 11px; opacity: 0.5; }
|
|
311
|
-
.kb-plan-phase-
|
|
338
|
+
.kb-plan-phase-body { display: flex; flex-direction: column; }
|
|
339
|
+
/* Section isolation: label on top, thin divider between adjacent sections. */
|
|
340
|
+
.kb-plan-phase-section { display: flex; flex-direction: column; }
|
|
341
|
+
.kb-plan-phase-section + .kb-plan-phase-section {
|
|
342
|
+
margin-top: 6px;
|
|
343
|
+
padding-top: 6px;
|
|
344
|
+
border-top: 1px solid rgba(128, 128, 128, 0.14);
|
|
345
|
+
}
|
|
346
|
+
.kb-plan-phase-section-title { font-size: 11px; opacity: 0.55; margin-bottom: 3px; }
|
|
347
|
+
.kb-plan-phase-goal { font-size: 12px; opacity: 0.85; white-space: pre-wrap; word-break: break-all; }
|
|
348
|
+
.kb-plan-phase-sessions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
349
|
+
.kb-plan-phase-conclusion { font-size: 12px; opacity: 0.85; white-space: pre-wrap; word-break: break-all; }
|
|
350
|
+
.kb-plan-phase-conclusion-item + .kb-plan-phase-conclusion-item { margin-top: 6px; }
|
|
351
|
+
/* Running phase keeps the blue highlight; completed phases get success color. */
|
|
352
|
+
.kb-plan-phase-current { border-color: rgba(59, 130, 246, 0.6); background: rgba(59, 130, 246, 0.08); }
|
|
353
|
+
.kb-plan-phase-current .kb-plan-phase-title { color: #60a5fa; }
|
|
354
|
+
.kb-plan-phase-completed { border-color: rgba(34, 197, 94, 0.45); background: rgba(34, 197, 94, 0.06); }
|
|
355
|
+
.kb-plan-phase-completed .kb-plan-phase-title { color: #4ade80; }
|
|
312
356
|
.kb-session-links { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
313
|
-
.kb-session-attempt { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
|
|
314
|
-
.kb-session-summary { font-size: 12px; opacity: 0.75; }
|
|
315
357
|
.kb-settings { display: flex; flex-direction: column; gap: 12px; max-width: 420px; }
|
|
316
358
|
.kb-settings-saved { font-size: 12px; color: #4ade80; }
|
|
359
|
+
.kb-settings-group { border-top: 1px solid rgba(128, 128, 128, 0.22); padding-top: 12px; }
|
|
360
|
+
.kb-settings-group-title { font-size: 12px; font-weight: 600; opacity: 0.9; margin-bottom: 10px; }
|
|
361
|
+
/* Settings card (设置 → 插件配置): mirrors the built-in plugin cards
|
|
362
|
+
(dsh-client-ui-settings-plugins PluginCard) — same surface, border, head
|
|
363
|
+
layout, and disclosure chevron, spelled with kb-settings-card prefixed
|
|
364
|
+
classes. The prefix deliberately does NOT reuse the board's `.kb-card*`
|
|
365
|
+
classes: the board card carries its own padding/cursor/user-select, and
|
|
366
|
+
sharing the root class would leak those onto the settings card. */
|
|
367
|
+
.kb-settings-card {
|
|
368
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
369
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
370
|
+
border-radius: 12px;
|
|
371
|
+
list-style: none;
|
|
372
|
+
transition: border-color .16s, background .16s;
|
|
373
|
+
}
|
|
374
|
+
.kb-settings-card:hover { border-color: var(--dsw-alias-label-dimmed); }
|
|
375
|
+
.kb-settings-card[data-open] {
|
|
376
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
377
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
378
|
+
}
|
|
379
|
+
.kb-settings-card-head {
|
|
380
|
+
appearance: none;
|
|
381
|
+
width: 100%;
|
|
382
|
+
font: inherit;
|
|
383
|
+
color: inherit;
|
|
384
|
+
text-align: left;
|
|
385
|
+
cursor: pointer;
|
|
386
|
+
background: transparent;
|
|
387
|
+
border: 0;
|
|
388
|
+
border-radius: 12px;
|
|
389
|
+
align-items: center;
|
|
390
|
+
gap: 12px;
|
|
391
|
+
padding: 14px 16px;
|
|
392
|
+
display: flex;
|
|
393
|
+
}
|
|
394
|
+
.kb-settings-card-head:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -2px; }
|
|
395
|
+
.kb-settings-card-headText { flex-direction: column; flex: 1; gap: 4px; min-width: 0; display: flex; }
|
|
396
|
+
.kb-settings-card-title { color: var(--dsw-alias-label-primary); font-size: 15px; font-weight: 600; line-height: 1.4; }
|
|
397
|
+
.kb-settings-card-sub { color: var(--dsw-alias-label-tertiary); font-size: 13px; line-height: 1.5; }
|
|
398
|
+
.kb-settings-card-chevron {
|
|
399
|
+
color: var(--dsw-alias-label-tertiary);
|
|
400
|
+
flex: none;
|
|
401
|
+
transition: transform .16s;
|
|
402
|
+
display: flex;
|
|
403
|
+
align-items: center;
|
|
404
|
+
justify-content: center;
|
|
405
|
+
}
|
|
406
|
+
.kb-settings-card-chevron[data-open] { transform: rotate(180deg); }
|
|
407
|
+
.kb-settings-card-body { border-top: 1px solid var(--dsw-alias-border-l2); margin: 0 16px; padding: 12px 0 8px; }
|
|
317
408
|
.kb-footer-action {
|
|
318
409
|
display: inline-flex;
|
|
319
410
|
align-items: center;
|
package/src/client/board.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
2
|
-
import type { KanbanCard, Lane } from '../shared/card'
|
|
2
|
+
import type { KanbanCard, Lane, PhaseAttempt, PlanPhase } from '../shared/card'
|
|
3
3
|
import { DROP_RULES, laneOf } from '../shared/lanes'
|
|
4
4
|
import { api, gatewaySkillList, type SkillOption } from './api'
|
|
5
5
|
import { exitBoard, getClient } from './kanban-state'
|
|
@@ -189,8 +189,6 @@ export function BoardRoot(props: BoardProps): JSX.Element {
|
|
|
189
189
|
<option key={w.workspaceId} value={w.path}>{w.title}</option>
|
|
190
190
|
))}
|
|
191
191
|
</select>
|
|
192
|
-
</div>
|
|
193
|
-
<div className="kb-board-actions">
|
|
194
192
|
<button type="button" className="kb-btn kb-btn-primary" onClick={() => setNewTaskOpen(true)}>{t('newTask')}</button>
|
|
195
193
|
</div>
|
|
196
194
|
</div>
|
|
@@ -328,13 +326,6 @@ function NewTaskModal({ t, workspaces, selectedPath, sessionId, onClose, onCreat
|
|
|
328
326
|
api.models()
|
|
329
327
|
.then((list) => { if (alive) setModels(list) })
|
|
330
328
|
.catch(() => { if (alive) setModels([]) })
|
|
331
|
-
api.settingsGet()
|
|
332
|
-
.then((s) => {
|
|
333
|
-
if (alive && s.defaultModel !== '') {
|
|
334
|
-
setModel(s.defaultModel)
|
|
335
|
-
}
|
|
336
|
-
})
|
|
337
|
-
.catch(() => undefined)
|
|
338
329
|
return () => { alive = false }
|
|
339
330
|
}, [])
|
|
340
331
|
|
|
@@ -564,14 +555,14 @@ function DetailPanel({ card, t, onClose, onChanged, onToast, onOpenSession }: De
|
|
|
564
555
|
<div className="kb-plan-summary">{card.plan.summary}</div>
|
|
565
556
|
<ol className="kb-plan-phases">
|
|
566
557
|
{card.plan.phases.map((phase, i) => (
|
|
567
|
-
<
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
558
|
+
<PhaseCard
|
|
559
|
+
key={phase.id}
|
|
560
|
+
phase={phase}
|
|
561
|
+
phaseIndex={i}
|
|
562
|
+
card={card}
|
|
563
|
+
t={t}
|
|
564
|
+
onOpenSession={onOpenSession}
|
|
565
|
+
/>
|
|
575
566
|
))}
|
|
576
567
|
</ol>
|
|
577
568
|
</div>
|
|
@@ -628,23 +619,68 @@ function DetailPanel({ card, t, onClose, onChanged, onToast, onOpenSession }: De
|
|
|
628
619
|
)
|
|
629
620
|
}
|
|
630
621
|
|
|
631
|
-
|
|
622
|
+
/** One plan phase rendered as a card with goal / sessions / conclusion sections. */
|
|
623
|
+
function PhaseCard({ phase, phaseIndex, card, t, onOpenSession }: {
|
|
624
|
+
phase: PlanPhase
|
|
632
625
|
phaseIndex: number
|
|
633
626
|
card: KanbanCard
|
|
634
|
-
t: (key: string) => string
|
|
627
|
+
t: (key: string, params?: Record<string, unknown>) => string
|
|
635
628
|
onOpenSession: (sessionId: string) => void
|
|
636
|
-
}): JSX.Element
|
|
629
|
+
}): JSX.Element {
|
|
637
630
|
const attempts = card.sessions.phases.filter((a) => a.phaseIndex === phaseIndex)
|
|
638
|
-
|
|
631
|
+
const summaries = attempts
|
|
632
|
+
.filter((a) => a.summary !== undefined && a.summary.trim() !== '')
|
|
633
|
+
.map((a) => a.summary as string)
|
|
634
|
+
const isCurrent = phaseIndex === card.currentPhase && card.status === 'running'
|
|
635
|
+
// A phase with at least one concluded attempt counts as completed.
|
|
636
|
+
const isCompleted = summaries.length > 0
|
|
637
|
+
const cls = 'kb-plan-phase'
|
|
638
|
+
+ (isCurrent ? ' kb-plan-phase-current' : '')
|
|
639
|
+
+ (isCompleted ? ' kb-plan-phase-completed' : '')
|
|
640
|
+
return (
|
|
641
|
+
<li className={cls}>
|
|
642
|
+
<div className="kb-plan-phase-head">
|
|
643
|
+
<span className="kb-plan-phase-title">{phase.title}</span>
|
|
644
|
+
<span className="kb-plan-phase-id">{phase.id}</span>
|
|
645
|
+
</div>
|
|
646
|
+
<div className="kb-plan-phase-body">
|
|
647
|
+
<div className="kb-plan-phase-section">
|
|
648
|
+
<div className="kb-plan-phase-section-title">{t('phaseGoal')}</div>
|
|
649
|
+
<div className="kb-plan-phase-goal">{phase.goal}</div>
|
|
650
|
+
</div>
|
|
651
|
+
{attempts.length > 0 && (
|
|
652
|
+
<div className="kb-plan-phase-section">
|
|
653
|
+
<div className="kb-plan-phase-section-title">{t('phaseSessions')}</div>
|
|
654
|
+
<PhaseSessions attempts={attempts} t={t} onOpenSession={onOpenSession} />
|
|
655
|
+
</div>
|
|
656
|
+
)}
|
|
657
|
+
{summaries.length > 0 && (
|
|
658
|
+
<div className="kb-plan-phase-section">
|
|
659
|
+
<div className="kb-plan-phase-section-title">{t('phaseConclusion')}</div>
|
|
660
|
+
<div className="kb-plan-phase-conclusion">
|
|
661
|
+
{summaries.map((s, idx) => (
|
|
662
|
+
<div key={idx} className="kb-plan-phase-conclusion-item">{s}</div>
|
|
663
|
+
))}
|
|
664
|
+
</div>
|
|
665
|
+
</div>
|
|
666
|
+
)}
|
|
667
|
+
</div>
|
|
668
|
+
</li>
|
|
669
|
+
)
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/** Open-session buttons for one phase's attempts (retries append more). */
|
|
673
|
+
function PhaseSessions({ attempts, t, onOpenSession }: {
|
|
674
|
+
attempts: PhaseAttempt[]
|
|
675
|
+
t: (key: string) => string
|
|
676
|
+
onOpenSession: (sessionId: string) => void
|
|
677
|
+
}): JSX.Element {
|
|
639
678
|
return (
|
|
640
|
-
<div className="kb-
|
|
679
|
+
<div className="kb-plan-phase-sessions">
|
|
641
680
|
{attempts.map((a) => (
|
|
642
|
-
<
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
</button>
|
|
646
|
-
{a.summary !== undefined && <span className="kb-session-summary">{a.summary}</span>}
|
|
647
|
-
</span>
|
|
681
|
+
<button key={a.sessionId} type="button" className="kb-btn kb-btn-small" onClick={() => onOpenSession(a.sessionId)}>
|
|
682
|
+
{t('openSession')} · {a.sessionId.slice(0, 13)}
|
|
683
|
+
</button>
|
|
648
684
|
))}
|
|
649
685
|
</div>
|
|
650
686
|
)
|
package/src/client/index.tsx
CHANGED
|
@@ -2,9 +2,9 @@ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
|
|
|
2
2
|
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
|
3
3
|
import type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'
|
|
4
4
|
import type {} from '@deepseek-ai/dsh-client-ui-layout/client'
|
|
5
|
-
import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
|
|
5
|
+
import type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'
|
|
6
6
|
import { BoardRoot } from './board'
|
|
7
|
-
import { KanbanFooterButton,
|
|
7
|
+
import { KanbanFooterButton, KanbanSettingsCard } from './sections'
|
|
8
8
|
import { LOCALE_NS, zh, en } from './locales'
|
|
9
9
|
import { setClient, setBoardRoot, bindSessionNavigation } from './kanban-state'
|
|
10
10
|
|
|
@@ -35,13 +35,15 @@ export function apply(ctx: ClientContext): void {
|
|
|
35
35
|
}, KanbanFooterButton as never),
|
|
36
36
|
)
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
// The plugin's own Settings Card (设置 → 插件配置) rides the `task-kanban`
|
|
39
|
+
// settings namespace: registering into the keyed `settings.plugin.item` slot
|
|
40
|
+
// with the namespace string makes the configurable-plugins tab dispatch the
|
|
41
|
+
// card next to the built-in ones (bash / agent loop / web search).
|
|
42
|
+
ctx.slots.inject('settings.plugin.item', () =>
|
|
39
43
|
ctx.slots.register({
|
|
40
|
-
name: 'settings.
|
|
41
|
-
|
|
42
|
-
order: 200,
|
|
43
|
-
label: () => t('settingsTitle'),
|
|
44
|
+
name: 'settings.plugin.item',
|
|
45
|
+
key: 'task-kanban',
|
|
44
46
|
locale: LOCALE_NS,
|
|
45
|
-
},
|
|
47
|
+
}, KanbanSettingsCard as never),
|
|
46
48
|
)
|
|
47
|
-
}
|
|
49
|
+
}
|
package/src/client/locales.ts
CHANGED
|
@@ -38,6 +38,9 @@ export const zh = {
|
|
|
38
38
|
plan: '实现方案',
|
|
39
39
|
summary: '摘要',
|
|
40
40
|
phases: '阶段',
|
|
41
|
+
phaseGoal: '目标',
|
|
42
|
+
phaseSessions: '会话',
|
|
43
|
+
phaseConclusion: '结论',
|
|
41
44
|
error: '错误',
|
|
42
45
|
requirementLabel: '需求文本',
|
|
43
46
|
requirementPlaceholder: '描述你要实现的需求……',
|
|
@@ -48,9 +51,16 @@ export const zh = {
|
|
|
48
51
|
modelPlaceholder: '(使用默认模型)',
|
|
49
52
|
noWorkspace: '没有可用工作区,请先在侧边栏添加',
|
|
50
53
|
refresh: '刷新',
|
|
51
|
-
settingsTitle: '
|
|
54
|
+
settingsTitle: '任务看板',
|
|
55
|
+
settingsDescription: '全局并行 worker 数与各会话类型的默认模型、推理强度、Agent 预设',
|
|
56
|
+
settingsExpand: '展开设置',
|
|
57
|
+
settingsCollapse: '收起设置',
|
|
52
58
|
maxParallelWorkers: '全局并行 worker 数',
|
|
53
|
-
|
|
59
|
+
settingsRefineGroup: '细化需求会话默认',
|
|
60
|
+
settingsPhaseGroup: 'Phase 实现会话默认',
|
|
61
|
+
reasoningEffort: '推理强度',
|
|
62
|
+
agentPreset: 'Agent 预设',
|
|
63
|
+
defaultOption: '(默认)',
|
|
54
64
|
saved: '已保存',
|
|
55
65
|
loadError: '加载任务失败',
|
|
56
66
|
noPlan: '该卡片还没有实现计划,请先点击"添加并细化"',
|
|
@@ -103,6 +113,9 @@ export const en = {
|
|
|
103
113
|
plan: 'Plan',
|
|
104
114
|
summary: 'Summary',
|
|
105
115
|
phases: 'Phases',
|
|
116
|
+
phaseGoal: 'Goal',
|
|
117
|
+
phaseSessions: 'Sessions',
|
|
118
|
+
phaseConclusion: 'Conclusion',
|
|
106
119
|
error: 'Error',
|
|
107
120
|
requirementLabel: 'Requirement',
|
|
108
121
|
requirementPlaceholder: 'Describe what you want to build…',
|
|
@@ -113,9 +126,16 @@ export const en = {
|
|
|
113
126
|
modelPlaceholder: '(use default model)',
|
|
114
127
|
noWorkspace: 'No workspaces available — add one in the sidebar first',
|
|
115
128
|
refresh: 'Refresh',
|
|
116
|
-
settingsTitle: 'Task Kanban
|
|
129
|
+
settingsTitle: 'Task Kanban',
|
|
130
|
+
settingsDescription: 'Global parallel workers and per-session-type defaults for model, reasoning effort, and agent preset',
|
|
131
|
+
settingsExpand: 'Show settings',
|
|
132
|
+
settingsCollapse: 'Hide settings',
|
|
117
133
|
maxParallelWorkers: 'Global parallel workers',
|
|
118
|
-
|
|
134
|
+
settingsRefineGroup: 'Refinement session defaults',
|
|
135
|
+
settingsPhaseGroup: 'Phase implementation defaults',
|
|
136
|
+
reasoningEffort: 'Reasoning effort',
|
|
137
|
+
agentPreset: 'Agent preset',
|
|
138
|
+
defaultOption: '(default)',
|
|
119
139
|
saved: 'Saved',
|
|
120
140
|
loadError: 'Failed to load tasks',
|
|
121
141
|
noPlan: 'This card has no plan yet — click "Add & Refine" first',
|