silvery 0.19.2 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/dist/Text-Lq0dmj8-.mjs +239 -0
- package/dist/Text-Lq0dmj8-.mjs.map +1 -0
- package/dist/UPNG-Bo33r8rA.mjs +3 -0
- package/dist/UPNG-DosRPdF4.mjs +5075 -0
- package/dist/UPNG-DosRPdF4.mjs.map +1 -0
- package/dist/__vite-browser-external-2447137e-D_JM6skp.mjs +6 -0
- package/dist/__vite-browser-external-2447137e-D_JM6skp.mjs.map +1 -0
- package/dist/{animation-Cn64yepo.mjs → animation-ZMN2_XKv.mjs} +2 -2
- package/dist/animation-ZMN2_XKv.mjs.map +1 -0
- package/dist/{ansi-Cc33mW54.d.mts → ansi-2Xn0yatP.d.mts} +1 -1
- package/dist/{ansi-Cc33mW54.d.mts.map → ansi-2Xn0yatP.d.mts.map} +1 -1
- package/dist/{ansi-CLOitHKx.mjs → ansi-D1KQMAbf.mjs} +1 -1
- package/dist/{ansi-CLOitHKx.mjs.map → ansi-D1KQMAbf.mjs.map} +1 -1
- package/dist/ansi-yC4RyBNY.mjs +22441 -0
- package/dist/ansi-yC4RyBNY.mjs.map +1 -0
- package/dist/apng-CR08rIaH.mjs +58 -0
- package/dist/apng-CR08rIaH.mjs.map +1 -0
- package/dist/apng-DaHfVaVI.mjs +3 -0
- package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
- package/dist/assets/skia.darwin-arm64-DQs5sT6N.node +0 -0
- package/dist/backend-B-WYLUib.mjs +13396 -0
- package/dist/backend-B-WYLUib.mjs.map +1 -0
- package/dist/backends-CUtan80W.mjs +3 -0
- package/dist/backends-DIVYzKqd.mjs +1083 -0
- package/dist/backends-DIVYzKqd.mjs.map +1 -0
- package/dist/bound-term-0sPrrzH1.d.mts +4640 -0
- package/dist/bound-term-0sPrrzH1.d.mts.map +1 -0
- package/dist/canvas-1v7dPT-_.mjs +3 -0
- package/dist/canvas-CSuPOMNt.mjs +1442 -0
- package/dist/canvas-CSuPOMNt.mjs.map +1 -0
- package/dist/{chunk-Vs_PY4HZ.mjs → chunk-BSw8zbkd.mjs} +1 -1
- package/dist/cli-dvo0r2fs.mjs +4 -0
- package/dist/compare-CQodSH4G.mjs +376 -0
- package/dist/compare-CQodSH4G.mjs.map +1 -0
- package/dist/compare-DHlcxEYA.mjs +3 -0
- package/dist/context-BU5LkkIy.mjs.map +1 -1
- package/dist/devtools-CJdt5H0X.mjs +2 -0
- package/dist/{devtools-DxkSLXDA.mjs → devtools-DcQjgyjL.mjs} +5 -4
- package/dist/{devtools-DxkSLXDA.mjs.map → devtools-DcQjgyjL.mjs.map} +1 -1
- package/dist/easing-BI-ASGMO.d.mts +24 -0
- package/dist/easing-BI-ASGMO.d.mts.map +1 -0
- package/dist/{eta-Bb3RH3wh.mjs → eta-CJlGH06n.mjs} +1 -1
- package/dist/{eta-Bb3RH3wh.mjs.map → eta-CJlGH06n.mjs.map} +1 -1
- package/dist/flexily-zero-adapter-C3Vj0fPt.mjs +306 -0
- package/dist/flexily-zero-adapter-C3Vj0fPt.mjs.map +1 -0
- package/dist/{flexily-zero-adapter-CMxXhdOL.mjs → flexily-zero-adapter-C4lW_Ov5.mjs} +1 -1
- package/dist/fonts-BFmhXDv7.mjs +88 -0
- package/dist/fonts-BFmhXDv7.mjs.map +1 -0
- package/dist/gif-C_AjaT9d.mjs +188 -0
- package/dist/gif-C_AjaT9d.mjs.map +1 -0
- package/dist/gif-DaC4XrxA.mjs +3 -0
- package/dist/gifenc-BOUT-KFB.mjs +730 -0
- package/dist/gifenc-BOUT-KFB.mjs.map +1 -0
- package/dist/image-C2Birh2x.mjs +1252 -0
- package/dist/image-C2Birh2x.mjs.map +1 -0
- package/dist/index-BUMxS65f.d.mts +453 -0
- package/dist/index-BUMxS65f.d.mts.map +1 -0
- package/dist/{index-D3saHouR.d.mts → index-CSQf13CI.d.mts} +1057 -1133
- package/dist/index-CSQf13CI.d.mts.map +1 -0
- package/dist/{index-BXslOebb.d.mts → index-Cl9KKjQ_.d.mts} +4919 -3921
- package/dist/index-Cl9KKjQ_.d.mts.map +1 -0
- package/dist/index-XbNrPhWl.d.mts +336 -0
- package/dist/index-XbNrPhWl.d.mts.map +1 -0
- package/dist/index.d.mts +8 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +14 -12
- package/dist/index.mjs.map +1 -1
- package/dist/key-mapping-CS-YD_cD.mjs +132 -0
- package/dist/key-mapping-CS-YD_cD.mjs.map +1 -0
- package/dist/key-mapping-Yn-Jgrij.mjs +3 -0
- package/dist/{layout-engine-B6Cdz1yZ.mjs → layout-engine-C07LEXWT.mjs} +1 -1
- package/dist/layout-engine-C2px0RJE.mjs +67 -0
- package/dist/layout-engine-C2px0RJE.mjs.map +1 -0
- package/dist/layout-signals-Cnw6xk8Q.mjs +988 -0
- package/dist/layout-signals-Cnw6xk8Q.mjs.map +1 -0
- package/dist/mouse-events-Dki3ISIp.mjs +1044 -0
- package/dist/mouse-events-Dki3ISIp.mjs.map +1 -0
- package/dist/{multi-progress-Bq9Oi_WI.mjs → multi-progress-CIRjrzma.mjs} +3 -3
- package/dist/{multi-progress-Bq9Oi_WI.mjs.map → multi-progress-CIRjrzma.mjs.map} +1 -1
- package/dist/{multi-progress-DAQC7eap.d.mts → multi-progress-DHZ2xUT2.d.mts} +2 -2
- package/dist/{multi-progress-DAQC7eap.d.mts.map → multi-progress-DHZ2xUT2.d.mts.map} +1 -1
- package/dist/{node-BeWlnCPY.mjs → node-CjM5Rt-M.mjs} +4 -4
- package/dist/node-CjM5Rt-M.mjs.map +1 -0
- package/dist/playwright-D5YiZcNS.mjs +76397 -0
- package/dist/playwright-D5YiZcNS.mjs.map +1 -0
- package/dist/png-codec-Dp84742B.mjs +36 -0
- package/dist/png-codec-Dp84742B.mjs.map +1 -0
- package/dist/png-codec-QwOtJ8Zs.mjs +3 -0
- package/dist/progress-DB_Xo071.mjs +675 -0
- package/dist/progress-DB_Xo071.mjs.map +1 -0
- package/dist/{progress-bar-CXE5Qfkd.mjs → progress-bar-oJwq22CR.mjs} +4 -4
- package/dist/{progress-bar-CXE5Qfkd.mjs.map → progress-bar-oJwq22CR.mjs.map} +1 -1
- package/dist/rasterizer-BRXrDdWx.mjs +3 -0
- package/dist/rasterizer-CpEhJvdR.mjs +296 -0
- package/dist/rasterizer-CpEhJvdR.mjs.map +1 -0
- package/dist/reconciler-DldIJB93.mjs +2083 -0
- package/dist/reconciler-DldIJB93.mjs.map +1 -0
- package/dist/{render-string-CDCeYkS3.mjs → render-string-BcoCpjCB.mjs} +1 -1
- package/dist/{render-string-Darrg7ku.mjs → render-string-DkQacASz.mjs} +2707 -549
- package/dist/render-string-DkQacASz.mjs.map +1 -0
- package/dist/resvg-js-DkOndZI3.mjs +203 -0
- package/dist/resvg-js-DkOndZI3.mjs.map +1 -0
- package/dist/runtime.d.mts +3 -2
- package/dist/runtime.mjs +3 -3
- package/dist/schemes-JjNp4aSl.mjs +2611 -0
- package/dist/schemes-JjNp4aSl.mjs.map +1 -0
- package/dist/{spinner-CGo34vyR.d.mts → spinner-CZINHpkV.d.mts} +2 -2
- package/dist/{spinner-CGo34vyR.d.mts.map → spinner-CZINHpkV.d.mts.map} +1 -1
- package/dist/{spinner-CeOmcuw_.mjs → spinner-D9lrHr8s.mjs} +7 -7
- package/dist/spinner-D9lrHr8s.mjs.map +1 -0
- package/dist/src-5w9QR6_8.mjs +1071 -0
- package/dist/src-5w9QR6_8.mjs.map +1 -0
- package/dist/src-BNTToU7l.mjs +4387 -0
- package/dist/src-BNTToU7l.mjs.map +1 -0
- package/dist/{src-CF-6UN01.mjs → src-BR4xNwdG.mjs} +10436 -2622
- package/dist/src-BR4xNwdG.mjs.map +1 -0
- package/dist/{types-Bk2yw9Qj.mjs → src-DKp-_OFG.mjs} +34 -94
- package/dist/src-DKp-_OFG.mjs.map +1 -0
- package/dist/src-bt8wSrfJ.mjs +258 -0
- package/dist/src-bt8wSrfJ.mjs.map +1 -0
- package/dist/src-e33Y6kNJ.mjs +3 -0
- package/dist/src-iDwu25UD.mjs +1814 -0
- package/dist/src-iDwu25UD.mjs.map +1 -0
- package/dist/steps-Bp2uNqnn.d.mts +202 -0
- package/dist/steps-Bp2uNqnn.d.mts.map +1 -0
- package/dist/svg-15lZZzxq.mjs +486 -0
- package/dist/svg-15lZZzxq.mjs.map +1 -0
- package/dist/svg-Cz0UXcDj.mjs +255 -0
- package/dist/svg-Cz0UXcDj.mjs.map +1 -0
- package/dist/svg-DY72a4HK.mjs +3 -0
- package/dist/svg-g1D6ErwR.d.mts +82 -0
- package/dist/svg-g1D6ErwR.d.mts.map +1 -0
- package/dist/term.d.mts +3 -0
- package/dist/term.mjs +9 -0
- package/dist/term.mjs.map +1 -0
- package/dist/theme.d.mts +95 -2
- package/dist/theme.d.mts.map +1 -0
- package/dist/theme.mjs +9 -3
- package/dist/theme.mjs.map +1 -0
- package/dist/{types-BH_v3iMT.d.mts → types-kt_fKR37.d.mts} +2 -15
- package/dist/types-kt_fKR37.d.mts.map +1 -0
- package/dist/ui/animation.d.mts +2 -1
- package/dist/ui/animation.mjs +1 -1
- package/dist/ui/ansi.d.mts +1 -1
- package/dist/ui/ansi.mjs +1 -1
- package/dist/ui/cli.d.mts +3 -3
- package/dist/ui/cli.mjs +5 -5
- package/dist/ui/display.d.mts +1 -1
- package/dist/ui/image.d.mts +2 -2
- package/dist/ui/image.mjs +2 -2
- package/dist/ui/input.d.mts +1 -1
- package/dist/ui/input.mjs +4 -2
- package/dist/ui/input.mjs.map +1 -1
- package/dist/ui/progress.d.mts +5 -249
- package/dist/ui/progress.mjs +5 -858
- package/dist/ui/react.d.mts +1 -1
- package/dist/ui/react.mjs +2 -2
- package/dist/ui/recording-chrome-react.d.mts +21 -0
- package/dist/ui/recording-chrome-react.d.mts.map +1 -0
- package/dist/ui/recording-chrome-react.mjs +105 -0
- package/dist/ui/recording-chrome-react.mjs.map +1 -0
- package/dist/ui/recording-chrome.d.mts +2 -0
- package/dist/ui/recording-chrome.mjs +2 -0
- package/dist/ui/utils.mjs +1 -1
- package/dist/ui/wrappers.d.mts +3 -3
- package/dist/ui/wrappers.mjs +2 -2
- package/dist/ui.d.mts +7 -6
- package/dist/ui.mjs +8 -7
- package/dist/{useLatest-Bg2x4bfP.d.mts → useLatest-DRDDVwjh.d.mts} +5 -25
- package/dist/useLatest-DRDDVwjh.d.mts.map +1 -0
- package/dist/{with-text-input-CRfoiFFG.d.mts → with-text-input-YeohVLeo.d.mts} +4 -55
- package/dist/with-text-input-YeohVLeo.d.mts.map +1 -0
- package/dist/wrapper-C70ATkVv.mjs +3527 -0
- package/dist/wrapper-C70ATkVv.mjs.map +1 -0
- package/dist/{wrappers-UTADQkSY.mjs → wrappers-BCUYITrY.mjs} +5 -157
- package/dist/wrappers-BCUYITrY.mjs.map +1 -0
- package/dist/{yoga-adapter-8oRGRw8V.mjs → yoga-adapter-BnZX1PAY.mjs} +28 -2
- package/dist/yoga-adapter-BnZX1PAY.mjs.map +1 -0
- package/dist/yoga-adapter-DxgsQ_gg.mjs +2 -0
- package/dist/zipBundle-3nqeDRtm.mjs +3 -0
- package/dist/zipBundle-VNAYFmqJ.mjs +2003 -0
- package/dist/zipBundle-VNAYFmqJ.mjs.map +1 -0
- package/package.json +20 -9
- package/dist/animation-Cn64yepo.mjs.map +0 -1
- package/dist/cli-BKp0YtBD.mjs +0 -4
- package/dist/devtools-9QY4teqI.mjs +0 -2
- package/dist/flexily-zero-adapter-BlQa46nr.mjs +0 -3385
- package/dist/flexily-zero-adapter-BlQa46nr.mjs.map +0 -1
- package/dist/image-CTII5QWI.mjs +0 -477
- package/dist/image-CTII5QWI.mjs.map +0 -1
- package/dist/index-BXslOebb.d.mts.map +0 -1
- package/dist/index-BnA7mNpo.d.mts +0 -175
- package/dist/index-BnA7mNpo.d.mts.map +0 -1
- package/dist/index-D3saHouR.d.mts.map +0 -1
- package/dist/layout-engine-ClUgv6jB.mjs +0 -50
- package/dist/layout-engine-ClUgv6jB.mjs.map +0 -1
- package/dist/node-BeWlnCPY.mjs.map +0 -1
- package/dist/reconciler-Cwgm8hRR.mjs +0 -8459
- package/dist/reconciler-Cwgm8hRR.mjs.map +0 -1
- package/dist/render-string-Darrg7ku.mjs.map +0 -1
- package/dist/spinner-CeOmcuw_.mjs.map +0 -1
- package/dist/src-B5GjfG7g.mjs +0 -4305
- package/dist/src-B5GjfG7g.mjs.map +0 -1
- package/dist/src-CChwjk0Z.mjs +0 -738
- package/dist/src-CChwjk0Z.mjs.map +0 -1
- package/dist/src-CF-6UN01.mjs.map +0 -1
- package/dist/src-NCKb8kE5.mjs +0 -2660
- package/dist/src-NCKb8kE5.mjs.map +0 -1
- package/dist/types-BH_v3iMT.d.mts.map +0 -1
- package/dist/types-Bk2yw9Qj.mjs.map +0 -1
- package/dist/ui/progress.d.mts.map +0 -1
- package/dist/ui/progress.mjs.map +0 -1
- package/dist/useLatest-Bg2x4bfP.d.mts.map +0 -1
- package/dist/with-text-input-CRfoiFFG.d.mts.map +0 -1
- package/dist/wrappers-UTADQkSY.mjs.map +0 -1
- package/dist/yoga-adapter-8oRGRw8V.mjs.map +0 -1
- package/dist/yoga-adapter-D_CcxSt5.mjs +0 -2
|
@@ -0,0 +1,1083 @@
|
|
|
1
|
+
import { n as __esmMin, o as __toESM } from "./chunk-BSw8zbkd.mjs";
|
|
2
|
+
import { n as keyToAnsi, r as parseKey, t as init_key_mapping } from "./key-mapping-CS-YD_cD.mjs";
|
|
3
|
+
import { c as init_fonts, o as bundledFontFiles } from "./fonts-BFmhXDv7.mjs";
|
|
4
|
+
import { a as screenshotSvg, n as init_svg } from "./svg-15lZZzxq.mjs";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { execSync } from "node:child_process";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
//#region ../termless/src/terminal/spawn.ts
|
|
12
|
+
/**
|
|
13
|
+
* Portable PTY spawn abstraction.
|
|
14
|
+
*
|
|
15
|
+
* Detects the runtime (Bun vs Node.js) and uses the appropriate PTY backend:
|
|
16
|
+
* - Bun: native `Bun.spawn()` with `terminal` option
|
|
17
|
+
* - Node.js: `node-pty` (optional peer dependency — throws if not installed)
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Spawn a process with a PTY, using the appropriate runtime backend.
|
|
21
|
+
*
|
|
22
|
+
* - On Bun: uses `Bun.spawn()` with the `terminal` option (built-in PTY support).
|
|
23
|
+
* - On Node.js: uses `node-pty` (loaded via createRequire). Throws a clear error if not installed.
|
|
24
|
+
*/
|
|
25
|
+
function spawnPortablePty(options) {
|
|
26
|
+
if (isBun) return spawnBunPty(options);
|
|
27
|
+
return spawnNodePty(options);
|
|
28
|
+
}
|
|
29
|
+
function spawnBunPty(options) {
|
|
30
|
+
const { argv, cols, rows, cwd, env, onData } = options;
|
|
31
|
+
const proc = Bun.spawn(argv, {
|
|
32
|
+
cwd,
|
|
33
|
+
env: {
|
|
34
|
+
...process.env,
|
|
35
|
+
...env
|
|
36
|
+
},
|
|
37
|
+
terminal: {
|
|
38
|
+
cols,
|
|
39
|
+
rows,
|
|
40
|
+
data: (_terminal, data) => {
|
|
41
|
+
try {
|
|
42
|
+
onData(data);
|
|
43
|
+
} catch {}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const pty = proc.terminal;
|
|
48
|
+
return {
|
|
49
|
+
write(data) {
|
|
50
|
+
pty.write(data);
|
|
51
|
+
},
|
|
52
|
+
resize(newCols, newRows) {
|
|
53
|
+
pty.resize(newCols, newRows);
|
|
54
|
+
},
|
|
55
|
+
closePty() {
|
|
56
|
+
try {
|
|
57
|
+
pty.close();
|
|
58
|
+
} catch {}
|
|
59
|
+
},
|
|
60
|
+
kill(signal) {
|
|
61
|
+
proc.kill(signal);
|
|
62
|
+
},
|
|
63
|
+
get exitCode() {
|
|
64
|
+
return proc.exitCode;
|
|
65
|
+
},
|
|
66
|
+
get exited() {
|
|
67
|
+
return proc.exited;
|
|
68
|
+
},
|
|
69
|
+
get pid() {
|
|
70
|
+
return proc.pid;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Load node-pty synchronously using createRequire.
|
|
76
|
+
*
|
|
77
|
+
* node-pty is a CommonJS native addon, so createRequire is the correct way
|
|
78
|
+
* to load it from ESM. This keeps spawnPortablePty() synchronous.
|
|
79
|
+
*/
|
|
80
|
+
function loadNodePty() {
|
|
81
|
+
try {
|
|
82
|
+
return createRequire(import.meta.url)("node-pty");
|
|
83
|
+
} catch {
|
|
84
|
+
throw new Error("node-pty is required for PTY support on Node.js but was not found.\nInstall it with: npm install node-pty\nNote: node-pty requires native compilation tools (Python, C++ compiler).");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function spawnNodePty(options) {
|
|
88
|
+
const { argv, cols, rows, cwd, env, onData } = options;
|
|
89
|
+
const ptyProcess = loadNodePty().spawn(argv[0], argv.slice(1), {
|
|
90
|
+
name: "xterm-256color",
|
|
91
|
+
cols,
|
|
92
|
+
rows,
|
|
93
|
+
cwd,
|
|
94
|
+
env: {
|
|
95
|
+
...process.env,
|
|
96
|
+
...env
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const encoder = new TextEncoder();
|
|
100
|
+
ptyProcess.onData((data) => {
|
|
101
|
+
try {
|
|
102
|
+
onData(encoder.encode(data));
|
|
103
|
+
} catch {}
|
|
104
|
+
});
|
|
105
|
+
let _exitCode = null;
|
|
106
|
+
let _exitResolve = null;
|
|
107
|
+
const exitedPromise = new Promise((resolve) => {
|
|
108
|
+
_exitResolve = resolve;
|
|
109
|
+
});
|
|
110
|
+
ptyProcess.onExit((e) => {
|
|
111
|
+
_exitCode = e.exitCode;
|
|
112
|
+
_exitResolve?.(e.exitCode);
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
write(data) {
|
|
116
|
+
ptyProcess.write(data);
|
|
117
|
+
},
|
|
118
|
+
resize(newCols, newRows) {
|
|
119
|
+
ptyProcess.resize(newCols, newRows);
|
|
120
|
+
},
|
|
121
|
+
closePty() {
|
|
122
|
+
try {
|
|
123
|
+
ptyProcess.destroy();
|
|
124
|
+
} catch {}
|
|
125
|
+
},
|
|
126
|
+
kill(signal) {
|
|
127
|
+
const sig = signal === 9 ? "SIGKILL" : "SIGTERM";
|
|
128
|
+
try {
|
|
129
|
+
ptyProcess.kill(sig);
|
|
130
|
+
} catch {}
|
|
131
|
+
},
|
|
132
|
+
get exitCode() {
|
|
133
|
+
return _exitCode;
|
|
134
|
+
},
|
|
135
|
+
get exited() {
|
|
136
|
+
return exitedPromise;
|
|
137
|
+
},
|
|
138
|
+
get pid() {
|
|
139
|
+
return ptyProcess.pid;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
var isBun;
|
|
144
|
+
var init_spawn = __esmMin((() => {
|
|
145
|
+
isBun = typeof globalThis.Bun !== "undefined";
|
|
146
|
+
}));
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region ../termless/src/terminal/pty.ts
|
|
149
|
+
/**
|
|
150
|
+
* Spawn a child process with a PTY and return a handle for interacting with it.
|
|
151
|
+
*
|
|
152
|
+
* The command is spawned directly (no shell wrapper) to avoid shell injection.
|
|
153
|
+
* Sets FORCE_COLOR=1 and TERM=xterm-256color to ensure proper color output.
|
|
154
|
+
*
|
|
155
|
+
* Runtime support:
|
|
156
|
+
* - Bun: uses native `Bun.spawn()` with `terminal` option (built-in PTY)
|
|
157
|
+
* - Node.js: uses `node-pty` (must be installed as a peer dependency)
|
|
158
|
+
*/
|
|
159
|
+
function spawnPty(options) {
|
|
160
|
+
const { env, cwd, cols, rows, onData } = options;
|
|
161
|
+
const proc = spawnPortablePty({
|
|
162
|
+
argv: "shellCommand" in options ? [
|
|
163
|
+
"bash",
|
|
164
|
+
"-c",
|
|
165
|
+
options.shellCommand
|
|
166
|
+
] : options.command,
|
|
167
|
+
cols,
|
|
168
|
+
rows,
|
|
169
|
+
cwd,
|
|
170
|
+
env: {
|
|
171
|
+
FORCE_COLOR: "1",
|
|
172
|
+
TERM: "xterm-256color",
|
|
173
|
+
...env
|
|
174
|
+
},
|
|
175
|
+
onData
|
|
176
|
+
});
|
|
177
|
+
let closed = false;
|
|
178
|
+
let exitCode = null;
|
|
179
|
+
(async () => {
|
|
180
|
+
try {
|
|
181
|
+
exitCode = await proc.exited;
|
|
182
|
+
} catch {}
|
|
183
|
+
})();
|
|
184
|
+
async function close() {
|
|
185
|
+
if (closed) return;
|
|
186
|
+
closed = true;
|
|
187
|
+
proc.closePty();
|
|
188
|
+
try {
|
|
189
|
+
proc.kill();
|
|
190
|
+
if (!await Promise.race([proc.exited.then(() => true), new Promise((resolve) => setTimeout(() => resolve(false), 2e3))])) proc.kill(9);
|
|
191
|
+
} catch {}
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
write(data) {
|
|
195
|
+
if (closed) throw new Error("PTY is closed");
|
|
196
|
+
proc.write(data);
|
|
197
|
+
},
|
|
198
|
+
resize(newCols, newRows) {
|
|
199
|
+
if (closed) throw new Error("PTY is closed");
|
|
200
|
+
proc.resize(newCols, newRows);
|
|
201
|
+
},
|
|
202
|
+
get alive() {
|
|
203
|
+
return !closed && exitCode === null;
|
|
204
|
+
},
|
|
205
|
+
get exitInfo() {
|
|
206
|
+
if (exitCode !== null) return `exit=${exitCode}`;
|
|
207
|
+
return null;
|
|
208
|
+
},
|
|
209
|
+
close
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
var init_pty = __esmMin((() => {
|
|
213
|
+
init_spawn();
|
|
214
|
+
}));
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region ../termless/src/render/png.ts
|
|
217
|
+
async function loadResvg() {
|
|
218
|
+
if (resvgModule) return resvgModule;
|
|
219
|
+
try {
|
|
220
|
+
resvgModule = await import("./resvg-js-DkOndZI3.mjs").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
|
|
221
|
+
return resvgModule;
|
|
222
|
+
} catch {
|
|
223
|
+
throw new Error("screenshotPng() requires @resvg/resvg-js. Install it:\n bun add -d @resvg/resvg-js");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Render a terminal screenshot as a PNG buffer.
|
|
228
|
+
*
|
|
229
|
+
* Requires `@resvg/resvg-js` as an optional dependency:
|
|
230
|
+
* bun add -d @resvg/resvg-js
|
|
231
|
+
*/
|
|
232
|
+
async function screenshotPng(terminal, options) {
|
|
233
|
+
const svg = screenshotSvg(terminal, options);
|
|
234
|
+
const scale = options?.scale ?? 2;
|
|
235
|
+
const { Resvg } = await loadResvg();
|
|
236
|
+
return new Resvg(svg, {
|
|
237
|
+
fitTo: {
|
|
238
|
+
mode: "zoom",
|
|
239
|
+
value: scale
|
|
240
|
+
},
|
|
241
|
+
font: {
|
|
242
|
+
loadSystemFonts: true,
|
|
243
|
+
defaultFontFamily: "Menlo",
|
|
244
|
+
fontFiles: bundledFontFiles()
|
|
245
|
+
}
|
|
246
|
+
}).render().asPng();
|
|
247
|
+
}
|
|
248
|
+
var resvgModule;
|
|
249
|
+
var init_png = __esmMin((() => {
|
|
250
|
+
init_svg();
|
|
251
|
+
init_fonts();
|
|
252
|
+
resvgModule = null;
|
|
253
|
+
}));
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region ../termless/src/terminal/views.ts
|
|
256
|
+
/** Convert a Cell[] to trimmed text. */
|
|
257
|
+
function cellsToText(cells) {
|
|
258
|
+
return cells.map((c) => c.char || " ").join("").trimEnd();
|
|
259
|
+
}
|
|
260
|
+
/** Get rows of text from a TerminalReadable for an absolute row range. */
|
|
261
|
+
function getRowTexts(readable, startRow, endRow) {
|
|
262
|
+
const lines = [];
|
|
263
|
+
for (let i = startRow; i < endRow; i++) lines.push(cellsToText(readable.getLine(i)));
|
|
264
|
+
return lines;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Create a lazy RegionView from a row-range resolver.
|
|
268
|
+
* The resolver is called on every getText()/getLines() access,
|
|
269
|
+
* so the view always reflects current terminal state.
|
|
270
|
+
*/
|
|
271
|
+
function createLazyRegionView(readable, resolveRange) {
|
|
272
|
+
return {
|
|
273
|
+
getText() {
|
|
274
|
+
const [start, end] = resolveRange();
|
|
275
|
+
return getRowTexts(readable, start, end).join("\n");
|
|
276
|
+
},
|
|
277
|
+
getLines() {
|
|
278
|
+
const [start, end] = resolveRange();
|
|
279
|
+
return getRowTexts(readable, start, end);
|
|
280
|
+
},
|
|
281
|
+
containsText(text) {
|
|
282
|
+
return this.getText().includes(text);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/** Create a CellView from a Cell with positional context. */
|
|
287
|
+
function createCellView(cell, row, col) {
|
|
288
|
+
return {
|
|
289
|
+
char: cell.char,
|
|
290
|
+
row,
|
|
291
|
+
col,
|
|
292
|
+
fg: cell.fg,
|
|
293
|
+
bg: cell.bg,
|
|
294
|
+
bold: cell.bold,
|
|
295
|
+
dim: cell.dim,
|
|
296
|
+
italic: cell.italic,
|
|
297
|
+
underline: cell.underline,
|
|
298
|
+
underlineColor: cell.underlineColor,
|
|
299
|
+
strikethrough: cell.strikethrough,
|
|
300
|
+
inverse: cell.inverse,
|
|
301
|
+
blink: cell.blink,
|
|
302
|
+
hidden: cell.hidden,
|
|
303
|
+
wide: cell.wide,
|
|
304
|
+
continuation: cell.continuation,
|
|
305
|
+
hyperlink: cell.hyperlink
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/** Create a RegionView for a fixed absolute row range [startRow, endRow). */
|
|
309
|
+
function createRegionView(readable, startRow, endRow) {
|
|
310
|
+
return createLazyRegionView(readable, () => [startRow, endRow]);
|
|
311
|
+
}
|
|
312
|
+
/** Create a RowView for an absolute row position. screenRow is the display row number. */
|
|
313
|
+
function createRowView(readable, absRow, screenRow) {
|
|
314
|
+
return {
|
|
315
|
+
get row() {
|
|
316
|
+
return screenRow;
|
|
317
|
+
},
|
|
318
|
+
get cells() {
|
|
319
|
+
return readable.getLine(absRow);
|
|
320
|
+
},
|
|
321
|
+
getText() {
|
|
322
|
+
return cellsToText(readable.getLine(absRow));
|
|
323
|
+
},
|
|
324
|
+
getLines() {
|
|
325
|
+
return [this.getText()];
|
|
326
|
+
},
|
|
327
|
+
containsText(text) {
|
|
328
|
+
return this.getText().includes(text);
|
|
329
|
+
},
|
|
330
|
+
cellAt(col) {
|
|
331
|
+
return createCellView(readable.getCell(absRow, col), screenRow, col);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Screen view: the fixed rows × cols grid at the bottom of the buffer.
|
|
337
|
+
* In alt mode, this is the entire alt buffer.
|
|
338
|
+
*/
|
|
339
|
+
function createScreenView(readable) {
|
|
340
|
+
return createLazyRegionView(readable, () => {
|
|
341
|
+
const { totalLines, screenLines } = readable.getScrollback();
|
|
342
|
+
const base = totalLines - screenLines;
|
|
343
|
+
return [base, base + screenLines];
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Scrollback view: history lines above the screen.
|
|
348
|
+
* Empty in alt screen mode.
|
|
349
|
+
* @param n - If provided, only the last N scrollback lines.
|
|
350
|
+
*/
|
|
351
|
+
function createScrollbackView(readable, n) {
|
|
352
|
+
return createLazyRegionView(readable, () => {
|
|
353
|
+
const { totalLines, screenLines } = readable.getScrollback();
|
|
354
|
+
const base = totalLines - screenLines;
|
|
355
|
+
if (base <= 0) return [0, 0];
|
|
356
|
+
return [n != null ? Math.max(0, base - n) : 0, base];
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Buffer view: everything (scrollback + screen).
|
|
361
|
+
* Uses readable.getText() directly — not row-based.
|
|
362
|
+
*/
|
|
363
|
+
function createBufferView(readable) {
|
|
364
|
+
return {
|
|
365
|
+
getText() {
|
|
366
|
+
return readable.getText();
|
|
367
|
+
},
|
|
368
|
+
getLines() {
|
|
369
|
+
return readable.getText().split("\n");
|
|
370
|
+
},
|
|
371
|
+
containsText(text) {
|
|
372
|
+
return readable.getText().includes(text);
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Viewport view: what's visible at the current scroll position.
|
|
378
|
+
* At bottom (viewportOffset = totalLines - screenLines): same as screen.
|
|
379
|
+
* Scrolled up: shows older scrollback lines.
|
|
380
|
+
*/
|
|
381
|
+
function createViewportView(readable) {
|
|
382
|
+
return createLazyRegionView(readable, () => {
|
|
383
|
+
const { viewportOffset, screenLines } = readable.getScrollback();
|
|
384
|
+
return [viewportOffset, viewportOffset + screenLines];
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Range view: a rectangular region of the screen.
|
|
389
|
+
* Coordinates are screen-relative. Uses getTextRange() — not row-based.
|
|
390
|
+
*/
|
|
391
|
+
function createRangeView(readable, r1, c1, r2, c2) {
|
|
392
|
+
return {
|
|
393
|
+
getText() {
|
|
394
|
+
const { totalLines, screenLines } = readable.getScrollback();
|
|
395
|
+
const base = totalLines - screenLines;
|
|
396
|
+
return readable.getTextRange(base + r1, c1, base + r2, c2);
|
|
397
|
+
},
|
|
398
|
+
getLines() {
|
|
399
|
+
return this.getText().split("\n");
|
|
400
|
+
},
|
|
401
|
+
containsText(text) {
|
|
402
|
+
return this.getText().includes(text);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
var init_views = __esmMin((() => {}));
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region ../termless/src/terminal/terminal.ts
|
|
409
|
+
/**
|
|
410
|
+
* Create a Terminal instance wrapping a backend with optional PTY support.
|
|
411
|
+
*
|
|
412
|
+
* The terminal initializes the backend immediately and provides methods for:
|
|
413
|
+
* - Feeding data directly (no PTY)
|
|
414
|
+
* - Spawning a child process with a PTY
|
|
415
|
+
* - Sending key presses and typed text to the PTY
|
|
416
|
+
* - Waiting for terminal content to appear or stabilize
|
|
417
|
+
* - Searching terminal text
|
|
418
|
+
* - Taking SVG and PNG screenshots
|
|
419
|
+
*/
|
|
420
|
+
function createTerminal(options) {
|
|
421
|
+
const { backend, scrollbackLimit } = options;
|
|
422
|
+
let cols = options.cols ?? DEFAULT_COLS;
|
|
423
|
+
let rows = options.rows ?? DEFAULT_ROWS;
|
|
424
|
+
backend.init({
|
|
425
|
+
cols,
|
|
426
|
+
rows,
|
|
427
|
+
scrollbackLimit
|
|
428
|
+
});
|
|
429
|
+
let ptyHandle = null;
|
|
430
|
+
let closed = false;
|
|
431
|
+
/** OSC 52 regex: \x1b]52;c;<base64>\x07 or \x1b]52;c;<base64>\x1b\\ */
|
|
432
|
+
const osc52Re = /\x1b\]52;[a-z]*;([A-Za-z0-9+/=]+)(?:\x07|\x1b\\)/g;
|
|
433
|
+
const clipboardWrites = [];
|
|
434
|
+
const outputChunks = [];
|
|
435
|
+
let outputDecoder = new TextDecoder();
|
|
436
|
+
const out = {
|
|
437
|
+
getText() {
|
|
438
|
+
return outputChunks.join("");
|
|
439
|
+
},
|
|
440
|
+
getChunks() {
|
|
441
|
+
return [...outputChunks];
|
|
442
|
+
},
|
|
443
|
+
containsOutput(text) {
|
|
444
|
+
return this.getText().includes(text);
|
|
445
|
+
},
|
|
446
|
+
clear() {
|
|
447
|
+
outputChunks.length = 0;
|
|
448
|
+
outputDecoder = new TextDecoder();
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
function captureOutput(data) {
|
|
452
|
+
if (data.length > 0) outputChunks.push(data);
|
|
453
|
+
}
|
|
454
|
+
function scanOsc52(data) {
|
|
455
|
+
osc52Re.lastIndex = 0;
|
|
456
|
+
let match;
|
|
457
|
+
while ((match = osc52Re.exec(data)) !== null) try {
|
|
458
|
+
const decoded = atob(match[1]);
|
|
459
|
+
clipboardWrites.push(decoded);
|
|
460
|
+
} catch {}
|
|
461
|
+
}
|
|
462
|
+
function getText() {
|
|
463
|
+
return backend.getText();
|
|
464
|
+
}
|
|
465
|
+
function getTextRange(startRow, startCol, endRow, endCol) {
|
|
466
|
+
return backend.getTextRange(startRow, startCol, endRow, endCol);
|
|
467
|
+
}
|
|
468
|
+
function getCell(row, col) {
|
|
469
|
+
return backend.getCell(row, col);
|
|
470
|
+
}
|
|
471
|
+
function getLine(row) {
|
|
472
|
+
return backend.getLine(row);
|
|
473
|
+
}
|
|
474
|
+
function getLines() {
|
|
475
|
+
return backend.getLines();
|
|
476
|
+
}
|
|
477
|
+
function getCursor() {
|
|
478
|
+
return backend.getCursor();
|
|
479
|
+
}
|
|
480
|
+
function getMode(mode) {
|
|
481
|
+
return backend.getMode(mode);
|
|
482
|
+
}
|
|
483
|
+
function getTitle() {
|
|
484
|
+
return backend.getTitle();
|
|
485
|
+
}
|
|
486
|
+
function getScrollback() {
|
|
487
|
+
return backend.getScrollback();
|
|
488
|
+
}
|
|
489
|
+
function feed(data) {
|
|
490
|
+
if (closed) throw new Error("Terminal is closed");
|
|
491
|
+
const text = typeof data === "string" ? data : outputDecoder.decode(data, { stream: true });
|
|
492
|
+
captureOutput(text);
|
|
493
|
+
scanOsc52(text);
|
|
494
|
+
const bytes = typeof data === "string" ? encoder.encode(data) : data;
|
|
495
|
+
backend.feed(bytes);
|
|
496
|
+
options.onAfterWrite?.(bytes);
|
|
497
|
+
}
|
|
498
|
+
async function spawn(command, spawnOpts) {
|
|
499
|
+
if (closed) throw new Error("Terminal is closed");
|
|
500
|
+
if (ptyHandle) throw new Error("Terminal already has a spawned process");
|
|
501
|
+
ptyHandle = spawnPty({
|
|
502
|
+
command,
|
|
503
|
+
env: spawnOpts?.env,
|
|
504
|
+
cwd: spawnOpts?.cwd,
|
|
505
|
+
cols,
|
|
506
|
+
rows,
|
|
507
|
+
onData: (data) => {
|
|
508
|
+
const text = outputDecoder.decode(data, { stream: true });
|
|
509
|
+
captureOutput(text);
|
|
510
|
+
scanOsc52(text);
|
|
511
|
+
backend.feed(data);
|
|
512
|
+
options.onAfterWrite?.(data);
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
backend.onResponse = (data) => {
|
|
516
|
+
if (ptyHandle?.alive) ptyHandle.write(new TextDecoder().decode(data));
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function press(key) {
|
|
520
|
+
if (closed) throw new Error("Terminal is closed");
|
|
521
|
+
if (!ptyHandle) throw new Error("No PTY spawned — call spawn() first");
|
|
522
|
+
const desc = parseKey(key);
|
|
523
|
+
const encoded = backend.encodeKey(desc);
|
|
524
|
+
if (encoded.length > 0) ptyHandle.write(new TextDecoder().decode(encoded));
|
|
525
|
+
else {
|
|
526
|
+
const ansi = keyToAnsi(desc);
|
|
527
|
+
if (ansi) ptyHandle.write(ansi);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function type(text) {
|
|
531
|
+
if (closed) throw new Error("Terminal is closed");
|
|
532
|
+
if (!ptyHandle) throw new Error("No PTY spawned — call spawn() first");
|
|
533
|
+
ptyHandle.write(text);
|
|
534
|
+
}
|
|
535
|
+
/** Encode SGR button byte: button number + modifier bits. */
|
|
536
|
+
function sgrButton(options) {
|
|
537
|
+
let btn = options?.button ?? 0;
|
|
538
|
+
if (options?.shift) btn += 4;
|
|
539
|
+
if (options?.alt) btn += 8;
|
|
540
|
+
if (options?.ctrl) btn += 16;
|
|
541
|
+
return btn;
|
|
542
|
+
}
|
|
543
|
+
function requirePty() {
|
|
544
|
+
if (closed) throw new Error("Terminal is closed");
|
|
545
|
+
if (!ptyHandle) throw new Error("No PTY spawned — call spawn() first");
|
|
546
|
+
return ptyHandle;
|
|
547
|
+
}
|
|
548
|
+
function click(x, y, options) {
|
|
549
|
+
const pty = requirePty();
|
|
550
|
+
const col = x + 1;
|
|
551
|
+
const row = y + 1;
|
|
552
|
+
const btn = sgrButton(options);
|
|
553
|
+
pty.write(`\x1b[<${btn};${col};${row}M`);
|
|
554
|
+
pty.write(`\x1b[<${btn};${col};${row}m`);
|
|
555
|
+
}
|
|
556
|
+
async function dblclick(x, y, options) {
|
|
557
|
+
const delay = options?.delay ?? 50;
|
|
558
|
+
click(x, y, options);
|
|
559
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
560
|
+
click(x, y, options);
|
|
561
|
+
}
|
|
562
|
+
function mouseDown(x, y, options) {
|
|
563
|
+
const pty = requirePty();
|
|
564
|
+
const btn = sgrButton(options);
|
|
565
|
+
pty.write(`\x1b[<${btn};${x + 1};${y + 1}M`);
|
|
566
|
+
}
|
|
567
|
+
function mouseUp(x, y, options) {
|
|
568
|
+
const pty = requirePty();
|
|
569
|
+
const btn = sgrButton(options);
|
|
570
|
+
pty.write(`\x1b[<${btn};${x + 1};${y + 1}m`);
|
|
571
|
+
}
|
|
572
|
+
function mouseMove(x, y, options) {
|
|
573
|
+
const pty = requirePty();
|
|
574
|
+
const btn = 32 + sgrButton(options);
|
|
575
|
+
pty.write(`\x1b[<${btn};${x + 1};${y + 1}M`);
|
|
576
|
+
}
|
|
577
|
+
function wheel(deltaX, deltaY, options) {
|
|
578
|
+
const pty = requirePty();
|
|
579
|
+
const col = (options?.x ?? 0) + 1;
|
|
580
|
+
const row = (options?.y ?? 0) + 1;
|
|
581
|
+
let mods = 0;
|
|
582
|
+
if (options?.shift) mods += 4;
|
|
583
|
+
if (options?.alt) mods += 8;
|
|
584
|
+
if (options?.ctrl) mods += 16;
|
|
585
|
+
if (deltaY < 0) for (let i = 0; i < Math.abs(deltaY); i++) pty.write(`\x1b[<${64 + mods};${col};${row}M`);
|
|
586
|
+
else if (deltaY > 0) for (let i = 0; i < deltaY; i++) pty.write(`\x1b[<${65 + mods};${col};${row}M`);
|
|
587
|
+
}
|
|
588
|
+
/** @deprecated Use `await expect(term.screen).toContainText("text", { timeout })` instead. */
|
|
589
|
+
async function waitFor(text, timeout = DEFAULT_WAIT_TIMEOUT) {
|
|
590
|
+
const start = Date.now();
|
|
591
|
+
while (Date.now() - start < timeout) {
|
|
592
|
+
if (getText().includes(text)) return;
|
|
593
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
|
|
594
|
+
}
|
|
595
|
+
throw new Error(`Timeout waiting for "${text}" after ${timeout}ms`);
|
|
596
|
+
}
|
|
597
|
+
async function waitForStable(stableMs = DEFAULT_STABLE_MS, timeout = DEFAULT_WAIT_TIMEOUT) {
|
|
598
|
+
const start = Date.now();
|
|
599
|
+
let lastContent = "";
|
|
600
|
+
let stableStart = Date.now();
|
|
601
|
+
while (Date.now() - start < timeout) {
|
|
602
|
+
const content = getText();
|
|
603
|
+
if (content === lastContent) {
|
|
604
|
+
if (Date.now() - stableStart >= stableMs) return;
|
|
605
|
+
} else {
|
|
606
|
+
lastContent = content;
|
|
607
|
+
stableStart = Date.now();
|
|
608
|
+
}
|
|
609
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
|
|
610
|
+
}
|
|
611
|
+
throw new Error(`Terminal did not stabilize within ${timeout}ms`);
|
|
612
|
+
}
|
|
613
|
+
function find(text) {
|
|
614
|
+
const lines = getText().split("\n");
|
|
615
|
+
for (let row = 0; row < lines.length; row++) {
|
|
616
|
+
const col = lines[row].indexOf(text);
|
|
617
|
+
if (col !== -1) return {
|
|
618
|
+
row,
|
|
619
|
+
col,
|
|
620
|
+
text
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
function findAll(pattern) {
|
|
626
|
+
const lines = getText().split("\n");
|
|
627
|
+
const results = [];
|
|
628
|
+
for (let row = 0; row < lines.length; row++) {
|
|
629
|
+
const line = lines[row];
|
|
630
|
+
const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
|
|
631
|
+
let match;
|
|
632
|
+
while ((match = re.exec(line)) !== null) {
|
|
633
|
+
results.push({
|
|
634
|
+
row,
|
|
635
|
+
col: match.index,
|
|
636
|
+
text: match[0]
|
|
637
|
+
});
|
|
638
|
+
if (match[0].length === 0) re.lastIndex++;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return results;
|
|
642
|
+
}
|
|
643
|
+
function screenshot(svgOptions) {
|
|
644
|
+
return screenshotSvg(terminal, svgOptions);
|
|
645
|
+
}
|
|
646
|
+
function screenshotAsPng(pngOptions) {
|
|
647
|
+
return screenshotPng(terminal, pngOptions);
|
|
648
|
+
}
|
|
649
|
+
function screenshotOptionsToPng(opts) {
|
|
650
|
+
if (!opts) return void 0;
|
|
651
|
+
return {
|
|
652
|
+
...opts,
|
|
653
|
+
scale: opts.dpr ?? 2
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Auto-picking screenshot — see Terminal.screenshot in types.ts for the
|
|
658
|
+
* decision tree.
|
|
659
|
+
*
|
|
660
|
+
* `opts.renderer` is a *force* override:
|
|
661
|
+
* - `canvas` — always the native-canvas path (`screenshotCanvasPng`).
|
|
662
|
+
* - `resvg` — always the resvg SVG → PNG path (`screenshotPng`).
|
|
663
|
+
* - `auto` / unset — the decision tree below:
|
|
664
|
+
* 1. Backend has its own raster renderer (ghostty) — use it directly.
|
|
665
|
+
* 2. `@termless/ghostty` is installed — proxy via cellsToAnsi + renderAnsiPng.
|
|
666
|
+
* 3. Fall back to resvg-based SVG → PNG (cross-platform safe; lower fidelity).
|
|
667
|
+
*/
|
|
668
|
+
async function screenshotAuto(opts) {
|
|
669
|
+
if (opts?.renderer === "canvas") return screenshotAsCanvasPng(opts);
|
|
670
|
+
if (opts?.renderer === "resvg") return screenshotPng(terminal, screenshotOptionsToPng(opts));
|
|
671
|
+
if (opts?.renderer === "swash") return screenshotAsSwashPng(opts);
|
|
672
|
+
if (opts?.renderer === "browser") return screenshotAsBrowserPng(opts);
|
|
673
|
+
if (backend.screenshot) return backend.screenshot(opts);
|
|
674
|
+
try {
|
|
675
|
+
const ghosttyMod = await import("./src-e33Y6kNJ.mjs");
|
|
676
|
+
const ansi = ghosttyMod.cellsToAnsi(backend, {
|
|
677
|
+
cols: opts?.cols ?? cols,
|
|
678
|
+
rows: opts?.rows ?? rows
|
|
679
|
+
});
|
|
680
|
+
return ghosttyMod.renderAnsiPng(ansi, {
|
|
681
|
+
cols,
|
|
682
|
+
rows,
|
|
683
|
+
...opts
|
|
684
|
+
});
|
|
685
|
+
} catch (err) {
|
|
686
|
+
if (err instanceof Error && /Cannot find (module|package)|MODULE_NOT_FOUND|ERR_MODULE_NOT_FOUND/.test(err.message)) return screenshotPng(terminal, screenshotOptionsToPng(opts));
|
|
687
|
+
throw err;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Explicit swash path — rasterizes the cell grid directly via
|
|
692
|
+
* `@termless/swash-render` (pure-Rust swash). The cells path is swash's
|
|
693
|
+
* fidelity edge: color-emoji glyphs composite their native color bitmaps,
|
|
694
|
+
* which the SVG-flattening canvas / resvg paths lose. Fails loudly if the
|
|
695
|
+
* native binding is not built.
|
|
696
|
+
*/
|
|
697
|
+
async function screenshotAsSwashPng(opts) {
|
|
698
|
+
const { selectRasterizer } = await import("./rasterizer-BRXrDdWx.mjs");
|
|
699
|
+
const rasterizer = await selectRasterizer("swash");
|
|
700
|
+
if (!rasterizer.cellsToPng) throw new Error("swash renderer did not expose a cells path");
|
|
701
|
+
const scale = opts?.dpr ?? 2;
|
|
702
|
+
return rasterizer.cellsToPng(terminal, scale);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Explicit browser path — rasterizes the SVG via headless Chromium
|
|
706
|
+
* (Playwright). The absolute-max-fidelity renderer: a real browser text
|
|
707
|
+
* engine gives Chrome-identical shaping, font fallback, ligatures, and
|
|
708
|
+
* color emoji. Opt-in only — Playwright is an optional dependency, and
|
|
709
|
+
* `selectRasterizer("browser")` throws a clear install hint if absent.
|
|
710
|
+
*/
|
|
711
|
+
async function screenshotAsBrowserPng(opts) {
|
|
712
|
+
const { selectRasterizer } = await import("./rasterizer-BRXrDdWx.mjs");
|
|
713
|
+
const rasterizer = await selectRasterizer("browser");
|
|
714
|
+
const scale = opts?.dpr ?? 2;
|
|
715
|
+
const svg = screenshot({
|
|
716
|
+
embedFonts: true,
|
|
717
|
+
...opts?.fontFamily ? { fontFamily: opts.fontFamily } : {},
|
|
718
|
+
...opts?.fontSize ? { fontSize: opts.fontSize } : {},
|
|
719
|
+
...opts?.cellWidth ? { cellWidth: opts.cellWidth } : {},
|
|
720
|
+
...opts?.cellHeight ? { cellHeight: opts.cellHeight } : {}
|
|
721
|
+
});
|
|
722
|
+
try {
|
|
723
|
+
return await rasterizer.toPng(svg, scale);
|
|
724
|
+
} finally {
|
|
725
|
+
await rasterizer.dispose?.();
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Explicit native-canvas path — always routes through `@termless/ghostty`'s
|
|
730
|
+
* `renderAnsiPng`. Fails loudly if the package is missing.
|
|
731
|
+
*/
|
|
732
|
+
async function screenshotAsCanvasPng(opts) {
|
|
733
|
+
const ghosttyMod = await import("./src-e33Y6kNJ.mjs");
|
|
734
|
+
const ansi = ghosttyMod.cellsToAnsi(backend, {
|
|
735
|
+
cols: opts?.cols ?? cols,
|
|
736
|
+
rows: opts?.rows ?? rows
|
|
737
|
+
});
|
|
738
|
+
return ghosttyMod.renderAnsiPng(ansi, {
|
|
739
|
+
cols,
|
|
740
|
+
rows,
|
|
741
|
+
...opts
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
function resize(newCols, newRows) {
|
|
745
|
+
if (closed) throw new Error("Terminal is closed");
|
|
746
|
+
cols = newCols;
|
|
747
|
+
rows = newRows;
|
|
748
|
+
backend.resize(newCols, newRows);
|
|
749
|
+
if (ptyHandle?.alive) ptyHandle.resize(newCols, newRows);
|
|
750
|
+
}
|
|
751
|
+
async function close() {
|
|
752
|
+
if (closed) return;
|
|
753
|
+
closed = true;
|
|
754
|
+
backend.onResponse = void 0;
|
|
755
|
+
if (ptyHandle) {
|
|
756
|
+
await ptyHandle.close();
|
|
757
|
+
ptyHandle = null;
|
|
758
|
+
}
|
|
759
|
+
backend.destroy();
|
|
760
|
+
}
|
|
761
|
+
const terminal = {
|
|
762
|
+
get cols() {
|
|
763
|
+
return cols;
|
|
764
|
+
},
|
|
765
|
+
get rows() {
|
|
766
|
+
return rows;
|
|
767
|
+
},
|
|
768
|
+
get backend() {
|
|
769
|
+
return backend;
|
|
770
|
+
},
|
|
771
|
+
getText,
|
|
772
|
+
getTextRange,
|
|
773
|
+
getCell,
|
|
774
|
+
getLine,
|
|
775
|
+
getLines,
|
|
776
|
+
getCursor,
|
|
777
|
+
getMode,
|
|
778
|
+
getTitle,
|
|
779
|
+
getScrollback,
|
|
780
|
+
get screen() {
|
|
781
|
+
return createScreenView(backend);
|
|
782
|
+
},
|
|
783
|
+
get scrollback() {
|
|
784
|
+
return createScrollbackView(backend);
|
|
785
|
+
},
|
|
786
|
+
get buffer() {
|
|
787
|
+
return createBufferView(backend);
|
|
788
|
+
},
|
|
789
|
+
get viewport() {
|
|
790
|
+
return createViewportView(backend);
|
|
791
|
+
},
|
|
792
|
+
get out() {
|
|
793
|
+
return out;
|
|
794
|
+
},
|
|
795
|
+
row(n) {
|
|
796
|
+
const { totalLines, screenLines } = backend.getScrollback();
|
|
797
|
+
const base = totalLines - screenLines;
|
|
798
|
+
const screenRow = n >= 0 ? n : screenLines + n;
|
|
799
|
+
return createRowView(backend, base + screenRow, screenRow);
|
|
800
|
+
},
|
|
801
|
+
cell(r, c) {
|
|
802
|
+
const { totalLines, screenLines } = backend.getScrollback();
|
|
803
|
+
const base = totalLines - screenLines;
|
|
804
|
+
const screenRow = r >= 0 ? r : screenLines + r;
|
|
805
|
+
return createCellView(backend.getCell(base + screenRow, c), screenRow, c);
|
|
806
|
+
},
|
|
807
|
+
range(r1, c1, r2, c2) {
|
|
808
|
+
return createRangeView(backend, r1, c1, r2, c2);
|
|
809
|
+
},
|
|
810
|
+
firstRow() {
|
|
811
|
+
return this.row(0);
|
|
812
|
+
},
|
|
813
|
+
lastRow() {
|
|
814
|
+
return this.row(-1);
|
|
815
|
+
},
|
|
816
|
+
feed,
|
|
817
|
+
spawn,
|
|
818
|
+
get alive() {
|
|
819
|
+
return ptyHandle?.alive ?? false;
|
|
820
|
+
},
|
|
821
|
+
get exitInfo() {
|
|
822
|
+
return ptyHandle?.exitInfo ?? null;
|
|
823
|
+
},
|
|
824
|
+
press,
|
|
825
|
+
type,
|
|
826
|
+
clipboardWrites,
|
|
827
|
+
click,
|
|
828
|
+
dblclick,
|
|
829
|
+
mouseDown,
|
|
830
|
+
mouseUp,
|
|
831
|
+
mouseMove,
|
|
832
|
+
wheel,
|
|
833
|
+
waitFor,
|
|
834
|
+
waitForStable,
|
|
835
|
+
find,
|
|
836
|
+
findAll,
|
|
837
|
+
screenshotSvg: screenshot,
|
|
838
|
+
screenshotPng: screenshotAsPng,
|
|
839
|
+
screenshot: screenshotAuto,
|
|
840
|
+
screenshotCanvasPng: screenshotAsCanvasPng,
|
|
841
|
+
resize,
|
|
842
|
+
close,
|
|
843
|
+
[Symbol.asyncDispose]: close
|
|
844
|
+
};
|
|
845
|
+
return terminal;
|
|
846
|
+
}
|
|
847
|
+
var POLL_INTERVAL, DEFAULT_COLS, DEFAULT_ROWS, DEFAULT_WAIT_TIMEOUT, DEFAULT_STABLE_MS, encoder;
|
|
848
|
+
var init_terminal = __esmMin((() => {
|
|
849
|
+
init_key_mapping();
|
|
850
|
+
init_pty();
|
|
851
|
+
init_svg();
|
|
852
|
+
init_png();
|
|
853
|
+
init_views();
|
|
854
|
+
POLL_INTERVAL = 50;
|
|
855
|
+
DEFAULT_COLS = 80;
|
|
856
|
+
DEFAULT_ROWS = 24;
|
|
857
|
+
DEFAULT_WAIT_TIMEOUT = 5e3;
|
|
858
|
+
DEFAULT_STABLE_MS = 200;
|
|
859
|
+
encoder = new TextEncoder();
|
|
860
|
+
}));
|
|
861
|
+
//#endregion
|
|
862
|
+
//#region ../termless/src/backend/backends.ts
|
|
863
|
+
/**
|
|
864
|
+
* Backend registry — one function, everything derived.
|
|
865
|
+
*
|
|
866
|
+
* @example
|
|
867
|
+
* ```typescript
|
|
868
|
+
* import { backend } from "termless"
|
|
869
|
+
*
|
|
870
|
+
* const b = await backend("ghostty")
|
|
871
|
+
* const b = await backend("xtermjs", { version: "5.4.0" })
|
|
872
|
+
* ```
|
|
873
|
+
*/
|
|
874
|
+
function manifest() {
|
|
875
|
+
if (_manifest) return _manifest;
|
|
876
|
+
const raw = JSON.parse(readFileSync(MANIFEST_PATH, "utf-8"));
|
|
877
|
+
const backends = {};
|
|
878
|
+
for (const [name, entry] of Object.entries(raw.backends)) backends[name] = {
|
|
879
|
+
package: entry.package,
|
|
880
|
+
upstream: entry.upstream ?? null,
|
|
881
|
+
version: entry.upstreamVersion ?? null,
|
|
882
|
+
type: entry.type,
|
|
883
|
+
default: entry.default,
|
|
884
|
+
platforms: entry.platforms,
|
|
885
|
+
label: entry.label,
|
|
886
|
+
description: entry.description,
|
|
887
|
+
url: entry.url,
|
|
888
|
+
caveat: entry.caveat,
|
|
889
|
+
slug: entry.slug,
|
|
890
|
+
terminal: entry.terminal
|
|
891
|
+
};
|
|
892
|
+
_manifest = {
|
|
893
|
+
version: raw.version,
|
|
894
|
+
backends
|
|
895
|
+
};
|
|
896
|
+
return _manifest;
|
|
897
|
+
}
|
|
898
|
+
function hasFilesWithExt(dir, ext, subdirs = []) {
|
|
899
|
+
const dirs = [dir, ...subdirs.map((s) => join(dir, s))];
|
|
900
|
+
for (const d of dirs) {
|
|
901
|
+
if (!existsSync(d)) continue;
|
|
902
|
+
try {
|
|
903
|
+
for (const f of readdirSync(d)) if (f.endsWith(ext)) return true;
|
|
904
|
+
} catch {}
|
|
905
|
+
}
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
function resolveModule(pkg, opts) {
|
|
909
|
+
return async () => {
|
|
910
|
+
const mod = await import(pkg);
|
|
911
|
+
return typeof mod.resolve === "function" ? mod.resolve(opts) : mod[Object.keys(mod).find((k) => k.startsWith("create"))](opts);
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
/** Run a backend's build/build.sh, falling back to nix if tools aren't in PATH. */
|
|
915
|
+
function runBuildScript(pkgDir) {
|
|
916
|
+
if (!existsSync(join(pkgDir, "build", "build.sh"))) return;
|
|
917
|
+
console.log(` Building in ${pkgDir}...`);
|
|
918
|
+
try {
|
|
919
|
+
execSync(`bash build/build.sh`, {
|
|
920
|
+
cwd: pkgDir,
|
|
921
|
+
stdio: "inherit"
|
|
922
|
+
});
|
|
923
|
+
} catch {
|
|
924
|
+
const flakeDir = PACKAGE_ROOT;
|
|
925
|
+
if (existsSync(join(flakeDir, "flake.nix"))) execSync(`nix develop ${flakeDir} --command bash build/build.sh`, {
|
|
926
|
+
cwd: pkgDir,
|
|
927
|
+
stdio: "inherit"
|
|
928
|
+
});
|
|
929
|
+
else throw new Error(`Build failed. Install dependencies or use the nix flake: nix develop`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
/** Build a backend's native artifacts if not already ready. */
|
|
933
|
+
function buildBackend(name) {
|
|
934
|
+
const e = manifest().backends[name];
|
|
935
|
+
if (!e) throw new Error(`Unknown backend: ${name}`);
|
|
936
|
+
const type = backendTypes[e.type];
|
|
937
|
+
if (!type) return;
|
|
938
|
+
const pkgDir = findPackageDir(e.package);
|
|
939
|
+
if (!pkgDir) return;
|
|
940
|
+
if (!type.isReady(pkgDir)) type.build(pkgDir);
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Resolve a backend by name. The one function you need.
|
|
944
|
+
*
|
|
945
|
+
* @example
|
|
946
|
+
* ```typescript
|
|
947
|
+
* const b = await backend("ghostty")
|
|
948
|
+
* const b = await backend("xtermjs", { version: "5.4.0" })
|
|
949
|
+
* ```
|
|
950
|
+
*/
|
|
951
|
+
async function backend(name, opts) {
|
|
952
|
+
const m = manifest();
|
|
953
|
+
const entry = m.backends[name];
|
|
954
|
+
if (!entry) throw new Error(`Unknown backend "${name}". Available: ${Object.keys(m.backends).join(", ")}`);
|
|
955
|
+
const type = backendTypes[entry.type];
|
|
956
|
+
if (!type) throw new Error(`Unknown backend type "${entry.type}" for "${name}"`);
|
|
957
|
+
if (opts?.version && opts.version !== entry.version) return resolveVersioned(name, entry, type, opts.version, opts);
|
|
958
|
+
try {
|
|
959
|
+
import.meta.resolve(entry.package);
|
|
960
|
+
} catch {
|
|
961
|
+
throw new Error(`Backend "${name}" is not installed.\nRun: bunx termless backend install ${name}`);
|
|
962
|
+
}
|
|
963
|
+
const pkgDir = findPackageDir(entry.package);
|
|
964
|
+
if (pkgDir && !type.isReady(pkgDir)) throw new Error(`Backend "${name}" is installed but not built.\nRun: cd ${pkgDir} && ${getBuildHint(entry)}`);
|
|
965
|
+
return type.resolve(entry.package, opts);
|
|
966
|
+
}
|
|
967
|
+
/** Check if a backend is installed and ready. */
|
|
968
|
+
function isReady(name) {
|
|
969
|
+
const entry = manifest().backends[name];
|
|
970
|
+
if (!entry) return false;
|
|
971
|
+
try {
|
|
972
|
+
import.meta.resolve(entry.package);
|
|
973
|
+
} catch {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
const type = backendTypes[entry.type];
|
|
977
|
+
if (!type) return false;
|
|
978
|
+
const pkgDir = findPackageDir(entry.package);
|
|
979
|
+
return pkgDir ? type.isReady(pkgDir) : false;
|
|
980
|
+
}
|
|
981
|
+
/** List all backend names. */
|
|
982
|
+
function backends() {
|
|
983
|
+
return Object.keys(manifest().backends);
|
|
984
|
+
}
|
|
985
|
+
/** Get entry for a backend. */
|
|
986
|
+
function entry(name) {
|
|
987
|
+
return manifest().backends[name];
|
|
988
|
+
}
|
|
989
|
+
/** Create a Terminal by backend name. */
|
|
990
|
+
async function createTerminalByName(name, opts) {
|
|
991
|
+
return createTerminal({
|
|
992
|
+
backend: await backend(name, opts),
|
|
993
|
+
...opts
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
async function resolveVersioned(name, entry, type, version, opts) {
|
|
997
|
+
if (entry.type === "native") throw new Error(`Version-pinned resolution for native backend "${name}" requires nix.\nRun: nix develop .#${name}-${version.replace(/\./g, "_")}`);
|
|
998
|
+
if (!entry.upstream) throw new Error(`Backend "${name}" has no upstream to version-pin.`);
|
|
999
|
+
const cacheDir = ensureCachedVersion(entry.upstream, version);
|
|
1000
|
+
const origNodePath = process.env.NODE_PATH;
|
|
1001
|
+
process.env.NODE_PATH = join(cacheDir, "node_modules") + (origNodePath ? `:${origNodePath}` : "");
|
|
1002
|
+
try {
|
|
1003
|
+
return await type.resolve(entry.package, opts);
|
|
1004
|
+
} finally {
|
|
1005
|
+
if (origNodePath) process.env.NODE_PATH = origNodePath;
|
|
1006
|
+
else delete process.env.NODE_PATH;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Install an upstream package at a specific version to the cache directory.
|
|
1011
|
+
* Returns the cache dir path (contains node_modules/).
|
|
1012
|
+
* Shared by backend() version-pinned resolution and census versioned runs.
|
|
1013
|
+
*/
|
|
1014
|
+
function ensureCachedVersion(upstream, version) {
|
|
1015
|
+
const cacheDir = join(CACHE_DIR, `${upstream.replace(/[/@]/g, "_")}-${version}`);
|
|
1016
|
+
if (!existsSync(join(cacheDir, "node_modules"))) {
|
|
1017
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
1018
|
+
writeFileSync(join(cacheDir, "package.json"), JSON.stringify({
|
|
1019
|
+
private: true,
|
|
1020
|
+
dependencies: { [upstream]: version }
|
|
1021
|
+
}));
|
|
1022
|
+
execSync("bun install --no-save", {
|
|
1023
|
+
cwd: cacheDir,
|
|
1024
|
+
stdio: "pipe"
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
return cacheDir;
|
|
1028
|
+
}
|
|
1029
|
+
function findPackageDir(packageName) {
|
|
1030
|
+
try {
|
|
1031
|
+
let dir = dirname(fileURLToPath(import.meta.resolve(packageName)));
|
|
1032
|
+
for (let i = 0; i < 10; i++) {
|
|
1033
|
+
if (existsSync(join(dir, "package.json"))) try {
|
|
1034
|
+
if (JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")).name === packageName) return dir;
|
|
1035
|
+
} catch {}
|
|
1036
|
+
const parent = dirname(dir);
|
|
1037
|
+
if (parent === dir) break;
|
|
1038
|
+
dir = parent;
|
|
1039
|
+
}
|
|
1040
|
+
} catch {}
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
function getBuildHint(entry) {
|
|
1044
|
+
if (entry.type === "native") return "cargo build --release";
|
|
1045
|
+
if (entry.type === "wasm") return "bash build/build.sh";
|
|
1046
|
+
return "bun install";
|
|
1047
|
+
}
|
|
1048
|
+
var PACKAGE_ROOT, MANIFEST_PATH, _manifest, backendTypes, CACHE_DIR;
|
|
1049
|
+
var init_backends = __esmMin((() => {
|
|
1050
|
+
init_terminal();
|
|
1051
|
+
PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
1052
|
+
MANIFEST_PATH = join(PACKAGE_ROOT, "backends.json");
|
|
1053
|
+
_manifest = null;
|
|
1054
|
+
backendTypes = {
|
|
1055
|
+
js: {
|
|
1056
|
+
isReady: () => true,
|
|
1057
|
+
build: () => {},
|
|
1058
|
+
resolve: async (pkg, opts) => resolveModule(pkg, opts)()
|
|
1059
|
+
},
|
|
1060
|
+
wasm: {
|
|
1061
|
+
isReady: (pkgDir) => {
|
|
1062
|
+
return hasFilesWithExt(pkgDir, ".wasm", ["wasm", "build"]) || !existsSync(join(pkgDir, "build"));
|
|
1063
|
+
},
|
|
1064
|
+
build: (pkgDir) => runBuildScript(pkgDir),
|
|
1065
|
+
resolve: async (pkg, opts) => resolveModule(pkg, opts)()
|
|
1066
|
+
},
|
|
1067
|
+
native: {
|
|
1068
|
+
isReady: (pkgDir) => hasFilesWithExt(pkgDir, ".node", ["build", "native"]),
|
|
1069
|
+
build: (pkgDir) => runBuildScript(pkgDir),
|
|
1070
|
+
resolve: async (pkg, opts) => resolveModule(pkg, opts)()
|
|
1071
|
+
},
|
|
1072
|
+
os: {
|
|
1073
|
+
isReady: () => true,
|
|
1074
|
+
build: () => {},
|
|
1075
|
+
resolve: async (pkg, opts) => resolveModule(pkg, opts)()
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
CACHE_DIR = join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "termless", "backends");
|
|
1079
|
+
}));
|
|
1080
|
+
//#endregion
|
|
1081
|
+
export { screenshotPng as _, ensureCachedVersion as a, isReady as c, init_terminal as d, createCellView as f, init_png as g, init_views as h, createTerminalByName as i, manifest as l, createRowView as m, backends as n, entry as o, createRegionView as p, buildBackend as r, init_backends as s, backend as t, createTerminal as u };
|
|
1082
|
+
|
|
1083
|
+
//# sourceMappingURL=backends-DIVYzKqd.mjs.map
|