feat: remove container layer, run agents as direct host processes

- Rewrite container-runner.ts to spawn node processes directly instead
  of Docker/Apple Container
- Runner paths configurable via env vars (NANOCLAW_GROUP_DIR, etc.)
  with container-path defaults for backwards compat
- Pass real credentials directly (no credential proxy needed)
- Remove ensureContainerSystemRunning() and startCredentialProxy()
  from startup
- Add build:runners script for building agent-runner and codex-runner
- Fix TS strict mode errors in agent-runner ipc-mcp-stdio.ts
This commit is contained in:
Eyejoker
2026-03-10 21:05:21 +09:00
parent 4a34a9c802
commit 08dd468692
15 changed files with 449 additions and 498 deletions

View File

@@ -5,7 +5,10 @@ import { logger } from './logger.js';
* Extract a session slash command from a message, stripping the trigger prefix if present.
* Returns the slash command (e.g., '/compact') or null if not a session command.
*/
export function extractSessionCommand(content: string, triggerPattern: RegExp): string | null {
export function extractSessionCommand(
content: string,
triggerPattern: RegExp,
): string | null {
let text = content.trim();
text = text.replace(triggerPattern, '').trim();
if (text === '/compact') return '/compact';
@@ -16,7 +19,10 @@ export function extractSessionCommand(content: string, triggerPattern: RegExp):
* Check if a session command sender is authorized.
* Allowed: main group (any sender), or trusted/admin sender (is_from_me) in any group.
*/
export function isSessionCommandAllowed(isMainGroup: boolean, isFromMe: boolean): boolean {
export function isSessionCommandAllowed(
isMainGroup: boolean,
isFromMe: boolean,
): boolean {
return isMainGroup || isFromMe;
}
@@ -61,12 +67,21 @@ export async function handleSessionCommand(opts: {
timezone: string;
deps: SessionCommandDeps;
}): Promise<{ handled: false } | { handled: true; success: boolean }> {
const { missedMessages, isMainGroup, groupName, triggerPattern, timezone, deps } = opts;
const {
missedMessages,
isMainGroup,
groupName,
triggerPattern,
timezone,
deps,
} = opts;
const cmdMsg = missedMessages.find(
(m) => extractSessionCommand(m.content, triggerPattern) !== null,
);
const command = cmdMsg ? extractSessionCommand(cmdMsg.content, triggerPattern) : null;
const command = cmdMsg
? extractSessionCommand(cmdMsg.content, triggerPattern)
: null;
if (!command || !cmdMsg) return { handled: false };
@@ -109,8 +124,13 @@ export async function handleSessionCommand(opts: {
});
if (preResult === 'error' || hadPreError) {
logger.warn({ group: groupName }, 'Pre-compact processing failed, aborting session command');
await deps.sendMessage(`Failed to process messages before ${command}. Try again.`);
logger.warn(
{ group: groupName },
'Pre-compact processing failed, aborting session command',
);
await deps.sendMessage(
`Failed to process messages before ${command}. Try again.`,
);
if (preOutputSent) {
// Output was already sent — don't retry or it will duplicate.
// Advance cursor past pre-compact messages, leave command pending.