From cbccb7fdc0b43f948efa387e9e0430fc99a1e7bd Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 20 Mar 2026 02:44:25 -0700 Subject: [PATCH] fix: strip validator shebangs on Windows CRLF checkouts --- tests/ci/validators.test.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/ci/validators.test.js b/tests/ci/validators.test.js index 16981188..d90b4809 100644 --- a/tests/ci/validators.test.js +++ b/tests/ci/validators.test.js @@ -52,6 +52,10 @@ function writeInstallComponentsManifest(testDir, components) { }); } +function stripShebang(source) { + return source.replace(/^#![^\r\n]*(?:\r?\n)?/, ''); +} + /** * Run modified source via a temp file (avoids Windows node -e shebang issues). * The temp file is written inside the repo so require() can resolve node_modules. @@ -95,8 +99,8 @@ function runValidatorWithDir(validatorName, dirConstant, overridePath) { // Read the validator source, replace the directory constant, and run as a wrapper let source = fs.readFileSync(validatorPath, 'utf8'); - // Remove the shebang line (Windows node cannot parse shebangs in eval/inline mode) - source = source.replace(/^#!.*\n/, ''); + // Remove the shebang line so wrappers also work against CRLF-checked-out files on Windows. + source = stripShebang(source); // Replace the directory constant with our override path const dirRegex = new RegExp(`const ${dirConstant} = .*?;`); @@ -113,7 +117,7 @@ function runValidatorWithDir(validatorName, dirConstant, overridePath) { function runValidatorWithDirs(validatorName, overrides) { const validatorPath = path.join(validatorsDir, `${validatorName}.js`); let source = fs.readFileSync(validatorPath, 'utf8'); - source = source.replace(/^#!.*\n/, ''); + source = stripShebang(source); for (const [constant, overridePath] of Object.entries(overrides)) { const dirRegex = new RegExp(`const ${constant} = .*?;`); source = source.replace(dirRegex, `const ${constant} = ${JSON.stringify(overridePath)};`); @@ -145,7 +149,7 @@ function runValidator(validatorName) { function runCatalogValidator(overrides = {}) { const validatorPath = path.join(validatorsDir, 'catalog.js'); let source = fs.readFileSync(validatorPath, 'utf8'); - source = source.replace(/^#!.*\n/, ''); + source = stripShebang(source); source = `process.argv.push('--text');\n${source}`; const resolvedOverrides = { @@ -202,6 +206,11 @@ function runTests() { // ========================================== console.log('validate-agents.js:'); + if (test('strips CRLF shebangs before writing temp wrappers', () => { + const source = '#!/usr/bin/env node\r\nconsole.log("ok");'; + assert.strictEqual(stripShebang(source), 'console.log("ok");'); + })) passed++; else failed++; + if (test('passes on real project agents', () => { const result = runValidator('validate-agents'); assert.strictEqual(result.code, 0, `Should pass, got stderr: ${result.stderr}`);