* fix(#2602): discover project-local Codex agents - Select an existing local Codex agents directory before global fallback - Prove init reports the canonical local installation through compiled CJS * test(#2602): lock Codex agent precedence - Cover override, local authority, global fallback, and runtime compatibility - Exercise installed state through the compiled resolver * fix(#2602): resolve local Codex agent skills - Pass the canonical project root to the non-Claude persona fallback - Cover nested-Codex fallback and Claude compatibility through the CLI * test(#2602): cover local Codex validation status - Assert emitted validate and health commands use the project-local install - Preserve empty local-directory authority beside complete global agents * fix(#2602): align validation with local Codex discovery - Pass the resolved runtime and project root to health W010 - Resolve the validate-agents runtime before checking installation status * test(#2602): cover local Codex docs status - Assert docs-init reports an authoritative empty local install as unhealthy * fix(#2602): align docs with local Codex discovery - Pass the resolved runtime and canonical project root to the shared agent checker * fix(#2602): honor agent-skills runtime override - Resolve agent-skills fallback runtime through the canonical project resolver - Cover conflicting config and GSD_RUNTIME values through the emitted CLI * fix(#2602): ignore non-directory local agents paths - Treat only a local Codex agents directory as authoritative - Cover regular-file fallback through the emitted install checker * chore(#2602): add changelog fragment - record the user-visible local Codex agent discovery fix for PR #2623 * fix(#2602): align local agent discovery with runtime policy - Resolve Codex's local config directory through the canonical runtime policy - Use test-managed cleanup for local-agent discovery coverage * fix(#2602): discover local agents across runtimes - Prefer manifest-backed project-local installs for non-Claude runtimes - Respect runtime-specific local install roots and preserve global fallback behavior - Cover native, partial, cross-runtime, and project-root local discovery * fix(#2602): preserve agent discovery fallback - Fall back globally when local-install probes fail - Document and test symlink rejection - Align the changeset with repository format * fix(#2602): reuse local directory policy - Resolve runtimes without local config through the canonical sentinel - Document the manifest gate and refresh the context index --------- Co-authored-by: Daniel E. <daniel.e@teachingstrategies.com> Co-authored-by: Rezolv <dave@sienkowski.com>
This commit is contained in:
committed by
GitHub
parent
7b204ad2ac
commit
f0ff23635e
@@ -42,6 +42,23 @@ function _createAgentsDir(configDir, agentNames = []) {
|
||||
return agentsDir;
|
||||
}
|
||||
|
||||
function createCompleteCodexAgents(configDir) {
|
||||
const agentsDir = path.join(configDir, '.codex', AGENTS_DIR_NAME);
|
||||
fs.mkdirSync(agentsDir, { recursive: true });
|
||||
const files = {};
|
||||
for (const name of EXPECTED_AGENTS) {
|
||||
fs.writeFileSync(path.join(agentsDir, `${name}.md`), `# ${name}\n`);
|
||||
fs.writeFileSync(path.join(agentsDir, `${name}.toml`), `name = "${name}"\n`);
|
||||
files[`agents/${name}.md`] = {};
|
||||
files[`agents/${name}.toml`] = {};
|
||||
}
|
||||
fs.writeFileSync(
|
||||
path.join(configDir, '.codex', 'gsd-file-manifest.json'),
|
||||
JSON.stringify({ files }),
|
||||
);
|
||||
return agentsDir;
|
||||
}
|
||||
|
||||
// ─── Init command agent validation ──────────────────────────────────────────
|
||||
|
||||
describe('init commands: agents_installed field (#1371)', () => {
|
||||
@@ -92,6 +109,30 @@ describe('init commands: agents_installed field (#1371)', () => {
|
||||
assert.strictEqual(output.agents_installed, true);
|
||||
});
|
||||
|
||||
test('init plan-phase reports the complete project-local Codex installation', () => {
|
||||
const phaseDir = path.join(tmpDir, '.planning', 'phases', '01-setup');
|
||||
const globalHome = path.join(tmpDir, 'global-codex');
|
||||
fs.mkdirSync(phaseDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'config.json'),
|
||||
JSON.stringify({ runtime: 'codex' }),
|
||||
);
|
||||
createCompleteCodexAgents(tmpDir);
|
||||
const canonicalRoot = fs.realpathSync(tmpDir);
|
||||
const localAgentsDir = path.join(canonicalRoot, '.codex', AGENTS_DIR_NAME);
|
||||
_createAgentsDir(globalHome, EXPECTED_AGENTS);
|
||||
|
||||
const result = runGsdTools('init plan-phase 1 --raw', tmpDir, { CODEX_HOME: globalHome });
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.project_root, canonicalRoot);
|
||||
assert.strictEqual(output.agent_runtime, 'codex');
|
||||
assert.strictEqual(output.agents_dir, localAgentsDir);
|
||||
assert.strictEqual(output.agents_installed, true);
|
||||
assert.deepStrictEqual(output.missing_agents, []);
|
||||
});
|
||||
|
||||
test('init execute-phase includes missing_agents list when agents are missing', () => {
|
||||
const phaseDir = path.join(tmpDir, '.planning', 'phases', '01-setup');
|
||||
fs.mkdirSync(phaseDir, { recursive: true });
|
||||
@@ -162,6 +203,67 @@ describe('validate health: agent installation check W010 (#1371)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Codex project-local validation status ──────────────────────────────────
|
||||
|
||||
describe('Codex project-local validation status', () => {
|
||||
let tmpDir;
|
||||
let globalHome;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = createTempProject();
|
||||
globalHome = path.join(tmpDir, 'global-codex');
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'config.json'),
|
||||
JSON.stringify({ runtime: 'codex' }),
|
||||
);
|
||||
_createAgentsDir(globalHome, EXPECTED_AGENTS);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup(tmpDir);
|
||||
});
|
||||
|
||||
test('validate agents and health use a complete project-local Codex installation', () => {
|
||||
createCompleteCodexAgents(tmpDir);
|
||||
const localAgentsDir = path.join(fs.realpathSync(tmpDir), '.codex', AGENTS_DIR_NAME);
|
||||
const env = { CODEX_HOME: globalHome };
|
||||
|
||||
const validateResult = runGsdTools('validate agents --raw', tmpDir, env);
|
||||
assert.ok(validateResult.success, `validate agents failed: ${validateResult.error}`);
|
||||
const validateOutput = JSON.parse(validateResult.output);
|
||||
assert.strictEqual(validateOutput.agents_dir, localAgentsDir);
|
||||
assert.strictEqual(validateOutput.agents_found, true);
|
||||
assert.deepStrictEqual(validateOutput.missing, []);
|
||||
assert.deepStrictEqual(validateOutput.incomplete, []);
|
||||
|
||||
const healthResult = runGsdTools('validate health --raw', tmpDir, env);
|
||||
assert.ok(healthResult.success, `validate health failed: ${healthResult.error}`);
|
||||
const healthOutput = JSON.parse(healthResult.output);
|
||||
assert.ok(!(healthOutput.warnings || []).some(warning => warning.code === 'W010'));
|
||||
});
|
||||
|
||||
test('an empty project-local Codex directory remains authoritative for validate agents and health', () => {
|
||||
fs.mkdirSync(path.join(tmpDir, '.codex', AGENTS_DIR_NAME), { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpDir, '.codex', 'gsd-file-manifest.json'), JSON.stringify({ files: {} }));
|
||||
const localAgentsDir = path.join(fs.realpathSync(tmpDir), '.codex', AGENTS_DIR_NAME);
|
||||
const env = { CODEX_HOME: globalHome };
|
||||
|
||||
const validateResult = runGsdTools('validate agents --raw', tmpDir, env);
|
||||
assert.ok(validateResult.success, `validate agents failed: ${validateResult.error}`);
|
||||
const validateOutput = JSON.parse(validateResult.output);
|
||||
assert.strictEqual(validateOutput.agents_dir, localAgentsDir);
|
||||
assert.strictEqual(validateOutput.agents_found, false);
|
||||
assert.deepStrictEqual(validateOutput.installed, []);
|
||||
assert.deepStrictEqual(validateOutput.incomplete, []);
|
||||
assert.deepStrictEqual(validateOutput.missing, EXPECTED_AGENTS);
|
||||
|
||||
const healthResult = runGsdTools('validate health --raw', tmpDir, env);
|
||||
assert.ok(healthResult.success, `validate health failed: ${healthResult.error}`);
|
||||
const healthOutput = JSON.parse(healthResult.output);
|
||||
assert.ok((healthOutput.warnings || []).some(warning => warning.code === 'W010'));
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Copilot .agent.md detection (#1512) ────────────────────────────────────
|
||||
|
||||
describe('checkAgentsInstalled: Copilot .agent.md format (#1512)', () => {
|
||||
|
||||
Reference in New Issue
Block a user