fix: pass room role to Codex MCP tools (#185)
This commit is contained in:
@@ -118,6 +118,21 @@ function writeSkill(dir: string, name: string): void {
|
||||
);
|
||||
}
|
||||
|
||||
function resetRoutingMocks(): void {
|
||||
vi.mocked(config.isReviewService).mockReturnValue(false);
|
||||
vi.mocked(serviceRouting.hasReviewerLease).mockReturnValue(false);
|
||||
vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({
|
||||
chat_jid: 'dc:test',
|
||||
owner_service_id: 'claude',
|
||||
reviewer_service_id: 'codex-main',
|
||||
arbiter_service_id: null,
|
||||
owner_failover_active: false,
|
||||
activated_at: null,
|
||||
reason: null,
|
||||
explicit: false,
|
||||
});
|
||||
}
|
||||
|
||||
describe('prepareGroupEnvironment codex auth handling', () => {
|
||||
let tempRoot: string;
|
||||
let previousCwd: string;
|
||||
@@ -380,6 +395,79 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepareGroupEnvironment Codex MCP room role env', () => {
|
||||
let tempRoot: string;
|
||||
let previousCwd: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tempRoot = fs.mkdtempSync(path.join('/tmp', 'ejclaw-agent-env-'));
|
||||
previousCwd = process.cwd();
|
||||
process.chdir(tempRoot);
|
||||
|
||||
process.env.EJ_TEST_ROOT = tempRoot;
|
||||
process.env.EJ_TEST_HOME = path.join(tempRoot, 'home');
|
||||
fs.mkdirSync(process.env.EJ_TEST_HOME, { recursive: true });
|
||||
|
||||
mockReadEnvFile.mockReset();
|
||||
mockGetActiveCodexAuthPath.mockReset();
|
||||
resetRoutingMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.chdir(previousCwd);
|
||||
delete process.env.EJ_TEST_ROOT;
|
||||
delete process.env.EJ_TEST_HOME;
|
||||
fs.rmSync(tempRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
function writeMcpServer(): void {
|
||||
const mcpServerPath = path.join(
|
||||
tempRoot,
|
||||
'runners',
|
||||
'agent-runner',
|
||||
'dist',
|
||||
'ipc-mcp-stdio.js',
|
||||
);
|
||||
fs.mkdirSync(path.dirname(mcpServerPath), { recursive: true });
|
||||
fs.writeFileSync(mcpServerPath, '// test mcp server\n');
|
||||
}
|
||||
|
||||
function readCodexConfigToml(): string {
|
||||
return fs.readFileSync(
|
||||
path.join(
|
||||
tempRoot,
|
||||
'sessions',
|
||||
group.folder,
|
||||
'services',
|
||||
'codex-main',
|
||||
'.codex',
|
||||
'config.toml',
|
||||
),
|
||||
'utf-8',
|
||||
);
|
||||
}
|
||||
|
||||
it('writes paired owner role into the Codex MCP config env', () => {
|
||||
mockReadEnvFile.mockReturnValue({});
|
||||
writeMcpServer();
|
||||
|
||||
prepareGroupEnvironment(group, false, 'dc:test', {
|
||||
roomRole: 'owner',
|
||||
});
|
||||
|
||||
expect(readCodexConfigToml()).toContain('EJCLAW_ROOM_ROLE = "owner"');
|
||||
});
|
||||
|
||||
it('omits room role from non-paired Codex MCP config env', () => {
|
||||
mockReadEnvFile.mockReturnValue({});
|
||||
writeMcpServer();
|
||||
|
||||
prepareGroupEnvironment(group, true, 'dc:test');
|
||||
|
||||
expect(readCodexConfigToml()).not.toContain('EJCLAW_ROOM_ROLE');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepareGroupEnvironment room skill overrides', () => {
|
||||
let tempRoot: string;
|
||||
let previousCwd: string;
|
||||
@@ -694,6 +782,7 @@ args = ["other.js"]
|
||||
expect(toml).toContain('[mcp_servers.ejclaw]');
|
||||
expect(toml).toContain('EJCLAW_IPC_DIR = "/workspace/ipc"');
|
||||
expect(toml).toContain('EJCLAW_GROUP_FOLDER = "codex-test-group"');
|
||||
expect(toml).toContain('EJCLAW_ROOM_ROLE = "reviewer"');
|
||||
expect(toml).toContain('EJCLAW_WORK_DIR = "/workspace/project"');
|
||||
expect(toml).not.toContain('old-ipc.js');
|
||||
expect(toml).not.toContain('"/old/ipc"');
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
getEffectiveChannelLease,
|
||||
hasReviewerLease,
|
||||
} from './service-routing.js';
|
||||
import type { AgentType, RegisteredGroup } from './types.js';
|
||||
import type { AgentType, PairedRoomRole, RegisteredGroup } from './types.js';
|
||||
import type { StoredRoomSkillOverride } from './db/rooms.js';
|
||||
|
||||
// writeCodexApiKeyAuth removed — Codex uses OAuth only.
|
||||
@@ -173,6 +173,7 @@ function upsertEjclawMcpServerSection(args: {
|
||||
groupFolder: string;
|
||||
isMain: boolean;
|
||||
agentType: AgentType;
|
||||
roomRole?: PairedRoomRole;
|
||||
workDir?: string;
|
||||
}): void {
|
||||
const stripEjclawMcpServerSections = (input: string): string => {
|
||||
@@ -221,6 +222,7 @@ EJCLAW_CHAT_JID = ${JSON.stringify(args.chatJid)}
|
||||
EJCLAW_GROUP_FOLDER = ${JSON.stringify(args.groupFolder)}
|
||||
EJCLAW_IS_MAIN = ${JSON.stringify(args.isMain ? '1' : '0')}
|
||||
EJCLAW_AGENT_TYPE = ${JSON.stringify(args.agentType)}
|
||||
${args.roomRole ? `EJCLAW_ROOM_ROLE = ${JSON.stringify(args.roomRole)}\n` : ''}
|
||||
${args.workDir ? `EJCLAW_WORK_DIR = ${JSON.stringify(args.workDir)}\n` : ''}
|
||||
`;
|
||||
fs.writeFileSync(args.sessionConfigPath, toml.trimEnd() + '\n' + mcpSection);
|
||||
@@ -347,6 +349,7 @@ function prepareCodexSessionEnvironment(args: {
|
||||
sessionRootDir: string;
|
||||
chatJid: string;
|
||||
isMain: boolean;
|
||||
roomRole?: PairedRoomRole;
|
||||
isPairedRoom: boolean;
|
||||
useFailoverPromptPack: boolean;
|
||||
memoryBriefing?: string;
|
||||
@@ -489,6 +492,7 @@ function prepareCodexSessionEnvironment(args: {
|
||||
groupFolder: args.group.folder,
|
||||
isMain: args.isMain,
|
||||
agentType: 'codex',
|
||||
roomRole: args.roomRole,
|
||||
workDir:
|
||||
args.env.EJCLAW_WORK_DIR || args.group.workDir || args.projectRoot,
|
||||
});
|
||||
@@ -520,6 +524,7 @@ export function prepareGroupEnvironment(
|
||||
runtimeTaskId?: string;
|
||||
useTaskScopedSession?: boolean;
|
||||
skillOverrides?: StoredRoomSkillOverride[];
|
||||
roomRole?: PairedRoomRole;
|
||||
},
|
||||
): PreparedGroupEnvironment {
|
||||
const projectRoot = process.cwd();
|
||||
@@ -659,6 +664,7 @@ export function prepareGroupEnvironment(
|
||||
sessionRootDir,
|
||||
chatJid,
|
||||
isMain,
|
||||
roomRole: options?.roomRole,
|
||||
isPairedRoom,
|
||||
useFailoverPromptPack: useCodexReviewFailoverPromptPack,
|
||||
memoryBriefing: options?.memoryBriefing,
|
||||
@@ -799,6 +805,7 @@ export function prepareReadonlySessionEnvironment(args: {
|
||||
groupFolder,
|
||||
isMain,
|
||||
agentType,
|
||||
roomRole: role,
|
||||
workDir,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ export async function runAgentProcess(
|
||||
runtimeTaskId: input.runtimeTaskId,
|
||||
useTaskScopedSession: input.useTaskScopedSession,
|
||||
skillOverrides,
|
||||
roomRole: input.roomRoleContext?.role,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user