mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
* feat(install): add guided Claude plugin setup * fix: support Claude command shims on Windows * feat: support safe Claude plugin scope migration * fix(install): preserve interactive setup terminal * fix(install): auto-migrate setup scope changes * feat(install): add guided multi-harness installer * fix(install): sync Yarn binary metadata * fix(install): handle wizard EOF on Node 18 * ci: allow installer matrix tests to finish * test(install): allow slower PowerShell delegation * fix(install): harden guided provider reconciliation * test(install): harden packaged and local compatibility * chore: prepare guided installer release 2.2.0 * fix(install): report refreshed Codex marketplace state * fix(install): verify managed content provenance * test(install): allow empty Yarn smoke fixture * test(install): invoke Windows package shims safely * fix(install): close cross-platform release gaps * fix(install): require trusted GitHub origins * fix(install): preserve hook profile precedence * refactor(install): centralize trusted GitHub origins * ci: retrigger workflow run after merge of main Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
95 lines
2.7 KiB
JavaScript
95 lines
2.7 KiB
JavaScript
/**
|
|
* Integration checks for the native Codex plugin hook boundary.
|
|
*
|
|
* Run with: node tests/codex-native-hooks.test.js
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const { spawnSync } = require('child_process');
|
|
|
|
const repoRoot = path.resolve(__dirname, '..');
|
|
const hookConfig = JSON.parse(fs.readFileSync(path.join(repoRoot, 'hooks', 'codex-hooks.json'), 'utf8'));
|
|
const sessionStart = hookConfig.hooks.SessionStart[0].hooks[0];
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function test(name, fn) {
|
|
try {
|
|
fn();
|
|
console.log(` ✓ ${name}`);
|
|
passed++;
|
|
} catch (error) {
|
|
console.log(` ✗ ${name}`);
|
|
console.log(` Error: ${error.message}`);
|
|
failed++;
|
|
}
|
|
}
|
|
|
|
function runSessionStart({ pluginRoot }) {
|
|
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-codex-hook-'));
|
|
const userHome = path.join(fixtureRoot, 'user-home');
|
|
const projectDir = path.join(fixtureRoot, 'project');
|
|
const pluginData = path.join(fixtureRoot, 'plugin-data');
|
|
fs.mkdirSync(userHome, { recursive: true });
|
|
fs.mkdirSync(projectDir, { recursive: true });
|
|
fs.mkdirSync(pluginData, { recursive: true });
|
|
|
|
const env = {
|
|
...process.env,
|
|
HOME: userHome,
|
|
USERPROFILE: userHome,
|
|
PLUGIN_DATA: pluginData
|
|
};
|
|
delete env.CLAUDE_PLUGIN_ROOT;
|
|
if (pluginRoot) {
|
|
env.PLUGIN_ROOT = pluginRoot;
|
|
} else {
|
|
delete env.PLUGIN_ROOT;
|
|
}
|
|
|
|
const input = JSON.stringify({
|
|
session_id: 'codex-native-hook-test',
|
|
transcript_path: path.join(fixtureRoot, 'transcript.jsonl'),
|
|
cwd: projectDir,
|
|
hook_event_name: 'SessionStart',
|
|
source: 'startup'
|
|
});
|
|
|
|
try {
|
|
return spawnSync(sessionStart.command, {
|
|
cwd: projectDir,
|
|
env,
|
|
input,
|
|
encoding: 'utf8',
|
|
shell: true,
|
|
timeout: 15_000
|
|
});
|
|
} finally {
|
|
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
test('installed Codex SessionStart hook resolves from PLUGIN_ROOT and emits Codex output', () => {
|
|
const result = runSessionStart({ pluginRoot: repoRoot });
|
|
assert.strictEqual(result.status, 0, result.stderr || result.error?.message);
|
|
const output = JSON.parse(result.stdout);
|
|
assert.strictEqual(output.hookSpecificOutput.hookEventName, 'SessionStart');
|
|
assert.strictEqual(typeof output.hookSpecificOutput.additionalContext, 'string');
|
|
});
|
|
|
|
test('Codex SessionStart hook fails closed when PLUGIN_ROOT is absent', () => {
|
|
const result = runSessionStart({ pluginRoot: null });
|
|
assert.notStrictEqual(result.status, 0, 'Hook must not fall through to a stale ~/.claude plugin');
|
|
assert.match(result.stderr, /Missing Codex PLUGIN_ROOT/);
|
|
});
|
|
|
|
console.log(`\nPassed: ${passed}`);
|
|
console.log(`Failed: ${failed}`);
|
|
process.exit(failed > 0 ? 1 : 0);
|