Repository: stateful/vscode-runme
Pull request #837 (2023-09-18 15:40:36)

Bump @vercel/client from 13.0.1 to 13.0.3
Bumps [@vercel/client](https://github.com/vercel/vercel/tree/HEAD/packages/client) from 13.0.1 to 13.0.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/vercel/vercel/releases"><code>@​vercel/client</code>'s releases</a>.</em></p>
<blockquote>
<h2><code>@​vercel/client</code><a href="https://github.com/13"><code>@​13</code></a>.0.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [<a href="https://github.com/vercel/vercel/commit/50e04dd8584664c842a86c15d92d654f4ea8dcbb"><code>50e04dd85</code></a>, <a href="https://github.com/vercel/vercel/commit/45b73c7e86458564dc0bab007f6f6365c4c4ab5d"><code>45b73c7e8</code></a>, <a href="https://github.com/vercel/vercel/commit/d8bc570f604950d97156d4f33c8accecf3b3b28f"><code>d8bc570f6</code></a>]:
<ul>
<li><code>@​vercel/build-utils</code><a href="https://github.com/7"><code>@​7</code></a>.2.0</li>
</ul>
</li>
</ul>
<h2><code>@​vercel/client</code><a href="https://github.com/13"><code>@​13</code></a>.0.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [<a href="https://github.com/vercel/vercel/commit/5609a1187be9d6cf8d5f16825690c5ea72f17dc5"><code>5609a1187</code></a>, <a href="https://github.com/vercel/vercel/commit/1b4de4a986f7a612aac834ebae3ec7bb9e9b8cf8"><code>1b4de4a98</code></a>]:
<ul>
<li><code>@​vercel/build-utils</code><a href="https://github.com/7"><code>@​7</code></a>.1.1</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/vercel/vercel/blob/main/packages/client/CHANGELOG.md"><code>@​vercel/client</code>'s changelog</a>.</em></p>
<blockquote>
<h2>13.0.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [<a href="https://github.com/vercel/vercel/commit/50e04dd8584664c842a86c15d92d654f4ea8dcbb"><code>50e04dd85</code></a>, <a href="https://github.com/vercel/vercel/commit/45b73c7e86458564dc0bab007f6f6365c4c4ab5d"><code>45b73c7e8</code></a>, <a href="https://github.com/vercel/vercel/commit/d8bc570f604950d97156d4f33c8accecf3b3b28f"><code>d8bc570f6</code></a>]:
<ul>
<li><code>@​vercel/build-utils</code><a href="https://github.com/7"><code>@​7</code></a>.2.0</li>
</ul>
</li>
</ul>
<h2>13.0.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [<a href="https://github.com/vercel/vercel/commit/5609a1187be9d6cf8d5f16825690c5ea72f17dc5"><code>5609a1187</code></a>, <a href="https://github.com/vercel/vercel/commit/1b4de4a986f7a612aac834ebae3ec7bb9e9b8cf8"><code>1b4de4a98</code></a>]:
<ul>
<li><code>@​vercel/build-utils</code><a href="https://github.com/7"><code>@​7</code></a>.1.1</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/vercel/vercel/commit/bcebab7517a2d440bde4cfd486f68025e2408d5a"><code>bcebab7</code></a> Version Packages (<a href="https://github.com/vercel/vercel/tree/HEAD/packages/client/issues/10478">#10478</a>)</li>
<li><a href="https://github.com/vercel/vercel/commit/82231058da85a9bab65940180718e0538da0d35b"><code>8223105</code></a> Version Packages (<a href="https://github.com/vercel/vercel/tree/HEAD/packages/client/issues/10400">#10400</a>)</li>
<li><a href="https://github.com/vercel/vercel/commit/1138f7e3d16719b154cff73bc31b05c40c1e5710"><code>1138f7e</code></a> Use <code>esbuild</code> for non-ncc'd packages (<a href="https://github.com/vercel/vercel/tree/HEAD/packages/client/issues/10430">#10430</a>)</li>
<li>See full diff in <a href="https://github.com/vercel/vercel/commits/@vercel/client@13.0.3/packages/client">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@vercel/client&package-manager=npm_and_yarn&previous-version=13.0.1&new-version=13.0.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/package-lock.json b/package-lock.json
index 70b52167..39d3b81b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5457,16 +5457,16 @@
       }
     },
     "node_modules/@vercel/build-utils": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-7.1.0.tgz",
-      "integrity": "sha512-NoeBoZIueYUpuQc6W+4YuN3+XgxcuuQwZdahw1bfO2pWuWK4ikoZNHfSACyA/BL2j2LqjRBxIhVOI08CnPCXcA=="
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-7.2.0.tgz",
+      "integrity": "sha512-zLGXMuqRG/s++tqmui6MNRmHHi9phArug6XF5iRLVN8w/w3UxnnMVn3zXmnozrljrjwqSE43u8jLOVDqnk879Q=="
     },
     "node_modules/@vercel/client": {
-      "version": "13.0.1",
-      "resolved": "https://registry.npmjs.org/@vercel/client/-/client-13.0.1.tgz",
-      "integrity": "sha512-NbrDvLVh/P3g9A9L2RzZOZPS9JSqAlSdc070xCiIgWzPGiHt/NnGsHtEOYsJKYwpfdLKXJL4+7tndutKFxg+lg==",
+      "version": "13.0.3",
+      "resolved": "https://registry.npmjs.org/@vercel/client/-/client-13.0.3.tgz",
+      "integrity": "sha512-5nh0sUw2JptJ5EbXkwrLqucazZ/R+81m9CVbjwfXbiiv4OdbhBiDQvrxZO0xIiAfpzoehKdHxfxBeSZjoi6Bnw==",
       "dependencies": {
-        "@vercel/build-utils": "7.1.0",
+        "@vercel/build-utils": "7.2.0",
         "@vercel/routing-utils": "3.0.0",
         "@zeit/fetch": "5.2.0",
         "async-retry": "1.2.3",
diff --git a/package.json b/package.json
index 984c6d2d..2f1671e2 100644
--- a/package.json
+++ b/package.json
@@ -453,6 +453,34 @@
             "default": null,
             "markdownDescription": "Font family of Runme notebook terminal"
           },
+          "runme.terminal.cursorStyle": {
+            "type": "string",
+            "enum": [
+              "block",
+              "bar",
+              "underline"
+            ],
+            "default": "bar",
+            "markdownDescription": "The style of the Runme notebook terminal cursor."
+          },
+          "runme.terminal.cursorBlink": {
+            "type": "boolean",
+            "default": true,
+            "markdownDescription": "Defines whether the Runme notebook terminal cursor blinks."
+          },
+          "runme.terminal.cursorWidth": {
+            "type": "number",
+            "markdownDescription": "The width of the cursor in CSS pixels when `cursorStyle` is set to 'bar'."
+          },
+          "runme.terminal.smoothScrollDuration": {
+            "type": "number",
+            "default": 0,
+            "markdownDescription": "The duration to smoothly scroll between the origin and the target in milliseconds. Set to 0 to disable smooth scrolling and scroll instantly."
+          },
+          "runme.terminal.scrollback": {
+            "type": "number",
+            "markdownDescription": "The amount of scrollback in the terminal. Scrollback is the amount of rows that are retained when lines are scrolled beyond the initial viewport."
+          },
           "runme.terminal.rows": {
             "type": "integer",
             "default": 10,
@@ -719,4 +747,4 @@
     "yaml": "^2.3.2",
     "zod": "^3.22.2"
   }
-}
+}
\ No newline at end of file
diff --git a/src/client/components/terminal/index.ts b/src/client/components/terminal/index.ts
index 631257e9..e175385d 100644
--- a/src/client/components/terminal/index.ts
+++ b/src/client/components/terminal/index.ts
@@ -13,6 +13,7 @@ import { closeOutput, getContext } from '../../utils'
 import { onClientMessage, postClientMessage } from '../../../utils/messaging'
 import { stripANSI } from '../../../utils/ansi'
 import { APIMethod } from '../../../types'
+import type { TerminalConfiguration } from '../../../utils/configuration'
 
 import '../closeCellButton'
 import '../copyButton'
@@ -310,10 +311,25 @@ export class TerminalView extends LitElement {
   uuid?: string
 
   @property({ type: String })
-  terminalFontFamily?: string
+  fontFamily?: TerminalConfiguration['fontFamily']
 
   @property({ type: Number })
-  terminalFontSize?: number
+  fontSize?: TerminalConfiguration['fontSize']
+
+  @property({ type: String })
+  cursorStyle?: TerminalConfiguration['cursorStyle']
+
+  @property({ type: Boolean })
+  cursorBlink?: TerminalConfiguration['cursorBlink']
+
+  @property({ type: Number })
+  cursorWidth?: TerminalConfiguration['cursorWidth']
+
+  @property({ type: Number })
+  smoothScrollDuration?: TerminalConfiguration['smoothScrollDuration']
+
+  @property({ type: Number })
+  scrollback?: TerminalConfiguration['scrollback']
 
   @property({ type: String })
   initialContent?: string
@@ -359,15 +375,28 @@ export class TerminalView extends LitElement {
 
     this.rows = this.initialRows ?? this.rows
 
+    const {
+      rows,
+      cursorBlink,
+      fontSize,
+      cursorStyle,
+      cursorWidth,
+      fontFamily,
+      smoothScrollDuration,
+      scrollback,
+    } = this
     this.terminal = new XTermJS({
-      rows: this.rows,
-      cursorBlink: true,
-      fontSize: this.terminalFontSize,
-      cursorStyle: 'bar',
+      rows,
+      fontSize,
+      fontFamily,
+      scrollback,
+      cursorWidth,
+      cursorBlink,
+      cursorStyle,
+      smoothScrollDuration,
       disableStdin: false,
       convertEol: true,
       allowProposedApi: true,
-      fontFamily: this.terminalFontFamily,
       drawBoldTextInBrightColors: false,
     })
 
diff --git a/src/client/index.ts b/src/client/index.ts
index c02b1645..036d5f19 100644
--- a/src/client/index.ts
+++ b/src/client/index.ts
@@ -71,11 +71,31 @@ export const activate: ActivationFunction = (context: RendererContext<void>) =>
         case OutputType.terminal:
           const terminalElement = document.createElement(RENDERERS.TerminalView)
           terminalElement.setAttribute('uuid', payload.output['runme.dev/uuid'])
-          terminalElement.setAttribute('terminalFontFamily', payload.output.terminalFontFamily)
-          terminalElement.setAttribute(
-            'terminalFontSize',
-            payload.output.terminalFontSize.toString(),
-          )
+          terminalElement.setAttribute('fontFamily', payload.output.fontFamily)
+          if (typeof payload.output.fontSize === 'number') {
+            terminalElement.setAttribute('fontSize', payload.output.fontSize.toString())
+          }
+          if (payload.output.cursorStyle) {
+            terminalElement.setAttribute('cursorStyle', payload.output.cursorStyle)
+          }
+          if (typeof payload.output.cursorBlink === 'boolean') {
+            terminalElement.setAttribute(
+              'cursorBlink',
+              payload.output.cursorBlink ? 'true' : 'false',
+            )
+          }
+          if (typeof payload.output.cursorWidth === 'number') {
+            terminalElement.setAttribute('cursorWidth', payload.output.cursorWidth.toString())
+          }
+          if (typeof payload.output.smoothScrollDuration === 'number') {
+            terminalElement.setAttribute(
+              'smoothScrollDuration',
+              payload.output.smoothScrollDuration.toString(),
+            )
+          }
+          if (typeof payload.output.scrollback === 'number') {
+            terminalElement.setAttribute('scrollback', payload.output.scrollback.toString())
+          }
           if (payload.output.enableShareButton) {
             terminalElement.setAttribute(
               'enableShareButton',
diff --git a/src/extension/cell.ts b/src/extension/cell.ts
index 62792b63..226cd30e 100644
--- a/src/extension/cell.ts
+++ b/src/extension/cell.ts
@@ -17,12 +17,7 @@ import {
 import { OutputType } from '../constants'
 import { CellOutputPayload, DenoState, GitHubState, Serializer, VercelState } from '../types'
 import { Mutex } from '../utils/sync'
-import {
-  getNotebookTerminalFontFamily,
-  getNotebookTerminalFontSize,
-  getNotebookTerminalRows,
-  isRunmeAppButtonsEnabled,
-} from '../utils/configuration'
+import { getNotebookTerminalConfigurations, isRunmeAppButtonsEnabled } from '../utils/configuration'
 
 import { getAnnotations, replaceOutput, validateAnnotations } from './utils'
 import {
@@ -160,23 +155,16 @@ export class NotebookCellOutputManager {
         }
 
         if (type === OutputType.terminal) {
-          const editorSettings = workspace.getConfiguration('editor')
-
-          const terminalFontFamily =
-            getNotebookTerminalFontFamily() ?? editorSettings.get<string>('fontFamily', 'Arial')
-
-          const terminalFontSize =
-            getNotebookTerminalFontSize() ?? editorSettings.get<number>('fontSize', 10)
+          const terminalConfigurations = getNotebookTerminalConfigurations()
 
           const json: CellOutputPayload<OutputType.terminal> = {
             type: OutputType.terminal,
             output: {
               'runme.dev/uuid': cellId,
-              terminalFontFamily,
-              terminalFontSize,
               content: terminalState.serialize(),
-              initialRows: terminalRows || getNotebookTerminalRows(),
+              initialRows: terminalRows || terminalConfigurations.rows,
               enableShareButton: isRunmeAppButtonsEnabled(),
+              ...terminalConfigurations,
             },
           }
 
diff --git a/src/extension/commands/index.ts b/src/extension/commands/index.ts
index 7d4603dc..af0f1867 100644
--- a/src/extension/commands/index.ts
+++ b/src/extension/commands/index.ts
@@ -194,9 +194,7 @@ export function runCLICommand(
       env: envs,
     })
 
-    const runmeExec = getCLIUseIntegratedRunme()
-      ? getBinaryPath(extensionBaseUri, process.platform).fsPath
-      : 'runme'
+    const runmeExec = getCLIUseIntegratedRunme() ? getBinaryPath(extensionBaseUri).fsPath : 'runme'
 
     term.show(false)
     term.sendText(`${runmeExec} run ${args.join(' ')}`)
diff --git a/src/extension/server/runmeServer.ts b/src/extension/server/runmeServer.ts
index a9d5e9eb..07ea4bdd 100644
--- a/src/extension/server/runmeServer.ts
+++ b/src/extension/server/runmeServer.ts
@@ -62,7 +62,7 @@ class RunmeServer implements Disposable {
   ) {
     this.#port = getPortNumber()
     this.#loggingEnabled = enableServerLogs()
-    this.#binaryPath = getBinaryPath(extBasePath, process.platform)
+    this.#binaryPath = getBinaryPath(extBasePath)
     this.#retryOnFailure = options.retryOnFailure || false
     this.#maxNumberOfIntents = options.maxNumberOfIntents
     this.#acceptsIntents = options.acceptsConnection?.intents || 50
diff --git a/src/types.ts b/src/types.ts
index d87bdbd6..588af57d 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -18,6 +18,7 @@ import type * as Grpc from './extension/grpc/serializerTypes'
 import { IWorkflowRun } from './extension/services/types'
 import { Kernel } from './extension/kernel'
 import { IAppToken } from './extension/services/runme'
+import type { TerminalConfiguration } from './utils/configuration'
 
 export interface SyncSchema {
   onCommand?: {
@@ -114,10 +115,8 @@ interface Payload {
     validationErrors?: CellAnnotationsErrorResult
     uuid?: string
   }
-  [OutputType.terminal]: {
+  [OutputType.terminal]: TerminalConfiguration & {
     ['runme.dev/uuid']: string
-    terminalFontFamily: string
-    terminalFontSize: number
     content?: string
     initialRows?: number
     enableShareButton: boolean
diff --git a/src/utils/configuration.ts b/src/utils/configuration.ts
index 5af15e47..ef108137 100644
--- a/src/utils/configuration.ts
+++ b/src/utils/configuration.ts
@@ -26,7 +26,22 @@ const APP_LOOPBACK_MAPPING = new Map<string, string>([
   ['app.', ':4001'],
 ])
 
-type NotebookTerminalValue = keyof typeof configurationSchema.notebookTerminal
+type NotebookTerminalValue = keyof typeof notebookTerminalSchema
+
+const editorSettings = workspace.getConfiguration('editor')
+const notebookTerminalSchema = {
+  backgroundTask: z.boolean().default(true),
+  nonInteractive: z.boolean().default(false),
+  interactive: z.boolean().default(true),
+  fontSize: z.number().default(editorSettings.get<number>('fontSize', 10)),
+  fontFamily: z.string().default(editorSettings.get<string>('fontFamily', 'Arial')),
+  rows: z.number().int().default(10),
+  cursorStyle: z.enum(['block', 'bar', 'underline']).default('bar'),
+  cursorBlink: z.boolean().default(true).optional(),
+  cursorWidth: z.number().optional(),
+  smoothScrollDuration: z.number().optional(),
+  scrollback: z.number().optional(),
+}
 
 const configurationSchema = {
   actions: {
@@ -39,14 +54,6 @@ const configurationSchema = {
     enableTLS: z.boolean().default(true),
     tlsDir: z.string().optional(),
   },
-  notebookTerminal: {
-    backgroundTask: z.boolean().default(true),
-    nonInteractive: z.boolean().default(false),
-    interactive: z.boolean().default(true),
-    fontSize: z.number().optional(),
-    fontFamily: z.string().optional(),
-    rows: z.number().int(),
-  },
   codelens: {
     enable: z.boolean().default(true),
   },
@@ -64,6 +71,9 @@ const configurationSchema = {
   },
 }
 
+const notebookTerminalSchemaObject = z.object(notebookTerminalSchema)
+export type TerminalConfiguration = z.infer<typeof notebookTerminalSchemaObject>
+
 const getActionsConfigurationValue = <T>(
   configName: keyof typeof configurationSchema.actions,
   defaultValue: T,
@@ -96,7 +106,7 @@ const getRunmeTerminalConfigurationValue = <T>(
 ) => {
   const configurationSection = workspace.getConfiguration(TERMINAL_SECTION_NAME)
   const configurationValue = configurationSection.get<T>(configName)!
-  const parseResult = configurationSchema.notebookTerminal[configName].safeParse(configurationValue)
+  const parseResult = notebookTerminalSchema[configName].safeParse(configurationValue)
   if (parseResult.success) {
     return parseResult.data as T
   }
@@ -178,7 +188,7 @@ const getTLSDir = (extensionsDir: Uri): string => {
   )
 }
 
-const getBinaryPath = (extensionBaseUri: Uri, platform: string): Uri => {
+const getBinaryPath = (extensionBaseUri: Uri, platform = os.platform()): Uri => {
   const userPath = getServerConfigurationValue<string | undefined>('binaryPath', undefined)
 
   const isWin = platform.toLowerCase().startsWith('win')
@@ -201,17 +211,21 @@ const enableServerLogs = (): boolean => {
 }
 
 const isNotebookTerminalFeatureEnabled = (
-  featureName: keyof typeof configurationSchema.notebookTerminal,
+  featureName: keyof typeof notebookTerminalSchema,
 ): boolean => {
   return getRunmeTerminalConfigurationValue(featureName, false)
 }
 
-const getNotebookTerminalFontSize = (): number | undefined => {
-  return getRunmeTerminalConfigurationValue<number | undefined>('fontSize', undefined)
-}
-
-const getNotebookTerminalFontFamily = (): string | undefined => {
-  return getRunmeTerminalConfigurationValue<string | undefined>('fontFamily', undefined)
+const getNotebookTerminalConfigurations = () => {
+  const schema = z.object(notebookTerminalSchema)
+  const keys = Object.keys(notebookTerminalSchema) as Array<keyof typeof notebookTerminalSchema>
+  return keys.reduce(
+    (p, c) => {
+      p[c] = getRunmeTerminalConfigurationValue<never>(c, undefined as never)
+      return p
+    },
+    {} as z.infer<typeof schema>,
+  )
 }
 
 const isNotebookTerminalEnabledForCell = (cell: NotebookCell): boolean => {
@@ -224,10 +238,6 @@ const isNotebookTerminalEnabledForCell = (cell: NotebookCell): boolean => {
     : isNotebookTerminalFeatureEnabled('nonInteractive')
 }
 
-const getNotebookTerminalRows = (): number => {
-  return getRunmeTerminalConfigurationValue<number>('rows', 10)
-}
-
 const getCodeLensEnabled = (): boolean => {
   return getCodeLensConfigurationValue<boolean>('enable', true)
 }
@@ -235,8 +245,7 @@ const getCodeLensEnabled = (): boolean => {
 const registerExtensionEnvironmentVariables = (context: ExtensionContext): void => {
   context.environmentVariableCollection.prepend(
     'PATH',
-    path.dirname(getBinaryPath(context.extensionUri, os.platform()).fsPath) +
-      (isWindows() ? ';' : ':'),
+    path.dirname(getBinaryPath(context.extensionUri).fsPath) + (isWindows() ? ';' : ':'),
   )
 }
 
@@ -317,9 +326,7 @@ export {
   isNotebookTerminalEnabledForCell,
   getTLSEnabled,
   getTLSDir,
-  getNotebookTerminalFontFamily,
-  getNotebookTerminalFontSize,
-  getNotebookTerminalRows,
+  getNotebookTerminalConfigurations,
   getCodeLensEnabled,
   registerExtensionEnvironmentVariables,
   getCustomServerAddress,


Test patch:
diff --git a/tests/extension/__snapshots__/configuration.test.ts.snap b/tests/extension/__snapshots__/configuration.test.ts.snap
new file mode 100644
index 00000000..062fb37d
--- /dev/null
+++ b/tests/extension/__snapshots__/configuration.test.ts.snap
@@ -0,0 +1,17 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Configuration > should get nullish from font family 1`] = `
+{
+  "backgroundTask": true,
+  "cursorBlink": undefined,
+  "cursorStyle": "bar",
+  "cursorWidth": undefined,
+  "fontFamily": undefined,
+  "fontSize": undefined,
+  "interactive": true,
+  "nonInteractive": false,
+  "rows": 10,
+  "scrollback": undefined,
+  "smoothScrollDuration": undefined,
+}
+`;
diff --git a/tests/extension/commands/index.test.ts b/tests/extension/commands/index.test.ts
index 8ed9d0a2..5af52d03 100644
--- a/tests/extension/commands/index.test.ts
+++ b/tests/extension/commands/index.test.ts
@@ -140,13 +140,6 @@ suite('runCliCommand', () => {
       isDirty: false
     }
 
-    // vi.mocked(getAnnotations).mockReturnValueOnce({
-    //   name: 'foo-bar',
-    // } as any)
-
-    // vi.mocked(getBinaryPath).mockReturnValueOnce(Uri.file('/bin/runme'))
-    // vi.mocked(window.showInformationMessage).mockResolvedValueOnce(false as any)
-
     await runCLICommand({} as any, false, {} as any, {} as any)(cell)
     expect(vi.mocked((terminal as any).sendText)).toHaveBeenCalledWith(
       'runme run --chdir="/foo/bar" --filename="README.md" --index=0'
diff --git a/tests/extension/configuration.test.ts b/tests/extension/configuration.test.ts
index 89482b2a..4cd0b1d4 100644
--- a/tests/extension/configuration.test.ts
+++ b/tests/extension/configuration.test.ts
@@ -10,8 +10,7 @@ import {
   getBinaryPath,
   getServerConfigurationValue,
   getTLSDir,
-  getNotebookTerminalFontFamily,
-  getNotebookTerminalFontSize,
+  getNotebookTerminalConfigurations,
   getCodeLensEnabled,
   getCLIUseIntegratedRunme
 } from '../../src/utils/configuration'
@@ -23,7 +22,19 @@ vi.mock('../../src/extension/grpc/runnerTypes', () => ({}))
 const FAKE_UNIX_EXT_PATH = '/Users/user/.vscode/extension/stateful.runme'
 const FAKE_WIN_EXT_PATH = 'C:\\Users\\.vscode\\extensions\\stateful.runme'
 
-const SETTINGS_MOCK:
+vi.mock('path', async (origModFactory) => {
+  const origMod = await origModFactory<typeof path>()
+  const p = {
+    ...origMod,
+    join: vi.fn(origMod.join),
+    isAbsolute: vi.fn(origMod.isAbsolute)
+  }
+  return { ...p, default: p }
+})
+
+vi.mock('vscode', async () => {
+  const mocked = await import('../../__mocks__/vscode')
+  const SETTINGS_MOCK:
     {
         port: number | string | undefined
         binaryPath: string | undefined
@@ -36,67 +47,38 @@ const SETTINGS_MOCK:
     enableLogger: undefined,
     tlsDir: undefined,
     baseDomain: undefined,
-}
-
-beforeEach(() => {
-  vi.mock('vscode', async () => {
-    const mocked = await import('../../__mocks__/vscode')
-
-    return ({
-      ...mocked,
-      workspace: {
-        getConfiguration: vi.fn().mockReturnValue({
-          get: (configurationName) => {
-            return SETTINGS_MOCK[configurationName]
-          }
-        }),
-      },
-      Uri: mocked.Uri,
-    })
-  })
-
-  vi.mock('vscode-telemetry')
-
-  vi.mock('node:path', async () => {
-    const p = await vi.importActual('node:path') as typeof import('node:path')
-
-    const pathMock = {
-      win32: p.win32,
-      posix: p.posix,
-    }
-
-    mockedPathMethods().forEach(m => pathMock[m] = vi.fn(p[m] as any))
-
-    return ({
-      ...pathMock,
-      default: pathMock,
-    })
+  }
+
+  return ({
+    ...mocked,
+    workspace: {
+      getConfiguration: vi.fn().mockReturnValue({
+        update: (configurationName: string, val: unknown) => {
+          SETTINGS_MOCK[configurationName] = val
+        },
+        get: (configurationName) => {
+          return SETTINGS_MOCK[configurationName]
+        }
+      }),
+    },
+    Uri: mocked.Uri,
   })
 })
 
-function mockedPathMethods() {
-  return ['join', 'isAbsolute'] as const
-}
-
-function platformPathMocks(platform: path.PlatformPath) {
-  mockedPathMethods().forEach(m => vi.mocked(path[m]).mockImplementation(platform[m] as any))
-}
-
-afterEach(() => {
-    Object.keys(SETTINGS_MOCK).forEach(key => {
-          SETTINGS_MOCK[key] = undefined
-    })
-})
+vi.mock('vscode-telemetry')
 
 suite('Configuration', () => {
     test('should get nullish from font family', () => {
-      const fontFamily = getNotebookTerminalFontFamily()
-      expect(fontFamily).toBeUndefined()
-    })
+      expect(getNotebookTerminalConfigurations()).toMatchSnapshot()
+      workspace.getConfiguration().update('fontFamily', 'Fira Code')
+      expect(getNotebookTerminalConfigurations().fontFamily).toStrictEqual('Fira Code')
+
+      // example fails because "line" is not valid
+      workspace.getConfiguration().update('cursorStyle', 'line')
+      expect(getNotebookTerminalConfigurations().cursorStyle).toStrictEqual(undefined)
 
-    test('should get nullish from font size', () => {
-      const fontSize = getNotebookTerminalFontSize()
-      expect(fontSize).toBeUndefined()
+      workspace.getConfiguration().update('cursorStyle', 'underline')
+      expect(getNotebookTerminalConfigurations().cursorStyle).toStrictEqual('underline')
     })
 
     test('should default to a valid port number', () => {
@@ -110,29 +92,29 @@ suite('Configuration', () => {
     })
 
     test('should disable server logs with an invalid value', () => {
-      SETTINGS_MOCK.enableLogger = undefined
+      workspace.getConfiguration().update('enableLogger', undefined)
       const path = enableServerLogs()
       expect(path).toBeFalsy()
     })
 
     test('should disable server logs with an invalid string', () => {
-        SETTINGS_MOCK.enableLogger = 'true'
+        workspace.getConfiguration().update('enableLogger', 'true')
         const path = enableServerLogs()
         expect(path).toBeFalsy()
     })
 
     test('should get default TLS dir by default', () => {
-      SETTINGS_MOCK.tlsDir = undefined
+      workspace.getConfiguration().update('tlsDir', undefined)
       expect(getTLSDir(Uri.file('/ext/base'))).toBe(Uri.file('/ext/base/tls').fsPath)
     })
 
     test('should get set TLS dir if set', () => {
-      SETTINGS_MOCK.tlsDir = '/tmp/runme/tls'
+      workspace.getConfiguration().update('tlsDir', '/tmp/runme/tls')
       expect(getTLSDir(Uri.file('/ext/base'))).toBe('/tmp/runme/tls')
     })
 
     test('getServerConfigurationValue Should default to undefined binaryPath', () => {
-      SETTINGS_MOCK.binaryPath = undefined
+      workspace.getConfiguration().update('binaryPath', undefined)
 
       expect(
         getServerConfigurationValue<string | undefined>('binaryPath', undefined)
@@ -140,7 +122,7 @@ suite('Configuration', () => {
     })
 
     test('getServerConfigurationValue Should give proper binaryPath if defined', () => {
-      SETTINGS_MOCK.binaryPath = '/binary/path'
+      workspace.getConfiguration().update('binaryPath', '/binary/path')
 
       expect(
         getServerConfigurationValue<string | undefined>('binaryPath', undefined)
@@ -159,7 +141,11 @@ suite('Configuration', () => {
 
     suite('posix', () => {
       beforeEach(() => {
-        platformPathMocks(path.posix)
+        workspace.getConfiguration().update('binaryPath', undefined)
+      })
+
+      afterEach(() => {
+        workspace.getConfiguration().update('binaryPath', undefined)
       })
 
       test('should default to a valid binaryPath', () => {
@@ -168,21 +154,21 @@ suite('Configuration', () => {
       })
 
       test('should default to a valid relative binaryPath when specified', () => {
-          SETTINGS_MOCK.binaryPath = 'newBin'
-          // @ts-expect-error
+          workspace.getConfiguration().update('binaryPath', 'newBin')
+          // @ts-expect-error readonly
           workspace.workspaceFolders = [{ uri: Uri.file('/Users/user/Projects/project') }]
           const binary = getBinaryPath(Uri.file(FAKE_UNIX_EXT_PATH), 'linux')
           expect(binary.fsPath).toStrictEqual('/Users/user/Projects/project/newBin')
       })
 
       test('should default to a valid absolute binaryPath when specified', () => {
-        SETTINGS_MOCK.binaryPath = '/opt/homebrew/bin/runme'
+        workspace.getConfiguration().update('binaryPath', '/opt/homebrew/bin/runme')
         const binary = getBinaryPath(Uri.file(FAKE_UNIX_EXT_PATH), 'linux')
         expect(binary.fsPath).toStrictEqual('/opt/homebrew/bin/runme')
       })
 
       test('should use runme for non-windows platforms', () => {
-          SETTINGS_MOCK.binaryPath = '/opt/homebrew/bin/runme'
+          workspace.getConfiguration().update('binaryPath', '/opt/homebrew/bin/runme')
           const binary = getBinaryPath(Uri.file(FAKE_UNIX_EXT_PATH), 'darwin')
           expect(binary.fsPath).toStrictEqual('/opt/homebrew/bin/runme')
       })
@@ -190,26 +176,32 @@ suite('Configuration', () => {
 
     suite('win32', () => {
       beforeEach(() => {
-        platformPathMocks(path.win32)
+        path.join = vi.fn(path.win32.join)
+        path.isAbsolute = vi.fn(path.win32.isAbsolute)
+      })
+
+      afterEach(() => {
+        vi.mocked(path.join).mockRestore()
+        vi.mocked(path.isAbsolute).mockRestore()
       })
 
       test('should default to a valid binaryPath exe on windows', () => {
-        const binary = getBinaryPath(Uri.file(FAKE_WIN_EXT_PATH), 'win')
+        const binary = getBinaryPath(Uri.file(FAKE_WIN_EXT_PATH), 'win32')
         expect(binary.fsPath).toStrictEqual(
           'c:\\Users\\.vscode\\extensions\\stateful.runme\\bin\\runme.exe'
         )
       })
 
       test('should use runme.exe for windows platforms with absolute path', () => {
-        SETTINGS_MOCK.binaryPath = 'C:\\custom\\path\\to\\bin\\runme.exe'
+        workspace.getConfiguration().update('binaryPath', 'C:\\custom\\path\\to\\bin\\runme.exe')
 
         const binary = getBinaryPath(Uri.file(FAKE_WIN_EXT_PATH), 'win32')
         expect(binary.fsPath).toStrictEqual('c:\\custom\\path\\to\\bin\\runme.exe')
       })
 
       test('should use runme.exe for windows platforms with relative path', () => {
-          SETTINGS_MOCK.binaryPath = 'newBin.exe'
-          // @ts-expect-error
+          workspace.getConfiguration().update('binaryPath', 'newBin.exe')
+          // @ts-expect-error readonly
           workspace.workspaceFolders = [{ uri: Uri.file('c:\\Users\\Projects\\project') }]
           const binary = getBinaryPath(Uri.file(FAKE_WIN_EXT_PATH), 'win32')
           expect(binary.fsPath).toStrictEqual('c:\\Users\\Projects\\project\\newBin.exe')
@@ -238,25 +230,25 @@ suite('Configuration', () => {
       })
 
       test('should allow api URL with http for 127.0.0.1', async () => {
-        SETTINGS_MOCK.baseDomain = '127.0.0.1'
+        workspace.getConfiguration().update('baseDomain', '127.0.0.1')
         const url = getRunmeAppUrl(['api'])
         expect(url).toStrictEqual('http://127.0.0.1:4000/')
       })
 
       test('should allow app URL with http for localhost', async () => {
-        SETTINGS_MOCK.baseDomain = 'localhost'
+        workspace.getConfiguration().update('baseDomain', 'localhost')
         const url = getRunmeAppUrl(['app'])
         expect(url).toStrictEqual('http://localhost:4001/')
       })
 
       test('should allow app URL with http for localhost without subdomain', async () => {
-        SETTINGS_MOCK.baseDomain = 'localhost'
+        workspace.getConfiguration().update('baseDomain', 'localhost')
         const url = getRunmeAppUrl([])
         expect(url).toStrictEqual('http://localhost/')
       })
 
       test('should allow specific app URL for remote dev returning staging-based domains', async () => {
-        SETTINGS_MOCK.baseDomain = 'http://localhost:4001'
+        workspace.getConfiguration().update('baseDomain', 'http://localhost:4001')
         const app = getRunmeAppUrl(['app'])
         expect(app).toStrictEqual('http://localhost:4001')
         const api = getRunmeAppUrl(['api'])
diff --git a/tests/extension/panels/panel.test.ts b/tests/extension/panels/panel.test.ts
index a9ea48ef..51503264 100644
--- a/tests/extension/panels/panel.test.ts
+++ b/tests/extension/panels/panel.test.ts
@@ -1,5 +1,5 @@
-import { suite, test, expect, vi, afterEach, beforeEach } from 'vitest'
-import { Uri, type ExtensionContext, type WebviewView } from 'vscode'
+import { suite, test, expect, vi } from 'vitest'
+import { workspace, Uri, type ExtensionContext, type WebviewView } from 'vscode'
 
 import Panel from '../../../src/extension/panels/panel'
 
@@ -9,37 +9,25 @@ vi.mock('vscode-telemetry')
 vi.mock('../../../src/extension/grpc/client', () => ({}))
 vi.mock('../../../src/extension/runner', () => ({}))
 
-const SETTINGS_MOCK:
-    {
-        baseDomain: string | undefined
-    } = {
-    baseDomain: undefined,
-}
-
-beforeEach(() => {
-  vi.mock('vscode', async () => {
-    const mocked = await import('../../../__mocks__/vscode')
-
-    return ({
-      ...mocked,
-      workspace: {
-        getConfiguration: vi.fn().mockReturnValue({
-          get: (configurationName) => {
-            return SETTINGS_MOCK[configurationName]
-          }
-        }),
-      },
-      Uri: mocked.Uri,
-    })
+vi.mock('vscode', async () => {
+  const mocked = await import('../../../__mocks__/vscode')
+  const SETTINGS_MOCK: any = { baseDomain: undefined }
+
+  return ({
+    ...mocked,
+    workspace: {
+      getConfiguration: vi.fn().mockReturnValue({
+        update: (configurationName: string, val: unknown) => {
+          SETTINGS_MOCK[configurationName] = val
+        },
+        get: (configurationName) => {
+          return SETTINGS_MOCK[configurationName]
+        }
+      })
+    }
   })
 })
 
-afterEach(() => {
-    Object.keys(SETTINGS_MOCK).forEach(key => {
-          SETTINGS_MOCK[key] = undefined
-    })
-})
-
 vi.mock('../../../src/extension/utils', () => {
   return {
     fetchStaticHtml: vi.fn().mockResolvedValue({
@@ -100,7 +88,7 @@ suite('Panel', () => {
   })
 
   test('resovles authed localhost', async () => {
-    SETTINGS_MOCK.baseDomain = 'localhost'
+    workspace.getConfiguration().update('baseDomain', 'localhost')
     const p = new Panel(contextMock, 'testing')
     p.getAppToken = vi.fn().mockResolvedValue({ token: 'webview.auth.token' })
 
@@ -113,7 +101,7 @@ suite('Panel', () => {
   })
 
   test('resovles unauthed localhost', async () => {
-    SETTINGS_MOCK.baseDomain = 'localhost'
+    workspace.getConfiguration().update('baseDomain', 'localhost')
     const p = new Panel(contextMock, 'testing')
     p.getAppToken = vi.fn().mockResolvedValue(null)
 
diff --git a/tests/extension/utils.test.ts b/tests/extension/utils.test.ts
index b4a5193b..9b85324d 100644
--- a/tests/extension/utils.test.ts
+++ b/tests/extension/utils.test.ts
@@ -64,7 +64,7 @@ vi.mock('vscode', async () => {
       }
     },
     workspace: {
-      getConfiguration: vi.fn(),
+      getConfiguration: vi.fn().mockReturnValue(new Map()),
       fs: mocked.workspace.fs,
       workspaceFolders: [],
     },