New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

run-pty

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

run-pty - npm Package Compare versions

Comparing version

to
2.3.0-beta.1

10

package.json
{
"name": "run-pty",
"version": "2.2.0",
"version": "2.3.0-beta.1",
"author": "Simon Lydell",

@@ -32,5 +32,5 @@ "license": "MIT",

"@types/jest": "26.0.20",
"@typescript-eslint/eslint-plugin": "4.14.0",
"@typescript-eslint/parser": "4.14.0",
"eslint": "7.18.0",
"@typescript-eslint/eslint-plugin": "4.14.1",
"@typescript-eslint/parser": "4.14.1",
"eslint": "7.19.0",
"eslint-plugin-jest": "24.1.3",

@@ -43,3 +43,3 @@ "jest": "26.6.3",

"scripts": {
"start": "node run-pty.js % cat % false % echo hello world % ping localhost % node get-cursor-position.js % node test-keys.js % node signals.js % node slow-kill.js % node slow-kill.js 2000 \"Shutting down…\" % make watch",
"start": "node run-pty.js % cat % false % echo hello world % ping localhost % node get-cursor-position.js % node test-keys.js % node signals.js % node slow-kill.js % node slow-kill.js 2000 \"Shutting down…\" % make watch % make signals",
"example": "node run-pty.js example.json",

@@ -46,0 +46,0 @@ "test": "prettier --check . && eslint . --report-unused-disable-directives && tsc && jest",

@@ -38,3 +38,5 @@ # run-pty

[1-2] focus command
[1-2] focus command (or click)
[enter] focus selected command
[↑/↓] move selection
[ctrl+c] kill all

@@ -93,3 +95,5 @@ ```

[1-2] focus command
[1-2] focus command (or click)
[enter] focus selected command
[↑/↓] move selection
[ctrl+c] kill all

@@ -96,0 +100,0 @@ ```

@@ -12,3 +12,3 @@ #!/usr/bin/env node

| { tag: "Running", terminal: import("node-pty").IPty }
| { tag: "Killing", terminal: import("node-pty").IPty, slow: boolean }
| { tag: "Killing", terminal: import("node-pty").IPty, slow: boolean, lastKillPress: number | undefined }
| { tag: "Exit", exitCode: number }

@@ -23,6 +23,9 @@ } Status

// node-pty does not support kill signals on Windows.
// This is the same check that node-pty uses.
const IS_WINDOWS = process.platform === "win32";
const SLOW_KILL = 100; // ms
// This is apparently what Windows uses for double clicks.
const DOUBLE_PRESS = 500; // ms
const MAX_HISTORY_DEFAULT = 1000000;

@@ -43,2 +46,4 @@

dashboard: "ctrl+z",
navigate: "↑/↓",
enter: "enter",
};

@@ -50,2 +55,11 @@

dashboard: "\x1a",
// https://vi.stackexchange.com/questions/15324/up-arrow-key-code-why-a-becomes-oa
up: "\x1B[A",
upAlt: "\x1BOA",
upVim: "k",
down: "\x1B[B",
downAlt: "\x1BOB",
downVim: "j",
enter: "\r",
enterVim: "o",
};

@@ -61,2 +75,4 @@

const DISABLE_BRACKETED_PASTE_MODE = "\x1B[?2004l";
const ENABLE_MOUSE = "\x1B[?1000;1006h";
const DISABLE_MOUSE = "\x1B[?1000;1006l";
const RESET_COLOR = "\x1B[m";

@@ -83,3 +99,4 @@ const CLEAR = IS_WINDOWS ? "\x1B[2J\x1B[0f" : "\x1B[2J\x1B[3J\x1B[H";

const exitIndicator = (exitCode) =>
exitCode === 0
// 130 commonly means exit by ctrl+c.
exitCode === 0 || exitCode === 130
? NO_COLOR

@@ -118,8 +135,15 @@ ? "●"

* @param {string} string
* @param {{ pad?: boolean }} pad
* @returns {string}
*/
const shortcut = (string, { pad = true } = {}) =>
dim("[") +
bold(string) +
dim("]") +
const invert = (string) =>
NO_COLOR ? string : `\x1B[7m${string}${RESET_COLOR}`;
/**
* @param {string} string
* @param {{ pad?: boolean, highlight?: boolean }} pad
*/
const shortcut = (string, { pad = true, highlight = false } = {}) =>
dim(NO_COLOR && highlight ? "<" : "[") +
bold(highlight ? invert(string) : string) +
dim(NO_COLOR && highlight ? ">" : "]") +
(pad ? " ".repeat(Math.max(0, KEYS.kill.length - string.length)) : "");

@@ -163,7 +187,2 @@

${shortcut(summarizeLabels(ALL_LABELS.split("")))} focus command
${shortcut(KEYS.dashboard)} dashboard
${shortcut(KEYS.kill)} kill focused/all
${shortcut(KEYS.restart)} restart killed/exited command
Separate the commands with a character of choice:

@@ -200,3 +219,3 @@

commands.some((command) => command.status.tag === "Killing")
? "force kill all"
? `kill all ${dim("(double-press to force) ")}`
: commands.every((command) => command.status.tag === "Exit")

@@ -209,9 +228,13 @@ ? "exit"

* @param {number} width
* @param {boolean} attemptedKillAll
* @param {number | undefined} cursorIndex
* @returns {Array<{ line: string, length: number }>}
*/
const drawDashboard = (commands, width, attemptedKillAll) => {
const lines = commands.map((command) => {
const drawDashboardCommandLines = (commands, width, cursorIndex) => {
const lines = commands.map((command, index) => {
const [icon, status] = statusText(command.status, command.statusFromRules);
return {
label: shortcut(command.label || " ", { pad: false }),
label: shortcut(command.label || " ", {
pad: false,
highlight: index === cursorIndex,
}),
icon,

@@ -228,30 +251,51 @@ status,

const finalLines = lines
.map(({ label, icon, status, title }) => {
const separator = " ";
const start = truncate(`${label}${separator}${icon}`, width);
const startLength =
removeGraphicRenditions(label).length + separator.length + ICON_WIDTH;
const end =
status === undefined
? title
: `${status.padEnd(widestStatus, " ")}${separator}${title}`;
return `${start}${RESET_COLOR}${cursorHorizontalAbsolute(
return lines.map(({ label, icon, status, title }) => {
const separator = " ";
const start = truncate(`${label}${separator}${icon}`, width);
const startLength =
removeGraphicRenditions(label).length + separator.length + ICON_WIDTH;
const end =
status === undefined
? title
: `${status.padEnd(widestStatus, " ")}${separator}${title}`;
const truncatedEnd = truncate(end, width - startLength - separator.length);
const length =
startLength +
separator.length +
removeGraphicRenditions(truncatedEnd).length;
return {
line: `${start}${RESET_COLOR}${cursorHorizontalAbsolute(
startLength + 1
)}${CLEAR_RIGHT}${separator}${truncate(
end,
width - startLength - separator.length
)}${RESET_COLOR}`;
})
)}${CLEAR_RIGHT}${separator}${truncatedEnd}${RESET_COLOR}`,
length,
};
});
};
/**
* @param {Array<Command>} commands
* @param {number} width
* @param {boolean} attemptedKillAll
* @param {number | undefined} cursorIndex
* @returns {string}
*/
const drawDashboard = (commands, width, attemptedKillAll, cursorIndex) => {
const done =
attemptedKillAll &&
commands.every((command) => command.status.tag === "Exit");
const finalLines = drawDashboardCommandLines(
commands,
width,
done ? undefined : cursorIndex
)
.map(({ line }) => line)
.join("\n");
const label = summarizeLabels(commands.map((command) => command.label));
if (
attemptedKillAll &&
commands.every((command) => command.status.tag === "Exit")
) {
if (done) {
return `${finalLines}\n`;
}
const label = summarizeLabels(commands.map((command) => command.label));
// Newlines at the end are wanted here.

@@ -261,3 +305,5 @@ return `

${shortcut(label)} focus command
${shortcut(label)} focus command ${dim("(or click)")}
${shortcut(KEYS.enter)} focus selected command
${shortcut(KEYS.navigate)} move selection
${shortcut(KEYS.kill)} ${killAllLabel(commands)}

@@ -315,3 +361,3 @@ `.trimStart();

${shortcut(KEYS.kill)} force kill ${dim(`(pid ${pid})`)}
${shortcut(KEYS.kill)} kill ${dim(`(double-press to force) (pid ${pid})`)}
${shortcut(KEYS.dashboard)} dashboard

@@ -829,3 +875,2 @@ `;

kill() {
// https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
switch (this.status.tag) {

@@ -837,2 +882,3 @@ case "Running":

slow: false,
lastKillPress: undefined,
};

@@ -845,20 +891,23 @@ setTimeout(() => {

}
}, 100);
if (IS_WINDOWS) {
this.status.terminal.kill();
} else {
// SIGHUP causes a silent exit for `npm run`.
this.status.terminal.kill("SIGHUP");
// SIGTERM is needed for some programs (but is noisy for `npm run`).
this.status.terminal.kill("SIGTERM");
}
}, SLOW_KILL);
this.status.terminal.write(KEY_CODES.kill);
return undefined;
case "Killing":
if (IS_WINDOWS) {
this.status.terminal.kill();
case "Killing": {
const now = Date.now();
if (
this.status.lastKillPress !== undefined &&
now - this.status.lastKillPress <= DOUBLE_PRESS
) {
if (IS_WINDOWS) {
this.status.terminal.kill();
} else {
this.status.terminal.kill("SIGKILL");
}
} else {
this.status.terminal.kill("SIGKILL");
this.status.terminal.write(KEY_CODES.kill);
}
this.status.lastKillPress = now;
return undefined;
}

@@ -941,2 +990,4 @@ case "Exit":

let attemptedKillAll = false;
/** @type {number | undefined} */
let cursorIndex = undefined;

@@ -951,2 +1002,3 @@ /**

DISABLE_ALTERNATE_SCREEN +
DISABLE_MOUSE +
RESET_COLOR +

@@ -957,2 +1009,4 @@ CLEAR +

const maybeNewline = /[\r\n][^\S\r\n]*$/.test(command.history) ? "" : "\n";
switch (command.status.tag) {

@@ -965,3 +1019,5 @@ case "Running":

process.stdout.write(
RESET_COLOR + runningText(command.status.terminal.pid)
RESET_COLOR +
maybeNewline +
runningText(command.status.terminal.pid)
);

@@ -976,2 +1032,3 @@ }

RESET_COLOR +
maybeNewline +
killingText(command, command.status.terminal.pid)

@@ -986,2 +1043,3 @@ );

RESET_COLOR +
maybeNewline +
exitText(commands, command, command.status.exitCode)

@@ -1001,5 +1059,11 @@ );

DISABLE_ALTERNATE_SCREEN +
ENABLE_MOUSE +
RESET_COLOR +
CLEAR +
drawDashboard(commands, process.stdout.columns, attemptedKillAll)
drawDashboard(
commands,
process.stdout.columns,
attemptedKillAll,
cursorIndex
)
);

@@ -1021,2 +1085,35 @@ };

*/
const switchToCommandAtCursor = () => {
if (cursorIndex !== undefined) {
const command = commands[cursorIndex];
current = { tag: "Command", index: cursorIndex };
printHistoryAndExtraText(command);
}
};
/**
* @param {number} delta
* @returns {void}
*/
const moveCursor = (delta) => {
if (cursorIndex === undefined) {
cursorIndex =
delta === 0
? undefined
: delta > 0
? delta - 1
: commands.length + delta;
} else {
cursorIndex = (cursorIndex + delta) % commands.length;
if (cursorIndex < 0) {
cursorIndex = commands.length + cursorIndex;
}
}
// Redraw dashboard.
switchToDashboard();
};
/**
* @returns {void}
*/
const killAll = () => {

@@ -1129,2 +1226,4 @@ attemptedKillAll = true;

switchToCommand,
switchToCommandAtCursor,
moveCursor,
killAll,

@@ -1159,3 +1258,3 @@ printHistoryAndExtraText

process.stdout.write(
SHOW_CURSOR + DISABLE_BRACKETED_PASTE_MODE + RESET_COLOR
SHOW_CURSOR + DISABLE_BRACKETED_PASTE_MODE + DISABLE_MOUSE + RESET_COLOR
);

@@ -1177,2 +1276,4 @@ });

* @param {(index: number) => void} switchToCommand
* @param {() => void} switchToCommandAtCursor
* @param {(delta: number) => void} moveCursor
* @param {() => void} killAll

@@ -1188,2 +1289,4 @@ * @param {(command: Command) => void} printHistoryAndExtraText

switchToCommand,
switchToCommandAtCursor,
moveCursor,
killAll,

@@ -1197,2 +1300,3 @@ printHistoryAndExtraText

case "Running":
case "Killing":
switch (data) {

@@ -1212,16 +1316,2 @@ case KEY_CODES.kill:

case "Killing":
switch (data) {
case KEY_CODES.kill:
command.kill();
return undefined;
case KEY_CODES.dashboard:
switchToDashboard();
return undefined;
default:
return undefined;
}
case "Exit":

@@ -1254,2 +1344,19 @@ switch (data) {

case KEY_CODES.enter:
case KEY_CODES.enterVim:
switchToCommandAtCursor();
return undefined;
case KEY_CODES.up:
case KEY_CODES.upAlt:
case KEY_CODES.upVim:
moveCursor(-1);
return undefined;
case KEY_CODES.down:
case KEY_CODES.downAlt:
case KEY_CODES.downVim:
moveCursor(1);
return undefined;
default: {

@@ -1261,3 +1368,23 @@ const commandIndex = commands.findIndex(

switchToCommand(commandIndex);
return undefined;
}
const mouseupPosition = parseMouseup(data);
if (mouseupPosition !== undefined) {
const { x, y } = mouseupPosition;
const lines = drawDashboardCommandLines(
commands,
process.stdout.columns,
undefined
);
if (y >= 0 && y < lines.length) {
const max = Math.max(
...lines.map((otherLine) => otherLine.length)
);
if (x >= 0 && x < max) {
switchToCommand(y);
}
}
}
return undefined;

@@ -1269,3 +1396,19 @@ }

// eslint-disable-next-line no-control-regex
const MOUSEUP_REGEX = /\x1B\[<0;(\d+);(\d+)M/;
/**
* @param {string} string
* @returns {{ x: number, y: number } | undefined}
*/
const parseMouseup = (string) => {
const match = MOUSEUP_REGEX.exec(string);
if (match === null) {
return undefined;
}
const [, x, y] = match;
return { x: Number(x) - 1, y: Number(y) - 1 };
};
/**
* @returns {undefined}

@@ -1272,0 +1415,0 @@ */