Repository: stateful/vscode-runme
Pull request #900 (2023-10-16 15:19:04)

Avoid race condition when dispose is called on terminals
Unfortunately, since we have to adhere to the pseudo terminal interface, calling `dispose` on a terminal will cause a race condition where for a period of time it's unclear whether or not the underlying process has exited. Stopping an already exited process breaking every "second" successive runs of back-to-back runs of a cell.

https://github.com/stateful/vscode-runme/pull/829/files#diff-61fe624cda28319d214d5b79f135f89003df9be2b56ee99ddd05978827d9b40bR627

This PR introduces a timeout of 1s which only occurs when background tasks are being stopped. Since they are a lot less common and stopping them is infrequent it feels like the right tradeoff to me.

Steps to repro: run same cell (background=false) multiple times consecutively. Please note that `main` currently forgoes `dispose` to unbreak cell execution.


Patch:
diff --git a/package-lock.json b/package-lock.json
index 95b6a91b..0e87ab2b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "runme",
-  "version": "1.10.2",
+  "version": "1.10.3",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "runme",
-      "version": "1.10.2",
+      "version": "1.10.3",
       "hasInstallScript": true,
       "license": "Apache-2.0",
       "dependencies": {
@@ -465,12 +465,12 @@
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.22.10",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
-      "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
+      "version": "7.22.13",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+      "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
       "dev": true,
       "dependencies": {
-        "@babel/highlight": "^7.22.10",
+        "@babel/highlight": "^7.22.13",
         "chalk": "^2.4.2"
       },
       "engines": {
@@ -597,12 +597,12 @@
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.22.10",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
-      "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
+      "version": "7.23.0",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+      "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.22.10",
+        "@babel/types": "^7.23.0",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
@@ -681,22 +681,22 @@
       }
     },
     "node_modules/@babel/helper-environment-visitor": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
-      "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+      "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-function-name": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
-      "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+      "version": "7.23.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+      "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
       "dev": true,
       "dependencies": {
-        "@babel/template": "^7.22.5",
-        "@babel/types": "^7.22.5"
+        "@babel/template": "^7.22.15",
+        "@babel/types": "^7.23.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -841,9 +841,9 @@
       }
     },
     "node_modules/@babel/helper-validator-identifier": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
-      "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+      "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
       "dev": true,
       "engines": {
         "node": ">=6.9.0"
@@ -873,12 +873,12 @@
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.22.10",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
-      "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+      "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-validator-identifier": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.20",
         "chalk": "^2.4.2",
         "js-tokens": "^4.0.0"
       },
@@ -958,9 +958,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.22.10",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz",
-      "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==",
+      "version": "7.23.0",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+      "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
       "dev": true,
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -1406,33 +1406,33 @@
       }
     },
     "node_modules/@babel/template": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
-      "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+      "version": "7.22.15",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+      "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
       "dev": true,
       "dependencies": {
-        "@babel/code-frame": "^7.22.5",
-        "@babel/parser": "^7.22.5",
-        "@babel/types": "^7.22.5"
+        "@babel/code-frame": "^7.22.13",
+        "@babel/parser": "^7.22.15",
+        "@babel/types": "^7.22.15"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.22.10",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz",
-      "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==",
+      "version": "7.23.2",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+      "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
       "dev": true,
       "dependencies": {
-        "@babel/code-frame": "^7.22.10",
-        "@babel/generator": "^7.22.10",
-        "@babel/helper-environment-visitor": "^7.22.5",
-        "@babel/helper-function-name": "^7.22.5",
+        "@babel/code-frame": "^7.22.13",
+        "@babel/generator": "^7.23.0",
+        "@babel/helper-environment-visitor": "^7.22.20",
+        "@babel/helper-function-name": "^7.23.0",
         "@babel/helper-hoist-variables": "^7.22.5",
         "@babel/helper-split-export-declaration": "^7.22.6",
-        "@babel/parser": "^7.22.10",
-        "@babel/types": "^7.22.10",
+        "@babel/parser": "^7.23.0",
+        "@babel/types": "^7.23.0",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -1441,13 +1441,13 @@
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.22.10",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz",
-      "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==",
+      "version": "7.23.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+      "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
       "dev": true,
       "dependencies": {
         "@babel/helper-string-parser": "^7.22.5",
-        "@babel/helper-validator-identifier": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.20",
         "to-fast-properties": "^2.0.0"
       },
       "engines": {
@@ -5310,53 +5310,6 @@
         }
       }
     },
-    "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz",
-      "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "@typescript-eslint/visitor-keys": "6.7.4"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
-      "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
-      "dev": true,
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
-      "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "eslint-visitor-keys": "^3.4.1"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
     "node_modules/@typescript-eslint/parser": {
       "version": "6.7.4",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz",
@@ -5429,63 +5382,6 @@
         }
       }
     },
-    "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
-      "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
-      "dev": true,
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz",
-      "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "@typescript-eslint/visitor-keys": "6.7.4",
-        "debug": "^4.3.4",
-        "globby": "^11.1.0",
-        "is-glob": "^4.0.3",
-        "semver": "^7.5.4",
-        "ts-api-utils": "^1.0.1"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
-      "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "eslint-visitor-keys": "^3.4.1"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
     "node_modules/@typescript-eslint/types": {
       "version": "6.7.4",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
@@ -5551,80 +5447,6 @@
         "eslint": "^7.0.0 || ^8.0.0"
       }
     },
-    "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz",
-      "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "@typescript-eslint/visitor-keys": "6.7.4"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
-      "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
-      "dev": true,
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz",
-      "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "@typescript-eslint/visitor-keys": "6.7.4",
-        "debug": "^4.3.4",
-        "globby": "^11.1.0",
-        "is-glob": "^4.0.3",
-        "semver": "^7.5.4",
-        "ts-api-utils": "^1.0.1"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
-      "version": "6.7.4",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
-      "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
-      "dev": true,
-      "dependencies": {
-        "@typescript-eslint/types": "6.7.4",
-        "eslint-visitor-keys": "^3.4.1"
-      },
-      "engines": {
-        "node": "^16.0.0 || >=18.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
     "node_modules/@typescript-eslint/visitor-keys": {
       "version": "6.7.4",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
diff --git a/package.json b/package.json
index 91f3b05c..41a14959 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "runme",
-  "version": "1.10.2",
+  "version": "1.10.3",
   "publisher": "stateful",
   "displayName": "Runme runs Markdown",
   "description": "Execute commands inside your runbooks, docs, and READMEs.",
@@ -416,6 +416,16 @@
             "default": true,
             "markdownDescription": "Use TLS over GRPC server interface (strongly recommended - only disable if you know what you are doing!!!)"
           },
+          "runme.server.transportType": {
+            "type": "string",
+            "scope": "window",
+            "default": "TCP",
+            "enum": [
+              "TCP",
+              "UDS"
+            ],
+            "markdownDescription": "Connect to GRPC server interface via TCP or Unix Domain Socket (not available on Windows)"
+          },
           "runme.terminal.backgroundTask": {
             "type": "boolean",
             "scope": "machine",
diff --git a/src/extension/kernel.ts b/src/extension/kernel.ts
index 42526dc8..12ec3f79 100644
--- a/src/extension/kernel.ts
+++ b/src/extension/kernel.ts
@@ -640,7 +640,7 @@ export class Kernel implements Disposable {
     // Dispose previously attached terminal
     const activeTerminal = this.activeTerminals.find((t) => t.runmeId === runmeId)
     if (activeTerminal) {
-      // activeTerminal.dispose()
+      activeTerminal.dispose()
       this.activeTerminals.splice(this.activeTerminals.indexOf(activeTerminal), 1)
     }
     const exists = this.activeTerminals.find((t) => t.executionId === executionId)
diff --git a/src/extension/runner.ts b/src/extension/runner.ts
index c3994dd7..1088f2e7 100644
--- a/src/extension/runner.ts
+++ b/src/extension/runner.ts
@@ -8,6 +8,7 @@ import {
   EventEmitter,
   window,
 } from 'vscode'
+import { interval, take, takeWhile, map } from 'rxjs'
 import { RpcError } from '@protobuf-ts/runtime-rpc'
 
 import type { DisposableAsync } from '../types'
@@ -660,15 +661,27 @@ export class GrpcRunnerProgramSession implements IRunnerProgramSession {
    * please use `_close` internally
    */
   close() {
-    if (this.hasExited()) {
-      return
-    }
-
-    this.session.requests.send(
-      ExecuteRequest.create({
-        stop: this.isPseudoterminal() ? ExecuteStop.INTERRUPT : ExecuteStop.KILL,
-      }),
+    let reason = this.hasExited()
+    // avoid race by giving it 1s to have a reason
+    const reasonInterval$ = interval(50).pipe(
+      take(20),
+      map(() => this.hasExited()),
+      takeWhile((r) => !Boolean(r)),
     )
+
+    reasonInterval$.subscribe({
+      next: (r) => (reason = r),
+      complete: () => {
+        if (reason) {
+          return
+        }
+        this.session.requests.send(
+          ExecuteRequest.create({
+            stop: this.isPseudoterminal() ? ExecuteStop.INTERRUPT : ExecuteStop.KILL,
+          }),
+        )
+      },
+    })
   }
 
   /**
diff --git a/src/extension/server/runmeServer.ts b/src/extension/server/runmeServer.ts
index 07ea4bdd..f8204bde 100644
--- a/src/extension/server/runmeServer.ts
+++ b/src/extension/server/runmeServer.ts
@@ -1,6 +1,7 @@
 import { ChildProcessWithoutNullStreams, spawn } from 'node:child_process'
 import fs from 'node:fs/promises'
 import path from 'node:path'
+import crypto from 'node:crypto'
 
 import { ChannelCredentials } from '@grpc/grpc-js'
 import { GrpcTransport } from '@protobuf-ts/grpc-transport'
@@ -10,10 +11,12 @@ import getLogger from '../logger'
 import { HealthCheckRequest, HealthCheckResponse_ServingStatus } from '../grpc/healthTypes'
 import { SERVER_ADDRESS } from '../../constants'
 import {
+  ServerTransportType,
   enableServerLogs,
   getBinaryPath,
   getCustomServerAddress,
   getPortNumber,
+  getServerConfigurationValue,
   getTLSDir,
   getTLSEnabled,
 } from '../../utils/configuration'
@@ -36,6 +39,7 @@ const log = getLogger('RunmeServer')
 
 class RunmeServer implements Disposable {
   #port: number
+  #socketId?: string
   #process: ChildProcessWithoutNullStreams | undefined
   #binaryPath: Uri
   #retryOnFailure: boolean
@@ -106,8 +110,32 @@ class RunmeServer implements Disposable {
     return false
   }
 
-  address() {
-    return getCustomServerAddress() || `${SERVER_ADDRESS}:${this.#port}`
+  address(): string {
+    const customAddress = getCustomServerAddress()
+    if (customAddress) {
+      return customAddress
+    }
+
+    const defaultTransport: ServerTransportType = 'TCP'
+    const transportType = getServerConfigurationValue<ServerTransportType>(
+      'transportType',
+      defaultTransport,
+    )
+
+    if (transportType === defaultTransport) {
+      const host = `${SERVER_ADDRESS}:${this.#port}`
+      return host
+    }
+
+    // only do this once and only if required
+    if (!this.#socketId) {
+      const rndBytes = crypto.randomBytes(4)
+      this.#socketId = rndBytes.toString('hex')
+    }
+
+    const sockPath = path.join('/tmp', `/runme-${this.#socketId}.sock`)
+    const unix = `unix://${sockPath}`
+    return unix
   }
 
   private get externalServer(): boolean {
diff --git a/src/utils/configuration.ts b/src/utils/configuration.ts
index d4db48e3..37517e3c 100644
--- a/src/utils/configuration.ts
+++ b/src/utils/configuration.ts
@@ -51,11 +51,12 @@ const configurationSchema = {
     openViewInEditor: OpenViewInEditorAction.default('split'),
   },
   server: {
-    customAddress: z.string().nonempty().optional(),
+    customAddress: z.string().min(1).optional(),
     binaryPath: z.string().optional(),
     enableLogger: z.boolean().default(false),
     enableTLS: z.boolean().default(true),
     tlsDir: z.string().optional(),
+    transportType: z.enum(['TCP', 'UDS']).default('TCP'),
   },
   codelens: {
     enable: z.boolean().default(true),
@@ -77,6 +78,7 @@ const configurationSchema = {
 
 const notebookTerminalSchemaObject = z.object(notebookTerminalSchema)
 export type TerminalConfiguration = z.infer<typeof notebookTerminalSchemaObject>
+export type ServerTransportType = z.infer<typeof configurationSchema.server.transportType>
 
 const getActionsConfigurationValue = <T>(
   configName: keyof typeof configurationSchema.actions,


Test patch:
diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json
index 690da5ae..c509d478 100644
--- a/tests/e2e/package-lock.json
+++ b/tests/e2e/package-lock.json
@@ -182,6 +182,14 @@
         "fast-uri": "^2.0.0"
       }
     },
+    "node_modules/@fastify/busboy": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz",
+      "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==",
+      "engines": {
+        "node": ">=14"
+      }
+    },
     "node_modules/@fastify/cors": {
       "version": "8.3.0",
       "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-8.3.0.tgz",
@@ -1530,17 +1538,6 @@
         "node": ">=0.2.0"
       }
     },
-    "node_modules/busboy": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
-      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
-      "dependencies": {
-        "streamsearch": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=10.16.0"
-      }
-    },
     "node_modules/cac": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz",
@@ -7313,14 +7310,6 @@
         "node": ">= 0.10.0"
       }
     },
-    "node_modules/streamsearch": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
-      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
-      "engines": {
-        "node": ">=10.0.0"
-      }
-    },
     "node_modules/streamx": {
       "version": "2.15.1",
       "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz",
@@ -7829,11 +7818,11 @@
       }
     },
     "node_modules/undici": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz",
-      "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==",
+      "version": "5.26.3",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.3.tgz",
+      "integrity": "sha512-H7n2zmKEWgOllKkIUkLvFmsJQj062lSm3uA4EYApG8gLuiOM0/go9bIoC3HVaSnfg4xunowDE2i9p8drkXuvDw==",
       "dependencies": {
-        "busboy": "^1.6.0"
+        "@fastify/busboy": "^2.0.0"
       },
       "engines": {
         "node": ">=14.0"
diff --git a/tests/e2e/specs/basic.e2e.ts b/tests/e2e/specs/basic.e2e.ts
index 4ed3d43c..91339a17 100644
--- a/tests/e2e/specs/basic.e2e.ts
+++ b/tests/e2e/specs/basic.e2e.ts
@@ -73,9 +73,11 @@ describe('Runme VS Code Extension', async () => {
       await tryExecuteCommand(workbench, 'clear all notifications')
     })
 
-    it('basic hello world shell execution', async () => {
+    it('basic hello world, run twice back-to-back', async () => {
       const cell = await notebook.getCell('echo "Hello World!')
 
+      // running 2x to avoid regression with terminal/process disposal
+      await cell.run()
       await cell.run()
 
       expect(await cell.getCellOutput(OutputType.TerminalView)).toStrictEqual([
diff --git a/tests/extension/server/runmeServer.test.ts b/tests/extension/server/runmeServer.test.ts
index 75c5033f..ea33a622 100644
--- a/tests/extension/server/runmeServer.test.ts
+++ b/tests/extension/server/runmeServer.test.ts
@@ -48,6 +48,12 @@ vi.mock('node:fs/promises', async () => ({
   }
 }))
 
+vi.mock('crypto', async () => ({
+  default: {
+    randomBytes: vi.fn().mockReturnValue('abcdefgh')
+  }
+}))
+
 vi.mock('node:child_process', async () => ({
   spawn: vi.fn(),
 }))
@@ -99,21 +105,53 @@ suite('Runme server spawn process', () => {
       expect(creds._isSecure()).toBe(false)
   })
 
-  test('proper credentials with tls', async () => {
-    configValues.enableTLS = true
+    test('proper credentials with tls', async () => {
+      configValues.enableTLS = true
 
-    const server = new Server(
-      Uri.file('/Users/user/.vscode/extension/stateful.runme'),
-      {
-        retryOnFailure: true,
-        maxNumberOfIntents: 2,
-      },
-      false
-    )
+      const server = new Server(
+        Uri.file('/Users/user/.vscode/extension/stateful.runme'),
+        {
+          retryOnFailure: true,
+          maxNumberOfIntents: 2,
+        },
+        false
+      )
 
-    const creds = await server['channelCredentials']()
-    expect(creds._isSecure()).toBe(true)
-})
+      const creds = await server['channelCredentials']()
+      expect(creds._isSecure()).toBe(true)
+    })
+
+    test('uses UDS instead of TCP socket', async () => {
+      configValues.transportType = 'UDS'
+
+      const server = new Server(
+        Uri.file('/Users/user/.vscode/extension/stateful.runme'),
+        {
+          retryOnFailure: true,
+          maxNumberOfIntents: 2,
+        },
+        false
+      )
+
+      const address = server['address']()
+      expect(address).toStrictEqual('unix:///tmp/runme-abcdefgh.sock')
+    })
+
+    test('uses TCP socket by default', async () => {
+      configValues.transportType = undefined
+
+      const server = new Server(
+        Uri.file('/Users/user/.vscode/extension/stateful.runme'),
+        {
+          retryOnFailure: true,
+          maxNumberOfIntents: 2,
+        },
+        false
+      )
+
+      const address = server['address']()
+      expect(address).toStrictEqual('localhost:7863')
+    })
 
     test('Should try 2 times before failing', async () => {
       configValues.enableTLS = true