diff --git a/containers/api-proxy/Dockerfile b/containers/api-proxy/Dockerfile index 8e74fe1d..a7f5b310 100644 --- a/containers/api-proxy/Dockerfile +++ b/containers/api-proxy/Dockerfile @@ -30,6 +30,6 @@ USER apiproxy # 10004 - OpenCode API proxy (routes to Anthropic) EXPOSE 10000 10001 10002 10004 -# Redirect stdout/stderr to log file for persistence -# Use shell form to enable redirection and tee for both file and console -CMD node server.js 2>&1 | tee -a /var/log/api-proxy/api-proxy.log +# Use exec form so Node.js is PID 1 and receives SIGTERM directly +# Docker captures stdout/stderr automatically, no need for manual log redirection +CMD ["node", "server.js"] diff --git a/scripts/ci/postprocess-smoke-workflows.ts b/scripts/ci/postprocess-smoke-workflows.ts index 8cf3a2df..e518acfe 100644 --- a/scripts/ci/postprocess-smoke-workflows.ts +++ b/scripts/ci/postprocess-smoke-workflows.ts @@ -94,6 +94,14 @@ const shallowDepthRegex = /^(\s+)depth: 1\n/gm; // instead of pre-built GHCR images that may be stale. const imageTagRegex = /--image-tag\s+[0-9.]+\s+--skip-pull/g; +// Add --skip-cleanup after sudo -E awf to skip container shutdown in CI +// (saves ~10 seconds per run since containers are cleaned up when runner terminates) +// Match patterns: +// - sudo -E awf -- ... (with any flags after awf except --skip-cleanup which may already exist) +// - sudo -E awf "$command" (when command is directly after awf) +// Strategy: Insert --skip-cleanup right after "awf " if not already present +const awfCleanupRegex = /sudo -E awf (?!.*--skip-cleanup)/g; + for (const workflowPath of workflowPaths) { let content = fs.readFileSync(workflowPath, 'utf-8'); let modified = false; @@ -139,6 +147,14 @@ for (const workflowPath of workflowPaths) { console.log(` Replaced ${imageTagMatches.length} --image-tag/--skip-pull with --build-local`); } + // Add --skip-cleanup to all awf invocations (saves ~10s per run in CI) + const awfCleanupMatches = content.match(awfCleanupRegex); + if (awfCleanupMatches) { + content = content.replace(awfCleanupRegex, 'sudo -E awf --skip-cleanup '); + modified = true; + console.log(` Added --skip-cleanup to ${awfCleanupMatches.length} awf invocation(s)`); + } + if (modified) { fs.writeFileSync(workflowPath, content); console.log(`Updated ${workflowPath}`); diff --git a/src/cli.ts b/src/cli.ts index b06238e5..d59e7f0e 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -696,6 +696,11 @@ program 'Keep containers running after command exits', false ) + .option( + '--skip-cleanup', + 'Skip all cleanup (containers, iptables, work dir) - useful in CI where runner terminates anyway', + false + ) .option( '--tty', 'Allocate a pseudo-TTY for the container (required for interactive tools like Claude Code)', @@ -1062,6 +1067,7 @@ program agentCommand, logLevel, keepContainers: options.keepContainers, + skipCleanup: options.skipCleanup, tty: options.tty || false, workDir: options.workDir, buildLocal: options.buildLocal, @@ -1180,6 +1186,12 @@ program logger.info(`Received ${signal}, cleaning up...`); } + // Skip all cleanup if requested (useful in CI where runner terminates anyway) + if (config.skipCleanup) { + logger.info('Skipping cleanup (--skip-cleanup enabled)'); + return; + } + if (containersStarted) { await stopContainers(config.workDir, config.keepContainers); } diff --git a/src/types.ts b/src/types.ts index 1ee1c8bf..97967820 100644 --- a/src/types.ts +++ b/src/types.ts @@ -131,6 +131,23 @@ export interface WrapperConfig { */ keepContainers: boolean; + /** + * Whether to skip cleanup when the process exits + * + * When true: + * - Containers are not stopped (left running or stopped by Docker daemon) + * - Host iptables rules are not cleaned up + * - Work directory is not deleted + * - Useful in CI environments where the runner will terminate anyway, + * saving ~10 seconds of shutdown time + * + * This is a stronger version of keepContainers that also skips all cleanup + * operations, not just container removal. + * + * @default false + */ + skipCleanup?: boolean; + /** * Whether to allocate a pseudo-TTY for the agent execution container *