@design.estate/dees-catalog 6.2.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_bundle/bundle.js +301 -67
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.d.ts +9 -2
- package/dist_ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.js +133 -30
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +3 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +24 -2
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.d.ts +6 -4
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.js +7 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.js +67 -6
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +10 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +77 -9
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/renderers.d.ts +2 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/renderers.js +31 -4
- package/dist_ts_web/elements/00group-harness/interfaces.d.ts +8 -0
- package/dist_ts_web/elements/00group-harness/toolregistry.d.ts +2 -0
- package/dist_ts_web/elements/00group-harness/toolregistry.js +1 -1
- package/package.json +1 -1
- package/readme.hints.md +2 -1
- package/readme.md +13 -6
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.ts +135 -31
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +13 -0
- package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.ts +6 -0
- package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.ts +64 -5
- package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +74 -7
- package/ts_web/elements/00group-harness/dees-harness-tool-card/renderers.ts +43 -4
- package/ts_web/elements/00group-harness/interfaces.ts +10 -0
- package/ts_web/elements/00group-harness/toolregistry.ts +7 -1
|
@@ -40,6 +40,12 @@ declare global {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export type TDiffView = 'inline' | 'split';
|
|
44
|
+
|
|
45
|
+
export interface IDiffViewChangeDetail {
|
|
46
|
+
diffView: TDiffView;
|
|
47
|
+
}
|
|
48
|
+
|
|
43
49
|
@customElement('dees-dataview-codebox')
|
|
44
50
|
export class DeesDataviewCodebox extends DeesElement {
|
|
45
51
|
public static demo = demoFunc;
|
|
@@ -69,7 +75,11 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
69
75
|
|
|
70
76
|
/** '' = regular code view; 'inline' = unified rows; 'split' = side by side */
|
|
71
77
|
@property({ type: String })
|
|
72
|
-
accessor diffView: '' |
|
|
78
|
+
accessor diffView: '' | TDiffView = '';
|
|
79
|
+
|
|
80
|
+
/** Hide gutters when a diff source does not provide trustworthy positions. */
|
|
81
|
+
@property({ type: Boolean })
|
|
82
|
+
accessor showDiffLineNumbers: boolean = true;
|
|
73
83
|
|
|
74
84
|
@state()
|
|
75
85
|
accessor highlightedCode: string = '';
|
|
@@ -123,9 +133,40 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
123
133
|
.appbar .actions {
|
|
124
134
|
grid-column: 3;
|
|
125
135
|
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: var(--dees-spacing-sm);
|
|
126
138
|
justify-content: flex-end;
|
|
127
139
|
}
|
|
128
140
|
|
|
141
|
+
.viewToggle {
|
|
142
|
+
display: flex;
|
|
143
|
+
padding: 2px;
|
|
144
|
+
border: 1px solid var(--dees-color-border-subtle);
|
|
145
|
+
border-radius: var(--dees-radius-md);
|
|
146
|
+
background: var(--dees-color-bg-tertiary);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.viewButton {
|
|
150
|
+
padding: 3px 7px;
|
|
151
|
+
border: 0;
|
|
152
|
+
border-radius: calc(var(--dees-radius-md) - 2px);
|
|
153
|
+
background: transparent;
|
|
154
|
+
color: var(--dees-color-text-muted);
|
|
155
|
+
cursor: pointer;
|
|
156
|
+
font: inherit;
|
|
157
|
+
font-size: var(--dees-font-caption2-size);
|
|
158
|
+
line-height: 1.2;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.viewButton:hover {
|
|
162
|
+
color: var(--dees-color-text-primary);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.viewButton.active {
|
|
166
|
+
background: var(--dees-color-active);
|
|
167
|
+
color: var(--dees-color-text-primary);
|
|
168
|
+
}
|
|
169
|
+
|
|
129
170
|
.copyButton {
|
|
130
171
|
display: flex;
|
|
131
172
|
align-items: center;
|
|
@@ -247,8 +288,37 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
247
288
|
grid-template-columns: minmax(3ch, auto) minmax(3ch, auto) 2ch minmax(0, 1fr);
|
|
248
289
|
}
|
|
249
290
|
|
|
250
|
-
.diffGrid.
|
|
251
|
-
grid-template-columns:
|
|
291
|
+
.diffGrid.inline.withoutLineNumbers {
|
|
292
|
+
grid-template-columns: 2ch minmax(0, 1fr);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.diffSplit {
|
|
296
|
+
display: grid;
|
|
297
|
+
grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr);
|
|
298
|
+
align-items: start;
|
|
299
|
+
min-width: 0;
|
|
300
|
+
padding: var(--dees-spacing-sm) 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.diffSplitDivider {
|
|
304
|
+
align-self: stretch;
|
|
305
|
+
background: var(--dees-color-border-default);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.diffSplitPane {
|
|
309
|
+
min-width: 0;
|
|
310
|
+
overflow-x: auto;
|
|
311
|
+
overflow-y: hidden;
|
|
312
|
+
scrollbar-width: thin;
|
|
313
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.diffGrid.splitSide {
|
|
317
|
+
grid-template-columns: minmax(3ch, auto) 2ch minmax(24ch, 1fr);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.diffGrid.splitSide.withoutLineNumbers {
|
|
321
|
+
grid-template-columns: 2ch minmax(24ch, 1fr);
|
|
252
322
|
}
|
|
253
323
|
|
|
254
324
|
.diffGrid > div {
|
|
@@ -336,10 +406,6 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
336
406
|
color: var(--dees-color-link-hover);
|
|
337
407
|
}
|
|
338
408
|
|
|
339
|
-
.diffSplitSep {
|
|
340
|
-
border-left: 1px solid var(--dees-color-border-subtle);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
409
|
.diffStat {
|
|
344
410
|
font-weight: 600;
|
|
345
411
|
}
|
|
@@ -382,6 +448,24 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
382
448
|
<div slot="header" class="appbar">
|
|
383
449
|
<div class="fileName">${this.filename}</div>
|
|
384
450
|
<div class="actions">
|
|
451
|
+
${this.isDiffActive
|
|
452
|
+
? html`
|
|
453
|
+
<div class="viewToggle" role="group" aria-label="Diff layout">
|
|
454
|
+
<button
|
|
455
|
+
class="viewButton ${this.effectiveDiffView === 'inline' ? 'active' : ''}"
|
|
456
|
+
type="button"
|
|
457
|
+
aria-pressed=${String(this.effectiveDiffView === 'inline')}
|
|
458
|
+
@click=${() => this.setDiffView('inline')}
|
|
459
|
+
>Inline</button>
|
|
460
|
+
<button
|
|
461
|
+
class="viewButton ${this.effectiveDiffView === 'split' ? 'active' : ''}"
|
|
462
|
+
type="button"
|
|
463
|
+
aria-pressed=${String(this.effectiveDiffView === 'split')}
|
|
464
|
+
@click=${() => this.setDiffView('split')}
|
|
465
|
+
>Split</button>
|
|
466
|
+
</div>
|
|
467
|
+
`
|
|
468
|
+
: ''}
|
|
385
469
|
<div
|
|
386
470
|
class="copyButton ${this.copied ? 'copied' : ''}"
|
|
387
471
|
title="Copy code"
|
|
@@ -431,18 +515,14 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
431
515
|
|
|
432
516
|
private renderDiff(): TemplateResult {
|
|
433
517
|
const displayRows = this.displayRowsWithFolds();
|
|
434
|
-
return
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
? this.renderSplitGrid(displayRows)
|
|
438
|
-
: this.renderInlineGrid(displayRows)}
|
|
439
|
-
</div>
|
|
440
|
-
`;
|
|
518
|
+
return this.effectiveDiffView === 'split'
|
|
519
|
+
? this.renderSplitGrid(displayRows)
|
|
520
|
+
: html`<div class="diffScroll">${this.renderInlineGrid(displayRows)}</div>`;
|
|
441
521
|
}
|
|
442
522
|
|
|
443
523
|
private renderInlineGrid(displayRows: TDiffDisplayRow[]): TemplateResult {
|
|
444
524
|
return html`
|
|
445
|
-
<div class="diffGrid inline">
|
|
525
|
+
<div class="diffGrid inline ${this.showDiffLineNumbers ? '' : 'withoutLineNumbers'}">
|
|
446
526
|
${displayRows.map((displayRow) => {
|
|
447
527
|
if (displayRow.kind === 'fold') {
|
|
448
528
|
return this.renderFoldRow(displayRow.rows.length, displayRow.ordinal ?? 0);
|
|
@@ -452,8 +532,12 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
452
532
|
}
|
|
453
533
|
const rowClass = displayRow.kind === 'add' ? 'row-add' : displayRow.kind === 'remove' ? 'row-remove' : '';
|
|
454
534
|
return html`
|
|
455
|
-
|
|
456
|
-
|
|
535
|
+
${this.showDiffLineNumbers
|
|
536
|
+
? html`
|
|
537
|
+
<div class="diffNum ${rowClass}">${displayRow.oldLine ?? ''}</div>
|
|
538
|
+
<div class="diffNum ${rowClass}">${displayRow.newLine ?? ''}</div>
|
|
539
|
+
`
|
|
540
|
+
: ''}
|
|
457
541
|
<div class="diffSign ${rowClass}">${displayRow.kind === 'add' ? '+' : displayRow.kind === 'remove' ? '−' : ''}</div>
|
|
458
542
|
<div class="diffText ${rowClass}">${this.renderDiffLine(displayRow.text, displayRow.segments, displayRow.kind)}</div>
|
|
459
543
|
`;
|
|
@@ -463,18 +547,17 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
463
547
|
}
|
|
464
548
|
|
|
465
549
|
private renderSplitGrid(displayRows: TDiffDisplayRow[]): TemplateResult {
|
|
466
|
-
|
|
467
|
-
const
|
|
550
|
+
const leftRendered: TemplateResult[] = [];
|
|
551
|
+
const rightRendered: TemplateResult[] = [];
|
|
468
552
|
let run: IDiffRow[] = [];
|
|
469
553
|
const flushRun = () => {
|
|
470
554
|
for (const splitRow of buildSplitRows(run)) {
|
|
471
555
|
if (splitRow.kind === 'hunk') {
|
|
472
|
-
|
|
556
|
+
leftRendered.push(html`<div class="diffHunk">${splitRow.text}</div>`);
|
|
557
|
+
rightRendered.push(html`<div class="diffHunk">${splitRow.text}</div>`);
|
|
473
558
|
} else {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
${this.renderSplitCell(splitRow.right, 'right')}
|
|
477
|
-
`);
|
|
559
|
+
leftRendered.push(this.renderSplitCell(splitRow.left));
|
|
560
|
+
rightRendered.push(this.renderSplitCell(splitRow.right));
|
|
478
561
|
}
|
|
479
562
|
}
|
|
480
563
|
run = [];
|
|
@@ -482,27 +565,38 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
482
565
|
for (const displayRow of displayRows) {
|
|
483
566
|
if (displayRow.kind === 'fold') {
|
|
484
567
|
flushRun();
|
|
485
|
-
|
|
568
|
+
leftRendered.push(this.renderFoldRow(displayRow.rows.length, displayRow.ordinal ?? 0));
|
|
569
|
+
rightRendered.push(this.renderFoldRow(displayRow.rows.length, displayRow.ordinal ?? 0));
|
|
486
570
|
} else {
|
|
487
571
|
run.push(displayRow);
|
|
488
572
|
}
|
|
489
573
|
}
|
|
490
574
|
flushRun();
|
|
491
|
-
|
|
575
|
+
const lineNumberClass = this.showDiffLineNumbers ? '' : 'withoutLineNumbers';
|
|
576
|
+
return html`
|
|
577
|
+
<div class="diffSplit">
|
|
578
|
+
<div class="diffSplitPane" data-side="left" aria-label="Before">
|
|
579
|
+
<div class="diffGrid splitSide ${lineNumberClass}">${leftRendered}</div>
|
|
580
|
+
</div>
|
|
581
|
+
<div class="diffSplitDivider" aria-hidden="true"></div>
|
|
582
|
+
<div class="diffSplitPane" data-side="right" aria-label="After">
|
|
583
|
+
<div class="diffGrid splitSide ${lineNumberClass}">${rightRendered}</div>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
`;
|
|
492
587
|
}
|
|
493
588
|
|
|
494
|
-
private renderSplitCell(cell: ISplitCell | undefined
|
|
495
|
-
const separatorClass = side === 'right' ? 'diffSplitSep' : '';
|
|
589
|
+
private renderSplitCell(cell: ISplitCell | undefined): TemplateResult {
|
|
496
590
|
if (!cell) {
|
|
497
591
|
return html`
|
|
498
|
-
|
|
592
|
+
${this.showDiffLineNumbers ? html`<div class="diffNum row-filler"></div>` : ''}
|
|
499
593
|
<div class="diffSign row-filler"></div>
|
|
500
594
|
<div class="diffText row-filler"></div>
|
|
501
595
|
`;
|
|
502
596
|
}
|
|
503
597
|
const rowClass = cell.kind === 'add' ? 'row-add' : cell.kind === 'remove' ? 'row-remove' : '';
|
|
504
598
|
return html`
|
|
505
|
-
|
|
599
|
+
${this.showDiffLineNumbers ? html`<div class="diffNum ${rowClass}">${cell.line || ''}</div>` : ''}
|
|
506
600
|
<div class="diffSign ${rowClass}">${cell.kind === 'add' ? '+' : cell.kind === 'remove' ? '−' : ''}</div>
|
|
507
601
|
<div class="diffText ${rowClass}">${this.renderDiffLine(cell.text, cell.segments, cell.kind)}</div>
|
|
508
602
|
`;
|
|
@@ -552,10 +646,20 @@ export class DeesDataviewCodebox extends DeesElement {
|
|
|
552
646
|
return Boolean(this.unifiedDiff || this.codeBefore || this.diffView);
|
|
553
647
|
}
|
|
554
648
|
|
|
555
|
-
public get effectiveDiffView():
|
|
649
|
+
public get effectiveDiffView(): TDiffView {
|
|
556
650
|
return this.diffView === 'split' ? 'split' : 'inline';
|
|
557
651
|
}
|
|
558
652
|
|
|
653
|
+
private setDiffView(diffViewArg: TDiffView): void {
|
|
654
|
+
if (this.effectiveDiffView === diffViewArg) return;
|
|
655
|
+
this.diffView = diffViewArg;
|
|
656
|
+
this.dispatchEvent(new CustomEvent<IDiffViewChangeDetail>('diff-view-change', {
|
|
657
|
+
detail: { diffView: diffViewArg },
|
|
658
|
+
bubbles: true,
|
|
659
|
+
composed: true,
|
|
660
|
+
}));
|
|
661
|
+
}
|
|
662
|
+
|
|
559
663
|
public willUpdate(changedProperties: Map<string, any>) {
|
|
560
664
|
super.willUpdate(changedProperties);
|
|
561
665
|
if (changedProperties.has('codeToDisplay')) {
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
} from '@design.estate/dees-element';
|
|
12
12
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
13
13
|
import type {
|
|
14
|
+
IHarnessAccountChangeDetail,
|
|
14
15
|
IHarnessAttachment,
|
|
16
|
+
IHarnessComposerOption,
|
|
15
17
|
IHarnessMessage,
|
|
16
18
|
IHarnessPermissionRequest,
|
|
17
19
|
IHarnessQuestionRequest,
|
|
@@ -148,6 +150,12 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
148
150
|
@property({ attribute: false })
|
|
149
151
|
accessor attachments: IHarnessAttachment[] = [];
|
|
150
152
|
|
|
153
|
+
@property()
|
|
154
|
+
accessor account: string = '';
|
|
155
|
+
|
|
156
|
+
@property({ attribute: false })
|
|
157
|
+
accessor accountOptions: IHarnessComposerOption[] = [];
|
|
158
|
+
|
|
151
159
|
@property()
|
|
152
160
|
accessor model: string = '';
|
|
153
161
|
|
|
@@ -641,6 +649,8 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
641
649
|
.disabled=${this.disabled}
|
|
642
650
|
.busy=${this.busy || this.status.type === 'busy'}
|
|
643
651
|
.queuedCount=${this.queuedCount}
|
|
652
|
+
.account=${this.account}
|
|
653
|
+
.accountOptions=${this.accountOptions}
|
|
644
654
|
.model=${this.model}
|
|
645
655
|
.modelOptions=${this.modelOptions}
|
|
646
656
|
.reasoningEffort=${this.reasoningEffort}
|
|
@@ -653,6 +663,9 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
653
663
|
@harness-attachments-change=${(event: CustomEvent<{ attachments: IHarnessAttachment[] }>) => {
|
|
654
664
|
this.attachments = event.detail?.attachments ?? [];
|
|
655
665
|
}}
|
|
666
|
+
@harness-account-change=${(event: CustomEvent<IHarnessAccountChangeDetail>) => {
|
|
667
|
+
if (event.detail?.account) this.account = event.detail.account;
|
|
668
|
+
}}
|
|
656
669
|
@harness-model-change=${(event: CustomEvent<{ model?: string; reasoningEffort?: string }>) => {
|
|
657
670
|
if (event.detail?.model) this.model = event.detail.model;
|
|
658
671
|
if (event.detail?.reasoningEffort) this.reasoningEffort = event.detail.reasoningEffort;
|
|
@@ -29,15 +29,21 @@ export const demoFunc = () => html`
|
|
|
29
29
|
@harness-input=${logEvent}
|
|
30
30
|
@harness-attachments-change=${logEvent}
|
|
31
31
|
@harness-attachment-error=${logEvent}
|
|
32
|
+
@harness-account-change=${logEvent}
|
|
32
33
|
@harness-model-change=${logEvent}
|
|
33
34
|
@harness-mode-change=${logEvent}
|
|
34
35
|
>
|
|
35
36
|
<div class="label">default with mode switcher + model controls (events log to console)</div>
|
|
36
37
|
<dees-harness-composer
|
|
38
|
+
account="account-1"
|
|
37
39
|
model="gpt-5.5"
|
|
38
40
|
reasoningEffort="high"
|
|
39
41
|
mode="Planning"
|
|
40
42
|
.modeOptions=${['Planning', 'Building']}
|
|
43
|
+
.accountOptions=${[
|
|
44
|
+
{ label: 'Personal · alex@example.com', value: 'account-1' },
|
|
45
|
+
{ label: 'Team · alex@example.com', value: 'account-2' },
|
|
46
|
+
]}
|
|
41
47
|
.modelOptions=${['gpt-5.5', 'gpt-5', 'o4-mini']}
|
|
42
48
|
.effortOptions=${['xhigh', 'high', 'medium', 'low']}
|
|
43
49
|
></dees-harness-composer>
|
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
cssManager,
|
|
10
10
|
} from '@design.estate/dees-element';
|
|
11
11
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
12
|
-
import type {
|
|
12
|
+
import type {
|
|
13
|
+
IHarnessAttachment,
|
|
14
|
+
IHarnessComposerOption,
|
|
15
|
+
IHarnessComposerSendDetail,
|
|
16
|
+
} from '../interfaces.js';
|
|
13
17
|
import {
|
|
14
18
|
harnessFileToBase64,
|
|
15
19
|
harnessFormatBytes,
|
|
@@ -33,16 +37,19 @@ type TDropdownOption = { option: string; key: string };
|
|
|
33
37
|
const toDropdownOptions = (values: string[]): TDropdownOption[] =>
|
|
34
38
|
values.map((value) => ({ option: value, key: value }));
|
|
35
39
|
|
|
40
|
+
const toLabeledDropdownOptions = (values: IHarnessComposerOption[]): TDropdownOption[] =>
|
|
41
|
+
values.map((value) => ({ option: value.label, key: value.value }));
|
|
42
|
+
|
|
36
43
|
/**
|
|
37
44
|
* Prompt composer: autogrow textarea, attachments (picker / paste /
|
|
38
|
-
* drag-drop with per-file and total size limits), optional model
|
|
39
|
-
* reasoning-effort dropdowns. Cmd/Ctrl+Enter sends. While busy, Stop is an
|
|
45
|
+
* drag-drop with per-file and total size limits), optional account, model,
|
|
46
|
+
* and reasoning-effort dropdowns. Cmd/Ctrl+Enter sends. While busy, Stop is an
|
|
40
47
|
* additional button and Send stays available for queueing; an empty prompt
|
|
41
48
|
* with queued messages offers "Steer now".
|
|
42
49
|
*
|
|
43
50
|
* Controlled component: `value` and `attachments` are owned by the host;
|
|
44
51
|
* the composer emits `harness-input`, `harness-attachments-change`,
|
|
45
|
-
* `harness-attachment-error`, `harness-model-change`, `harness-send`,
|
|
52
|
+
* `harness-attachment-error`, `harness-account-change`, `harness-model-change`, `harness-send`,
|
|
46
53
|
* `harness-steer`, and `harness-abort` (all bubbling + composed).
|
|
47
54
|
*/
|
|
48
55
|
@customElement('dees-harness-composer')
|
|
@@ -90,6 +97,12 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
90
97
|
@property({ type: Number })
|
|
91
98
|
accessor maxTotalAttachmentBytes: number = harnessMaxTotalAttachmentBytes;
|
|
92
99
|
|
|
100
|
+
@property()
|
|
101
|
+
accessor account: string = '';
|
|
102
|
+
|
|
103
|
+
@property({ attribute: false })
|
|
104
|
+
accessor accountOptions: IHarnessComposerOption[] = [];
|
|
105
|
+
|
|
93
106
|
@property()
|
|
94
107
|
accessor model: string = '';
|
|
95
108
|
|
|
@@ -122,6 +135,7 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
122
135
|
:host {
|
|
123
136
|
display: block;
|
|
124
137
|
font-family: var(--dees-font-family);
|
|
138
|
+
container-type: inline-size;
|
|
125
139
|
}
|
|
126
140
|
|
|
127
141
|
.composer {
|
|
@@ -296,6 +310,12 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
296
310
|
margin: 0;
|
|
297
311
|
}
|
|
298
312
|
|
|
313
|
+
.accountSelect {
|
|
314
|
+
flex: 0 1 180px;
|
|
315
|
+
width: 180px;
|
|
316
|
+
min-width: 120px;
|
|
317
|
+
}
|
|
318
|
+
|
|
299
319
|
/* Model identifiers are provider-qualified ("anthropic/claude-opus-5"),
|
|
300
320
|
so the control grows into the free space instead of truncating,
|
|
301
321
|
while still shrinking on narrow hosts. */
|
|
@@ -313,6 +333,25 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
313
333
|
.spacer {
|
|
314
334
|
flex: 1;
|
|
315
335
|
}
|
|
336
|
+
|
|
337
|
+
@container (max-width: 760px) {
|
|
338
|
+
.controlsRow {
|
|
339
|
+
flex-wrap: wrap;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.modelControls {
|
|
343
|
+
order: 3;
|
|
344
|
+
flex: 1 0 100%;
|
|
345
|
+
flex-wrap: wrap;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.accountSelect,
|
|
349
|
+
.modelSelect {
|
|
350
|
+
flex: 1 1 140px;
|
|
351
|
+
width: auto;
|
|
352
|
+
min-width: 0;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
316
355
|
`,
|
|
317
356
|
];
|
|
318
357
|
|
|
@@ -386,9 +425,28 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
386
425
|
</div>
|
|
387
426
|
`
|
|
388
427
|
: ''}
|
|
389
|
-
${this.showModelControls && (
|
|
428
|
+
${this.showModelControls && (
|
|
429
|
+
this.accountOptions.length || this.modelOptions.length || this.effortOptions.length
|
|
430
|
+
)
|
|
390
431
|
? html`
|
|
391
432
|
<div class="modelControls">
|
|
433
|
+
${this.accountOptions.length
|
|
434
|
+
? html`
|
|
435
|
+
<dees-input-dropdown
|
|
436
|
+
class="accountSelect"
|
|
437
|
+
.options=${toLabeledDropdownOptions(this.accountOptions)}
|
|
438
|
+
.selectedOption=${this.account
|
|
439
|
+
? toLabeledDropdownOptions(this.accountOptions)
|
|
440
|
+
.find((option) => option.key === this.account) ?? null
|
|
441
|
+
: null}
|
|
442
|
+
.disabled=${this.disabled}
|
|
443
|
+
@selectedOption=${(event: CustomEvent<TDropdownOption>) => {
|
|
444
|
+
this.account = event.detail?.key ?? this.account;
|
|
445
|
+
this.emit('harness-account-change', { account: this.account });
|
|
446
|
+
}}
|
|
447
|
+
></dees-input-dropdown>
|
|
448
|
+
`
|
|
449
|
+
: ''}
|
|
392
450
|
${this.modelOptions.length
|
|
393
451
|
? html`
|
|
394
452
|
<dees-input-dropdown
|
|
@@ -589,6 +647,7 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
589
647
|
const detail: IHarnessComposerSendDetail = {
|
|
590
648
|
text: this.value,
|
|
591
649
|
attachments: this.attachments,
|
|
650
|
+
account: this.account || undefined,
|
|
592
651
|
model: this.model || undefined,
|
|
593
652
|
reasoningEffort: this.reasoningEffort || undefined,
|
|
594
653
|
};
|
|
@@ -31,6 +31,10 @@ import {
|
|
|
31
31
|
harnessTruncate,
|
|
32
32
|
} from '../harness.helpers.js';
|
|
33
33
|
import { DeesHarnessMessageList } from '../dees-harness-message-list/dees-harness-message-list.js';
|
|
34
|
+
import type {
|
|
35
|
+
IDiffViewChangeDetail,
|
|
36
|
+
TDiffView,
|
|
37
|
+
} from '../../00group-dataview/dees-dataview-codebox/dees-dataview-codebox.js';
|
|
34
38
|
import '../dees-harness-content-blocks/dees-harness-content-blocks.js';
|
|
35
39
|
import '../dees-harness-overflow-text.js';
|
|
36
40
|
import '../../00group-dataview/dees-dataview-codebox/dees-dataview-codebox.js';
|
|
@@ -91,12 +95,18 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
91
95
|
@state()
|
|
92
96
|
accessor outcomeScanTone: 'success' | 'error' | null = null;
|
|
93
97
|
|
|
98
|
+
@state()
|
|
99
|
+
accessor diffViewOverride: TDiffView | null = null;
|
|
100
|
+
|
|
94
101
|
private bodyResizeObserver: ResizeObserver | null = null;
|
|
95
102
|
private observedBodyInner: Element | null = null;
|
|
96
103
|
private fullscreenPortal: HTMLElementTagNameMap['dees-harness-tool-fullscreen'] | null = null;
|
|
97
104
|
private disclosureFrame: number | null = null;
|
|
98
105
|
private subtaskResultElement: HTMLElement | null = null;
|
|
99
106
|
private subtaskResultResizeObserver: ResizeObserver | null = null;
|
|
107
|
+
private terminalTailFollowing = true;
|
|
108
|
+
private terminalTailReturnTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
109
|
+
private terminalTailReturnDelayMs = 5000;
|
|
100
110
|
|
|
101
111
|
public static styles = [
|
|
102
112
|
themeDefaultStyles,
|
|
@@ -496,7 +506,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
496
506
|
border: 1px solid var(--dees-color-border-subtle);
|
|
497
507
|
border-radius: var(--dees-radius-md);
|
|
498
508
|
corner-shape: var(--dees-corner-shape);
|
|
499
|
-
background:
|
|
509
|
+
background: #0c0c0e;
|
|
500
510
|
overflow: hidden;
|
|
501
511
|
font-family: var(--dees-font-family-mono);
|
|
502
512
|
font-size: var(--dees-font-control-size-sm, 12px);
|
|
@@ -506,7 +516,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
506
516
|
.harness-terminal-command {
|
|
507
517
|
padding: var(--dees-spacing-xs) var(--dees-spacing-md);
|
|
508
518
|
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
509
|
-
color:
|
|
519
|
+
color: #f5f5f7;
|
|
510
520
|
font-weight: 600;
|
|
511
521
|
white-space: pre-wrap;
|
|
512
522
|
overflow-wrap: anywhere;
|
|
@@ -521,7 +531,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
521
531
|
margin: 0;
|
|
522
532
|
padding: var(--dees-spacing-xs) var(--dees-spacing-md) var(--dees-spacing-sm);
|
|
523
533
|
max-height: 100%;
|
|
524
|
-
color:
|
|
534
|
+
color: #c7c7cc;
|
|
525
535
|
white-space: pre-wrap;
|
|
526
536
|
overflow-wrap: anywhere;
|
|
527
537
|
}
|
|
@@ -535,7 +545,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
535
545
|
align-items: center;
|
|
536
546
|
gap: var(--dees-spacing-xs);
|
|
537
547
|
padding: var(--dees-spacing-xs) var(--dees-spacing-md) var(--dees-spacing-sm);
|
|
538
|
-
color:
|
|
548
|
+
color: #8e8e93;
|
|
539
549
|
}
|
|
540
550
|
|
|
541
551
|
.harness-terminal-running .cursor {
|
|
@@ -691,6 +701,8 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
691
701
|
const duration = harnessFormatDuration(call.startedAt, call.finishedAt);
|
|
692
702
|
return html`
|
|
693
703
|
<div class="harness-card status-${effectiveStatus} ${descriptor.destructive ? 'destructive' : ''} ${this.hasSubtaskPreview ? 'subtaskPreviewCard' : ''} ${this.hasSubtaskPreview && open ? 'subtaskPreviewOpen' : ''} ${this.returnFlash ? 'returnFlash' : ''} ${this.outcomeScanTone ? `outcomeScan outcomeScan-${this.outcomeScanTone}` : ''}"
|
|
704
|
+
@mouseenter=${this.cancelTerminalTailReturn}
|
|
705
|
+
@mouseleave=${this.scheduleTerminalTailReturn}
|
|
694
706
|
@animationend=${(event: AnimationEvent) => {
|
|
695
707
|
if (event.animationName === 'harness-card-return-flash') {
|
|
696
708
|
this.endReturnFlash();
|
|
@@ -735,6 +747,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
735
747
|
<div
|
|
736
748
|
class="bodyClipFrame"
|
|
737
749
|
style=${this.uncapped || this.activeSubtaskPreview ? '' : `max-height: ${this.bodyCapPx}px;`}
|
|
750
|
+
@scroll=${this.handleBodyScroll}
|
|
738
751
|
>
|
|
739
752
|
<div class=${`body bodyInner ${this.hasLiveSubtaskPreview ? 'liveSubtaskBody' : ''}`}>
|
|
740
753
|
${this.renderBody(call)}
|
|
@@ -849,7 +862,13 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
849
862
|
public willUpdate(changedProperties: Map<PropertyKey, unknown>): void {
|
|
850
863
|
super.willUpdate(changedProperties);
|
|
851
864
|
const previousCall = changedProperties.get('call') as IHarnessToolCall | undefined;
|
|
852
|
-
if (!previousCall
|
|
865
|
+
if (!previousCall) return;
|
|
866
|
+
if (previousCall.id !== this.call.id) {
|
|
867
|
+
this.diffViewOverride = null;
|
|
868
|
+
this.terminalTailFollowing = true;
|
|
869
|
+
this.cancelTerminalTailReturn();
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
853
872
|
const previousStatus = harnessEffectiveToolStatus(previousCall);
|
|
854
873
|
const currentStatus = harnessEffectiveToolStatus(this.call);
|
|
855
874
|
const wasActive = previousStatus === 'pending' || previousStatus === 'running';
|
|
@@ -880,7 +899,15 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
880
899
|
return;
|
|
881
900
|
}
|
|
882
901
|
const bodyInner = this.shadowRoot?.querySelector('.bodyInner') ?? null;
|
|
883
|
-
if (bodyInner === this.observedBodyInner)
|
|
902
|
+
if (bodyInner === this.observedBodyInner) {
|
|
903
|
+
if (
|
|
904
|
+
(changedProperties.has('call') || changedProperties.has('bodyCapPx'))
|
|
905
|
+
&& this.terminalTailFollowing
|
|
906
|
+
) {
|
|
907
|
+
this.scrollTerminalToTail();
|
|
908
|
+
}
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
884
911
|
this.bodyResizeObserver?.disconnect();
|
|
885
912
|
this.observedBodyInner = bodyInner;
|
|
886
913
|
if (!bodyInner) {
|
|
@@ -892,10 +919,46 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
892
919
|
if (!inner) return;
|
|
893
920
|
// small slack so a few px never trigger the cap chrome
|
|
894
921
|
this.bodyOverflowing = inner.scrollHeight > this.bodyCapPx + 24;
|
|
922
|
+
if (this.terminalTailFollowing) this.scrollTerminalToTail();
|
|
895
923
|
});
|
|
896
924
|
this.bodyResizeObserver.observe(bodyInner);
|
|
925
|
+
if (this.terminalTailFollowing) this.scrollTerminalToTail();
|
|
897
926
|
}
|
|
898
927
|
|
|
928
|
+
private readonly handleBodyScroll = (eventArg: Event): void => {
|
|
929
|
+
if (this.descriptor.kind !== 'terminal' || this.uncapped) return;
|
|
930
|
+
const frame = eventArg.currentTarget as HTMLElement;
|
|
931
|
+
this.terminalTailFollowing = frame.scrollHeight - frame.scrollTop - frame.clientHeight <= 2;
|
|
932
|
+
if (this.terminalTailFollowing) this.cancelTerminalTailReturn();
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
private scrollTerminalToTail(): void {
|
|
936
|
+
if (this.descriptor.kind !== 'terminal' || this.uncapped || !this.isOpen) return;
|
|
937
|
+
const frame = this.shadowRoot?.querySelector<HTMLElement>('.bodyClipFrame');
|
|
938
|
+
if (!frame) return;
|
|
939
|
+
frame.scrollTop = frame.scrollHeight;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
private readonly scheduleTerminalTailReturn = (): void => {
|
|
943
|
+
if (this.descriptor.kind !== 'terminal' || this.terminalTailFollowing || this.uncapped) return;
|
|
944
|
+
this.cancelTerminalTailReturn();
|
|
945
|
+
this.terminalTailReturnTimeout = setTimeout(() => {
|
|
946
|
+
this.terminalTailReturnTimeout = null;
|
|
947
|
+
this.terminalTailFollowing = true;
|
|
948
|
+
this.scrollTerminalToTail();
|
|
949
|
+
}, this.terminalTailReturnDelayMs);
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
private readonly cancelTerminalTailReturn = (): void => {
|
|
953
|
+
if (!this.terminalTailReturnTimeout) return;
|
|
954
|
+
clearTimeout(this.terminalTailReturnTimeout);
|
|
955
|
+
this.terminalTailReturnTimeout = null;
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
private readonly handleDiffViewChange = (eventArg: CustomEvent<IDiffViewChangeDetail>): void => {
|
|
959
|
+
this.diffViewOverride = eventArg.detail.diffView;
|
|
960
|
+
};
|
|
961
|
+
|
|
899
962
|
private readonly syncSubtaskResultScroll = (): void => {
|
|
900
963
|
const result = this.subtaskResultElement;
|
|
901
964
|
if (!result) return;
|
|
@@ -943,6 +1006,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
943
1006
|
clearTimeout(this.outcomeScanFallbackTimeout);
|
|
944
1007
|
this.outcomeScanFallbackTimeout = null;
|
|
945
1008
|
}
|
|
1009
|
+
this.cancelTerminalTailReturn();
|
|
946
1010
|
this.fullscreenPortal?.remove();
|
|
947
1011
|
this.fullscreenPortal = null;
|
|
948
1012
|
this.bodyResizeObserver?.disconnect();
|
|
@@ -1076,9 +1140,12 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
1076
1140
|
<dees-dataview-codebox
|
|
1077
1141
|
.progLang=${options?.language ?? 'plaintext'}
|
|
1078
1142
|
.filename=${options?.filename ?? ''}
|
|
1079
|
-
.diffView=${options?.view ?? 'inline'}
|
|
1143
|
+
.diffView=${this.diffViewOverride ?? options?.view ?? 'inline'}
|
|
1144
|
+
.unifiedDiff=${options?.unifiedDiff ?? ''}
|
|
1145
|
+
.showDiffLineNumbers=${options?.showLineNumbers ?? true}
|
|
1080
1146
|
.codeBefore=${before}
|
|
1081
1147
|
.codeToDisplay=${after}
|
|
1148
|
+
@diff-view-change=${this.handleDiffViewChange}
|
|
1082
1149
|
></dees-dataview-codebox>
|
|
1083
1150
|
`,
|
|
1084
1151
|
monoBlock: (text, options) => {
|