fix: prepare CLAUDE.md and roomRoleContext for container reviewer

Container reviewer was running without prompts because the container
path in agent-runner.ts skipped prepareGroupEnvironment() entirely.
This meant no CLAUDE.md (platform + paired room prompts + memory
briefing) and no roomRoleContext were passed to the container.

- Add prepareContainerSessionEnvironment() to write CLAUDE.md, sync
  skills, and ensure settings.json for the reviewer session directory
- Pass roomRoleContext through ReviewerContainerInput so the runner
  can prepend the [ROOM_ROLE] header
- Add roomRoleContext field to ReviewerContainerInput interface
This commit is contained in:
Eyejoker
2026-03-30 01:12:47 +09:00
parent cb66510378
commit d024b763f0
3 changed files with 76 additions and 1 deletions

View File

@@ -525,3 +525,60 @@ export function prepareGroupEnvironment(
return { env, groupDir, runnerDir }; return { env, groupDir, runnerDir };
} }
/**
* Prepare the Claude session directory for a container-based reviewer.
*
* Writes CLAUDE.md (platform + paired room prompts + global memory + briefing),
* syncs skills, and ensures settings.json exist — the same steps that
* `prepareGroupEnvironment` does for host-mode agents, but targeted at an
* externally provided session directory (the one mounted into the container).
*/
export function prepareContainerSessionEnvironment(args: {
sessionDir: string;
chatJid: string;
isMain: boolean;
memoryBriefing?: string;
}): void {
const { sessionDir, chatJid, isMain, memoryBriefing } = args;
const projectRoot = process.cwd();
fs.mkdirSync(sessionDir, { recursive: true });
ensureClaudeSessionSettings(sessionDir);
// Sync skills from host
const skillSources = [
path.join(os.homedir(), '.claude', 'skills'),
path.join(projectRoot, 'runners', 'skills'),
];
syncDirectoryEntries(skillSources, path.join(sessionDir, 'skills'));
// Build CLAUDE.md with reviewer-appropriate prompts
const claudePlatformPrompt = readPlatformPrompt('claude-code', projectRoot);
const claudePairedRoomPrompt = isPairedRoomJid(chatJid)
? readPairedRoomPrompt('claude-code', projectRoot)
: undefined;
const globalDir = path.join(GROUPS_DIR, 'global');
const globalClaudeMdPath = path.join(globalDir, 'CLAUDE.md');
const globalClaudeMemory =
!isMain && fs.existsSync(globalClaudeMdPath)
? fs.readFileSync(globalClaudeMdPath, 'utf-8').trim()
: undefined;
const sessionClaudeMd = [
claudePlatformPrompt,
claudePairedRoomPrompt,
globalClaudeMemory,
memoryBriefing,
]
.filter((value): value is string => Boolean(value))
.join('\n\n---\n\n')
.trim();
const sessionClaudeMdPath = path.join(sessionDir, 'CLAUDE.md');
if (sessionClaudeMd) {
fs.writeFileSync(sessionClaudeMdPath, sessionClaudeMd + '\n');
} else if (fs.existsSync(sessionClaudeMdPath)) {
fs.unlinkSync(sessionClaudeMdPath);
}
}

View File

@@ -12,7 +12,10 @@ import {
AGENT_TIMEOUT, AGENT_TIMEOUT,
IDLE_TIMEOUT, IDLE_TIMEOUT,
} from './config.js'; } from './config.js';
import { prepareGroupEnvironment } from './agent-runner-environment.js'; import {
prepareContainerSessionEnvironment,
prepareGroupEnvironment,
} from './agent-runner-environment.js';
import { getEnv } from './env.js'; import { getEnv } from './env.js';
export { export {
type AvailableGroup, type AvailableGroup,
@@ -75,6 +78,19 @@ export async function runAgentProcess(
if (envOverrides?.EJCLAW_REVIEWER_RUNTIME === '1') { if (envOverrides?.EJCLAW_REVIEWER_RUNTIME === '1') {
const ownerWorkspaceDir = const ownerWorkspaceDir =
envOverrides?.EJCLAW_WORK_DIR || group.workDir || process.cwd(); envOverrides?.EJCLAW_WORK_DIR || group.workDir || process.cwd();
// Prepare session directory for the container (CLAUDE.md, skills, settings)
// so the Claude SDK inside the container has platform & paired room prompts.
const sessionDir = envOverrides?.CLAUDE_CONFIG_DIR;
if (sessionDir) {
prepareContainerSessionEnvironment({
sessionDir,
chatJid: input.chatJid,
isMain: input.isMain,
memoryBriefing: input.memoryBriefing,
});
}
return runReviewerContainer({ return runReviewerContainer({
group, group,
input: { input: {
@@ -85,6 +101,7 @@ export async function runAgentProcess(
runId: input.runId || `${Date.now()}`, runId: input.runId || `${Date.now()}`,
isMain: input.isMain, isMain: input.isMain,
assistantName: input.assistantName, assistantName: input.assistantName,
roomRoleContext: input.roomRoleContext,
}, },
ownerWorkspaceDir, ownerWorkspaceDir,
envOverrides, envOverrides,

View File

@@ -58,6 +58,7 @@ export interface ReviewerContainerInput {
runId: string; runId: string;
isMain: boolean; isMain: boolean;
assistantName?: string; assistantName?: string;
roomRoleContext?: import('./types.js').RoomRoleContext;
} }
interface VolumeMount { interface VolumeMount {