mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-10 03:27:59 +00:00
fix(setup): honor active Codex home for hooks and skills
This commit is contained in:
parent
44a2905330
commit
f1736bb957
4 changed files with 54 additions and 3 deletions
|
|
@ -208,10 +208,10 @@ export function getEditorTargets(home: string = os.homedir()): EditorTargets {
|
|||
// Codex hooks use Claude Code's exact {hooks: {Event: [...]}} JSON shape
|
||||
// and hookSpecificOutput response contract, in a dedicated hooks.json
|
||||
// (https://developers.openai.com/codex/hooks).
|
||||
settingsFile: path.join(home, '.codex', 'hooks.json'),
|
||||
settingsFile: path.join(codexHome, 'hooks.json'),
|
||||
events: ['PreToolUse', 'PostToolUse'],
|
||||
needle: 'gitnexus-hook',
|
||||
scriptDir: path.join(home, '.codex', 'hooks', 'gitnexus'),
|
||||
scriptDir: path.join(codexHome, 'hooks', 'gitnexus'),
|
||||
},
|
||||
{
|
||||
id: 'antigravity',
|
||||
|
|
|
|||
|
|
@ -1325,7 +1325,7 @@ async function installOpenCodeSkills(result: SetupResult): Promise<void> {
|
|||
* Install global Codex skills to ~/.agents/skills/gitnexus/
|
||||
*/
|
||||
async function installCodexSkills(result: SetupResult): Promise<void> {
|
||||
const codexDir = path.join(os.homedir(), '.codex');
|
||||
const codexDir = path.dirname(getEditorTargets().codex.configFile);
|
||||
if (!(await dirExists(codexDir))) return;
|
||||
|
||||
const skillsDir = skillTarget('codex').dir;
|
||||
|
|
|
|||
|
|
@ -834,6 +834,7 @@ describe('Codex hooks (installClaudeSchemaHooks)', () => {
|
|||
let tempHome: string;
|
||||
let originalHome: string | undefined;
|
||||
let originalUserProfile: string | undefined;
|
||||
let originalCodexHome: string | undefined;
|
||||
|
||||
const hooksJsonPath = () => path.join(tempHome, '.codex', 'hooks.json');
|
||||
|
||||
|
|
@ -843,6 +844,8 @@ describe('Codex hooks (installClaudeSchemaHooks)', () => {
|
|||
|
||||
originalHome = process.env.HOME;
|
||||
originalUserProfile = process.env.USERPROFILE;
|
||||
originalCodexHome = process.env.CODEX_HOME;
|
||||
delete process.env.CODEX_HOME;
|
||||
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), 'gn-codex-hooks-'));
|
||||
process.env.HOME = tempHome;
|
||||
process.env.USERPROFILE = tempHome;
|
||||
|
|
@ -858,6 +861,8 @@ describe('Codex hooks (installClaudeSchemaHooks)', () => {
|
|||
vi.restoreAllMocks();
|
||||
process.env.HOME = originalHome;
|
||||
process.env.USERPROFILE = originalUserProfile;
|
||||
if (originalCodexHome === undefined) delete process.env.CODEX_HOME;
|
||||
else process.env.CODEX_HOME = originalCodexHome;
|
||||
await fs.rm(tempHome, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
|
|
@ -878,6 +883,28 @@ describe('Codex hooks (installClaudeSchemaHooks)', () => {
|
|||
).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('installs hooks and skills for active CODEX_HOME without touching the default home', async () => {
|
||||
const activeHome = path.join(tempHome, 'active-codex');
|
||||
const defaultHooks = hooksJsonPath();
|
||||
await fs.rm(path.join(tempHome, '.codex'), { recursive: true, force: true });
|
||||
await fs.mkdir(activeHome);
|
||||
process.env.CODEX_HOME = activeHome;
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand({ codingAgent: 'codex' });
|
||||
|
||||
const hooks = JSON.parse(await fs.readFile(path.join(activeHome, 'hooks.json'), 'utf-8')).hooks;
|
||||
expect(hooks.PreToolUse).toHaveLength(1);
|
||||
expect(hooks.PostToolUse).toHaveLength(1);
|
||||
await expect(
|
||||
fs.access(path.join(activeHome, 'hooks', 'gitnexus', 'gitnexus-hook.cjs')),
|
||||
).resolves.toBeUndefined();
|
||||
await expect(
|
||||
fs.access(path.join(tempHome, '.agents', 'skills', 'gitnexus-guide', 'SKILL.md')),
|
||||
).resolves.toBeUndefined();
|
||||
await expect(fs.access(defaultHooks)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('is idempotent — a second setup run adds no duplicate entries', async () => {
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
|
|
|||
|
|
@ -212,22 +212,46 @@ describe('uninstallCommand', () => {
|
|||
const activeHome = path.join(tempHome, 'active-codex');
|
||||
const activeConfig = path.join(activeHome, 'config.toml');
|
||||
const defaultConfig = path.join(tempHome, '.codex', 'config.toml');
|
||||
const activeHooks = path.join(activeHome, 'hooks.json');
|
||||
const defaultHooks = path.join(tempHome, '.codex', 'hooks.json');
|
||||
const activeScriptDir = path.join(activeHome, 'hooks', 'gitnexus');
|
||||
const defaultScriptDir = path.join(tempHome, '.codex', 'hooks', 'gitnexus');
|
||||
const activeRaw = '[mcp_servers.gitnexus]\ncommand = "active"\n';
|
||||
const defaultRaw = '[mcp_servers.gitnexus]\ncommand = "default"\n';
|
||||
const hooksRaw = JSON.stringify({
|
||||
hooks: {
|
||||
PreToolUse: [
|
||||
{ matcher: 'Bash', hooks: [{ type: 'command', command: 'node gitnexus-hook.cjs' }] },
|
||||
{ matcher: 'Read', hooks: [{ type: 'command', command: 'user-hook' }] },
|
||||
],
|
||||
},
|
||||
});
|
||||
await fs.mkdir(activeHome);
|
||||
await fs.mkdir(path.dirname(defaultConfig));
|
||||
await fs.mkdir(activeScriptDir, { recursive: true });
|
||||
await fs.mkdir(defaultScriptDir, { recursive: true });
|
||||
await fs.writeFile(activeConfig, activeRaw);
|
||||
await fs.writeFile(defaultConfig, defaultRaw);
|
||||
await fs.writeFile(activeHooks, hooksRaw);
|
||||
await fs.writeFile(defaultHooks, hooksRaw);
|
||||
process.env.CODEX_HOME = activeHome;
|
||||
|
||||
const uninstallCommand = await importUninstall();
|
||||
await uninstallCommand();
|
||||
expect(vi.mocked(console.log).mock.calls.flat().join('\n')).toContain(activeConfig);
|
||||
expect(vi.mocked(console.log).mock.calls.flat().join('\n')).toContain(activeHooks);
|
||||
expect(await fs.readFile(activeConfig, 'utf-8')).toBe(activeRaw);
|
||||
expect(await fs.readFile(activeHooks, 'utf-8')).toBe(hooksRaw);
|
||||
|
||||
await uninstallCommand({ force: true });
|
||||
expect(await fs.readFile(activeConfig, 'utf-8')).not.toContain('[mcp_servers.gitnexus]');
|
||||
expect(await fs.readFile(defaultConfig, 'utf-8')).toBe(defaultRaw);
|
||||
const remaining = JSON.parse(await fs.readFile(activeHooks, 'utf-8'));
|
||||
expect(remaining.hooks.PreToolUse).toHaveLength(1);
|
||||
expect(remaining.hooks.PreToolUse[0].hooks[0].command).toBe('user-hook');
|
||||
expect(await fs.readFile(defaultHooks, 'utf-8')).toBe(hooksRaw);
|
||||
await expect(fs.access(activeScriptDir)).rejects.toThrow();
|
||||
await expect(fs.access(defaultScriptDir)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('leaves a corrupt JSON config untouched', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue