@goodandready/dsh-kanban 0.2.32 → 0.2.34

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/lib/client.js CHANGED
@@ -22,11 +22,6 @@ window.__ModuleLoader__.load({
22
22
  const ROW_CONFIG_KEY = PKG + '#' + ROW_ID
23
23
  const COLUMN_ORDER = ['backlog', 'in-progress', 'review', 'deploy', 'cleanup', 'done']
24
24
 
25
-
26
- /**
27
- * Neighbours for card repositioning. The store operates on relative neighbours
28
- * rather than numeric indexes: `afterId` above, `beforeId` below.
29
- */
30
25
  function neighboursFor(columnTasks, dragId, index) {
31
26
  const rest = (columnTasks || []).filter((t) => t.id !== dragId)
32
27
  const clamped = Math.max(0, Math.min(index, rest.length))
@@ -40,13 +35,6 @@ window.__ModuleLoader__.load({
40
35
  return (tasks || []).filter((t) => t.column === column)
41
36
  }
42
37
 
43
- /**
44
- * Task ordering within a column.
45
- *
46
- * `manual` — server-provided order: manual order with active tasks on top.
47
- * `old`/`new` sort by creation date while preserving project grouping
48
- * and "active work first".
49
- */
50
38
  function sortTasks(tasks, order) {
51
39
  const list = tasks || []
52
40
  if (order !== 'old' && order !== 'new') return list
@@ -67,22 +55,6 @@ window.__ModuleLoader__.load({
67
55
  return out
68
56
  }
69
57
 
70
- /**
71
- * Session task batch progress: sequence index and total count.
72
- *
73
- * Orders matching the agent execution order: active task first,
74
- * followed by queue time.
75
- *
76
- * @returns {Object<string, {at: number, total: number}>} keyed by task id
77
- */
78
- /**
79
- * Apply a single batch action across all selected tasks.
80
- *
81
- * Failures on individual tasks do not abort remaining tasks;
82
- * completed count is reported to the user.
83
- *
84
- * @returns {Promise<{done: number, failed: number}>}
85
- */
86
58
  async function applyToEach(ids, act) {
87
59
  let done = 0
88
60
  let failed = 0
@@ -92,12 +64,6 @@ window.__ModuleLoader__.load({
92
64
  return { done, failed }
93
65
  }
94
66
 
95
- /**
96
- * Remembered launch settings in browser localStorage.
97
- *
98
- * Stored per user browser rather than plugin settings. Handles storage
99
- * errors gracefully if localStorage is disabled or restricted.
100
- */
101
67
  const RECALL_KEY = 'dsh-kanban:launch:'
102
68
 
103
69
  function recallLaunch(board) {
@@ -114,13 +80,6 @@ window.__ModuleLoader__.load({
114
80
  } catch { /* storage unavailable */ }
115
81
  }
116
82
 
117
- /**
118
- * Re-apply remembered preset only if still available in active runtime.
119
- *
120
- * Avoids applying obsolete profiles or permission ranks removed from the build.
121
- *
122
- * @param {Array<string>} known valid choices
123
- */
124
83
  function stillOffered(value, known, fallback) {
125
84
  return typeof value === 'string' && (known || []).indexOf(value) >= 0 ? value : fallback
126
85
  }
@@ -142,14 +101,6 @@ window.__ModuleLoader__.load({
142
101
  return out
143
102
  }
144
103
 
145
- /**
146
- * Group column tasks by assignee.
147
- *
148
- * Unassigned group ('Nobody') is placed first to highlight available work,
149
- * followed alphabetically by assignee username.
150
- *
151
- * @returns {Array<{who: string, tasks: object[]}>}
152
- */
153
104
  function groupByAssignee(tasks) {
154
105
  const by = new Map()
155
106
  for (const task of tasks || []) {
@@ -168,11 +119,6 @@ window.__ModuleLoader__.load({
168
119
  return task.repo + '#' + task.issueNumber
169
120
  }
170
121
 
171
- /**
172
- * Project repository and issue number rendered separately.
173
- *
174
- * Issue number links directly to the remote issue.
175
- */
176
122
  function taskRef(task, t) {
177
123
  if (!task || !task.repo) return null
178
124
  const number = typeof task.issueNumber === 'number' ? '#' + task.issueNumber : ''
@@ -202,11 +148,6 @@ window.__ModuleLoader__.load({
202
148
  return parts.join(' · ')
203
149
  }
204
150
 
205
- /**
206
- * Compact plan summary line for card badge: "3 of 7 · writing tests".
207
- *
208
- * Only progress numbers and current item description are shown on cards.
209
- */
210
151
  function planLine(task, t) {
211
152
  const progress = task && task.plan && task.plan.progress
212
153
  if (!progress || !progress.total) return ''
@@ -215,7 +156,6 @@ window.__ModuleLoader__.load({
215
156
  return progress.text ? counter + ' · ' + progress.text : counter
216
157
  }
217
158
 
218
- /** Status badge text. Waiting indicator is rendered separately. */
219
159
  function stateLabel(task, t) {
220
160
  const state = task && task.state
221
161
  if (state === 'running') return t('state.running')
@@ -223,26 +163,12 @@ window.__ModuleLoader__.load({
223
163
  return ''
224
164
  }
225
165
 
226
- /**
227
- * Determine whether column is collapsed.
228
- *
229
- * Empty columns collapse automatically to save horizontal space;
230
- * explicit user toggle overrides automatic behavior.
231
- *
232
- * @param {object} column column data from board response
233
- * @param {object} manual map of column id -> boolean user preference
234
- */
235
166
  function isCollapsed(column, manual) {
236
167
  const own = manual && manual[column.id]
237
168
  if (own === true || own === false) return own
238
169
  return (column.count || 0) === 0
239
170
  }
240
171
 
241
- /**
242
- * Relative elapsed time string: "5m", "3h", "3d".
243
- *
244
- * Computed client-side with full ISO timestamp displayed on hover tooltip.
245
- */
246
172
  function agoText(now, then, t) {
247
173
  if (typeof then !== 'number' || then <= 0) return ''
248
174
  const delta = Math.max(0, now - then)
@@ -254,7 +180,6 @@ window.__ModuleLoader__.load({
254
180
  return t('time.day', { n: Math.floor(hours / 24) })
255
181
  }
256
182
 
257
- /** Date formatted without time. Year is included only when not the current year. */
258
183
  function shortDate(then) {
259
184
  if (typeof then !== 'number' || then <= 0) return ''
260
185
  try {
@@ -266,19 +191,11 @@ window.__ModuleLoader__.load({
266
191
  } catch { return '' }
267
192
  }
268
193
 
269
- /** Exact timestamp for tooltip. Empty tooltip if timestamp is invalid. */
270
194
  function exactAt(then) {
271
195
  if (typeof then !== 'number' || then <= 0) return ''
272
196
  try { return new Date(then).toLocaleString() } catch { return '' }
273
197
  }
274
198
 
275
- /**
276
- * Sync telemetry status message.
277
- *
278
- * Alerts user when synchronization has halted or encountered errors.
279
- *
280
- * @returns {{tone: 'ok'|'bad'|'idle', text: string, title: string}}
281
- */
282
199
  function syncLine(sync, now, t) {
283
200
  const state = (sync && sync.state) || 'never'
284
201
  if (state === 'running') return { tone: 'idle', text: t('sync.running'), title: '' }
@@ -303,13 +220,6 @@ window.__ModuleLoader__.load({
303
220
  }
304
221
  }
305
222
 
306
- /**
307
- * Accessible text color over label background color.
308
- *
309
- * Computes perceived brightness and picks black or white accordingly.
310
- *
311
- * @param {string} hex 6-character hex code without '#'
312
- */
313
223
  function readableOn(hex) {
314
224
  const n = parseInt(String(hex || ''), 16)
315
225
  if (!isFinite(n)) return ''
@@ -319,11 +229,6 @@ window.__ModuleLoader__.load({
319
229
  return (r * 299 + g * 587 + b * 114) / 1000 > 140 ? '#111' : '#fff'
320
230
  }
321
231
 
322
- /**
323
- * Color accent stripe on left border of card for priority.
324
- *
325
- * Only applies to `priority/*` labels. Tasks without priority display no stripe.
326
- */
327
232
  function priorityColor(task) {
328
233
  const values = (task && task.facets && task.facets.priority) || []
329
234
  for (const value of values) {
@@ -333,18 +238,12 @@ window.__ModuleLoader__.load({
333
238
  return ''
334
239
  }
335
240
 
336
- /** Tag style helper. Neutral style when color is not defined. */
337
241
  function tagStyle(task, name) {
338
242
  const hex = task && task.labelColors ? task.labelColors[name] : undefined
339
243
  if (!hex) return undefined
340
244
  return { background: '#' + hex, color: readableOn(hex), borderColor: 'transparent' }
341
245
  }
342
246
 
343
- /**
344
- * Render parsed task body tree safely using React elements.
345
- *
346
- * Constructs DOM elements rather than using dangerouslySetInnerHTML to prevent XSS.
347
- */
348
247
  function renderSpans(spans, keyBase) {
349
248
  return (spans || []).map((span, i) => {
350
249
  const key = keyBase + '-' + i
@@ -385,14 +284,6 @@ window.__ModuleLoader__.load({
385
284
  })
386
285
  }
387
286
 
388
- /**
389
- * Label namespace display title.
390
- *
391
- * Falls back to raw namespace name when no translation key exists.
392
- */
393
- /**
394
- * Column title: custom override if configured, otherwise localized default.
395
- */
396
287
  function columnTitle(col, t) {
397
288
  const own = col && col.name
398
289
  return own !== undefined && own !== '' ? own : t('column.' + (col && col.id))
@@ -404,11 +295,6 @@ window.__ModuleLoader__.load({
404
295
  return text === key ? ns : text
405
296
  }
406
297
 
407
- /**
408
- * Board title.
409
- *
410
- * Default 'main' and 'simple' boards use localized titles; custom board names are preserved verbatim.
411
- */
412
298
  function boardTitle(board, t) {
413
299
  const key = 'boardName.' + (board && board.id)
414
300
  const text = t(key)
@@ -434,15 +320,8 @@ window.__ModuleLoader__.load({
434
320
  }
435
321
  }
436
322
 
437
- /** Repository facet filter key matching backend dimension. */
438
323
  const REPO_FACET = 'repo'
439
324
 
440
- /**
441
- * Check whether task matches active facet filters.
442
- *
443
- * AND across namespaces, OR within each namespace.
444
- * Uses pre-parsed task.facets from server response.
445
- */
446
325
  function matchesFilters(task, selected) {
447
326
  const keys = Object.keys(selected || {})
448
327
  for (const ns of keys) {
@@ -456,14 +335,12 @@ window.__ModuleLoader__.load({
456
335
  return true
457
336
  }
458
337
 
459
- /** True if any filter is active. */
460
338
  function anySelected(selected) {
461
339
  const keys = Object.keys(selected || {})
462
340
  for (const ns of keys) if ((selected[ns] || []).length > 0) return true
463
341
  return false
464
342
  }
465
343
 
466
- /** Toggle filter value, returning a new map for React immutability. */
467
344
  function toggleValue(selected, ns, value) {
468
345
  const current = (selected || {})[ns] || []
469
346
  const next = current.indexOf(value) >= 0
@@ -475,7 +352,6 @@ window.__ModuleLoader__.load({
475
352
  return out
476
353
  }
477
354
 
478
- /** Human-readable explanation for empty state or error. */
479
355
  function errorKey(error) {
480
356
  switch (error) {
481
357
  case 'gitea-absent': return 'error.giteaAbsent'
@@ -492,11 +368,6 @@ window.__ModuleLoader__.load({
492
368
  }
493
369
  }
494
370
 
495
- /**
496
- * Open session conversation in chat panel.
497
- *
498
- * @returns {boolean} true if session opened successfully
499
- */
500
371
  function openSession(ctx, sessionId) {
501
372
  if (!sessionId) return false
502
373
  const sessions = ctx && typeof ctx.get === 'function' ? ctx.get('sessions') : undefined
@@ -509,7 +380,6 @@ window.__ModuleLoader__.load({
509
380
  }
510
381
  }
511
382
 
512
- /** Repository option label with open issue count; marks archived repositories. */
513
383
  function repoOption(r, t) {
514
384
  const full = r.fullName || ((r.owner || '') + '/' + (r.repo || ''))
515
385
  const parts = [full]
@@ -518,16 +388,12 @@ window.__ModuleLoader__.load({
518
388
  return parts.join(' ')
519
389
  }
520
390
 
521
- /** Parse 'owner/repo' string into separate parts. */
522
391
  function splitFullName(fullName) {
523
392
  const parts = String(fullName || '').split('/')
524
393
  if (parts.length !== 2 || parts[0] === '' || parts[1] === '') return undefined
525
394
  return { owner: parts[0], repo: parts[1] }
526
395
  }
527
396
 
528
- /**
529
- * Filter cards by client-side text search query: title, repo, issue number.
530
- */
531
397
  function matchesQuery(task, query) {
532
398
  const needle = String(query || '').trim().toLowerCase()
533
399
  if (needle === '') return true
@@ -540,7 +406,6 @@ window.__ModuleLoader__.load({
540
406
  return hay.indexOf(needle) >= 0
541
407
  }
542
408
 
543
- /** Retrieve session ID for header chip. */
544
409
  function chipSessionId(props, session) {
545
410
  return String((props && props.sessionId) || (session && (session.sessionId || session.id)) || '').trim()
546
411
  }
@@ -554,7 +419,6 @@ window.__ModuleLoader__.load({
554
419
  chipSessionId, matchesQuery, splitFullName, repoOption, openSession, COLUMN_ORDER,
555
420
  }
556
421
 
557
-
558
422
  function createTimeoutSignal(ms) {
559
423
  const sig = typeof AbortSignal !== 'undefined' ? AbortSignal : (typeof globalThis !== 'undefined' ? globalThis.AbortSignal : undefined)
560
424
  if (sig && typeof sig.timeout === 'function') {
@@ -689,183 +553,7 @@ window.__ModuleLoader__.load({
689
553
  return () => clearTimer(timer)
690
554
  }
691
555
 
692
-
693
- const css =
694
- '.dkb-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:14px 16px;display:flex;flex-direction:column;gap:8px;margin-bottom:12px}' +'.dkb-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px;padding-bottom:4px;border-bottom:1px solid var(--dsw-alias-border-l2)}' +'.dkb-section-badge{font-size:11px;font-weight:500;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}' +'.dkb-section-badge-ok{border-color:var(--dsw-alias-state-success-secondary,#34d399);color:var(--dsw-alias-state-success-primary,#059669);background:var(--dsw-alias-state-success-secondary,rgba(16,185,129,0.1))}' +
695
- '.dkb-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none}' +
696
- '.dkb-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}' +
697
- '.dkb-page{padding:0}' +
698
- '.dkb-page .dkb-body{border-top:none;margin:0}' +
699
- '.dkb-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 16px}' +
700
- '.dkb-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}' +
701
- '.dkb-title{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}' +
702
- '.dkb-sub{color:var(--dsw-alias-label-secondary);font-size:13px}' +
703
- '.dkb-chevron{color:var(--dsw-alias-label-secondary);display:inline-flex;align-items:center;justify-content:center;flex:none;transition:transform .16s}' +
704
- '.dkb-chevronOpen{transform:rotate(180deg)}' +
705
- '.dkb-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}' +
706
- '.dkb-group{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:14px 0 2px}' +
707
- '.dkb-field{display:flex;flex-direction:column;gap:6px;padding:10px 0}' +
708
- '.dkb-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}' +
709
- '.dkb-hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}' +
710
- '.dkb-input{height:34px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;box-sizing:border-box;width:100%}' +
711
- '.dkb-area{min-height:96px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:8px 12px;font-size:13px;box-sizing:border-box;width:100%;resize:vertical;font:inherit}' +
712
- '.dkb-input:disabled,.dkb-area:disabled{opacity:.55}' +
713
- '.dkb-foot{border-top:1px solid var(--dsw-alias-border-l2);display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px}' +
714
- '.dkb-footSplit{justify-content:space-between}' +
715
- '.dkb-footLeft{display:flex;align-items:center;gap:8px}' +
716
- '.dkb-note{min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary)}' +
717
- '.dkb-failed{min-width:0;color:var(--dsw-alias-state-error-primary);flex:1;margin:0;font-size:12px;line-height:1.5}' +
718
- '.dkb-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}' +
719
- '.dkb-discard{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:5px 14px;font-size:13px;color:var(--dsw-alias-label-secondary);background:transparent}' +
720
- '.dkb-discard:disabled,.dkb-save:disabled{opacity:.4;cursor:default}' +
721
- '.dkb-entry-clone{align-items:center;gap:8px;display:flex}' +
722
- '.dkb-entry-clone[data-active]{font-weight:600}' +
723
- '.dkb-entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}' +
724
- '.dkb-entryLabel{text-overflow:ellipsis;overflow:hidden}' +
725
- '[data-dsh-frame][data-sidebar-collapsed] .dkb-entryLabel{display:none}' +
726
- '[data-pane=conversation],[class*=centerCol]{position:relative}' +
727
- '[data-dsh-kanban-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}' +
728
- 'html[data-dsh-kanban-active]:not([data-dsh-ssh-active]) [data-dsh-kanban-view]{display:block}' +
729
- 'html[data-dsh-kanban-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-kanban-view]),' +
730
- 'html[data-dsh-kanban-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-kanban-view]){display:none!important}' +
731
- '.dkb-screen{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 56px;display:flex}' +
732
- '.dkb-bar{flex:none;align-items:center;gap:8px;display:flex;flex-wrap:wrap}' +
733
- '.dkb-bar .dkb-input,.dkb-bar .dkb-search,.dkb-bar .dkb-save,.dkb-bar .dkb-discard,.dkb-bar .dkb-facetHead,.dkb-bar .dkb-back{height:30px;box-sizing:border-box;padding-top:0;padding-bottom:0;border-radius:8px;font-size:13px;line-height:28px;display:inline-flex;align-items:center}' +
734
- '.dkb-bar .dkb-facet{display:inline-flex}' +
735
- '.dkb-back{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;align-items:center;gap:6px;padding:4px 10px;font-size:13px;display:flex;flex:none}' +
736
- '.dkb-back:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}' +
737
- '.dkb-backIcon{align-items:center;display:flex}' +
738
- '.dkb-archive{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:8px}' +
739
- '.dkb-archiveList{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}' +
740
- '.dkb-archiveRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;align-items:center;gap:12px;padding:8px 12px;display:flex}' +
741
- '.dkb-start{display:contents}' +
742
- '.dkb-pack{color:var(--dsw-alias-label-secondary)}' +
743
- '.dkb-who{color:var(--dsw-alias-label-secondary)}' +
744
- '.dkb-sameSession{outline:1px solid var(--dsw-alias-label-secondary);outline-offset:1px}' +
745
- '.dkb-waitCount{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:0 10px;height:30px;cursor:pointer;color:var(--dsw-alias-label-primary)}' +
746
- '.dkb-archiveOpen{background:none;border:0;padding:0;text-align:left;cursor:pointer;font:inherit}' +
747
- '.dkb-archiveTitle{flex:1;font-size:13px;color:var(--dsw-alias-label-primary)}' +
748
- '.dkb-urgent{border-left-width:3px;border-left-style:solid;padding-left:9px}' +
749
- '.dkb-cardMenu{position:relative;align-self:flex-start;opacity:0;transition:opacity .12s}' +
750
- '.dkb-taskCard:hover .dkb-cardMenu,.dkb-taskCard:focus-within .dkb-cardMenu,.dkb-taskCard:focus-visible .dkb-cardMenu{opacity:1}' +
751
- '.dkb-groupHead{appearance:none;width:100%;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:0;border-top:1px solid var(--dsw-alias-border-l2);align-items:center;gap:6px;padding:8px 2px 4px;font-size:11px;font-weight:600;display:flex}' +
752
- '.dkb-groupHead:first-child{border-top:0;padding-top:2px}' +
753
- '.dkb-groupHead:hover{color:var(--dsw-alias-label-primary)}' +
754
- '.dkb-groupCount{margin-left:auto;color:var(--dsw-alias-label-tertiary);font-weight:400}' +
755
- '.dkb-shown{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;flex:none}' +
756
- '.dkb-moveBtn{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-tertiary);background:0 0;border:0;padding:0;font-size:11px;text-decoration:underline dotted}' +
757
- '.dkb-moveBtn:hover{color:var(--dsw-alias-label-primary)}' +
758
- '.dkb-taskCard:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}' +
759
- '.dkb-sync{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;flex:none}' +
760
- '.dkb-syncBad{color:var(--dsw-alias-state-error-primary,#e5534b);cursor:help}' +
761
- '.dkb-facet{position:relative;flex:none}' +
762
- '.dkb-facetHead{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px 10px;font-size:13px;white-space:nowrap}' +
763
- '.dkb-facetHead:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}' +
764
- '.dkb-facetOn{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-interactive-bg-hover)}' +
765
- '.dkb-facetList{position:absolute;top:calc(100% + 4px);left:0;z-index:60;min-width:180px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;box-shadow:var(--dsw-shadow-lv2);padding:6px;display:flex;flex-direction:column;gap:2px}' +
766
- '.dkb-facetRow{align-items:center;gap:8px;padding:4px 6px;border-radius:6px;font-size:13px;cursor:pointer;display:flex}' +
767
- '.dkb-facetRow:hover{background:var(--dsw-alias-interactive-bg-hover)}' +
768
- '.dkb-facetName{flex:1;color:var(--dsw-alias-label-primary)}' +
769
- '.dkb-barTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700;margin-right:auto}' +
770
- '.dkb-cols{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;gap:12px;min-height:0;padding-bottom:6px;display:flex;overflow:auto hidden}' +
771
- '.dkb-cols::-webkit-scrollbar{height:10px}' +
772
- '.dkb-cols::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}' +
773
- '.dkb-cols::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid transparent;border-radius:999px}' +
774
- '.dkb-col{flex:1 1 220px;min-width:220px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}' +
775
- '.dkb-colOver{border-color:var(--dsw-alias-border-l3)}' +
776
- '.dkb-colHead{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}' +
777
- '.dkb-colHead:hover{background:var(--dsw-alias-interactive-bg-hover)}' +
778
- '.dkb-colShut{flex:0 0 auto;min-width:0;width:40px}' +
779
- '.dkb-colShut .dkb-colHead{writing-mode:vertical-rl;height:100%;width:auto;padding:12px 10px;justify-content:flex-start;gap:10px}' +
780
- '.dkb-colShut .dkb-colHead .dkb-dot{writing-mode:horizontal-tb}' +
781
- '.dkb-colShut .dkb-count{writing-mode:horizontal-tb}' +
782
- '.dkb-dot{border-radius:50%;flex:none;width:8px;height:8px}' +
783
- '.dkb-dot[data-col=backlog]{background:var(--dsw-alias-label-tertiary)}' +
784
- '.dkb-dot[data-col=in-progress]{background:var(--dsw-alias-state-warn-primary)}' +
785
- '.dkb-dot[data-col=review]{background:var(--dsw-alias-state-business-primary)}' +
786
- '.dkb-dot[data-col=deploy]{background:var(--dsw-alias-state-business-primary)}' +
787
- '.dkb-dot[data-col=cleanup]{background:var(--dsw-alias-label-tertiary)}' +
788
- '.dkb-dot[data-col=done]{background:var(--dsw-alias-state-success-primary)}' +
789
- '.dkb-colName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}' +
790
- '.dkb-count{min-width:20px;text-align:center;color:var(--dsw-alias-bg-base);background:var(--dsw-alias-label-tertiary);border-radius:999px;flex:none;padding:1px 8px;font-size:12px;font-weight:600}' +
791
- '.dkb-count[data-col=in-progress]{background:var(--dsw-alias-state-warn-primary)}' +
792
- '.dkb-count[data-col=review]{background:var(--dsw-alias-state-business-primary)}' +
793
- '.dkb-count[data-col=deploy]{background:var(--dsw-alias-state-business-primary)}' +
794
- '.dkb-count[data-col=done]{background:var(--dsw-alias-state-success-primary)}' +
795
- '.dkb-countOver{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-inverted,#fff)}' +
796
- '.dkb-overdue{border-color:var(--dsw-alias-state-error-primary)}' +
797
- '.dkb-dueOver{color:var(--dsw-alias-state-error-primary);font-weight:600}' +
798
- '.dkb-list{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}' +
799
- '.dkb-empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}' +
800
- '.dkb-taskCard{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}' +
801
- '.dkb-taskCard:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}' +
802
- '.dkb-taskTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}' +
803
- '.dkb-mdBody{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.55;display:flex;flex-direction:column;gap:8px;max-height:46vh;overflow-y:auto}' +
804
- '.dkb-mdPara{margin:0;overflow-wrap:anywhere}' +
805
- '.dkb-mdHead{color:var(--dsw-alias-label-primary);font-weight:700;margin:6px 0 0;line-height:1.35}' +
806
- '.dkb-mdHead1{font-size:15px}' +
807
- '.dkb-mdHead2{font-size:14px}' +
808
- '.dkb-mdHead3{font-size:13px;color:var(--dsw-alias-label-secondary)}' +
809
- '.dkb-mdList{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:3px}' +
810
- '.dkb-mdCode{margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);font-size:12px;overflow-x:auto;white-space:pre}' +
811
- '.dkb-mdQuote{margin:0;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary)}' +
812
- '.dkb-mdRule{border:0;border-top:1px solid var(--dsw-alias-border-l2);margin:2px 0;width:100%}' +
813
- '.dkb-code{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:4px;padding:0 4px;font-size:12px}' +
814
- '.dkb-issueLink{color:var(--dsw-alias-label-secondary)}' +
815
- '.dkb-taskHead{align-items:center;gap:6px;flex-wrap:wrap;display:flex}' +
816
- '.dkb-ref{align-items:baseline;gap:5px;min-width:0;display:inline-flex}' +
817
- '.dkb-refRepo{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:1px 7px;font-size:11px;font-weight:600}' +
818
- '.dkb-refNum{flex:none;color:var(--dsw-alias-label-tertiary);font-size:11px;font-family:var(--dsw-font-family-mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.02em}' +
819
- '.dkb-refLink{text-decoration:none}' +
820
- '.dkb-refLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}' +
821
- '.dkb-taskRef{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}' +
822
- '.dkb-planLine{color:var(--dsw-alias-label-secondary);font-size:11px;line-height:1.35;overflow:hidden;-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box}' +
823
- '.dkb-state{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:0 5px;font-size:10px;line-height:16px}' +
824
- '.dkb-stateLive{border-color:var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);font-weight:600}' +
825
- '.dkb-batchList{list-style:none;margin:0;padding:0;max-height:200px;overflow-y:auto;display:flex;flex-direction:column;gap:4px}' +
826
- '.dkb-batchRow{align-items:baseline;gap:8px;font-size:13px;color:var(--dsw-alias-label-primary);display:flex}' +
827
- '.dkb-pick{margin:0;flex:none;opacity:0;transition:opacity .12s}' +
828
- '.dkb-taskCard:hover .dkb-pick,.dkb-taskCard:focus-within .dkb-pick,.dkb-pickOn{opacity:1}' +
829
- '.dkb-toChat{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border:0;padding:0;font-size:11px;text-decoration:underline dotted}' +
830
- '.dkb-toChat:hover{color:var(--dsw-alias-label-primary)}' +
831
- '.dkb-planList{display:flex;flex-direction:column;gap:4px;margin:0;padding:0;list-style:none}' +
832
- '.dkb-planItem{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:baseline}' +
833
- '.dkb-planItem.dkb-planDone{color:var(--dsw-alias-label-tertiary);text-decoration:line-through}' +
834
- '.dkb-planItem.dkb-planActive{color:var(--dsw-alias-label-primary);font-weight:600;text-decoration:none}' +
835
- '.dkb-planMark{flex:none;width:14px;text-align:center}' +
836
- '.dkb-tags{display:flex;flex-wrap:wrap;gap:4px}' +
837
- '.dkb-waiting{color:var(--dsw-alias-state-warn-primary);font-weight:600}' +
838
- '.dkb-waitDot{border-radius:50%;flex:none;width:8px;height:8px;background:var(--dsw-alias-state-warn-primary);display:inline-block}' +
839
- '.dkb-tag{white-space:nowrap;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border:1px solid transparent;border-radius:999px;padding:1px 7px;font-size:11px;line-height:1.5;font-weight:500}' +
840
- '.dkb-modal{position:absolute;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.4));display:flex;align-items:center;justify-content:center;padding:24px 24px 84px;box-sizing:border-box;z-index:70}' +
841
- '.dkb-panel{width:min(720px,100%);max-height:100%;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;box-sizing:border-box;overflow-y:auto;display:flex;flex-direction:column;gap:12px}' +
842
- '@media (min-width: 960px){.dkb-panelWide{width:min(1100px,96%)}.dkb-drawerGrid{display:grid;grid-template-columns:300px 1fr;gap:20px;align-items:start}}' +
843
- '.dkb-drawerSidebar{display:flex;flex-direction:column;gap:12px;border-right:1px solid var(--dsw-alias-border-l2);padding-right:16px}' +
844
- '.dkb-drawerMain{display:flex;flex-direction:column;gap:12px;min-width:0}' +
845
- '.dkb-panelBody{white-space:pre-wrap;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5;margin:0}' +
846
- '.dkb-log{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}' +
847
- '.dkb-logRow{color:var(--dsw-alias-label-secondary);font-size:12px}' +
848
- '.dkb-dialog{position:absolute;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.4));display:flex;align-items:center;justify-content:center;z-index:80}' +
849
- '.dkb-dialogBox{width:min(560px,94%);max-height:86%;overflow-y:auto;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;display:flex;flex-direction:column;gap:10px}' +
850
- '.dkb-issue{appearance:none;font:inherit;text-align:left;cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 10px;color:var(--dsw-alias-label-primary);font-size:13px}' +
851
- '.dkb-issueUsed{opacity:.5}' +
852
- '.dkb-row{display:flex;gap:8px;align-items:center}' +
853
- '.dkb-search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 240px;padding:6px 10px;font-size:13px}' +
854
- '.dkb-search::placeholder{color:var(--dsw-alias-label-tertiary)}' +
855
- '.dkb-slot{height:2px;border-radius:2px;background:transparent;flex:none}' +
856
- '.dkb-slotOn{background:var(--dsw-alias-state-business-primary)}' +
857
- '.dkb-danger{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;padding:5px 14px;font-size:13px;color:var(--dsw-alias-state-error-primary);background:transparent}' +
858
- '.dkb-danger:hover{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-bg-base)}' +
859
- '.dkb-quickFilterBar{display:flex;gap:6px;align-items:center;flex-wrap:wrap;padding:4px 0}' +
860
- '.dkb-filterChip{appearance:none;font:inherit;cursor:pointer;background:var(--dsw-alias-interactive-bg-hover);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:3px 10px;font-size:12px;color:var(--dsw-alias-label-secondary);transition:all .15s}' +
861
- '.dkb-filterChip:hover{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}' +
862
- '.dkb-filterChipActive{background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary-inverted,#fff);border-color:transparent;font-weight:600}' +
863
- '.dkb-epicTag{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary,#0969da);font-weight:600}' +
864
- '.dkb-progressBar{height:4px;background:var(--dsw-alias-border-l2);border-radius:2px;overflow:hidden;margin:4px 0}' +
865
- '.dkb-progressFill{height:100%;background:var(--dsw-alias-state-success-primary,#16a34a);transition:width .2s}' +
866
- '.dkb-consolePre{background:var(--dsw-alias-bg-layer-1,#0d1117);color:var(--dsw-alias-state-business-primary,#58a6ff);border:1px solid var(--dsw-alias-border-l2);padding:12px;border-radius:8px;font-family:monospace;font-size:11px;max-height:260px;overflow-y:auto;white-space:pre-wrap}'
867
-
868
-
556
+ const css = '.dkb-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:14px 16px;display:flex;flex-direction:column;gap:8px;margin-bottom:12px}.dkb-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px;padding-bottom:4px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dkb-section-badge{font-size:11px;font-weight:500;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}.dkb-section-badge-ok{border-color:var(--dsw-alias-state-success-secondary,#34d399);color:var(--dsw-alias-state-success-primary,#059669);background:var(--dsw-alias-state-success-secondary,rgba(16,185,129,0.1))}.dkb-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none}.dkb-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.dkb-page{padding:0}.dkb-page .dkb-body{border-top:none;margin:0}.dkb-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 16px}.dkb-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.dkb-title{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.dkb-sub{color:var(--dsw-alias-label-secondary);font-size:13px}.dkb-chevron{color:var(--dsw-alias-label-secondary);display:inline-flex;align-items:center;justify-content:center;flex:none;transition:transform .16s}.dkb-chevronOpen{transform:rotate(180deg)}.dkb-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.dkb-group{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:14px 0 2px}.dkb-field{display:flex;flex-direction:column;gap:6px;padding:10px 0}.dkb-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.dkb-hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}.dkb-input{height:34px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;box-sizing:border-box;width:100%}.dkb-area{min-height:96px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:8px 12px;font-size:13px;box-sizing:border-box;width:100%;resize:vertical;font:inherit}.dkb-input:disabled,.dkb-area:disabled{opacity:.55}.dkb-foot{border-top:1px solid var(--dsw-alias-border-l2);display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px}.dkb-footSplit{justify-content:space-between}.dkb-footLeft{display:flex;align-items:center;gap:8px}.dkb-note{min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary)}.dkb-failed{min-width:0;color:var(--dsw-alias-state-error-primary);flex:1;margin:0;font-size:12px;line-height:1.5}.dkb-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.dkb-discard{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:5px 14px;font-size:13px;color:var(--dsw-alias-label-secondary);background:transparent}.dkb-discard:disabled,.dkb-save:disabled{opacity:.4;cursor:default}.dkb-entry-clone{align-items:center;gap:8px;display:flex}.dkb-entry-clone[data-active]{font-weight:600}.dkb-entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.dkb-entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .dkb-entryLabel{display:none}[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-kanban-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-kanban-active]:not([data-dsh-ssh-active]) [data-dsh-kanban-view]{display:block}html[data-dsh-kanban-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-kanban-view]),html[data-dsh-kanban-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-kanban-view]){display:none!important}.dkb-screen{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 56px;display:flex}.dkb-bar{flex:none;align-items:center;gap:8px;display:flex;flex-wrap:wrap}.dkb-bar .dkb-input,.dkb-bar .dkb-search,.dkb-bar .dkb-save,.dkb-bar .dkb-discard,.dkb-bar .dkb-facetHead,.dkb-bar .dkb-back{height:30px;box-sizing:border-box;padding-top:0;padding-bottom:0;border-radius:8px;font-size:13px;line-height:28px;display:inline-flex;align-items:center}.dkb-bar .dkb-facet{display:inline-flex}.dkb-back{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;align-items:center;gap:6px;padding:4px 10px;font-size:13px;display:flex;flex:none}.dkb-back:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dkb-backIcon{align-items:center;display:flex}.dkb-archive{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:8px}.dkb-archiveList{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.dkb-archiveRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;align-items:center;gap:12px;padding:8px 12px;display:flex}.dkb-start{display:contents}.dkb-pack{color:var(--dsw-alias-label-secondary)}.dkb-who{color:var(--dsw-alias-label-secondary)}.dkb-sameSession{outline:1px solid var(--dsw-alias-label-secondary);outline-offset:1px}.dkb-waitCount{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:0 10px;height:30px;cursor:pointer;color:var(--dsw-alias-label-primary)}.dkb-archiveOpen{background:none;border:0;padding:0;text-align:left;cursor:pointer;font:inherit}.dkb-archiveTitle{flex:1;font-size:13px;color:var(--dsw-alias-label-primary)}.dkb-urgent{border-left-width:3px;border-left-style:solid;padding-left:9px}.dkb-cardMenu{position:relative;align-self:flex-start;opacity:0;transition:opacity .12s}.dkb-taskCard:hover .dkb-cardMenu,.dkb-taskCard:focus-within .dkb-cardMenu,.dkb-taskCard:focus-visible .dkb-cardMenu{opacity:1}.dkb-groupHead{appearance:none;width:100%;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:0;border-top:1px solid var(--dsw-alias-border-l2);align-items:center;gap:6px;padding:8px 2px 4px;font-size:11px;font-weight:600;display:flex}.dkb-groupHead:first-child{border-top:0;padding-top:2px}.dkb-groupHead:hover{color:var(--dsw-alias-label-primary)}.dkb-groupCount{margin-left:auto;color:var(--dsw-alias-label-tertiary);font-weight:400}.dkb-shown{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;flex:none}.dkb-moveBtn{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-tertiary);background:0 0;border:0;padding:0;font-size:11px;text-decoration:underline dotted}.dkb-moveBtn:hover{color:var(--dsw-alias-label-primary)}.dkb-taskCard:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.dkb-sync{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px;flex:none}.dkb-syncBad{color:var(--dsw-alias-state-error-primary,#e5534b);cursor:help}.dkb-facet{position:relative;flex:none}.dkb-facetHead{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px 10px;font-size:13px;white-space:nowrap}.dkb-facetHead:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dkb-facetOn{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-interactive-bg-hover)}.dkb-facetList{position:absolute;top:calc(100% + 4px);left:0;z-index:60;min-width:180px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;box-shadow:var(--dsw-shadow-lv2);padding:6px;display:flex;flex-direction:column;gap:2px}.dkb-facetRow{align-items:center;gap:8px;padding:4px 6px;border-radius:6px;font-size:13px;cursor:pointer;display:flex}.dkb-facetRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.dkb-facetName{flex:1;color:var(--dsw-alias-label-primary)}.dkb-barTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700;margin-right:auto}.dkb-cols{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;gap:12px;min-height:0;padding-bottom:6px;display:flex;overflow:auto hidden}.dkb-cols::-webkit-scrollbar{height:10px}.dkb-cols::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}.dkb-cols::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid transparent;border-radius:999px}.dkb-col{flex:1 1 220px;min-width:220px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}.dkb-colOver{border-color:var(--dsw-alias-border-l3)}.dkb-colHead{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}.dkb-colHead:hover{background:var(--dsw-alias-interactive-bg-hover)}.dkb-colShut{flex:0 0 auto;min-width:0;width:40px}.dkb-colShut .dkb-colHead{writing-mode:vertical-rl;height:100%;width:auto;padding:12px 10px;justify-content:flex-start;gap:10px}.dkb-colShut .dkb-colHead .dkb-dot{writing-mode:horizontal-tb}.dkb-colShut .dkb-count{writing-mode:horizontal-tb}.dkb-dot{border-radius:50%;flex:none;width:8px;height:8px}.dkb-dot[data-col=backlog]{background:var(--dsw-alias-label-tertiary)}.dkb-dot[data-col=in-progress]{background:var(--dsw-alias-state-warn-primary)}.dkb-dot[data-col=review]{background:var(--dsw-alias-state-business-primary)}.dkb-dot[data-col=deploy]{background:var(--dsw-alias-state-business-primary)}.dkb-dot[data-col=cleanup]{background:var(--dsw-alias-label-tertiary)}.dkb-dot[data-col=done]{background:var(--dsw-alias-state-success-primary)}.dkb-colName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}.dkb-count{min-width:20px;text-align:center;color:var(--dsw-alias-bg-base);background:var(--dsw-alias-label-tertiary);border-radius:999px;flex:none;padding:1px 8px;font-size:12px;font-weight:600}.dkb-count[data-col=in-progress]{background:var(--dsw-alias-state-warn-primary)}.dkb-count[data-col=review]{background:var(--dsw-alias-state-business-primary)}.dkb-count[data-col=deploy]{background:var(--dsw-alias-state-business-primary)}.dkb-count[data-col=done]{background:var(--dsw-alias-state-success-primary)}.dkb-countOver{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-inverted,#fff)}.dkb-overdue{border-color:var(--dsw-alias-state-error-primary)}.dkb-dueOver{color:var(--dsw-alias-state-error-primary);font-weight:600}.dkb-list{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}.dkb-empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}.dkb-taskCard{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}.dkb-taskCard:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}.dkb-taskTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}.dkb-mdBody{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.55;display:flex;flex-direction:column;gap:8px;max-height:46vh;overflow-y:auto}.dkb-mdPara{margin:0;overflow-wrap:anywhere}.dkb-mdHead{color:var(--dsw-alias-label-primary);font-weight:700;margin:6px 0 0;line-height:1.35}.dkb-mdHead1{font-size:15px}.dkb-mdHead2{font-size:14px}.dkb-mdHead3{font-size:13px;color:var(--dsw-alias-label-secondary)}.dkb-mdList{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:3px}.dkb-mdCode{margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);font-size:12px;overflow-x:auto;white-space:pre}.dkb-mdQuote{margin:0;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary)}.dkb-mdRule{border:0;border-top:1px solid var(--dsw-alias-border-l2);margin:2px 0;width:100%}.dkb-code{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:4px;padding:0 4px;font-size:12px}.dkb-issueLink{color:var(--dsw-alias-label-secondary)}.dkb-taskHead{align-items:center;gap:6px;flex-wrap:wrap;display:flex}.dkb-ref{align-items:baseline;gap:5px;min-width:0;display:inline-flex}.dkb-refRepo{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:1px 7px;font-size:11px;font-weight:600}.dkb-refNum{flex:none;color:var(--dsw-alias-label-tertiary);font-size:11px;font-family:var(--dsw-font-family-mono,ui-monospace,SFMono-Regular,Menlo,monospace);letter-spacing:.02em}.dkb-refLink{text-decoration:none}.dkb-refLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dkb-taskRef{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}.dkb-planLine{color:var(--dsw-alias-label-secondary);font-size:11px;line-height:1.35;overflow:hidden;-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box}.dkb-state{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:0 5px;font-size:10px;line-height:16px}.dkb-stateLive{border-color:var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);font-weight:600}.dkb-batchList{list-style:none;margin:0;padding:0;max-height:200px;overflow-y:auto;display:flex;flex-direction:column;gap:4px}.dkb-batchRow{align-items:baseline;gap:8px;font-size:13px;color:var(--dsw-alias-label-primary);display:flex}.dkb-pick{margin:0;flex:none;opacity:0;transition:opacity .12s}.dkb-taskCard:hover .dkb-pick,.dkb-taskCard:focus-within .dkb-pick,.dkb-pickOn{opacity:1}.dkb-toChat{appearance:none;font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border:0;padding:0;font-size:11px;text-decoration:underline dotted}.dkb-toChat:hover{color:var(--dsw-alias-label-primary)}.dkb-planList{display:flex;flex-direction:column;gap:4px;margin:0;padding:0;list-style:none}.dkb-planItem{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.4;display:flex;gap:8px;align-items:baseline}.dkb-planItem.dkb-planDone{color:var(--dsw-alias-label-tertiary);text-decoration:line-through}.dkb-planItem.dkb-planActive{color:var(--dsw-alias-label-primary);font-weight:600;text-decoration:none}.dkb-planMark{flex:none;width:14px;text-align:center}.dkb-tags{display:flex;flex-wrap:wrap;gap:4px}.dkb-waiting{color:var(--dsw-alias-state-warn-primary);font-weight:600}.dkb-waitDot{border-radius:50%;flex:none;width:8px;height:8px;background:var(--dsw-alias-state-warn-primary);display:inline-block}.dkb-tag{white-space:nowrap;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border:1px solid transparent;border-radius:999px;padding:1px 7px;font-size:11px;line-height:1.5;font-weight:500}.dkb-modal{position:absolute;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.4));display:flex;align-items:center;justify-content:center;padding:24px 24px 84px;box-sizing:border-box;z-index:70}.dkb-panel{width:min(720px,100%);max-height:100%;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;box-sizing:border-box;overflow-y:auto;display:flex;flex-direction:column;gap:12px}@media (min-width:960px){.dkb-panelWide{width:min(1100px,96%)}.dkb-drawerGrid{display:grid;grid-template-columns:300px 1fr;gap:20px;align-items:start}}.dkb-drawerSidebar{display:flex;flex-direction:column;gap:12px;border-right:1px solid var(--dsw-alias-border-l2);padding-right:16px}.dkb-drawerMain{display:flex;flex-direction:column;gap:12px;min-width:0}.dkb-panelBody{white-space:pre-wrap;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5;margin:0}.dkb-log{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}.dkb-logRow{color:var(--dsw-alias-label-secondary);font-size:12px}.dkb-dialog{position:absolute;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.4));display:flex;align-items:center;justify-content:center;z-index:80}.dkb-dialogBox{width:min(560px,94%);max-height:86%;overflow-y:auto;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;display:flex;flex-direction:column;gap:10px}.dkb-issue{appearance:none;font:inherit;text-align:left;cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 10px;color:var(--dsw-alias-label-primary);font-size:13px}.dkb-issueUsed{opacity:.5}.dkb-row{display:flex;gap:8px;align-items:center}.dkb-search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 240px;padding:6px 10px;font-size:13px}.dkb-search::placeholder{color:var(--dsw-alias-label-tertiary)}.dkb-slot{height:2px;border-radius:2px;background:transparent;flex:none}.dkb-slotOn{background:var(--dsw-alias-state-business-primary)}.dkb-danger{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;padding:5px 14px;font-size:13px;color:var(--dsw-alias-state-error-primary);background:transparent}.dkb-danger:hover{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-bg-base)}.dkb-quickFilterBar{display:flex;gap:6px;align-items:center;flex-wrap:wrap;padding:4px 0}.dkb-filterChip{appearance:none;font:inherit;cursor:pointer;background:var(--dsw-alias-interactive-bg-hover);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:3px 10px;font-size:12px;color:var(--dsw-alias-label-secondary);transition:all .15s}.dkb-filterChip:hover{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.dkb-filterChipActive{background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary-inverted,#fff);border-color:transparent;font-weight:600}.dkb-epicTag{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary,#0969da);font-weight:600}.dkb-progressBar{height:4px;background:var(--dsw-alias-border-l2);border-radius:2px;overflow:hidden;margin:4px 0}.dkb-progressFill{height:100%;background:var(--dsw-alias-state-success-primary,#16a34a);transition:width .2s}.dkb-consolePre{background:var(--dsw-alias-bg-layer-1,#0d1117);color:var(--dsw-alias-state-business-primary,#58a6ff);border:1px solid var(--dsw-alias-border-l2);padding:12px;border-radius:8px;font-family:monospace;font-size:11px;max-height:260px;overflow-y:auto;white-space:pre-wrap}'
869
557
 
870
558
  const en = {
871
559
  'updater.title': 'Plugin Updates',
@@ -1266,6 +954,55 @@ window.__ModuleLoader__.load({
1266
954
  'error.crossSite': 'Request rejected as cross-site.',
1267
955
  'error.timeout': 'Request timed out. Please try again.',
1268
956
  'error.unknown': 'Request failed.',
957
+ 'field.costMeterEnabled': 'Cost Meter Telemetry',
958
+ 'hint.costMeterEnabled': 'Enable token and cost telemetry integration via @goodandready/dsh-cost-meter.',
959
+ 'field.taskCostLimit': 'Task Cost Limit (USD)',
960
+ 'hint.taskCostLimit': 'Cost threshold per task in USD; 0 disables threshold warnings.',
961
+ 'card.costLimitExceeded': 'Cost limit exceeded',
962
+ 'card.nudge': 'Nudge',
963
+ 'card.nudgeHint': 'Send live instruction to running agent',
964
+ 'nudge.title': 'Live Steering',
965
+ 'nudge.placeholder': 'Enter immediate instruction or correction for the agent...',
966
+ 'nudge.send': 'Send',
967
+ 'nudge.sending': 'Sending...',
968
+ 'nudge.success': 'Instruction delivered to agent',
969
+ 'nudge.failed': 'Failed to deliver instruction',
970
+ 'costMeter.notice': 'Cost and token tracking requires @goodandready/dsh-cost-meter to be installed and active in DSH profile.',
971
+ 'costMeter.active': 'Plugin @goodandready/dsh-cost-meter is active',
972
+ 'costMeter.inactive': 'Plugin @goodandready/dsh-cost-meter not detected',
973
+ 'telemetry.title': 'Resource Telemetry',
974
+ 'telemetry.tokens': 'Tokens',
975
+ 'telemetry.input': 'Input',
976
+ 'telemetry.output': 'Output',
977
+ 'telemetry.cache': 'Cached',
978
+ 'telemetry.cost': 'Estimated Cost',
979
+ 'group.remote': 'Remote execution (Server 111)',
980
+ 'field.remoteMode': 'Remote mode',
981
+ 'hint.remoteMode': 'Execute tasks, worktrees, and git commands on remote server 111.',
982
+ 'field.remoteHost': 'Remote host',
983
+ 'hint.remoteHost': 'Hostname or IP address of the remote server.',
984
+ 'field.remotePort': 'SSH port',
985
+ 'hint.remotePort': 'SSH port on remote server (default 22).',
986
+ 'field.remoteUser': 'SSH user',
987
+ 'hint.remoteUser': 'SSH login username on remote host.',
988
+ 'field.remoteAuthType': 'SSH auth type',
989
+ 'hint.remoteAuthType': 'SSH authentication method: key, agent, or password.',
990
+ 'field.remoteKeyPath': 'SSH private key',
991
+ 'hint.remoteKeyPath': 'Path to SSH private key file on local PC.',
992
+ 'field.remoteSudoUser': 'Sudo user',
993
+ 'hint.remoteSudoUser': 'Run remote commands under this Linux user via sudo -u.',
994
+ 'field.remoteRoot': 'Remote project root',
995
+ 'hint.remoteRoot': 'Remote projects directory (/mnt/external/Project/DEV).',
996
+ 'field.remoteServerUrl': 'DSH server URL',
997
+ 'hint.remoteServerUrl': 'Remote DSH URL (http://192.168.1.111:3080) for unified board state.',
998
+ 'field.remoteServerToken': 'Server auth token',
999
+ 'hint.remoteServerToken': 'Optional authentication token for remote DSH server.',
1000
+ 'remote.testBtn': 'Test Connection',
1001
+ 'remote.testing': 'Testing connection...',
1002
+ 'remote.ok': 'Connected to server 111',
1003
+ 'remote.failed': 'Connection failed',
1004
+ 'remote.badge': 'Remote: 111',
1005
+ 'telemetry.limit': 'Budget Limit',
1269
1006
  }
1270
1007
 
1271
1008
  const zh = {
@@ -1667,6 +1404,55 @@ window.__ModuleLoader__.load({
1667
1404
  'error.crossSite': '请求被判定为跨站而拒绝。',
1668
1405
  'error.timeout': '请求超时,请重试。',
1669
1406
  'error.unknown': '请求失败。',
1407
+ 'field.costMeterEnabled': '成本计量遥测',
1408
+ 'hint.costMeterEnabled': '通过 @goodandready/dsh-cost-meter 启用 Token 和成本遥测集成。',
1409
+ 'field.taskCostLimit': '任务成本限额 (USD)',
1410
+ 'hint.taskCostLimit': '每个任务的成本阈值(美元);0 表示禁用超额警告。',
1411
+ 'card.costLimitExceeded': '超出成本限额',
1412
+ 'card.nudge': '引导',
1413
+ 'card.nudgeHint': '向正在运行的 Agent 发送实时引导指令',
1414
+ 'nudge.title': '实时引导',
1415
+ 'nudge.placeholder': '输入对 Agent 的即时指令或修正建议...',
1416
+ 'nudge.send': '发送',
1417
+ 'nudge.sending': '正在发送...',
1418
+ 'nudge.success': '指令已发送给 Agent',
1419
+ 'nudge.failed': '发送指令失败',
1420
+ 'costMeter.notice': 'Token 及成本追踪功能需要 DSH Profile 中安装并激活 @goodandready/dsh-cost-meter 插件。',
1421
+ 'costMeter.active': '已激活 @goodandready/dsh-cost-meter 插件',
1422
+ 'costMeter.inactive': '未检测到 @goodandready/dsh-cost-meter 插件',
1423
+ 'telemetry.title': '资源遥测',
1424
+ 'telemetry.tokens': 'Token 统计',
1425
+ 'telemetry.input': '输入',
1426
+ 'telemetry.output': '输出',
1427
+ 'telemetry.cache': '缓存命中',
1428
+ 'telemetry.cost': '预估成本',
1429
+ 'group.remote': '远程执行 (111 服务器)',
1430
+ 'field.remoteMode': '远程模式',
1431
+ 'hint.remoteMode': '在远程 111 服务器上执行任务、工作树和 git 命令。',
1432
+ 'field.remoteHost': '远程主机',
1433
+ 'hint.remoteHost': '远程服务器的主机名或 IP 地址。',
1434
+ 'field.remotePort': 'SSH 端口',
1435
+ 'hint.remotePort': '远程服务器的 SSH 端口(默认 22)。',
1436
+ 'field.remoteUser': 'SSH 用户',
1437
+ 'hint.remoteUser': '远程主机上的 SSH 登录用户名。',
1438
+ 'field.remoteAuthType': 'SSH 认证类型',
1439
+ 'hint.remoteAuthType': 'SSH 认证方式:key、agent 或 password。',
1440
+ 'field.remoteKeyPath': 'SSH 私钥路径',
1441
+ 'hint.remoteKeyPath': '本地电脑上的 SSH 私钥文件路径。',
1442
+ 'field.remoteSudoUser': 'Sudo 执行用户',
1443
+ 'hint.remoteSudoUser': '在远程通过 sudo -u 以此 Linux 用户身份运行命令。',
1444
+ 'field.remoteRoot': '远程项目根目录',
1445
+ 'hint.remoteRoot': '远程项目仓库目录 (/mnt/external/Project/DEV)。',
1446
+ 'field.remoteServerUrl': 'DSH 服务器地址',
1447
+ 'hint.remoteServerUrl': '远程 DSH 服务器地址 (http://192.168.1.111:3080),用于共享看板状态。',
1448
+ 'field.remoteServerToken': '服务器认证令牌',
1449
+ 'hint.remoteServerToken': '远程 DSH 服务器的可选认证令牌。',
1450
+ 'remote.testBtn': '测试连接',
1451
+ 'remote.testing': '正在测试连接...',
1452
+ 'remote.ok': '已连接到 111 服务器',
1453
+ 'remote.failed': '连接失败',
1454
+ 'remote.badge': '远程: 111',
1455
+ 'telemetry.limit': '预算限额',
1670
1456
  }
1671
1457
 
1672
1458
  function fallbackT(key, vars) {
@@ -1679,7 +1465,6 @@ window.__ModuleLoader__.load({
1679
1465
  return text
1680
1466
  }
1681
1467
 
1682
-
1683
1468
  const FIELDS = [
1684
1469
  { field: 'gitProvider', kind: 'text', group: 'forge' },
1685
1470
  { field: 'giteaUrl', kind: 'text', group: 'gitea' },
@@ -1715,6 +1500,18 @@ window.__ModuleLoader__.load({
1715
1500
  { field: 'verificationGateEnabled', kind: 'bool', group: 'general' },
1716
1501
  { field: 'verificationCommand', kind: 'text', group: 'general' },
1717
1502
  { field: 'verificationTimeoutMs', kind: 'number', group: 'general' },
1503
+ { field: 'costMeterEnabled', kind: 'bool', group: 'sync' },
1504
+ { field: 'taskCostLimit', kind: 'number', group: 'limits' },
1505
+ { field: 'remoteMode', kind: 'bool', group: 'remote' },
1506
+ { field: 'remoteHost', kind: 'text', group: 'remote' },
1507
+ { field: 'remotePort', kind: 'number', group: 'remote' },
1508
+ { field: 'remoteUser', kind: 'text', group: 'remote' },
1509
+ { field: 'remoteAuthType', kind: 'text', group: 'remote' },
1510
+ { field: 'remoteKeyPath', kind: 'text', group: 'remote' },
1511
+ { field: 'remoteSudoUser', kind: 'text', group: 'remote' },
1512
+ { field: 'remoteRoot', kind: 'text', group: 'remote' },
1513
+ { field: 'remoteServerUrl', kind: 'text', group: 'remote' },
1514
+ { field: 'remoteServerToken', kind: 'text', group: 'remote' },
1718
1515
  ]
1719
1516
 
1720
1517
  function hintKey(spec) {
@@ -1722,6 +1519,7 @@ window.__ModuleLoader__.load({
1722
1519
  if (spec.group === 'gitea') return 'hint.' + spec.field
1723
1520
  if (spec.group === 'github') return 'hint.' + spec.field
1724
1521
  if (spec.group === 'forge') return 'hint.' + spec.field
1522
+ if (spec.group === 'remote') return 'hint.' + spec.field
1725
1523
  if (spec.group === 'labels') return 'hint.label'
1726
1524
  if (spec.group === 'limits') return 'hint.limit'
1727
1525
  return 'hint.' + spec.field
@@ -1759,6 +1557,63 @@ window.__ModuleLoader__.load({
1759
1557
  }, h(Icon))
1760
1558
  }
1761
1559
 
1560
+ function RemoteConnectionSection(props) {
1561
+ const t = props.t || fallbackT
1562
+ const [testing, setTesting] = React.useState(false)
1563
+ const [result, setResult] = React.useState(null)
1564
+
1565
+ const handleTest = React.useCallback(async () => {
1566
+ setTesting(true)
1567
+ setResult(null)
1568
+ try {
1569
+ const res = await fetch('/api/dsh-kanban/remote/test', {
1570
+ method: 'POST',
1571
+ headers: { 'Content-Type': 'application/json' },
1572
+ })
1573
+ const data = await res.json()
1574
+ setResult(data)
1575
+ } catch (e) {
1576
+ setResult({ ok: false, error: e?.message || String(e) })
1577
+ } finally {
1578
+ setTesting(false)
1579
+ }
1580
+ }, [])
1581
+
1582
+ return h('div', {
1583
+ className: 'dkb-section-card',
1584
+ key: 'remote-test-card',
1585
+ style: { borderLeft: '3px solid var(--dsw-alias-state-business-primary, #0969da)', background: 'var(--dsw-alias-bg-layer-1, #f6f8fa)', padding: '12px 14px', marginBottom: '12px' },
1586
+ },
1587
+ h('div', {
1588
+ style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: result ? '8px' : '0' },
1589
+ },
1590
+ h('span', { style: { fontWeight: '600', fontSize: '13px' } }, '🌐 ' + t('group.remote')),
1591
+ h('button', {
1592
+ type: 'button',
1593
+ className: 'dkb-save',
1594
+ style: { padding: '3px 10px', fontSize: '12px' },
1595
+ disabled: testing,
1596
+ onClick: handleTest,
1597
+ }, testing ? t('remote.testing') : t('remote.testBtn')),
1598
+ ),
1599
+ result ? h('div', {
1600
+ style: {
1601
+ fontSize: '12px',
1602
+ padding: '6px 8px',
1603
+ borderRadius: '4px',
1604
+ background: (result.ssh?.ok || result.server?.ok)
1605
+ ? 'var(--dsw-alias-state-success-secondary, #dafbe1)'
1606
+ : 'var(--dsw-alias-state-error-secondary, #ffebe9)',
1607
+ color: (result.ssh?.ok || result.server?.ok)
1608
+ ? 'var(--dsw-alias-state-success-primary, #1a7f37)'
1609
+ : 'var(--dsw-alias-state-error-primary, #cf222e)',
1610
+ },
1611
+ },
1612
+ h('div', null, (result.ssh?.ok ? '✓ SSH: OK (' + result.ssh.latencyMs + 'ms)' : '✗ SSH: ' + (result.ssh?.error || 'unreachable'))),
1613
+ h('div', null, (result.server?.ok ? '✓ DSH Server: OK (' + result.server.latencyMs + 'ms)' : '✗ DSH Server: ' + (result.server?.error || 'unreachable'))),
1614
+ ) : null,
1615
+ )
1616
+ }
1762
1617
 
1763
1618
  function PluginUpdaterSection(props) {
1764
1619
  const t = props.t || fallbackT
@@ -2014,6 +1869,30 @@ window.__ModuleLoader__.load({
2014
1869
  else if (!writable) note = h('p', { className: 'dkb-note', role: 'status' }, t('settings.readOnly'))
2015
1870
  else if (saved) note = h('p', { className: 'dkb-note', role: 'status' }, t('settings.saved'))
2016
1871
  else note = h('p', { className: 'dkb-note' })
1872
+ const costMeterDetected = Boolean(ctx?.costMeter || (ctx?.registry && Array.from(ctx.registry.keys()).some((k) => k === '@goodandready/dsh-cost-meter' || k?.name === '@goodandready/dsh-cost-meter')))
1873
+ rows.push(h('div', {
1874
+ className: 'dkb-section-card',
1875
+ key: 'cost-meter-notice',
1876
+ style: {
1877
+ borderLeft: '3px solid var(--dsw-alias-state-business-primary, #0969da)',
1878
+ background: 'var(--dsw-alias-bg-layer-1, #f6f8fa)',
1879
+ padding: '12px 14px',
1880
+ marginBottom: '12px',
1881
+ },
1882
+ },
1883
+ h('div', {
1884
+ style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' },
1885
+ },
1886
+ h('span', { style: { fontWeight: '600', fontSize: '13px' } }, '🪙 ' + t('telemetry.title')),
1887
+ h('span', {
1888
+ className: 'dkb-section-badge' + (costMeterDetected ? ' dkb-section-badge-ok' : ''),
1889
+ }, costMeterDetected ? t('costMeter.active') : t('costMeter.inactive')),
1890
+ ),
1891
+ h('p', { className: 'dkb-hint', style: { margin: 0, fontSize: '12px', lineHeight: '1.4' } },
1892
+ t('costMeter.notice'),
1893
+ ),
1894
+ ))
1895
+ rows.push(h(RemoteConnectionSection, { t, key: 'remote-test' }))
2017
1896
  rows.push(h(PluginUpdaterSection, { t, key: 'updater' }))
2018
1897
  rows.push(h('div', { className: 'dkb-foot', key: 'foot' },
2019
1898
  note,
@@ -2029,12 +1908,10 @@ window.__ModuleLoader__.load({
2029
1908
  return h('li', { className: 'dkb-card dkb-cardOpen' }, head, h('div', { className: 'dkb-body' }, body))
2030
1909
  }
2031
1910
 
2032
- /** Back button arrow icon: 14x14 stroke currentColor. */
2033
1911
  const BACK_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor"'
2034
1912
  + ' stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">'
2035
1913
  + '<path d="M10 3.5 5.5 8l4.5 4.5"/></svg>'
2036
1914
 
2037
-
2038
1915
  const TaskCard = React.memo(function TaskCard(props) {
2039
1916
  const { task, t, now } = props
2040
1917
  const ref = cardRef(task)
@@ -2094,6 +1971,20 @@ window.__ModuleLoader__.load({
2094
1971
  : (task.report?.verification?.status === 'failed'
2095
1972
  ? h('span', { className: 'dkb-tag', style: { background: 'var(--dsw-alias-state-error-secondary, #ffebe9)', color: 'var(--dsw-alias-state-error-primary, #cf222e)', borderColor: 'var(--dsw-alias-state-error-secondary, #ffc1c0)' }, title: task.report.verification.command || 'Tests failed' }, '✗ FAIL')
2096
1973
  : null),
1974
+ task.costMetrics && task.costMetrics.totalTokens > 0
1975
+ ? h('span', {
1976
+ className: 'dkb-tag',
1977
+ style: { background: 'var(--dsw-alias-state-business-tertiary, #ddf4ff)', color: 'var(--dsw-alias-state-business-primary, #0969da)', borderColor: 'var(--dsw-alias-state-business-tertiary, #54aeff)' },
1978
+ title: 'Tokens: ' + task.costMetrics.totalTokens.toLocaleString()
1979
+ }, '🪙 ' + (task.costMetrics.totalTokens / 1000).toFixed(1) + 'k' + (task.costMetrics.costFormatted ? ' · ' + task.costMetrics.costFormatted : ''))
1980
+ : null,
1981
+ task.costLimitExceeded
1982
+ ? h('span', {
1983
+ className: 'dkb-tag',
1984
+ style: { background: 'var(--dsw-alias-state-warn-secondary, #fff8c5)', color: 'var(--dsw-alias-state-warn-primary, #9a6700)', borderColor: 'var(--dsw-alias-state-warn-secondary, #d4a72c)' },
1985
+ title: 'Budget limit exceeded'
1986
+ }, '⚠️ ' + t('card.costLimitExceeded'))
1987
+ : null,
2097
1988
  task.report && task.report.summary
2098
1989
  ? h('span', { className: 'dkb-tag', title: 'Execution Report' }, '📄 report')
2099
1990
  : null,
@@ -2104,6 +1995,16 @@ window.__ModuleLoader__.load({
2104
1995
  className: 'dkb-tag', key: l, style: tagStyle(task, l),
2105
1996
  }, l))),
2106
1997
  h('div', { className: 'dkb-taskTitle' }, task.title),
1998
+ task.state === 'running' && task.liveStep
1999
+ ? h('div', {
2000
+ className: 'dkb-liveStep',
2001
+ style: { fontSize: '11px', color: 'var(--dsw-alias-state-business-primary, #0969da)', display: 'flex', alignItems: 'center', gap: '4px', margin: '3px 0' },
2002
+ title: task.liveStep
2003
+ },
2004
+ h('span', { style: { display: 'inline-block' } }, '⟳'),
2005
+ h('span', { style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, task.liveStep)
2006
+ )
2007
+ : null,
2107
2008
  task.subtasksCount && task.subtasksCount.total > 0
2108
2009
  ? h('div', { className: 'dkb-progressBar', title: `${task.subtasksCount.completed}/${task.subtasksCount.total}` },
2109
2010
  h('div', {
@@ -2160,6 +2061,26 @@ window.__ModuleLoader__.load({
2160
2061
  onClick: (e) => { e.stopPropagation(); props.onOpenChat(task) },
2161
2062
  }, t('card.toChat'))
2162
2063
  : null,
2064
+ (task.column === 'in-progress' || task.col === 'in-progress') && task.sessionId && (task.state === 'running' || task.state === 'idle')
2065
+ ? h('button', {
2066
+ type: 'button',
2067
+ className: 'dkb-nudgeBtn',
2068
+ title: t('card.nudgeHint'),
2069
+ style: {
2070
+ fontSize: '11px',
2071
+ padding: '1px 6px',
2072
+ borderRadius: '4px',
2073
+ cursor: 'pointer',
2074
+ border: '1px solid var(--dsw-alias-state-business-tertiary, #54aeff)',
2075
+ background: 'var(--dsw-alias-state-business-tertiary, #ddf4ff)',
2076
+ color: 'var(--dsw-alias-state-business-primary, #0969da)',
2077
+ },
2078
+ onClick: (e) => {
2079
+ e.stopPropagation();
2080
+ if (props.onNudge) props.onNudge(task);
2081
+ }
2082
+ }, '💬 ' + t('card.nudge'))
2083
+ : null,
2163
2084
  touched
2164
2085
  ? h('span', {
2165
2086
  className: task.stale ? 'dkb-countOver' : '',
@@ -2189,10 +2110,6 @@ window.__ModuleLoader__.load({
2189
2110
  )
2190
2111
  })
2191
2112
 
2192
- /**
2193
- * Execution options: agent preset and permission rank.
2194
- * Shared across single-task and batch launch modals.
2195
- */
2196
2113
  function LaunchFields(props) {
2197
2114
  const t = props.t
2198
2115
  const rows = []
@@ -2317,6 +2234,32 @@ window.__ModuleLoader__.load({
2317
2234
  const [agentPreset, setAgentPreset] = React.useState('')
2318
2235
  const [permission, setPermission] = React.useState('')
2319
2236
  const dragged = React.useRef(null)
2237
+ const [nudgeTask, setNudgeTask] = React.useState(null)
2238
+ const [nudgePrompt, setNudgePrompt] = React.useState('')
2239
+ const [nudgeSending, setNudgeSending] = React.useState(false)
2240
+ const [nudgeSuccess, setNudgeSuccess] = React.useState(false)
2241
+
2242
+ const handleNudgeSubmit = React.useCallback(async () => {
2243
+ if (!nudgeTask || !nudgePrompt.trim() || nudgeSending) return
2244
+ setNudgeSending(true)
2245
+ try {
2246
+ await api('/task/' + encodeURIComponent(nudgeTask.id) + '/nudge', {
2247
+ method: 'POST',
2248
+ body: JSON.stringify({ prompt: nudgePrompt.trim() }),
2249
+ })
2250
+ setNudgeSuccess(true)
2251
+ setTimeout(() => {
2252
+ setNudgeTask(null)
2253
+ setNudgePrompt('')
2254
+ setNudgeSuccess(false)
2255
+ }, 1200)
2256
+ load(board)
2257
+ } catch (e) {
2258
+ setError(t(e.key || e.error || 'nudge.failed'))
2259
+ } finally {
2260
+ setNudgeSending(false)
2261
+ }
2262
+ }, [nudgeTask, nudgePrompt, nudgeSending, load, board, t])
2320
2263
 
2321
2264
  const load = React.useCallback(async (nextBoard) => {
2322
2265
  try {
@@ -2474,9 +2417,6 @@ window.__ModuleLoader__.load({
2474
2417
  }
2475
2418
  }, [load, t])
2476
2419
 
2477
- /**
2478
- * Confirm and execute card move transition.
2479
- */
2480
2420
  const askMove = React.useCallback((task, column, where) => {
2481
2421
  if (!task) return
2482
2422
  const place = where ?? neighboursFor(tasksOf((state && state.tasks) || [], column), task.id, Infinity)
@@ -2547,6 +2487,19 @@ window.__ModuleLoader__.load({
2547
2487
  h('span', null, t('board.back')),
2548
2488
  ),
2549
2489
  h('span', { className: 'dkb-barTitle' }, t('section.label')),
2490
+ state && state.remoteMode
2491
+ ? h('span', {
2492
+ className: 'dkb-tag',
2493
+ style: {
2494
+ background: 'var(--dsw-alias-state-business-tertiary, #ddf4ff)',
2495
+ color: 'var(--dsw-alias-state-business-primary, #0969da)',
2496
+ borderColor: 'var(--dsw-alias-state-business-tertiary, #54aeff)',
2497
+ fontWeight: '600',
2498
+ fontSize: '11px',
2499
+ },
2500
+ title: 'Operating in remote mode against server 111',
2501
+ }, '🌐 ' + t('remote.badge'))
2502
+ : null,
2550
2503
  boards.length > 1
2551
2504
  ? h('select', {
2552
2505
  className: 'dkb-input', style: { width: 'auto' }, value: board,
@@ -2868,6 +2821,7 @@ window.__ModuleLoader__.load({
2868
2821
  if (manyGroups && groups[col.id + '/' + (task.repo || '')] === true) return
2869
2822
  rows.push(h(TaskCard, {
2870
2823
  key: task.id, task, t, now: state.now,
2824
+ onNudge: (t) => { setNudgeTask(t); setNudgePrompt(''); setNudgeSuccess(false) },
2871
2825
  columns: (state.columns || []).map((c) => c.id),
2872
2826
  menuOpen: cardMenu,
2873
2827
  onMenu: setCardMenu,
@@ -2913,6 +2867,11 @@ window.__ModuleLoader__.load({
2913
2867
  } catch (e) { setError(t(e.key || 'error.unknown')) }
2914
2868
  },
2915
2869
  onOpenChat: (x) => {
2870
+ if (state && state.remoteMode && x.sessionId) {
2871
+ const url = 'http://192.168.1.111:3080/#/chat?sessionId=' + encodeURIComponent(x.sessionId)
2872
+ if (typeof window !== 'undefined') window.open(url, '_blank')
2873
+ return
2874
+ }
2916
2875
  if (!openSession(props.ctx, x.sessionId)) {
2917
2876
  setError(t('error.sessionNotOpened', { id: x.sessionId }))
2918
2877
  return
@@ -3328,6 +3287,59 @@ window.__ModuleLoader__.load({
3328
3287
  },
3329
3288
  }, t('panel.openChat'))
3330
3289
  : null,
3290
+ openTask.sessionId && (openTask.column === 'in-progress' || openTask.col === 'in-progress')
3291
+ ? h('button', {
3292
+ type: 'button', className: 'dkb-discard', style: { alignSelf: 'flex-start' },
3293
+ onClick: () => { setNudgeTask(openTask); setNudgePrompt(''); setNudgeSuccess(false) },
3294
+ }, '💬 ' + t('card.nudge'))
3295
+ : null,
3296
+ openTask.costMetrics && openTask.costMetrics.totalTokens > 0
3297
+ ? h('div', {
3298
+ className: 'dkb-section-card',
3299
+ style: {
3300
+ margin: '8px 0', padding: 12, border: '1px solid var(--dsw-alias-border-l2)',
3301
+ borderRadius: 8, display: 'flex', flexDirection: 'column', gap: 6,
3302
+ },
3303
+ },
3304
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' } },
3305
+ h('div', { className: 'dkb-group', style: { margin: 0, fontWeight: 600 } },
3306
+ '🪙 ' + t('telemetry.title')
3307
+ ),
3308
+ h('span', {
3309
+ className: 'dkb-tag',
3310
+ style: { background: 'var(--dsw-alias-state-business-tertiary, #ddf4ff)', color: 'var(--dsw-alias-state-business-primary, #0969da)', borderColor: 'var(--dsw-alias-state-business-tertiary, #54aeff)' }
3311
+ }, openTask.costMetrics.costFormatted || '$0.00'),
3312
+ ),
3313
+ h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, fontSize: '11px', textAlign: 'center' } },
3314
+ h('div', { style: { background: 'var(--dsw-alias-bg-layer-1)', padding: '6px', borderRadius: '4px' } },
3315
+ h('div', { style: { opacity: 0.7 } }, t('telemetry.tokens')),
3316
+ h('div', { style: { fontWeight: 600 } }, openTask.costMetrics.totalTokens.toLocaleString()),
3317
+ ),
3318
+ h('div', { style: { background: 'var(--dsw-alias-bg-layer-1)', padding: '6px', borderRadius: '4px' } },
3319
+ h('div', { style: { opacity: 0.7 } }, t('telemetry.input')),
3320
+ h('div', { style: { fontWeight: 600 } }, (openTask.costMetrics.uncachedInputTokens || 0).toLocaleString()),
3321
+ ),
3322
+ h('div', { style: { background: 'var(--dsw-alias-bg-layer-1)', padding: '6px', borderRadius: '4px' } },
3323
+ h('div', { style: { opacity: 0.7 } }, t('telemetry.output')),
3324
+ h('div', { style: { fontWeight: 600 } }, (openTask.costMetrics.outputTokens || 0).toLocaleString()),
3325
+ ),
3326
+ h('div', { style: { background: 'var(--dsw-alias-bg-layer-1)', padding: '6px', borderRadius: '4px' } },
3327
+ h('div', { style: { opacity: 0.7 } }, t('telemetry.cache')),
3328
+ h('div', { style: { fontWeight: 600 } }, (openTask.costMetrics.cacheReadTokens || 0).toLocaleString()),
3329
+ ),
3330
+ ),
3331
+ openTask.costLimitExceeded
3332
+ ? h('div', {
3333
+ style: {
3334
+ fontSize: '11px',
3335
+ color: 'var(--dsw-alias-state-warn-primary, #9a6700)',
3336
+ background: 'var(--dsw-alias-state-warn-secondary, #fff8c5)',
3337
+ padding: '4px 8px', borderRadius: '4px', marginTop: '4px'
3338
+ }
3339
+ }, '⚠️ ' + t('card.costLimitExceeded'))
3340
+ : null
3341
+ )
3342
+ : null,
3331
3343
  log.length
3332
3344
  ? h('div', null,
3333
3345
  h('div', { className: 'dkb-group' }, t('panel.log')),
@@ -4372,17 +4384,79 @@ window.__ModuleLoader__.load({
4372
4384
  )
4373
4385
  : null
4374
4386
 
4387
+ const nudgeDialogEl = nudgeTask
4388
+ ? h('div', {
4389
+ className: 'dkb-modal',
4390
+ onClick: () => { setNudgeTask(null); setNudgePrompt(''); setNudgeSuccess(false) },
4391
+ },
4392
+ h('div', {
4393
+ className: 'dkb-dialog',
4394
+ style: { maxWidth: '440px', width: '90%', padding: '16px' },
4395
+ onClick: (e) => e.stopPropagation(),
4396
+ },
4397
+ h('div', { className: 'dkb-dialogHead', style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' } },
4398
+ h('h3', { style: { margin: 0, fontSize: '15px' } }, t('nudge.title') + ': ' + (nudgeTask.title || '')),
4399
+ h('button', {
4400
+ type: 'button',
4401
+ className: 'dkb-discard',
4402
+ style: { border: 'none', background: 'transparent', cursor: 'pointer', fontSize: '16px', padding: '0 4px' },
4403
+ onClick: () => { setNudgeTask(null); setNudgePrompt(''); setNudgeSuccess(false) },
4404
+ }, '✕'),
4405
+ ),
4406
+ nudgeSuccess
4407
+ ? h('div', {
4408
+ style: {
4409
+ padding: '12px',
4410
+ borderRadius: '6px',
4411
+ background: 'var(--dsw-alias-state-success-secondary, #dafbe1)',
4412
+ color: 'var(--dsw-alias-state-success-primary, #1a7f37)',
4413
+ marginBottom: '12px',
4414
+ textAlign: 'center',
4415
+ fontWeight: '600',
4416
+ },
4417
+ }, '✓ ' + t('nudge.success'))
4418
+ : h('div', null,
4419
+ h('textarea', {
4420
+ className: 'dkb-area',
4421
+ style: { width: '100%', minHeight: '90px', marginBottom: '12px', boxSizing: 'border-box' },
4422
+ placeholder: t('nudge.placeholder'),
4423
+ value: nudgePrompt,
4424
+ autoFocus: true,
4425
+ onChange: (e) => setNudgePrompt(e.target.value),
4426
+ onKeyDown: (e) => {
4427
+ if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
4428
+ e.preventDefault();
4429
+ handleNudgeSubmit();
4430
+ }
4431
+ },
4432
+ }),
4433
+ h('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: '8px' } },
4434
+ h('button', {
4435
+ type: 'button',
4436
+ className: 'dkb-discard',
4437
+ disabled: nudgeSending,
4438
+ onClick: () => { setNudgeTask(null); setNudgePrompt(''); setNudgeSuccess(false) },
4439
+ }, t('panel.close')),
4440
+ h('button', {
4441
+ type: 'button',
4442
+ className: 'dkb-save',
4443
+ disabled: !nudgePrompt.trim() || nudgeSending,
4444
+ onClick: handleNudgeSubmit,
4445
+ }, nudgeSending ? t('nudge.sending') : t('nudge.send')),
4446
+ ),
4447
+ ),
4448
+ ),
4449
+ )
4450
+ : null;
4451
+
4375
4452
  return h('div', { className: 'dkb-screen' },
4376
4453
  style, bar,
4377
4454
  error ? h('p', { className: 'dkb-failed' }, error) : null,
4378
4455
  metrics ? metricsEl : archive ? archiveEl : columns,
4379
- panel, dialogEl, moveDialogEl, batchEl, queueEl,
4456
+ panel, dialogEl, moveDialogEl, batchEl, queueEl, nudgeDialogEl,
4380
4457
  )
4381
4458
  }
4382
4459
 
4383
- /**
4384
- * Header task chip in chat conversation. Only rendered when session is linked to a task.
4385
- */
4386
4460
  function TaskChip(props) {
4387
4461
  const t = props.t || fallbackT
4388
4462
  const [task, setTask] = React.useState(null)
@@ -4466,8 +4540,6 @@ window.__ModuleLoader__.load({
4466
4540
  )
4467
4541
  }
4468
4542
 
4469
-
4470
-
4471
4543
  const PANEL = 'kanban'
4472
4544
  const ACTIVATE_EVENT = 'dsh-panel-activate'
4473
4545
  const ACTIVE_ATTR = 'data-dsh-kanban-active'
@@ -4480,8 +4552,6 @@ window.__ModuleLoader__.load({
4480
4552
  + ' stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">'
4481
4553
  + '<rect x="2" y="2.5" width="12" height="11" rx="1.5"/><path d="M2 6.5h12M6.5 6.5v7"/></svg>'
4482
4554
 
4483
- /** Board visibility state manager. */
4484
- /** @see helpers.createToggle */
4485
4555
  function createToggle() {
4486
4556
  let open = false
4487
4557
  let wanted = undefined
@@ -4494,12 +4564,10 @@ window.__ModuleLoader__.load({
4494
4564
  for (const fn of listeners) fn()
4495
4565
  },
4496
4566
  toggle() { this.set(!open) },
4497
- /** Open board focused on a specific task. */
4498
4567
  show(taskId, boardId) {
4499
4568
  wanted = { id: String(taskId || ''), board: String(boardId || 'main') }
4500
4569
  if (open) { for (const fn of listeners) fn() } else this.set(true)
4501
4570
  },
4502
- /** Consume requested focus task ID (cleared after first read). */
4503
4571
  takeWanted() {
4504
4572
  const asked = wanted
4505
4573
  wanted = undefined
@@ -4509,7 +4577,6 @@ window.__ModuleLoader__.load({
4509
4577
  }
4510
4578
  }
4511
4579
 
4512
- /** Find native 'New Session' sidebar button. */
4513
4580
  function nativeButton() {
4514
4581
  const nodes = document.querySelectorAll('button[class*="newSession"]')
4515
4582
  for (const node of nodes) {
@@ -4518,9 +4585,6 @@ window.__ModuleLoader__.load({
4518
4585
  return undefined
4519
4586
  }
4520
4587
 
4521
- /**
4522
- * Kanban entry button cloning native button styles to match host theme.
4523
- */
4524
4588
  function createEntry(target, toggle, label) {
4525
4589
  const entry = target.cloneNode(true)
4526
4590
  entry.className = String(target.className) + ' dkb-entry-clone'
@@ -4549,7 +4613,6 @@ window.__ModuleLoader__.load({
4549
4613
  return entry
4550
4614
  }
4551
4615
 
4552
- /** Place button at end of injected extension entries. */
4553
4616
  function placeEntry(target, entry) {
4554
4617
  let anchor = target
4555
4618
  let next = target.nextElementSibling
@@ -4562,7 +4625,6 @@ window.__ModuleLoader__.load({
4562
4625
  return true
4563
4626
  }
4564
4627
 
4565
- /** Sidebar entry button persistent across shell re-renders. */
4566
4628
  function mountSidebarEntry(toggle, label) {
4567
4629
  if (typeof document === 'undefined') return () => {}
4568
4630
 
@@ -4596,7 +4658,6 @@ window.__ModuleLoader__.load({
4596
4658
  }
4597
4659
  }
4598
4660
 
4599
- /** Board overlay container mounted over conversation column. */
4600
4661
  function mountBoard(ctx, toggle) {
4601
4662
  if (typeof document === 'undefined') return () => {}
4602
4663
  let root
@@ -4653,12 +4714,6 @@ window.__ModuleLoader__.load({
4653
4714
  }
4654
4715
  }
4655
4716
 
4656
-
4657
- /**
4658
- * Register component into first available UI slot.
4659
- *
4660
- * @returns {string|undefined} name of successfully resolved slot
4661
- */
4662
4717
  function registerFirst(ctx, candidates, component) {
4663
4718
  for (const entry of candidates) {
4664
4719
  try {