@tui-sandbox/library 9.2.1 → 9.3.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 (45) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/browser/assets/{index-BVkLGLTD.js → index-CwXs-hE_.js} +6 -6
  3. package/dist/browser/index.html +1 -1
  4. package/dist/src/browser/neovim-client.d.ts +2 -1
  5. package/dist/src/browser/neovim-client.js.map +1 -1
  6. package/dist/src/client/neovim-terminal-client.d.ts +2 -1
  7. package/dist/src/client/neovim-terminal-client.js.map +1 -1
  8. package/dist/src/client/terminal-terminal-client.d.ts +1 -1
  9. package/dist/src/client/terminal-terminal-client.js.map +1 -1
  10. package/dist/src/server/blockingCommandInputSchema.d.ts +70 -0
  11. package/dist/src/server/blockingCommandInputSchema.js +20 -0
  12. package/dist/src/server/blockingCommandInputSchema.js.map +1 -0
  13. package/dist/src/server/blockingCommandInputSchema.test.d.ts +1 -0
  14. package/dist/src/server/blockingCommandInputSchema.test.js +22 -0
  15. package/dist/src/server/blockingCommandInputSchema.test.js.map +1 -0
  16. package/dist/src/server/cypress-support/contents.js +11 -9
  17. package/dist/src/server/cypress-support/contents.js.map +1 -1
  18. package/dist/src/server/neovim/index.d.ts +2 -1
  19. package/dist/src/server/neovim/index.js +1 -1
  20. package/dist/src/server/neovim/index.js.map +1 -1
  21. package/dist/src/server/server.d.ts +15 -53
  22. package/dist/src/server/server.js +1 -11
  23. package/dist/src/server/server.js.map +1 -1
  24. package/dist/src/server/terminal/index.d.ts +1 -1
  25. package/dist/src/server/terminal/index.js +1 -1
  26. package/dist/src/server/terminal/index.js.map +1 -1
  27. package/dist/src/server/terminal/runBlockingShellCommand.d.ts +10 -3
  28. package/dist/src/server/terminal/runBlockingShellCommand.js +21 -10
  29. package/dist/src/server/terminal/runBlockingShellCommand.js.map +1 -1
  30. package/dist/src/server/terminal/runBlockingShellCommand.test.d.ts +1 -0
  31. package/dist/src/server/terminal/runBlockingShellCommand.test.js +35 -0
  32. package/dist/src/server/terminal/runBlockingShellCommand.test.js.map +1 -0
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +7 -7
  35. package/src/browser/neovim-client.ts +2 -1
  36. package/src/client/neovim-terminal-client.ts +2 -6
  37. package/src/client/terminal-terminal-client.ts +2 -1
  38. package/src/server/blockingCommandInputSchema.test.ts +23 -0
  39. package/src/server/blockingCommandInputSchema.ts +28 -0
  40. package/src/server/cypress-support/contents.ts +11 -9
  41. package/src/server/neovim/index.ts +3 -2
  42. package/src/server/server.ts +1 -16
  43. package/src/server/terminal/index.ts +2 -2
  44. package/src/server/terminal/runBlockingShellCommand.test.ts +40 -0
  45. package/src/server/terminal/runBlockingShellCommand.ts +30 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tui-sandbox/library",
3
- "version": "9.2.1",
3
+ "version": "9.3.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,8 +8,8 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@catppuccin/palette": "1.7.1",
11
- "@trpc/client": "11.0.0-rc.768",
12
- "@trpc/server": "11.0.0-rc.768",
11
+ "@trpc/client": "11.0.0-rc.795",
12
+ "@trpc/server": "11.0.0-rc.795",
13
13
  "@xterm/addon-attach": "0.11.0",
14
14
  "@xterm/addon-fit": "0.10.0",
15
15
  "@xterm/xterm": "5.5.0",
@@ -21,8 +21,8 @@
21
21
  "neovim": "5.3.0",
22
22
  "node-pty": "1.0.0",
23
23
  "prettier": "3.5.1",
24
- "tsx": "4.19.2",
25
- "type-fest": "4.34.1",
24
+ "tsx": "4.19.3",
25
+ "type-fest": "4.35.0",
26
26
  "winston": "3.17.0",
27
27
  "zod": "3.24.2"
28
28
  },
@@ -33,8 +33,8 @@
33
33
  "@types/express": "5.0.0",
34
34
  "@types/node": "22.13.4",
35
35
  "nodemon": "3.1.9",
36
- "vite": "6.1.0",
37
- "vitest": "3.0.5"
36
+ "vite": "6.1.1",
37
+ "vitest": "3.0.6"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "cypress": "^13 || ^14",
@@ -1,6 +1,7 @@
1
1
  import { TerminalClient as NeovimTerminalClient } from "../client/index.js"
2
2
  import { TerminalTerminalClient } from "../client/terminal-terminal-client.js"
3
- import type { BlockingCommandClientInput, ExCommandClientInput, LuaCodeClientInput } from "../server/server.js"
3
+ import type { BlockingCommandClientInput } from "../server/blockingCommandInputSchema.js"
4
+ import type { ExCommandClientInput, LuaCodeClientInput } from "../server/server.js"
4
5
  import type { StartTerminalGenericArguments } from "../server/terminal/TerminalTestApplication.js"
5
6
  import type {
6
7
  BlockingShellCommandOutput,
@@ -1,12 +1,8 @@
1
1
  import { createTRPCClient, httpBatchLink, splitLink, unstable_httpSubscriptionLink } from "@trpc/client"
2
2
  import type { Terminal } from "@xterm/xterm"
3
3
  import "@xterm/xterm/css/xterm.css"
4
- import type {
5
- AppRouter,
6
- BlockingCommandClientInput,
7
- ExCommandClientInput,
8
- LuaCodeClientInput,
9
- } from "../server/server.js"
4
+ import type { BlockingCommandClientInput } from "../server/blockingCommandInputSchema.js"
5
+ import type { AppRouter, ExCommandClientInput, LuaCodeClientInput } from "../server/server.js"
10
6
  import type {
11
7
  BlockingShellCommandOutput,
12
8
  RunExCommandOutput,
@@ -1,7 +1,8 @@
1
1
  import { createTRPCClient, httpBatchLink, splitLink, unstable_httpSubscriptionLink } from "@trpc/client"
2
2
  import type { Terminal } from "@xterm/xterm"
3
3
  import "@xterm/xterm/css/xterm.css"
4
- import type { AppRouter, BlockingCommandClientInput } from "../server/server.js"
4
+ import type { BlockingCommandClientInput } from "../server/blockingCommandInputSchema.js"
5
+ import type { AppRouter } from "../server/server.js"
5
6
  import type { StartTerminalGenericArguments } from "../server/terminal/TerminalTestApplication.js"
6
7
  import type { BlockingShellCommandOutput, TestDirectory } from "../server/types.js"
7
8
  import "./style.css"
@@ -0,0 +1,23 @@
1
+ import { blockingCommandInputSchema, type BlockingCommandInput } from "./blockingCommandInputSchema.js"
2
+
3
+ describe("blockingCommandInputSchema", () => {
4
+ it("allows either cwd or cwdRelative but not both", () => {
5
+ // It doesn't make sense to have two sources of truth for the cwd.
6
+ const fails = blockingCommandInputSchema.safeParse({
7
+ command: "command",
8
+ tabId: { tabId: "123" },
9
+ cwd: "cwd",
10
+ cwdRelative: "cwdRelative",
11
+ } satisfies Partial<BlockingCommandInput>)
12
+
13
+ expect(fails.error).toMatchInlineSnapshot(`
14
+ [ZodError: [
15
+ {
16
+ "code": "custom",
17
+ "message": "Both cwd and cwdRelative provided. Please provide either but not both at the same time.",
18
+ "path": []
19
+ }
20
+ ]]
21
+ `)
22
+ })
23
+ })
@@ -0,0 +1,28 @@
1
+ import "core-js/proposals/async-explicit-resource-management.js"
2
+ import type { Except } from "type-fest"
3
+ import { z } from "zod"
4
+ import { tabIdSchema } from "./utilities/tabId.js"
5
+
6
+ export const blockingCommandInputSchema = z
7
+ .object({
8
+ command: z.string(),
9
+ shell: z.string().optional(),
10
+ tabId: tabIdSchema,
11
+ allowFailure: z.boolean().optional(),
12
+
13
+ // absolute cwd
14
+ cwd: z.string().optional(),
15
+ cwdRelative: z.string().optional(),
16
+ envOverrides: z.record(z.string()).optional(),
17
+ uid: z.number().optional(),
18
+ gid: z.number().optional(),
19
+ })
20
+ .refine(
21
+ data =>
22
+ // disallow both cwd and cwdRelative
23
+ !(data.cwd && data.cwdRelative),
24
+ { message: "Both cwd and cwdRelative provided. Please provide either but not both at the same time." }
25
+ )
26
+
27
+ export type BlockingCommandClientInput = Except<BlockingCommandInput, "tabId">
28
+ export type BlockingCommandInput = z.infer<typeof blockingCommandInputSchema>
@@ -14,11 +14,7 @@ import type {
14
14
  GenericNeovimBrowserApi,
15
15
  GenericTerminalBrowserApi,
16
16
  } from "@tui-sandbox/library/dist/src/browser/neovim-client"
17
- import type {
18
- BlockingCommandClientInput,
19
- ExCommandClientInput,
20
- LuaCodeClientInput,
21
- } from "@tui-sandbox/library/dist/src/server/server"
17
+ import type { ExCommandClientInput, LuaCodeClientInput } from "@tui-sandbox/library/dist/src/server/server"
22
18
  import type {
23
19
  BlockingShellCommandOutput,
24
20
  RunExCommandOutput,
@@ -26,6 +22,7 @@ import type {
26
22
  StartNeovimGenericArguments,
27
23
  TestDirectory,
28
24
  } from "@tui-sandbox/library/dist/src/server/types"
25
+ import type { BlockingCommandClientInput } from "@tui-sandbox/library/src/server/blockingCommandInputSchema"
29
26
  import type { StartTerminalGenericArguments } from "@tui-sandbox/library/src/server/terminal/TerminalTestApplication"
30
27
  import type { OverrideProperties } from "type-fest"
31
28
  import type { MyTestDirectory, MyTestDirectoryFile } from "../../MyTestDirectory"
@@ -37,7 +34,7 @@ export type TerminalTestApplicationContext = {
37
34
 
38
35
  /** Runs a shell command in a blocking manner, waiting for the command to
39
36
  * finish before returning. Requires the terminal to be running. */
40
- runBlockingShellCommand(input: BlockingCommandClientInput): Cypress.Chainable<BlockingShellCommandOutput>
37
+ runBlockingShellCommand(input: MyBlockingCommandClientInput): Cypress.Chainable<BlockingShellCommandOutput>
41
38
 
42
39
  /** The test directory, providing type-safe access to its file and directory structure */
43
40
  dir: TestDirectory<MyTestDirectory>
@@ -51,7 +48,7 @@ export type NeovimContext = {
51
48
 
52
49
  /** Runs a shell command in a blocking manner, waiting for the command to
53
50
  * finish before returning. Requires neovim to be running. */
54
- runBlockingShellCommand(input: BlockingCommandClientInput): Cypress.Chainable<BlockingShellCommandOutput>
51
+ runBlockingShellCommand(input: MyBlockingCommandClientInput): Cypress.Chainable<BlockingShellCommandOutput>
55
52
 
56
53
  /** Runs a shell command in a blocking manner, waiting for the command to
57
54
  * finish before returning. Requires neovim to be running. */
@@ -147,6 +144,11 @@ before(function () {
147
144
  cy.intercept({ resourceType: /xhr|fetch/ }, { log: false })
148
145
  })
149
146
 
147
+ export type MyBlockingCommandClientInput = OverrideProperties<
148
+ BlockingCommandClientInput,
149
+ { cwdRelative?: MyTestDirectoryFile | undefined }
150
+ >
151
+
150
152
  declare global {
151
153
  namespace Cypress {
152
154
  interface Chainable {
@@ -159,7 +161,7 @@ declare global {
159
161
 
160
162
  /** Runs a shell command in a blocking manner, waiting for the command to
161
163
  * finish before returning. Requires neovim to be running. */
162
- nvim_runBlockingShellCommand(input: BlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
164
+ nvim_runBlockingShellCommand(input: MyBlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
163
165
 
164
166
  nvim_runLuaCode(input: LuaCodeClientInput): Chainable<RunLuaCodeOutput>
165
167
 
@@ -168,7 +170,7 @@ declare global {
168
170
  */
169
171
  nvim_runExCommand(input: ExCommandClientInput): Chainable<RunExCommandOutput>
170
172
 
171
- terminal_runBlockingShellCommand(input: BlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
173
+ terminal_runBlockingShellCommand(input: MyBlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
172
174
  }
173
175
  }
174
176
  }
@@ -2,7 +2,8 @@ import assert from "assert"
2
2
  import "core-js/proposals/async-explicit-resource-management.js"
3
3
  import { access } from "fs/promises"
4
4
  import path from "path"
5
- import type { BlockingCommandInput, ExCommandInput, LuaCodeInput } from "../server.js"
5
+ import type { BlockingCommandInput } from "../blockingCommandInputSchema.js"
6
+ import type { ExCommandInput, LuaCodeInput } from "../server.js"
6
7
  import { executeBlockingShellCommand } from "../terminal/runBlockingShellCommand.js"
7
8
  import type {
8
9
  BlockingShellCommandOutput,
@@ -124,7 +125,7 @@ export async function runBlockingShellCommand(
124
125
  assert(testDirectory, `Test directory not found for client id ${input.tabId.tabId}. Maybe neovim's not started yet?`)
125
126
 
126
127
  const env = neovim.getEnvironmentVariables(testDirectory, input.envOverrides)
127
- return executeBlockingShellCommand(input, signal, allowFailure, env)
128
+ return executeBlockingShellCommand(testDirectory, input, signal, allowFailure, env)
128
129
  }
129
130
 
130
131
  export async function runLuaCode(options: LuaCodeInput): Promise<RunLuaCodeOutput> {
@@ -2,6 +2,7 @@ import type { inferRouterInputs } from "@trpc/server"
2
2
  import "core-js/proposals/async-explicit-resource-management.js"
3
3
  import type { Except } from "type-fest"
4
4
  import { z } from "zod"
5
+ import { blockingCommandInputSchema } from "./blockingCommandInputSchema.js"
5
6
  import { trpc } from "./connection/trpc.js"
6
7
  import * as neovim from "./neovim/index.js"
7
8
  import * as terminal from "./terminal/index.js"
@@ -9,22 +10,6 @@ import { TestServer } from "./TestServer.js"
9
10
  import type { DirectoriesConfig, TestServerConfig } from "./updateTestdirectorySchemaFile.js"
10
11
  import { tabIdSchema } from "./utilities/tabId.js"
11
12
 
12
- const blockingCommandInputSchema = z.object({
13
- command: z.string(),
14
- shell: z.string().optional(),
15
- tabId: tabIdSchema,
16
- allowFailure: z.boolean().optional(),
17
-
18
- // child_process.ProcessEnvOptions
19
- uid: z.number().optional(),
20
- gid: z.number().optional(),
21
- cwd: z.string().optional(),
22
- envOverrides: z.record(z.string()).optional(),
23
- })
24
-
25
- export type BlockingCommandClientInput = Except<BlockingCommandInput, "tabId">
26
- export type BlockingCommandInput = z.infer<typeof blockingCommandInputSchema>
27
-
28
13
  const luaCodeInputSchema = z.object({ tabId: tabIdSchema, luaCode: z.string() })
29
14
  export type LuaCodeClientInput = Except<LuaCodeInput, "tabId">
30
15
  export type LuaCodeInput = z.infer<typeof luaCodeInputSchema>
@@ -1,8 +1,8 @@
1
1
  import assert from "assert"
2
2
  import "core-js/proposals/async-explicit-resource-management.js"
3
+ import type { BlockingCommandInput } from "../blockingCommandInputSchema.js"
3
4
  import type { TerminalDimensions } from "../neovim/NeovimApplication.js"
4
5
  import { prepareNewTestDirectory } from "../neovim/prepareNewTestDirectory.js"
5
- import type { BlockingCommandInput } from "../server.js"
6
6
  import type { BlockingShellCommandOutput } from "../types.js"
7
7
  import type { DirectoriesConfig } from "../updateTestdirectorySchemaFile.js"
8
8
  import { convertEventEmitterToAsyncGenerator } from "../utilities/generator.js"
@@ -81,5 +81,5 @@ export async function runBlockingShellCommand(
81
81
  assert(testDirectory, `Test directory not found for client id ${input.tabId.tabId}. Maybe neovim's not started yet?`)
82
82
 
83
83
  const env = app.getEnvironmentVariables(testDirectory, input.envOverrides)
84
- return executeBlockingShellCommand(input, signal, allowFailure, env)
84
+ return executeBlockingShellCommand(testDirectory, input, signal, allowFailure, env)
85
85
  }
@@ -0,0 +1,40 @@
1
+ import { getCwd } from "./runBlockingShellCommand.js"
2
+
3
+ describe("getCwd", () => {
4
+ it("prefers cwdRelative if it is defined", () => {
5
+ // in many cases this is what the user wants to do, so prefer that
6
+
7
+ const result = getCwd({
8
+ rootPathAbsolute: "/root-absolute",
9
+ cwdRelative: "test-cwd-relative",
10
+ cwdAbsolute: "/test-cwd",
11
+ home: "/test-home",
12
+ })
13
+ expect(result).toEqual("/root-absolute/test-cwd-relative")
14
+ })
15
+
16
+ it("falls back to cwd if cwdRelative is not defined", () => {
17
+ // this is used when the user wants to use absolute paths
18
+
19
+ const result = getCwd({
20
+ rootPathAbsolute: "/root-absolute",
21
+ cwdRelative: undefined,
22
+ cwdAbsolute: "/test-cwd",
23
+ home: "/test-home",
24
+ })
25
+ expect(result).toEqual("/test-cwd")
26
+ })
27
+
28
+ it("falls back to HOME if neither cwdRelative nor cwd are defined", () => {
29
+ // if the user doesn't specify anything, we default to the home directory
30
+ // because a directory must be present when running the command
31
+
32
+ const result = getCwd({
33
+ rootPathAbsolute: "/root-absolute",
34
+ cwdRelative: undefined,
35
+ cwdAbsolute: undefined,
36
+ home: "/test-home",
37
+ })
38
+ expect(result).toEqual("/test-home")
39
+ })
40
+ })
@@ -1,10 +1,12 @@
1
1
  import { exec } from "child_process"
2
2
  import "core-js/proposals/async-explicit-resource-management.js"
3
+ import { join } from "path"
3
4
  import util from "util"
4
- import type { BlockingCommandInput } from "../server.js"
5
- import type { BlockingShellCommandOutput } from "../types.js"
5
+ import type { BlockingCommandInput } from "../blockingCommandInputSchema.js"
6
+ import type { BlockingShellCommandOutput, TestDirectory } from "../types.js"
6
7
 
7
8
  export async function executeBlockingShellCommand(
9
+ testDirectory: TestDirectory,
8
10
  input: BlockingCommandInput,
9
11
  signal: AbortSignal | undefined,
10
12
  allowFailure: boolean,
@@ -12,19 +14,22 @@ export async function executeBlockingShellCommand(
12
14
  ): Promise<BlockingShellCommandOutput> {
13
15
  const execPromise = util.promisify(exec)
14
16
 
15
- const cwd = input.cwd ?? env["HOME"]
16
-
17
- const processPromise = execPromise(input.command, {
18
- signal: signal,
19
- shell: input.shell,
20
- uid: input.uid,
21
- gid: input.gid,
22
- cwd: cwd,
23
- env,
17
+ const cwd = getCwd({
18
+ rootPathAbsolute: testDirectory.rootPathAbsolute,
19
+ cwdRelative: input.cwdRelative,
20
+ cwdAbsolute: input.cwd,
21
+ home: testDirectory.rootPathAbsolute,
24
22
  })
25
23
 
26
24
  try {
27
- const result = await processPromise
25
+ const result = await execPromise(input.command, {
26
+ signal: signal,
27
+ shell: input.shell,
28
+ uid: input.uid,
29
+ gid: input.gid,
30
+ cwd,
31
+ env,
32
+ })
28
33
  console.log(
29
34
  `Successfully ran shell blockingCommand (${input.command}) with stdout: ${result.stdout}, stderr: ${result.stderr}`
30
35
  )
@@ -43,3 +48,16 @@ export async function executeBlockingShellCommand(
43
48
  throw new Error(`Error running shell blockingCommand (${input.command})`, { cause: e })
44
49
  }
45
50
  }
51
+
52
+ export type GetCwdArguments = {
53
+ rootPathAbsolute: string
54
+ cwdRelative: string | undefined
55
+ cwdAbsolute: string | undefined
56
+ home: string
57
+ }
58
+ export function getCwd(args: GetCwdArguments): string {
59
+ if (args.cwdRelative) {
60
+ return join(args.rootPathAbsolute, args.cwdRelative)
61
+ }
62
+ return args.cwdAbsolute ?? args.home
63
+ }