@design.estate/dees-catalog 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,13 +13,31 @@ export interface ITerminalResizeDetail {
13
13
  rows: number;
14
14
  cols: number;
15
15
  }
16
+ /**
17
+ * Detail of `terminal-error`: xterm could not be loaded, or the live terminal
18
+ * refused output. The element stays usable and keeps buffering.
19
+ */
20
+ export interface ITerminalErrorDetail {
21
+ error: unknown;
22
+ }
23
+ /**
24
+ * Upper bound on output buffered while no terminal is live, in bytes.
25
+ * `Uint8Array` chunks count their `byteLength`, strings their UTF-16 memory
26
+ * (two bytes per code unit). Beyond the bound the oldest chunks are dropped,
27
+ * and the flush then emits RIS before the survivors so a truncated prefix is
28
+ * never rendered as if it were contiguous output.
29
+ */
30
+ export declare const maxPendingWriteBytes: number;
16
31
  /**
17
32
  * Transport-agnostic xterm.js surface: the host pipes remote PTY output into
18
33
  * `write()` and receives keystrokes via `terminal-input` — no process,
19
34
  * runtime, or socket coupling. `terminal-resize` reports the grid size after
20
- * every refit so the host can negotiate a PTY size. xterm loads through
21
- * DeesServiceLibLoader; CSP-locked hosts can pre-register bundled modules
22
- * with `provideXtermModules()` to avoid the CDN.
35
+ * every refit so the host can negotiate a PTY size. Output that arrives while
36
+ * no terminal is live is buffered up to `maxPendingWriteBytes` and replayed in
37
+ * order on the next connection, so a replay may start before the element is
38
+ * ready and survives being detached. xterm loads through DeesServiceLibLoader;
39
+ * CSP-locked hosts can pre-register bundled modules with
40
+ * `provideXtermModules()` to avoid the CDN.
23
41
  */
24
42
  export declare class DeesTerminalView extends DeesElement {
25
43
  static demo: () => TemplateResult<1>;
@@ -33,18 +51,39 @@ export declare class DeesTerminalView extends DeesElement {
33
51
  private inputDisposable;
34
52
  private lastReportedSize;
35
53
  private pendingWrites;
54
+ private pendingWriteBytes;
55
+ private pendingWritesDropped;
36
56
  private setupPromise;
57
+ private readyPending;
58
+ private readyResolve;
59
+ private readyReject;
60
+ /**
61
+ * Resolves once the terminal of the current connection is live; a fresh
62
+ * promise is created for every connection. It rejects with the load error
63
+ * when xterm cannot be loaded (`terminal-error` carries the same error), and
64
+ * when the element is disconnected before the terminal came up.
65
+ */
66
+ ready: Promise<void>;
67
+ constructor();
37
68
  static styles: import("@design.estate/dees-element").CSSResult[];
38
69
  render(): TemplateResult;
39
- firstUpdated(): Promise<void>;
70
+ connectedCallback(): Promise<void>;
40
71
  /** Feed remote output into the terminal; safe to call before setup finishes. */
41
72
  write(dataArg: string | Uint8Array): void;
42
73
  /** Reset the screen and scrollback, e.g. before a full replay. */
43
74
  clear(): void;
44
75
  focus(): void;
45
- /** Current grid size, or undefined while xterm is still loading. */
76
+ /** Current grid size, or undefined while no terminal is live. */
46
77
  get currentSize(): ITerminalResizeDetail | undefined;
78
+ private createReadyPromise;
79
+ private bufferWrite;
80
+ private flushPendingWrites;
81
+ /** xterm throws at its own flow-control watermark; that has to reach the host. */
82
+ private writeToTerminal;
83
+ private reportError;
84
+ private ensureTerminal;
47
85
  private setupTerminal;
86
+ private createTerminal;
48
87
  private refit;
49
- disconnectedCallback(): Promise<void>;
88
+ private teardownTerminal;
50
89
  }
@@ -36,13 +36,34 @@ import { demoFunc } from './dees-terminal-view.demo.js';
36
36
  import { DeesElement, html, css, customElement, property, } from '@design.estate/dees-element';
37
37
  import { themeDefaultStyles } from '../../00theme.js';
38
38
  import { DeesServiceLibLoader } from '../../../services/index.js';
39
+ /**
40
+ * Upper bound on output buffered while no terminal is live, in bytes.
41
+ * `Uint8Array` chunks count their `byteLength`, strings their UTF-16 memory
42
+ * (two bytes per code unit). Beyond the bound the oldest chunks are dropped,
43
+ * and the flush then emits RIS before the survivors so a truncated prefix is
44
+ * never rendered as if it were contiguous output.
45
+ */
46
+ export const maxPendingWriteBytes = 8 * 1024 * 1024;
47
+ /**
48
+ * RIS (ESC c), a hard reset carried *inside* the write stream: xterm parses it
49
+ * in order and routes it to the very same `Terminal.reset()` (InputHandler's
50
+ * ESC-c handler calls `fullReset()`, which fires `onRequestReset`, which
51
+ * `Terminal` handles with `reset()`), whereas calling `reset()` directly is
52
+ * documented as out of band with the pending write queue.
53
+ */
54
+ const RIS = '\x1bc';
55
+ /** Memory cost of one buffered chunk, in bytes. */
56
+ const chunkByteLength = (chunkArg) => typeof chunkArg === 'string' ? chunkArg.length * 2 : chunkArg.byteLength;
39
57
  /**
40
58
  * Transport-agnostic xterm.js surface: the host pipes remote PTY output into
41
59
  * `write()` and receives keystrokes via `terminal-input` — no process,
42
60
  * runtime, or socket coupling. `terminal-resize` reports the grid size after
43
- * every refit so the host can negotiate a PTY size. xterm loads through
44
- * DeesServiceLibLoader; CSP-locked hosts can pre-register bundled modules
45
- * with `provideXtermModules()` to avoid the CDN.
61
+ * every refit so the host can negotiate a PTY size. Output that arrives while
62
+ * no terminal is live is buffered up to `maxPendingWriteBytes` and replayed in
63
+ * order on the next connection, so a replay may start before the element is
64
+ * ready and survives being detached. xterm loads through DeesServiceLibLoader;
65
+ * CSP-locked hosts can pre-register bundled modules with
66
+ * `provideXtermModules()` to avoid the CDN.
46
67
  */
47
68
  let DeesTerminalView = (() => {
48
69
  let _classDecorators = [customElement('dees-terminal-view')];
@@ -82,9 +103,35 @@ let DeesTerminalView = (() => {
82
103
  resizeObserver;
83
104
  inputDisposable;
84
105
  lastReportedSize = '';
85
- // Output that arrives before xterm finished loading is replayed in order.
106
+ // Output that arrives before xterm is live is replayed in order, bounded by
107
+ // maxPendingWriteBytes and retained across a disconnect.
86
108
  pendingWrites = [];
109
+ pendingWriteBytes = 0;
110
+ pendingWritesDropped = false;
87
111
  setupPromise;
112
+ readyPending = true;
113
+ readyResolve = () => undefined;
114
+ readyReject = () => undefined;
115
+ /**
116
+ * Resolves once the terminal of the current connection is live; a fresh
117
+ * promise is created for every connection. It rejects with the load error
118
+ * when xterm cannot be loaded (`terminal-error` carries the same error), and
119
+ * when the element is disconnected before the terminal came up.
120
+ */
121
+ ready;
122
+ constructor() {
123
+ super();
124
+ this.ready = this.createReadyPromise();
125
+ // The house lifecycle: startup runs on every connection with an abort
126
+ // signal, garbage on every disconnection, so a reattached element is a
127
+ // live surface again instead of a permanently dead one.
128
+ this.registerStartupFunction(async (signalArg) => {
129
+ await this.ensureTerminal(signalArg);
130
+ });
131
+ this.registerGarbageFunction(() => {
132
+ this.teardownTerminal();
133
+ });
134
+ }
88
135
  static styles = [
89
136
  themeDefaultStyles,
90
137
  css `
@@ -234,40 +281,130 @@ let DeesTerminalView = (() => {
234
281
  render() {
235
282
  return html `<div class="terminalHost"></div>`;
236
283
  }
237
- async firstUpdated() {
238
- this.setupPromise = this.setupTerminal();
239
- await this.setupPromise;
284
+ connectedCallback() {
285
+ // A consumer awaiting readiness after reattaching must not be handed the
286
+ // settled promise of the previous connection.
287
+ if (!this.readyPending)
288
+ this.ready = this.createReadyPromise();
289
+ return super.connectedCallback();
240
290
  }
241
291
  /** Feed remote output into the terminal; safe to call before setup finishes. */
242
292
  write(dataArg) {
243
- if (this.terminal) {
244
- this.terminal.write(dataArg);
245
- }
246
- else {
247
- this.pendingWrites.push(dataArg);
293
+ // While detached the terminal is about to be disposed, so output belongs in
294
+ // the buffer rather than in a surface nobody will see again.
295
+ if (this.terminal && this.isConnected) {
296
+ this.writeToTerminal(this.terminal, dataArg);
297
+ return;
248
298
  }
299
+ this.bufferWrite(dataArg);
249
300
  }
250
301
  /** Reset the screen and scrollback, e.g. before a full replay. */
251
302
  clear() {
252
- this.pendingWrites = [];
253
- this.terminal?.reset();
303
+ const terminal = this.terminal;
304
+ if (terminal && this.isConnected) {
305
+ this.writeToTerminal(terminal, RIS);
306
+ return;
307
+ }
308
+ // Without a terminal the reset is expressed as a buffered sentinel, so the
309
+ // flush of the next connection still performs it in the right order.
310
+ this.pendingWrites = [RIS];
311
+ this.pendingWriteBytes = chunkByteLength(RIS);
312
+ this.pendingWritesDropped = false;
254
313
  }
255
314
  focus() {
256
315
  this.terminal?.focus();
257
316
  }
258
- /** Current grid size, or undefined while xterm is still loading. */
317
+ /** Current grid size, or undefined while no terminal is live. */
259
318
  get currentSize() {
260
319
  if (!this.terminal)
261
320
  return undefined;
262
321
  return { rows: this.terminal.rows, cols: this.terminal.cols };
263
322
  }
264
- async setupTerminal() {
323
+ createReadyPromise() {
324
+ this.readyPending = true;
325
+ const promise = new Promise((resolveArg, rejectArg) => {
326
+ this.readyResolve = () => {
327
+ this.readyPending = false;
328
+ resolveArg();
329
+ };
330
+ this.readyReject = (reasonArg) => {
331
+ this.readyPending = false;
332
+ rejectArg(reasonArg);
333
+ };
334
+ });
335
+ // A readiness promise nobody awaits must never surface as an unhandled
336
+ // rejection; consumers that do await it still observe the reason.
337
+ promise.catch(() => undefined);
338
+ return promise;
339
+ }
340
+ bufferWrite(chunkArg) {
341
+ this.pendingWrites.push(chunkArg);
342
+ this.pendingWriteBytes += chunkByteLength(chunkArg);
343
+ while (this.pendingWriteBytes > maxPendingWriteBytes && this.pendingWrites.length > 1) {
344
+ const droppedChunk = this.pendingWrites.shift();
345
+ this.pendingWriteBytes -= chunkByteLength(droppedChunk);
346
+ this.pendingWritesDropped = true;
347
+ }
348
+ }
349
+ flushPendingWrites(terminalArg) {
350
+ const pending = this.pendingWrites;
351
+ const dropped = this.pendingWritesDropped;
352
+ this.pendingWrites = [];
353
+ this.pendingWriteBytes = 0;
354
+ this.pendingWritesDropped = false;
355
+ if (dropped && !this.writeToTerminal(terminalArg, RIS))
356
+ return;
357
+ for (const chunk of pending) {
358
+ if (!this.writeToTerminal(terminalArg, chunk))
359
+ return;
360
+ }
361
+ }
362
+ /** xterm throws at its own flow-control watermark; that has to reach the host. */
363
+ writeToTerminal(terminalArg, chunkArg) {
364
+ try {
365
+ terminalArg.write(chunkArg);
366
+ return true;
367
+ }
368
+ catch (error) {
369
+ this.reportError(error);
370
+ return false;
371
+ }
372
+ }
373
+ reportError(errorArg) {
374
+ if (this.readyPending)
375
+ this.readyReject(errorArg);
376
+ const detail = { error: errorArg };
377
+ this.dispatchEvent(new CustomEvent('terminal-error', { detail, bubbles: true, composed: true }));
378
+ }
379
+ ensureTerminal(signalArg) {
380
+ if (this.terminal)
381
+ return Promise.resolve();
382
+ if (!this.setupPromise)
383
+ this.setupPromise = this.setupTerminal(signalArg);
384
+ return this.setupPromise;
385
+ }
386
+ async setupTerminal(signalArg) {
387
+ try {
388
+ await this.createTerminal(signalArg);
389
+ }
390
+ catch (error) {
391
+ this.reportError(error);
392
+ }
393
+ finally {
394
+ // Nothing came up: release the guard so the next connection retries.
395
+ if (!this.terminal)
396
+ this.setupPromise = undefined;
397
+ }
398
+ }
399
+ async createTerminal(signalArg) {
400
+ await this.updateComplete;
265
401
  const libLoader = DeesServiceLibLoader.getInstance();
266
402
  const [xterm, fit] = await Promise.all([
267
403
  libLoader.loadXterm(),
268
404
  libLoader.loadXtermFitAddon(),
269
405
  ]);
270
- if (!this.isConnected)
406
+ // The load was awaited: the element may have been detached meanwhile.
407
+ if (signalArg.aborted || !this.isConnected)
271
408
  return;
272
409
  const host = this.shadowRoot?.querySelector('.terminalHost');
273
410
  if (!host)
@@ -289,9 +426,23 @@ let DeesTerminalView = (() => {
289
426
  cursor: themeColor('--dees-color-accent-primary', '#e6e6e6'),
290
427
  },
291
428
  });
292
- const fitAddon = new fit.FitAddon();
293
- terminal.loadAddon(fitAddon);
294
- terminal.open(host);
429
+ let fitAddon;
430
+ try {
431
+ fitAddon = new fit.FitAddon();
432
+ terminal.loadAddon(fitAddon);
433
+ terminal.open(host);
434
+ }
435
+ catch (error) {
436
+ // The element does not own this instance yet, so teardown cannot reach
437
+ // it; a half-opened terminal would otherwise leak with its DOM attached.
438
+ try {
439
+ terminal.dispose();
440
+ }
441
+ catch {
442
+ // Disposing a half-opened terminal must not mask the real failure.
443
+ }
444
+ throw error;
445
+ }
295
446
  this.terminal = terminal;
296
447
  this.fitAddon = fitAddon;
297
448
  this.inputDisposable = terminal.onData((dataArg) => {
@@ -300,12 +451,11 @@ let DeesTerminalView = (() => {
300
451
  const detail = { data: dataArg };
301
452
  this.dispatchEvent(new CustomEvent('terminal-input', { detail, bubbles: true, composed: true }));
302
453
  });
303
- for (const pending of this.pendingWrites)
304
- terminal.write(pending);
305
- this.pendingWrites = [];
454
+ this.flushPendingWrites(terminal);
306
455
  this.refit();
307
456
  this.resizeObserver = new ResizeObserver(() => this.refit());
308
457
  this.resizeObserver.observe(host);
458
+ this.readyResolve();
309
459
  }
310
460
  refit() {
311
461
  if (!this.terminal || !this.fitAddon)
@@ -326,8 +476,7 @@ let DeesTerminalView = (() => {
326
476
  };
327
477
  this.dispatchEvent(new CustomEvent('terminal-resize', { detail, bubbles: true, composed: true }));
328
478
  }
329
- async disconnectedCallback() {
330
- await super.disconnectedCallback();
479
+ teardownTerminal() {
331
480
  this.resizeObserver?.disconnect();
332
481
  this.resizeObserver = undefined;
333
482
  this.inputDisposable?.dispose();
@@ -335,7 +484,15 @@ let DeesTerminalView = (() => {
335
484
  this.terminal?.dispose();
336
485
  this.terminal = undefined;
337
486
  this.fitAddon = undefined;
338
- this.pendingWrites = [];
487
+ // Instance state of the finished connection: a reattached element has to
488
+ // re-announce its grid and may retry a load that failed.
489
+ this.lastReportedSize = '';
490
+ this.setupPromise = undefined;
491
+ // Buffered output deliberately survives, so a replay that arrived while the
492
+ // element was detached still reaches the next connection.
493
+ if (this.readyPending) {
494
+ this.readyReject(new Error('dees-terminal-view was disconnected before the terminal became ready'));
495
+ }
339
496
  }
340
497
  static {
341
498
  __runInitializers(_classThis, _classExtraInitializers);
@@ -344,4 +501,4 @@ let DeesTerminalView = (() => {
344
501
  return DeesTerminalView = _classThis;
345
502
  })();
346
503
  export { DeesTerminalView };
347
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVlcy10ZXJtaW5hbC12aWV3LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHNfd2ViL2VsZW1lbnRzLzAwZ3JvdXAtaGFybmVzcy9kZWVzLXRlcm1pbmFsLXZpZXcvZGVlcy10ZXJtaW5hbC12aWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDeEQsT0FBTyxFQUNMLFdBQVcsRUFDWCxJQUFJLEVBQ0osR0FBRyxFQUNILGFBQWEsRUFFYixRQUFRLEdBQ1QsTUFBTSw2QkFBNkIsQ0FBQztBQUdyQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQW1CbEU7Ozs7Ozs7R0FPRztJQUVVLGdCQUFnQjs0QkFENUIsYUFBYSxDQUFDLG9CQUFvQixDQUFDOzs7O3NCQUNFLFdBQVc7Ozs7Ozs7Z0NBQW5CLFNBQVEsV0FBVzs7OztvQ0FLOUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO29DQUcxQixRQUFRLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFGNUIsNktBQVMsUUFBUSw2QkFBUixRQUFRLDJGQUFjO1lBRy9CLDZLQUFTLFFBQVEsNkJBQVIsUUFBUSwyRkFBa0I7WUFUckMsNktBb1JDOzs7O1FBblJRLE1BQU0sQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDO1FBQ3ZCLE1BQU0sQ0FBQyxVQUFVLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUkxQyw2RUFBNEIsRUFBRSxFQUFDO1FBRi9CLDZDQUE2QztRQUU3QyxJQUFTLFFBQVEsOENBQWM7UUFBL0IsSUFBUyxRQUFRLG9EQUFjO1FBRy9CLG9JQUE2QixLQUFLLEdBQUM7UUFBbkMs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
504
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVlcy10ZXJtaW5hbC12aWV3LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHNfd2ViL2VsZW1lbnRzLzAwZ3JvdXAtaGFybmVzcy9kZWVzLXRlcm1pbmFsLXZpZXcvZGVlcy10ZXJtaW5hbC12aWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDeEQsT0FBTyxFQUNMLFdBQVcsRUFDWCxJQUFJLEVBQ0osR0FBRyxFQUNILGFBQWEsRUFFYixRQUFRLEdBQ1QsTUFBTSw2QkFBNkIsQ0FBQztBQUdyQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQTJCbEU7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFFcEQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDO0FBRXBCLG1EQUFtRDtBQUNuRCxNQUFNLGVBQWUsR0FBRyxDQUFDLFFBQTZCLEVBQVUsRUFBRSxDQUNoRSxPQUFPLFFBQVEsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDO0FBRTNFOzs7Ozs7Ozs7O0dBVUc7SUFFVSxnQkFBZ0I7NEJBRDVCLGFBQWEsQ0FBQyxvQkFBb0IsQ0FBQzs7OztzQkFDRSxXQUFXOzs7Ozs7O2dDQUFuQixTQUFRLFdBQVc7Ozs7b0NBSzlDLFFBQVEsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztvQ0FHMUIsUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFB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
@@ -328,6 +328,20 @@ export interface IHarnessSessionMeta {
328
328
  /** Set false for pinned, non-sortable entries such as terminals. Defaults to true. */
329
329
  draggable?: boolean;
330
330
  }
331
+ /** Discriminates the two kinds of rows the session list orders as peers. */
332
+ export type THarnessSessionListItemKind = 'session' | 'resource';
333
+ /**
334
+ * Stable reference to one ordered row. Session ids and resource ids are
335
+ * separate namespaces, so ordering always carries the kind alongside the id.
336
+ */
337
+ export interface IHarnessSessionListItemRef {
338
+ kind: THarnessSessionListItemKind;
339
+ id: string;
340
+ }
341
+ /** Detail of `harness-session-select` and `harness-session-open`. */
342
+ export interface IHarnessSessionEventDetail {
343
+ session: IHarnessSessionMeta;
344
+ }
331
345
  /** Host-owned metadata for a resource that can be associated with a harness session. */
332
346
  export interface IHarnessResourceMeta<TState extends string = string> {
333
347
  /** Stable identity used by selection and association records. */
@@ -342,34 +356,44 @@ export interface IHarnessResourceMeta<TState extends string = string> {
342
356
  updatedAt?: number;
343
357
  /** Optional host-defined display state. */
344
358
  state?: TState;
359
+ /** Set false for pinned, non-sortable entries. Defaults to true. */
360
+ draggable?: boolean;
345
361
  }
346
- /** A controlled zero-or-one session association for one resource. */
362
+ /**
363
+ * A controlled zero-or-one association for one resource. The target is any
364
+ * other list item — a session or another resource such as a terminal.
365
+ */
347
366
  export interface IHarnessResourceAssociation {
348
367
  resourceId: string;
349
- sessionId: string;
368
+ target: IHarnessSessionListItemRef;
350
369
  }
351
370
  export interface IHarnessResourceEventDetail<TState extends string = string> {
352
371
  resource: IHarnessResourceMeta<TState>;
353
- sessionId: string | null;
372
+ /** The controlled association target, or null when the resource is unattached. */
373
+ target: IHarnessSessionListItemRef | null;
354
374
  }
355
- export type THarnessResourceAssociationInteractionSource = 'drop' | 'action' | 'keyboard';
375
+ /**
376
+ * Association is an explicit host action, never a drop: dragging a resource
377
+ * only moves it inside the ordered list.
378
+ */
379
+ export type THarnessResourceAssociationInteractionSource = 'action' | 'keyboard';
356
380
  export type THarnessResourceAssociationRequestDetail<TState extends string = string> = {
357
381
  intent: 'attach';
358
382
  resource: IHarnessResourceMeta<TState>;
359
- fromSessionId: null;
360
- toSessionId: string;
383
+ fromTarget: null;
384
+ toTarget: IHarnessSessionListItemRef;
361
385
  source: THarnessResourceAssociationInteractionSource;
362
386
  } | {
363
387
  intent: 'detach';
364
388
  resource: IHarnessResourceMeta<TState>;
365
- fromSessionId: string;
366
- toSessionId: null;
389
+ fromTarget: IHarnessSessionListItemRef;
390
+ toTarget: null;
367
391
  source: THarnessResourceAssociationInteractionSource;
368
392
  } | {
369
393
  intent: 'reassign';
370
394
  resource: IHarnessResourceMeta<TState>;
371
- fromSessionId: string;
372
- toSessionId: string;
395
+ fromTarget: IHarnessSessionListItemRef;
396
+ toTarget: IHarnessSessionListItemRef;
373
397
  source: THarnessResourceAssociationInteractionSource;
374
398
  };
375
399
  export type THarnessResourceContextSource = 'pointer' | 'action' | 'keyboard';
@@ -380,7 +404,7 @@ export interface IHarnessResourceContextDetail<TState extends string = string> e
380
404
  source: THarnessResourceContextSource;
381
405
  originalEvent: MouseEvent | KeyboardEvent;
382
406
  /** Routes a host menu choice through the component's validated controlled request event. */
383
- requestAssociation: (toSessionId: string | null) => boolean;
407
+ requestAssociation: (toTarget: IHarnessSessionListItemRef | null) => boolean;
384
408
  /** Closes the external-menu disclosure state and restores focus to its invoking control. */
385
409
  close: () => void;
386
410
  }
@@ -393,21 +417,32 @@ export interface IHarnessSessionContextDetail {
393
417
  /** Pass synchronously to DeesContextmenu.openContextMenuWithOptions to retain its composed dialog owner. */
394
418
  originalEvent: MouseEvent;
395
419
  }
396
- /** A user-defined session group; ordering of `sessionIds` is the display order. */
420
+ /**
421
+ * A user-defined group of list items; ordering of `itemIds` is the display
422
+ * order. Sessions and resources may be members in any interleaving.
423
+ */
397
424
  export interface IHarnessSessionGroup {
398
425
  id: string;
399
426
  name: string;
400
- sessionIds: string[];
401
- }
402
- /** Detail of `harness-session-move`: a session was dropped into a group slot. */
403
- export interface IHarnessSessionMoveDetail {
404
- sessionId: string;
427
+ itemIds: IHarnessSessionListItemRef[];
428
+ }
429
+ export type THarnessItemMoveSource = 'pointer' | 'keyboard';
430
+ /** Detail of `harness-item-move`: one item landed in a new ordered position. */
431
+ export interface IHarnessItemMoveDetail {
432
+ item: IHarnessSessionListItemRef;
433
+ /** Group the item came from, or null for the ungrouped section. */
434
+ fromGroupId: string | null;
405
435
  /** Target group, or null for the ungrouped section. */
436
+ toGroupId: string | null;
437
+ /** Stable target anchor in the dragged-item-excluded order; null means append. */
438
+ beforeItem: IHarnessSessionListItemRef | null;
439
+ source: THarnessItemMoveSource;
440
+ }
441
+ /** The open insertion slot a drag currently targets. */
442
+ export interface IDropSlot {
406
443
  groupId: string | null;
407
- /** Compatibility insertion index using the pre-drag order for same-section moves. */
444
+ /** Index within the section's sortable, dragged-item-excluded order. */
408
445
  index: number;
409
- /** Stable target anchor in the dragged-card-excluded order; absent means append. */
410
- beforeSessionId?: string;
411
446
  }
412
447
  /** Detail of `harness-group-context`, fired on right-click of a group header. */
413
448
  export interface IHarnessGroupContextDetail {
@@ -132,6 +132,13 @@ export declare class DeesServiceLibLoader {
132
132
  * Get the singleton instance of DeesServiceLibLoader
133
133
  */
134
134
  static getInstance(): DeesServiceLibLoader;
135
+ /**
136
+ * Shares one in-flight load between concurrent callers — but only for as long
137
+ * as that load can still succeed. A rejected load clears its own cache entry,
138
+ * so the next call makes a fresh attempt instead of replaying a stale failure
139
+ * for the lifetime of the page. Every load below goes through this.
140
+ */
141
+ private shareLoad;
135
142
  /**
136
143
  * Load xterm terminal emulator from CDN
137
144
  * @returns Promise resolving to xterm module with Terminal class