Add native Codex hooks integration (#2319)
* Add native Codex hooks integration * Address Codex review feedback * Use durable Codex marketplace root * Address Codex file context review feedback * Harden Codex installer review paths * Report Codex legacy cleanup failures * fix: keep MCP manifests in marketplace sync * fix: bundle zod in MCP server * fix: warn on Codex legacy cleanup failure * Fix hook observation readiness timeouts * Address Codex hook review notes * Tighten Codex MCP file context matching * Resolve final Codex review nits * Add Codex marketplace version guidance * Reset worker failure counter on API fallback * Fix Codex cat flag file extraction
This commit is contained in:
@@ -11,6 +11,22 @@ const installSourcePath = join(
|
||||
'install.ts',
|
||||
);
|
||||
const installSource = readFileSync(installSourcePath, 'utf-8');
|
||||
const codexInstallerSourcePath = join(
|
||||
__dirname,
|
||||
'..',
|
||||
'src',
|
||||
'services',
|
||||
'integrations',
|
||||
'CodexCliInstaller.ts',
|
||||
);
|
||||
const codexInstallerSource = readFileSync(codexInstallerSourcePath, 'utf-8');
|
||||
const syncMarketplaceSourcePath = join(
|
||||
__dirname,
|
||||
'..',
|
||||
'scripts',
|
||||
'sync-marketplace.cjs',
|
||||
);
|
||||
const syncMarketplaceSource = readFileSync(syncMarketplaceSourcePath, 'utf-8');
|
||||
|
||||
describe('Install Non-TTY Support', () => {
|
||||
describe('isInteractive flag', () => {
|
||||
@@ -76,6 +92,76 @@ describe('Install Non-TTY Support', () => {
|
||||
it('uses console.log for note/summary in non-interactive mode', () => {
|
||||
expect(installSource).toContain("console.log(`\\n ${installStatus}`)");
|
||||
});
|
||||
|
||||
it('copies Codex marketplace metadata to the durable marketplace directory', () => {
|
||||
const copyRegion = installSource.slice(
|
||||
installSource.indexOf('const allowedTopLevelEntries = ['),
|
||||
installSource.indexOf('function copyPluginToCache'),
|
||||
);
|
||||
expect(copyRegion).toContain("'.agents'");
|
||||
expect(copyRegion).toContain("'.codex-plugin'");
|
||||
expect(copyRegion).toContain("'.mcp.json'");
|
||||
});
|
||||
|
||||
it('does not exclude MCP manifests during local marketplace sync', () => {
|
||||
const gitignoreExcludeRegion = syncMarketplaceSource.slice(
|
||||
syncMarketplaceSource.indexOf('function getGitignoreExcludes'),
|
||||
syncMarketplaceSource.indexOf('const branch = getCurrentBranch'),
|
||||
);
|
||||
expect(gitignoreExcludeRegion).toContain("'.mcp.json'");
|
||||
expect(gitignoreExcludeRegion).toContain('syncManagedFiles.has(line)');
|
||||
});
|
||||
|
||||
it('registers Codex against the durable marketplace directory', () => {
|
||||
expect(installSource).toContain('installCodexCli(marketplaceDirectory())');
|
||||
});
|
||||
|
||||
it('captures Codex CLI output for install failure reporting', () => {
|
||||
const runCodexRegion = codexInstallerSource.slice(
|
||||
codexInstallerSource.indexOf('function runCodex'),
|
||||
codexInstallerSource.indexOf('function removeCodexAgentsMdContext'),
|
||||
);
|
||||
expect(runCodexRegion).toContain('spawnSync');
|
||||
expect(runCodexRegion).not.toContain("stdio: 'inherit'");
|
||||
});
|
||||
|
||||
it('checks Codex CLI marketplace version before registration', () => {
|
||||
const installRegion = codexInstallerSource.slice(
|
||||
codexInstallerSource.indexOf('export async function installCodexCli'),
|
||||
codexInstallerSource.indexOf('export function uninstallCodexCli'),
|
||||
);
|
||||
expect(codexInstallerSource).toContain("const MIN_CODEX_MARKETPLACE_VERSION = '0.128.0'");
|
||||
expect(codexInstallerSource).toContain("spawnSync('codex', ['--version']");
|
||||
expect(installRegion.indexOf('assertCodexMarketplaceSupported()'))
|
||||
.toBeLessThan(installRegion.indexOf("runCodex(['plugin', 'marketplace', 'add', marketplaceRoot])"));
|
||||
});
|
||||
|
||||
it('removes legacy Codex AGENTS context only after marketplace registration succeeds', () => {
|
||||
const installRegion = codexInstallerSource.slice(
|
||||
codexInstallerSource.indexOf('export async function installCodexCli'),
|
||||
codexInstallerSource.indexOf('export function uninstallCodexCli'),
|
||||
);
|
||||
expect(installRegion.indexOf("runCodex(['plugin', 'marketplace', 'add', marketplaceRoot])"))
|
||||
.toBeLessThan(installRegion.indexOf('cleanupLegacyCodexAgentsMdContext()'));
|
||||
});
|
||||
|
||||
it('reports legacy Codex AGENTS cleanup failures to callers', () => {
|
||||
expect(codexInstallerSource).toContain('function removeCodexAgentsMdContext(): boolean');
|
||||
expect(codexInstallerSource).toContain('if (!cleanupLegacyCodexAgentsMdContext())');
|
||||
});
|
||||
|
||||
it('does not fail Codex install after marketplace registration when only AGENTS cleanup fails', () => {
|
||||
const installRegion = codexInstallerSource.slice(
|
||||
codexInstallerSource.indexOf('export async function installCodexCli'),
|
||||
codexInstallerSource.indexOf('export function uninstallCodexCli'),
|
||||
);
|
||||
const cleanupFailureRegion = installRegion.slice(
|
||||
installRegion.indexOf('if (!cleanupLegacyCodexAgentsMdContext())'),
|
||||
installRegion.indexOf('Installation complete!'),
|
||||
);
|
||||
expect(cleanupFailureRegion).toContain('console.warn');
|
||||
expect(cleanupFailureRegion).not.toContain('return 1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('TaskDescriptor interface', () => {
|
||||
|
||||
Reference in New Issue
Block a user