@design.estate/dees-catalog 3.102.0 → 3.103.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 +1285 -972
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.js +10 -1
- package/dist_ts_web/elements/00group-harness/dees-terminal-view/dees-terminal-view.d.ts +50 -0
- package/dist_ts_web/elements/00group-harness/dees-terminal-view/dees-terminal-view.demo.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-terminal-view/dees-terminal-view.demo.js +26 -0
- package/dist_ts_web/elements/00group-harness/dees-terminal-view/dees-terminal-view.js +347 -0
- package/dist_ts_web/elements/00group-harness/dees-terminal-view/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-terminal-view/index.js +2 -0
- package/dist_ts_web/elements/00group-harness/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/index.js +2 -1
- package/dist_ts_web/elements/00group-harness/interfaces.d.ts +2 -0
- package/package.json +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts +9 -0
- package/ts_web/elements/00group-harness/dees-terminal-view/dees-terminal-view.demo.ts +26 -0
- package/ts_web/elements/00group-harness/dees-terminal-view/dees-terminal-view.ts +317 -0
- package/ts_web/elements/00group-harness/dees-terminal-view/index.ts +1 -0
- package/ts_web/elements/00group-harness/index.ts +1 -0
- package/ts_web/elements/00group-harness/interfaces.ts +2 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { demoFunc } from './dees-terminal-view.demo.js';
|
|
2
|
+
import {
|
|
3
|
+
DeesElement,
|
|
4
|
+
html,
|
|
5
|
+
css,
|
|
6
|
+
customElement,
|
|
7
|
+
type TemplateResult,
|
|
8
|
+
property,
|
|
9
|
+
} from '@design.estate/dees-element';
|
|
10
|
+
import type { Terminal } from 'xterm';
|
|
11
|
+
import type { FitAddon } from 'xterm-addon-fit';
|
|
12
|
+
import { themeDefaultStyles } from '../../00theme.js';
|
|
13
|
+
import { DeesServiceLibLoader } from '../../../services/index.js';
|
|
14
|
+
|
|
15
|
+
declare global {
|
|
16
|
+
interface HTMLElementTagNameMap {
|
|
17
|
+
'dees-terminal-view': DeesTerminalView;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Detail of `terminal-input`: bytes the user typed, as a UTF-8 string. */
|
|
22
|
+
export interface ITerminalInputDetail {
|
|
23
|
+
data: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Detail of `terminal-resize`, fired after the terminal refits its container. */
|
|
27
|
+
export interface ITerminalResizeDetail {
|
|
28
|
+
rows: number;
|
|
29
|
+
cols: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Transport-agnostic xterm.js surface: the host pipes remote PTY output into
|
|
34
|
+
* `write()` and receives keystrokes via `terminal-input` — no process,
|
|
35
|
+
* runtime, or socket coupling. `terminal-resize` reports the grid size after
|
|
36
|
+
* every refit so the host can negotiate a PTY size. xterm loads through
|
|
37
|
+
* DeesServiceLibLoader; CSP-locked hosts can pre-register bundled modules
|
|
38
|
+
* with `provideXtermModules()` to avoid the CDN.
|
|
39
|
+
*/
|
|
40
|
+
@customElement('dees-terminal-view')
|
|
41
|
+
export class DeesTerminalView extends DeesElement {
|
|
42
|
+
public static demo = demoFunc;
|
|
43
|
+
public static demoGroups = ['Agent Chat'];
|
|
44
|
+
|
|
45
|
+
/** Font size in px for the terminal grid. */
|
|
46
|
+
@property({ type: Number })
|
|
47
|
+
accessor fontSize: number = 13;
|
|
48
|
+
|
|
49
|
+
@property({ type: Boolean })
|
|
50
|
+
accessor disabled: boolean = false;
|
|
51
|
+
|
|
52
|
+
private terminal: Terminal | undefined;
|
|
53
|
+
private fitAddon: FitAddon | undefined;
|
|
54
|
+
private resizeObserver: ResizeObserver | undefined;
|
|
55
|
+
private inputDisposable: { dispose(): void } | undefined;
|
|
56
|
+
private lastReportedSize = '';
|
|
57
|
+
// Output that arrives before xterm finished loading is replayed in order.
|
|
58
|
+
private pendingWrites: Array<string | Uint8Array> = [];
|
|
59
|
+
private setupPromise: Promise<void> | undefined;
|
|
60
|
+
|
|
61
|
+
public static styles = [
|
|
62
|
+
themeDefaultStyles,
|
|
63
|
+
css`
|
|
64
|
+
:host {
|
|
65
|
+
display: block;
|
|
66
|
+
min-height: 0;
|
|
67
|
+
height: 100%;
|
|
68
|
+
background: var(--dees-color-bg-primary);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.terminalHost {
|
|
72
|
+
width: 100%;
|
|
73
|
+
height: 100%;
|
|
74
|
+
padding: var(--dees-spacing-xs);
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* xterm.js styles (shadow DOM needs them locally) */
|
|
79
|
+
.xterm {
|
|
80
|
+
font-feature-settings: 'liga' 0;
|
|
81
|
+
position: relative;
|
|
82
|
+
user-select: none;
|
|
83
|
+
-ms-user-select: none;
|
|
84
|
+
-webkit-user-select: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.xterm.focus,
|
|
88
|
+
.xterm:focus {
|
|
89
|
+
outline: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.xterm .xterm-helpers {
|
|
93
|
+
position: absolute;
|
|
94
|
+
top: 0;
|
|
95
|
+
z-index: 5;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.xterm .xterm-helper-textarea {
|
|
99
|
+
padding: 0;
|
|
100
|
+
border: 0;
|
|
101
|
+
margin: 0;
|
|
102
|
+
position: absolute;
|
|
103
|
+
opacity: 0;
|
|
104
|
+
left: -9999em;
|
|
105
|
+
top: 0;
|
|
106
|
+
width: 0;
|
|
107
|
+
height: 0;
|
|
108
|
+
z-index: -5;
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
resize: none;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.xterm .composition-view {
|
|
115
|
+
background: var(--dees-color-bg-primary);
|
|
116
|
+
color: var(--dees-color-text-primary);
|
|
117
|
+
display: none;
|
|
118
|
+
position: absolute;
|
|
119
|
+
white-space: nowrap;
|
|
120
|
+
z-index: 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.xterm .composition-view.active {
|
|
124
|
+
display: block;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.xterm .xterm-viewport {
|
|
128
|
+
background-color: var(--dees-color-bg-primary);
|
|
129
|
+
overflow-y: scroll;
|
|
130
|
+
cursor: default;
|
|
131
|
+
position: absolute;
|
|
132
|
+
right: 0;
|
|
133
|
+
left: 0;
|
|
134
|
+
top: 0;
|
|
135
|
+
bottom: 0;
|
|
136
|
+
scrollbar-width: thin;
|
|
137
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.xterm .xterm-screen {
|
|
141
|
+
position: relative;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.xterm .xterm-screen canvas {
|
|
145
|
+
position: absolute;
|
|
146
|
+
left: 0;
|
|
147
|
+
top: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.xterm .xterm-scroll-area {
|
|
151
|
+
visibility: hidden;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.xterm-char-measure-element {
|
|
155
|
+
display: inline-block;
|
|
156
|
+
visibility: hidden;
|
|
157
|
+
position: absolute;
|
|
158
|
+
top: 0;
|
|
159
|
+
left: -9999em;
|
|
160
|
+
line-height: normal;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.xterm {
|
|
164
|
+
cursor: text;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.xterm.enable-mouse-events {
|
|
168
|
+
cursor: default;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.xterm.xterm-cursor-pointer {
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.xterm.column-select.focus {
|
|
176
|
+
cursor: crosshair;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.xterm .xterm-accessibility,
|
|
180
|
+
.xterm .xterm-message {
|
|
181
|
+
position: absolute;
|
|
182
|
+
left: 0;
|
|
183
|
+
top: 0;
|
|
184
|
+
bottom: 0;
|
|
185
|
+
right: 0;
|
|
186
|
+
z-index: 10;
|
|
187
|
+
color: transparent;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.xterm .live-region {
|
|
191
|
+
position: absolute;
|
|
192
|
+
left: -9999px;
|
|
193
|
+
width: 1px;
|
|
194
|
+
height: 1px;
|
|
195
|
+
overflow: hidden;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.xterm-dim {
|
|
199
|
+
opacity: 0.5;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.xterm-underline {
|
|
203
|
+
text-decoration: underline;
|
|
204
|
+
}
|
|
205
|
+
`,
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
public render(): TemplateResult {
|
|
209
|
+
return html`<div class="terminalHost"></div>`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public async firstUpdated(): Promise<void> {
|
|
213
|
+
this.setupPromise = this.setupTerminal();
|
|
214
|
+
await this.setupPromise;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Feed remote output into the terminal; safe to call before setup finishes. */
|
|
218
|
+
public write(dataArg: string | Uint8Array): void {
|
|
219
|
+
if (this.terminal) {
|
|
220
|
+
this.terminal.write(dataArg);
|
|
221
|
+
} else {
|
|
222
|
+
this.pendingWrites.push(dataArg);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Reset the screen and scrollback, e.g. before a full replay. */
|
|
227
|
+
public clear(): void {
|
|
228
|
+
this.pendingWrites = [];
|
|
229
|
+
this.terminal?.reset();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public focus(): void {
|
|
233
|
+
this.terminal?.focus();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Current grid size, or undefined while xterm is still loading. */
|
|
237
|
+
public get currentSize(): ITerminalResizeDetail | undefined {
|
|
238
|
+
if (!this.terminal) return undefined;
|
|
239
|
+
return { rows: this.terminal.rows, cols: this.terminal.cols };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private async setupTerminal(): Promise<void> {
|
|
243
|
+
const libLoader = DeesServiceLibLoader.getInstance();
|
|
244
|
+
const [xterm, fit] = await Promise.all([
|
|
245
|
+
libLoader.loadXterm(),
|
|
246
|
+
libLoader.loadXtermFitAddon(),
|
|
247
|
+
]);
|
|
248
|
+
if (!this.isConnected) return;
|
|
249
|
+
const host = this.shadowRoot?.querySelector<HTMLElement>('.terminalHost');
|
|
250
|
+
if (!host) return;
|
|
251
|
+
const computed = getComputedStyle(this);
|
|
252
|
+
const themeColor = (nameArg: string, fallbackArg: string): string => {
|
|
253
|
+
const value = computed.getPropertyValue(nameArg).trim();
|
|
254
|
+
return value || fallbackArg;
|
|
255
|
+
};
|
|
256
|
+
const terminal = new xterm.Terminal({
|
|
257
|
+
fontSize: this.fontSize,
|
|
258
|
+
fontFamily: themeColor('--dees-font-family-mono', 'monospace'),
|
|
259
|
+
cursorBlink: true,
|
|
260
|
+
allowProposedApi: true,
|
|
261
|
+
scrollback: 10_000,
|
|
262
|
+
theme: {
|
|
263
|
+
background: themeColor('--dees-color-bg-primary', '#111111'),
|
|
264
|
+
foreground: themeColor('--dees-color-text-primary', '#e6e6e6'),
|
|
265
|
+
cursor: themeColor('--dees-color-accent-primary', '#e6e6e6'),
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
const fitAddon = new fit.FitAddon();
|
|
269
|
+
terminal.loadAddon(fitAddon);
|
|
270
|
+
terminal.open(host);
|
|
271
|
+
this.terminal = terminal;
|
|
272
|
+
this.fitAddon = fitAddon;
|
|
273
|
+
this.inputDisposable = terminal.onData((dataArg) => {
|
|
274
|
+
if (this.disabled) return;
|
|
275
|
+
const detail: ITerminalInputDetail = { data: dataArg };
|
|
276
|
+
this.dispatchEvent(
|
|
277
|
+
new CustomEvent('terminal-input', { detail, bubbles: true, composed: true }),
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
for (const pending of this.pendingWrites) terminal.write(pending);
|
|
281
|
+
this.pendingWrites = [];
|
|
282
|
+
this.refit();
|
|
283
|
+
this.resizeObserver = new ResizeObserver(() => this.refit());
|
|
284
|
+
this.resizeObserver.observe(host);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private refit(): void {
|
|
288
|
+
if (!this.terminal || !this.fitAddon) return;
|
|
289
|
+
try {
|
|
290
|
+
this.fitAddon.fit();
|
|
291
|
+
} catch {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const size = `${this.terminal.rows}x${this.terminal.cols}`;
|
|
295
|
+
if (size === this.lastReportedSize) return;
|
|
296
|
+
this.lastReportedSize = size;
|
|
297
|
+
const detail: ITerminalResizeDetail = {
|
|
298
|
+
rows: this.terminal.rows,
|
|
299
|
+
cols: this.terminal.cols,
|
|
300
|
+
};
|
|
301
|
+
this.dispatchEvent(
|
|
302
|
+
new CustomEvent('terminal-resize', { detail, bubbles: true, composed: true }),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public async disconnectedCallback(): Promise<void> {
|
|
307
|
+
await super.disconnectedCallback();
|
|
308
|
+
this.resizeObserver?.disconnect();
|
|
309
|
+
this.resizeObserver = undefined;
|
|
310
|
+
this.inputDisposable?.dispose();
|
|
311
|
+
this.inputDisposable = undefined;
|
|
312
|
+
this.terminal?.dispose();
|
|
313
|
+
this.terminal = undefined;
|
|
314
|
+
this.fitAddon = undefined;
|
|
315
|
+
this.pendingWrites = [];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dees-terminal-view.js';
|
|
@@ -17,6 +17,7 @@ export * from './dees-harness-question-card/index.js';
|
|
|
17
17
|
export * from './dees-harness-message-list/index.js';
|
|
18
18
|
export * from './dees-harness-reasoning/index.js';
|
|
19
19
|
export * from './dees-harness-session-list/index.js';
|
|
20
|
+
export * from './dees-terminal-view/index.js';
|
|
20
21
|
export * from './dees-harness-status/index.js';
|
|
21
22
|
export * from './dees-harness-todos/index.js';
|
|
22
23
|
export * from './dees-harness-tool-card/index.js';
|
|
@@ -198,6 +198,8 @@ export interface IHarnessSessionMeta {
|
|
|
198
198
|
updatedAt?: number;
|
|
199
199
|
messageCount?: number;
|
|
200
200
|
preview?: string;
|
|
201
|
+
/** Optional dees-icon name (e.g. 'lucide:Terminal') shown before the title. */
|
|
202
|
+
icon?: string;
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
/** Detail of `harness-session-context`, fired on right-click of a session item. */
|