From 2256b09f031c460e7e1aded00759341f1d1dcb0e Mon Sep 17 00:00:00 2001 From: Aliaksei Khval Date: Mon, 18 May 2026 13:55:29 +0200 Subject: [PATCH] fix: ensure UTF-8 encoding for hooks and scripts (#116) --- init.py | 3 ++- opencode-plugin/src/index.ts | 22 +++++++++++++++------- tracking/hooks/post-commit.py | 3 ++- tracking/hooks/post-fetch.py | 1 + tracking/hooks/post-merge.py | 1 + tracking/hooks/post-rewrite.py | 3 ++- tracking/hooks/pre-push.py | 1 + tracking/hooks/reference-transaction.py | 1 + tracking/tracy.py | 3 ++- 9 files changed, 27 insertions(+), 11 deletions(-) diff --git a/init.py b/init.py index 14c500c..5aa4612 100644 --- a/init.py +++ b/init.py @@ -18,6 +18,7 @@ def run_git(repo, args, capture=False, check=False): result = subprocess.run( ["git", "-C", repo] + args, text=True, + encoding='utf-8', capture_output=capture, check=check ) @@ -134,7 +135,7 @@ def main(): # ------------------------------- # CONFIG FILE # ------------------------------- - with open(tracy_dir / "config", "w") as f: + with open(tracy_dir / "config", "w", encoding='utf-8') as f: f.write(f"TRACY_SNAPSHOT_SCRIPT={script_source.as_posix()}\n") # ------------------------------- diff --git a/opencode-plugin/src/index.ts b/opencode-plugin/src/index.ts index d8e950f..b8f2de3 100644 --- a/opencode-plugin/src/index.ts +++ b/opencode-plugin/src/index.ts @@ -19,7 +19,7 @@ export const MyPlugin: Plugin = async (input: PluginInput) => { async function getRepoRoot(): Promise { try { const result = await $`git rev-parse --show-toplevel`.cwd(directory).quiet() - return String(result.stdout).trim() as string + return Buffer.from(result.stdout).toString('utf8').trim() as string } catch { return null } @@ -42,7 +42,15 @@ export const MyPlugin: Plugin = async (input: PluginInput) => { if (!(await configFile.exists())) return // cannot use dotenv, so enjoy this handrolled env parsing - const text = await configFile.text(); + // Try UTF-8 first; fall back to windows-1252 for config files written + // before the utf-8 fix was applied to init.py (Windows default encoding). + const bytes = await configFile.bytes() + let text: string + try { + text = new TextDecoder('utf-8', { fatal: true }).decode(bytes) + } catch { + text = new TextDecoder('windows-1252').decode(bytes) + } // Remove UTF-8 BOM (safeguard for cross-platform edge cases) const cleanedText = text.replace(/^\uFEFF/, ''); @@ -78,11 +86,11 @@ export const MyPlugin: Plugin = async (input: PluginInput) => { await L.info("Plugin initialized", { repoRoot, tracyPath }) let pythonCmd; - if ((await $`python3 --version`.quiet()).exitCode === 0) { + if ((await $`python3 --version`.quiet().nothrow()).exitCode === 0) { pythonCmd = 'python3' await L.info("Detected python command: python3") } else { - if ((await $`python --version`.quiet()).exitCode === 0) { + if ((await $`python --version`.quiet().nothrow()).exitCode === 0) { pythonCmd = 'python' await L.info("Detected python command: python") } else { @@ -279,15 +287,15 @@ export const MyPlugin: Plugin = async (input: PluginInput) => { if (result.exitCode !== 0) { await L.error("Python failed", { - stdout: result.stdout.toString(), - stderr: result.stderr.toString(), + stdout: Buffer.from(result.stdout).toString('utf8'), + stderr: Buffer.from(result.stderr).toString('utf8'), exitCode: result.exitCode }) return } await L.info( - `created user snapshot for ${path}. tracy.py: ${result.stdout.toString().trim()}` + `created user snapshot for ${path}. tracy.py: ${Buffer.from(result.stdout).toString('utf8').trim()}` ) })() diff --git a/tracking/hooks/post-commit.py b/tracking/hooks/post-commit.py index c1f4eec..c4627d1 100644 --- a/tracking/hooks/post-commit.py +++ b/tracking/hooks/post-commit.py @@ -12,6 +12,7 @@ def run_git(args, capture=False, check=False, env=None): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture else None, stderr=subprocess.DEVNULL, check=check, @@ -138,7 +139,7 @@ def build_filtered_chain(local_ref, origin_commit, files_in_commit): if commit_desc: cmd += ["-m", commit_desc] - result = subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=commit_env) + result = subprocess.run(cmd, text=True, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=commit_env) new_commit = result.stdout.strip() if not new_commit: diff --git a/tracking/hooks/post-fetch.py b/tracking/hooks/post-fetch.py index 02f9426..4dbb5a1 100644 --- a/tracking/hooks/post-fetch.py +++ b/tracking/hooks/post-fetch.py @@ -16,6 +16,7 @@ def run_git(args, capture=False, check=False): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture else None, stderr=subprocess.DEVNULL, check=check diff --git a/tracking/hooks/post-merge.py b/tracking/hooks/post-merge.py index 139f055..eb0f5f8 100644 --- a/tracking/hooks/post-merge.py +++ b/tracking/hooks/post-merge.py @@ -6,6 +6,7 @@ def run_git(args, capture=False): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture else None, stderr=subprocess.DEVNULL, ) diff --git a/tracking/hooks/post-rewrite.py b/tracking/hooks/post-rewrite.py index a869281..f4f2113 100644 --- a/tracking/hooks/post-rewrite.py +++ b/tracking/hooks/post-rewrite.py @@ -12,6 +12,7 @@ def run_git(args, capture=False, check=False, env=None): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture else None, stderr=subprocess.DEVNULL, check=check, @@ -134,7 +135,7 @@ def build_chain_from_commits(commits_list, origin_commit): cmd.extend(["-p", parent]) cmd.extend(["-m", msg]) - result = subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env) + result = subprocess.run(cmd, text=True, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env) new_commit = (result.stdout or "").strip() if new_commit: diff --git a/tracking/hooks/pre-push.py b/tracking/hooks/pre-push.py index 345f064..d1cdcae 100644 --- a/tracking/hooks/pre-push.py +++ b/tracking/hooks/pre-push.py @@ -13,6 +13,7 @@ def run_git(args, capture=False, check=False): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture else None, stderr=subprocess.DEVNULL, check=check diff --git a/tracking/hooks/reference-transaction.py b/tracking/hooks/reference-transaction.py index e7917a3..72c8a01 100644 --- a/tracking/hooks/reference-transaction.py +++ b/tracking/hooks/reference-transaction.py @@ -7,6 +7,7 @@ def run_git(args, capture=False): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture else None, stderr=subprocess.DEVNULL, ) diff --git a/tracking/tracy.py b/tracking/tracy.py index 628fae6..65cfe50 100644 --- a/tracking/tracy.py +++ b/tracking/tracy.py @@ -20,6 +20,7 @@ def run_git(args, capture_output=False, check=False, cwd=None): result = subprocess.run( ["git"] + args, text=True, + encoding='utf-8', stdout=subprocess.PIPE if capture_output else None, stderr=subprocess.DEVNULL, check=check, @@ -206,7 +207,7 @@ def run_git(args, capture_output=False, check=False, cwd=None): if DESCRIPTION: commit_cmd += ["-m", DESCRIPTION] -result = subprocess.run(commit_cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env) +result = subprocess.run(commit_cmd, text=True, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env) COMMIT = result.stdout.strip() if not COMMIT: