From e4c031e84085ce2a990953581aa5a1af1c06f5b7 Mon Sep 17 00:00:00 2001 From: Derek Date: Wed, 7 Oct 2026 12:17:48 +1100 Subject: [PATCH] fix: drop ts-node, which breaks on typescript 7 TypeScript 7.0 removed the compiler API ts-node calls, so ts-node crashes on start whenever the global typescript is 7 (latest since 2026-07-08). Its last release was 10.9.2 in 2023-12. tsx runs the same files without that API. developer-typescript now installs typescript and tsx only, and --tags removals removes the ts-node pnpm global the role used to install on Linux. --- .../roles/developer-typescript/meta/main.yml | 2 +- .../roles/developer-typescript/tasks/main.yml | 2 +- .../developer-typescript/tasks/typescript.yml | 6 ++-- .../files/update/hyperi-update-linux.sh | 2 +- .../files/update/hyperi-update-macos.sh | 4 +-- ansible/roles/developer/tasks/removals.yml | 29 +++++++++++++++++++ docs/install-matrix.md | 4 +-- install.sh | 2 +- 8 files changed, 40 insertions(+), 11 deletions(-) diff --git a/ansible/roles/developer-typescript/meta/main.yml b/ansible/roles/developer-typescript/meta/main.yml index 67773f4..7176a5f 100644 --- a/ansible/roles/developer-typescript/meta/main.yml +++ b/ansible/roles/developer-typescript/meta/main.yml @@ -1,6 +1,6 @@ --- # Developer-TypeScript depends on developer-node — Node.js + npm/pnpm are -# prerequisites for installing typescript/tsx/ts-node. +# prerequisites for installing typescript/tsx. dependencies: - role: developer-node diff --git a/ansible/roles/developer-typescript/tasks/main.yml b/ansible/roles/developer-typescript/tasks/main.yml index c0f1d9a..bc8fb5d 100644 --- a/ansible/roles/developer-typescript/tasks/main.yml +++ b/ansible/roles/developer-typescript/tasks/main.yml @@ -4,7 +4,7 @@ # the dependency so `--tags developer-typescript` automatically pulls in # developer-node first. -- name: Install TypeScript and tsx/ts-node +- name: Install TypeScript and tsx ansible.builtin.include_tasks: file: typescript.yml apply: diff --git a/ansible/roles/developer-typescript/tasks/typescript.yml b/ansible/roles/developer-typescript/tasks/typescript.yml index 586d9b9..fee20a1 100644 --- a/ansible/roles/developer-typescript/tasks/typescript.yml +++ b/ansible/roles/developer-typescript/tasks/typescript.yml @@ -1,11 +1,11 @@ --- -# TypeScript toolchain — installs typescript + tsx + ts-node globally via pnpm. +# TypeScript toolchain — installs typescript + tsx globally via pnpm. # Node.js and pnpm come from the core `developer` role now; developer-node is # still the declared dependency (meta/main.yml) and pulls that role in. -- name: Install TypeScript and runners (typescript, tsx, ts-node) +- name: Install TypeScript and the tsx runner ansible.builtin.command: - cmd: pnpm install -g typescript tsx ts-node + cmd: pnpm install -g typescript tsx # Same prerequisite as developer-node: pnpm will not do a global install # unless PNPM_HOME is set and its bin directory is on PATH. pnpm_env comes # from the core role, which installs pnpm in the first place. diff --git a/ansible/roles/developer/files/update/hyperi-update-linux.sh b/ansible/roles/developer/files/update/hyperi-update-linux.sh index 140640d..bfe17d9 100644 --- a/ansible/roles/developer/files/update/hyperi-update-linux.sh +++ b/ansible/roles/developer/files/update/hyperi-update-linux.sh @@ -404,7 +404,7 @@ fi # --- npm and pnpm global tools --------------------------------------------- # semantic-release, maid and wrangler are npm globals. eslint, prettier, -# typescript, tsx and ts-node are pnpm globals, which `npm update -g` never +# typescript and tsx are pnpm globals, which `npm update -g` never # sees. pnpm itself is corepack's, so it is re-activated at latest first. section "npm global tools" if have npm; then diff --git a/ansible/roles/developer/files/update/hyperi-update-macos.sh b/ansible/roles/developer/files/update/hyperi-update-macos.sh index d2324c2..20e75e8 100644 --- a/ansible/roles/developer/files/update/hyperi-update-macos.sh +++ b/ansible/roles/developer/files/update/hyperi-update-macos.sh @@ -299,8 +299,8 @@ else fi # --- npm and pnpm global tools --------------------------------------------- -# semantic-release and maid are npm globals. eslint, prettier, typescript, tsx -# and ts-node are pnpm globals, which `npm update -g` never sees. pnpm itself is +# semantic-release and maid are npm globals. eslint, prettier, typescript and +# tsx are pnpm globals, which `npm update -g` never sees. pnpm itself is # corepack's, so it is re-activated at latest first. section "npm global tools" if have npm; then diff --git a/ansible/roles/developer/tasks/removals.yml b/ansible/roles/developer/tasks/removals.yml index 6ef2367..8486ebc 100644 --- a/ansible/roles/developer/tasks/removals.yml +++ b/ansible/roles/developer/tasks/removals.yml @@ -705,6 +705,35 @@ when: ansible_facts['distribution'] == 'Ubuntu' failed_when: false +# ts-node crashes on TypeScript 7, which removed the compiler API it calls, and +# has had no release since 2023-12. tsx runs the same files. +- name: Check for pnpm before removing a pnpm global (Linux) + ansible.builtin.command: + cmd: pnpm --version + environment: "{{ pnpm_env }}" + become: true + become_user: "{{ actual_user }}" + register: developer_rm_pnpm_present + changed_when: false + failed_when: false + check_mode: false + when: ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] + +- name: Remove the retired ts-node pnpm global (Linux) + ansible.builtin.command: + cmd: pnpm remove -g ts-node + environment: "{{ pnpm_env }}" + become: true + become_user: "{{ actual_user }}" + register: developer_rm_ts_node + changed_when: developer_rm_ts_node.rc == 0 + failed_when: + - developer_rm_ts_node.rc != 0 + - "'GLOBAL_PKG_NOT_FOUND' not in (developer_rm_ts_node.stdout ~ developer_rm_ts_node.stderr)" + when: + - ansible_facts['distribution'] in ['Fedora', 'Ubuntu'] + - developer_rm_pnpm_present.rc | default(1) == 0 + # macOS is deliberately absent. These came from brew, and `brew uninstall` on a # Mac hits tools the developer may well have installed themselves for their own # reasons -- on a personal machine, undeclared state is theirs, not ours. The diff --git a/docs/install-matrix.md b/docs/install-matrix.md index a49f8ec..0231f13 100644 --- a/docs/install-matrix.md +++ b/docs/install-matrix.md @@ -283,7 +283,7 @@ table used to say the opposite. | Tool(s) | Platforms | Method | |---|---|---| -| typescript, tsx, ts-node | all | pnpm global | +| typescript, tsx | all | pnpm global | #### developer-c @@ -630,7 +630,7 @@ security, so it holds the version it shipped with for the life of the release (see the ladder note above). A vendor repo, a snap and Fedora's own packages all track upstream properly. -**Tier 2 - language-manager tools.** Tools installed by uv / cargo / go / npm / pnpm have no OS channel, so `hyperi-update` refreshes them through each manager: `uv tool upgrade --all`, `rustup update` and `cargo install-update -a --locked`, `go install ...@latest` for the tools in `~/go/bin` (only when the module or the Go toolchain moved), `npm update -g`, and `pnpm update -g --latest`. The pnpm globals (eslint, prettier, typescript, tsx, ts-node) are installed unpinned, so `--latest` moves them to what a fresh converge would install, majors included. `uv python upgrade` moves each uv-managed Python to its newest patch without adding a python or python3 shim, and leaves the superseded patch installed, because uv has no command that removes only those. E.g. ruff, ty, semgrep, pip-audit, cargo-audit, cargo-hack, typos, govulncheck, maid. +**Tier 2 - language-manager tools.** Tools installed by uv / cargo / go / npm / pnpm have no OS channel, so `hyperi-update` refreshes them through each manager: `uv tool upgrade --all`, `rustup update` and `cargo install-update -a --locked`, `go install ...@latest` for the tools in `~/go/bin` (only when the module or the Go toolchain moved), `npm update -g`, and `pnpm update -g --latest`. The pnpm globals (eslint, prettier, typescript, tsx) are installed unpinned, so `--latest` moves them to what a fresh converge would install, majors included. `uv python upgrade` moves each uv-managed Python to its newest patch without adding a python or python3 shim, and leaves the superseded patch installed, because uv has no command that removes only those. E.g. ruff, ty, semgrep, pip-audit, cargo-audit, cargo-hack, typos, govulncheck, maid. **Tier 3 - static binaries.** A handful ship only as a release binary with no repo, snap, or language manager: kind, argocd, kubeconform, kube-linter, terraform-docs, golangci-lint, lazygit, actionlint, osv-scanner, aws-vault, git-scrub, sccache, fnm, hadolint, tea and macbash on both distros, k9s, kustomize, yq, gitleaks and act on Ubuntu, and sd, kubectx and kubens on Fedora. `hyperi-update` re-fetches each one only where the role put it in `/usr/local/bin` on that distro, so the binary cannot shadow a packaged copy. Each download must match the sha256 GitHub publishes for the asset, or the release's checksum file where there is no digest (tea and macbash publish a `.sha256` beside the asset), and is renamed into place so the working copy is never half-written. Each GitHub release is the newest at least 7 days old, as in the roles, which write their age and exempt orgs to `/etc/default/hyperi-update`. `HYPERI_RELEASE_MIN_AGE_DAYS` in the environment overrides that file and `--min-age DAYS` overrides both. With no release old enough the installed copy stays and the summary lists it. A stamp in `/var/lib/hyperi-update` stops an unmoved release being downloaded again, and the GitHub API is asked with the last ETag, so with a token set an unchanged release costs no rate limit (an anonymous 304 still counts). When the API refuses, the release document from the last run stands in. On Ubuntu, uv and uvx in `~/.local/bin` are refreshed the same way as the invoking user. diff --git a/install.sh b/install.sh index 0027ca1..c0aa7be 100755 --- a/install.sh +++ b/install.sh @@ -169,7 +169,7 @@ Languages (developer-; --languages [list] or developer-languages for all): developer-python mypy (opt-in; ruff/ty ship in the base astral suite) developer-node eslint + prettier (Node itself is in the base -- it is core tooling, needed by semantic-release and CI) - developer-typescript typescript + tsx + ts-node (pulls developer-node) + developer-typescript typescript + tsx (pulls developer-node) developer-c C/C++ build tools Infrastructure (infrastructure):