moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
import { describe, expect, it } from 'vitest';
import {
HIVE_MIND_MARKER,
HOOK_EVENT_BY_BASENAME,
defaultHookEntries,
hasHiveHooks,
mergeHiveHooks,
type ClaudeCodeSettings,
type HookEntrySpec,
} from '../src/settings-merger.js';
import { hookCommandFor } from '../src/paths.js';
const HOOKS_DIR = '/abs/dist/hooks';
function makeEntry(basename: 'session-start' | 'user-prompt-submit' | 'stop' | 'pre-compact'): HookEntrySpec {
return {
basename,
command: hookCommandFor(HOOKS_DIR, basename),
timeout: 5,
};
}
describe('mergeHiveHooks', () => {
it('returns a new object — does not mutate input', () => {
const original: ClaudeCodeSettings = { hooks: { SessionStart: [] } };
const merged = mergeHiveHooks(original, [makeEntry('session-start')]);
expect(merged).not.toBe(original);
expect(original.hooks?.SessionStart).toEqual([]);
});
it('appends a hive group to each requested event array', () => {
const merged = mergeHiveHooks({}, [
makeEntry('session-start'),
makeEntry('user-prompt-submit'),
makeEntry('stop'),
makeEntry('pre-compact'),
]);
expect(merged.hooks?.SessionStart).toHaveLength(1);
expect(merged.hooks?.UserPromptSubmit).toHaveLength(1);
expect(merged.hooks?.Stop).toHaveLength(1);
expect(merged.hooks?.PreCompact).toHaveLength(1);
});
it('preserves existing hook entries verbatim', () => {
const existing: ClaudeCodeSettings = {
hooks: {
SessionStart: [
{ hooks: [{ type: 'command', command: 'node /existing/gsd-context.js', timeout: 10 }] },
],
},
};
const merged = mergeHiveHooks(existing, [makeEntry('session-start')]);
const arr = merged.hooks?.SessionStart;
expect(arr).toHaveLength(2);
expect(arr?.[0].hooks[0].command).toBe('node /existing/gsd-context.js');
expect(arr?.[1]._hiveMindShim).toBe(HIVE_MIND_MARKER);
});
it('replaces an existing hive entry when the same command is re-installed (idempotent)', () => {
const cmd = hookCommandFor(HOOKS_DIR, 'session-start');
const merged1 = mergeHiveHooks({}, [{ basename: 'session-start', command: cmd, timeout: 5 }]);
const merged2 = mergeHiveHooks(merged1, [{ basename: 'session-start', command: cmd, timeout: 7 }]);
expect(merged2.hooks?.SessionStart).toHaveLength(1);
expect(merged2.hooks?.SessionStart?.[0].hooks[0].timeout).toBe(7);
});
it('preserves unrelated top-level fields', () => {
const merged = mergeHiveHooks(
{ env: { SOMETHING: '1' }, statusLine: { type: 'command', command: 'foo' }, hooks: {} } as ClaudeCodeSettings,
[makeEntry('session-start')],
);
expect(merged['env']).toEqual({ SOMETHING: '1' });
expect(merged['statusLine']).toEqual({ type: 'command', command: 'foo' });
});
});
describe('hasHiveHooks', () => {
it('returns false on empty settings', () => {
expect(hasHiveHooks(undefined)).toBe(false);
expect(hasHiveHooks({})).toBe(false);
expect(hasHiveHooks({ hooks: {} })).toBe(false);
});
it('returns true when at least one event array has the marker', () => {
const merged = mergeHiveHooks({}, [makeEntry('stop')]);
expect(hasHiveHooks(merged)).toBe(true);
});
});
describe('defaultHookEntries', () => {
it('builds 4 entries — one per canonical hook', () => {
const entries = defaultHookEntries(HOOKS_DIR, 5, hookCommandFor);
expect(entries).toHaveLength(4);
const events = entries.map((e) => HOOK_EVENT_BY_BASENAME[e.basename]);
expect([...events].sort()).toEqual(['PreCompact', 'SessionStart', 'Stop', 'UserPromptSubmit']);
});
it('every entry carries the requested timeout', () => {
const entries = defaultHookEntries(HOOKS_DIR, 9, hookCommandFor);
expect(entries.every((e) => e.timeout === 9)).toBe(true);
});
it('threads cliPath into every generated hook command', () => {
const cliPath = '/abs/cli.js';
const entries = defaultHookEntries(HOOKS_DIR, 5, hookCommandFor, cliPath);
expect(entries.every((e) => e.command.includes(`--cli-path "${cliPath}"`))).toBe(true);
});
it('omits --cli-path entirely when none supplied', () => {
const entries = defaultHookEntries(HOOKS_DIR, 5, hookCommandFor);
expect(entries.every((e) => !e.command.includes('--cli-path'))).toBe(true);
});
});