feat(#2088): migrate Codex onto the Embeddable Orchestration System (ADR-1239)

Drive Codex install/uninstall through the descriptor-driven Host-Integration
Interface (declarative embedding adapter → engine surface dispatch) and fold
every positive `runtime === 'codex'` / `isCodex` projection into descriptor-driven
`runtime.hostBehaviors`. Install/uninstall output stays byte-parity-gated
(tests/fixtures/golden-install-parity/codex.json); no other runtime changes.

Three Context7-verified upgrades, each with a test on the user-reachable surface:
- Skill root → canonical $HOME/.agents/skills via a skills-kind `home` override,
  with pre-move migration cleanup (stale ~/.codex/skills/gsd-* removed on install
  and uninstall; user content preserved). Fixes getGlobalSkillsBase, writeManifest,
  and the skill-manifest inventory to honor the override so --skills-root /
  sync-skills / the manifest report the real location.
- Six new hooks.json lifecycle events (PreToolUse, PermissionRequest, PreCompact,
  PostCompact, SubagentStop, UserPromptSubmit) shared by install + uninstall;
  extendedHookEvents reconciled [] -> the schema-valid wired subset.
- Explicit `[agents] max_depth = 1` in the managed config.toml block, pinning the
  negotiated dispatch.maxDepth:1 axis. validateCodexConfigSchema now permits a
  known-scalar-only bare `[agents]` AgentsToml table (still rejects [[agents]] and
  unknown-key break-forms, #2760); mergeCodexConfig preserves the user's own
  AgentsToml scalars (max_threads etc.) instead of dropping them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-08 21:42:11 -04:00
parent e5a1d7f5c4
commit 6e773d97df
24 changed files with 1252 additions and 211 deletions

View File

@@ -325,11 +325,14 @@ describe('generate-dev-preferences command', () => {
const result = runGsdTools(
['generate-dev-preferences', '--analysis', analysisPath, '--raw'],
tmpDir,
{ CODEX_HOME: codexHome, GSD_RUNTIME: 'codex' }
// #2088 (ADR-1239 upgrade 3): Codex skills resolve to $HOME/.agents/skills
// (HOME-relative), so sandbox HOME to keep the dev-preferences write inside
// the temp dir rather than the developer's real ~/.agents/skills.
{ CODEX_HOME: codexHome, GSD_RUNTIME: 'codex', HOME: codexHome, USERPROFILE: codexHome }
);
assert.ok(result.success, `Failed: ${result.error}`);
const out = JSON.parse(result.output);
assert.strictEqual(out.command_path, path.join(codexHome, 'skills', 'gsd-dev-preferences', 'SKILL.md'));
assert.strictEqual(out.command_path, path.join(codexHome, '.agents', 'skills', 'gsd-dev-preferences', 'SKILL.md'));
assert.ok(fs.existsSync(out.command_path), 'runtime-aware output should be written');
});
@@ -347,11 +350,12 @@ describe('generate-dev-preferences command', () => {
const result = runGsdTools(
['generate-dev-preferences', '--analysis', analysisPath, '--raw'],
tmpDir,
{ CODEX_HOME: codexHome, GSD_RUNTIME: 'codex-app' }
// #2088: codex-app alias canonicalizes to codex → $HOME/.agents/skills.
{ CODEX_HOME: codexHome, GSD_RUNTIME: 'codex-app', HOME: codexHome, USERPROFILE: codexHome }
);
assert.ok(result.success, `Failed: ${result.error}`);
const out = JSON.parse(result.output);
assert.strictEqual(out.command_path, path.join(codexHome, 'skills', 'gsd-dev-preferences', 'SKILL.md'));
assert.strictEqual(out.command_path, path.join(codexHome, '.agents', 'skills', 'gsd-dev-preferences', 'SKILL.md'));
});
test('uses runtime-aware skills dir for cline by default (#782)', () => {