@design.estate/dees-catalog 4.12.0 → 6.0.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 (37) hide show
  1. package/dist_bundle/bundle.js +2719 -1261
  2. package/dist_ts_web/00_commitinfo_data.js +2 -2
  3. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +23 -4
  4. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +290 -78
  5. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +419 -42
  6. package/dist_ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.js +44 -3
  7. package/dist_ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.js +5 -7
  8. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.js +5 -2
  9. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.d.ts +54 -0
  10. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.demo.d.ts +1 -0
  11. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.demo.js +56 -0
  12. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.js +870 -0
  13. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/index.d.ts +1 -0
  14. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/index.js +2 -0
  15. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +5 -0
  16. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +87 -3
  17. package/dist_ts_web/elements/00group-harness/harness.markdown.js +3 -1
  18. package/dist_ts_web/elements/00group-harness/harness.styles.js +48 -1
  19. package/dist_ts_web/elements/00group-harness/index.d.ts +1 -0
  20. package/dist_ts_web/elements/00group-harness/index.js +2 -1
  21. package/dist_ts_web/elements/00group-harness/interfaces.d.ts +41 -0
  22. package/package.json +1 -1
  23. package/readme.md +13 -5
  24. package/ts_web/00_commitinfo_data.ts +1 -1
  25. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +277 -79
  26. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +367 -36
  27. package/ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.ts +43 -2
  28. package/ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.ts +4 -6
  29. package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts +4 -1
  30. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.demo.ts +67 -0
  31. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts +802 -0
  32. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/index.ts +1 -0
  33. package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +79 -1
  34. package/ts_web/elements/00group-harness/harness.markdown.ts +2 -0
  35. package/ts_web/elements/00group-harness/harness.styles.ts +47 -0
  36. package/ts_web/elements/00group-harness/index.ts +1 -0
  37. package/ts_web/elements/00group-harness/interfaces.ts +48 -0
@@ -6,6 +6,7 @@ import {
6
6
  customElement,
7
7
  type TemplateResult,
8
8
  property,
9
+ state,
9
10
  cssManager,
10
11
  } from '@design.estate/dees-element';
11
12
  import { themeDefaultStyles } from '../../00theme.js';
@@ -14,6 +15,9 @@ import type {
14
15
  IHarnessMessage,
15
16
  IHarnessPermissionRequest,
16
17
  IHarnessQuestionRequest,
18
+ IHarnessIntelligenceExchange,
19
+ IHarnessScratchpad,
20
+ IHarnessSessionMetrics,
17
21
  IHarnessStatus,
18
22
  IHarnessTodoItem,
19
23
  IHarnessUsage,
@@ -24,6 +28,7 @@ import { DeesHarnessToolRegistry } from '../toolregistry.js';
24
28
  import { DeesHarnessMessageList } from '../dees-harness-message-list/dees-harness-message-list.js';
25
29
  import { DeesHarnessComposer } from '../dees-harness-composer/dees-harness-composer.js';
26
30
  import '../dees-harness-todos/dees-harness-todos.js';
31
+ import '../dees-harness-session-sidebar/dees-harness-session-sidebar.js';
27
32
  import '../dees-harness-usage/dees-harness-usage.js';
28
33
  import '../../00group-button/dees-button/dees-button.js';
29
34
  import '../../00group-utility/dees-icon/dees-icon.js';
@@ -40,8 +45,7 @@ declare global {
40
45
  * pinned permission queue, status line, and composer. Owns no business
41
46
  * logic — consumers feed `.messages`/`.permissions`/`.status` (and stream
42
47
  * through `applyDelta()`), and listen for the bubbling harness-* events
43
- * from the children plus `harness-new-session` / `harness-open-sessions`
44
- * from the toolbar.
48
+ * from the children.
45
49
  */
46
50
  @customElement('dees-harness-chat')
47
51
  export class DeesHarnessChat extends DeesElement {
@@ -75,6 +79,44 @@ export class DeesHarnessChat extends DeesElement {
75
79
  @property({ type: Boolean })
76
80
  accessor showTodosPanel: boolean = true;
77
81
 
82
+ @property({ type: Boolean })
83
+ accessor showSessionSidebar: boolean = true;
84
+
85
+ @property({ attribute: false })
86
+ accessor sessionMetrics: IHarnessSessionMetrics = {};
87
+
88
+ @property({ attribute: false })
89
+ accessor scratchpad: IHarnessScratchpad | undefined = undefined;
90
+
91
+ @property({ type: Boolean })
92
+ accessor scratchpadBusy: boolean = false;
93
+
94
+ @property()
95
+ accessor scratchpadError: string = '';
96
+
97
+ @property({ type: Boolean })
98
+ accessor sessionIntelligenceEnabled: boolean = false;
99
+
100
+ @property({ attribute: false })
101
+ accessor intelligenceExchanges: IHarnessIntelligenceExchange[] = [];
102
+
103
+ @property({ type: Boolean })
104
+ accessor intelligenceBusy: boolean = false;
105
+
106
+ @property()
107
+ accessor intelligenceError: string = '';
108
+
109
+ @state()
110
+ private accessor sessionSidebarOpen: boolean = false;
111
+
112
+ @state()
113
+ private accessor desktopSessionSidebarVisible: boolean = true;
114
+
115
+ @state()
116
+ private accessor narrowSessionLayout: boolean = false;
117
+
118
+ private sessionLayoutResizeObserver: ResizeObserver | undefined;
119
+
78
120
  @property()
79
121
  accessor heading: string = '';
80
122
 
@@ -144,6 +186,7 @@ export class DeesHarnessChat extends DeesElement {
144
186
  }
145
187
 
146
188
  .chatBody {
189
+ position: relative;
147
190
  flex: 1;
148
191
  min-height: 0;
149
192
  min-width: 0;
@@ -156,22 +199,135 @@ export class DeesHarnessChat extends DeesElement {
156
199
  min-width: 0;
157
200
  }
158
201
 
159
- .todosPanel {
202
+ .transcriptColumn {
203
+ flex: 1;
204
+ min-height: 0;
205
+ display: flex;
206
+ flex-direction: column;
207
+ }
208
+
209
+ .sessionPanel {
160
210
  flex: 0 0 232px;
161
211
  min-width: 0;
162
- overflow-y: auto;
163
- scrollbar-width: thin;
164
- scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
165
- padding: var(--dees-spacing-sm) var(--dees-spacing-md);
212
+ min-height: 0;
213
+ display: flex;
214
+ flex-direction: column;
215
+ overflow: hidden;
216
+ padding: 0;
166
217
  border-left: 1px solid var(--dees-color-border-subtle);
167
218
  background: var(--dees-color-bg-secondary);
168
219
  }
169
220
 
170
- /* narrow hosts (e.g. a sidebar chat) drop the panel; todo tool cards
171
- in the transcript still carry the same information */
172
- @container (max-width: 520px) {
173
- .todosPanel {
174
- display: none;
221
+ .sessionPanel.desktopHidden {
222
+ display: none;
223
+ }
224
+
225
+ .sessionPanel > dees-harness-session-sidebar {
226
+ flex: 1;
227
+ min-height: 0;
228
+ }
229
+
230
+ .sessionPanelClose,
231
+ .sessionPanelToggle,
232
+ .sessionPanelBackdrop {
233
+ display: none;
234
+ }
235
+
236
+ .sessionPanelToggle,
237
+ .toolbarSessionPanelToggle {
238
+ box-sizing: border-box;
239
+ width: var(--dees-control-height-lg);
240
+ height: var(--dees-control-height-lg);
241
+ padding: 0;
242
+ align-items: center;
243
+ justify-content: center;
244
+ border: 1px solid transparent;
245
+ border-radius: var(--dees-radius-lg);
246
+ corner-shape: var(--dees-corner-shape);
247
+ background: transparent;
248
+ color: var(--dees-color-text-primary);
249
+ cursor: pointer;
250
+ }
251
+
252
+ .toolbarSessionPanelToggle {
253
+ display: flex;
254
+ }
255
+
256
+ .sessionPanelToggle:hover,
257
+ .toolbarSessionPanelToggle:hover {
258
+ background: var(--dees-color-badge-default-bg);
259
+ }
260
+
261
+ .sessionPanelToggle:focus-visible,
262
+ .toolbarSessionPanelToggle:focus-visible {
263
+ outline: 2px solid var(--dees-color-accent-primary);
264
+ outline-offset: 2px;
265
+ }
266
+
267
+ /* Narrow hosts keep every session section reachable in an overlay.
268
+ Todo tool cards remain a second transcript-level representation. */
269
+ @container (max-width: 680px) {
270
+ .sessionPanel {
271
+ position: absolute;
272
+ inset: 0 0 0 auto;
273
+ display: flex;
274
+ width: min(320px, calc(100% - 36px));
275
+ max-width: none;
276
+ padding: 42px 0 0;
277
+ border-left-color: var(--dees-color-border-default);
278
+ box-shadow: var(--dees-shadow-lg);
279
+ visibility: hidden;
280
+ transform: translateX(100%);
281
+ transition:
282
+ transform var(--dees-transition-default) var(--dees-ease-out),
283
+ visibility 0s linear var(--dees-transition-default);
284
+ }
285
+
286
+ .sessionPanel.desktopHidden {
287
+ display: flex;
288
+ }
289
+
290
+ .sessionPanel.open {
291
+ visibility: visible;
292
+ transform: translateX(0);
293
+ transition-delay: 0s;
294
+ }
295
+
296
+ .sessionPanelClose {
297
+ position: absolute;
298
+ top: 6px;
299
+ right: 8px;
300
+ display: block;
301
+ }
302
+
303
+ .sessionPanelToggle {
304
+ position: absolute;
305
+ top: 8px;
306
+ right: 8px;
307
+ display: flex;
308
+ }
309
+
310
+ .sessionPanelBackdrop {
311
+ position: absolute;
312
+ inset: 0;
313
+ display: block;
314
+ border: 0;
315
+ background: color-mix(in srgb, var(--dees-color-bg-primary) 58%, transparent);
316
+ opacity: 0;
317
+ pointer-events: none;
318
+ transition: opacity var(--dees-transition-default) var(--dees-ease-standard);
319
+ }
320
+
321
+ .sessionPanelBackdrop.open {
322
+ opacity: 1;
323
+ pointer-events: auto;
324
+ }
325
+
326
+ @media (prefers-reduced-motion: reduce) {
327
+ .sessionPanel,
328
+ .sessionPanelBackdrop {
329
+ transition: none;
330
+ }
175
331
  }
176
332
  }
177
333
 
@@ -219,7 +375,7 @@ export class DeesHarnessChat extends DeesElement {
219
375
  flex: 0 0 auto;
220
376
  }
221
377
 
222
- .chatBody dees-harness-message-list {
378
+ .transcriptColumn dees-harness-message-list {
223
379
  flex: 1;
224
380
  min-height: 0;
225
381
  }
@@ -232,6 +388,36 @@ export class DeesHarnessChat extends DeesElement {
232
388
  position: relative;
233
389
  z-index: 1;
234
390
  }
391
+
392
+ .composerContextBar {
393
+ min-width: 0;
394
+ display: flex;
395
+ align-items: center;
396
+ gap: var(--dees-spacing-xs);
397
+ padding: 5px var(--dees-spacing-md);
398
+ background: var(--dees-color-bg-secondary);
399
+ color: var(--dees-color-text-muted);
400
+ font-size: var(--dees-font-caption2-size, 10px);
401
+ line-height: 1.3;
402
+ }
403
+
404
+ .composerContextBar dees-icon {
405
+ flex: 0 0 auto;
406
+ color: var(--dees-color-text-secondary);
407
+ }
408
+
409
+ .composerContextLabel {
410
+ flex: 0 0 auto;
411
+ }
412
+
413
+ .composerContextTitle {
414
+ min-width: 0;
415
+ overflow: hidden;
416
+ color: var(--dees-color-text-secondary);
417
+ font-weight: 600;
418
+ text-overflow: ellipsis;
419
+ white-space: nowrap;
420
+ }
235
421
  `,
236
422
  ];
237
423
 
@@ -256,6 +442,32 @@ export class DeesHarnessChat extends DeesElement {
256
442
  this.listElement?.scrollToBottom(force);
257
443
  }
258
444
 
445
+ public async connectedCallback(): Promise<void> {
446
+ await super.connectedCallback();
447
+ await this.updateComplete;
448
+ if (!this.isConnected) return;
449
+ this.syncSessionLayout(this.getBoundingClientRect().width);
450
+ this.sessionLayoutResizeObserver?.disconnect();
451
+ this.sessionLayoutResizeObserver = new ResizeObserver((entries) => {
452
+ const entry = entries[0];
453
+ if (entry) this.syncSessionLayout(entry.contentRect.width);
454
+ });
455
+ this.sessionLayoutResizeObserver.observe(this);
456
+ }
457
+
458
+ public async disconnectedCallback(): Promise<void> {
459
+ this.sessionLayoutResizeObserver?.disconnect();
460
+ this.sessionLayoutResizeObserver = undefined;
461
+ await super.disconnectedCallback();
462
+ }
463
+
464
+ private syncSessionLayout(widthArg: number): void {
465
+ const narrow = widthArg <= 680;
466
+ if (narrow === this.narrowSessionLayout) return;
467
+ this.narrowSessionLayout = narrow;
468
+ this.sessionSidebarOpen = false;
469
+ }
470
+
259
471
  public get effectiveTodos(): IHarnessTodoItem[] {
260
472
  if (this.todos.length) return this.todos;
261
473
  // the newest todo call is the current state — an empty write clears
@@ -269,6 +481,16 @@ export class DeesHarnessChat extends DeesElement {
269
481
  return [];
270
482
  }
271
483
 
484
+ public get hasSessionSidebar(): boolean {
485
+ if (!this.showSessionSidebar) return false;
486
+ return (
487
+ (this.showTodosPanel && this.effectiveTodos.length > 0)
488
+ || Object.values(this.sessionMetrics).some((value) => value !== undefined)
489
+ || this.scratchpad !== undefined
490
+ || this.sessionIntelligenceEnabled
491
+ );
492
+ }
493
+
272
494
  private get listElement(): DeesHarnessMessageList | undefined {
273
495
  const element = this.shadowRoot?.querySelector('dees-harness-message-list');
274
496
  return element instanceof DeesHarnessMessageList ? element : undefined;
@@ -279,26 +501,125 @@ export class DeesHarnessChat extends DeesElement {
279
501
  return element instanceof DeesHarnessComposer ? element : undefined;
280
502
  }
281
503
 
504
+ private readonly toggleSessionSidebar = (): void => {
505
+ if (!this.narrowSessionLayout) {
506
+ this.desktopSessionSidebarVisible = !this.desktopSessionSidebarVisible;
507
+ return;
508
+ }
509
+ if (this.sessionSidebarOpen) {
510
+ void this.closeSessionSidebar();
511
+ return;
512
+ }
513
+ void this.openSessionSidebar();
514
+ };
515
+
516
+ private async openSessionSidebar(): Promise<void> {
517
+ this.sessionSidebarOpen = true;
518
+ await this.updateComplete;
519
+ const panel = this.shadowRoot?.querySelector<HTMLElement>('.sessionPanel');
520
+ await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));
521
+ panel?.focus();
522
+ }
523
+
524
+ private async closeSessionSidebar(): Promise<void> {
525
+ this.sessionSidebarOpen = false;
526
+ await this.updateComplete;
527
+ const toggleButton = this.shadowRoot?.querySelector<HTMLButtonElement>(
528
+ this.showToolbar ? '.toolbarSessionPanelToggle' : '.sessionPanelToggle',
529
+ );
530
+ toggleButton?.focus();
531
+ }
532
+
282
533
  // ----------------------------------------------------------------- render
283
534
 
284
535
  public render(): TemplateResult {
285
536
  return html`
286
537
  ${this.showToolbar ? this.renderToolbar() : ''}
287
538
  <div class="chatBody">
288
- <dees-harness-message-list
289
- .messages=${this.messages}
290
- .permissions=${this.permissions}
291
- .permissionsBusy=${this.disabled}
292
- .questions=${this.questions}
293
- .status=${this.status}
294
- .showRoles=${this.showRoles}
295
- .showTimestamps=${this.showTimestamps}
296
- .toolRegistry=${this.toolRegistry}
297
- ></dees-harness-message-list>
298
- ${this.showTodosPanel && this.effectiveTodos.length
539
+ <div class="transcriptColumn">
540
+ <dees-harness-message-list
541
+ .messages=${this.messages}
542
+ .permissions=${this.permissions}
543
+ .permissionsBusy=${this.disabled}
544
+ .questions=${this.questions}
545
+ .status=${this.status}
546
+ .showRoles=${this.showRoles}
547
+ .showTimestamps=${this.showTimestamps}
548
+ .toolRegistry=${this.toolRegistry}
549
+ ></dees-harness-message-list>
550
+ ${this.heading
551
+ ? html`
552
+ <div class="composerContextBar" title=${`Replying to ${this.heading}`}>
553
+ <dees-icon icon="lucide:MessageSquare" iconSize="11"></dees-icon>
554
+ <span class="composerContextLabel">Replying to</span>
555
+ <span class="composerContextTitle">${this.heading}</span>
556
+ </div>
557
+ `
558
+ : ''}
559
+ ${this.hasSessionSidebar && !this.showToolbar ? html`
560
+ <button
561
+ class="sessionPanelToggle"
562
+ type="button"
563
+ aria-label="Session details"
564
+ title="Session details"
565
+ aria-expanded=${String(this.sessionSidebarOpen)}
566
+ aria-controls="harness-session-panel"
567
+ @click=${this.toggleSessionSidebar}
568
+ >
569
+ <dees-icon icon="lucide:PanelRight" iconSize="16"></dees-icon>
570
+ </button>
571
+ ` : ''}
572
+ </div>
573
+ ${this.hasSessionSidebar
299
574
  ? html`
300
- <aside class="todosPanel">
301
- <dees-harness-todos heading="Tasks" .todos=${this.effectiveTodos}></dees-harness-todos>
575
+ <button
576
+ class=${`sessionPanelBackdrop ${this.sessionSidebarOpen ? 'open' : ''}`}
577
+ aria-label="Close session details"
578
+ aria-hidden=${String(!this.sessionSidebarOpen)}
579
+ ?inert=${!this.sessionSidebarOpen}
580
+ tabindex=${this.sessionSidebarOpen ? '0' : '-1'}
581
+ @click=${() => void this.closeSessionSidebar()}
582
+ ></button>
583
+ <aside
584
+ id="harness-session-panel"
585
+ class=${`todosPanel sessionPanel ${this.sessionSidebarOpen ? 'open' : ''} ${this.desktopSessionSidebarVisible ? '' : 'desktopHidden'}`}
586
+ aria-label="Session details"
587
+ aria-hidden=${String(this.narrowSessionLayout
588
+ ? !this.sessionSidebarOpen
589
+ : !this.desktopSessionSidebarVisible)}
590
+ ?inert=${this.narrowSessionLayout
591
+ ? !this.sessionSidebarOpen
592
+ : !this.desktopSessionSidebarVisible}
593
+ tabindex="-1"
594
+ @keydown=${(event: KeyboardEvent) => {
595
+ if (event.key !== 'Escape' || !this.narrowSessionLayout) return;
596
+ event.preventDefault();
597
+ event.stopPropagation();
598
+ void this.closeSessionSidebar();
599
+ }}
600
+ >
601
+ <dees-button
602
+ class="sessionPanelClose"
603
+ size="icon"
604
+ type="ghost"
605
+ icon="lucide:X"
606
+ text="Close session details"
607
+ title="Close session details"
608
+ @clicked=${() => void this.closeSessionSidebar()}
609
+ ></dees-button>
610
+ <dees-harness-session-sidebar
611
+ .todos=${this.effectiveTodos}
612
+ .showTasks=${this.showTodosPanel}
613
+ .metrics=${this.sessionMetrics}
614
+ .scratchpad=${this.scratchpad}
615
+ .scratchpadBusy=${this.scratchpadBusy}
616
+ .scratchpadError=${this.scratchpadError}
617
+ .intelligenceEnabled=${this.sessionIntelligenceEnabled}
618
+ .intelligenceExchanges=${this.intelligenceExchanges}
619
+ .intelligenceBusy=${this.intelligenceBusy}
620
+ .intelligenceError=${this.intelligenceError}
621
+ .disabled=${this.disabled}
622
+ ></dees-harness-session-sidebar>
302
623
  </aside>
303
624
  `
304
625
  : ''}
@@ -344,18 +665,28 @@ export class DeesHarnessChat extends DeesElement {
344
665
  </div>
345
666
  <div class="toolbarActions">
346
667
  <dees-harness-usage compact .usage=${this.usage}></dees-harness-usage>
347
- <dees-button size="sm" type="ghost" title="Conversations" @clicked=${() => this.emit('harness-open-sessions')}>
348
- <dees-icon icon="lucide:History" iconSize="14"></dees-icon>
349
- </dees-button>
350
- <dees-button size="sm" type="ghost" title="New conversation" @clicked=${() => this.emit('harness-new-session')}>
351
- <dees-icon icon="lucide:SquarePen" iconSize="14"></dees-icon>
352
- </dees-button>
668
+ ${this.hasSessionSidebar ? html`
669
+ <button
670
+ class="toolbarSessionPanelToggle"
671
+ type="button"
672
+ aria-label="Toggle session details"
673
+ title="Toggle session details"
674
+ aria-expanded=${String(this.narrowSessionLayout
675
+ ? this.sessionSidebarOpen
676
+ : this.desktopSessionSidebarVisible)}
677
+ aria-controls="harness-session-panel"
678
+ @click=${this.toggleSessionSidebar}
679
+ >
680
+ <dees-icon
681
+ icon=${this.narrowSessionLayout
682
+ ? (this.sessionSidebarOpen ? 'lucide:PanelRightClose' : 'lucide:PanelRightOpen')
683
+ : (this.desktopSessionSidebarVisible ? 'lucide:PanelRightClose' : 'lucide:PanelRightOpen')}
684
+ iconSize="16"
685
+ ></dees-icon>
686
+ </button>
687
+ ` : ''}
353
688
  </div>
354
689
  </div>
355
690
  `;
356
691
  }
357
-
358
- private emit(name: string): void {
359
- this.dispatchEvent(new CustomEvent(name, { detail: {}, bubbles: true, composed: true }));
360
- }
361
692
  }
@@ -136,6 +136,46 @@ export class DeesHarnessMessage extends DeesElement {
136
136
  background: var(--dees-color-bg-secondary);
137
137
  }
138
138
 
139
+ .message.role-assistant {
140
+ position: relative;
141
+ padding: var(--dees-spacing-xs) var(--dees-spacing-md);
142
+ border: 0;
143
+ border-radius: 0;
144
+ background: transparent;
145
+ }
146
+
147
+ .message.role-assistant::before {
148
+ content: '';
149
+ position: absolute;
150
+ inset: 0 auto 0 0;
151
+ width: 1px;
152
+ background: transparent;
153
+ pointer-events: none;
154
+ }
155
+
156
+ .message.role-assistant.streaming::before {
157
+ background:
158
+ linear-gradient(
159
+ to bottom,
160
+ transparent 40%,
161
+ color-mix(in srgb, var(--dees-color-accent-primary) 85%, transparent) 50%,
162
+ transparent 60%
163
+ ) 0 100% / 100% 250% no-repeat;
164
+ animation: assistantActivityScan 2s linear infinite;
165
+ }
166
+
167
+ @keyframes assistantActivityScan {
168
+ from { background-position: 0 100%; }
169
+ to { background-position: 0 0; }
170
+ }
171
+
172
+ @media (prefers-reduced-motion: reduce) {
173
+ .message.role-assistant.streaming::before {
174
+ animation: none;
175
+ background: color-mix(in srgb, var(--dees-color-accent-primary) 65%, transparent);
176
+ }
177
+ }
178
+
139
179
  .message.role-user {
140
180
  /* chat-like: user turns bind right and size to their content */
141
181
  border-left-color: var(--dees-color-accent-primary);
@@ -210,7 +250,8 @@ export class DeesHarnessMessage extends DeesElement {
210
250
  vertical-align: text-bottom;
211
251
  border-radius: 1px;
212
252
  background: var(--dees-color-accent-primary);
213
- animation: harness-cursor-blink 1s steps(2, start) infinite;
253
+ will-change: opacity;
254
+ animation: harness-cursor-blink 1.2s ease-in-out infinite;
214
255
  }
215
256
 
216
257
  @keyframes harness-cursor-blink {
@@ -385,7 +426,7 @@ export class DeesHarnessMessage extends DeesElement {
385
426
  }
386
427
  const roleClass = `role-${message.role}`;
387
428
  return html`
388
- <div class="message ${roleClass} ${message.error ? 'has-error' : ''}">
429
+ <div class="message ${roleClass} ${message.streaming ? 'streaming' : ''} ${message.error ? 'has-error' : ''}">
389
430
  ${this.showRole || this.showTimestamp || message.model
390
431
  ? html`
391
432
  <div class="roleRow">
@@ -50,10 +50,8 @@ export class DeesHarnessReasoning extends DeesElement {
50
50
  }
51
51
 
52
52
  .reasoning {
53
- border: 1px solid var(--dees-color-border-subtle);
54
- border-radius: var(--dees-radius-md);
55
- corner-shape: var(--dees-corner-shape);
56
- background: var(--dees-color-bg-tertiary);
53
+ border: 0;
54
+ background: transparent;
57
55
  overflow: hidden;
58
56
  animation: harness-reasoning-enter var(--dees-transition-default) var(--dees-ease-out);
59
57
  }
@@ -101,7 +99,7 @@ export class DeesHarnessReasoning extends DeesElement {
101
99
  display: flex;
102
100
  align-items: center;
103
101
  gap: var(--dees-spacing-sm);
104
- padding: var(--dees-spacing-xs) var(--dees-spacing-md);
102
+ padding: var(--dees-spacing-xs) 0;
105
103
  border: 0;
106
104
  background: transparent;
107
105
  color: var(--dees-color-text-secondary);
@@ -165,7 +163,7 @@ export class DeesHarnessReasoning extends DeesElement {
165
163
 
166
164
  .body {
167
165
  margin: 0;
168
- padding: 0 var(--dees-spacing-md) var(--dees-spacing-sm);
166
+ padding: 0 0 var(--dees-spacing-sm) calc(12px + var(--dees-spacing-sm));
169
167
  color: var(--dees-color-text-secondary);
170
168
  white-space: pre-wrap;
171
169
  overflow-wrap: anywhere;
@@ -507,7 +507,10 @@ export class DeesHarnessSessionList extends DeesElement {
507
507
  .expandToggle {
508
508
  display: grid;
509
509
  place-items: center;
510
- margin: 7px 7px 7px 0;
510
+ min-width: 27px;
511
+ min-height: 32px;
512
+ margin: 7px 3px 7px 0;
513
+ padding: 0;
511
514
  border-radius: 9px;
512
515
  color: var(--dees-color-text-muted);
513
516
  cursor: pointer;
@@ -0,0 +1,67 @@
1
+ import { html } from '@design.estate/dees-element';
2
+
3
+ import type {
4
+ IHarnessIntelligenceExchange,
5
+ IHarnessScratchpad,
6
+ IHarnessSessionMetrics,
7
+ IHarnessTodoItem,
8
+ } from '../interfaces.js';
9
+
10
+ const todos: IHarnessTodoItem[] = [
11
+ { content: 'Inspect current context usage', status: 'completed' },
12
+ { content: 'Verify the cache-key patch', status: 'in_progress' },
13
+ { content: 'Prepare the release', status: 'pending' },
14
+ ];
15
+
16
+ const metrics: IHarnessSessionMetrics = {
17
+ lifetimeUsedTokens: 184_320,
18
+ compactionCount: 2,
19
+ tokensBeforeLatestCompaction: 112_840,
20
+ currentContextTokens: 47_200,
21
+ maxContextTokens: 128_000,
22
+ };
23
+
24
+ const scratchpad: IHarnessScratchpad = {
25
+ id: 'demo-session',
26
+ text: '- Cache keys use the route manifest hash.\n- Release after staging verification.',
27
+ revision: 4,
28
+ updatedAt: Date.now() - 45_000,
29
+ updatedBy: 'intelligence',
30
+ };
31
+
32
+ const exchanges: IHarnessIntelligenceExchange[] = [{
33
+ id: 'intelligence-1',
34
+ question: 'What remains before release?',
35
+ answer: 'Staging verification is the only remaining task.',
36
+ status: 'completed',
37
+ model: 'gpt-5.6-luna',
38
+ createdAt: Date.now() - 30_000,
39
+ completedAt: Date.now() - 28_000,
40
+ }];
41
+
42
+ export const demoFunc = () => html`
43
+ <style>
44
+ .harnessSessionSidebarDemo {
45
+ width: 280px;
46
+ height: 720px;
47
+ margin: 40px auto;
48
+ border: 1px solid var(--dees-color-border-subtle);
49
+ background: var(--dees-color-bg-secondary);
50
+ }
51
+ </style>
52
+ <div class="harnessSessionSidebarDemo">
53
+ <dees-harness-session-sidebar
54
+ .todos=${todos}
55
+ .metrics=${metrics}
56
+ .scratchpad=${scratchpad}
57
+ .intelligenceEnabled=${true}
58
+ .intelligenceExchanges=${exchanges}
59
+ @harness-scratchpad-save=${(event: CustomEvent) => {
60
+ console.log('harness-scratchpad-save', event.detail);
61
+ }}
62
+ @harness-session-intelligence-ask=${(event: CustomEvent) => {
63
+ console.log('harness-session-intelligence-ask', event.detail);
64
+ }}
65
+ ></dees-harness-session-sidebar>
66
+ </div>
67
+ `;