@tui-sandbox/library 0.0.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 (57) hide show
  1. package/LICENSE +9 -0
  2. package/dist/src/client/validateMouseEvent.d.ts +1 -0
  3. package/dist/src/client/validateMouseEvent.js +13 -0
  4. package/dist/src/client/websocket-client.d.ts +25 -0
  5. package/dist/src/client/websocket-client.js +127 -0
  6. package/dist/src/server/connection/trpc.d.ts +44 -0
  7. package/dist/src/server/connection/trpc.js +5 -0
  8. package/dist/src/server/dirtree/index.d.ts +25 -0
  9. package/dist/src/server/dirtree/index.js +80 -0
  10. package/dist/src/server/dirtree/index.test.d.ts +1 -0
  11. package/dist/src/server/dirtree/index.test.js +172 -0
  12. package/dist/src/server/dirtree/json-to-zod.d.ts +1 -0
  13. package/dist/src/server/dirtree/json-to-zod.js +56 -0
  14. package/dist/src/server/index.d.ts +8 -0
  15. package/dist/src/server/index.js +49 -0
  16. package/dist/src/server/neovim/NeovimApplication.d.ts +25 -0
  17. package/dist/src/server/neovim/NeovimApplication.js +111 -0
  18. package/dist/src/server/neovim/environment/createTempDir.d.ts +3 -0
  19. package/dist/src/server/neovim/environment/createTempDir.js +41 -0
  20. package/dist/src/server/neovim/index.d.ts +13 -0
  21. package/dist/src/server/neovim/index.js +40 -0
  22. package/dist/src/server/server.d.ts +59 -0
  23. package/dist/src/server/server.js +55 -0
  24. package/dist/src/server/types.d.ts +13 -0
  25. package/dist/src/server/types.js +1 -0
  26. package/dist/src/server/updateTestdirectorySchemaFile.d.ts +6 -0
  27. package/dist/src/server/updateTestdirectorySchemaFile.js +13 -0
  28. package/dist/src/server/utilities/DisposableSingleApplication.d.ts +16 -0
  29. package/dist/src/server/utilities/DisposableSingleApplication.js +27 -0
  30. package/dist/src/server/utilities/Lazy.d.ts +6 -0
  31. package/dist/src/server/utilities/Lazy.js +13 -0
  32. package/dist/src/server/utilities/TerminalApplication.d.ts +21 -0
  33. package/dist/src/server/utilities/TerminalApplication.js +54 -0
  34. package/dist/src/server/utilities/tabId.d.ts +9 -0
  35. package/dist/src/server/utilities/tabId.js +2 -0
  36. package/dist/tsconfig.tsbuildinfo +1 -0
  37. package/package.json +41 -0
  38. package/src/client/style.css +26 -0
  39. package/src/client/validateMouseEvent.ts +15 -0
  40. package/src/client/websocket-client.ts +157 -0
  41. package/src/public/DejaVuSansMNerdFontMono-Regular.ttf +0 -0
  42. package/src/server/connection/trpc.ts +17 -0
  43. package/src/server/dirtree/index.test.ts +179 -0
  44. package/src/server/dirtree/index.ts +114 -0
  45. package/src/server/dirtree/json-to-zod.ts +58 -0
  46. package/src/server/index.ts +54 -0
  47. package/src/server/neovim/NeovimApplication.ts +134 -0
  48. package/src/server/neovim/environment/createTempDir.ts +46 -0
  49. package/src/server/neovim/index.ts +63 -0
  50. package/src/server/server.ts +67 -0
  51. package/src/server/types.ts +13 -0
  52. package/src/server/updateTestdirectorySchemaFile.ts +23 -0
  53. package/src/server/utilities/DisposableSingleApplication.ts +33 -0
  54. package/src/server/utilities/Lazy.ts +12 -0
  55. package/src/server/utilities/TerminalApplication.ts +88 -0
  56. package/src/server/utilities/tabId.ts +4 -0
  57. package/tsconfig.json +22 -0
@@ -0,0 +1,111 @@
1
+ import { exec } from "child_process";
2
+ import EventEmitter from "events";
3
+ import { existsSync } from "fs";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ import { DisposableSingleApplication } from "../utilities/DisposableSingleApplication";
7
+ import { TerminalApplication } from "../utilities/TerminalApplication";
8
+ /*
9
+
10
+ Usage:
11
+ nvim [options] [file ...]
12
+
13
+ Options:
14
+ --cmd <cmd> Execute <cmd> before any config
15
+ +<cmd>, -c <cmd> Execute <cmd> after config and first file
16
+ -l <script> [args...] Execute Lua <script> (with optional args)
17
+ -S <session> Source <session> after loading the first file
18
+ -s <scriptin> Read Normal mode commands from <scriptin>
19
+ -u <config> Use this config file
20
+
21
+ -d Diff mode
22
+ -es, -Es Silent (batch) mode
23
+ -h, --help Print this help message
24
+ -i <shada> Use this shada file
25
+ -n No swap file, use memory only
26
+ -o[N] Open N windows (default: one per file)
27
+ -O[N] Open N vertical windows (default: one per file)
28
+ -p[N] Open N tab pages (default: one per file)
29
+ -R Read-only (view) mode
30
+ -v, --version Print version information
31
+ -V[N][file] Verbose [level][file]
32
+
33
+ -- Only file names after this
34
+ --api-info Write msgpack-encoded API metadata to stdout
35
+ --clean "Factory defaults" (skip user config and plugins, shada)
36
+ --embed Use stdin/stdout as a msgpack-rpc channel
37
+ --headless Don't start a user interface
38
+ --listen <address> Serve RPC API from this address
39
+ --remote[-subcommand] Execute commands remotely on a server
40
+ --server <address> Specify RPC server to send commands to
41
+ --startuptime <file> Write startup timing messages to <file>
42
+
43
+ See ":help startup-options" for all options.
44
+
45
+ $ nvim --version
46
+ NVIM v0.11.0-dev-608+g9d74dc3ac
47
+ Build type: Release
48
+ LuaJIT 2.1.1720049189
49
+ Run "nvim -V1 -v" for more info
50
+
51
+ */
52
+ const __dirname = fileURLToPath(new URL(".", import.meta.url));
53
+ export class NeovimApplication extends DisposableSingleApplication {
54
+ testEnvironmentPath;
55
+ testDirectory;
56
+ events;
57
+ constructor(testEnvironmentPath) {
58
+ super();
59
+ this.testEnvironmentPath = testEnvironmentPath;
60
+ this.events = new EventEmitter();
61
+ }
62
+ /**
63
+ * Kill the current application and start a new one with the given arguments.
64
+ */
65
+ async startNextAndKillCurrent(testDirectory, startArgs) {
66
+ await this[Symbol.asyncDispose]();
67
+ this.testDirectory = testDirectory;
68
+ const neovimArguments = ["-u", "test-setup.lua"];
69
+ if (startArgs.startupScriptModifications) {
70
+ for (const modification of startArgs.startupScriptModifications) {
71
+ const file = path.join(testDirectory.rootPathAbsolute, "config-modifications", modification);
72
+ if (!existsSync(file)) {
73
+ throw new Error(`startupScriptModifications file does not exist: ${file}`);
74
+ }
75
+ neovimArguments.push("-c", `lua dofile('${file}')`);
76
+ }
77
+ }
78
+ if (!startArgs.filename) {
79
+ startArgs.filename = "initial-file.txt";
80
+ }
81
+ if (typeof startArgs.filename === "string") {
82
+ const file = path.join(testDirectory.rootPathAbsolute, startArgs.filename);
83
+ neovimArguments.push(file);
84
+ }
85
+ else if (startArgs.filename.openInVerticalSplits.length > 0) {
86
+ // `-O[N]` Open N vertical windows (default: one per file)
87
+ neovimArguments.push("-O");
88
+ for (const file of startArgs.filename.openInVerticalSplits) {
89
+ const filePath = path.join(testDirectory.rootPathAbsolute, file);
90
+ neovimArguments.push(filePath);
91
+ }
92
+ }
93
+ const stdout = this.events;
94
+ this.application = TerminalApplication.start({
95
+ command: "nvim",
96
+ args: neovimArguments,
97
+ cwd: this.testEnvironmentPath,
98
+ env: process.env,
99
+ dimensions: startArgs.terminalDimensions,
100
+ onStdoutOrStderr(data) {
101
+ stdout.emit("stdout", data);
102
+ },
103
+ });
104
+ }
105
+ async [Symbol.asyncDispose]() {
106
+ await super.killCurrent();
107
+ if (this.testDirectory) {
108
+ exec(`rm -rf ${this.testDirectory.rootPathAbsolute}`);
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,3 @@
1
+ import type { TestDirectory } from "../../types";
2
+ import type { TestServerConfig } from "../../updateTestdirectorySchemaFile";
3
+ export declare function createTempDir(config: TestServerConfig): Promise<TestDirectory>;
@@ -0,0 +1,41 @@
1
+ import assert from "assert";
2
+ import { execSync } from "child_process";
3
+ import { Type } from "dree";
4
+ import { constants, readdirSync } from "fs";
5
+ import { access, mkdir, mkdtemp } from "fs/promises";
6
+ import path from "path";
7
+ import { convertDree, getDirectoryTree } from "../../dirtree";
8
+ import { updateTestdirectorySchemaFile } from "../../updateTestdirectorySchemaFile";
9
+ export async function createTempDir(config) {
10
+ try {
11
+ const dir = await createUniqueDirectory(config.testEnvironmentPath);
12
+ readdirSync(config.testEnvironmentPath).forEach(entry => {
13
+ if (entry === "testdirs")
14
+ return;
15
+ if (entry === ".repro")
16
+ return;
17
+ execSync(`cp -a '${path.join(config.testEnvironmentPath, entry)}' ${dir}/`);
18
+ });
19
+ console.log(`Created test directory at ${dir}`);
20
+ const tree = convertDree(getDirectoryTree(dir).dree);
21
+ assert(tree.type === Type.DIRECTORY);
22
+ await updateTestdirectorySchemaFile(config);
23
+ return { rootPathAbsolute: dir, contents: tree.contents };
24
+ }
25
+ catch (err) {
26
+ console.error(err);
27
+ throw err;
28
+ }
29
+ }
30
+ async function createUniqueDirectory(testEnvironmentPath) {
31
+ const testdirs = path.join(testEnvironmentPath, "testdirs");
32
+ try {
33
+ await access(testdirs, constants.F_OK);
34
+ }
35
+ catch {
36
+ await mkdir(testdirs);
37
+ }
38
+ const dir = await mkdtemp(path.join(testdirs, "dir-"));
39
+ assert(typeof dir === "string");
40
+ return dir;
41
+ }
@@ -0,0 +1,13 @@
1
+ import type { Observable } from "@trpc/server/observable";
2
+ import type { TestDirectory } from "../types";
3
+ import type { TestServerConfig } from "../updateTestdirectorySchemaFile";
4
+ import type { TabId } from "../utilities/tabId";
5
+ import type { StartNeovimGenericArguments } from "./NeovimApplication";
6
+ export declare function onStdout(options: {
7
+ client: TabId;
8
+ }, testEnvironmentPath: string): Observable<string, unknown>;
9
+ export declare function start(options: StartNeovimGenericArguments, tabId: TabId, config: TestServerConfig): Promise<TestDirectory>;
10
+ export declare function sendStdin(options: {
11
+ tabId: TabId;
12
+ data: string;
13
+ }): Promise<void>;
@@ -0,0 +1,40 @@
1
+ import { observable } from "@trpc/server/observable";
2
+ import assert from "assert";
3
+ import { createTempDir } from "./environment/createTempDir";
4
+ import { NeovimApplication } from "./NeovimApplication";
5
+ const neovims = new Map();
6
+ export function onStdout(options, testEnvironmentPath) {
7
+ return observable(emit => {
8
+ const tabId = options.client.tabId;
9
+ const neovim = neovims.get(tabId) ?? new NeovimApplication(testEnvironmentPath);
10
+ if (neovims.get(tabId) === undefined) {
11
+ neovims.set(tabId, neovim);
12
+ }
13
+ const send = (data) => {
14
+ assert(typeof data === "string");
15
+ emit.next(data);
16
+ };
17
+ neovim.events.on("stdout", send);
18
+ return () => {
19
+ neovim.events.off("stdout", send);
20
+ void neovim[Symbol.asyncDispose]().finally(() => {
21
+ neovims.delete(tabId);
22
+ });
23
+ };
24
+ });
25
+ }
26
+ export async function start(options, tabId, config) {
27
+ const neovim = neovims.get(tabId.tabId);
28
+ assert(neovim, `Neovim instance not found for client id ${tabId.tabId}`);
29
+ const testDirectory = await createTempDir(config);
30
+ await neovim.startNextAndKillCurrent(testDirectory, options);
31
+ const processId = neovim.processId();
32
+ assert(processId !== undefined, "Neovim was started without a process ID. This is a bug - please open an issue.");
33
+ console.log(`🚀 Started Neovim instance ${processId}`);
34
+ return testDirectory;
35
+ }
36
+ export async function sendStdin(options) {
37
+ const neovim = neovims.get(options.tabId.tabId);
38
+ assert(neovim !== undefined, `Neovim instance for clientId not found - cannot send stdin. Maybe it's not started yet?`);
39
+ await neovim.write(options.data);
40
+ }
@@ -0,0 +1,59 @@
1
+ import type { inferRouterInputs } from "@trpc/server";
2
+ import { TestServer } from ".";
3
+ import type { TestServerConfig } from "./updateTestdirectorySchemaFile";
4
+ /** Stack for managing resources that need to be disposed of when the server
5
+ * shuts down */
6
+ declare const autocleanup: AsyncDisposableStack;
7
+ export { autocleanup };
8
+ declare function createAppRouter(config: TestServerConfig): import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
9
+ ctx: import("./connection/trpc").Connection;
10
+ meta: object;
11
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
12
+ transformer: false;
13
+ }, import("@trpc/server/unstable-core-do-not-import").DecorateCreateRouterOptions<{
14
+ neovim: import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
15
+ ctx: import("./connection/trpc").Connection;
16
+ meta: object;
17
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
18
+ transformer: false;
19
+ }, {
20
+ start: import("@trpc/server").TRPCMutationProcedure<{
21
+ input: {
22
+ tabId: {
23
+ tabId: string;
24
+ };
25
+ startNeovimArguments: {
26
+ filename?: string | {
27
+ openInVerticalSplits: string[];
28
+ } | undefined;
29
+ startupScriptModifications?: string[] | undefined;
30
+ };
31
+ terminalDimensions?: {
32
+ cols: number;
33
+ rows: number;
34
+ } | undefined;
35
+ };
36
+ output: import("./types").TestDirectory;
37
+ }>;
38
+ onStdout: import("@trpc/server").TRPCSubscriptionProcedure<{
39
+ input: {
40
+ client: {
41
+ tabId: string;
42
+ };
43
+ };
44
+ output: string;
45
+ }>;
46
+ sendStdin: import("@trpc/server").TRPCMutationProcedure<{
47
+ input: {
48
+ tabId: {
49
+ tabId: string;
50
+ };
51
+ data: string;
52
+ };
53
+ output: void;
54
+ }>;
55
+ }>;
56
+ }>>;
57
+ export type AppRouter = ReturnType<typeof createAppRouter>;
58
+ export type RouterInput = inferRouterInputs<AppRouter>;
59
+ export declare function startTestServer(config: TestServerConfig): Promise<TestServer>;
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { TestServer } from ".";
3
+ import { trpc } from "./connection/trpc";
4
+ import * as neovim from "./neovim";
5
+ import { tabIdSchema } from "./utilities/tabId";
6
+ /** Stack for managing resources that need to be disposed of when the server
7
+ * shuts down */
8
+ await using autocleanup = new AsyncDisposableStack();
9
+ autocleanup.defer(() => {
10
+ console.log("Closing any open test applications");
11
+ });
12
+ export { autocleanup };
13
+ function createAppRouter(config) {
14
+ const appRouter = trpc.router({
15
+ neovim: trpc.router({
16
+ start: trpc.procedure
17
+ .input(z.object({
18
+ tabId: tabIdSchema,
19
+ terminalDimensions: z
20
+ .object({
21
+ cols: z.number(),
22
+ rows: z.number(),
23
+ })
24
+ .optional(),
25
+ startNeovimArguments: z.object({
26
+ filename: z
27
+ .union([
28
+ z.string(),
29
+ z.object({
30
+ openInVerticalSplits: z.array(z.string()),
31
+ }),
32
+ ])
33
+ .optional(),
34
+ startupScriptModifications: z.array(z.string()).optional(),
35
+ }),
36
+ }))
37
+ .mutation(options => {
38
+ return neovim.start(options.input, options.input.tabId, config);
39
+ }),
40
+ onStdout: trpc.procedure.input(z.object({ client: tabIdSchema })).subscription(options => {
41
+ return neovim.onStdout(options.input, config.testEnvironmentPath);
42
+ }),
43
+ sendStdin: trpc.procedure.input(z.object({ tabId: tabIdSchema, data: z.string() })).mutation(options => {
44
+ return neovim.sendStdin(options.input);
45
+ }),
46
+ }),
47
+ });
48
+ return appRouter;
49
+ }
50
+ export async function startTestServer(config) {
51
+ const testServer = new TestServer(3000);
52
+ const appRouter = createAppRouter(config);
53
+ await testServer.startAndRun(appRouter, config);
54
+ return testServer;
55
+ }
@@ -0,0 +1,13 @@
1
+ /** Describes the contents of the test directory, which is a blueprint for
2
+ * files and directories. Tests can create a unique, safe environment for
3
+ * interacting with the contents of such a directory.
4
+ *
5
+ * Having strong typing for the test directory contents ensures that tests can
6
+ * be written with confidence that the files and directories they expect are
7
+ * actually found. Otherwise the tests are brittle and can break easily.
8
+ */
9
+ export type TestDirectory = {
10
+ /** The path to the unique test directory (the root). */
11
+ rootPathAbsolute: string;
12
+ contents: object;
13
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import "core-js/proposals/async-explicit-resource-management";
2
+ export type TestServerConfig = {
3
+ testEnvironmentPath: string;
4
+ outputFilePath: string;
5
+ };
6
+ export declare function updateTestdirectorySchemaFile({ testEnvironmentPath, outputFilePath, }: TestServerConfig): Promise<void>;
@@ -0,0 +1,13 @@
1
+ import "core-js/proposals/async-explicit-resource-management";
2
+ import { readFileSync, writeFileSync } from "fs";
3
+ import { buildTestDirectorySchema } from "./dirtree";
4
+ export async function updateTestdirectorySchemaFile({ testEnvironmentPath, outputFilePath, }) {
5
+ const newSchema = await buildTestDirectorySchema(testEnvironmentPath);
6
+ const oldSchema = readFileSync(outputFilePath, "utf-8");
7
+ if (oldSchema !== newSchema) {
8
+ // it's important to not write the file if the schema hasn't changed
9
+ // because file watchers will trigger on file changes and we don't want to
10
+ // trigger a build if the schema hasn't changed
11
+ writeFileSync(outputFilePath, newSchema);
12
+ }
13
+ }
@@ -0,0 +1,16 @@
1
+ import type { TerminalApplication } from "./TerminalApplication";
2
+ /** A testable application that can be started, killed, and given input. For a
3
+ * single instance of this interface, only a single instance can be running at
4
+ * a time (1 to 1 mapping).
5
+ *
6
+ * @typeParam T The type of context the tests should have, e.g. information
7
+ * about a custom directory that the application is running in.
8
+ *
9
+ */
10
+ export declare abstract class DisposableSingleApplication implements AsyncDisposable {
11
+ protected application: TerminalApplication | undefined;
12
+ killCurrent(): Promise<void>;
13
+ write(input: string): Promise<void>;
14
+ processId(): number | undefined;
15
+ [Symbol.asyncDispose](): Promise<void>;
16
+ }
@@ -0,0 +1,27 @@
1
+ /** A testable application that can be started, killed, and given input. For a
2
+ * single instance of this interface, only a single instance can be running at
3
+ * a time (1 to 1 mapping).
4
+ *
5
+ * @typeParam T The type of context the tests should have, e.g. information
6
+ * about a custom directory that the application is running in.
7
+ *
8
+ */
9
+ export class DisposableSingleApplication {
10
+ application;
11
+ async killCurrent() {
12
+ await this.application?.killAndWait();
13
+ }
14
+ async write(input) {
15
+ return this.application?.write(input);
16
+ }
17
+ processId() {
18
+ return this.application?.processId;
19
+ }
20
+ async [Symbol.asyncDispose]() {
21
+ if (this.processId() === undefined) {
22
+ return;
23
+ }
24
+ console.log(`Killing current application ${this.processId()}...`);
25
+ await this.killCurrent();
26
+ }
27
+ }
@@ -0,0 +1,6 @@
1
+ export declare class Lazy<T> {
2
+ private readonly factory;
3
+ private value?;
4
+ constructor(factory: () => T);
5
+ get(): T;
6
+ }
@@ -0,0 +1,13 @@
1
+ export class Lazy {
2
+ factory;
3
+ value;
4
+ constructor(factory) {
5
+ this.factory = factory;
6
+ }
7
+ get() {
8
+ if (this.value === undefined) {
9
+ this.value = this.factory();
10
+ }
11
+ return this.value;
12
+ }
13
+ }
@@ -0,0 +1,21 @@
1
+ import winston from "winston";
2
+ import type { ITerminalDimensions } from "@xterm/addon-fit";
3
+ export declare class TerminalApplication {
4
+ private readonly subProcess;
5
+ readonly onStdoutOrStderr: (data: string) => void;
6
+ readonly processId: number;
7
+ readonly logger: winston.Logger;
8
+ private constructor();
9
+ /** @constructor Start a new terminal application. */
10
+ static start({ onStdoutOrStderr, command, args, cwd, env, dimensions: givenDimensions, }: {
11
+ onStdoutOrStderr: (data: string) => void;
12
+ command: string;
13
+ args: string[];
14
+ cwd: string;
15
+ env?: NodeJS.ProcessEnv;
16
+ dimensions?: ITerminalDimensions;
17
+ }): TerminalApplication;
18
+ /** Write to the terminal's stdin. */
19
+ write(data: string): void;
20
+ killAndWait(): Promise<void>;
21
+ }
@@ -0,0 +1,54 @@
1
+ import winston from "winston";
2
+ import pty from "node-pty";
3
+ // NOTE the size for the terminal was chosen so that it looks good in my
4
+ // cypress test preview
5
+ const defaultDimensions = { cols: 125, rows: 43 };
6
+ // NOTE separating stdout and stderr is not supported by node-pty
7
+ // https://github.com/microsoft/node-pty/issues/71
8
+ export class TerminalApplication {
9
+ subProcess;
10
+ onStdoutOrStderr;
11
+ processId;
12
+ logger;
13
+ constructor(subProcess, onStdoutOrStderr) {
14
+ this.subProcess = subProcess;
15
+ this.onStdoutOrStderr = onStdoutOrStderr;
16
+ this.processId = subProcess.pid;
17
+ this.logger = winston.createLogger({
18
+ transports: [new winston.transports.Console()],
19
+ defaultMeta: { pid: this.processId },
20
+ format: winston.format.combine(winston.format.colorize(), winston.format.cli()),
21
+ });
22
+ this.logger.debug(`started`);
23
+ subProcess.onData(this.onStdoutOrStderr);
24
+ subProcess.onExit(({ exitCode, signal }) => {
25
+ this.logger.debug(`Child process ${this.processId} exited with code ${String(exitCode)} and signal ${String(signal)}`);
26
+ });
27
+ }
28
+ /** @constructor Start a new terminal application. */
29
+ static start({ onStdoutOrStderr, command, args, cwd, env, dimensions: givenDimensions, }) {
30
+ const dimensions = givenDimensions ?? defaultDimensions;
31
+ console.log(`Starting '${command} ${args.join(" ")}' in cwd '${cwd}'`);
32
+ const ptyProcess = pty.spawn(command, args, {
33
+ name: "xterm-color",
34
+ cwd,
35
+ env,
36
+ cols: dimensions.cols,
37
+ rows: dimensions.rows,
38
+ });
39
+ const processId = ptyProcess.pid;
40
+ if (!processId) {
41
+ throw new Error("Failed to spawn child process");
42
+ }
43
+ return new TerminalApplication(ptyProcess, onStdoutOrStderr);
44
+ }
45
+ /** Write to the terminal's stdin. */
46
+ write(data) {
47
+ this.subProcess.write(data);
48
+ }
49
+ async killAndWait() {
50
+ console.log(`💣 Killing process ${this.processId}`);
51
+ this.subProcess.kill();
52
+ console.log(`💥 Killed process ${this.processId}`);
53
+ }
54
+ }
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export type TabId = z.infer<typeof tabIdSchema>;
3
+ export declare const tabIdSchema: z.ZodObject<{
4
+ tabId: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ tabId: string;
7
+ }, {
8
+ tabId: string;
9
+ }>;
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const tabIdSchema = z.object({ tabId: z.string() });