nomoreide 0.1.35 → 0.1.36

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.
@@ -3,12 +3,26 @@ import { type PtyAdapter, type TerminalSessionLike, type TerminalSize, type Term
3
3
  export interface TerminalSessionInfo extends TerminalSnapshot {
4
4
  id: string;
5
5
  }
6
+ /** Per-session context overriding the manager's workspace defaults. */
7
+ export interface TerminalSpawnOptions {
8
+ cwd?: string;
9
+ env?: NodeJS.ProcessEnv;
10
+ shell?: string;
11
+ args?: string[];
12
+ label?: string;
13
+ }
6
14
  /** The subset of the manager the web layer depends on (so tests can fake it). */
7
15
  export interface TerminalSessionManagerLike {
8
16
  list(): TerminalSessionInfo[];
9
- create(size?: Partial<TerminalSize>): TerminalSessionInfo;
17
+ create(size?: Partial<TerminalSize>, options?: TerminalSpawnOptions): TerminalSessionInfo;
18
+ /** Get-or-create a session under a caller-chosen id (deduping reopens). */
19
+ createWithId(id: string, options?: TerminalSpawnOptions): TerminalSessionInfo;
10
20
  get(id: string): TerminalSessionLike | undefined;
11
21
  ensure(id: string, size?: Partial<TerminalSize>): TerminalSessionLike;
22
+ /** Register client activity (input/resize) so the idle timer resets. */
23
+ touch(id: string): void;
24
+ /** A client socket disconnected; reap the session after the grace window. */
25
+ detach(id: string): void;
12
26
  close(id: string): boolean;
13
27
  disposeAll(): void;
14
28
  }
@@ -18,23 +32,47 @@ export interface TerminalSessionManagerOptions {
18
32
  shell?: string;
19
33
  /** Injectable per-session adapter factory; defaults to the real node-pty adapter. */
20
34
  adapterFactory?: () => PtyAdapter | undefined;
35
+ /** Dispose a session after this many ms with no I/O. `0` disables. */
36
+ idleTimeoutMs?: number;
37
+ /** Dispose a session this many ms after its last client disconnects. `0` disables. */
38
+ disconnectGraceMs?: number;
21
39
  }
22
40
  /**
23
41
  * Owns the live terminal sessions keyed by id so the web UI can run several
24
42
  * tabs at once. The PTY lifecycle stays in {@link TerminalSession}; this layer
25
- * only adds the keyed map, id generation, and fan-out helpers.
43
+ * adds the keyed map, id generation, and crucially for ssh/docker sessions
44
+ * that hold real connections — automatic reaping: a session is disposed once it
45
+ * goes idle for too long or once its last socket disconnects (after a short
46
+ * grace window so a page reload can reattach).
26
47
  */
27
48
  export declare class TerminalSessionManager implements TerminalSessionManagerLike {
28
49
  private readonly options;
50
+ private readonly idleTimeoutMs;
51
+ private readonly disconnectGraceMs;
29
52
  private readonly sessions;
30
53
  private counter;
31
54
  constructor(options: TerminalSessionManagerOptions);
32
55
  list(): TerminalSessionInfo[];
33
- create(size?: Partial<TerminalSize>): TerminalSessionInfo;
56
+ create(size?: Partial<TerminalSize>, options?: TerminalSpawnOptions): TerminalSessionInfo;
57
+ /**
58
+ * Get-or-create a session under a caller-chosen id (e.g. `svc:<service>`), so
59
+ * reopening a service terminal reattaches to the same shell instead of
60
+ * spawning a duplicate. The spawn options are honored only on first creation.
61
+ */
62
+ createWithId(id: string, options?: TerminalSpawnOptions): TerminalSessionInfo;
34
63
  get(id: string): TerminalSessionLike | undefined;
35
- /** Returns the session for `id`, creating and starting one if it is unknown. */
64
+ /**
65
+ * Returns the session for `id`, creating one if unknown, and marks a client
66
+ * as attached (this is the socket "connect" path).
67
+ */
36
68
  ensure(id: string, size?: Partial<TerminalSize>): TerminalSessionLike;
69
+ touch(id: string): void;
70
+ detach(id: string): void;
37
71
  close(id: string): boolean;
38
72
  disposeAll(): void;
39
73
  private spawn;
74
+ private markConnected;
75
+ private resetIdle;
76
+ private scheduleGrace;
77
+ private clearTimers;
40
78
  }
@@ -1,64 +1,153 @@
1
1
  import { TerminalSession, } from "./terminal-session.js";
2
+ /** 30 minutes of silence (no input or output) reaps a session. */
3
+ const DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
4
+ /** A reload reconnects within a moment; wait this long before reaping an orphan. */
5
+ const DEFAULT_DISCONNECT_GRACE_MS = 30 * 1000;
2
6
  /**
3
7
  * Owns the live terminal sessions keyed by id so the web UI can run several
4
8
  * tabs at once. The PTY lifecycle stays in {@link TerminalSession}; this layer
5
- * only adds the keyed map, id generation, and fan-out helpers.
9
+ * adds the keyed map, id generation, and crucially for ssh/docker sessions
10
+ * that hold real connections — automatic reaping: a session is disposed once it
11
+ * goes idle for too long or once its last socket disconnects (after a short
12
+ * grace window so a page reload can reattach).
6
13
  */
7
14
  export class TerminalSessionManager {
8
15
  options;
16
+ idleTimeoutMs;
17
+ disconnectGraceMs;
9
18
  sessions = new Map();
10
19
  counter = 0;
11
20
  constructor(options) {
12
21
  this.options = options;
22
+ this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
23
+ this.disconnectGraceMs =
24
+ options.disconnectGraceMs ?? DEFAULT_DISCONNECT_GRACE_MS;
13
25
  }
14
26
  list() {
15
- return [...this.sessions.entries()].map(([id, session]) => ({
27
+ return [...this.sessions.entries()].map(([id, managed]) => ({
16
28
  id,
17
- ...session.snapshot(),
29
+ ...managed.session.snapshot(),
18
30
  }));
19
31
  }
20
- create(size = {}) {
32
+ create(size = {}, options = {}) {
21
33
  const id = `term_${++this.counter}`;
22
- const session = this.spawn(size);
23
- this.sessions.set(id, session);
24
- return { id, ...session.snapshot() };
34
+ const managed = this.spawn(id, size, options);
35
+ this.sessions.set(id, managed);
36
+ // Created but not yet connected: reap it if no socket attaches in time
37
+ // (e.g. the POST landed but the client navigated away before connecting).
38
+ this.scheduleGrace(id, managed);
39
+ return { id, ...managed.session.snapshot() };
40
+ }
41
+ /**
42
+ * Get-or-create a session under a caller-chosen id (e.g. `svc:<service>`), so
43
+ * reopening a service terminal reattaches to the same shell instead of
44
+ * spawning a duplicate. The spawn options are honored only on first creation.
45
+ */
46
+ createWithId(id, options = {}) {
47
+ const existing = this.sessions.get(id);
48
+ if (existing)
49
+ return { id, ...existing.session.snapshot() };
50
+ const managed = this.spawn(id, {}, options);
51
+ this.sessions.set(id, managed);
52
+ this.scheduleGrace(id, managed);
53
+ return { id, ...managed.session.snapshot() };
25
54
  }
26
55
  get(id) {
27
- return this.sessions.get(id);
56
+ return this.sessions.get(id)?.session;
28
57
  }
29
- /** Returns the session for `id`, creating and starting one if it is unknown. */
58
+ /**
59
+ * Returns the session for `id`, creating one if unknown, and marks a client
60
+ * as attached (this is the socket "connect" path).
61
+ */
30
62
  ensure(id, size = {}) {
31
63
  const existing = this.sessions.get(id);
32
64
  if (existing) {
33
- existing.start(size);
34
- return existing;
65
+ existing.session.start(size);
66
+ this.markConnected(id, existing);
67
+ return existing.session;
35
68
  }
36
- const session = this.spawn(size);
37
- this.sessions.set(id, session);
38
- return session;
69
+ const managed = this.spawn(id, size, {});
70
+ this.sessions.set(id, managed);
71
+ this.markConnected(id, managed);
72
+ return managed.session;
73
+ }
74
+ touch(id) {
75
+ const managed = this.sessions.get(id);
76
+ if (managed)
77
+ this.resetIdle(id, managed);
78
+ }
79
+ detach(id) {
80
+ const managed = this.sessions.get(id);
81
+ if (!managed)
82
+ return;
83
+ // Keep the session alive on disconnect so a page reload or reopening the
84
+ // tab reattaches to it. The idle timer is the only soft reaper; a full
85
+ // process shutdown disposes everything (see `disposeAll`).
86
+ managed.connections = Math.max(0, managed.connections - 1);
39
87
  }
40
88
  close(id) {
41
- const session = this.sessions.get(id);
42
- if (!session)
89
+ const managed = this.sessions.get(id);
90
+ if (!managed)
43
91
  return false;
44
- session.dispose();
92
+ this.clearTimers(managed);
93
+ managed.outputSub.dispose();
94
+ managed.session.dispose();
45
95
  this.sessions.delete(id);
46
96
  return true;
47
97
  }
48
98
  disposeAll() {
49
- for (const session of this.sessions.values())
50
- session.dispose();
99
+ for (const managed of this.sessions.values()) {
100
+ this.clearTimers(managed);
101
+ managed.outputSub.dispose();
102
+ managed.session.dispose();
103
+ }
51
104
  this.sessions.clear();
52
105
  }
53
- spawn(size) {
106
+ spawn(id, size, options) {
54
107
  const session = new TerminalSession({
55
108
  adapter: this.options.adapterFactory?.(),
56
- cwd: this.options.cwd,
57
- env: this.options.env,
58
- shell: this.options.shell,
109
+ cwd: options.cwd ?? this.options.cwd,
110
+ env: options.env ?? this.options.env,
111
+ shell: options.shell ?? this.options.shell,
112
+ args: options.args,
113
+ label: options.label,
59
114
  });
115
+ // PTY output counts as activity, so a live tail keeps the session alive.
116
+ const outputSub = session.onOutput(() => this.touch(id));
60
117
  session.start(size);
61
- return session;
118
+ return { session, connections: 0, outputSub };
119
+ }
120
+ markConnected(id, managed) {
121
+ managed.connections += 1;
122
+ if (managed.graceTimer) {
123
+ clearTimeout(managed.graceTimer);
124
+ managed.graceTimer = undefined;
125
+ }
126
+ this.resetIdle(id, managed);
127
+ }
128
+ resetIdle(id, managed) {
129
+ if (managed.idleTimer)
130
+ clearTimeout(managed.idleTimer);
131
+ if (this.idleTimeoutMs <= 0)
132
+ return;
133
+ managed.idleTimer = setTimeout(() => this.close(id), this.idleTimeoutMs);
134
+ managed.idleTimer.unref?.();
135
+ }
136
+ scheduleGrace(id, managed) {
137
+ if (managed.graceTimer)
138
+ clearTimeout(managed.graceTimer);
139
+ if (this.disconnectGraceMs <= 0)
140
+ return;
141
+ managed.graceTimer = setTimeout(() => this.close(id), this.disconnectGraceMs);
142
+ managed.graceTimer.unref?.();
143
+ }
144
+ clearTimers(managed) {
145
+ if (managed.idleTimer)
146
+ clearTimeout(managed.idleTimer);
147
+ if (managed.graceTimer)
148
+ clearTimeout(managed.graceTimer);
149
+ managed.idleTimer = undefined;
150
+ managed.graceTimer = undefined;
62
151
  }
63
152
  }
64
153
  //# sourceMappingURL=terminal-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-manager.js","sourceRoot":"","sources":["../../src/core/terminal-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,GAIhB,MAAM,uBAAuB,CAAC;AAyB/B;;;;GAIG;AACH,MAAM,OAAO,sBAAsB;IAChB,OAAO,CAAgC;IACvC,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC3D,OAAO,GAAG,CAAC,CAAC;IAEpB,YAAY,OAAsC;QAChD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1D,EAAE;YACF,GAAG,OAAO,CAAC,QAAQ,EAAE;SACtB,CAAC,CAAC,CAAC;IACN,CAAC;IAED,MAAM,CAAC,OAA8B,EAAE;QACrC,MAAM,EAAE,GAAG,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IACvC,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,gFAAgF;IAChF,MAAM,CAAC,EAAU,EAAE,OAA8B,EAAE;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,EAAU;QACd,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU;QACR,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;YAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAChE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,IAA2B;QACvC,MAAM,OAAO,GAAG,IAAI,eAAe,CAAC;YAClC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE;YACxC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;YACrB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;YACrB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;SAC1B,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpB,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
1
+ {"version":3,"file":"terminal-manager.js","sourceRoot":"","sources":["../../src/core/terminal-manager.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,8 @@ export interface TerminalSnapshot extends TerminalSize {
11
11
  cwd: string;
12
12
  state: TerminalState;
13
13
  shell: string;
14
+ /** Human label for the tab (e.g. a service name); absent for plain shells. */
15
+ label?: string;
14
16
  exit?: TerminalExit;
15
17
  error?: string;
16
18
  }
@@ -39,6 +41,9 @@ export interface TerminalSessionOptions {
39
41
  cwd: string;
40
42
  env?: NodeJS.ProcessEnv;
41
43
  shell?: string;
44
+ /** Args for the spawned program. Empty → a plain interactive shell. */
45
+ args?: string[];
46
+ label?: string;
42
47
  }
43
48
  type Listener<T> = (value: T) => void;
44
49
  export interface TerminalSessionLike {
@@ -61,6 +66,8 @@ export declare class TerminalSession implements TerminalSessionLike {
61
66
  private readonly cwd;
62
67
  private readonly env;
63
68
  private readonly shell;
69
+ private readonly args;
70
+ private readonly label;
64
71
  private cols;
65
72
  private rows;
66
73
  private exit;
@@ -5,6 +5,8 @@ export class TerminalSession {
5
5
  cwd;
6
6
  env;
7
7
  shell;
8
+ args;
9
+ label;
8
10
  cols = 80;
9
11
  rows = 24;
10
12
  exit;
@@ -19,6 +21,8 @@ export class TerminalSession {
19
21
  this.cwd = options.cwd;
20
22
  this.env = options.env ?? process.env;
21
23
  this.shell = options.shell ?? defaultShell();
24
+ this.args = options.args ?? [];
25
+ this.label = options.label;
22
26
  }
23
27
  snapshot() {
24
28
  return {
@@ -26,6 +30,7 @@ export class TerminalSession {
26
30
  cwd: this.cwd,
27
31
  error: this.error,
28
32
  exit: this.exit,
33
+ label: this.label,
29
34
  rows: this.rows,
30
35
  shell: this.shell,
31
36
  state: this.state,
@@ -58,7 +63,7 @@ export class TerminalSession {
58
63
  this.exit = undefined;
59
64
  this.error = undefined;
60
65
  try {
61
- const child = this.adapter.spawn(this.shell, [], {
66
+ const child = this.adapter.spawn(this.shell, this.args, {
62
67
  cols: this.cols,
63
68
  cwd: this.cwd,
64
69
  env: this.env,
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-session.js","sourceRoot":"","sources":["../../src/core/terminal-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal-session.js","sourceRoot":"","sources":["../../src/core/terminal-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ServiceDefinition } from "./types.js";
2
+ import type { TerminalSpawnOptions } from "./terminal-manager.js";
3
+ /**
4
+ * Result of mapping a service to terminal spawn options. `ok: false` carries a
5
+ * user-facing reason (e.g. an SSH service with no host) the route returns as a
6
+ * 400 instead of spawning a broken session.
7
+ */
8
+ export type TerminalSpawnResolution = {
9
+ ok: true;
10
+ options: TerminalSpawnOptions;
11
+ } | {
12
+ ok: false;
13
+ error: string;
14
+ };
15
+ /**
16
+ * Decide what a "connect" terminal runs for a given service:
17
+ * - **local** → an interactive shell in the service's cwd, with its env merged
18
+ * over the inherited environment so PATH survives.
19
+ * - **ssh** → `ssh -t <host>` into the remote, cd-ing into the service dir and
20
+ * launching a login shell there.
21
+ * - **docker-compose** → `docker compose exec <service> sh` from the project dir.
22
+ *
23
+ * The client only ever sends a service *name*; the server derives the command
24
+ * here, so this endpoint can't be coerced into running an arbitrary program.
25
+ */
26
+ export declare function resolveServiceTerminal(service: ServiceDefinition): TerminalSpawnResolution;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Decide what a "connect" terminal runs for a given service:
3
+ * - **local** → an interactive shell in the service's cwd, with its env merged
4
+ * over the inherited environment so PATH survives.
5
+ * - **ssh** → `ssh -t <host>` into the remote, cd-ing into the service dir and
6
+ * launching a login shell there.
7
+ * - **docker-compose** → `docker compose exec <service> sh` from the project dir.
8
+ *
9
+ * The client only ever sends a service *name*; the server derives the command
10
+ * here, so this endpoint can't be coerced into running an arbitrary program.
11
+ */
12
+ export function resolveServiceTerminal(service) {
13
+ const kind = service.kind ?? "local";
14
+ if (kind === "ssh") {
15
+ if (!service.host) {
16
+ return { ok: false, error: "SSH service is missing a host." };
17
+ }
18
+ const remote = service.cwd
19
+ ? `cd ${singleQuote(service.cwd)} 2>/dev/null; exec "$SHELL" -l`
20
+ : `exec "$SHELL" -l`;
21
+ return {
22
+ ok: true,
23
+ options: {
24
+ shell: "ssh",
25
+ args: ["-t", service.host, remote],
26
+ label: service.name,
27
+ },
28
+ };
29
+ }
30
+ if (kind === "docker-compose") {
31
+ if (!service.composeService) {
32
+ return { ok: false, error: "Docker service is missing a compose service name." };
33
+ }
34
+ return {
35
+ ok: true,
36
+ options: {
37
+ shell: "docker",
38
+ args: [
39
+ "compose",
40
+ ...(service.composeFile ? ["-f", service.composeFile] : []),
41
+ "exec",
42
+ service.composeService,
43
+ "sh",
44
+ ],
45
+ cwd: service.cwd,
46
+ label: service.name,
47
+ },
48
+ };
49
+ }
50
+ return {
51
+ ok: true,
52
+ options: {
53
+ cwd: service.cwd,
54
+ env: service.env ? { ...process.env, ...service.env } : undefined,
55
+ label: service.name,
56
+ },
57
+ };
58
+ }
59
+ /** Single-quote a value for safe interpolation into a remote shell command. */
60
+ function singleQuote(value) {
61
+ return `'${value.replace(/'/g, `'\\''`)}'`;
62
+ }
63
+ //# sourceMappingURL=terminal-spawn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-spawn.js","sourceRoot":"","sources":["../../src/core/terminal-spawn.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA0B;IAE1B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC;IAErC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;QAChE,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG;YACxB,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC;YAChE,CAAC,CAAC,kBAAkB,CAAC;QACvB,OAAO;YACL,EAAE,EAAE,IAAI;YACR,OAAO,EAAE;gBACP,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;gBAClC,KAAK,EAAE,OAAO,CAAC,IAAI;aACpB;SACF,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mDAAmD,EAAE,CAAC;QACnF,CAAC;QACD,OAAO;YACL,EAAE,EAAE,IAAI;YACR,OAAO,EAAE;gBACP,KAAK,EAAE,QAAQ;gBACf,IAAI,EAAE;oBACJ,SAAS;oBACT,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3D,MAAM;oBACN,OAAO,CAAC,cAAc;oBACtB,IAAI;iBACL;gBACD,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,KAAK,EAAE,OAAO,CAAC,IAAI;aACpB;SACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE;YACP,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;YACjE,KAAK,EAAE,OAAO,CAAC,IAAI;SACpB;KACF,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC"}