merge: sync Kilo runtime branch with latest main

This commit is contained in:
Alex Alecu
2026-04-03 12:47:24 +03:00
43 changed files with 3868 additions and 407 deletions

View File

@@ -659,7 +659,7 @@ describe('copyCommandsAsCopilotSkills', () => {
assert.ok(skillContent.includes('description: Run all remaining phases autonomously'),
'description preserved');
// argument-hint present and double-quoted
assert.ok(skillContent.includes('argument-hint: "[--from N]"'), 'argument-hint present and quoted');
assert.ok(skillContent.includes('argument-hint: "[--from N] [--only N] [--interactive]"'), 'argument-hint present and quoted');
// allowed-tools comma-separated
assert.ok(skillContent.includes('allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion, Task'),
'allowed-tools is comma-separated');
@@ -1349,3 +1349,89 @@ describe('E2E: Copilot uninstall verification', () => {
});
});
});
// ─── Claude uninstall: user file preservation (#1423) ─────────────────────────
function runClaudeInstall(cwd) {
const env = { ...process.env };
delete env.GSD_TEST_MODE;
return execFileSync(process.execPath, [INSTALL_PATH, '--claude', '--local'], {
cwd,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
env,
});
}
function runClaudeUninstall(cwd) {
const env = { ...process.env };
delete env.GSD_TEST_MODE;
return execFileSync(process.execPath, [INSTALL_PATH, '--claude', '--local', '--uninstall'], {
cwd,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
env,
});
}
describe('Claude uninstall preserves user-generated files (#1423)', () => {
let tmpDir;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-preserve-'));
runClaudeInstall(tmpDir);
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
test('preserves USER-PROFILE.md across uninstall', () => {
const profilePath = path.join(tmpDir, '.claude', 'get-shit-done', 'USER-PROFILE.md');
const content = '# Developer Profile\n\nAutonomy: High\nGenerated: 2026-03-29\n';
fs.writeFileSync(profilePath, content);
runClaudeUninstall(tmpDir);
assert.ok(fs.existsSync(profilePath), 'USER-PROFILE.md should survive uninstall');
assert.strictEqual(fs.readFileSync(profilePath, 'utf-8'), content, 'content should be identical');
});
test('preserves dev-preferences.md across uninstall', () => {
const prefsDir = path.join(tmpDir, '.claude', 'commands', 'gsd');
fs.mkdirSync(prefsDir, { recursive: true });
const prefsPath = path.join(prefsDir, 'dev-preferences.md');
const content = '---\nname: dev-preferences\n---\n# Preferences\nUse TypeScript strict.\n';
fs.writeFileSync(prefsPath, content);
runClaudeUninstall(tmpDir);
assert.ok(fs.existsSync(prefsPath), 'dev-preferences.md should survive uninstall');
assert.strictEqual(fs.readFileSync(prefsPath, 'utf-8'), content, 'content should be identical');
});
test('still removes GSD engine files during uninstall', () => {
const profilePath = path.join(tmpDir, '.claude', 'get-shit-done', 'USER-PROFILE.md');
fs.writeFileSync(profilePath, '# Profile\n');
// Verify engine files exist before uninstall
const binDir = path.join(tmpDir, '.claude', 'get-shit-done', 'bin');
assert.ok(fs.existsSync(binDir), 'bin/ should exist before uninstall');
runClaudeUninstall(tmpDir);
// Engine files gone, user file preserved
assert.ok(!fs.existsSync(binDir), 'bin/ should be removed after uninstall');
assert.ok(fs.existsSync(profilePath), 'USER-PROFILE.md should survive');
});
test('clean uninstall when no user files exist', () => {
runClaudeUninstall(tmpDir);
const gsdDir = path.join(tmpDir, '.claude', 'get-shit-done');
const cmdDir = path.join(tmpDir, '.claude', 'commands', 'gsd');
// Directories should be fully removed when no user files to preserve
assert.ok(!fs.existsSync(gsdDir), 'get-shit-done/ should not exist after clean uninstall');
assert.ok(!fs.existsSync(cmdDir), 'commands/gsd/ should not exist after clean uninstall');
});
});