-
Notifications
You must be signed in to change notification settings - Fork 0
IRIS CLI v1.2.2 — Fix iris update not replacing binary #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -137,21 +137,36 @@ export namespace Installation { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ext = platform === "linux" ? "tar.gz" : "zip" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const assetName = `iris-${platform}-${arch}.${ext}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const releaseUrl = `https://github.com/FREELABEL/iris-opencode/releases/download/v${target}/${assetName}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const binDir = path.dirname(process.execPath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Resolve symlinks to get the real binary path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const realExecPath = await import("fs").then(fs => fs.realpathSync(process.execPath)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const binDir = path.dirname(realExecPath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const tmpDir = path.join(binDir, ".iris-update-tmp") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd = $`set -e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p ${tmpDir} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cd ${tmpDir} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curl -fsSL -o ${assetName} ${releaseUrl} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Use a script file to avoid Bun template literal interpolation issues | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const script = `#!/bin/bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p "${tmpDir}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cd "${tmpDir}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curl -fsSL -o "${assetName}" "${releaseUrl}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "${ext}" = "tar.gz" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tar -xzf ${assetName} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tar -xzf "${assetName}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unzip -o ${assetName} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unzip -o "${assetName}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cp -f iris ${binDir}/iris | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rm -rf ${tmpDir} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Updated to v${target}"`.env({ ...process.env }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chmod +x iris | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Remove old binary first (avoids overwriting a running executable) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rm -f "${binDir}/iris" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mv iris "${binDir}/iris" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rm -rf "${tmpDir}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Verify the new binary works | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "${binDir}/iris" --version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+161
to
+162
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Verify the new binary works | |
| "${binDir}/iris" --version | |
| # Best-effort verification only; let the TypeScript layer handle warnings/fallbacks. | |
| set +e | |
| "${binDir}/iris" --version >/dev/null 2>&1 | |
| verify_status=$? | |
| set -e | |
| exit 0 |
Copilot
AI
Apr 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The update script deletes the existing "${binDir}/iris" before moving the new binary into place. If the mv fails (download/extract issues, permissions, disk full), this leaves the user with no iris binary at all. Consider doing an atomic swap (move new binary to a temp name in binDir, then rename over), and/or moving the old binary to a backup and restoring it on failure.
| # Remove old binary first (avoids overwriting a running executable) | |
| rm -f "${binDir}/iris" | |
| mv iris "${binDir}/iris" | |
| rm -rf "${tmpDir}" | |
| # Verify the new binary works | |
| "${binDir}/iris" --version | |
| newBinary="${binDir}/iris.new.$$" | |
| backupBinary="${binDir}/iris.backup.$$" | |
| restore_previous() { | |
| status=$? | |
| if [ -f "${backupBinary}" ] && [ ! -f "${binDir}/iris" ]; then | |
| mv -f "${backupBinary}" "${binDir}/iris" || true | |
| fi | |
| rm -f "${newBinary}" | |
| rm -rf "${tmpDir}" | |
| exit $status | |
| } | |
| trap restore_previous EXIT | |
| # Stage the new binary in the target directory before replacing the current one. | |
| mv -f iris "${newBinary}" | |
| # Move the current binary aside so it can be restored if anything fails. | |
| if [ -f "${binDir}/iris" ]; then | |
| mv -f "${binDir}/iris" "${backupBinary}" | |
| fi | |
| mv -f "${newBinary}" "${binDir}/iris" | |
| # Verify the new binary works before removing the backup. | |
| "${binDir}/iris" --version | |
| rm -f "${backupBinary}" | |
| rm -rf "${tmpDir}" | |
| trap - EXIT |
Copilot
AI
Apr 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bash ${scriptPath} && rm -f ${scriptPath} only removes the script on success. If the script fails at any step (curl/unzip/mv/version check), the script file will be left behind in the install directory. Prefer ensuring cleanup in a finally/trap (or use ; rm -f after capturing exit code) so the temp script is removed even on failure.
| cmd = $`bash ${scriptPath} && rm -f ${scriptPath}`.env({ ...process.env }) | |
| cmd = | |
| $`bash -c 'script_path="$1"; trap '"'"'rm -f "$script_path"'"'"' EXIT; bash "$script_path"' -- ${scriptPath}`.env( | |
| { ...process.env }, | |
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verification uses
.nothrow().quiet().text()and then treats an empty/failed command the same as success (it falls into theelsebranch and prints "Verified"). Consider capturing the process result (including exit code) and only reporting success when exitCode is 0 and a version string was produced.