merge: integrate origin/main (406 commits) into live branch

Merge upstream's paired-room stabilization, dedicated message-runtime-loop,
outbound delivery refactor (ipc-outbound-delivery / deliverFormattedCanonicalMessage),
discord module split, dashboard rework, and migrations 015-018 into our branch.

Conflict policy: prefer upstream for the heavily-refactored paired-room /
message-runtime / db cluster (it supersedes our earlier loop band-aids), keep
only orthogonal unique fixes:
- codex bundled-JS launcher fix (codex-warmup.ts)
- slot-aligned Claude+Codex usage primer (usage-primer.ts) re-wired into index.ts
- MemoryHigh=3G cgroup bound, discord perms diagnostic, prompt docs
- progress null-race + silent-failure publish guards (message-turn-controller.ts)

Dropped (superseded by upstream or unwired): reviewer STEP_DONE/TASK_DONE loop
band-aids, router markdown-escape override, register tribunal-default+git-init,
restart-context rewindToSeq (unwired).

Verified: typecheck clean, build clean, vitest shows zero new regressions vs the
origin/main baseline (only pre-existing env-config failures remain).
This commit is contained in:
Codex
2026-06-08 21:15:39 +09:00
409 changed files with 53523 additions and 10332 deletions

View File

@@ -22,6 +22,11 @@ interface RunSpawnedAgentProcessArgs {
logsDir: string;
startTime: number;
onOutput?: (output: AgentOutput) => Promise<void>;
onTerminalStreamedOutputFlushed?: (output: AgentOutput) => void;
}
function isTerminalStreamedOutput(output: AgentOutput): boolean {
return (output.phase ?? 'final') !== 'progress';
}
function parseLegacyAgentOutput(stdout: string): AgentOutput {
@@ -39,6 +44,88 @@ function parseLegacyAgentOutput(stdout: string): AgentOutput {
return JSON.parse(jsonLine) as AgentOutput;
}
function logStreamedOutputDeliveryError(
err: unknown,
group: RegisteredGroup,
input: AgentInput,
): void {
logger.warn(
{
group: group.name,
chatJid: input.chatJid,
runId: input.runId,
error: getErrorMessage(err),
},
'Streamed agent output delivery failed',
);
}
function logStreamedAgentErrorOutput(
output: AgentOutput,
group: RegisteredGroup,
input: AgentInput,
): void {
if (output.status !== 'error') return;
logger.warn(
{
group: group.name,
chatJid: input.chatJid,
runId: input.runId,
error: output.error,
newSessionId: output.newSessionId,
},
'Streamed agent error output',
);
}
function chainStreamedOutputDelivery(args: {
outputChain: Promise<void>;
parsed: AgentOutput;
onOutput: (output: AgentOutput) => Promise<void>;
onTerminalStreamedOutputFlushed?: (output: AgentOutput) => void;
group: RegisteredGroup;
input: AgentInput;
}): Promise<void> {
return args.outputChain.then(async () => {
try {
await args.onOutput(args.parsed);
if (isTerminalStreamedOutput(args.parsed)) {
args.onTerminalStreamedOutputFlushed?.(args.parsed);
}
} catch (err) {
logStreamedOutputDeliveryError(err, args.group, args.input);
}
});
}
function writeTimeoutLog(args: {
logsDir: string;
input: AgentInput;
group: RegisteredGroup;
processName: string;
duration: number;
code: number | null;
signal: NodeJS.Signals | null;
hadStreamingOutput: boolean;
}): void {
const ts = new Date().toISOString().replace(/[:.]/g, '-');
fs.writeFileSync(
path.join(args.logsDir, `agent-${args.input.runId || 'adhoc'}-${ts}.log`),
[
`=== Agent Run Log (TIMEOUT) ===`,
`Timestamp: ${new Date().toISOString()}`,
`Group: ${args.group.name}`,
`ChatJid: ${args.input.chatJid}`,
`RunId: ${args.input.runId || 'n/a'}`,
`Process: ${args.processName}`,
`Duration: ${args.duration}ms`,
`Exit Code: ${args.code}`,
`Signal: ${args.signal}`,
`Had Streaming Output: ${args.hadStreamingOutput}`,
].join('\n'),
);
}
export function runSpawnedAgentProcess(
args: RunSpawnedAgentProcessArgs,
): Promise<AgentOutput> {
@@ -144,19 +231,16 @@ export function runSpawnedAgentProcess(
}
hadStreamingOutput = true;
resetTimeout();
if (parsed.status === 'error') {
logger.warn(
{
group: group.name,
chatJid: input.chatJid,
runId: input.runId,
error: parsed.error,
newSessionId: parsed.newSessionId,
},
'Streamed agent error output',
);
}
outputChain = outputChain.then(() => onOutput(parsed));
logStreamedAgentErrorOutput(parsed, group, input);
outputChain = chainStreamedOutputDelivery({
outputChain,
parsed,
onOutput,
onTerminalStreamedOutputFlushed:
args.onTerminalStreamedOutputFlushed,
group,
input,
});
} catch (err) {
logger.warn(
{
@@ -215,22 +299,16 @@ export function runSpawnedAgentProcess(
const duration = Date.now() - startTime;
if (timedOut) {
const ts = new Date().toISOString().replace(/[:.]/g, '-');
fs.writeFileSync(
path.join(logsDir, `agent-${input.runId || 'adhoc'}-${ts}.log`),
[
`=== Agent Run Log (TIMEOUT) ===`,
`Timestamp: ${new Date().toISOString()}`,
`Group: ${group.name}`,
`ChatJid: ${input.chatJid}`,
`RunId: ${input.runId || 'n/a'}`,
`Process: ${processName}`,
`Duration: ${duration}ms`,
`Exit Code: ${code}`,
`Signal: ${signal}`,
`Had Streaming Output: ${hadStreamingOutput}`,
].join('\n'),
);
writeTimeoutLog({
logsDir,
input,
group,
processName,
duration,
code,
signal,
hadStreamingOutput,
});
if (hadStreamingOutput) {
logger.info(