From f230ee428f6cc6e80244f9002ad901eb4fdd64ef Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Sun, 12 Apr 2026 22:06:04 -0700 Subject: [PATCH] fix: stabilize windows ci portability --- scripts/hooks/session-activity-tracker.js | 89 ++++++++++++++--------- tests/scripts/build-opencode.test.js | 13 ++-- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/scripts/hooks/session-activity-tracker.js b/scripts/hooks/session-activity-tracker.js index 9d4716a1..5ff85d35 100644 --- a/scripts/hooks/session-activity-tracker.js +++ b/scripts/hooks/session-activity-tracker.js @@ -359,44 +359,65 @@ function gitRepoRoot(cwd) { return runGit(['rev-parse', '--show-toplevel'], cwd); } -function repoRelativePath(repoRoot, filePath) { +function candidateGitPaths(repoRoot, filePath) { + const resolvedRepoRoot = path.resolve(repoRoot); const absolute = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(process.cwd(), filePath); - const relative = path.relative(repoRoot, absolute); + const relative = path.relative(resolvedRepoRoot, absolute); + if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) { - return null; + return []; } - return relative.split(path.sep).join('/'); + + const candidates = []; + const pushCandidate = value => { + const candidate = String(value || '').trim(); + if (!candidate || candidates.includes(candidate)) { + return; + } + candidates.push(candidate); + }; + + pushCandidate(relative); + pushCandidate(relative.split(path.sep).join('/')); + pushCandidate(absolute); + pushCandidate(absolute.split(path.sep).join('/')); + + return candidates; } -function patchPreviewFromGitDiff(repoRoot, repoRelative) { - const patch = runGit( - ['diff', '--no-ext-diff', '--no-color', '--unified=1', '--', repoRelative], - repoRoot +function patchPreviewFromGitDiff(repoRoot, pathCandidates) { + for (const candidate of pathCandidates) { + const patch = runGit( + ['diff', '--no-ext-diff', '--no-color', '--unified=1', '--', candidate], + repoRoot + ); + if (!patch) { + continue; + } + + const relevant = patch + .split(/\r?\n/) + .filter(line => + line.startsWith('@@') + || (line.startsWith('+') && !line.startsWith('+++')) + || (line.startsWith('-') && !line.startsWith('---')) + ) + .slice(0, 6); + + if (relevant.length > 0) { + return relevant.join('\n'); + } + } + + return undefined; +} + +function trackedInGit(repoRoot, pathCandidates) { + return pathCandidates.some(candidate => + runGit(['ls-files', '--error-unmatch', '--', candidate], repoRoot) !== null ); - if (!patch) { - return undefined; - } - - const relevant = patch - .split(/\r?\n/) - .filter(line => - line.startsWith('@@') - || (line.startsWith('+') && !line.startsWith('+++')) - || (line.startsWith('-') && !line.startsWith('---')) - ) - .slice(0, 6); - - if (relevant.length === 0) { - return undefined; - } - - return relevant.join('\n'); -} - -function trackedInGit(repoRoot, repoRelative) { - return runGit(['ls-files', '--error-unmatch', '--', repoRelative], repoRoot) !== null; } function enrichFileEventFromWorkingTree(toolName, event) { @@ -409,14 +430,14 @@ function enrichFileEventFromWorkingTree(toolName, event) { return event; } - const repoRelative = repoRelativePath(repoRoot, event.path); - if (!repoRelative) { + const pathCandidates = candidateGitPaths(repoRoot, event.path); + if (pathCandidates.length === 0) { return event; } const tool = String(toolName || '').trim().toLowerCase(); - const tracked = trackedInGit(repoRoot, repoRelative); - const patchPreview = patchPreviewFromGitDiff(repoRoot, repoRelative) || event.patch_preview; + const tracked = trackedInGit(repoRoot, pathCandidates); + const patchPreview = patchPreviewFromGitDiff(repoRoot, pathCandidates) || event.patch_preview; const diffPreview = buildDiffPreviewFromPatchPreview(patchPreview) || event.diff_preview; if (tool.includes('write')) { diff --git a/tests/scripts/build-opencode.test.js b/tests/scripts/build-opencode.test.js index 56b30f43..3cd62c19 100644 --- a/tests/scripts/build-opencode.test.js +++ b/tests/scripts/build-opencode.test.js @@ -26,11 +26,12 @@ function main() { let failed = 0 const repoRoot = path.join(__dirname, "..", "..") - const packageJson = JSON.parse( - fs.readFileSync(path.join(repoRoot, "package.json"), "utf8") - ) - const buildScript = path.join(repoRoot, "scripts", "build-opencode.js") - const distEntry = path.join(repoRoot, ".opencode", "dist", "index.js") +const packageJson = JSON.parse( + fs.readFileSync(path.join(repoRoot, "package.json"), "utf8") +) +const buildScript = path.join(repoRoot, "scripts", "build-opencode.js") +const distEntry = path.join(repoRoot, ".opencode", "dist", "index.js") +const npmExecutable = process.platform === "win32" ? "npm.cmd" : "npm" const tests = [ ["package.json exposes the OpenCode build and prepack hooks", () => { assert.strictEqual(packageJson.scripts["build:opencode"], "node scripts/build-opencode.js") @@ -46,7 +47,7 @@ function main() { assert.ok(fs.existsSync(distEntry), ".opencode/dist/index.js should exist after build") }], ["npm pack includes the compiled OpenCode dist payload", () => { - const result = spawnSync("npm", ["pack", "--dry-run", "--json"], { + const result = spawnSync(npmExecutable, ["pack", "--dry-run", "--json"], { cwd: repoRoot, encoding: "utf8", })