Skip to content

fix: support current opencode installs#6

Open
kbdevs wants to merge 1 commit intoguard22:mainfrom
kbdevs:fix/current-opencode-support
Open

fix: support current opencode installs#6
kbdevs wants to merge 1 commit intoguard22:mainfrom
kbdevs:fix/current-opencode-support

Conversation

@kbdevs
Copy link
Copy Markdown

@kbdevs kbdevs commented Apr 21, 2026

Summary

  • update the auto-patcher for current OpenCode releases by supporting the installation/version.ts layout and the newer typed TUI event source used by v1.14.20
  • install the wrapper beside the detected opencode binary so current installs under ~/.opencode/bin are actually patched, and persist launcher metadata so uninstall can restore the right location
  • tighten the live TPS estimate so it tracks streamed visible output more closely instead of overcounting reasoning updates and tiny chunk boundaries

Validation

  • bun ./scripts/apply-opencode-tps-patch.mjs <v1.14.20 clone> 1.14.20
  • (cd <v1.14.20 clone>/packages/opencode && bun install --frozen-lockfile && bun run typecheck)
  • bun ./scripts/apply-opencode-tps-patch.mjs <v1.4.1 clone> 1.4.1
  • isolated install.sh run against a simulated ~/.opencode/bin/opencode setup
  • real local install to ~/.opencode/bin/opencode, verified with opencode --version

Handle the current OpenCode 1.14.20 layout and install path so the patch works with binaries installed under ~/.opencode/bin as well as older ~/.local/bin setups. Tighten the live TPS estimate to track visible streamed output more closely instead of overcounting small chunks and reasoning updates.
Copilot AI review requested due to automatic review settings April 21, 2026 22:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the OpenCode TPS Meter installer/patcher to support newer OpenCode releases (notably v1.14.20) by handling upstream source layout and event API changes, and by installing the launcher wrapper alongside the detected opencode binary.

Changes:

  • Extend the auto-patcher to handle installation/version.ts (in addition to installation/meta.ts) and support different TUI event sources.
  • Change install/uninstall behavior to place the wrapper next to the detected opencode binary and persist launcher locations in launcher.env.
  • Refine live TPS estimation to better align with visible streamed output (avoid counting reasoning and tiny chunk boundaries).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
scripts/apply-opencode-tps-patch.mjs Adds version-file detection and adjusts event wiring + live TPS sampling logic for newer OpenCode TUI changes.
install.sh Installs wrapper beside detected opencode, writes launcher.env, and updates fallback path behavior.
uninstall.sh Restores launcher based on persisted launcher.env (or a legacy ~/.opencode/bin fallback).
manifest.sh Updates the tested versions list to include 1.14.20.
README.md Documents new wrapper placement behavior and updated tested versions.
.github/workflows/validate.yml Adds 1.14.20 to the CI patch/typecheck matrix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread uninstall.sh
Comment on lines +10 to +16
if [ -f "$LAUNCHER_STATE" ]; then
# shellcheck disable=SC1090
. "$LAUNCHER_STATE"
elif [ -e "$HOME/.opencode/bin/opencode-stock" ]; then
BIN_DIR="$HOME/.opencode/bin"
WRAPPER="$BIN_DIR/opencode"
STOCK="$BIN_DIR/opencode-stock"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uninstall.sh sources launcher.env directly. If that file is corrupted/edited, the script will execute its contents and may end up moving/removing unintended paths via the subsequent mv/rm. Consider parsing the state file safely (not via .), and validating that WRAPPER/STOCK are within an expected bin directory before using them.

Copilot uses AI. Check for mistakes.
Comment thread install.sh
Comment on lines 112 to +115
DETECTED_VERSION="$(detect_installed_version)"
BIN_DIR="$(resolve_bin_dir)"
WRAPPER="$BIN_DIR/opencode"
STOCK="$BIN_DIR/opencode-stock"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detect_installed_version is called before BIN_DIR/WRAPPER/STOCK are initialized (they’re still empty strings). This means the EXISTING_OPENCODE != "$WRAPPER" guard will always pass, so a previously-installed TPS wrapper can be treated as “non-wrapper” and used for version detection, potentially failing (--version may error if the source dir is missing) or selecting the wrong REQUESTED_VERSION. Initialize BIN_DIR/WRAPPER/STOCK first (after EXISTING_OPENCODE is known), then call detect_installed_version so wrapper-vs-stock detection works as intended.

Suggested change
DETECTED_VERSION="$(detect_installed_version)"
BIN_DIR="$(resolve_bin_dir)"
WRAPPER="$BIN_DIR/opencode"
STOCK="$BIN_DIR/opencode-stock"
BIN_DIR="$(resolve_bin_dir)"
WRAPPER="$BIN_DIR/opencode"
STOCK="$BIN_DIR/opencode-stock"
DETECTED_VERSION="$(detect_installed_version)"

Copilot uses AI. Check for mistakes.
Comment thread install.sh
Comment on lines +147 to +151
cat > "$LAUNCHER_STATE" <<EOF
BIN_DIR='$BIN_DIR'
WRAPPER='$WRAPPER'
STOCK='$STOCK'
EOF
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

launcher.env is being written and later sourced (. "$LAUNCHER_STATE"). Because it’s executed as shell code, a corrupted or manually edited state file could cause arbitrary code execution and/or make uninstall.sh move/remove unexpected paths. Consider storing state in a non-executable format (e.g., key=value lines parsed safely) and validating that WRAPPER/STOCK resolve under an expected bin dir before using them.

Copilot uses AI. Check for mistakes.
Comment thread install.sh
Comment on lines 156 to 182
@@ -135,7 +165,7 @@ cat > "$WRAPPER" <<'WRAPEOF'
#!/bin/zsh
set -euo pipefail
SOURCE_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/opencode-tps-meter/current/packages/opencode"
FALLBACK="$HOME/.local/bin/opencode-stock"
FALLBACK="__STOCK_PATH__"
if [ ! -d "$SOURCE_DIR" ]; then
if [ -x "$FALLBACK" ]; then
exec "$FALLBACK" "$@"
@@ -148,13 +178,15 @@ export OPENCODE_LAUNCH_CWD="$ORIG_PWD"
exec "__BUN_BIN__" --cwd "$SOURCE_DIR" --conditions=browser ./src/index.ts "$@"
WRAPEOF
perl -0pi -e 's|__BUN_BIN__|'"$BUN_BIN"'|g' "$WRAPPER"
perl -0pi -e 's|__STOCK_PATH__|'"$STOCK"'|g' "$WRAPPER"
chmod +x "$WRAPPER"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The perl ... s|__EXISTING_OPENCODE__|...| / __BUN_BIN__ / __STOCK_PATH__ substitutions interpolate unescaped paths into a Perl replacement string. If any of these paths contain Perl metacharacters (e.g., |, \, $, @) the generated wrapper/stock script can be corrupted. Use a safer replacement approach (e.g., choose a delimiter you escape, or pass the value via an env var and read it inside Perl, or generate the wrapper with proper shell escaping rather than string substitution).

Copilot uses AI. Check for mistakes.
Comment on lines 46 to 48
if (!source.includes("function estimateStreamTokens(delta: string)")) {
const helpers = `

Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This includes("function estimateStreamTokens(delta: string)") guard no longer matches the helper you now inject (estimateStreamTokens(chars: number)). If the patcher is run twice on the same source tree, it will re-insert the helper block and duplicate the injected code. Update the idempotency check to look for the new helper signature (or a stable marker comment) so re-running the patcher is safe.

Suggested change
if (!source.includes("function estimateStreamTokens(delta: string)")) {
const helpers = `
if (!source.includes("// opencode-tps-patch helpers")) {
const helpers = `
// opencode-tps-patch helpers

Copilot uses AI. Check for mistakes.

function patchPromptIndexTsx(file) {
let source = read(file)
const eventSource = source.includes("const event = useEvent()") ? "event" : "sdk.event"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eventSource selection relies on an exact string match ("const event = useEvent()"). Minor upstream formatting changes (spacing, let vs const, etc.) will flip this to sdk.event and break the injected listener wiring. Prefer a more resilient detection (e.g., regex for useEvent\(\) with an event binding, or checking for useEvent import/usage patterns) to reduce patch fragility across upstream versions.

Suggested change
const eventSource = source.includes("const event = useEvent()") ? "event" : "sdk.event"
const hasUseEventBinding = /\b(?:const|let|var)\s+event\s*=\s*useEvent\s*\(\s*\)\s*;?/.test(source)
const eventSource = hasUseEventBinding ? "event" : "sdk.event"

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants