@design.estate/dees-catalog 5.0.0 → 6.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.
- package/dist_bundle/bundle.js +526 -134
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +7 -2
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +1 -2
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +110 -26
- package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.d.ts +5 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.js +287 -66
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +5 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +91 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/renderers.js +6 -5
- package/dist_ts_web/elements/00group-harness/harness.styles.js +23 -4
- package/dist_ts_web/elements/00group-harness/interfaces.d.ts +2 -0
- package/package.json +1 -1
- package/readme.md +6 -4
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +0 -1
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +101 -25
- package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts +318 -73
- package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +83 -1
- package/ts_web/elements/00group-harness/dees-harness-tool-card/renderers.ts +5 -4
- package/ts_web/elements/00group-harness/harness.styles.ts +22 -3
- package/ts_web/elements/00group-harness/interfaces.ts +2 -0
package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts
CHANGED
|
@@ -26,6 +26,7 @@ import '../../00group-utility/dees-icon/dees-icon.js';
|
|
|
26
26
|
const { repeat } = directives;
|
|
27
27
|
|
|
28
28
|
const formatTokenCount = (valueArg: number): string => valueArg.toLocaleString('en-US');
|
|
29
|
+
type TSessionSidebarSection = 'tasks' | 'metrics' | 'scratchpad' | 'intelligence';
|
|
29
30
|
|
|
30
31
|
declare global {
|
|
31
32
|
interface HTMLElementTagNameMap {
|
|
@@ -90,13 +91,20 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
90
91
|
@state()
|
|
91
92
|
private accessor intelligenceQuestion: string = '';
|
|
92
93
|
|
|
94
|
+
@state()
|
|
95
|
+
private accessor expandedSection: TSessionSidebarSection | undefined = undefined;
|
|
96
|
+
|
|
97
|
+
private sectionStateInitialized = false;
|
|
98
|
+
|
|
93
99
|
public static styles = [
|
|
94
100
|
themeDefaultStyles,
|
|
95
101
|
cssManager.defaultStyles,
|
|
96
102
|
css`
|
|
97
103
|
:host {
|
|
98
|
-
display:
|
|
104
|
+
display: flex;
|
|
105
|
+
flex-direction: column;
|
|
99
106
|
min-width: 0;
|
|
107
|
+
min-height: 0;
|
|
100
108
|
height: 100%;
|
|
101
109
|
font-family: var(--dees-font-family);
|
|
102
110
|
color: var(--dees-color-text-primary);
|
|
@@ -105,32 +113,206 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
105
113
|
.sidebar {
|
|
106
114
|
display: flex;
|
|
107
115
|
flex-direction: column;
|
|
108
|
-
min-height:
|
|
116
|
+
min-height: 0;
|
|
117
|
+
height: 100%;
|
|
118
|
+
overflow: hidden;
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
.section {
|
|
112
|
-
|
|
122
|
+
display: flex;
|
|
123
|
+
flex: 0 0 auto;
|
|
124
|
+
flex-direction: column;
|
|
125
|
+
min-height: 0;
|
|
126
|
+
overflow: hidden;
|
|
113
127
|
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
114
128
|
}
|
|
115
129
|
|
|
130
|
+
.section.expanded {
|
|
131
|
+
flex: 1 1 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
116
134
|
.section:last-child {
|
|
117
135
|
border-bottom: 0;
|
|
118
136
|
}
|
|
119
137
|
|
|
120
138
|
.sectionHeading {
|
|
121
139
|
display: flex;
|
|
140
|
+
flex: 0 0 auto;
|
|
122
141
|
align-items: center;
|
|
123
142
|
gap: var(--dees-spacing-xs);
|
|
124
|
-
|
|
143
|
+
width: 100%;
|
|
144
|
+
min-height: 30px;
|
|
145
|
+
margin: 0;
|
|
146
|
+
padding: 6px var(--dees-spacing-md) 6px var(--dees-spacing-xs);
|
|
147
|
+
border: 0;
|
|
148
|
+
background: var(--dees-color-bg-secondary);
|
|
125
149
|
color: var(--dees-color-text-primary);
|
|
150
|
+
font-family: inherit;
|
|
126
151
|
font-size: var(--dees-font-control-size-sm, 12px);
|
|
127
152
|
font-weight: 650;
|
|
153
|
+
text-align: left;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.sectionHeading:hover {
|
|
158
|
+
background: var(--dees-color-badge-default-bg);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.sectionHeading:focus-visible {
|
|
162
|
+
position: relative;
|
|
163
|
+
z-index: 1;
|
|
164
|
+
outline: 2px solid var(--dees-color-accent-primary);
|
|
165
|
+
outline-offset: -2px;
|
|
128
166
|
}
|
|
129
167
|
|
|
130
168
|
.sectionHeading dees-icon {
|
|
169
|
+
flex: 0 0 auto;
|
|
131
170
|
color: var(--dees-color-text-secondary);
|
|
132
171
|
}
|
|
133
172
|
|
|
173
|
+
.sectionHeadingText {
|
|
174
|
+
min-width: 0;
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
text-overflow: ellipsis;
|
|
177
|
+
white-space: nowrap;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.sectionSummary {
|
|
181
|
+
flex: 0 0 auto;
|
|
182
|
+
margin-left: auto;
|
|
183
|
+
color: var(--dees-color-text-muted);
|
|
184
|
+
font-size: var(--dees-font-caption2-size, 10px);
|
|
185
|
+
font-variant-numeric: tabular-nums;
|
|
186
|
+
font-weight: 500;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.sectionContent {
|
|
190
|
+
flex: 1;
|
|
191
|
+
min-height: 0;
|
|
192
|
+
overflow-x: hidden;
|
|
193
|
+
overflow-y: auto;
|
|
194
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
195
|
+
scrollbar-width: thin;
|
|
196
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.sectionContent[hidden] {
|
|
200
|
+
display: none;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.sectionContent dees-harness-todos {
|
|
204
|
+
min-width: 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.scratchpadSection .sectionContent:not([hidden]) {
|
|
208
|
+
display: flex;
|
|
209
|
+
flex-direction: column;
|
|
210
|
+
overflow: hidden;
|
|
211
|
+
padding: 0;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.scratchpadSection textarea {
|
|
215
|
+
flex: 1;
|
|
216
|
+
min-height: 0;
|
|
217
|
+
resize: none;
|
|
218
|
+
overflow-y: auto;
|
|
219
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
220
|
+
border: 0;
|
|
221
|
+
border-radius: 0;
|
|
222
|
+
background: color-mix(in srgb, var(--dees-color-bg-secondary) 92%, black);
|
|
223
|
+
color: var(--dees-color-text-secondary);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.scratchpadSection textarea:focus-visible {
|
|
227
|
+
border-color: transparent;
|
|
228
|
+
background: color-mix(in srgb, var(--dees-color-bg-secondary) 92%, black);
|
|
229
|
+
box-shadow: none;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.scratchpadSection .conflict,
|
|
233
|
+
.scratchpadSection .error {
|
|
234
|
+
margin-right: var(--dees-spacing-md);
|
|
235
|
+
margin-left: var(--dees-spacing-md);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.scratchpadFooter {
|
|
239
|
+
display: flex;
|
|
240
|
+
flex: 0 0 auto;
|
|
241
|
+
align-items: center;
|
|
242
|
+
justify-content: space-between;
|
|
243
|
+
gap: var(--dees-spacing-sm);
|
|
244
|
+
padding: var(--dees-spacing-xs) var(--dees-spacing-md) var(--dees-spacing-sm);
|
|
245
|
+
border-top: 0;
|
|
246
|
+
background: linear-gradient(
|
|
247
|
+
to bottom,
|
|
248
|
+
color-mix(in srgb, var(--dees-color-bg-secondary) 92%, black),
|
|
249
|
+
var(--dees-color-bg-secondary)
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.scratchpadFooter .editorMeta {
|
|
254
|
+
margin-top: 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.intelligenceSection .sectionContent:not([hidden]) {
|
|
258
|
+
display: flex;
|
|
259
|
+
flex-direction: column;
|
|
260
|
+
overflow: hidden;
|
|
261
|
+
padding: 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.intelligenceHistory {
|
|
265
|
+
flex: 1;
|
|
266
|
+
min-height: 0;
|
|
267
|
+
overflow-x: hidden;
|
|
268
|
+
overflow-y: auto;
|
|
269
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
270
|
+
scrollbar-width: thin;
|
|
271
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.intelligenceComposer {
|
|
275
|
+
flex: 0 0 auto;
|
|
276
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md) var(--dees-spacing-md);
|
|
277
|
+
background: linear-gradient(
|
|
278
|
+
to bottom,
|
|
279
|
+
var(--dees-color-bg-primary),
|
|
280
|
+
var(--dees-color-bg-secondary)
|
|
281
|
+
);
|
|
282
|
+
box-shadow: var(--dees-shadow-up-sm);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.intelligenceComposer textarea {
|
|
286
|
+
min-height: 64px;
|
|
287
|
+
max-height: 160px;
|
|
288
|
+
resize: none;
|
|
289
|
+
padding: var(--dees-spacing-sm) 0;
|
|
290
|
+
border: 0;
|
|
291
|
+
border-radius: 0;
|
|
292
|
+
background: transparent;
|
|
293
|
+
color: var(--dees-color-text-primary);
|
|
294
|
+
font-family: inherit;
|
|
295
|
+
font-size: var(--dees-font-control-size, 13px);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.intelligenceComposer textarea:focus-visible {
|
|
299
|
+
border-color: transparent;
|
|
300
|
+
box-shadow: none;
|
|
301
|
+
outline: 2px solid color-mix(in srgb, var(--dees-color-accent-primary) 55%, transparent);
|
|
302
|
+
outline-offset: 2px;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.intelligenceControls {
|
|
306
|
+
display: flex;
|
|
307
|
+
align-items: center;
|
|
308
|
+
gap: var(--dees-spacing-sm);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.intelligenceControls .hint {
|
|
312
|
+
flex: 1;
|
|
313
|
+
min-width: 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
134
316
|
.metricList {
|
|
135
317
|
display: grid;
|
|
136
318
|
gap: 6px;
|
|
@@ -281,6 +463,16 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
281
463
|
];
|
|
282
464
|
|
|
283
465
|
protected willUpdate(changedPropertiesArg: Map<PropertyKey, unknown>): void {
|
|
466
|
+
const availableSections = this.availableSections;
|
|
467
|
+
if (!this.sectionStateInitialized && availableSections.length > 0) {
|
|
468
|
+
this.expandedSection = this.defaultExpandedSection;
|
|
469
|
+
this.sectionStateInitialized = true;
|
|
470
|
+
} else if (
|
|
471
|
+
this.expandedSection !== undefined
|
|
472
|
+
&& !availableSections.includes(this.expandedSection)
|
|
473
|
+
) {
|
|
474
|
+
this.expandedSection = this.defaultExpandedSection;
|
|
475
|
+
}
|
|
284
476
|
if (!changedPropertiesArg.has('scratchpad')) return;
|
|
285
477
|
const next = this.scratchpad;
|
|
286
478
|
if (!next) {
|
|
@@ -324,14 +516,70 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
324
516
|
return Object.values(this.metrics).some((value) => value !== undefined);
|
|
325
517
|
}
|
|
326
518
|
|
|
327
|
-
private
|
|
519
|
+
private get availableSections(): TSessionSidebarSection[] {
|
|
520
|
+
return [
|
|
521
|
+
...(this.showTasks ? ['tasks' as const] : []),
|
|
522
|
+
...(this.hasMetrics ? ['metrics' as const] : []),
|
|
523
|
+
...(this.scratchpad ? ['scratchpad' as const] : []),
|
|
524
|
+
...(this.intelligenceEnabled ? ['intelligence' as const] : []),
|
|
525
|
+
];
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
private get defaultExpandedSection(): TSessionSidebarSection | undefined {
|
|
529
|
+
if (this.showTasks && this.todos.length > 0) return 'tasks';
|
|
530
|
+
if (this.hasMetrics) return 'metrics';
|
|
531
|
+
if (this.scratchpad) return 'scratchpad';
|
|
532
|
+
if (this.intelligenceEnabled) return 'intelligence';
|
|
533
|
+
return this.showTasks ? 'tasks' : undefined;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private renderSection(
|
|
537
|
+
idArg: TSessionSidebarSection,
|
|
538
|
+
labelArg: string,
|
|
539
|
+
iconArg: string,
|
|
540
|
+
contentArg: TemplateResult,
|
|
541
|
+
summaryArg = '',
|
|
542
|
+
): TemplateResult {
|
|
543
|
+
const expanded = this.expandedSection === idArg;
|
|
544
|
+
const contentId = `harness-session-section-${idArg}`;
|
|
328
545
|
return html`
|
|
329
|
-
<section class
|
|
330
|
-
<
|
|
546
|
+
<section class=${`section ${idArg}Section ${expanded ? 'expanded' : ''}`}>
|
|
547
|
+
<button
|
|
548
|
+
class="sectionHeading"
|
|
549
|
+
type="button"
|
|
550
|
+
aria-expanded=${String(expanded)}
|
|
551
|
+
aria-controls=${contentId}
|
|
552
|
+
@click=${() => {
|
|
553
|
+
this.sectionStateInitialized = true;
|
|
554
|
+
this.expandedSection = expanded ? undefined : idArg;
|
|
555
|
+
}}
|
|
556
|
+
>
|
|
557
|
+
<dees-icon
|
|
558
|
+
icon=${expanded ? 'lucide:ChevronDown' : 'lucide:ChevronRight'}
|
|
559
|
+
iconSize="13"
|
|
560
|
+
></dees-icon>
|
|
561
|
+
<dees-icon icon=${iconArg} iconSize="13"></dees-icon>
|
|
562
|
+
<span class="sectionHeadingText">${labelArg}</span>
|
|
563
|
+
${summaryArg ? html`<span class="sectionSummary">${summaryArg}</span>` : ''}
|
|
564
|
+
</button>
|
|
565
|
+
<div id=${contentId} class="sectionContent" ?hidden=${!expanded}>
|
|
566
|
+
${contentArg}
|
|
567
|
+
</div>
|
|
331
568
|
</section>
|
|
332
569
|
`;
|
|
333
570
|
}
|
|
334
571
|
|
|
572
|
+
private renderTasks(): TemplateResult {
|
|
573
|
+
const completed = this.todos.filter((todo) => todo.status === 'completed').length;
|
|
574
|
+
return this.renderSection(
|
|
575
|
+
'tasks',
|
|
576
|
+
'Tasks',
|
|
577
|
+
'lucide:ListChecks',
|
|
578
|
+
html`<dees-harness-todos .todos=${this.todos} .showProgress=${false}></dees-harness-todos>`,
|
|
579
|
+
this.todos.length > 0 ? `${completed}/${this.todos.length}` : '',
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
335
583
|
private renderMetrics(): TemplateResult {
|
|
336
584
|
const metrics = this.metrics;
|
|
337
585
|
const percentage = this.contextPercentage;
|
|
@@ -342,12 +590,11 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
342
590
|
['Context window', metrics.maxContextTokens],
|
|
343
591
|
['Current context', metrics.currentContextTokens],
|
|
344
592
|
];
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
</div>
|
|
593
|
+
return this.renderSection(
|
|
594
|
+
'metrics',
|
|
595
|
+
'Tokens',
|
|
596
|
+
'lucide:Gauge',
|
|
597
|
+
html`
|
|
351
598
|
<div class="metricList">
|
|
352
599
|
${rows.map(([label, value]) => value === undefined ? '' : html`
|
|
353
600
|
<div class="metricRow">
|
|
@@ -372,19 +619,17 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
372
619
|
</div>
|
|
373
620
|
`}
|
|
374
621
|
</div>
|
|
375
|
-
|
|
376
|
-
|
|
622
|
+
`,
|
|
623
|
+
);
|
|
377
624
|
}
|
|
378
625
|
|
|
379
626
|
private renderScratchpad(): TemplateResult {
|
|
380
627
|
const scratchpad = this.scratchpad!;
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
<span>Session Scratchpad</span>
|
|
387
|
-
</div>
|
|
628
|
+
return this.renderSection(
|
|
629
|
+
'scratchpad',
|
|
630
|
+
'Session Scratchpad',
|
|
631
|
+
'lucide:NotebookPen',
|
|
632
|
+
html`
|
|
388
633
|
<textarea
|
|
389
634
|
aria-label="Session scratchpad"
|
|
390
635
|
maxlength="32768"
|
|
@@ -401,11 +646,6 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
401
646
|
}
|
|
402
647
|
}}
|
|
403
648
|
></textarea>
|
|
404
|
-
<div class="editorMeta">
|
|
405
|
-
Revision ${scratchpad.revision}${scratchpad.updatedAt
|
|
406
|
-
? ` · updated by ${updatedBy} ${new Date(scratchpad.updatedAt).toLocaleString()}`
|
|
407
|
-
: ''}
|
|
408
|
-
</div>
|
|
409
649
|
${this.scratchpadStale ? html`
|
|
410
650
|
<div class="conflict" role="status">
|
|
411
651
|
A newer revision arrived. Keep this draft on the latest revision or discard it.
|
|
@@ -426,7 +666,8 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
426
666
|
</div>
|
|
427
667
|
` : ''}
|
|
428
668
|
${this.scratchpadError ? html`<div class="error" role="alert">${this.scratchpadError}</div>` : ''}
|
|
429
|
-
<div class="
|
|
669
|
+
<div class="scratchpadFooter">
|
|
670
|
+
<span class="editorMeta">rev. ${scratchpad.revision}</span>
|
|
430
671
|
<dees-button
|
|
431
672
|
size="sm"
|
|
432
673
|
type="accent"
|
|
@@ -436,57 +677,61 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
436
677
|
@clicked=${this.saveScratchpad}
|
|
437
678
|
></dees-button>
|
|
438
679
|
</div>
|
|
439
|
-
|
|
440
|
-
|
|
680
|
+
`,
|
|
681
|
+
);
|
|
441
682
|
}
|
|
442
683
|
|
|
443
684
|
private renderIntelligence(): TemplateResult {
|
|
444
|
-
return
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
685
|
+
return this.renderSection(
|
|
686
|
+
'intelligence',
|
|
687
|
+
'Session Intelligence',
|
|
688
|
+
'lucide:Sparkles',
|
|
689
|
+
html`
|
|
690
|
+
<div class="intelligenceHistory" role="log" aria-live="polite">
|
|
691
|
+
${this.intelligenceExchanges.length ? html`
|
|
692
|
+
<div class="exchangeList">
|
|
693
|
+
${repeat(
|
|
694
|
+
this.intelligenceExchanges,
|
|
695
|
+
(exchange) => exchange.id,
|
|
696
|
+
(exchange) => this.renderExchange(exchange),
|
|
697
|
+
)}
|
|
698
|
+
</div>
|
|
699
|
+
` : html`<div class="empty">Ask about this session without interrupting its main work.</div>`}
|
|
449
700
|
</div>
|
|
450
|
-
|
|
451
|
-
<
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
701
|
+
<div class="intelligenceComposer">
|
|
702
|
+
<textarea
|
|
703
|
+
class="intelligenceInput"
|
|
704
|
+
aria-label="Ask Session Intelligence"
|
|
705
|
+
placeholder="Ask a parallel question…"
|
|
706
|
+
maxlength="8192"
|
|
707
|
+
rows="2"
|
|
708
|
+
.value=${this.intelligenceQuestion}
|
|
709
|
+
?disabled=${this.disabled || this.intelligenceBusy}
|
|
710
|
+
@input=${(event: InputEvent) => {
|
|
711
|
+
this.intelligenceQuestion = (event.currentTarget as HTMLTextAreaElement).value;
|
|
712
|
+
}}
|
|
713
|
+
@keydown=${(event: KeyboardEvent) => {
|
|
714
|
+
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
715
|
+
event.preventDefault();
|
|
716
|
+
this.askIntelligence();
|
|
717
|
+
}
|
|
718
|
+
}}
|
|
719
|
+
></textarea>
|
|
720
|
+
<div class="intelligenceControls">
|
|
721
|
+
<span class="hint">Parallel session · Ctrl/⌘ + Enter</span>
|
|
722
|
+
<dees-button
|
|
723
|
+
size="sm"
|
|
724
|
+
type="accent"
|
|
725
|
+
text="Ask"
|
|
726
|
+
.status=${this.intelligenceBusy ? 'pending' : 'normal'}
|
|
727
|
+
?disabled=${this.disabled || this.intelligenceBusy || !this.intelligenceQuestion.trim()}
|
|
728
|
+
@clicked=${this.askIntelligence}
|
|
729
|
+
></dees-button>
|
|
457
730
|
</div>
|
|
458
|
-
|
|
459
|
-
<textarea
|
|
460
|
-
class="intelligenceInput"
|
|
461
|
-
aria-label="Ask Session Intelligence"
|
|
462
|
-
placeholder="Ask a parallel question…"
|
|
463
|
-
maxlength="8192"
|
|
464
|
-
.value=${this.intelligenceQuestion}
|
|
465
|
-
?disabled=${this.disabled || this.intelligenceBusy}
|
|
466
|
-
@input=${(event: InputEvent) => {
|
|
467
|
-
this.intelligenceQuestion = (event.currentTarget as HTMLTextAreaElement).value;
|
|
468
|
-
}}
|
|
469
|
-
@keydown=${(event: KeyboardEvent) => {
|
|
470
|
-
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
471
|
-
event.preventDefault();
|
|
472
|
-
this.askIntelligence();
|
|
473
|
-
}
|
|
474
|
-
}}
|
|
475
|
-
></textarea>
|
|
476
|
-
<div class="hint">Runs separately from the main session. Ctrl/⌘ + Enter to ask.</div>
|
|
477
|
-
${this.intelligenceError ? html`<div class="error" role="alert">${this.intelligenceError}</div>` : ''}
|
|
478
|
-
<div class="actions">
|
|
479
|
-
<dees-button
|
|
480
|
-
size="sm"
|
|
481
|
-
type="accent"
|
|
482
|
-
text="Ask"
|
|
483
|
-
.status=${this.intelligenceBusy ? 'pending' : 'normal'}
|
|
484
|
-
?disabled=${this.disabled || this.intelligenceBusy || !this.intelligenceQuestion.trim()}
|
|
485
|
-
@clicked=${this.askIntelligence}
|
|
486
|
-
></dees-button>
|
|
731
|
+
${this.intelligenceError ? html`<div class="error" role="alert">${this.intelligenceError}</div>` : ''}
|
|
487
732
|
</div>
|
|
488
|
-
|
|
489
|
-
|
|
733
|
+
`,
|
|
734
|
+
);
|
|
490
735
|
}
|
|
491
736
|
|
|
492
737
|
private renderExchange(exchangeArg: IHarnessIntelligenceExchange): TemplateResult {
|
|
@@ -69,6 +69,9 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
69
69
|
@state()
|
|
70
70
|
accessor returnFlash: boolean = false;
|
|
71
71
|
|
|
72
|
+
@state()
|
|
73
|
+
accessor outcomeScanTone: 'success' | 'error' | null = null;
|
|
74
|
+
|
|
72
75
|
private bodyResizeObserver: ResizeObserver | null = null;
|
|
73
76
|
private observedBodyInner: Element | null = null;
|
|
74
77
|
private fullscreenPortal: HTMLElementTagNameMap['dees-harness-tool-fullscreen'] | null = null;
|
|
@@ -306,6 +309,10 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
306
309
|
font-size: var(--dees-font-caption1-size, 11px);
|
|
307
310
|
}
|
|
308
311
|
|
|
312
|
+
.harness-terminal-exit.tone-success {
|
|
313
|
+
color: var(--dees-color-accent-success);
|
|
314
|
+
}
|
|
315
|
+
|
|
309
316
|
.harness-subtask-open {
|
|
310
317
|
justify-self: start;
|
|
311
318
|
display: inline-flex;
|
|
@@ -332,6 +339,30 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
332
339
|
transform-origin: center;
|
|
333
340
|
}
|
|
334
341
|
|
|
342
|
+
.harness-card.outcomeScan {
|
|
343
|
+
--harness-outcome-scan-color: var(--dees-color-accent-success);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.harness-card.outcomeScan-error {
|
|
347
|
+
--harness-outcome-scan-color: var(--dees-color-accent-error);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.harness-card.outcomeScan::after {
|
|
351
|
+
content: '';
|
|
352
|
+
position: absolute;
|
|
353
|
+
inset: 0;
|
|
354
|
+
pointer-events: none;
|
|
355
|
+
background: linear-gradient(
|
|
356
|
+
105deg,
|
|
357
|
+
transparent 40%,
|
|
358
|
+
color-mix(in srgb, var(--harness-outcome-scan-color) 3%, transparent) 45%,
|
|
359
|
+
color-mix(in srgb, var(--harness-outcome-scan-color) 14%, transparent) 50%,
|
|
360
|
+
color-mix(in srgb, var(--harness-outcome-scan-color) 3%, transparent) 55%,
|
|
361
|
+
transparent 60%
|
|
362
|
+
) 100% 0 / 250% 100% no-repeat;
|
|
363
|
+
animation: harness-tool-outcome-scan 0.48s linear 0.08s both;
|
|
364
|
+
}
|
|
365
|
+
|
|
335
366
|
@keyframes harness-card-return-flash {
|
|
336
367
|
0%, 100% {
|
|
337
368
|
transform: scale(1);
|
|
@@ -341,10 +372,20 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
341
372
|
}
|
|
342
373
|
}
|
|
343
374
|
|
|
375
|
+
@keyframes harness-tool-outcome-scan {
|
|
376
|
+
from { background-position: 100% 0; }
|
|
377
|
+
to { background-position: 0 0; }
|
|
378
|
+
}
|
|
379
|
+
|
|
344
380
|
@media (prefers-reduced-motion: reduce) {
|
|
345
381
|
.harness-card.returnFlash {
|
|
346
382
|
animation: none;
|
|
347
383
|
}
|
|
384
|
+
|
|
385
|
+
.harness-card.outcomeScan::after {
|
|
386
|
+
animation: none;
|
|
387
|
+
opacity: 0;
|
|
388
|
+
}
|
|
348
389
|
}
|
|
349
390
|
`,
|
|
350
391
|
];
|
|
@@ -376,10 +417,12 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
376
417
|
const statusTone = call.isError ? 'error' : call.status === 'completed' ? 'success' : call.status;
|
|
377
418
|
const duration = harnessFormatDuration(call.startedAt, call.finishedAt);
|
|
378
419
|
return html`
|
|
379
|
-
<div class="harness-card status-${call.isError ? 'error' : call.status} ${descriptor.destructive ? 'destructive' : ''} ${this.returnFlash ? 'returnFlash' : ''}"
|
|
420
|
+
<div class="harness-card status-${call.isError ? 'error' : call.status} ${descriptor.destructive ? 'destructive' : ''} ${this.returnFlash ? 'returnFlash' : ''} ${this.outcomeScanTone ? `outcomeScan outcomeScan-${this.outcomeScanTone}` : ''}"
|
|
380
421
|
@animationend=${(event: AnimationEvent) => {
|
|
381
422
|
if (event.animationName === 'harness-card-return-flash') {
|
|
382
423
|
this.endReturnFlash();
|
|
424
|
+
} else if (event.animationName === 'harness-tool-outcome-scan') {
|
|
425
|
+
this.endOutcomeScan();
|
|
383
426
|
}
|
|
384
427
|
}}
|
|
385
428
|
>
|
|
@@ -444,6 +487,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
444
487
|
};
|
|
445
488
|
|
|
446
489
|
private flashFallbackTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
490
|
+
private outcomeScanFallbackTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
447
491
|
|
|
448
492
|
private readonly closeFullscreen = (): void => {
|
|
449
493
|
const portal = this.fullscreenPortal;
|
|
@@ -480,8 +524,42 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
480
524
|
}));
|
|
481
525
|
}
|
|
482
526
|
|
|
527
|
+
private startOutcomeScan(toneArg: 'success' | 'error'): void {
|
|
528
|
+
if (this.outcomeScanFallbackTimeout) clearTimeout(this.outcomeScanFallbackTimeout);
|
|
529
|
+
this.outcomeScanTone = toneArg;
|
|
530
|
+
this.outcomeScanFallbackTimeout = setTimeout(() => this.endOutcomeScan(), 750);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
private endOutcomeScan(): void {
|
|
534
|
+
if (this.outcomeScanFallbackTimeout) {
|
|
535
|
+
clearTimeout(this.outcomeScanFallbackTimeout);
|
|
536
|
+
this.outcomeScanFallbackTimeout = null;
|
|
537
|
+
}
|
|
538
|
+
this.outcomeScanTone = null;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
public willUpdate(changedProperties: Map<PropertyKey, unknown>): void {
|
|
542
|
+
super.willUpdate(changedProperties);
|
|
543
|
+
const previousCall = changedProperties.get('call') as IHarnessToolCall | undefined;
|
|
544
|
+
if (!previousCall || previousCall.id !== this.call.id) return;
|
|
545
|
+
const wasActive = previousCall.status === 'pending' || previousCall.status === 'running';
|
|
546
|
+
const outcomeTone = this.call.status === 'error' || this.call.isError
|
|
547
|
+
? 'error'
|
|
548
|
+
: this.call.status === 'completed'
|
|
549
|
+
? 'success'
|
|
550
|
+
: null;
|
|
551
|
+
if (wasActive && outcomeTone) {
|
|
552
|
+
this.startOutcomeScan(outcomeTone);
|
|
553
|
+
} else if (!outcomeTone && this.outcomeScanTone) {
|
|
554
|
+
this.endOutcomeScan();
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
483
558
|
public updated(changedProperties: Map<PropertyKey, unknown>): void {
|
|
484
559
|
super.updated(changedProperties);
|
|
560
|
+
if (changedProperties.has('call') && this.fullscreenPortal) {
|
|
561
|
+
this.fullscreenPortal.call = this.enrichedCall;
|
|
562
|
+
}
|
|
485
563
|
if (this.uncapped) return;
|
|
486
564
|
const bodyInner = this.shadowRoot?.querySelector('.bodyInner') ?? null;
|
|
487
565
|
if (bodyInner === this.observedBodyInner) return;
|
|
@@ -505,6 +583,10 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
505
583
|
clearTimeout(this.flashFallbackTimeout);
|
|
506
584
|
this.flashFallbackTimeout = null;
|
|
507
585
|
}
|
|
586
|
+
if (this.outcomeScanFallbackTimeout) {
|
|
587
|
+
clearTimeout(this.outcomeScanFallbackTimeout);
|
|
588
|
+
this.outcomeScanFallbackTimeout = null;
|
|
589
|
+
}
|
|
508
590
|
this.fullscreenPortal?.remove();
|
|
509
591
|
this.fullscreenPortal = null;
|
|
510
592
|
this.bodyResizeObserver?.disconnect();
|
|
@@ -105,14 +105,15 @@ const renderTerminal = (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpe
|
|
|
105
105
|
const output = call.output;
|
|
106
106
|
let stdout = '';
|
|
107
107
|
let stderr = '';
|
|
108
|
-
let
|
|
108
|
+
let nestedExitCode: number | undefined;
|
|
109
109
|
if (harnessIsRecord(output)) {
|
|
110
110
|
stdout = typeof output.stdout === 'string' ? output.stdout : harnessStringifyValue(output.stdout ?? '');
|
|
111
111
|
stderr = typeof output.stderr === 'string' ? output.stderr : '';
|
|
112
|
-
|
|
112
|
+
nestedExitCode = typeof output.exitCode === 'number' ? output.exitCode : undefined;
|
|
113
113
|
} else {
|
|
114
114
|
stdout = harnessStringifyValue(output);
|
|
115
115
|
}
|
|
116
|
+
const exitCode = typeof call.exitCode === 'number' ? call.exitCode : nestedExitCode;
|
|
116
117
|
const running = call.status === 'pending' || call.status === 'running';
|
|
117
118
|
return html`
|
|
118
119
|
<div class="harness-terminal">
|
|
@@ -125,8 +126,8 @@ const renderTerminal = (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpe
|
|
|
125
126
|
${running && !stdout && !stderr
|
|
126
127
|
? html`<div class="harness-terminal-running"><span class="cursor"></span> running…</div>`
|
|
127
128
|
: ''}
|
|
128
|
-
${exitCode !== undefined
|
|
129
|
-
? html`<div class="harness-terminal-exit">exit ${exitCode}</div>`
|
|
129
|
+
${exitCode !== undefined
|
|
130
|
+
? html`<div class="harness-terminal-exit ${exitCode === 0 ? 'tone-success' : ''}">exit code ${exitCode}</div>`
|
|
130
131
|
: ''}
|
|
131
132
|
</div>
|
|
132
133
|
`;
|