diff --git a/bin/install.js b/bin/install.js index 063752c1..c08cdae3 100755 --- a/bin/install.js +++ b/bin/install.js @@ -6130,6 +6130,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS const isCursor = runtime === 'cursor'; const isWindsurf = runtime === 'windsurf'; const isTrae = runtime === 'trae'; + const isCline = runtime === 'cline'; if (shouldInstallStatusline && !isOpencode && !isKilo && !isCodex && !isCopilot && !isCursor && !isWindsurf && !isTrae) { settings.statusLine = { @@ -6140,7 +6141,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS } // Write settings when runtime supports settings.json - if (!isCodex && !isCopilot && !isKilo && !isCursor && !isWindsurf && !isTrae) { + if (!isCodex && !isCopilot && !isKilo && !isCursor && !isWindsurf && !isTrae && !isCline) { writeSettings(settingsPath, settings); } @@ -6489,6 +6490,7 @@ if (process.env.GSD_TEST_MODE) { validateHookFields, preserveUserArtifacts, restoreUserArtifacts, + finishInstall, }; } else { diff --git a/tests/cline-install.test.cjs b/tests/cline-install.test.cjs index e0ed7e4c..383b89c6 100644 --- a/tests/cline-install.test.cjs +++ b/tests/cline-install.test.cjs @@ -29,6 +29,7 @@ const { getConfigDirFromHome, convertClaudeToCliineMarkdown, install, + finishInstall, } = require('../bin/install.js'); describe('Cline runtime directory mapping', () => { @@ -154,6 +155,23 @@ describe('Cline install (local)', () => { assert.ok(fs.existsSync(engineDir), 'get-shit-done directory must exist after install'); }); + test('finishInstall does not throw ERR_INVALID_ARG_TYPE for cline runtime (regression: null settingsPath guard)', () => { + // install() returns settingsPath: null for cline — finishInstall() must not call + // writeSettings(null, ...) or it crashes with ERR_INVALID_ARG_TYPE. + // Before fix: isCline was missing from the writeSettings guard in finishInstall(). + // After fix: !isCline is in the guard, matching codex/copilot/cursor/windsurf/trae. + assert.doesNotThrow( + () => finishInstall(null, null, null, false, 'cline', false, tmpDir), + 'finishInstall must not throw when called with null settingsPath for cline runtime' + ); + }); + + test('settings.json is not written for cline runtime', () => { + finishInstall(null, null, null, false, 'cline', false, tmpDir); + const settingsJson = path.join(tmpDir, 'settings.json'); + assert.ok(!fs.existsSync(settingsJson), 'settings.json must not be written for cline runtime'); + }); + test('installed engine files have no leaked .claude paths', () => { install(false, 'cline'); const engineDir = path.join(tmpDir, 'get-shit-done');