@design.estate/dees-catalog 3.93.0 → 3.94.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 (42) hide show
  1. package/dist_bundle/bundle.js +1936 -1376
  2. package/dist_ts_web/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +6 -3
  4. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +34 -4
  5. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +49 -45
  6. package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.d.ts +13 -0
  7. package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.js +5 -2
  8. package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.js +118 -3
  9. package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.d.ts +25 -3
  10. package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.js +156 -48
  11. package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.d.ts +2 -0
  12. package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.js +9 -5
  13. package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.d.ts +31 -0
  14. package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.d.ts +1 -0
  15. package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.js +69 -0
  16. package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.js +382 -0
  17. package/dist_ts_web/elements/00group-harness/dees-harness-question-card/index.d.ts +1 -0
  18. package/dist_ts_web/elements/00group-harness/dees-harness-question-card/index.js +2 -0
  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 +33 -0
  22. package/dist_ts_web/elements/00group-harness/toolregistry.js +9 -1
  23. package/dist_ts_web/elements/00theme.js +6 -1
  24. package/dist_watch/bundle.js +1937 -1377
  25. package/dist_watch/bundle.js.map +4 -4
  26. package/package.json +1 -1
  27. package/readme.md +13 -5
  28. package/readme.playbook.md +1 -1
  29. package/ts_web/00_commitinfo_data.ts +1 -1
  30. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +37 -3
  31. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +31 -44
  32. package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.ts +4 -1
  33. package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.ts +99 -0
  34. package/ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.ts +148 -46
  35. package/ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.ts +9 -4
  36. package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.ts +70 -0
  37. package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.ts +319 -0
  38. package/ts_web/elements/00group-harness/dees-harness-question-card/index.ts +1 -0
  39. package/ts_web/elements/00group-harness/index.ts +1 -0
  40. package/ts_web/elements/00group-harness/interfaces.ts +36 -0
  41. package/ts_web/elements/00group-harness/toolregistry.ts +8 -0
  42. package/ts_web/elements/00theme.ts +7 -0
@@ -0,0 +1,319 @@
1
+ import { demoFunc } from './dees-harness-question-card.demo.js';
2
+ import {
3
+ DeesElement,
4
+ html,
5
+ css,
6
+ customElement,
7
+ type TemplateResult,
8
+ property,
9
+ state,
10
+ cssManager,
11
+ } from '@design.estate/dees-element';
12
+ import { themeDefaultStyles } from '../../00theme.js';
13
+ import type { IHarnessQuestionRequest } from '../interfaces.js';
14
+ import '../../00group-button/dees-button/dees-button.js';
15
+ import '../../00group-utility/dees-icon/dees-icon.js';
16
+
17
+ declare global {
18
+ interface HTMLElementTagNameMap {
19
+ 'dees-harness-question-card': DeesHarnessQuestionCard;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * A question the agent asks mid-run: option buttons (single-select answers
25
+ * immediately, multi-select collects then confirms) plus an optional
26
+ * free-text answer. Emits `harness-question-response` (bubbles, composed).
27
+ * Answered cards persist showing the chosen answer(s) — the host sets
28
+ * `response`/`respondedAt` on the request and keeps it in the array.
29
+ */
30
+ @customElement('dees-harness-question-card')
31
+ export class DeesHarnessQuestionCard extends DeesElement {
32
+ public static demo = demoFunc;
33
+ public static demoGroups = ['Agent Chat'];
34
+
35
+ @property({ attribute: false })
36
+ accessor request: IHarnessQuestionRequest = { id: '', question: '' };
37
+
38
+ @property({ type: Boolean })
39
+ accessor busy: boolean = false;
40
+
41
+ /** local optimistic answer; request.response (host echo) takes precedence */
42
+ @state()
43
+ accessor answered: string[] | undefined = undefined;
44
+
45
+ @state()
46
+ accessor selected: ReadonlySet<string> = new Set<string>();
47
+
48
+ @state()
49
+ accessor customText: string = '';
50
+
51
+ public get effectiveResponse(): string[] | undefined {
52
+ return this.request.response ?? this.answered;
53
+ }
54
+
55
+ public static styles = [
56
+ themeDefaultStyles,
57
+ cssManager.defaultStyles,
58
+ css`
59
+ :host {
60
+ display: block;
61
+ font-family: var(--dees-font-family);
62
+ interpolate-size: allow-keywords;
63
+ overflow: clip;
64
+ animation: harness-entry var(--dees-transition-default) var(--dees-ease-out);
65
+ }
66
+
67
+ @keyframes harness-entry {
68
+ from {
69
+ height: 0;
70
+ margin-top: 0;
71
+ opacity: 0;
72
+ }
73
+ }
74
+
75
+ @media (prefers-reduced-motion: reduce) {
76
+ :host {
77
+ animation: none;
78
+ }
79
+ }
80
+
81
+ .card {
82
+ padding: var(--dees-spacing-sm) var(--dees-spacing-md);
83
+ border: 1px solid var(--dees-color-border-default);
84
+ border-left: 2px solid var(--dees-color-accent-primary);
85
+ border-radius: var(--dees-radius-lg);
86
+ corner-shape: var(--dees-corner-shape);
87
+ background: var(--dees-color-bg-secondary);
88
+ }
89
+
90
+ .titleRow {
91
+ display: flex;
92
+ align-items: flex-start;
93
+ gap: var(--dees-spacing-sm);
94
+ margin-bottom: var(--dees-spacing-sm);
95
+ }
96
+
97
+ .titleRow dees-icon {
98
+ flex: 0 0 auto;
99
+ margin-top: 1px;
100
+ color: var(--dees-color-accent-primary);
101
+ }
102
+
103
+ .questionText {
104
+ min-width: 0;
105
+ color: var(--dees-color-text-primary);
106
+ font-size: var(--dees-font-control-size, 13px);
107
+ font-weight: 600;
108
+ line-height: 1.4;
109
+ overflow-wrap: anywhere;
110
+ }
111
+
112
+ .options {
113
+ display: block;
114
+ }
115
+
116
+ .options > * + * {
117
+ margin-top: var(--dees-spacing-xs);
118
+ }
119
+
120
+ .option {
121
+ width: 100%;
122
+ display: block;
123
+ padding: var(--dees-spacing-xs) var(--dees-spacing-sm);
124
+ border: 1px solid var(--dees-color-border-subtle);
125
+ border-radius: var(--dees-radius-md);
126
+ corner-shape: var(--dees-corner-shape);
127
+ background: var(--dees-color-bg-primary);
128
+ color: var(--dees-color-text-primary);
129
+ cursor: pointer;
130
+ font-family: inherit;
131
+ font-size: var(--dees-font-control-size-sm, 12px);
132
+ text-align: left;
133
+ transition:
134
+ border-color var(--dees-transition-fast) var(--dees-ease-standard),
135
+ background var(--dees-transition-fast) var(--dees-ease-standard);
136
+ }
137
+
138
+ .option:hover:not(:disabled) {
139
+ border-color: var(--dees-color-accent-primary);
140
+ }
141
+
142
+ .option.selected {
143
+ border-color: var(--dees-color-accent-primary);
144
+ background: color-mix(in srgb, var(--dees-color-accent-primary) 10%, var(--dees-color-bg-primary));
145
+ }
146
+
147
+ .option:disabled {
148
+ cursor: default;
149
+ opacity: 0.6;
150
+ }
151
+
152
+ .optionLabel {
153
+ font-weight: 500;
154
+ }
155
+
156
+ .optionDescription {
157
+ margin-top: 1px;
158
+ color: var(--dees-color-text-secondary);
159
+ font-size: var(--dees-font-caption1-size, 11px);
160
+ }
161
+
162
+ .customRow {
163
+ display: flex;
164
+ gap: var(--dees-spacing-xs);
165
+ margin-top: var(--dees-spacing-sm);
166
+ }
167
+
168
+ .customRow input {
169
+ flex: 1;
170
+ min-width: 0;
171
+ height: var(--dees-control-height-sm);
172
+ padding: 0 var(--dees-spacing-sm);
173
+ border: 1px solid var(--dees-color-border-default);
174
+ border-radius: var(--dees-radius-md);
175
+ corner-shape: var(--dees-corner-shape);
176
+ background: var(--dees-color-bg-primary);
177
+ color: var(--dees-color-text-primary);
178
+ font-family: inherit;
179
+ font-size: var(--dees-font-control-size-sm, 12px);
180
+ outline: none;
181
+ }
182
+
183
+ .customRow input:focus {
184
+ border-color: var(--dees-color-accent-primary);
185
+ box-shadow: 0 0 0 3px var(--dees-color-focus-ring);
186
+ }
187
+
188
+ .confirmRow {
189
+ display: flex;
190
+ justify-content: flex-end;
191
+ margin-top: var(--dees-spacing-sm);
192
+ }
193
+
194
+ .answeredNote {
195
+ display: flex;
196
+ align-items: baseline;
197
+ gap: var(--dees-spacing-sm);
198
+ color: var(--dees-color-text-secondary);
199
+ font-size: var(--dees-font-control-size-sm, 12px);
200
+ }
201
+
202
+ .answeredNote .answerText {
203
+ color: var(--dees-color-text-primary);
204
+ font-weight: 500;
205
+ overflow-wrap: anywhere;
206
+ }
207
+ `,
208
+ ];
209
+
210
+ public render(): TemplateResult {
211
+ const request = this.request;
212
+ const response = this.effectiveResponse;
213
+ const disabled = this.busy || response !== undefined;
214
+ return html`
215
+ <div class="card">
216
+ <div class="titleRow">
217
+ <dees-icon icon="lucide:MessageCircleQuestionMark" iconSize="15"></dees-icon>
218
+ <span class="questionText">${request.question}</span>
219
+ </div>
220
+ ${response
221
+ ? html`
222
+ <div class="answeredNote">
223
+ Answered:
224
+ <span class="answerText">${response.join(', ') || '—'}</span>
225
+ </div>
226
+ `
227
+ : html`
228
+ ${request.options?.length
229
+ ? html`
230
+ <div class="options" role=${request.multiSelect ? 'group' : 'radiogroup'}>
231
+ ${request.options.map((option) => html`
232
+ <button
233
+ class="option ${this.selected.has(option.label) ? 'selected' : ''}"
234
+ type="button"
235
+ ?disabled=${disabled}
236
+ @click=${() => this.handleOptionClick(option.label)}
237
+ >
238
+ <div class="optionLabel">${option.label}</div>
239
+ ${option.description
240
+ ? html`<div class="optionDescription">${option.description}</div>`
241
+ : ''}
242
+ </button>
243
+ `)}
244
+ </div>
245
+ `
246
+ : ''}
247
+ ${request.allowCustom !== false
248
+ ? html`
249
+ <div class="customRow">
250
+ <input
251
+ placeholder="Answer in your own words…"
252
+ .value=${this.customText}
253
+ ?disabled=${disabled}
254
+ @input=${(event: Event) => {
255
+ this.customText = (event.currentTarget as HTMLInputElement).value;
256
+ }}
257
+ @keydown=${(event: KeyboardEvent) => {
258
+ if (event.key === 'Enter' && this.customText.trim()) {
259
+ this.respond([...this.selected, this.customText.trim()]);
260
+ }
261
+ }}
262
+ />
263
+ <dees-button
264
+ size="sm"
265
+ ?disabled=${disabled || (!this.customText.trim() && !this.selected.size)}
266
+ @clicked=${() => {
267
+ const answers = [...this.selected];
268
+ if (this.customText.trim()) answers.push(this.customText.trim());
269
+ this.respond(answers);
270
+ }}
271
+ >Send Answer</dees-button>
272
+ </div>
273
+ `
274
+ : ''}
275
+ ${request.multiSelect && request.allowCustom === false
276
+ ? html`
277
+ <div class="confirmRow">
278
+ <dees-button
279
+ type="accent"
280
+ size="sm"
281
+ ?disabled=${disabled || !this.selected.size}
282
+ @clicked=${() => this.respond([...this.selected])}
283
+ >Confirm</dees-button>
284
+ </div>
285
+ `
286
+ : ''}
287
+ `}
288
+ </div>
289
+ `;
290
+ }
291
+
292
+ private handleOptionClick(label: string): void {
293
+ if (this.busy || this.effectiveResponse !== undefined) return;
294
+ if (this.request.multiSelect) {
295
+ const next = new Set(this.selected);
296
+ if (next.has(label)) next.delete(label);
297
+ else next.add(label);
298
+ this.selected = next;
299
+ return;
300
+ }
301
+ this.respond([label]);
302
+ }
303
+
304
+ private respond(answers: string[]): void {
305
+ if (this.busy || this.effectiveResponse !== undefined || !answers.length) return;
306
+ this.answered = answers;
307
+ this.dispatchEvent(
308
+ new CustomEvent('harness-question-response', {
309
+ detail: {
310
+ requestId: this.request.id,
311
+ answers,
312
+ request: this.request,
313
+ },
314
+ bubbles: true,
315
+ composed: true,
316
+ }),
317
+ );
318
+ }
319
+ }
@@ -0,0 +1 @@
1
+ export * from './dees-harness-question-card.js';
@@ -13,6 +13,7 @@ export * from './dees-harness-composer/index.js';
13
13
  export * from './dees-harness-content-blocks/index.js';
14
14
  export * from './dees-harness-message/index.js';
15
15
  export * from './dees-harness-permission-card/index.js';
16
+ export * from './dees-harness-question-card/index.js';
16
17
  export * from './dees-harness-message-list/index.js';
17
18
  export * from './dees-harness-reasoning/index.js';
18
19
  export * from './dees-harness-session-list/index.js';
@@ -142,10 +142,46 @@ export interface IHarnessPermissionRequest {
142
142
  /** open set; well-known values today: write | delete | shell | browser */
143
143
  type: string;
144
144
  metadata?: Record<string, unknown>;
145
+ /** set once answered — the card stays in the transcript showing the outcome */
146
+ response?: THarnessPermissionResponse;
147
+ /** epoch ms */
148
+ respondedAt?: number;
145
149
  }
146
150
 
147
151
  export type THarnessPermissionResponse = 'once' | 'always' | 'reject';
148
152
 
153
+ export interface IHarnessQuestionOption {
154
+ label: string;
155
+ description?: string;
156
+ }
157
+
158
+ /**
159
+ * A question the agent asks the user mid-run. Renders inline in the
160
+ * transcript like permissions: pending questions pin to the end, answered
161
+ * ones persist showing the chosen answer(s).
162
+ */
163
+ export interface IHarnessQuestionRequest {
164
+ id: string;
165
+ sessionId?: string;
166
+ /** epoch ms */
167
+ createdAt?: number;
168
+ question: string;
169
+ options?: IHarnessQuestionOption[];
170
+ multiSelect?: boolean;
171
+ /** allow a free-text answer alongside the options (default true) */
172
+ allowCustom?: boolean;
173
+ /** set once answered — the card stays in the transcript showing the answer */
174
+ response?: string[];
175
+ /** epoch ms */
176
+ respondedAt?: number;
177
+ }
178
+
179
+ export interface IHarnessQuestionResponseDetail {
180
+ requestId: string;
181
+ answers: string[];
182
+ request: IHarnessQuestionRequest;
183
+ }
184
+
149
185
  export interface IHarnessPermissionResponseDetail {
150
186
  requestId: string;
151
187
  response: THarnessPermissionResponse;
@@ -163,6 +163,14 @@ const defaultDescriptors: IHarnessToolDescriptor[] = [
163
163
  icon: 'lucide:Bot',
164
164
  subtitle: (call) => inputField(call, 'description') || inputField(call, 'prompt') || harnessSummaryLine(call.input),
165
165
  },
166
+ {
167
+ kind: 'question',
168
+ names: ['askuserquestion', 'ask_user_question', 'ask_question', 'ask_user', 'question'],
169
+ label: 'Question',
170
+ icon: 'lucide:MessageCircleQuestionMark',
171
+ subtitle: (call) => inputField(call, 'question') || inputField(call, 'prompt') || harnessSummaryLine(call.input),
172
+ defaultExpanded: true,
173
+ },
166
174
  {
167
175
  kind: 'todo',
168
176
  names: ['todowrite', 'todo_write', 'todoread'],
@@ -425,6 +425,11 @@ const l = themeDefaults.colors.light;
425
425
  const d = themeDefaults.colors.dark;
426
426
  const shadowsLight = themeDefaults.shadows;
427
427
  const shadowsDark = themeDefaults.shadowsDark ?? themeDefaults.shadows;
428
+
429
+ /** Flips the y offsets of a box-shadow list so bars can cast upward
430
+ * (e.g. a docked composer shadowing the content above it). */
431
+ const mirrorShadow = (shadow: string): string =>
432
+ shadow.replace(/(^|,)(\s*\S+\s+)(-?\d+(?:\.\d+)?)px/g, (match, sep, x, y) => `${sep}${x}${-Number(y)}px`);
428
433
  const matL = themeDefaults.materials.light;
429
434
  const matD = themeDefaults.materials.dark;
430
435
 
@@ -639,6 +644,8 @@ export const themeDefaultStyles: CSSResult = css`
639
644
  --dees-shadow-md: ${cssManager.bdTheme(shadowsLight.md, shadowsDark.md)};
640
645
  --dees-shadow-lg: ${cssManager.bdTheme(shadowsLight.lg, shadowsDark.lg)};
641
646
  --dees-shadow-xl: ${cssManager.bdTheme(shadowsLight.xl, shadowsDark.xl)};
647
+ /* upward-casting bar shadow (mirrored sm) for bottom-docked chrome */
648
+ --dees-shadow-up-sm: ${cssManager.bdTheme(mirrorShadow(shadowsLight.sm), mirrorShadow(shadowsDark.sm))};
642
649
 
643
650
  /* ========================================
644
651
  * Materials / Vibrancy (theme-aware bg + opaque fallback; theme-agnostic filter)