Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions scripts/cursor-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,18 @@ function readConfig(file) {
} catch (e) {
if (e.code !== 'ENOENT') throw e;
}
if (!config || typeof config !== 'object' || Array.isArray(config)) config = {};
if (!config.hooks || typeof config.hooks !== 'object' || Array.isArray(config.hooks)) config.hooks = {};
if (!config || typeof config !== 'object' || Array.isArray(config)) {
throw new Error(file + ' must contain a JSON object; nothing was changed');
}
if (config.hooks === undefined) config.hooks = {};
if (!config.hooks || typeof config.hooks !== 'object' || Array.isArray(config.hooks)) {
throw new Error(file + ': hooks must be an object; nothing was changed');
}
for (const [event, entries] of Object.entries(config.hooks)) {
if (!Array.isArray(entries)) {
throw new Error(file + ': hooks.' + event + ' must be an array; nothing was changed');
}
}
return config;
}

Expand Down
17 changes: 17 additions & 0 deletions tests/cursor-hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,20 @@ test('installer refuses to touch a malformed hooks.json', () => {
assert.equal(fs.readFileSync(file, 'utf8'), broken, 'malformed file must be left byte-for-byte intact');
}
});

for (const [name, config] of Object.entries({
'root-array': [{ command: 'keep me' }],
'hooks-array': { hooks: [{ command: 'keep me' }] },
'event-string': { hooks: { sessionStart: 'node custom-hook.js' } },
})) {
test(`installer refuses ${name} without overwriting hooks.json`, () => {
const c = cursorEnv(`invalid-${name}`);
const file = path.join(c.home, '.cursor', 'hooks.json');
fs.mkdirSync(path.dirname(file), { recursive: true });
const original = JSON.stringify(config, null, 2) + '\n';
fs.writeFileSync(file, original);
const result = cli(['install'], c.env);
assert.notEqual(result.status, 0, 'invalid config must not be silently rewritten');
assert.equal(fs.readFileSync(file, 'utf8'), original);
});
}
Loading