@pstdio/ui 0.39.0 → 0.41.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 (82) hide show
  1. package/dist/{MermaidComponent-81jr28u4.js → MermaidComponent-BCiI63_G.js} +3 -3
  2. package/dist/{MermaidComponent-81jr28u4.js.map → MermaidComponent-BCiI63_G.js.map} +1 -1
  3. package/dist/chat-question-bubble-w2vMbFsS.js +68 -0
  4. package/dist/chat-question-bubble-w2vMbFsS.js.map +1 -0
  5. package/dist/chat-ui.d.ts +94 -17
  6. package/dist/chat-ui.js +2240 -1476
  7. package/dist/chat-ui.js.map +1 -1
  8. package/dist/{data-table-stats-row-CpRe_xK2.js → data-table-stats-row-EiTEONdY.js} +2 -2
  9. package/dist/{data-table-stats-row-CpRe_xK2.js.map → data-table-stats-row-EiTEONdY.js.map} +1 -1
  10. package/dist/data-table.d.ts +27 -7
  11. package/dist/data-table.js +1035 -872
  12. package/dist/data-table.js.map +1 -1
  13. package/dist/diff-bubble-DewUd_2w.js +61 -0
  14. package/dist/diff-bubble-DewUd_2w.js.map +1 -0
  15. package/dist/{diff-drawer-45rpk3aq.js → diff-drawer-BwZBOObe.js} +106 -85
  16. package/dist/diff-drawer-BwZBOObe.js.map +1 -0
  17. package/dist/diff-viewer-kOOd7C7h.js +574 -0
  18. package/dist/diff-viewer-kOOd7C7h.js.map +1 -0
  19. package/dist/diff.d.ts +11 -0
  20. package/dist/diff.js +107 -98
  21. package/dist/diff.js.map +1 -1
  22. package/dist/display-sort-control-DPxc0e5z.js +587 -0
  23. package/dist/display-sort-control-DPxc0e5z.js.map +1 -0
  24. package/dist/{workspace-badge-Brm3Xr3m.d.ts → host-storage-DP0RLj4i.d.ts} +15 -1
  25. package/dist/{index-BfFLdci8.d.ts → index-C9mywhyX.d.ts} +49 -13
  26. package/dist/index-D3UJyWWh.d.ts +501 -0
  27. package/dist/index.d.ts +38 -13
  28. package/dist/index.js +941 -908
  29. package/dist/index.js.map +1 -1
  30. package/dist/kanban-renderer.d.ts +2 -326
  31. package/dist/kanban-renderer.js +991 -610
  32. package/dist/kanban-renderer.js.map +1 -1
  33. package/dist/list-row-DM0DiIrN.js +1167 -0
  34. package/dist/list-row-DM0DiIrN.js.map +1 -0
  35. package/dist/{mermaid-renderer-DImi0fDp.js → mermaid-renderer-0PmNkOXI.js} +29 -29
  36. package/dist/mermaid-renderer-0PmNkOXI.js.map +1 -0
  37. package/dist/mermaid.js +1 -1
  38. package/dist/param-editor.js +2 -3
  39. package/dist/prism-JVIsQMoJ.js +1029 -0
  40. package/dist/prism-JVIsQMoJ.js.map +1 -0
  41. package/dist/{resource-badge-95WPVlZf.d.ts → resource-badge-nOWPqxFU.d.ts} +1 -0
  42. package/dist/rich-text-DM24VNQZ.js +10447 -0
  43. package/dist/rich-text-DM24VNQZ.js.map +1 -0
  44. package/dist/rich-text.d.ts +2 -2
  45. package/dist/rich-text.js +2 -2
  46. package/dist/style.css +1 -1
  47. package/dist/terminal.d.ts +5 -63
  48. package/dist/terminal.js +102 -122
  49. package/dist/terminal.js.map +1 -1
  50. package/dist/{theme-BsOWAIi2.js → theme-at0rtSnX.js} +441 -246
  51. package/dist/theme-at0rtSnX.js.map +1 -0
  52. package/dist/theme-kKuLN2jb.js +80 -0
  53. package/dist/theme-kKuLN2jb.js.map +1 -0
  54. package/dist/theme-preference-BV4cbJNB.js +115 -0
  55. package/dist/theme-preference-BV4cbJNB.js.map +1 -0
  56. package/dist/theme.js +3 -2
  57. package/dist/{tree-list-WhISG-cz.js → tree-list-Cqgl8mnN.js} +400 -377
  58. package/dist/tree-list-Cqgl8mnN.js.map +1 -0
  59. package/package.json +4 -4
  60. package/dist/diff-bubble-DZsarmSG.js +0 -61
  61. package/dist/diff-bubble-DZsarmSG.js.map +0 -1
  62. package/dist/diff-drawer-45rpk3aq.js.map +0 -1
  63. package/dist/diff-viewer-DJ1B5hxL.js +0 -558
  64. package/dist/diff-viewer-DJ1B5hxL.js.map +0 -1
  65. package/dist/list-row-uqD-q4gv.js +0 -1018
  66. package/dist/list-row-uqD-q4gv.js.map +0 -1
  67. package/dist/mermaid-renderer-DImi0fDp.js.map +0 -1
  68. package/dist/param-editor-BQd4AOUP.js +0 -225
  69. package/dist/param-editor-BQd4AOUP.js.map +0 -1
  70. package/dist/param-editor-field-BJ_rLUnV.js +0 -2385
  71. package/dist/param-editor-field-BJ_rLUnV.js.map +0 -1
  72. package/dist/prism-BStPsJSB.js +0 -658
  73. package/dist/prism-BStPsJSB.js.map +0 -1
  74. package/dist/rich-text-VYAmEigU.js +0 -6979
  75. package/dist/rich-text-VYAmEigU.js.map +0 -1
  76. package/dist/slider-hwHYe98I.js +0 -423
  77. package/dist/slider-hwHYe98I.js.map +0 -1
  78. package/dist/theme-BsOWAIi2.js.map +0 -1
  79. package/dist/theme-preference-pzfuK5cH.js +0 -101
  80. package/dist/theme-preference-pzfuK5cH.js.map +0 -1
  81. package/dist/tree-list-WhISG-cz.js.map +0 -1
  82. package/dist/types-DWA3enV6.d.ts +0 -182
package/dist/terminal.js CHANGED
@@ -1,12 +1,13 @@
1
- import { c as e } from "react/compiler-runtime";
2
- import { jsx as t } from "react/jsx-runtime";
3
- import { useEffect as n, useRef as r, useState as i } from "react";
4
- import { FitAddon as a } from "@xterm/addon-fit";
5
- import { WebLinksAddon as o } from "@xterm/addon-web-links";
6
- import { Terminal as s } from "@xterm/xterm";
1
+ import { t as e } from "./theme-at0rtSnX.js";
2
+ import { c as t } from "react/compiler-runtime";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ import { useEffect as r, useRef as i, useState as a } from "react";
5
+ import { FitAddon as o } from "@xterm/addon-fit";
6
+ import { WebLinksAddon as s } from "@xterm/addon-web-links";
7
+ import { Terminal as c } from "@xterm/xterm";
7
8
  import "@xterm/xterm/css/xterm.css";
8
9
  //#region src/components/terminal/bind-session.ts
9
- var c = (e, t, n = {}) => {
10
+ var l = (e, t, n = {}) => {
10
11
  let r = [];
11
12
  return r.push(t.onData((t) => e.write(t))), r.push(e.onInput((e) => {
12
13
  t.write(e), n.onInput?.(e);
@@ -20,17 +21,17 @@ var c = (e, t, n = {}) => {
20
21
  } catch {}
21
22
  }
22
23
  };
23
- }, l = new TextEncoder(), u = (e) => typeof e == "string" ? l.encode(e) : e, d = (e) => e > 0 ? new Promise((t) => setTimeout(t, e)) : Promise.resolve(), f = (e) => [{ data: e.replace(/\r/g, "\r\n") }], p = (e, t) => {
24
- t.data !== void 0 && e.emitData(u(t.data)), t.error !== void 0 && e.emitError({ message: t.error }), t.exit !== void 0 && e.emitExit({
24
+ }, u = new TextEncoder(), d = (e) => typeof e == "string" ? u.encode(e) : e, f = (e) => e > 0 ? new Promise((t) => setTimeout(t, e)) : Promise.resolve(), p = (e) => [{ data: e.replace(/\r/g, "\r\n") }], m = (e, t) => {
25
+ t.data !== void 0 && e.emitData(d(t.data)), t.error !== void 0 && e.emitError({ message: t.error }), t.exit !== void 0 && e.emitExit({
25
26
  code: t.exit.code,
26
27
  signal: t.exit.signal ?? null
27
28
  });
28
- }, m = async (e, t) => {
29
+ }, h = async (e, t) => {
29
30
  for (let n of t) {
30
- if (e.isExited() || (await d(n.delayMs ?? 0), e.isExited())) return;
31
- p(e, n);
31
+ if (e.isExited() || (await f(n.delayMs ?? 0), e.isExited())) return;
32
+ m(e, n);
32
33
  }
33
- }, h = (e, t) => {
34
+ }, g = (e, t) => {
34
35
  let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = !1, o = !1, s = {
35
36
  isExited: () => a,
36
37
  emitData(e) {
@@ -51,7 +52,7 @@ var c = (e, t, n = {}) => {
51
52
  write(e) {
52
53
  if (a) return;
53
54
  let n = t(typeof e == "string" ? e : new TextDecoder().decode(e));
54
- n && m(s, n);
55
+ n && h(s, n);
55
56
  },
56
57
  resize(t, n) {
57
58
  e.onResize?.({
@@ -66,7 +67,7 @@ var c = (e, t, n = {}) => {
66
67
  }));
67
68
  },
68
69
  onData(t) {
69
- return n.add(t), !o && e.initial && (o = !0, m(s, e.initial)), () => n.delete(t);
70
+ return n.add(t), !o && e.initial && (o = !0, h(s, e.initial)), () => n.delete(t);
70
71
  },
71
72
  onExit(e) {
72
73
  return r.add(e), () => r.delete(e);
@@ -75,81 +76,60 @@ var c = (e, t, n = {}) => {
75
76
  return i.add(e), () => i.delete(e);
76
77
  }
77
78
  } };
78
- }, g = (e = {}) => {
79
- let t = e.onInput ?? f;
79
+ }, _ = (e = {}) => {
80
+ let t = e.onInput ?? p;
80
81
  return { async openSession(n) {
81
- let { session: r } = h(e, t);
82
+ let { session: r } = g(e, t);
82
83
  return r;
83
84
  } };
84
- }, _ = {
85
- cursorAccent: "#000000",
86
- selectionForeground: void 0
87
- }, v = {
88
- ..._,
89
- background: "#f4f4f5",
90
- foreground: "#171717",
91
- cursor: "#171717",
92
- selectionBackground: "#d4d4d8",
93
- black: "#27272a",
94
- red: "#dc2626",
95
- green: "#16a34a",
96
- yellow: "#ca8a04",
97
- blue: "#2563eb",
98
- magenta: "#c026d3",
99
- cyan: "#0891b2",
100
- white: "#e4e4e7",
101
- brightBlack: "#52525b",
102
- brightRed: "#ef4444",
103
- brightGreen: "#22c55e",
104
- brightYellow: "#eab308",
105
- brightBlue: "#3b82f6",
106
- brightMagenta: "#d946ef",
107
- brightCyan: "#06b6d4",
108
- brightWhite: "#fafafa"
109
- }, y = {
110
- ..._,
111
- background: "#0a0a0a",
112
- foreground: "#fafafa",
113
- cursor: "#fafafa",
114
- selectionBackground: "#3f3f46",
115
- black: "#27272a",
116
- red: "#f87171",
117
- green: "#4ade80",
118
- yellow: "#facc15",
119
- blue: "#60a5fa",
120
- magenta: "#e879f9",
121
- cyan: "#22d3ee",
122
- white: "#e4e4e7",
123
- brightBlack: "#52525b",
124
- brightRed: "#fca5a5",
125
- brightGreen: "#86efac",
126
- brightYellow: "#fde047",
127
- brightBlue: "#93c5fd",
128
- brightMagenta: "#f0abfc",
129
- brightCyan: "#67e8f9",
130
- brightWhite: "#fafafa"
131
- }, b = {
132
- light: v,
133
- dark: y
134
- }, x = (e) => e ? typeof e == "string" ? b[e] : e : b.dark, S = (e) => JSON.stringify({
85
+ }, v = (t) => {
86
+ let n = (n) => e.token(`colors.terminal.${t}.${n}`);
87
+ return {
88
+ background: n("background"),
89
+ foreground: n("foreground"),
90
+ cursor: n("cursor"),
91
+ cursorAccent: n("cursorAccent"),
92
+ selectionBackground: n("selectionBackground"),
93
+ selectionForeground: void 0,
94
+ black: n("black"),
95
+ red: n("red"),
96
+ green: n("green"),
97
+ yellow: n("yellow"),
98
+ blue: n("blue"),
99
+ magenta: n("magenta"),
100
+ cyan: n("cyan"),
101
+ white: n("white"),
102
+ brightBlack: n("brightBlack"),
103
+ brightRed: n("brightRed"),
104
+ brightGreen: n("brightGreen"),
105
+ brightYellow: n("brightYellow"),
106
+ brightBlue: n("brightBlue"),
107
+ brightMagenta: n("brightMagenta"),
108
+ brightCyan: n("brightCyan"),
109
+ brightWhite: n("brightWhite")
110
+ };
111
+ }, y = v("light"), b = v("dark"), x = {
112
+ light: y,
113
+ dark: b
114
+ }, S = (e) => e ? typeof e == "string" ? x[e] : e : x.dark, C = (e) => JSON.stringify({
135
115
  command: e.command,
136
116
  cwd: e.cwd,
137
117
  env: e.env ? Object.fromEntries(Object.entries(e.env).sort(([e], [t]) => e.localeCompare(t))) : void 0,
138
118
  cols: e.cols,
139
119
  rows: e.rows
140
- }), C = (e) => JSON.parse(e), w = (t) => {
141
- let r = e(8), { bridge: a, request: o, killOnUnmount: s } = t, c = s === void 0 || s, l;
142
- r[0] === o ? l = r[1] : (l = S(o), r[0] = o, r[1] = l);
120
+ }), w = (e) => JSON.parse(e), T = (e) => {
121
+ let n = t(8), { bridge: i, request: o, killOnUnmount: s } = e, c = s === void 0 || s, l;
122
+ n[0] === o ? l = n[1] : (l = C(o), n[0] = o, n[1] = l);
143
123
  let u = l, d;
144
- r[2] === Symbol.for("react.memo_cache_sentinel") ? (d = {
124
+ n[2] === Symbol.for("react.memo_cache_sentinel") ? (d = {
145
125
  session: null,
146
126
  status: "idle",
147
127
  exit: null,
148
128
  error: null
149
- }, r[2] = d) : d = r[2];
150
- let [f, p] = i(d), m, h;
151
- return r[3] !== a || r[4] !== c || r[5] !== u ? (m = () => {
152
- if (!a) {
129
+ }, n[2] = d) : d = n[2];
130
+ let [f, p] = a(d), m, h;
131
+ return n[3] !== i || n[4] !== c || n[5] !== u ? (m = () => {
132
+ if (!i) {
153
133
  p({
154
134
  session: null,
155
135
  status: "idle",
@@ -165,8 +145,8 @@ var c = (e, t, n = {}) => {
165
145
  exit: null,
166
146
  error: null
167
147
  });
168
- let i = C(u);
169
- return a.openSession(i).then((i) => {
148
+ let a = w(u);
149
+ return i.openSession(a).then((i) => {
170
150
  if (e) {
171
151
  c && i.kill();
172
152
  return;
@@ -203,15 +183,15 @@ var c = (e, t, n = {}) => {
203
183
  c && t && n !== "exited" && t.kill();
204
184
  };
205
185
  }, h = [
206
- a,
186
+ i,
207
187
  u,
208
188
  c
209
- ], r[3] = a, r[4] = c, r[5] = u, r[6] = m, r[7] = h) : (m = r[6], h = r[7]), n(m, h), f;
210
- }, T = "\"JetBrains Mono\", \"Fira Code\", Menlo, Consolas, monospace", E = 13, D = 80, O = 24, k = (e) => ({
189
+ ], n[3] = i, n[4] = c, n[5] = u, n[6] = m, n[7] = h) : (m = n[6], h = n[7]), r(m, h), f;
190
+ }, E = "\"JetBrains Mono\", \"Fira Code\", Menlo, Consolas, monospace", D = 13, O = 80, k = 24, A = (e) => ({
211
191
  ...e,
212
- cols: e?.cols ?? D,
213
- rows: e?.rows ?? O
214
- }), A = (e) => {
192
+ cols: e?.cols ?? O,
193
+ rows: e?.rows ?? k
194
+ }), j = (e) => {
215
195
  let t = /* @__PURE__ */ new Set(), n = [], r = e.onData((e) => {
216
196
  if (t.size === 0) {
217
197
  n.push(e);
@@ -235,73 +215,73 @@ var c = (e, t, n = {}) => {
235
215
  r.dispose(), t.clear(), n.length = 0;
236
216
  }
237
217
  };
238
- }, j = (e) => {
218
+ }, M = (e) => {
239
219
  try {
240
220
  e?.fit();
241
221
  } catch {}
242
- }, M = (e, t) => {
222
+ }, N = (e, t) => {
243
223
  t.resize(e.cols, e.rows);
244
- }, N = (e, t, n, r) => {
245
- let i = c(t, n, { onExit: r.onSessionExit });
246
- return M(e, n), r.onSessionOpen?.(n.id), i;
247
- }, P = (e, t, n, r) => N(e, t, n, {
224
+ }, P = (e, t, n, r) => {
225
+ let i = l(t, n, { onExit: r.onSessionExit });
226
+ return N(e, n), r.onSessionOpen?.(n.id), i;
227
+ }, F = (e, t, n, r) => P(e, t, n, {
248
228
  onSessionOpen: (e) => r.onSessionOpen.current?.(e),
249
229
  onSessionExit: (e) => r.onSessionExit.current?.(e)
250
- }), F = (e) => {
251
- let { bridge: c, request: l, theme: u, fontFamily: d = T, fontSize: f = E, killOnUnmount: p = !0, autoFocus: m = !0, className: h, style: g, onSessionOpen: _, onSessionExit: v } = e, y = r(null), b = r(null), S = r(null), C = r(null), [M, N] = i(!1), F = r(null), I = r(_), L = r(v);
252
- I.current = _, L.current = v, F.current ||= k(l);
253
- let R = x(u);
254
- n(() => {
230
+ }), I = (e) => {
231
+ let { bridge: t, request: l, theme: u, fontFamily: d = E, fontSize: f = D, killOnUnmount: p = !0, autoFocus: m = !0, className: h, style: g, onSessionOpen: _, onSessionExit: v } = e, y = i(null), b = i(null), x = i(null), C = i(null), [w, N] = a(!1), P = i(null), I = i(_), L = i(v);
232
+ I.current = _, L.current = v, P.current ||= A(l);
233
+ let R = S(u);
234
+ r(() => {
255
235
  let e = y.current;
256
236
  if (!e) return;
257
- let t, n, r, i, c, l = window.requestAnimationFrame(() => {
258
- t = new s({
259
- cols: D,
260
- rows: O,
237
+ let t, n, r, i, a, l = window.requestAnimationFrame(() => {
238
+ t = new c({
239
+ cols: O,
240
+ rows: k,
261
241
  cursorBlink: !0,
262
242
  convertEol: !0,
263
243
  allowProposedApi: !0
264
244
  });
265
- let l = new a();
266
- t.loadAddon(l), t.loadAddon(new o((e, t) => {
245
+ let l = new o();
246
+ t.loadAddon(l), t.loadAddon(new s((e, t) => {
267
247
  (e.ctrlKey || e.metaKey) && window.open(t, "_blank", "noopener,noreferrer");
268
- })), t.open(e), n = A(t), b.current = t, S.current = l, C.current = n;
269
- let u = () => j(l);
270
- u(), r = window.requestAnimationFrame(u), i = window.setTimeout(u, 50), c = new ResizeObserver(u), c.observe(e), N(!0);
248
+ })), t.open(e), n = j(t), b.current = t, x.current = l, C.current = n;
249
+ let u = () => M(l);
250
+ u(), r = window.requestAnimationFrame(u), i = window.setTimeout(u, 50), a = new ResizeObserver(u), a.observe(e), N(!0);
271
251
  });
272
252
  return () => {
273
- window.cancelAnimationFrame(l), r !== void 0 && window.cancelAnimationFrame(r), i !== void 0 && window.clearTimeout(i), c?.disconnect(), n?.dispose(), t?.dispose(), b.current = null, S.current = null, C.current = null;
253
+ window.cancelAnimationFrame(l), r !== void 0 && window.cancelAnimationFrame(r), i !== void 0 && window.clearTimeout(i), a?.disconnect(), n?.dispose(), t?.dispose(), b.current = null, x.current = null, C.current = null;
274
254
  };
275
- }, []), n(() => {
276
- if (!M) return;
255
+ }, []), r(() => {
256
+ if (!w) return;
277
257
  let e = b.current;
278
- e && (e.options.theme = R, e.options.fontFamily = d, e.options.fontSize = f, j(S.current));
258
+ e && (e.options.theme = R, e.options.fontFamily = d, e.options.fontSize = f, M(x.current));
279
259
  }, [
280
- M,
260
+ w,
281
261
  R,
282
262
  d,
283
263
  f
284
264
  ]);
285
- let { session: z } = w({
286
- bridge: c,
287
- request: F.current,
265
+ let { session: z } = T({
266
+ bridge: t,
267
+ request: P.current,
288
268
  killOnUnmount: p
289
269
  });
290
- return n(() => {
291
- if (!M) return;
270
+ return r(() => {
271
+ if (!w) return;
292
272
  let e = b.current, t = C.current;
293
273
  if (!e || !t || !z) return;
294
- j(S.current);
295
- let n = window.requestAnimationFrame(() => j(S.current)), r = P(e, t, z, {
274
+ M(x.current);
275
+ let n = window.requestAnimationFrame(() => M(x.current)), r = F(e, t, z, {
296
276
  onSessionOpen: I,
297
277
  onSessionExit: L
298
278
  });
299
279
  return () => {
300
280
  window.cancelAnimationFrame(n), r();
301
281
  };
302
- }, [z, M]), n(() => {
303
- M && m && b.current?.focus();
304
- }, [m, M]), /* @__PURE__ */ t("div", {
282
+ }, [z, w]), r(() => {
283
+ w && m && b.current?.focus();
284
+ }, [m, w]), /* @__PURE__ */ n("div", {
305
285
  className: h,
306
286
  style: {
307
287
  position: "relative",
@@ -310,7 +290,7 @@ var c = (e, t, n = {}) => {
310
290
  backgroundColor: typeof R.background == "string" ? R.background : void 0,
311
291
  ...g
312
292
  },
313
- children: /* @__PURE__ */ t("div", {
293
+ children: /* @__PURE__ */ n("div", {
314
294
  ref: y,
315
295
  className: "pstdio-terminal",
316
296
  style: {
@@ -321,6 +301,6 @@ var c = (e, t, n = {}) => {
321
301
  });
322
302
  };
323
303
  //#endregion
324
- export { F as Terminal, c as bindSessionToSink, g as createScriptedTerminalBridge, y as darkTerminalTheme, v as lightTerminalTheme, x as resolveTerminalTheme, b as terminalThemes, w as useTerminalSession };
304
+ export { I as Terminal, l as bindSessionToSink, _ as createScriptedTerminalBridge, b as darkTerminalTheme, y as lightTerminalTheme, S as resolveTerminalTheme, x as terminalThemes, T as useTerminalSession };
325
305
 
326
306
  //# sourceMappingURL=terminal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.js","names":["TerminalSessionAdapter","TerminalSink","write","data","Uint8Array","onInput","handler","onResize","size","cols","rows","BindSessionOptions","onExit","exit","code","signal","onError","error","message","bindSessionToSink","sink","session","options","disposers","Array","push","onData","chunk","resize","length","dispose","pop","TerminalBridge","TerminalSessionAdapter","TerminalSessionError","TerminalSessionExit","ScriptedTerminalStep","data","Uint8Array","delayMs","exit","code","signal","error","ScriptedBridgeOptions","initial","onInput","input","onResize","size","cols","rows","onKill","encoder","TextEncoder","toChunk","encode","wait","ms","Promise","resolve","setTimeout","defaultEcho","replace","SessionEmitter","isExited","emitData","chunk","emitExit","emitError","runStep","emitter","step","undefined","message","playSteps","steps","createScriptedSession","options","NonNullable","dataHandlers","Set","exitHandlers","errorHandlers","exited","startedInitial","handler","session","id","crypto","randomUUID","write","text","TextDecoder","decode","response","resize","kill","onData","add","delete","onExit","onError","createScriptedTerminalBridge","openSession","_request","ITheme","TerminalThemeName","baseTheme","Partial","cursorAccent","selectionForeground","undefined","lightTerminalTheme","background","foreground","cursor","selectionBackground","black","red","green","yellow","blue","magenta","cyan","white","brightBlack","brightRed","brightGreen","brightYellow","brightBlue","brightMagenta","brightCyan","brightWhite","darkTerminalTheme","terminalThemes","Record","light","dark","resolveTerminalTheme","theme","useEffect","useState","TerminalBridge","TerminalSessionAdapter","TerminalSessionError","TerminalSessionExit","TerminalSessionRequest","TerminalSessionStatus","UseTerminalSessionResult","session","status","exit","error","UseTerminalSessionOptions","bridge","request","killOnUnmount","createTerminalSessionRequestKey","JSON","stringify","command","cwd","env","Object","fromEntries","entries","sort","left","right","localeCompare","undefined","cols","rows","readTerminalSessionRequestKey","requestKey","parse","useTerminalSession","t0","$","_c","t1","t2","t3","Symbol","for","state","setState","t4","t5","cancelled","activeSession","terminalState","disposers","requestSnapshot","openSession","then","kill","push","onExit","prev","onError","prev_0","catch","cause","message","Error","String","length","pop","_c","FitAddon","WebLinksAddon","ITheme","Terminal","Xterm","useEffect","useRef","useState","bindSessionToSink","TerminalSink","resolveTerminalTheme","TerminalThemeName","TerminalBridge","TerminalSessionAdapter","TerminalSessionRequest","useTerminalSession","DEFAULT_FONT_FAMILY","DEFAULT_FONT_SIZE","DEFAULT_COLS","DEFAULT_ROWS","createInitialTerminalSessionRequest","request","Partial","cols","rows","createTerminalSink","xterm","Pick","inputHandlers","Set","data","pendingInput","inputDisposable","onData","size","push","handler","write","Uint8Array","onInput","add","length","shift","delete","onResize","disposable","dispose","clear","fitTerminal","fit","resizeSessionToTerminalGeometry","terminal","session","resize","bindTerminalSession","sink","options","TerminalProps","unbind","onExit","onSessionExit","onSessionOpen","id","TerminalSessionCallbackRefs","React","RefObject","bindTerminalSessionWithCallbackRefs","callbackRefs","sessionId","current","exit","bridge","theme","fontFamily","fontSize","killOnUnmount","autoFocus","className","style","CSSProperties","code","signal","props","containerRef","HTMLDivElement","xtermRef","fitRef","sinkRef","ReturnType","terminalReady","setTerminalReady","initialSessionRequestRef","onSessionOpenRef","onSessionExitRef","resolvedTheme","container","measureAnimationFrame","measureTimeout","observer","ResizeObserver","initializationFrame","window","requestAnimationFrame","cursorBlink","convertEol","allowProposedApi","loadAddon","event","uri","ctrlKey","metaKey","open","measure","setTimeout","observe","cancelAnimationFrame","undefined","clearTimeout","disconnect","animationFrame","focus","position","width","height","backgroundColor","background","inset","Xterm","Terminal$1","bindSessionToSink","disposers","session","sink","chunk","data","options","cols","rows","dispose","encoder","toChunk","wait","ms","resolve","defaultEcho","input","runStep","step","emitter","playSteps","steps","createScriptedSession","dataHandlers","exitHandlers","errorHandlers","exited","startedInitial","handler","exit","error","response","onInput","signal","createScriptedTerminalBridge","baseTheme","lightTerminalTheme","darkTerminalTheme","terminalThemes","resolveTerminalTheme","theme","createTerminalSessionRequestKey","request","left","right","readTerminalSessionRequestKey","requestKey","useTerminalSession","$","c","t1","t0","killOnUnmount","t2","t3","state","setState","useState","t4","t5","bridge","cancelled","activeSession","terminalState","requestSnapshot","prev","prev_0","message","cause","useEffect","DEFAULT_FONT_FAMILY","DEFAULT_FONT_SIZE","DEFAULT_COLS","DEFAULT_ROWS","createInitialTerminalSessionRequest","createTerminalSink","inputHandlers","pendingInput","inputDisposable","xterm","disposable","fitTerminal","resizeSessionToTerminalGeometry","terminal","bindTerminalSession","unbind","bindTerminalSessionWithCallbackRefs","callbackRefs","sessionId","Terminal","props","containerRef","useRef","xtermRef","fitRef","sinkRef","terminalReady","setTerminalReady","initialSessionRequestRef","onSessionOpenRef","onSessionOpen","onSessionExitRef","onSessionExit","resolvedTheme","container","measureAnimationFrame","measureTimeout","observer","initializationFrame","fit","FitAddon","WebLinksAddon","event","uri","measure","xterm_0","fontFamily","fontSize","xterm_1","sink_0","animationFrame","autoFocus","style"],"sources":["../src/components/terminal/bind-session.ts","../src/components/terminal/scripted-bridge.ts","../src/components/terminal/terminal-theme.ts","../src/components/terminal/use-terminal-session.ts","../src/components/terminal/terminal.tsx"],"sourcesContent":["import type { TerminalSessionAdapter } from \"./types\";\n\n/**\n * Minimal subset of xterm.js that the binding needs. Tests substitute a fake\n * sink so the wire-up logic can be exercised without a DOM.\n */\nexport interface TerminalSink {\n write(data: string | Uint8Array): void;\n onInput(handler: (data: string) => void): () => void;\n onResize(handler: (size: { cols: number; rows: number }) => void): () => void;\n}\n\nexport interface BindSessionOptions {\n /** Forwarded to the session when the user types in the sink. */\n onInput?: (data: string) => void;\n /** Called once the session exits; useful for surfacing status. */\n onExit?: (exit: { code: number | null; signal: string | null }) => void;\n /** Called on transport errors. */\n onError?: (error: { message: string }) => void;\n}\n\n/**\n * Wires a {@link TerminalSink} (typically xterm.js) to a\n * {@link TerminalSessionAdapter}. Returns a disposer that detaches every\n * subscription it created. The session itself is *not* killed — owning the\n * session lifecycle is the caller's responsibility.\n */\nexport const bindSessionToSink = (\n sink: TerminalSink,\n session: TerminalSessionAdapter,\n options: BindSessionOptions = {},\n) => {\n const disposers: Array<() => void> = [];\n\n disposers.push(session.onData((chunk) => sink.write(chunk)));\n\n disposers.push(\n sink.onInput((data) => {\n session.write(data);\n options.onInput?.(data);\n }),\n );\n\n disposers.push(\n sink.onResize(({ cols, rows }) => {\n session.resize(cols, rows);\n }),\n );\n\n if (options.onExit) disposers.push(session.onExit(options.onExit));\n if (options.onError) disposers.push(session.onError(options.onError));\n\n return () => {\n while (disposers.length > 0) {\n const dispose = disposers.pop();\n try {\n dispose?.();\n } catch {\n // Disposer errors during teardown are intentionally swallowed so a\n // partially-bound session still cleans up the remaining subscriptions.\n }\n }\n };\n};\n","import type { TerminalBridge, TerminalSessionAdapter, TerminalSessionError, TerminalSessionExit } from \"./types\";\n\nexport interface ScriptedTerminalStep {\n /** Bytes the host pushes back to the renderer (utf-8 string is encoded for you). */\n data?: string | Uint8Array;\n /** Milliseconds to wait before delivering this step. */\n delayMs?: number;\n /** Marks the session as exited after this step. */\n exit?: { code: number | null; signal?: string | null };\n /** Delivers a transport error after this step. */\n error?: string;\n}\n\nexport interface ScriptedBridgeOptions {\n /** Initial script delivered after the first data subscriber attaches. */\n initial?: ScriptedTerminalStep[];\n /**\n * Responds to user input. Return additional steps to play, or `undefined`\n * to ignore. Defaults to echoing the input followed by a newline.\n */\n onInput?: (input: string) => ScriptedTerminalStep[] | undefined;\n /** Called whenever the renderer requests a resize. */\n onResize?: (size: { cols: number; rows: number }) => void;\n /** Called once when the renderer kills the session. */\n onKill?: (signal?: string) => void;\n}\n\nconst encoder = new TextEncoder();\n\nconst toChunk = (data: string | Uint8Array) => (typeof data === \"string\" ? encoder.encode(data) : data);\n\nconst wait = (ms: number) => (ms > 0 ? new Promise<void>((resolve) => setTimeout(resolve, ms)) : Promise.resolve());\n\nconst defaultEcho = (input: string): ScriptedTerminalStep[] => [{ data: input.replace(/\\r/g, \"\\r\\n\") }];\n\ninterface SessionEmitter {\n isExited(): boolean;\n emitData(chunk: Uint8Array): void;\n emitExit(exit: TerminalSessionExit): void;\n emitError(error: TerminalSessionError): void;\n}\n\nconst runStep = (emitter: SessionEmitter, step: ScriptedTerminalStep) => {\n if (step.data !== undefined) emitter.emitData(toChunk(step.data));\n if (step.error !== undefined) emitter.emitError({ message: step.error });\n if (step.exit !== undefined) emitter.emitExit({ code: step.exit.code, signal: step.exit.signal ?? null });\n};\n\nconst playSteps = async (emitter: SessionEmitter, steps: ScriptedTerminalStep[]) => {\n for (const step of steps) {\n if (emitter.isExited()) return;\n await wait(step.delayMs ?? 0);\n if (emitter.isExited()) return;\n runStep(emitter, step);\n }\n};\n\nconst createScriptedSession = (\n options: ScriptedBridgeOptions,\n onInput: NonNullable<ScriptedBridgeOptions[\"onInput\"]>,\n) => {\n const dataHandlers = new Set<(chunk: Uint8Array) => void>();\n const exitHandlers = new Set<(exit: TerminalSessionExit) => void>();\n const errorHandlers = new Set<(error: TerminalSessionError) => void>();\n let exited = false;\n let startedInitial = false;\n\n const emitter: SessionEmitter = {\n isExited: () => exited,\n emitData(chunk) {\n for (const handler of dataHandlers) handler(chunk);\n },\n emitExit(exit) {\n if (exited) return;\n exited = true;\n for (const handler of exitHandlers) handler(exit);\n },\n emitError(error) {\n for (const handler of errorHandlers) handler(error);\n },\n };\n\n const session: TerminalSessionAdapter = {\n id: crypto.randomUUID(),\n write(data) {\n if (exited) return;\n const text = typeof data === \"string\" ? data : new TextDecoder().decode(data);\n const response = onInput(text);\n if (response) void playSteps(emitter, response);\n },\n resize(cols, rows) {\n options.onResize?.({ cols, rows });\n },\n kill(signal) {\n if (exited) return;\n options.onKill?.(signal);\n emitter.emitExit({ code: null, signal: signal ?? null });\n },\n onData(handler) {\n dataHandlers.add(handler);\n if (!startedInitial && options.initial) {\n startedInitial = true;\n void playSteps(emitter, options.initial);\n }\n return () => dataHandlers.delete(handler);\n },\n onExit(handler) {\n exitHandlers.add(handler);\n return () => exitHandlers.delete(handler);\n },\n onError(handler) {\n errorHandlers.add(handler);\n return () => errorHandlers.delete(handler);\n },\n };\n\n return { session };\n};\n\n/**\n * Deterministic in-memory bridge. Used by stories and tests to exercise the\n * terminal UI without a real PTY supervisor.\n */\nexport const createScriptedTerminalBridge = (options: ScriptedBridgeOptions = {}): TerminalBridge => {\n const onInput = options.onInput ?? defaultEcho;\n\n return {\n async openSession(_request) {\n const { session } = createScriptedSession(options, onInput);\n return session;\n },\n };\n};\n","import type { ITheme } from \"@xterm/xterm\";\n\n/**\n * xterm theme presets aligned with the workbench `bg.inverted` / `fg.inverted`\n * pairings so the terminal blends with the surrounding chrome without the\n * consuming extension touching xterm directly. Consumers can still pass any\n * `ITheme` they like via the `theme` prop.\n */\nexport type TerminalThemeName = \"light\" | \"dark\";\n\nconst baseTheme: Partial<ITheme> = {\n cursorAccent: \"#000000\",\n selectionForeground: undefined,\n};\n\nexport const lightTerminalTheme: ITheme = {\n ...baseTheme,\n background: \"#f4f4f5\",\n foreground: \"#171717\",\n cursor: \"#171717\",\n selectionBackground: \"#d4d4d8\",\n black: \"#27272a\",\n red: \"#dc2626\",\n green: \"#16a34a\",\n yellow: \"#ca8a04\",\n blue: \"#2563eb\",\n magenta: \"#c026d3\",\n cyan: \"#0891b2\",\n white: \"#e4e4e7\",\n brightBlack: \"#52525b\",\n brightRed: \"#ef4444\",\n brightGreen: \"#22c55e\",\n brightYellow: \"#eab308\",\n brightBlue: \"#3b82f6\",\n brightMagenta: \"#d946ef\",\n brightCyan: \"#06b6d4\",\n brightWhite: \"#fafafa\",\n};\n\nexport const darkTerminalTheme: ITheme = {\n ...baseTheme,\n background: \"#0a0a0a\",\n foreground: \"#fafafa\",\n cursor: \"#fafafa\",\n selectionBackground: \"#3f3f46\",\n black: \"#27272a\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#facc15\",\n blue: \"#60a5fa\",\n magenta: \"#e879f9\",\n cyan: \"#22d3ee\",\n white: \"#e4e4e7\",\n brightBlack: \"#52525b\",\n brightRed: \"#fca5a5\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#f0abfc\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#fafafa\",\n};\n\nexport const terminalThemes: Record<TerminalThemeName, ITheme> = {\n light: lightTerminalTheme,\n dark: darkTerminalTheme,\n};\n\nexport const resolveTerminalTheme = (theme: TerminalThemeName | ITheme | undefined) => {\n if (!theme) return terminalThemes.dark;\n if (typeof theme === \"string\") return terminalThemes[theme];\n return theme;\n};\n","import { useEffect, useState } from \"react\";\nimport type {\n TerminalBridge,\n TerminalSessionAdapter,\n TerminalSessionError,\n TerminalSessionExit,\n TerminalSessionRequest,\n} from \"./types\";\n\nexport type TerminalSessionStatus = \"idle\" | \"opening\" | \"open\" | \"exited\" | \"error\";\n\nexport interface UseTerminalSessionResult {\n session: TerminalSessionAdapter | null;\n status: TerminalSessionStatus;\n exit: TerminalSessionExit | null;\n error: TerminalSessionError | null;\n}\n\nexport interface UseTerminalSessionOptions {\n bridge: TerminalBridge | null;\n request: TerminalSessionRequest;\n /** Set to false to keep the session alive when the hook unmounts. */\n killOnUnmount?: boolean;\n}\n\nexport const createTerminalSessionRequestKey = (request: TerminalSessionRequest) =>\n JSON.stringify({\n command: request.command,\n cwd: request.cwd,\n env: request.env\n ? Object.fromEntries(Object.entries(request.env).sort(([left], [right]) => left.localeCompare(right)))\n : undefined,\n cols: request.cols,\n rows: request.rows,\n });\n\nconst readTerminalSessionRequestKey = (requestKey: string): TerminalSessionRequest => JSON.parse(requestKey);\n\n/**\n * Opens a terminal session via the provided bridge and surfaces its lifecycle\n * for the renderer. The session is killed on unmount unless explicitly opted\n * out; switching bridges or request contents triggers a fresh open.\n */\nexport const useTerminalSession = ({ bridge, request, killOnUnmount = true }: UseTerminalSessionOptions) => {\n const requestKey = createTerminalSessionRequestKey(request);\n const [state, setState] = useState<UseTerminalSessionResult>({\n session: null,\n status: \"idle\",\n exit: null,\n error: null,\n });\n\n useEffect(() => {\n if (!bridge) {\n setState({ session: null, status: \"idle\", exit: null, error: null });\n return;\n }\n\n let cancelled = false;\n let activeSession: TerminalSessionAdapter | null = null;\n let terminalState: TerminalSessionStatus = \"opening\";\n const disposers: Array<() => void> = [];\n\n setState({ session: null, status: \"opening\", exit: null, error: null });\n const requestSnapshot = readTerminalSessionRequestKey(requestKey);\n\n bridge\n .openSession(requestSnapshot)\n .then((session) => {\n if (cancelled) {\n if (killOnUnmount) void session.kill();\n return;\n }\n activeSession = session;\n disposers.push(\n session.onExit((exit) => {\n terminalState = \"exited\";\n setState((prev) => ({ ...prev, status: \"exited\", exit }));\n }),\n session.onError((error) => {\n terminalState = \"error\";\n setState((prev) => ({ ...prev, status: \"error\", error }));\n }),\n );\n terminalState = \"open\";\n setState({ session, status: \"open\", exit: null, error: null });\n })\n .catch((cause: unknown) => {\n if (cancelled) return;\n const message = cause instanceof Error ? cause.message : String(cause);\n terminalState = \"error\";\n setState({ session: null, status: \"error\", exit: null, error: { message } });\n });\n\n return () => {\n cancelled = true;\n while (disposers.length > 0) disposers.pop()?.();\n if (killOnUnmount && activeSession && terminalState !== \"exited\") void activeSession.kill();\n };\n }, [bridge, requestKey, killOnUnmount]);\n\n return state;\n};\n","import { FitAddon } from \"@xterm/addon-fit\";\nimport { WebLinksAddon } from \"@xterm/addon-web-links\";\nimport type { ITheme } from \"@xterm/xterm\";\nimport { Terminal as Xterm } from \"@xterm/xterm\";\nimport \"@xterm/xterm/css/xterm.css\";\nimport \"./terminal.css\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { bindSessionToSink, type TerminalSink } from \"./bind-session\";\nimport { resolveTerminalTheme, type TerminalThemeName } from \"./terminal-theme\";\nimport type { TerminalBridge, TerminalSessionAdapter, TerminalSessionRequest } from \"./types\";\nimport { useTerminalSession } from \"./use-terminal-session\";\n\nconst DEFAULT_FONT_FAMILY = '\"JetBrains Mono\", \"Fira Code\", Menlo, Consolas, monospace';\nconst DEFAULT_FONT_SIZE = 13;\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport const createInitialTerminalSessionRequest = (\n request?: Partial<TerminalSessionRequest>,\n): TerminalSessionRequest => ({\n ...request,\n cols: request?.cols ?? DEFAULT_COLS,\n rows: request?.rows ?? DEFAULT_ROWS,\n});\n\nexport const createTerminalSink = (xterm: Pick<Xterm, \"write\" | \"onData\" | \"onResize\">) => {\n const inputHandlers = new Set<(data: string) => void>();\n const pendingInput: string[] = [];\n const inputDisposable = xterm.onData((data) => {\n if (inputHandlers.size === 0) {\n pendingInput.push(data);\n return;\n }\n for (const handler of inputHandlers) handler(data);\n });\n\n return {\n write(data: string | Uint8Array) {\n xterm.write(data);\n },\n onInput(handler: (data: string) => void) {\n inputHandlers.add(handler);\n while (pendingInput.length > 0) handler(pendingInput.shift() as string);\n return () => inputHandlers.delete(handler);\n },\n onResize(handler: (size: { cols: number; rows: number }) => void) {\n const disposable = xterm.onResize(handler);\n return () => disposable.dispose();\n },\n dispose() {\n inputDisposable.dispose();\n inputHandlers.clear();\n pendingInput.length = 0;\n },\n } satisfies TerminalSink & { dispose(): void };\n};\n\nconst fitTerminal = (fit: FitAddon | null) => {\n try {\n fit?.fit();\n } catch {\n // fit() throws if the container has zero size (e.g. hidden via CSS).\n }\n};\n\nexport const resizeSessionToTerminalGeometry = (\n terminal: Pick<Xterm, \"cols\" | \"rows\">,\n session: Pick<TerminalSessionAdapter, \"resize\">,\n) => {\n session.resize(terminal.cols, terminal.rows);\n};\n\nexport const bindTerminalSession = (\n terminal: Pick<Xterm, \"cols\" | \"rows\">,\n sink: TerminalSink,\n session: TerminalSessionAdapter,\n options: Pick<TerminalProps, \"onSessionOpen\" | \"onSessionExit\">,\n) => {\n const unbind = bindSessionToSink(sink, session, {\n onExit: options.onSessionExit,\n });\n resizeSessionToTerminalGeometry(terminal, session);\n options.onSessionOpen?.(session.id);\n return unbind;\n};\n\nexport interface TerminalSessionCallbackRefs {\n onSessionOpen: React.RefObject<TerminalProps[\"onSessionOpen\"]>;\n onSessionExit: React.RefObject<TerminalProps[\"onSessionExit\"]>;\n}\n\nexport const bindTerminalSessionWithCallbackRefs = (\n terminal: Pick<Xterm, \"cols\" | \"rows\">,\n sink: TerminalSink,\n session: TerminalSessionAdapter,\n callbackRefs: TerminalSessionCallbackRefs,\n) =>\n bindTerminalSession(terminal, sink, session, {\n onSessionOpen: (sessionId) => callbackRefs.onSessionOpen.current?.(sessionId),\n onSessionExit: (exit) => callbackRefs.onSessionExit.current?.(exit),\n });\n\nexport interface TerminalProps {\n /** Bridge adapter the component opens its session through. */\n bridge: TerminalBridge;\n /**\n * Optional initial session request overrides. `cols`/`rows` default to\n * 80x24; container resizes are forwarded after the session opens.\n */\n request?: Partial<TerminalSessionRequest>;\n /** Theme preset name or full xterm theme. */\n theme?: TerminalThemeName | ITheme;\n /** Monospace font family. */\n fontFamily?: string;\n fontSize?: number;\n /** Whether to kill the session when the component unmounts. Defaults to true. */\n killOnUnmount?: boolean;\n /** Focus the terminal while it is the active surface. Defaults to true. */\n autoFocus?: boolean;\n /** Forwarded to the container element. */\n className?: string;\n style?: React.CSSProperties;\n /** Called once the session is open; useful for imperative refs. */\n onSessionOpen?: (sessionId: string) => void;\n /** Called once the session exits. */\n onSessionExit?: (exit: { code: number | null; signal: string | null }) => void;\n}\n\n/**\n * High-level terminal component. Mounts xterm.js inside a `<div>` and binds it\n * to the session opened from `bridge.openSession(...)`. Resize is driven by\n * `ResizeObserver` so the terminal fills its container and the host PTY\n * geometry stays in sync.\n */\nexport const Terminal = (props: TerminalProps) => {\n const {\n bridge,\n request,\n theme,\n fontFamily = DEFAULT_FONT_FAMILY,\n fontSize = DEFAULT_FONT_SIZE,\n killOnUnmount = true,\n autoFocus = true,\n className,\n style,\n onSessionOpen,\n onSessionExit,\n } = props;\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const xtermRef = useRef<Xterm | null>(null);\n const fitRef = useRef<FitAddon | null>(null);\n const sinkRef = useRef<ReturnType<typeof createTerminalSink> | null>(null);\n const [terminalReady, setTerminalReady] = useState(false);\n const initialSessionRequestRef = useRef<TerminalSessionRequest | null>(null);\n const onSessionOpenRef = useRef(onSessionOpen);\n const onSessionExitRef = useRef(onSessionExit);\n\n onSessionOpenRef.current = onSessionOpen;\n onSessionExitRef.current = onSessionExit;\n\n if (!initialSessionRequestRef.current) {\n initialSessionRequestRef.current = createInitialTerminalSessionRequest(request);\n }\n\n const resolvedTheme = resolveTerminalTheme(theme);\n\n // Mount xterm once on the container. Theme, font, and size updates flow\n // through the dedicated options-sync effect below to avoid a full remount on\n // every prop change.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n let xterm: Xterm | undefined;\n let sink: ReturnType<typeof createTerminalSink> | undefined;\n let measureAnimationFrame: number | undefined;\n let measureTimeout: number | undefined;\n let observer: ResizeObserver | undefined;\n\n // Deferring construction skips React Strict Mode's disposable probe mount.\n // xterm schedules internal viewport work during construction that otherwise\n // runs after the probe instance has already been disposed.\n const initializationFrame = window.requestAnimationFrame(() => {\n xterm = new Xterm({\n cols: DEFAULT_COLS,\n rows: DEFAULT_ROWS,\n cursorBlink: true,\n convertEol: true,\n allowProposedApi: true,\n });\n const fit = new FitAddon();\n xterm.loadAddon(fit);\n xterm.loadAddon(\n new WebLinksAddon((event, uri) => {\n if (event.ctrlKey || event.metaKey) window.open(uri, \"_blank\", \"noopener,noreferrer\");\n }),\n );\n xterm.open(container);\n sink = createTerminalSink(xterm);\n\n xtermRef.current = xterm;\n fitRef.current = fit;\n sinkRef.current = sink;\n\n const measure = () => fitTerminal(fit);\n measure();\n measureAnimationFrame = window.requestAnimationFrame(measure);\n measureTimeout = window.setTimeout(measure, 50);\n observer = new ResizeObserver(measure);\n observer.observe(container);\n setTerminalReady(true);\n });\n\n return () => {\n window.cancelAnimationFrame(initializationFrame);\n if (measureAnimationFrame !== undefined) window.cancelAnimationFrame(measureAnimationFrame);\n if (measureTimeout !== undefined) window.clearTimeout(measureTimeout);\n observer?.disconnect();\n sink?.dispose();\n xterm?.dispose();\n xtermRef.current = null;\n fitRef.current = null;\n sinkRef.current = null;\n };\n }, []);\n\n useEffect(() => {\n if (!terminalReady) return;\n const xterm = xtermRef.current;\n if (!xterm) return;\n xterm.options.theme = resolvedTheme;\n xterm.options.fontFamily = fontFamily;\n xterm.options.fontSize = fontSize;\n fitTerminal(fitRef.current);\n }, [terminalReady, resolvedTheme, fontFamily, fontSize]);\n\n const { session } = useTerminalSession({ bridge, request: initialSessionRequestRef.current, killOnUnmount });\n\n useEffect(() => {\n if (!terminalReady) return;\n const xterm = xtermRef.current;\n const sink = sinkRef.current;\n if (!xterm || !sink || !session) return;\n fitTerminal(fitRef.current);\n const animationFrame = window.requestAnimationFrame(() => fitTerminal(fitRef.current));\n const unbind = bindTerminalSessionWithCallbackRefs(xterm, sink, session, {\n onSessionOpen: onSessionOpenRef,\n onSessionExit: onSessionExitRef,\n });\n return () => {\n window.cancelAnimationFrame(animationFrame);\n unbind();\n };\n }, [session, terminalReady]);\n\n useEffect(() => {\n if (terminalReady && autoFocus) xtermRef.current?.focus();\n }, [autoFocus, terminalReady]);\n\n // The mount element fills its box absolutely so xterm sizes to the panel\n // rather than growing it: inside a scrollable host, a self-sized terminal\n // would define its own height and never fit, leaving the host to scroll it.\n return (\n <div\n className={className}\n style={{\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n backgroundColor: typeof resolvedTheme.background === \"string\" ? resolvedTheme.background : undefined,\n ...style,\n }}\n >\n <div ref={containerRef} className=\"pstdio-terminal\" style={{ position: \"absolute\", inset: 0 }} />\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"terminal.js","names":["TerminalSessionAdapter","TerminalSink","write","data","Uint8Array","onInput","handler","onResize","size","cols","rows","BindSessionOptions","onExit","exit","code","signal","onError","error","message","bindSessionToSink","sink","session","options","disposers","Array","push","onData","chunk","resize","length","dispose","pop","TerminalBridge","TerminalSessionAdapter","TerminalSessionError","TerminalSessionExit","ScriptedTerminalStep","data","Uint8Array","delayMs","exit","code","signal","error","ScriptedBridgeOptions","initial","onInput","input","onResize","size","cols","rows","onKill","encoder","TextEncoder","toChunk","encode","wait","ms","Promise","resolve","setTimeout","defaultEcho","replace","SessionEmitter","isExited","emitData","chunk","emitExit","emitError","runStep","emitter","step","undefined","message","playSteps","steps","createScriptedSession","options","NonNullable","dataHandlers","Set","exitHandlers","errorHandlers","exited","startedInitial","handler","session","id","crypto","randomUUID","write","text","TextDecoder","decode","response","resize","kill","onData","add","delete","onExit","onError","createScriptedTerminalBridge","openSession","_request","ITheme","psTheme","TerminalThemeName","createTerminalTheme","preset","color","name","token","background","foreground","cursor","cursorAccent","selectionBackground","selectionForeground","undefined","black","red","green","yellow","blue","magenta","cyan","white","brightBlack","brightRed","brightGreen","brightYellow","brightBlue","brightMagenta","brightCyan","brightWhite","lightTerminalTheme","darkTerminalTheme","terminalThemes","Record","light","dark","resolveTerminalTheme","theme","psTheme","useEffect","useState","TerminalBridge","TerminalSessionAdapter","TerminalSessionError","TerminalSessionExit","TerminalSessionRequest","TerminalSessionStatus","UseTerminalSessionResult","session","status","exit","error","UseTerminalSessionOptions","bridge","request","killOnUnmount","createTerminalSessionRequestKey","JSON","stringify","command","cwd","env","Object","fromEntries","entries","sort","left","right","localeCompare","undefined","cols","rows","readTerminalSessionRequestKey","requestKey","parse","useTerminalSession","t0","$","_c","t1","t2","t3","Symbol","for","state","setState","t4","t5","cancelled","activeSession","terminalState","disposers","requestSnapshot","openSession","then","kill","push","onExit","prev","onError","prev_0","catch","cause","message","Error","String","length","pop","_c","FitAddon","WebLinksAddon","ITheme","Terminal","Xterm","useEffect","useRef","useState","bindSessionToSink","TerminalSink","resolveTerminalTheme","TerminalThemeName","TerminalBridge","TerminalSessionAdapter","TerminalSessionRequest","useTerminalSession","DEFAULT_FONT_FAMILY","DEFAULT_FONT_SIZE","DEFAULT_COLS","DEFAULT_ROWS","createInitialTerminalSessionRequest","request","Partial","cols","rows","createTerminalSink","xterm","Pick","inputHandlers","Set","data","pendingInput","inputDisposable","onData","size","push","handler","write","Uint8Array","onInput","add","length","shift","delete","onResize","disposable","dispose","clear","fitTerminal","fit","resizeSessionToTerminalGeometry","terminal","session","resize","bindTerminalSession","sink","options","TerminalProps","unbind","onExit","onSessionExit","onSessionOpen","id","TerminalSessionCallbackRefs","React","RefObject","bindTerminalSessionWithCallbackRefs","callbackRefs","sessionId","current","exit","bridge","theme","fontFamily","fontSize","killOnUnmount","autoFocus","className","style","CSSProperties","code","signal","props","containerRef","HTMLDivElement","xtermRef","fitRef","sinkRef","ReturnType","terminalReady","setTerminalReady","initialSessionRequestRef","onSessionOpenRef","onSessionExitRef","resolvedTheme","container","measureAnimationFrame","measureTimeout","observer","ResizeObserver","initializationFrame","window","requestAnimationFrame","cursorBlink","convertEol","allowProposedApi","loadAddon","event","uri","ctrlKey","metaKey","open","measure","setTimeout","observe","cancelAnimationFrame","undefined","clearTimeout","disconnect","animationFrame","focus","position","width","height","backgroundColor","background","inset","Xterm","theme_default","Terminal$1","bindSessionToSink","disposers","session","sink","chunk","data","options","cols","rows","dispose","encoder","toChunk","wait","ms","resolve","defaultEcho","input","runStep","step","emitter","playSteps","steps","createScriptedSession","dataHandlers","exitHandlers","errorHandlers","exited","startedInitial","handler","exit","error","response","onInput","signal","createScriptedTerminalBridge","createTerminalTheme","color","preset","name","lightTerminalTheme","darkTerminalTheme","terminalThemes","resolveTerminalTheme","theme","createTerminalSessionRequestKey","request","left","right","readTerminalSessionRequestKey","requestKey","useTerminalSession","$","c","t1","t0","killOnUnmount","t2","t3","state","setState","useState","t4","t5","bridge","cancelled","activeSession","terminalState","requestSnapshot","prev","prev_0","message","cause","useEffect","DEFAULT_FONT_FAMILY","DEFAULT_FONT_SIZE","DEFAULT_COLS","DEFAULT_ROWS","createInitialTerminalSessionRequest","createTerminalSink","inputHandlers","pendingInput","inputDisposable","xterm","disposable","fitTerminal","resizeSessionToTerminalGeometry","terminal","bindTerminalSession","unbind","bindTerminalSessionWithCallbackRefs","callbackRefs","sessionId","Terminal","props","containerRef","useRef","xtermRef","fitRef","sinkRef","terminalReady","setTerminalReady","initialSessionRequestRef","onSessionOpenRef","onSessionOpen","onSessionExitRef","onSessionExit","resolvedTheme","container","measureAnimationFrame","measureTimeout","observer","initializationFrame","fit","FitAddon","WebLinksAddon","event","uri","measure","xterm_0","fontFamily","fontSize","xterm_1","sink_0","animationFrame","autoFocus","style"],"sources":["../src/components/terminal/bind-session.ts","../src/components/terminal/scripted-bridge.ts","../src/components/terminal/terminal-theme.ts","../src/components/terminal/use-terminal-session.ts","../src/components/terminal/terminal.tsx"],"sourcesContent":["import type { TerminalSessionAdapter } from \"./types\";\n\n/**\n * Minimal subset of xterm.js that the binding needs. Tests substitute a fake\n * sink so the wire-up logic can be exercised without a DOM.\n */\nexport interface TerminalSink {\n write(data: string | Uint8Array): void;\n onInput(handler: (data: string) => void): () => void;\n onResize(handler: (size: { cols: number; rows: number }) => void): () => void;\n}\n\nexport interface BindSessionOptions {\n /** Forwarded to the session when the user types in the sink. */\n onInput?: (data: string) => void;\n /** Called once the session exits; useful for surfacing status. */\n onExit?: (exit: { code: number | null; signal: string | null }) => void;\n /** Called on transport errors. */\n onError?: (error: { message: string }) => void;\n}\n\n/**\n * Wires a {@link TerminalSink} (typically xterm.js) to a\n * {@link TerminalSessionAdapter}. Returns a disposer that detaches every\n * subscription it created. The session itself is *not* killed — owning the\n * session lifecycle is the caller's responsibility.\n */\nexport const bindSessionToSink = (\n sink: TerminalSink,\n session: TerminalSessionAdapter,\n options: BindSessionOptions = {},\n) => {\n const disposers: Array<() => void> = [];\n\n disposers.push(session.onData((chunk) => sink.write(chunk)));\n\n disposers.push(\n sink.onInput((data) => {\n session.write(data);\n options.onInput?.(data);\n }),\n );\n\n disposers.push(\n sink.onResize(({ cols, rows }) => {\n session.resize(cols, rows);\n }),\n );\n\n if (options.onExit) disposers.push(session.onExit(options.onExit));\n if (options.onError) disposers.push(session.onError(options.onError));\n\n return () => {\n while (disposers.length > 0) {\n const dispose = disposers.pop();\n try {\n dispose?.();\n } catch {\n // Disposer errors during teardown are intentionally swallowed so a\n // partially-bound session still cleans up the remaining subscriptions.\n }\n }\n };\n};\n","import type { TerminalBridge, TerminalSessionAdapter, TerminalSessionError, TerminalSessionExit } from \"./types\";\n\nexport interface ScriptedTerminalStep {\n /** Bytes the host pushes back to the renderer (utf-8 string is encoded for you). */\n data?: string | Uint8Array;\n /** Milliseconds to wait before delivering this step. */\n delayMs?: number;\n /** Marks the session as exited after this step. */\n exit?: { code: number | null; signal?: string | null };\n /** Delivers a transport error after this step. */\n error?: string;\n}\n\nexport interface ScriptedBridgeOptions {\n /** Initial script delivered after the first data subscriber attaches. */\n initial?: ScriptedTerminalStep[];\n /**\n * Responds to user input. Return additional steps to play, or `undefined`\n * to ignore. Defaults to echoing the input followed by a newline.\n */\n onInput?: (input: string) => ScriptedTerminalStep[] | undefined;\n /** Called whenever the renderer requests a resize. */\n onResize?: (size: { cols: number; rows: number }) => void;\n /** Called once when the renderer kills the session. */\n onKill?: (signal?: string) => void;\n}\n\nconst encoder = new TextEncoder();\n\nconst toChunk = (data: string | Uint8Array) => (typeof data === \"string\" ? encoder.encode(data) : data);\n\nconst wait = (ms: number) => (ms > 0 ? new Promise<void>((resolve) => setTimeout(resolve, ms)) : Promise.resolve());\n\nconst defaultEcho = (input: string): ScriptedTerminalStep[] => [{ data: input.replace(/\\r/g, \"\\r\\n\") }];\n\ninterface SessionEmitter {\n isExited(): boolean;\n emitData(chunk: Uint8Array): void;\n emitExit(exit: TerminalSessionExit): void;\n emitError(error: TerminalSessionError): void;\n}\n\nconst runStep = (emitter: SessionEmitter, step: ScriptedTerminalStep) => {\n if (step.data !== undefined) emitter.emitData(toChunk(step.data));\n if (step.error !== undefined) emitter.emitError({ message: step.error });\n if (step.exit !== undefined) emitter.emitExit({ code: step.exit.code, signal: step.exit.signal ?? null });\n};\n\nconst playSteps = async (emitter: SessionEmitter, steps: ScriptedTerminalStep[]) => {\n for (const step of steps) {\n if (emitter.isExited()) return;\n await wait(step.delayMs ?? 0);\n if (emitter.isExited()) return;\n runStep(emitter, step);\n }\n};\n\nconst createScriptedSession = (\n options: ScriptedBridgeOptions,\n onInput: NonNullable<ScriptedBridgeOptions[\"onInput\"]>,\n) => {\n const dataHandlers = new Set<(chunk: Uint8Array) => void>();\n const exitHandlers = new Set<(exit: TerminalSessionExit) => void>();\n const errorHandlers = new Set<(error: TerminalSessionError) => void>();\n let exited = false;\n let startedInitial = false;\n\n const emitter: SessionEmitter = {\n isExited: () => exited,\n emitData(chunk) {\n for (const handler of dataHandlers) handler(chunk);\n },\n emitExit(exit) {\n if (exited) return;\n exited = true;\n for (const handler of exitHandlers) handler(exit);\n },\n emitError(error) {\n for (const handler of errorHandlers) handler(error);\n },\n };\n\n const session: TerminalSessionAdapter = {\n id: crypto.randomUUID(),\n write(data) {\n if (exited) return;\n const text = typeof data === \"string\" ? data : new TextDecoder().decode(data);\n const response = onInput(text);\n if (response) void playSteps(emitter, response);\n },\n resize(cols, rows) {\n options.onResize?.({ cols, rows });\n },\n kill(signal) {\n if (exited) return;\n options.onKill?.(signal);\n emitter.emitExit({ code: null, signal: signal ?? null });\n },\n onData(handler) {\n dataHandlers.add(handler);\n if (!startedInitial && options.initial) {\n startedInitial = true;\n void playSteps(emitter, options.initial);\n }\n return () => dataHandlers.delete(handler);\n },\n onExit(handler) {\n exitHandlers.add(handler);\n return () => exitHandlers.delete(handler);\n },\n onError(handler) {\n errorHandlers.add(handler);\n return () => errorHandlers.delete(handler);\n },\n };\n\n return { session };\n};\n\n/**\n * Deterministic in-memory bridge. Used by stories and tests to exercise the\n * terminal UI without a real PTY supervisor.\n */\nexport const createScriptedTerminalBridge = (options: ScriptedBridgeOptions = {}): TerminalBridge => {\n const onInput = options.onInput ?? defaultEcho;\n\n return {\n async openSession(_request) {\n const { session } = createScriptedSession(options, onInput);\n return session;\n },\n };\n};\n","import type { ITheme } from \"@xterm/xterm\";\nimport psTheme from \"../../theme/theme\";\n\n/**\n * xterm theme presets built from the `colors.terminal.<preset>` tokens so the\n * terminal blends with the surrounding chrome without the consuming extension\n * touching xterm directly. Consumers can still pass any `ITheme` they like via\n * the `theme` prop.\n */\nexport type TerminalThemeName = \"light\" | \"dark\";\n\nconst createTerminalTheme = (preset: TerminalThemeName) => {\n // xterm parses color strings itself, so resolve raw token values instead of CSS variables.\n const color = (name: string) => psTheme.token(`colors.terminal.${preset}.${name}`);\n\n return {\n background: color(\"background\"),\n foreground: color(\"foreground\"),\n cursor: color(\"cursor\"),\n cursorAccent: color(\"cursorAccent\"),\n selectionBackground: color(\"selectionBackground\"),\n selectionForeground: undefined,\n black: color(\"black\"),\n red: color(\"red\"),\n green: color(\"green\"),\n yellow: color(\"yellow\"),\n blue: color(\"blue\"),\n magenta: color(\"magenta\"),\n cyan: color(\"cyan\"),\n white: color(\"white\"),\n brightBlack: color(\"brightBlack\"),\n brightRed: color(\"brightRed\"),\n brightGreen: color(\"brightGreen\"),\n brightYellow: color(\"brightYellow\"),\n brightBlue: color(\"brightBlue\"),\n brightMagenta: color(\"brightMagenta\"),\n brightCyan: color(\"brightCyan\"),\n brightWhite: color(\"brightWhite\"),\n };\n};\n\nexport const lightTerminalTheme: ITheme = createTerminalTheme(\"light\");\n\nexport const darkTerminalTheme: ITheme = createTerminalTheme(\"dark\");\n\nexport const terminalThemes: Record<TerminalThemeName, ITheme> = {\n light: lightTerminalTheme,\n dark: darkTerminalTheme,\n};\n\nexport const resolveTerminalTheme = (theme: TerminalThemeName | ITheme | undefined) => {\n if (!theme) return terminalThemes.dark;\n if (typeof theme === \"string\") return terminalThemes[theme];\n return theme;\n};\n","import { useEffect, useState } from \"react\";\nimport type {\n TerminalBridge,\n TerminalSessionAdapter,\n TerminalSessionError,\n TerminalSessionExit,\n TerminalSessionRequest,\n} from \"./types\";\n\nexport type TerminalSessionStatus = \"idle\" | \"opening\" | \"open\" | \"exited\" | \"error\";\n\nexport interface UseTerminalSessionResult {\n session: TerminalSessionAdapter | null;\n status: TerminalSessionStatus;\n exit: TerminalSessionExit | null;\n error: TerminalSessionError | null;\n}\n\nexport interface UseTerminalSessionOptions {\n bridge: TerminalBridge | null;\n request: TerminalSessionRequest;\n /** Set to false to keep the session alive when the hook unmounts. */\n killOnUnmount?: boolean;\n}\n\nexport const createTerminalSessionRequestKey = (request: TerminalSessionRequest) =>\n JSON.stringify({\n command: request.command,\n cwd: request.cwd,\n env: request.env\n ? Object.fromEntries(Object.entries(request.env).sort(([left], [right]) => left.localeCompare(right)))\n : undefined,\n cols: request.cols,\n rows: request.rows,\n });\n\nconst readTerminalSessionRequestKey = (requestKey: string): TerminalSessionRequest => JSON.parse(requestKey);\n\n/**\n * Opens a terminal session via the provided bridge and surfaces its lifecycle\n * for the renderer. The session is killed on unmount unless explicitly opted\n * out; switching bridges or request contents triggers a fresh open.\n */\nexport const useTerminalSession = ({ bridge, request, killOnUnmount = true }: UseTerminalSessionOptions) => {\n const requestKey = createTerminalSessionRequestKey(request);\n const [state, setState] = useState<UseTerminalSessionResult>({\n session: null,\n status: \"idle\",\n exit: null,\n error: null,\n });\n\n useEffect(() => {\n if (!bridge) {\n setState({ session: null, status: \"idle\", exit: null, error: null });\n return;\n }\n\n let cancelled = false;\n let activeSession: TerminalSessionAdapter | null = null;\n let terminalState: TerminalSessionStatus = \"opening\";\n const disposers: Array<() => void> = [];\n\n setState({ session: null, status: \"opening\", exit: null, error: null });\n const requestSnapshot = readTerminalSessionRequestKey(requestKey);\n\n bridge\n .openSession(requestSnapshot)\n .then((session) => {\n if (cancelled) {\n if (killOnUnmount) void session.kill();\n return;\n }\n activeSession = session;\n disposers.push(\n session.onExit((exit) => {\n terminalState = \"exited\";\n setState((prev) => ({ ...prev, status: \"exited\", exit }));\n }),\n session.onError((error) => {\n terminalState = \"error\";\n setState((prev) => ({ ...prev, status: \"error\", error }));\n }),\n );\n terminalState = \"open\";\n setState({ session, status: \"open\", exit: null, error: null });\n })\n .catch((cause: unknown) => {\n if (cancelled) return;\n const message = cause instanceof Error ? cause.message : String(cause);\n terminalState = \"error\";\n setState({ session: null, status: \"error\", exit: null, error: { message } });\n });\n\n return () => {\n cancelled = true;\n while (disposers.length > 0) disposers.pop()?.();\n if (killOnUnmount && activeSession && terminalState !== \"exited\") void activeSession.kill();\n };\n }, [bridge, requestKey, killOnUnmount]);\n\n return state;\n};\n","import { FitAddon } from \"@xterm/addon-fit\";\nimport { WebLinksAddon } from \"@xterm/addon-web-links\";\nimport type { ITheme } from \"@xterm/xterm\";\nimport { Terminal as Xterm } from \"@xterm/xterm\";\nimport \"@xterm/xterm/css/xterm.css\";\nimport \"./terminal.css\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { bindSessionToSink, type TerminalSink } from \"./bind-session\";\nimport { resolveTerminalTheme, type TerminalThemeName } from \"./terminal-theme\";\nimport type { TerminalBridge, TerminalSessionAdapter, TerminalSessionRequest } from \"./types\";\nimport { useTerminalSession } from \"./use-terminal-session\";\n\nconst DEFAULT_FONT_FAMILY = '\"JetBrains Mono\", \"Fira Code\", Menlo, Consolas, monospace';\nconst DEFAULT_FONT_SIZE = 13;\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport const createInitialTerminalSessionRequest = (\n request?: Partial<TerminalSessionRequest>,\n): TerminalSessionRequest => ({\n ...request,\n cols: request?.cols ?? DEFAULT_COLS,\n rows: request?.rows ?? DEFAULT_ROWS,\n});\n\nexport const createTerminalSink = (xterm: Pick<Xterm, \"write\" | \"onData\" | \"onResize\">) => {\n const inputHandlers = new Set<(data: string) => void>();\n const pendingInput: string[] = [];\n const inputDisposable = xterm.onData((data) => {\n if (inputHandlers.size === 0) {\n pendingInput.push(data);\n return;\n }\n for (const handler of inputHandlers) handler(data);\n });\n\n return {\n write(data: string | Uint8Array) {\n xterm.write(data);\n },\n onInput(handler: (data: string) => void) {\n inputHandlers.add(handler);\n while (pendingInput.length > 0) handler(pendingInput.shift() as string);\n return () => inputHandlers.delete(handler);\n },\n onResize(handler: (size: { cols: number; rows: number }) => void) {\n const disposable = xterm.onResize(handler);\n return () => disposable.dispose();\n },\n dispose() {\n inputDisposable.dispose();\n inputHandlers.clear();\n pendingInput.length = 0;\n },\n } satisfies TerminalSink & { dispose(): void };\n};\n\nconst fitTerminal = (fit: FitAddon | null) => {\n try {\n fit?.fit();\n } catch {\n // fit() throws if the container has zero size (e.g. hidden via CSS).\n }\n};\n\nexport const resizeSessionToTerminalGeometry = (\n terminal: Pick<Xterm, \"cols\" | \"rows\">,\n session: Pick<TerminalSessionAdapter, \"resize\">,\n) => {\n session.resize(terminal.cols, terminal.rows);\n};\n\nexport const bindTerminalSession = (\n terminal: Pick<Xterm, \"cols\" | \"rows\">,\n sink: TerminalSink,\n session: TerminalSessionAdapter,\n options: Pick<TerminalProps, \"onSessionOpen\" | \"onSessionExit\">,\n) => {\n const unbind = bindSessionToSink(sink, session, {\n onExit: options.onSessionExit,\n });\n resizeSessionToTerminalGeometry(terminal, session);\n options.onSessionOpen?.(session.id);\n return unbind;\n};\n\nexport interface TerminalSessionCallbackRefs {\n onSessionOpen: React.RefObject<TerminalProps[\"onSessionOpen\"]>;\n onSessionExit: React.RefObject<TerminalProps[\"onSessionExit\"]>;\n}\n\nexport const bindTerminalSessionWithCallbackRefs = (\n terminal: Pick<Xterm, \"cols\" | \"rows\">,\n sink: TerminalSink,\n session: TerminalSessionAdapter,\n callbackRefs: TerminalSessionCallbackRefs,\n) =>\n bindTerminalSession(terminal, sink, session, {\n onSessionOpen: (sessionId) => callbackRefs.onSessionOpen.current?.(sessionId),\n onSessionExit: (exit) => callbackRefs.onSessionExit.current?.(exit),\n });\n\nexport interface TerminalProps {\n /** Bridge adapter the component opens its session through. */\n bridge: TerminalBridge;\n /**\n * Optional initial session request overrides. `cols`/`rows` default to\n * 80x24; container resizes are forwarded after the session opens.\n */\n request?: Partial<TerminalSessionRequest>;\n /** Theme preset name or full xterm theme. */\n theme?: TerminalThemeName | ITheme;\n /** Monospace font family. */\n fontFamily?: string;\n fontSize?: number;\n /** Whether to kill the session when the component unmounts. Defaults to true. */\n killOnUnmount?: boolean;\n /** Focus the terminal while it is the active surface. Defaults to true. */\n autoFocus?: boolean;\n /** Forwarded to the container element. */\n className?: string;\n style?: React.CSSProperties;\n /** Called once the session is open; useful for imperative refs. */\n onSessionOpen?: (sessionId: string) => void;\n /** Called once the session exits. */\n onSessionExit?: (exit: { code: number | null; signal: string | null }) => void;\n}\n\n/**\n * High-level terminal component. Mounts xterm.js inside a `<div>` and binds it\n * to the session opened from `bridge.openSession(...)`. Resize is driven by\n * `ResizeObserver` so the terminal fills its container and the host PTY\n * geometry stays in sync.\n */\nexport const Terminal = (props: TerminalProps) => {\n const {\n bridge,\n request,\n theme,\n fontFamily = DEFAULT_FONT_FAMILY,\n fontSize = DEFAULT_FONT_SIZE,\n killOnUnmount = true,\n autoFocus = true,\n className,\n style,\n onSessionOpen,\n onSessionExit,\n } = props;\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const xtermRef = useRef<Xterm | null>(null);\n const fitRef = useRef<FitAddon | null>(null);\n const sinkRef = useRef<ReturnType<typeof createTerminalSink> | null>(null);\n const [terminalReady, setTerminalReady] = useState(false);\n const initialSessionRequestRef = useRef<TerminalSessionRequest | null>(null);\n const onSessionOpenRef = useRef(onSessionOpen);\n const onSessionExitRef = useRef(onSessionExit);\n\n onSessionOpenRef.current = onSessionOpen;\n onSessionExitRef.current = onSessionExit;\n\n if (!initialSessionRequestRef.current) {\n initialSessionRequestRef.current = createInitialTerminalSessionRequest(request);\n }\n\n const resolvedTheme = resolveTerminalTheme(theme);\n\n // Mount xterm once on the container. Theme, font, and size updates flow\n // through the dedicated options-sync effect below to avoid a full remount on\n // every prop change.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n let xterm: Xterm | undefined;\n let sink: ReturnType<typeof createTerminalSink> | undefined;\n let measureAnimationFrame: number | undefined;\n let measureTimeout: number | undefined;\n let observer: ResizeObserver | undefined;\n\n // Deferring construction skips React Strict Mode's disposable probe mount.\n // xterm schedules internal viewport work during construction that otherwise\n // runs after the probe instance has already been disposed.\n const initializationFrame = window.requestAnimationFrame(() => {\n xterm = new Xterm({\n cols: DEFAULT_COLS,\n rows: DEFAULT_ROWS,\n cursorBlink: true,\n convertEol: true,\n allowProposedApi: true,\n });\n const fit = new FitAddon();\n xterm.loadAddon(fit);\n xterm.loadAddon(\n new WebLinksAddon((event, uri) => {\n if (event.ctrlKey || event.metaKey) window.open(uri, \"_blank\", \"noopener,noreferrer\");\n }),\n );\n xterm.open(container);\n sink = createTerminalSink(xterm);\n\n xtermRef.current = xterm;\n fitRef.current = fit;\n sinkRef.current = sink;\n\n const measure = () => fitTerminal(fit);\n measure();\n measureAnimationFrame = window.requestAnimationFrame(measure);\n measureTimeout = window.setTimeout(measure, 50);\n observer = new ResizeObserver(measure);\n observer.observe(container);\n setTerminalReady(true);\n });\n\n return () => {\n window.cancelAnimationFrame(initializationFrame);\n if (measureAnimationFrame !== undefined) window.cancelAnimationFrame(measureAnimationFrame);\n if (measureTimeout !== undefined) window.clearTimeout(measureTimeout);\n observer?.disconnect();\n sink?.dispose();\n xterm?.dispose();\n xtermRef.current = null;\n fitRef.current = null;\n sinkRef.current = null;\n };\n }, []);\n\n useEffect(() => {\n if (!terminalReady) return;\n const xterm = xtermRef.current;\n if (!xterm) return;\n xterm.options.theme = resolvedTheme;\n xterm.options.fontFamily = fontFamily;\n xterm.options.fontSize = fontSize;\n fitTerminal(fitRef.current);\n }, [terminalReady, resolvedTheme, fontFamily, fontSize]);\n\n const { session } = useTerminalSession({ bridge, request: initialSessionRequestRef.current, killOnUnmount });\n\n useEffect(() => {\n if (!terminalReady) return;\n const xterm = xtermRef.current;\n const sink = sinkRef.current;\n if (!xterm || !sink || !session) return;\n fitTerminal(fitRef.current);\n const animationFrame = window.requestAnimationFrame(() => fitTerminal(fitRef.current));\n const unbind = bindTerminalSessionWithCallbackRefs(xterm, sink, session, {\n onSessionOpen: onSessionOpenRef,\n onSessionExit: onSessionExitRef,\n });\n return () => {\n window.cancelAnimationFrame(animationFrame);\n unbind();\n };\n }, [session, terminalReady]);\n\n useEffect(() => {\n if (terminalReady && autoFocus) xtermRef.current?.focus();\n }, [autoFocus, terminalReady]);\n\n // The mount element fills its box absolutely so xterm sizes to the panel\n // rather than growing it: inside a scrollable host, a self-sized terminal\n // would define its own height and never fit, leaving the host to scroll it.\n return (\n <div\n className={className}\n style={{\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n backgroundColor: typeof resolvedTheme.background === \"string\" ? resolvedTheme.background : undefined,\n ...style,\n }}\n >\n <div ref={containerRef} className=\"pstdio-terminal\" style={{ position: \"absolute\", inset: 0 }} />\n </div>\n );\n};\n"],"mappings":"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"}