prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  improve `healthy()` check for node
  See pre-commit/actions#45
  
  for `language_version: system` hooks this looks like:
  
  ```
  eslint...................................................................Failed
  - hook id: eslint
  - exit code: 127
  
  /home/runner/.cache/pre-commit/repoibq27hfw/node_env-system/bin/node: line 5: /opt/hostedtoolcache/node/14.8.0/x64/bin/node: No such file or directory
  /home/runner/.cache/pre-commit/repoibq27hfw/node_env-system/bin/node: line 5: /opt/hostedtoolcache/node/14.8.0/x64/bin/node: No such file or directory
  
  ##[error]The process '/opt/hostedtoolcache/Python/3.8.5/x64/bin/pre-commit' failed with exit code 1
  ```
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `pre_commit/languages/node.py`
  Content:
  ```
  1 import contextlib
  2 import functools
  3 import os
  4 import sys
  5 from typing import Generator
  6 from typing import Sequence
  7 from typing import Tuple
  8 
  9 import pre_commit.constants as C
  10 from pre_commit import parse_shebang
  11 from pre_commit.envcontext import envcontext
  12 from pre_commit.envcontext import PatchesT
  13 from pre_commit.envcontext import UNSET
  14 from pre_commit.envcontext import Var
  15 from pre_commit.hook import Hook
  16 from pre_commit.languages import helpers
  17 from pre_commit.languages.python import bin_dir
  18 from pre_commit.prefix import Prefix
  19 from pre_commit.util import clean_path_on_failure
  20 from pre_commit.util import cmd_output
  21 from pre_commit.util import cmd_output_b
  22 
  23 ENVIRONMENT_DIR = 'node_env'
  24 healthy = helpers.basic_healthy
  25 
  26 
  27 @functools.lru_cache(maxsize=1)
  28 def get_default_version() -> str:
  29     # nodeenv does not yet support `-n system` on windows
  30     if sys.platform == 'win32':
  31         return C.DEFAULT
  32     # if node is already installed, we can save a bunch of setup time by
  33     # using the installed version
  34     elif all(parse_shebang.find_executable(exe) for exe in ('node', 'npm')):
  35         return 'system'
  36     else:
  37         return C.DEFAULT
  38 
  39 
  40 def _envdir(prefix: Prefix, version: str) -> str:
  41     directory = helpers.environment_dir(ENVIRONMENT_DIR, version)
  42     return prefix.path(directory)
  43 
  44 
  45 def get_env_patch(venv: str) -> PatchesT:
  46     if sys.platform == 'cygwin':  # pragma: no cover
  47         _, win_venv, _ = cmd_output('cygpath', '-w', venv)
  48         install_prefix = fr'{win_venv.strip()}\bin'
  49         lib_dir = 'lib'
  50     elif sys.platform == 'win32':  # pragma: no cover
  51         install_prefix = bin_dir(venv)
  52         lib_dir = 'Scripts'
  53     else:  # pragma: win32 no cover
  54         install_prefix = venv
  55         lib_dir = 'lib'
  56     return (
  57         ('NODE_VIRTUAL_ENV', venv),
  58         ('NPM_CONFIG_PREFIX', install_prefix),
  59         ('npm_config_prefix', install_prefix),
  60         ('NPM_CONFIG_USERCONFIG', UNSET),
  61         ('npm_config_userconfig', UNSET),
  62         ('NODE_PATH', os.path.join(venv, lib_dir, 'node_modules')),
  63         ('PATH', (bin_dir(venv), os.pathsep, Var('PATH'))),
  64     )
  65 
  66 
  67 @contextlib.contextmanager
  68 def in_env(
  69         prefix: Prefix,
  70         language_version: str,
  71 ) -> Generator[None, None, None]:
  72     with envcontext(get_env_patch(_envdir(prefix, language_version))):
  73         yield
  74 
  75 
  76 def install_environment(
  77         prefix: Prefix, version: str, additional_dependencies: Sequence[str],
  78 ) -> None:
  79     additional_dependencies = tuple(additional_dependencies)
  80     assert prefix.exists('package.json')
  81     envdir = _envdir(prefix, version)
  82 
  83     # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath
  84     if sys.platform == 'win32':  # pragma: no cover
  85         envdir = fr'\\?\{os.path.normpath(envdir)}'
  86     with clean_path_on_failure(envdir):
  87         cmd = [
  88             sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir,
  89         ]
  90         if version != C.DEFAULT:
  91             cmd.extend(['-n', version])
  92         cmd_output_b(*cmd)
  93 
  94         with in_env(prefix, version):
  95             # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449
  96             # install as if we installed from git
  97             helpers.run_setup_cmd(prefix, ('npm', 'install'))
  98             helpers.run_setup_cmd(
  99                 prefix,
  100                 ('npm', 'install', '-g', '.', *additional_dependencies),
  101             )
  102 
  103 
  104 def run_hook(
  105         hook: Hook,
  106         file_args: Sequence[str],
  107         color: bool,
  108 ) -> Tuple[int, bytes]:
  109     with in_env(hook.prefix, hook.language_version):
  110         return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
  111
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py
  --- a/pre_commit/languages/node.py
  +++ b/pre_commit/languages/node.py
  @@ -21,7 +21,6 @@
   from pre_commit.util import cmd_output_b
   
   ENVIRONMENT_DIR = 'node_env'
  -healthy = helpers.basic_healthy
   
   
   @functools.lru_cache(maxsize=1)
  @@ -73,6 +72,12 @@
           yield
   
   
  +def healthy(prefix: Prefix, language_version: str) -> bool:
  +    with in_env(prefix, language_version):
  +        retcode, _, _ = cmd_output_b('node', '--version', retcode=None)
  +        return retcode == 0
  +
  +
   def install_environment(
           prefix: Prefix, version: str, additional_dependencies: Sequence[str],
   ) -> None:
  
verification_info: {"golden_diff": "diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py\n--- a/pre_commit/languages/node.py\n+++ b/pre_commit/languages/node.py\n@@ -21,7 +21,6 @@\n from pre_commit.util import cmd_output_b\n \n ENVIRONMENT_DIR = 'node_env'\n-healthy = helpers.basic_healthy\n \n \n @functools.lru_cache(maxsize=1)\n@@ -73,6 +72,12 @@\n         yield\n \n \n+def healthy(prefix: Prefix, language_version: str) -> bool:\n+    with in_env(prefix, language_version):\n+        retcode, _, _ = cmd_output_b('node', '--version', retcode=None)\n+        return retcode == 0\n+\n+\n def install_environment(\n         prefix: Prefix, version: str, additional_dependencies: Sequence[str],\n ) -> None:\n", "issue": "improve `healthy()` check for node\nSee pre-commit/actions#45\r\n\r\nfor `language_version: system` hooks this looks like:\r\n\r\n```\r\neslint...................................................................Failed\r\n- hook id: eslint\r\n- exit code: 127\r\n\r\n/home/runner/.cache/pre-commit/repoibq27hfw/node_env-system/bin/node: line 5: /opt/hostedtoolcache/node/14.8.0/x64/bin/node: No such file or directory\r\n/home/runner/.cache/pre-commit/repoibq27hfw/node_env-system/bin/node: line 5: /opt/hostedtoolcache/node/14.8.0/x64/bin/node: No such file or directory\r\n\r\n##[error]The process '/opt/hostedtoolcache/Python/3.8.5/x64/bin/pre-commit' failed with exit code 1\r\n```\r\n\r\n\n", "before_files": [{"content": "import contextlib\nimport functools\nimport os\nimport sys\nfrom typing import Generator\nfrom typing import Sequence\nfrom typing import Tuple\n\nimport pre_commit.constants as C\nfrom pre_commit import parse_shebang\nfrom pre_commit.envcontext import envcontext\nfrom pre_commit.envcontext import PatchesT\nfrom pre_commit.envcontext import UNSET\nfrom pre_commit.envcontext import Var\nfrom pre_commit.hook import Hook\nfrom pre_commit.languages import helpers\nfrom pre_commit.languages.python import bin_dir\nfrom pre_commit.prefix import Prefix\nfrom pre_commit.util import clean_path_on_failure\nfrom pre_commit.util import cmd_output\nfrom pre_commit.util import cmd_output_b\n\nENVIRONMENT_DIR = 'node_env'\nhealthy = helpers.basic_healthy\n\n\n@functools.lru_cache(maxsize=1)\ndef get_default_version() -> str:\n    # nodeenv does not yet support `-n system` on windows\n    if sys.platform == 'win32':\n        return C.DEFAULT\n    # if node is already installed, we can save a bunch of setup time by\n    # using the installed version\n    elif all(parse_shebang.find_executable(exe) for exe in ('node', 'npm')):\n        return 'system'\n    else:\n        return C.DEFAULT\n\n\ndef _envdir(prefix: Prefix, version: str) -> str:\n    directory = helpers.environment_dir(ENVIRONMENT_DIR, version)\n    return prefix.path(directory)\n\n\ndef get_env_patch(venv: str) -> PatchesT:\n    if sys.platform == 'cygwin':  # pragma: no cover\n        _, win_venv, _ = cmd_output('cygpath', '-w', venv)\n        install_prefix = fr'{win_venv.strip()}\\bin'\n        lib_dir = 'lib'\n    elif sys.platform == 'win32':  # pragma: no cover\n        install_prefix = bin_dir(venv)\n        lib_dir = 'Scripts'\n    else:  # pragma: win32 no cover\n        install_prefix = venv\n        lib_dir = 'lib'\n    return (\n        ('NODE_VIRTUAL_ENV', venv),\n        ('NPM_CONFIG_PREFIX', install_prefix),\n        ('npm_config_prefix', install_prefix),\n        ('NPM_CONFIG_USERCONFIG', UNSET),\n        ('npm_config_userconfig', UNSET),\n        ('NODE_PATH', os.path.join(venv, lib_dir, 'node_modules')),\n        ('PATH', (bin_dir(venv), os.pathsep, Var('PATH'))),\n    )\n\n\n@contextlib.contextmanager\ndef in_env(\n        prefix: Prefix,\n        language_version: str,\n) -> Generator[None, None, None]:\n    with envcontext(get_env_patch(_envdir(prefix, language_version))):\n        yield\n\n\ndef install_environment(\n        prefix: Prefix, version: str, additional_dependencies: Sequence[str],\n) -> None:\n    additional_dependencies = tuple(additional_dependencies)\n    assert prefix.exists('package.json')\n    envdir = _envdir(prefix, version)\n\n    # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath\n    if sys.platform == 'win32':  # pragma: no cover\n        envdir = fr'\\\\?\\{os.path.normpath(envdir)}'\n    with clean_path_on_failure(envdir):\n        cmd = [\n            sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir,\n        ]\n        if version != C.DEFAULT:\n            cmd.extend(['-n', version])\n        cmd_output_b(*cmd)\n\n        with in_env(prefix, version):\n            # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449\n            # install as if we installed from git\n            helpers.run_setup_cmd(prefix, ('npm', 'install'))\n            helpers.run_setup_cmd(\n                prefix,\n                ('npm', 'install', '-g', '.', *additional_dependencies),\n            )\n\n\ndef run_hook(\n        hook: Hook,\n        file_args: Sequence[str],\n        color: bool,\n) -> Tuple[int, bytes]:\n    with in_env(hook.prefix, hook.language_version):\n        return helpers.run_xargs(hook, hook.cmd, file_args, color=color)\n", "path": "pre_commit/languages/node.py"}], "after_files": [{"content": "import contextlib\nimport functools\nimport os\nimport sys\nfrom typing import Generator\nfrom typing import Sequence\nfrom typing import Tuple\n\nimport pre_commit.constants as C\nfrom pre_commit import parse_shebang\nfrom pre_commit.envcontext import envcontext\nfrom pre_commit.envcontext import PatchesT\nfrom pre_commit.envcontext import UNSET\nfrom pre_commit.envcontext import Var\nfrom pre_commit.hook import Hook\nfrom pre_commit.languages import helpers\nfrom pre_commit.languages.python import bin_dir\nfrom pre_commit.prefix import Prefix\nfrom pre_commit.util import clean_path_on_failure\nfrom pre_commit.util import cmd_output\nfrom pre_commit.util import cmd_output_b\n\nENVIRONMENT_DIR = 'node_env'\n\n\n@functools.lru_cache(maxsize=1)\ndef get_default_version() -> str:\n    # nodeenv does not yet support `-n system` on windows\n    if sys.platform == 'win32':\n        return C.DEFAULT\n    # if node is already installed, we can save a bunch of setup time by\n    # using the installed version\n    elif all(parse_shebang.find_executable(exe) for exe in ('node', 'npm')):\n        return 'system'\n    else:\n        return C.DEFAULT\n\n\ndef _envdir(prefix: Prefix, version: str) -> str:\n    directory = helpers.environment_dir(ENVIRONMENT_DIR, version)\n    return prefix.path(directory)\n\n\ndef get_env_patch(venv: str) -> PatchesT:\n    if sys.platform == 'cygwin':  # pragma: no cover\n        _, win_venv, _ = cmd_output('cygpath', '-w', venv)\n        install_prefix = fr'{win_venv.strip()}\\bin'\n        lib_dir = 'lib'\n    elif sys.platform == 'win32':  # pragma: no cover\n        install_prefix = bin_dir(venv)\n        lib_dir = 'Scripts'\n    else:  # pragma: win32 no cover\n        install_prefix = venv\n        lib_dir = 'lib'\n    return (\n        ('NODE_VIRTUAL_ENV', venv),\n        ('NPM_CONFIG_PREFIX', install_prefix),\n        ('npm_config_prefix', install_prefix),\n        ('NPM_CONFIG_USERCONFIG', UNSET),\n        ('npm_config_userconfig', UNSET),\n        ('NODE_PATH', os.path.join(venv, lib_dir, 'node_modules')),\n        ('PATH', (bin_dir(venv), os.pathsep, Var('PATH'))),\n    )\n\n\n@contextlib.contextmanager\ndef in_env(\n        prefix: Prefix,\n        language_version: str,\n) -> Generator[None, None, None]:\n    with envcontext(get_env_patch(_envdir(prefix, language_version))):\n        yield\n\n\ndef healthy(prefix: Prefix, language_version: str) -> bool:\n    with in_env(prefix, language_version):\n        retcode, _, _ = cmd_output_b('node', '--version', retcode=None)\n        return retcode == 0\n\n\ndef install_environment(\n        prefix: Prefix, version: str, additional_dependencies: Sequence[str],\n) -> None:\n    additional_dependencies = tuple(additional_dependencies)\n    assert prefix.exists('package.json')\n    envdir = _envdir(prefix, version)\n\n    # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath\n    if sys.platform == 'win32':  # pragma: no cover\n        envdir = fr'\\\\?\\{os.path.normpath(envdir)}'\n    with clean_path_on_failure(envdir):\n        cmd = [\n            sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir,\n        ]\n        if version != C.DEFAULT:\n            cmd.extend(['-n', version])\n        cmd_output_b(*cmd)\n\n        with in_env(prefix, version):\n            # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449\n            # install as if we installed from git\n            helpers.run_setup_cmd(prefix, ('npm', 'install'))\n            helpers.run_setup_cmd(\n                prefix,\n                ('npm', 'install', '-g', '.', *additional_dependencies),\n            )\n\n\ndef run_hook(\n        hook: Hook,\n        file_args: Sequence[str],\n        color: bool,\n) -> Tuple[int, bytes]:\n    with in_env(hook.prefix, hook.language_version):\n        return helpers.run_xargs(hook, hook.cmd, file_args, color=color)\n", "path": "pre_commit/languages/node.py"}]}