fix: pass actual chat JID to agent runner instead of group folder

watch_ci tasks in perf channel were silently failing because
NANOCLAW_CHAT_JID was set to the group folder name (e.g. "eyejokerdb-4")
instead of the actual Discord JID. The scheduler rejected the task with
"target group not registered".

Also adds a fallback in ipc.ts to resolve folder names to registered
JIDs when a folder name is passed instead of a JID.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eyejoker
2026-03-21 14:27:00 +09:00
parent 2c8260135f
commit dd15585941
4 changed files with 88 additions and 4 deletions

View File

@@ -1,6 +1,8 @@
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { EventEmitter } from 'events';
import { PassThrough } from 'stream';
import fs from 'fs';
import { spawn } from 'child_process';
// Sentinel markers must match agent-runner.ts
const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---';
@@ -253,6 +255,50 @@ describe('agent-runner timeout behavior', () => {
);
});
it('passes the actual chat JID into codex runner MCP env', async () => {
vi.useRealTimers();
fakeProc = createFakeProcess();
vi.mocked(fs.existsSync).mockImplementation((p: fs.PathLike) => {
const str = String(p);
return (
str.includes('dist/index.js') ||
str.includes('dist/ipc-mcp-stdio.js') ||
str.endsWith('/.codex/config.toml')
);
});
const codexGroup: RegisteredGroup = {
...testGroup,
agentType: 'codex',
};
const resultPromise = runAgentProcess(
codexGroup,
testInput,
() => {},
async () => {},
);
fakeProc.emit('close', 0);
const result = await resultPromise;
expect(result.status).toBe('success');
const spawnEnv = vi.mocked(spawn).mock.calls[0]?.[2]?.env as
| Record<string, string>
| undefined;
expect(spawnEnv?.NANOCLAW_CHAT_JID).toBe(testInput.chatJid);
const tomlWrite = vi
.mocked(fs.writeFileSync)
.mock.calls.find((call) =>
String(call[0]).endsWith('/.codex/config.toml'),
);
expect(String(tomlWrite?.[1])).toContain(
`NANOCLAW_CHAT_JID = ${JSON.stringify(testInput.chatJid)}`,
);
});
it('waits for queued streamed output before resolving an error exit', async () => {
let releaseOutputs: (() => void) | undefined;
const outputsFlushed = new Promise<void>((resolve) => {