refactor: dual-instance setup, remove dead container code

- Make STORE_DIR, DATA_DIR, GROUPS_DIR configurable via env vars
  (NANOCLAW_STORE_DIR, NANOCLAW_DATA_DIR, NANOCLAW_GROUPS_DIR)
  for running two instances from one codebase
- Remove broken 'both' agent type sequential loop from processGroupMessages
- Delete dead code: container-runtime, mount-security, credential-proxy,
  Dockerfiles, and related config constants (~1,085 lines removed)
- Add codex instance launchd plist template
This commit is contained in:
Eyejoker
2026-03-11 00:50:03 +09:00
parent 955a2901c8
commit 57cafc19f8
15 changed files with 84 additions and 1269 deletions

View File

@@ -239,81 +239,50 @@ async function processGroupMessages(chatJid: string): Promise<boolean> {
}, IDLE_TIMEOUT);
};
// Determine which agent types to run
const agentTypes: Array<'claude-code' | 'codex'> =
group.agentType === 'both'
? ['claude-code', 'codex']
: [group.agentType || 'claude-code'];
let hadError = false;
let outputSentToUser = false;
for (const agentType of agentTypes) {
// For 'both' groups, create a variant group with the specific agent type
// and a separate folder so each agent has its own session/workspace
const effectiveGroup: RegisteredGroup =
group.agentType === 'both'
? {
...group,
agentType,
folder: `${group.folder}_${agentType === 'claude-code' ? 'cc' : 'codex'}`,
}
: group;
await channel.setTyping?.(chatJid, true);
// Find the right channel to send responses through
const sendChannel =
group.agentType === 'both'
? channels.find(
(c) =>
c.name.includes('discord') &&
c.name.includes(
agentType === 'codex' ? 'codex' : 'claude-code',
),
) || channel
: channel;
await sendChannel.setTyping?.(chatJid, true);
const output = await runAgent(
effectiveGroup,
prompt,
chatJid,
async (result) => {
if (result.result) {
const raw =
typeof result.result === 'string'
? result.result
: JSON.stringify(result.result);
const text = raw
.replace(/<internal>[\s\S]*?<\/internal>/g, '')
.trim();
logger.info(
{ group: group.name, agentType },
`Agent output: ${raw.slice(0, 200)}`,
);
if (text) {
await sendChannel.sendMessage(chatJid, text);
outputSentToUser = true;
}
await sendChannel.setTyping?.(chatJid, false);
resetIdleTimer();
const output = await runAgent(
group,
prompt,
chatJid,
async (result) => {
if (result.result) {
const raw =
typeof result.result === 'string'
? result.result
: JSON.stringify(result.result);
const text = raw
.replace(/<internal>[\s\S]*?<\/internal>/g, '')
.trim();
logger.info(
{ group: group.name },
`Agent output: ${raw.slice(0, 200)}`,
);
if (text) {
await channel.sendMessage(chatJid, text);
outputSentToUser = true;
}
await channel.setTyping?.(chatJid, false);
resetIdleTimer();
}
if (result.status === 'success') {
queue.notifyIdle(chatJid);
}
if (result.status === 'success') {
queue.notifyIdle(chatJid);
}
if (result.status === 'error') {
hadError = true;
}
},
);
if (result.status === 'error') {
hadError = true;
}
},
);
await sendChannel.setTyping?.(chatJid, false);
await channel.setTyping?.(chatJid, false);
if (output === 'error') {
hadError = true;
}
if (output === 'error') {
hadError = true;
}
if (idleTimer) clearTimeout(idleTimer);