@co0ontty/wand 4.36.0 → 4.37.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.
@@ -0,0 +1,93 @@
1
+ import headless from "@xterm/headless";
2
+ import { SerializeAddon } from "@xterm/addon-serialize";
3
+ import { Unicode11Addon } from "@xterm/addon-unicode11";
4
+ const { Terminal } = headless;
5
+ /**
6
+ * Server-side xterm screen model used only for reconnect snapshots. Live PTY
7
+ * bytes still travel unchanged from node-pty to the browser terminal.
8
+ */
9
+ export class PtyTerminalState {
10
+ terminal;
11
+ serializer = new SerializeAddon();
12
+ unicode = new Unicode11Addon();
13
+ pending = [];
14
+ tail = Promise.resolve();
15
+ checkpointTimer;
16
+ nextId = 1;
17
+ committedData = "";
18
+ committedCols;
19
+ committedRows;
20
+ disposed = false;
21
+ constructor(cols, rows, initialData = "") {
22
+ this.committedCols = cols;
23
+ this.committedRows = rows;
24
+ this.terminal = new Terminal({ cols, rows, allowProposedApi: true, scrollback: 5000 });
25
+ this.terminal.loadAddon(this.serializer);
26
+ this.terminal.loadAddon(this.unicode);
27
+ this.terminal.unicode.activeVersion = "11";
28
+ if (initialData)
29
+ this.write(initialData);
30
+ }
31
+ write(data) {
32
+ if (this.disposed || !data)
33
+ return;
34
+ const pending = this.addPending({ type: "data", data });
35
+ this.tail = this.tail.then(() => new Promise((resolve) => {
36
+ if (this.disposed)
37
+ return resolve();
38
+ this.terminal.write(data, () => resolve());
39
+ }));
40
+ this.scheduleCheckpoint(pending.id);
41
+ }
42
+ resize(cols, rows) {
43
+ if (this.disposed)
44
+ return;
45
+ const pending = this.addPending({ type: "resize", cols, rows });
46
+ this.tail = this.tail.then(() => {
47
+ if (!this.disposed)
48
+ this.terminal.resize(cols, rows);
49
+ });
50
+ this.scheduleCheckpoint(pending.id);
51
+ }
52
+ snapshot() {
53
+ return {
54
+ version: 1,
55
+ data: this.committedData,
56
+ cols: this.committedCols,
57
+ rows: this.committedRows,
58
+ pending: this.pending.map(({ operation }) => ({ ...operation })),
59
+ };
60
+ }
61
+ dispose() {
62
+ if (this.disposed)
63
+ return;
64
+ this.disposed = true;
65
+ if (this.checkpointTimer)
66
+ clearTimeout(this.checkpointTimer);
67
+ this.checkpointTimer = undefined;
68
+ this.pending = [];
69
+ this.terminal.dispose();
70
+ }
71
+ addPending(operation) {
72
+ const pending = { id: this.nextId++, operation };
73
+ this.pending.push(pending);
74
+ return pending;
75
+ }
76
+ scheduleCheckpoint(_operationId) {
77
+ if (this.checkpointTimer || this.disposed)
78
+ return;
79
+ this.checkpointTimer = setTimeout(() => {
80
+ this.checkpointTimer = undefined;
81
+ const cutoff = this.pending.at(-1)?.id ?? 0;
82
+ this.tail = this.tail.then(() => {
83
+ if (this.disposed)
84
+ return;
85
+ this.committedData = this.serializer.serialize({ scrollback: 5000 });
86
+ this.committedCols = this.terminal.cols;
87
+ this.committedRows = this.terminal.rows;
88
+ this.pending = this.pending.filter((entry) => entry.id > cutoff);
89
+ });
90
+ }, 100);
91
+ this.checkpointTimer.unref?.();
92
+ }
93
+ }
package/dist/server.js CHANGED
@@ -551,8 +551,8 @@ export async function startServer(config, configPath, options = {}) {
551
551
  res.setHeader("Cache-Control", "public, max-age=604800, immutable");
552
552
  res.type(asset.contentType).send(asset.content);
553
553
  };
554
- app.get("/vendor/wterm/wterm.bundle.js", (req, res) => sendEmbeddedVendorAsset("/vendor/wterm/wterm.bundle.js", req, res));
555
- app.get("/vendor/wterm/terminal.css", (req, res) => sendEmbeddedVendorAsset("/vendor/wterm/terminal.css", req, res));
554
+ app.get("/vendor/xterm/xterm.bundle.js", (req, res) => sendEmbeddedVendorAsset("/vendor/xterm/xterm.bundle.js", req, res));
555
+ app.get("/vendor/xterm/xterm.css", (req, res) => sendEmbeddedVendorAsset("/vendor/xterm/xterm.css", req, res));
556
556
  app.get("/vendor/qrcode/qrcode.bundle.js", (req, res) => sendEmbeddedVendorAsset("/vendor/qrcode/qrcode.bundle.js", req, res));
557
557
  // ── Web UI endpoints ──
558
558
  app.get("/", (_req, res) => {
@@ -1088,7 +1088,18 @@ export async function startServer(config, configPath, options = {}) {
1088
1088
  },
1089
1089
  });
1090
1090
  const wsManager = new WsBroadcastManager(wss, () => config.cardDefaults ?? {}, useHttps, authService);
1091
- wsManager.setup((id) => sessionRegistry.get(id));
1091
+ wsManager.setup({
1092
+ getSession: (id) => sessionRegistry.get(id),
1093
+ getTerminalState: (id) => processes.getTerminalState(id),
1094
+ sendPtyInput: (id, input, shortcutKey, userInput) => {
1095
+ processes.sendInput(id, input, "terminal", shortcutKey, userInput);
1096
+ },
1097
+ resizePty: (id, cols, rows) => {
1098
+ processes.resize(id, cols, rows);
1099
+ },
1100
+ pausePtyOutput: (id) => processes.pauseOutput(id),
1101
+ resumePtyOutput: (id) => processes.resumeOutput(id),
1102
+ });
1092
1103
  disconnectAuthenticatedSockets = () => wsManager.disconnectAll();
1093
1104
  wss.on("error", (err) => {
1094
1105
  if (err.code === "EADDRINUSE")
@@ -22,6 +22,8 @@ function sessionBase(snapshot) {
22
22
  automationId: snapshot.automationId,
23
23
  sessionKind: snapshot.sessionKind,
24
24
  provider: snapshot.provider,
25
+ providerCliActive: snapshot.providerCliActive,
26
+ providerCliExitCode: snapshot.providerCliExitCode,
25
27
  runner: snapshot.runner,
26
28
  command: snapshot.command,
27
29
  cwd: snapshot.cwd,
package/dist/types.d.ts CHANGED
@@ -492,6 +492,10 @@ export interface SessionSnapshot {
492
492
  automationId?: string;
493
493
  sessionKind?: SessionKind;
494
494
  provider?: SessionProvider;
495
+ /** True while the provider CLI owns the PTY; false after it returns to the persistent shell. */
496
+ providerCliActive?: boolean;
497
+ /** Provider CLI exit status; separate from exitCode, which belongs to the persistent PTY shell. */
498
+ providerCliExitCode?: number | null;
495
499
  runner?: SessionRunner;
496
500
  command: string;
497
501
  cwd: string;