@design.estate/dees-catalog 9.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist_bundle/bundle.js +2636 -2150
  2. package/dist_bundle/bundle.js.map +1 -1
  3. package/dist_ts_web/00_commitinfo_data.js +1 -1
  4. package/dist_ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.d.ts +7 -2
  5. package/dist_ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.js +56 -5
  6. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +1 -0
  7. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +62 -18
  8. package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.d.ts +4 -2
  9. package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.js +7 -2
  10. package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.js +69 -29
  11. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.d.ts +6 -1
  12. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.demo.d.ts +2 -0
  13. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.demo.js +419 -83
  14. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.js +247 -118
  15. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +2 -2
  16. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/renderers.js +2 -4
  17. package/dist_ts_web/elements/00group-harness/interfaces.d.ts +15 -4
  18. package/dist_ts_web/elements/00group-harness/toolregistry.d.ts +2 -1
  19. package/dist_ts_web/elements/00group-harness/toolregistry.js +1 -1
  20. package/dist_ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.d.ts +1 -1
  21. package/dist_ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js +30 -12
  22. package/dist_ts_web/elements/00theme.js +3 -1
  23. package/package.json +1 -1
  24. package/readme.md +19 -3
  25. package/readme.plan.md +97 -0
  26. package/ts_web/00_commitinfo_data.ts +1 -1
  27. package/ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.ts +48 -4
  28. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +62 -17
  29. package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.ts +6 -1
  30. package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.ts +60 -27
  31. package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.demo.ts +341 -88
  32. package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts +257 -125
  33. package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +1 -1
  34. package/ts_web/elements/00group-harness/dees-harness-tool-card/renderers.ts +1 -3
  35. package/ts_web/elements/00group-harness/interfaces.ts +16 -4
  36. package/ts_web/elements/00group-harness/toolregistry.ts +2 -1
  37. package/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.ts +29 -15
  38. package/ts_web/elements/00theme.ts +2 -0
@@ -97,7 +97,7 @@ type TSectionRenderEntry =
97
97
  * Searchable conversation list, embeddable in a sidebar or a DeesModal.
98
98
  * Emits `harness-session-select` on click, `harness-session-open` on
99
99
  * double-click or Enter, and `harness-session-context` with viewport
100
- * pointer coordinates on right-click (the browser menu is suppressed).
100
+ * coordinates on right-click, Actions, or ContextMenu/Shift+F10.
101
101
  *
102
102
  * With `enableGrouping`, sessions render under user-defined `groups` and can
103
103
  * be dragged between groups and reordered. The component never mutates its
@@ -214,32 +214,37 @@ export class DeesHarnessSessionList extends DeesElement {
214
214
  min-height: 0;
215
215
  font-family: var(--dees-font-family);
216
216
  --session-normal: var(--dees-color-text-muted);
217
- --session-working: var(--dees-color-accent-primary);
218
- --session-finished: var(--dees-color-accent-success);
219
- --session-attention: #bf5af2;
220
- --session-error: var(--dees-color-accent-error);
221
- }
222
-
223
- :host([gobright]) {
224
- --session-attention: #af52de;
217
+ --session-working: var(--dees-color-link);
218
+ --session-finished: var(--dees-color-text-success);
219
+ --session-attention: var(--dees-color-text-warning);
220
+ --session-error: var(--dees-color-text-error);
225
221
  }
226
222
 
227
223
  .searchRow {
228
- position: relative;
224
+ display: flex;
225
+ align-items: center;
226
+ gap: var(--dees-spacing-sm);
229
227
  flex: 0 0 auto;
230
228
  padding: var(--dees-spacing-sm) var(--dees-spacing-md) var(--dees-spacing-md);
231
229
  }
232
230
 
231
+ .searchField {
232
+ position: relative;
233
+ flex: 1;
234
+ min-width: 0;
235
+ }
236
+
233
237
  .searchIcon {
234
238
  position: absolute;
235
239
  top: 50%;
236
- left: calc(var(--dees-spacing-md) + 10px);
240
+ left: 10px;
237
241
  color: var(--dees-color-text-muted);
238
- transform: translateY(-62%);
242
+ transform: translateY(-50%);
239
243
  pointer-events: none;
240
244
  }
241
245
 
242
246
  .searchRow input {
247
+ display: block;
243
248
  width: 100%;
244
249
  height: var(--dees-control-height-lg);
245
250
  padding: 0 var(--dees-spacing-md) 0 34px;
@@ -277,6 +282,11 @@ export class DeesHarnessSessionList extends DeesElement {
277
282
  min-height: 0;
278
283
  }
279
284
 
285
+ /* Drag scrolling owns the viewport while drop placeholders move. */
286
+ .list.dragActive {
287
+ overflow-anchor: none;
288
+ }
289
+
280
290
  .scrollShadow {
281
291
  position: absolute;
282
292
  z-index: 1;
@@ -296,20 +306,22 @@ export class DeesHarnessSessionList extends DeesElement {
296
306
  top: 0;
297
307
  background: linear-gradient(
298
308
  to bottom,
299
- color-mix(in srgb, var(--dees-material-thin-bg-opaque) 74%, transparent),
300
- transparent
309
+ var(--dees-color-scroll-edge-shadow),
310
+ color-mix(in srgb, var(--dees-color-scroll-edge-shadow) 35%, transparent) 6px,
311
+ transparent 100%
301
312
  );
302
- box-shadow: var(--dees-shadow-sm);
303
313
  }
304
314
 
305
315
  .scrollShadow.bottom {
306
316
  bottom: 0;
317
+ /* Paint inward from the boundary; an outer box shadow would cast
318
+ from the top of this band and appear to float above the footer. */
307
319
  background: linear-gradient(
308
320
  to top,
309
- color-mix(in srgb, var(--dees-material-thin-bg-opaque) 74%, transparent),
310
- transparent
321
+ var(--dees-color-scroll-edge-shadow),
322
+ color-mix(in srgb, var(--dees-color-scroll-edge-shadow) 35%, transparent) 6px,
323
+ transparent 100%
311
324
  );
312
- box-shadow: var(--dees-shadow-up-sm);
313
325
  }
314
326
 
315
327
  .section {
@@ -335,19 +347,11 @@ export class DeesHarnessSessionList extends DeesElement {
335
347
  box-sizing: border-box;
336
348
  }
337
349
 
338
- .item:hover {
339
- --card-inner-background: var(--dees-color-hover);
340
- }
341
-
342
350
  .item.selected {
343
351
  --card-inner-background: var(--dees-color-nav-selected);
344
352
  --card-inner-border: color-mix(in srgb, var(--dees-color-accent-primary) 35%, transparent);
345
353
  }
346
354
 
347
- .item.selected:hover {
348
- --card-inner-background: var(--dees-color-nav-selected);
349
- }
350
-
351
355
  .itemInner {
352
356
  position: relative;
353
357
  isolation: isolate;
@@ -381,8 +385,7 @@ export class DeesHarnessSessionList extends DeesElement {
381
385
  --card-accent: var(--session-working);
382
386
  }
383
387
 
384
- .item.state-working .itemHeader .stateDot,
385
- .item.state-attention .itemHeader .stateDot {
388
+ .item.active .itemHeader .stateDot {
386
389
  animation: harness-activity-pulse 1.6s ease-in-out infinite;
387
390
  }
388
391
 
@@ -390,6 +393,10 @@ export class DeesHarnessSessionList extends DeesElement {
390
393
  --card-accent: var(--session-finished);
391
394
  }
392
395
 
396
+ .item.state-finished .itemStatus {
397
+ color: var(--dees-color-text-secondary);
398
+ }
399
+
393
400
  .item.state-attention {
394
401
  --card-accent: var(--session-attention);
395
402
  }
@@ -398,6 +405,11 @@ export class DeesHarnessSessionList extends DeesElement {
398
405
  --card-accent: var(--session-error);
399
406
  }
400
407
 
408
+ .item.state-attention .itemInner,
409
+ .item.state-error .itemInner {
410
+ box-shadow: inset 3px 0 var(--card-accent);
411
+ }
412
+
401
413
  .item.resourceDropTarget {
402
414
  outline: 2px solid var(--dees-color-accent-primary);
403
415
  outline-offset: 2px;
@@ -406,12 +418,12 @@ export class DeesHarnessSessionList extends DeesElement {
406
418
 
407
419
  .itemHeader {
408
420
  display: grid;
409
- grid-template-columns: minmax(0, 1fr) 30px;
421
+ grid-template-columns: minmax(0, 1fr) 30px 30px;
410
422
  min-height: 44px;
411
423
  }
412
424
 
413
425
  .itemHeader.draggable {
414
- grid-template-columns: 24px minmax(0, 1fr) 30px;
426
+ grid-template-columns: 24px minmax(0, 1fr) 30px 30px;
415
427
  }
416
428
 
417
429
  .dragHandle {
@@ -437,6 +449,7 @@ export class DeesHarnessSessionList extends DeesElement {
437
449
  }
438
450
 
439
451
  .itemPrimary,
452
+ .sessionActions,
440
453
  .expandToggle {
441
454
  appearance: none;
442
455
  border: 0;
@@ -450,12 +463,13 @@ export class DeesHarnessSessionList extends DeesElement {
450
463
  min-width: 0;
451
464
  align-items: center;
452
465
  gap: var(--dees-spacing-sm);
453
- padding: var(--dees-spacing-sm) var(--dees-spacing-xs) var(--dees-spacing-sm) var(--dees-spacing-md);
466
+ padding: 6px var(--dees-spacing-xs) 6px var(--dees-spacing-md);
454
467
  text-align: left;
455
468
  cursor: pointer;
456
469
  }
457
470
 
458
471
  .itemPrimary:focus-visible,
472
+ .sessionActions:focus-visible,
459
473
  .expandToggle:focus-visible {
460
474
  outline: 2px solid var(--dees-color-accent-primary);
461
475
  outline-offset: -3px;
@@ -463,18 +477,50 @@ export class DeesHarnessSessionList extends DeesElement {
463
477
  }
464
478
 
465
479
  .stateDot {
466
- width: 8px;
467
- height: 8px;
480
+ display: grid;
481
+ place-items: center;
482
+ width: 16px;
483
+ height: 16px;
468
484
  flex: 0 0 auto;
469
- border-radius: 50%;
470
- background: var(--card-accent);
485
+ color: var(--card-accent);
471
486
  }
472
487
 
473
488
  .itemCopy {
489
+ display: grid;
490
+ gap: 2px;
474
491
  min-width: 0;
475
492
  flex: 1;
476
493
  }
477
494
 
495
+ .itemStatus {
496
+ color: var(--card-accent);
497
+ font-size: var(--dees-font-caption2-size, 11px);
498
+ font-weight: 560;
499
+ line-height: 14px;
500
+ overflow: hidden;
501
+ text-overflow: ellipsis;
502
+ white-space: nowrap;
503
+ }
504
+
505
+ .itemIdentity {
506
+ display: flex;
507
+ min-width: 0;
508
+ align-items: center;
509
+ gap: 5px;
510
+ color: var(--dees-color-text-secondary);
511
+ font-size: var(--dees-font-caption2-size, 10px);
512
+ line-height: 14px;
513
+ }
514
+
515
+ .harnessName {
516
+ min-width: 0;
517
+ overflow: hidden;
518
+ text-overflow: ellipsis;
519
+ white-space: nowrap;
520
+ }
521
+
522
+ .itemIdentity dees-icon { flex: 0 0 auto; }
523
+
478
524
  .itemTitle {
479
525
  display: flex;
480
526
  min-width: 0;
@@ -497,11 +543,12 @@ export class DeesHarnessSessionList extends DeesElement {
497
543
  }
498
544
 
499
545
  .itemTime {
500
- margin-top: 2px;
546
+ flex: 0 0 auto;
501
547
  color: var(--dees-color-text-muted);
502
548
  font-size: var(--dees-font-caption2-size, 10px);
503
549
  }
504
550
 
551
+ .sessionActions,
505
552
  .expandToggle {
506
553
  display: grid;
507
554
  place-items: center;
@@ -514,11 +561,6 @@ export class DeesHarnessSessionList extends DeesElement {
514
561
  cursor: pointer;
515
562
  }
516
563
 
517
- .expandToggle:hover {
518
- background: color-mix(in srgb, var(--card-accent) 11%, transparent);
519
- color: var(--dees-color-text-primary);
520
- }
521
-
522
564
  .expandToggle dees-icon {
523
565
  transition: transform var(--dees-transition-fast) var(--dees-ease-standard);
524
566
  }
@@ -536,15 +578,6 @@ export class DeesHarnessSessionList extends DeesElement {
536
578
  color: var(--dees-color-text-secondary);
537
579
  }
538
580
 
539
- .stateLine {
540
- display: flex;
541
- align-items: center;
542
- gap: 6px;
543
- color: var(--card-accent);
544
- font-size: var(--dees-font-caption1-size, 11px);
545
- font-weight: 650;
546
- }
547
-
548
581
  .itemPreview {
549
582
  color: var(--dees-color-text-secondary);
550
583
  font-size: var(--dees-font-caption1-size, 11px);
@@ -720,11 +753,6 @@ export class DeesHarnessSessionList extends DeesElement {
720
753
  cursor: pointer;
721
754
  }
722
755
 
723
- .resourceActions:hover {
724
- background: var(--dees-color-hover);
725
- color: var(--dees-color-text-primary);
726
- }
727
-
728
756
  .resourceDragHandle:focus-visible,
729
757
  .resourcePrimary:focus-visible,
730
758
  .resourceActions:focus-visible {
@@ -791,10 +819,6 @@ export class DeesHarnessSessionList extends DeesElement {
791
819
  text-align: left;
792
820
  }
793
821
 
794
- .groupHeader:hover {
795
- background: var(--dees-color-hover);
796
- }
797
-
798
822
  .groupHeader .chevron {
799
823
  transition: transform var(--dees-transition-fast) var(--dees-ease-standard);
800
824
  }
@@ -816,42 +840,77 @@ export class DeesHarnessSessionList extends DeesElement {
816
840
  outline-offset: -1px;
817
841
  }
818
842
 
819
- .dropLine {
820
- display: none;
843
+ .groupAttention {
844
+ display: inline-flex;
845
+ align-items: center;
846
+ gap: 4px;
847
+ margin-left: auto;
848
+ color: var(--dees-color-text-warning);
849
+ font-size: var(--dees-font-caption2-size, 10px);
821
850
  }
822
851
 
823
- .newGroupRow {
824
- flex: 0 0 auto;
825
- padding: 0 var(--dees-spacing-md) var(--dees-spacing-md);
852
+ .groupAttention + .groupCount { margin-left: 10px; }
853
+
854
+ .dropLine {
855
+ display: none;
826
856
  }
827
857
 
828
858
  .newGroupButton {
829
- display: flex;
830
- align-items: center;
831
- gap: var(--dees-spacing-xs);
832
- width: 100%;
833
- min-height: 34px;
834
- justify-content: center;
835
- padding: var(--dees-spacing-xs) var(--dees-spacing-sm);
836
- border: 1px dashed var(--dees-color-border-default);
837
- border-radius: 11px;
838
- background: color-mix(in srgb, var(--dees-color-bg-primary) 55%, transparent);
859
+ appearance: none;
860
+ display: grid;
861
+ place-items: center;
862
+ flex: 0 0 auto;
863
+ width: var(--dees-control-height-lg);
864
+ height: var(--dees-control-height-lg);
865
+ padding: 0;
866
+ border: 1px solid var(--dees-color-border-default);
867
+ border-radius: var(--dees-radius-lg);
868
+ corner-shape: var(--dees-corner-shape);
869
+ background: var(--dees-color-control-bg);
839
870
  color: var(--dees-color-text-secondary);
840
871
  cursor: pointer;
841
872
  font-family: inherit;
842
- font-size: var(--dees-font-control-size-sm, 12px);
843
873
  }
844
874
 
845
- .newGroupButton:hover {
846
- border-color: var(--dees-color-accent-primary);
847
- color: var(--dees-color-text-primary);
875
+ .newGroupButton:focus-visible {
876
+ outline: 2px solid var(--dees-color-accent-primary);
877
+ outline-offset: 2px;
878
+ }
879
+
880
+ @media (hover: hover) {
881
+ .item:hover {
882
+ --card-inner-background: var(--dees-color-hover);
883
+ }
884
+
885
+ .item.selected:hover {
886
+ --card-inner-background: var(--dees-color-nav-selected);
887
+ }
888
+
889
+ .sessionActions:hover,
890
+ .expandToggle:hover {
891
+ background: color-mix(in srgb, var(--card-accent) 11%, transparent);
892
+ color: var(--dees-color-text-primary);
893
+ }
894
+
895
+ .resourceActions:hover {
896
+ background: var(--dees-color-hover);
897
+ color: var(--dees-color-text-primary);
898
+ }
899
+
900
+ .groupHeader:hover {
901
+ background: var(--dees-color-hover);
902
+ }
903
+
904
+ .newGroupButton:hover {
905
+ background: var(--dees-color-hover);
906
+ color: var(--dees-color-text-primary);
907
+ }
848
908
  }
849
909
 
850
910
  @media (prefers-reduced-motion: reduce) {
851
911
  .item,
852
912
  .itemInner,
853
- .item.state-attention .itemHeader .stateDot,
854
- .item.state-working .itemHeader .stateDot,
913
+ .item.active .itemHeader .stateDot,
855
914
  .scrollShadow,
856
915
  .expandToggle dees-icon {
857
916
  animation: none;
@@ -861,6 +920,16 @@ export class DeesHarnessSessionList extends DeesElement {
861
920
  }
862
921
 
863
922
  @media (pointer: coarse) {
923
+ .searchRow input { height: 44px; }
924
+ .newGroupButton { width: 44px; height: 44px; }
925
+ .itemHeader { grid-template-columns: minmax(0, 1fr) 44px 47px; }
926
+ .itemHeader.draggable { grid-template-columns: 44px minmax(0, 1fr) 44px 47px; }
927
+ .dragHandle,
928
+ .sessionActions,
929
+ .expandToggle { min-width: 44px; min-height: 44px; }
930
+ .sessionActions { margin: 0; }
931
+ .expandToggle { margin: 0 3px 0 0; }
932
+
864
933
  .resourceRow {
865
934
  grid-template-columns: 44px minmax(0, 1fr) 44px;
866
935
  }
@@ -931,7 +1000,8 @@ export class DeesHarnessSessionList extends DeesElement {
931
1000
  }
932
1001
 
933
1002
  private sessionMatchesSearch(sessionArg: IHarnessSessionMeta, queryArg: string): boolean {
934
- return [sessionArg.title, sessionArg.preview, sessionArg.id]
1003
+ return [sessionArg.title, sessionArg.preview, sessionArg.id, sessionArg.harness?.id,
1004
+ sessionArg.harness?.name, this.sessionStatusLabel(sessionArg), this.sessionStateLabel(sessionArg.state ?? 'normal')]
935
1005
  .filter(Boolean)
936
1006
  .join(' ')
937
1007
  .toLowerCase()
@@ -1144,24 +1214,42 @@ export class DeesHarnessSessionList extends DeesElement {
1144
1214
  const groupingActive = this.enableGrouping && !this.search.trim();
1145
1215
  return html`
1146
1216
  <div class="searchRow">
1147
- <dees-icon class="searchIcon" icon="lucide:Search" iconSize="13"></dees-icon>
1148
- <input
1149
- placeholder=${this.acceptedResources.length
1150
- ? 'Search conversations and resources'
1151
- : 'Search conversations'}
1152
- aria-label=${this.acceptedResources.length
1153
- ? 'Search conversations and resources'
1154
- : 'Search conversations'}
1155
- .value=${this.search}
1156
- @input=${(event: Event) => {
1157
- this.search = (event.currentTarget as HTMLInputElement).value;
1158
- }}
1159
- />
1217
+ <div class="searchField">
1218
+ <dees-icon class="searchIcon" icon="lucide:Search" iconSize="13"></dees-icon>
1219
+ <input
1220
+ placeholder=${this.acceptedResources.length
1221
+ ? 'Search conversations and resources'
1222
+ : 'Search conversations'}
1223
+ aria-label=${this.acceptedResources.length
1224
+ ? 'Search conversations and resources'
1225
+ : 'Search conversations'}
1226
+ .value=${this.search}
1227
+ @input=${(event: Event) => {
1228
+ this.search = (event.currentTarget as HTMLInputElement).value;
1229
+ }}
1230
+ />
1231
+ </div>
1232
+ ${this.enableGrouping ? html`
1233
+ <button
1234
+ class="newGroupButton"
1235
+ type="button"
1236
+ aria-label="New group"
1237
+ title="New group"
1238
+ @click=${() => {
1239
+ this.dispatchEvent(new CustomEvent('harness-group-create-request', {
1240
+ bubbles: true,
1241
+ composed: true,
1242
+ }));
1243
+ }}
1244
+ >
1245
+ <dees-icon icon="lucide:FolderPlus" iconSize="14" aria-hidden="true"></dees-icon>
1246
+ </button>
1247
+ ` : ''}
1160
1248
  </div>
1161
1249
  <div class="listFrame">
1162
1250
  <div class="scrollShadow top ${this.topScrollShadowVisible ? 'visible' : ''}"></div>
1163
1251
  <div
1164
- class="list"
1252
+ class="list ${this.draggingSessionId || this.draggingResourceId ? 'dragActive' : ''}"
1165
1253
  @scroll=${this.syncScrollShadowState}
1166
1254
  >
1167
1255
  <div class="listContent">
@@ -1175,27 +1263,6 @@ export class DeesHarnessSessionList extends DeesElement {
1175
1263
  <div class="scrollShadow bottom ${this.bottomScrollShadowVisible ? 'visible' : ''}"></div>
1176
1264
  </div>
1177
1265
  <div class="visuallyHidden" aria-live="polite">${this.moveAnnouncement}</div>
1178
- ${groupingActive
1179
- ? html`
1180
- <div class="newGroupRow">
1181
- <button
1182
- class="newGroupButton"
1183
- type="button"
1184
- @click=${() => {
1185
- this.dispatchEvent(
1186
- new CustomEvent('harness-group-create-request', {
1187
- bubbles: true,
1188
- composed: true,
1189
- }),
1190
- );
1191
- }}
1192
- >
1193
- <dees-icon icon="lucide:FolderPlus" iconSize="13"></dees-icon>
1194
- New group
1195
- </button>
1196
- </div>
1197
- `
1198
- : ''}
1199
1266
  `;
1200
1267
  }
1201
1268
 
@@ -1238,6 +1305,7 @@ export class DeesHarnessSessionList extends DeesElement {
1238
1305
  .map((id) => byId.get(id))
1239
1306
  .filter((session): session is IHarnessSessionMeta => session !== undefined);
1240
1307
  const collapsed = this.collapsedGroupIds.has(group.id);
1308
+ const attentionCount = members.filter((session) => session.state === 'attention' || session.state === 'error').length;
1241
1309
  const isHeaderDrop =
1242
1310
  this.dropSlot?.groupId === group.id
1243
1311
  && this.dropSlot.index === this.sortableSessions(members).length
@@ -1265,6 +1333,9 @@ export class DeesHarnessSessionList extends DeesElement {
1265
1333
  >
1266
1334
  <dees-icon class="chevron" icon="lucide:ChevronDown" iconSize="12"></dees-icon>
1267
1335
  <span>${group.name}</span>
1336
+ ${attentionCount ? html`<span class="groupAttention" aria-label=${`${attentionCount} need attention`}>
1337
+ <dees-icon aria-hidden="true" icon="lucide:CircleAlert" iconSize="11"></dees-icon>${attentionCount}
1338
+ </span>` : ''}
1268
1339
  <span class="groupCount">${members.length}</span>
1269
1340
  </button>
1270
1341
  ${collapsed
@@ -1370,13 +1441,15 @@ export class DeesHarnessSessionList extends DeesElement {
1370
1441
  );
1371
1442
  const expanded = this.expandedSessionIds.has(session.id);
1372
1443
  const state = session.state ?? 'normal';
1444
+ const statusLabel = this.sessionStatusLabel(session);
1445
+ const active = (state === 'normal' || state === 'working') && (session.working ?? state === 'working');
1373
1446
  const detailsId = `session-details-${session.id}`;
1374
1447
  const dropIndex = index < 0 ? 0 : index;
1375
1448
  const resources = this.resourcesForSession(session);
1376
1449
  const isResourceDropTarget = this.resourceDropTargetSessionId === session.id;
1377
1450
  return html`
1378
1451
  <article
1379
- class="item state-${state} ${expanded ? 'expanded' : ''} ${
1452
+ class="item state-${state} ${active ? 'active' : ''} ${expanded ? 'expanded' : ''} ${
1380
1453
  session.id === this.selectedSessionId ? 'selected' : ''
1381
1454
  } ${
1382
1455
  this.draggingSessionId === session.id ? 'dragging' : ''
@@ -1388,12 +1461,14 @@ export class DeesHarnessSessionList extends DeesElement {
1388
1461
  data-drop-index=${dropIndex}
1389
1462
  data-drop-kind=${index < 0 ? 'slot' : 'card'}
1390
1463
  @dblclick=${(event: MouseEvent) => {
1391
- if (this.eventTargetsExpandToggle(event) || this.eventTargetsDragHandle(event)) return;
1464
+ if (this.eventTargetsExpandToggle(event) || this.eventTargetsDragHandle(event)
1465
+ || this.eventTargetsSessionActions(event)) return;
1392
1466
  this.emit('harness-session-open', session);
1393
1467
  }}
1394
1468
  @contextmenu=${(event: MouseEvent) => {
1395
1469
  if (this.eventTargetsExpandToggle(event)) return;
1396
1470
  event.preventDefault();
1471
+ event.stopPropagation();
1397
1472
  const detail: IHarnessSessionContextDetail = {
1398
1473
  session,
1399
1474
  clientX: event.clientX,
@@ -1433,15 +1508,19 @@ export class DeesHarnessSessionList extends DeesElement {
1433
1508
  <button
1434
1509
  class="itemPrimary"
1435
1510
  type="button"
1511
+ aria-keyshortcuts="ContextMenu Shift+F10"
1436
1512
  aria-current=${session.id === this.selectedSessionId ? 'true' : 'false'}
1437
1513
  @click=${() => this.emit('harness-session-select', session)}
1438
1514
  @keydown=${(event: KeyboardEvent) => {
1515
+ if (this.handleSessionContextKey(event)) return;
1439
1516
  if (event.key !== 'Enter') return;
1440
1517
  event.preventDefault();
1441
1518
  this.emit('harness-session-open', session);
1442
1519
  }}
1443
1520
  >
1444
- <span class="stateDot"></span>
1521
+ <span class="stateDot" aria-hidden="true">
1522
+ <dees-icon icon=${this.sessionStateIcon(state)} iconSize="14"></dees-icon>
1523
+ </span>
1445
1524
  <span class="itemCopy">
1446
1525
  <span class="itemTitle">
1447
1526
  ${session.icon
@@ -1449,10 +1528,29 @@ export class DeesHarnessSessionList extends DeesElement {
1449
1528
  : ''}
1450
1529
  <span class="titleText">${session.title || session.id}</span>
1451
1530
  </span>
1452
- <span class="itemTime">${harnessFormatRelativeTime(session.updatedAt ?? session.createdAt)}</span>
1453
- <span class="visuallyHidden">Status: ${this.sessionStateLabel(state)}</span>
1531
+ <span class="itemStatus" title=${statusLabel}>${statusLabel}</span>
1532
+ <span class="itemIdentity">
1533
+ ${session.harness ? html`
1534
+ ${session.harness.icon ? html`<dees-icon aria-hidden="true" icon=${session.harness.icon} iconSize="11"></dees-icon>` : ''}
1535
+ <span class="harnessName" title=${session.harness.name}>${session.harness.name}</span>
1536
+ <span aria-hidden="true">·</span>
1537
+ ` : ''}
1538
+ <span class="itemTime">${harnessFormatRelativeTime(session.updatedAt ?? session.createdAt)}</span>
1539
+ </span>
1454
1540
  </span>
1455
1541
  </button>
1542
+ <button
1543
+ class="sessionActions"
1544
+ type="button"
1545
+ title="Actions"
1546
+ aria-label=${`Actions for ${session.title || session.id}`}
1547
+ aria-haspopup="menu"
1548
+ aria-keyshortcuts="ContextMenu Shift+F10"
1549
+ @click=${this.invokeSessionContext}
1550
+ @keydown=${this.handleSessionContextKey}
1551
+ >
1552
+ <dees-icon icon="lucide:Ellipsis" iconSize="15"></dees-icon>
1553
+ </button>
1456
1554
  <button
1457
1555
  class="expandToggle"
1458
1556
  type="button"
@@ -1484,10 +1582,6 @@ export class DeesHarnessSessionList extends DeesElement {
1484
1582
  ${expanded
1485
1583
  ? html`
1486
1584
  <div class="itemDetails" id=${detailsId}>
1487
- <div class="stateLine">
1488
- <span class="stateDot"></span>
1489
- <span>${this.sessionStateLabel(state)}</span>
1490
- </div>
1491
1585
  ${session.preview ? html`<div class="itemPreview">${session.preview}</div>` : ''}
1492
1586
  <div class="itemMeta">
1493
1587
  ${session.messageCount ? `${session.messageCount} messages · ` : ''}${session.id}
@@ -1623,6 +1717,30 @@ export class DeesHarnessSessionList extends DeesElement {
1623
1717
  `;
1624
1718
  }
1625
1719
 
1720
+ private invokeSessionContext(event: MouseEvent | KeyboardEvent): void {
1721
+ event.preventDefault();
1722
+ event.stopPropagation();
1723
+ const control = event.currentTarget as HTMLElement;
1724
+ const rect = control.getBoundingClientRect();
1725
+ // Use the existing context-menu path, including its composed dialog owner.
1726
+ control.dispatchEvent(new MouseEvent('contextmenu', {
1727
+ bubbles: true, composed: true, cancelable: true,
1728
+ clientX: rect.left + rect.width / 2, clientY: rect.bottom,
1729
+ }));
1730
+ }
1731
+
1732
+ private handleSessionContextKey(event: KeyboardEvent): boolean {
1733
+ if (event.key !== 'ContextMenu' && !(event.key === 'F10' && event.shiftKey)) return false;
1734
+ this.invokeSessionContext(event);
1735
+ return true;
1736
+ }
1737
+
1738
+ private eventTargetsSessionActions(event: Event): boolean {
1739
+ return event.composedPath().some(
1740
+ (target) => target instanceof HTMLElement && target.classList.contains('sessionActions'),
1741
+ );
1742
+ }
1743
+
1626
1744
  private eventTargetsExpandToggle(event: Event): boolean {
1627
1745
  return event.composedPath().some(
1628
1746
  (target) => target instanceof HTMLElement && target.classList.contains('expandToggle'),
@@ -1654,6 +1772,20 @@ export class DeesHarnessSessionList extends DeesElement {
1654
1772
  }
1655
1773
  }
1656
1774
 
1775
+ private sessionStatusLabel(session: IHarnessSessionMeta): string {
1776
+ return session.statusLabel?.trim() || this.sessionStateLabel(session.state ?? 'normal');
1777
+ }
1778
+
1779
+ private sessionStateIcon(state: NonNullable<IHarnessSessionMeta['state']>): string {
1780
+ switch (state) {
1781
+ case 'working': return 'lucide:CircleDashed';
1782
+ case 'finished': return 'lucide:CircleCheck';
1783
+ case 'attention': return 'lucide:MessageCircleQuestion';
1784
+ case 'error': return 'lucide:CircleX';
1785
+ default: return 'lucide:Circle';
1786
+ }
1787
+ }
1788
+
1657
1789
  private toggleSessionExpanded(sessionIdArg: string): void {
1658
1790
  const next = new Set(this.expandedSessionIds);
1659
1791
  if (next.has(sessionIdArg)) next.delete(sessionIdArg);
@@ -1262,7 +1262,7 @@ export class DeesHarnessToolCard extends DeesElement {
1262
1262
  <dees-dataview-codebox
1263
1263
  .progLang=${options?.language ?? 'plaintext'}
1264
1264
  .filename=${options?.filename ?? ''}
1265
- .diffView=${this.diffViewOverride ?? options?.view ?? 'inline'}
1265
+ .diffView=${this.diffViewOverride ?? options?.view ?? 'auto'}
1266
1266
  .unifiedDiff=${options?.unifiedDiff ?? ''}
1267
1267
  .showDiffLineNumbers=${options?.showLineNumbers ?? true}
1268
1268
  .codeBefore=${before}