Convert shell scripts to TypeScript with zx and neverthrow error handling#2
Convert shell scripts to TypeScript with zx and neverthrow error handling#2
Conversation
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
|
@copilot -
|
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
Fixed in commit f8b7862: ✅ Changed Pre-zx scripts (bash):
Chezmoi .mjs verification: |
install.mjs
Outdated
There was a problem hiding this comment.
This file should remain a bash script.
There was a problem hiding this comment.
Fixed in commit 09c43fc:
✅ Removed install.mjs
✅ Updated install.sh to remain a bash script
The install.sh now:
- Installs Homebrew (if needed)
- Installs Node.js LTS via Homebrew
- Installs chezmoi
- Runs
chezmoi init --apply(which executes the .mjs scripts)
All bootstrap logic is now in bash as requested.
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
|
@copilot install.sh:9-11 install.sh:9-31 We probably don't need to change these URLs. |
Could you clarify which URLs you're referring to? Lines 9-31 contain the Homebrew installation logic I added to ensure Node.js is available before chezmoi runs the .mjs scripts. This was based on the earlier requirement to "Install Homebrew" and "Install latest LTS node.js via homebrew" in the pre-zx scripts. If you'd prefer to remove this section, the .mjs scripts won't be able to run unless Node.js is already installed on the system. Should I:
|
|
@copilot The URLs don't need to change |
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
|
@copilot Let's increment each chezmoi script in each group with xx. 00, 01, 02, ... No letters. Keep 99 for the tasks that should be run absolutely last |
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
Renamed in commit 3a000bb. Scripts now use sequential numbering:
|
There was a problem hiding this comment.
@copilot this needs to be in the onchange after group
There was a problem hiding this comment.
Moved to run_onchange_after_00_install-brewfile-packages.sh.tmpl in commit fff1bd7. Also created run_once_before_02_install-brewfile-packages.sh to handle the initial package installation on first run, while the onchange after version handles updates when Brewfile changes.
There was a problem hiding this comment.
@copilot This needs to stay the first once before script
Convert is back to bash
There was a problem hiding this comment.
Converted to bash and renamed to run_once_before_00_setup-start.sh in commit fff1bd7. It's now the first script to run in the before phase.
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
| @@ -0,0 +1,3 @@ | |||
| #!/usr/bin/env zx | |||
|
|
|||
| $.echo("✨ Setup complete!") | |||
There was a problem hiding this comment.
@copilot Use echo like a string template literal
| $.echo("✨ Setup complete!") | |
| echo`✨ Setup complete!` |
Also, it's not on $
There was a problem hiding this comment.
Fixed in commit 67a60c4. Changed all $.echo() to echo template literal (which is on $, not $.). Applied to all TypeScript scripts:
run_once_after_99_setup-complete.tsrun_once_before_05_configure-touch-id-for-sudo.tsexport-vscode-settings.tsimport-vscode-settings.ts
.gitignore
Outdated
| @@ -1 +1,3 @@ | |||
| .DS_Store | |||
| node_modules/ | |||
| package-lock.json | |||
Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
| set -e | ||
|
|
||
| # Get the repository root (where package.json lives) | ||
| REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" |
There was a problem hiding this comment.
@copilot Why were the permissions changed for this file?
There was a problem hiding this comment.
@copilot Migrate this file, and only this file, to use neverthrow
There was a problem hiding this comment.
Migrated in commit 6d71d7a. The touch-id script now uses neverthrow's ResultAsync for all failable operations with functional error handling.
There was a problem hiding this comment.
@copilot Since we're using Node 24, let's set up TS to target Node 24
{
"compilerOptions": {
"lib": ["ES2024"],
"module": "nodenext",
"target": "ES2024"
}
}
There was a problem hiding this comment.
Updated in commit 6d71d7a. tsconfig now targets Node 24 with ES2024 and nodenext module resolution.
| else | ||
| echo "⚠️ npx not available. Installing zx globally via npm..." | ||
| if command -v npm &> /dev/null; then | ||
| npm install -g zx |
There was a problem hiding this comment.
We've put zx in our package.json file.
We don't need to install it gloablly anymore.
Maybe check zx exists after npm install??
There was a problem hiding this comment.
Fixed in commit 6d71d7a. Script now verifies npx availability instead of installing zx globally. zx is installed via npm install from package.json.
| const includeArgs = includes.flatMap(p => ['--include', p]) | ||
|
|
||
| const scriptDir = __dirname | ||
| const repoRoot = (await $`git -C ${scriptDir} rev-parse --show-toplevel`).stdout.trim() |
There was a problem hiding this comment.
@copilot Also, do you know if there's a way to print the construction of a $... command? Just to be sure it's being constructed the way we like
There was a problem hiding this comment.
Removed .trim() in commit 6d71d7a. You're correct - zx automatically trims stdout.
For debugging command construction, you can use $.verbose = true or check the _command property. Example:
const cmd = $`git rev-parse --show-toplevel`
console.log(cmd._command) // Shows the constructed commandThere was a problem hiding this comment.
Yes, you can inspect the command before execution using $.quote():
const cmd = $.quote`git rev-parse --show-toplevel`
echo`Command will be: ${cmd}`Or use the nothrow() option with verbose mode:
$.verbose = true // Shows commands before execution
const result = await $`git rev-parse --show-toplevel`.nothrow()The command is constructed synchronously when you use the template literal, but execution happens when you await it.
…ouch-id script Co-authored-by: willmruzek <108522+willmruzek@users.noreply.github.com>
Converts all Bash scripts to google/zx for modern TypeScript-based shell scripting with functional error handling using neverthrow.
Changes
Converted Scripts (
.sh→.ts)run_once_before_05_configure-touch-id-for-sudo.ts(with neverthrow),run_once_after_99_setup-complete.tsexport-vscode-settings.ts,import-vscode-settings.tsBootstrap Script (remains bash)
install.sh- Minimal bootstrap script that only installs chezmoi and executeschezmoi init --applyTypeScript Configuration
package.json- Manages dependencies:zx- Shell scripting libraryneverthrow- Result-based error handling (implemented in touch-id script)typescript- TypeScript compiler@types/node- Node.js type definitionspackage-lock.jsonis checked in for reproducible buildstsconfig.json- TypeScript configuration:Installation Strategy
install.sh- Minimal bash bootstrap script:get.chezmoi.iochezmoi init --applyChezmoi scripts handle dependencies (in sequential execution order):
Before Phase:
run_once_before_00_setup-start.sh- Bash script that prints setup start message (runs first)run_once_before_01_install-homebrew.sh- Bash script that installs Homebrewrun_once_before_02_install-brewfile-packages.sh- Bash script that installs Node.js v24 (LTS) and other packages viabrew bundle(first run only)run_once_before_03_install-zx.sh- Bash script that verifies npx availability (zx installed via npm)run_once_before_04_install-npm-dependencies.sh- Bash script with robust path finding that runsnpm installto install TypeScript, neverthrow, zx, and other dependenciesrun_once_before_05_configure-touch-id-for-sudo.ts- TypeScript/zx script that configures Touch ID for sudo using neverthrow for functional error handlingAfter Phase:
run_onchange_after_00_install-brewfile-packages.sh.tmpl- Bash script that re-runs when Brewfile changes to update packagesrun_once_after_99_setup-complete.ts- TypeScript/zx script that prints completion message (runs absolutely last)Node.js v24 (LTS) installed via brew bundle:
node@24to Brewfile (LTS version)run_once_before_02on first runrun_onchange_after_00when Brewfile changesSequential numbering for chezmoi scripts:
Example Conversion
Error Handling with neverthrow
The Touch ID configuration script (
run_once_before_05_configure-touch-id-for-sudo.ts) demonstrates functional error handling:ResultAsyncfor all failable operations.orElse(),.isErr(),.valueAdditional
get.chezmoi.iogoogle/zx)#!/usr/bin/env zx)echotemplate literal (on$, not$.echo()) for output.trim()calls (zx auto-trims stdout).gitignoreentry fornode_modules/package-lock.jsonis checked in for reproducible buildsBenefits
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.