* Create and start an agent-job container. * Runs an autonomous task: clones repo, runs agent, commits, creates PR. * Uses a named volume for workspace (cleaned up by caller after exit). * @param {object} options * @param {string} options.agentJobId - Agent job UUID * @param {string} options.re
({ agentJobId, repo, branch, title, description, codingAgent, llmModel, scope, userId })
| 883 | * @returns {Promise<{containerId: string, containerName: string, volumeName: string}>} |
| 884 | */ |
| 885 | async function runAgentJobContainer({ agentJobId, repo, branch, title, description, codingAgent, llmModel, scope, userId }) { |
| 886 | const agent = codingAgent || getConfig('CODING_AGENT') || 'claude-code'; |
| 887 | const version = process.env.THEPOPEBOT_VERSION; |
| 888 | const image = `stephengpope/thepopebot:coding-agent-${agent}-${version}`; |
| 889 | |
| 890 | const shortId = agentJobId.replace(/-/g, '').slice(0, 8); |
| 891 | const containerName = `thepopebot-agent-job-${shortId}`; |
| 892 | const volumeName = `agent-job-${shortId}`; |
| 893 | |
| 894 | // Create named volume for workspace |
| 895 | await createVolume(volumeName); |
| 896 | |
| 897 | const env = [ |
| 898 | `RUNTIME=agent-job`, |
| 899 | `REPO=${repo}`, |
| 900 | `BRANCH=${branch}`, |
| 901 | `AGENT_JOB_ID=${agentJobId}`, |
| 902 | `AGENT_JOB_TITLE=${title}`, |
| 903 | `AGENT_JOB_DESCRIPTION=${description}`, |
| 904 | ]; |
| 905 | |
| 906 | if (llmModel) { |
| 907 | env.push(`LLM_MODEL=${llmModel}`); |
| 908 | } |
| 909 | if (scope) { |
| 910 | env.push(`SCOPE=${scope}`); |
| 911 | } |
| 912 | if (userId) { |
| 913 | env.push(`USER_ID=${userId}`); |
| 914 | } |
| 915 | |
| 916 | // Auth env vars based on agent type |
| 917 | const { env: authEnv, backendApi } = buildAgentAuthEnv(agent); |
| 918 | env.push(...authEnv); |
| 919 | |
| 920 | const ghToken = getConfig('GH_TOKEN'); |
| 921 | if (ghToken) { |
| 922 | env.push(`GH_TOKEN=${ghToken}`); |
| 923 | } |
| 924 | |
| 925 | // Inject APP_URL so agents can call back to the event handler |
| 926 | const appUrl = getConfig('APP_URL'); |
| 927 | if (appUrl) env.push(`APP_URL=${appUrl}`); |
| 928 | |
| 929 | // Create per-container API key for agent-secrets access |
| 930 | const { createAgentJobApiKey } = await import('../db/api-keys.js'); |
| 931 | const { key: agentJobToken } = createAgentJobApiKey(containerName); |
| 932 | env.push(`AGENT_JOB_TOKEN=${agentJobToken}`); |
| 933 | |
| 934 | // Inject agent job secrets (plain secrets as env vars; oauth types are null — agent must fetch via get) |
| 935 | const { getAllAgentJobSecrets } = await import('../db/config.js'); |
| 936 | const jobSecrets = getAllAgentJobSecrets(); |
| 937 | for (const { key, value } of jobSecrets) { |
| 938 | if (value !== null && !env.some(e => e.startsWith(`${key}=`))) { |
| 939 | env.push(`${key}=${value}`); |
| 940 | } |
| 941 | } |
| 942 |
no test coverage detected