@workermill/agent 0.8.5 → 0.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/setup.js +63 -47
- package/dist/config.js +6 -4
- package/dist/spawner.d.ts +6 -0
- package/dist/spawner.js +108 -28
- package/package.json +1 -1
package/dist/commands/setup.js
CHANGED
|
@@ -311,29 +311,9 @@ export async function setupCommand() {
|
|
|
311
311
|
}
|
|
312
312
|
process.exit(1);
|
|
313
313
|
}
|
|
314
|
-
// SCM
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
bitbucket: "",
|
|
318
|
-
gitlab: "",
|
|
319
|
-
};
|
|
320
|
-
const scmLabel = scmProvider === "bitbucket"
|
|
321
|
-
? "Bitbucket"
|
|
322
|
-
: scmProvider === "gitlab"
|
|
323
|
-
? "GitLab"
|
|
324
|
-
: "GitHub";
|
|
325
|
-
const { scmToken } = await inquirer.prompt([
|
|
326
|
-
{
|
|
327
|
-
type: "password",
|
|
328
|
-
name: "scmToken",
|
|
329
|
-
message: `${scmLabel} personal access token (for cloning/pushing to your repos):`,
|
|
330
|
-
mask: "*",
|
|
331
|
-
validate: (v) => (v.length > 0 ? true : "A token is required for workers to clone and push to your repositories"),
|
|
332
|
-
},
|
|
333
|
-
]);
|
|
334
|
-
if (scmToken) {
|
|
335
|
-
tokenPrompts[scmProvider] = scmToken;
|
|
336
|
-
}
|
|
314
|
+
// SCM tokens come from org Settings > Integrations (no local prompt needed)
|
|
315
|
+
console.log(chalk.dim(" SCM tokens are managed via Settings > Integrations on the dashboard."));
|
|
316
|
+
console.log();
|
|
337
317
|
const { agentId } = await inquirer.prompt([
|
|
338
318
|
{
|
|
339
319
|
type: "input",
|
|
@@ -342,36 +322,72 @@ export async function setupCommand() {
|
|
|
342
322
|
default: `agent-${hostname()}`,
|
|
343
323
|
},
|
|
344
324
|
]);
|
|
345
|
-
// ── Step 7:
|
|
325
|
+
// ── Step 7: AWS CLI + ECR auth + pull worker image ───────────────────────
|
|
346
326
|
console.log();
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
327
|
+
const PRIVATE_ECR_REGISTRY = "593971626975.dkr.ecr.us-east-1.amazonaws.com";
|
|
328
|
+
const workerImage = `${PRIVATE_ECR_REGISTRY}/workermill-dev/worker:latest`;
|
|
329
|
+
// Check AWS CLI
|
|
330
|
+
const awsSpinner = ora("Checking AWS CLI...").start();
|
|
331
|
+
if (commandExists("aws")) {
|
|
332
|
+
try {
|
|
333
|
+
execSync("aws sts get-caller-identity", {
|
|
334
|
+
stdio: "pipe",
|
|
335
|
+
timeout: 15000,
|
|
336
|
+
});
|
|
337
|
+
awsSpinner.succeed("AWS CLI configured");
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
awsSpinner.warn("AWS CLI found but credentials not configured");
|
|
341
|
+
console.log();
|
|
342
|
+
console.log(chalk.yellow(" Configure AWS credentials for private ECR image access:"));
|
|
343
|
+
console.log(chalk.cyan(" aws configure"));
|
|
344
|
+
console.log(chalk.dim(" Contact your WorkerMill admin for AWS access key / secret key."));
|
|
345
|
+
console.log(chalk.dim(" Setup will continue — you can configure AWS later before starting."));
|
|
346
|
+
}
|
|
359
347
|
}
|
|
360
348
|
else {
|
|
349
|
+
awsSpinner.warn("AWS CLI not found");
|
|
361
350
|
console.log();
|
|
362
|
-
console.log(chalk.
|
|
351
|
+
console.log(chalk.yellow(" AWS CLI is required for pulling worker images from private ECR."));
|
|
352
|
+
console.log(chalk.cyan(" Install: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html"));
|
|
353
|
+
console.log(chalk.dim(" Setup will continue — install AWS CLI before starting the agent."));
|
|
354
|
+
}
|
|
355
|
+
// Authenticate with ECR
|
|
356
|
+
console.log();
|
|
357
|
+
console.log(chalk.dim(` Authenticating with private ECR...`));
|
|
358
|
+
let ecrAuthed = false;
|
|
359
|
+
try {
|
|
360
|
+
execSync(`aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${PRIVATE_ECR_REGISTRY}`, { stdio: "pipe", timeout: 30_000 });
|
|
361
|
+
console.log(chalk.green(" ✓ ECR authenticated"));
|
|
362
|
+
ecrAuthed = true;
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
console.log(chalk.yellow(" ⚠ ECR authentication failed (AWS credentials may not be configured yet)"));
|
|
366
|
+
console.log(chalk.dim(" Worker image pull will be skipped — authenticate later with:"));
|
|
367
|
+
console.log(chalk.dim(` aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${PRIVATE_ECR_REGISTRY}`));
|
|
368
|
+
}
|
|
369
|
+
// Pull worker image (only if ECR auth succeeded)
|
|
370
|
+
if (ecrAuthed) {
|
|
363
371
|
console.log();
|
|
364
|
-
|
|
365
|
-
|
|
372
|
+
console.log(chalk.dim(` Pulling worker image: ${workerImage}`));
|
|
373
|
+
console.log(chalk.dim(" This may take a few minutes on first run (~1.1 GB)..."));
|
|
374
|
+
console.log();
|
|
375
|
+
const pullResult = spawnSync("docker", ["pull", workerImage], {
|
|
376
|
+
stdio: "inherit",
|
|
377
|
+
timeout: 600_000,
|
|
378
|
+
});
|
|
379
|
+
if (pullResult.status === 0) {
|
|
380
|
+
console.log();
|
|
381
|
+
console.log(chalk.green(" ✓ Worker image pulled"));
|
|
366
382
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
383
|
+
else {
|
|
384
|
+
console.log();
|
|
385
|
+
console.log(chalk.red(" ✗ Failed to pull worker image."));
|
|
386
|
+
if (pullResult.error) {
|
|
387
|
+
console.log(chalk.yellow(` Error: ${pullResult.error.message}`));
|
|
388
|
+
}
|
|
389
|
+
console.log(chalk.dim(" Setup will continue — you can pull the image later before starting."));
|
|
371
390
|
}
|
|
372
|
-
console.log(chalk.yellow(` ${isWindows ? "3" : "2"}. Try manually: ${chalk.cyan(`docker pull ${workerImage}`)}`));
|
|
373
|
-
console.log();
|
|
374
|
-
console.log(chalk.dim(" Setup will continue — you can pull the image later before starting."));
|
|
375
391
|
}
|
|
376
392
|
// ── Step 8: Save config ───────────────────────────────────────────────────
|
|
377
393
|
const fileConfig = {
|
|
@@ -381,7 +397,7 @@ export async function setupCommand() {
|
|
|
381
397
|
maxWorkers: 1,
|
|
382
398
|
pollIntervalMs: 5000,
|
|
383
399
|
heartbeatIntervalMs: 30000,
|
|
384
|
-
tokens:
|
|
400
|
+
tokens: { github: "", bitbucket: "", gitlab: "" }, // SCM tokens come from org Settings
|
|
385
401
|
workerImage,
|
|
386
402
|
setupCompletedAt: new Date().toISOString(),
|
|
387
403
|
};
|
package/dist/config.js
CHANGED
|
@@ -53,10 +53,12 @@ export function loadConfigFromFile() {
|
|
|
53
53
|
console.error("Config file is missing required fields (apiUrl, apiKey). Re-run 'workermill-agent setup'.");
|
|
54
54
|
process.exit(1);
|
|
55
55
|
}
|
|
56
|
-
// Migrate any stale image URLs to current default
|
|
57
|
-
const defaultImage = "
|
|
56
|
+
// Migrate any stale image URLs to current default (private ECR)
|
|
57
|
+
const defaultImage = "593971626975.dkr.ecr.us-east-1.amazonaws.com/workermill-dev/worker:latest";
|
|
58
58
|
let workerImage = fc.workerImage || defaultImage;
|
|
59
|
-
if (workerImage.includes("jarod1/") ||
|
|
59
|
+
if (workerImage.includes("jarod1/") ||
|
|
60
|
+
workerImage.includes("public.ecr.aws/") ||
|
|
61
|
+
!workerImage.includes("workermill-worker") && !workerImage.includes("workermill-dev/worker")) {
|
|
60
62
|
workerImage = defaultImage;
|
|
61
63
|
fc.workerImage = workerImage;
|
|
62
64
|
try {
|
|
@@ -151,7 +153,7 @@ export function findClaudePath() {
|
|
|
151
153
|
*/
|
|
152
154
|
export function checkPrerequisites(workerImage) {
|
|
153
155
|
const results = [];
|
|
154
|
-
const image = workerImage || "
|
|
156
|
+
const image = workerImage || "593971626975.dkr.ecr.us-east-1.amazonaws.com/workermill-dev/worker:latest";
|
|
155
157
|
// Docker
|
|
156
158
|
try {
|
|
157
159
|
const version = execSync("docker version --format {{.Server.Version}}", {
|
package/dist/spawner.d.ts
CHANGED
|
@@ -51,6 +51,9 @@ export interface ClaimCredentials {
|
|
|
51
51
|
githubReviewerToken?: string;
|
|
52
52
|
scmBaseUrl?: string;
|
|
53
53
|
ollamaContextWindow?: number;
|
|
54
|
+
scmToken?: string;
|
|
55
|
+
githubToken?: string;
|
|
56
|
+
bitbucketUsername?: string;
|
|
54
57
|
anthropicApiKey?: string;
|
|
55
58
|
openaiApiKey?: string;
|
|
56
59
|
googleApiKey?: string;
|
|
@@ -102,6 +105,9 @@ export interface ManagerCredentials {
|
|
|
102
105
|
jiraApiToken?: string;
|
|
103
106
|
linearApiKey?: string;
|
|
104
107
|
issueTrackerProvider?: string;
|
|
108
|
+
scmToken?: string;
|
|
109
|
+
githubToken?: string;
|
|
110
|
+
bitbucketUsername?: string;
|
|
105
111
|
}
|
|
106
112
|
/**
|
|
107
113
|
* Spawn a manager Docker container for PR review or log analysis.
|
package/dist/spawner.js
CHANGED
|
@@ -34,6 +34,21 @@ function detectWSL() {
|
|
|
34
34
|
}
|
|
35
35
|
const isWSL = detectWSL();
|
|
36
36
|
const isDockerDesktop = isWSL || process.platform === "darwin" || process.platform === "win32";
|
|
37
|
+
/**
|
|
38
|
+
* Get WSL2 host IP for Docker --add-host override.
|
|
39
|
+
* On WSL2, host-gateway resolves to the Docker VM, not WSL2 where the API runs.
|
|
40
|
+
*/
|
|
41
|
+
function getWSLHostIP() {
|
|
42
|
+
if (!isWSL)
|
|
43
|
+
return null;
|
|
44
|
+
try {
|
|
45
|
+
const ip = execSync("hostname -I", { encoding: "utf-8" }).trim().split(/\s+/)[0];
|
|
46
|
+
if (ip && /^\d+\.\d+\.\d+\.\d+$/.test(ip))
|
|
47
|
+
return ip;
|
|
48
|
+
}
|
|
49
|
+
catch { /* fall through */ }
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
37
52
|
/**
|
|
38
53
|
* Convert WSL paths to Windows paths for Docker volume mounts.
|
|
39
54
|
*/
|
|
@@ -69,14 +84,42 @@ function findClaudeConfigDir() {
|
|
|
69
84
|
}
|
|
70
85
|
return null;
|
|
71
86
|
}
|
|
87
|
+
/** Private ECR registry for worker images */
|
|
88
|
+
const PRIVATE_ECR_REGISTRY = "593971626975.dkr.ecr.us-east-1.amazonaws.com";
|
|
89
|
+
/** Cache ECR login (token lasts 12h, refresh after 11h) */
|
|
90
|
+
let ecrLoginExpiresAt = 0;
|
|
91
|
+
/**
|
|
92
|
+
* Ensure Docker is logged into private ECR.
|
|
93
|
+
* Uses ambient AWS credentials (aws configure).
|
|
94
|
+
*/
|
|
95
|
+
function ensureEcrLogin() {
|
|
96
|
+
if (Date.now() < ecrLoginExpiresAt)
|
|
97
|
+
return true;
|
|
98
|
+
try {
|
|
99
|
+
execSync(`aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${PRIVATE_ECR_REGISTRY}`, { stdio: "pipe", timeout: 30_000 });
|
|
100
|
+
ecrLoginExpiresAt = Date.now() + 11 * 60 * 60 * 1000;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
72
107
|
/**
|
|
73
108
|
* Get SCM token based on provider.
|
|
109
|
+
* Prefers org credentials from API, falls back to local config.
|
|
74
110
|
*/
|
|
75
|
-
function getScmToken(scmProvider, config) {
|
|
111
|
+
function getScmToken(scmProvider, config, credentials) {
|
|
112
|
+
// Org credentials from API are the primary source
|
|
113
|
+
if (credentials?.scmToken)
|
|
114
|
+
return credentials.scmToken;
|
|
115
|
+
// Fall back to local config tokens
|
|
76
116
|
switch (scmProvider) {
|
|
77
|
-
case "bitbucket":
|
|
78
|
-
|
|
79
|
-
|
|
117
|
+
case "bitbucket":
|
|
118
|
+
return config.bitbucketToken;
|
|
119
|
+
case "gitlab":
|
|
120
|
+
return config.gitlabToken;
|
|
121
|
+
default:
|
|
122
|
+
return config.githubToken;
|
|
80
123
|
}
|
|
81
124
|
}
|
|
82
125
|
/** Check if a task has the self-review label (works across Jira, GitHub, GitLab, Linear) */
|
|
@@ -112,7 +155,9 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
112
155
|
}
|
|
113
156
|
const containerName = `workermill-${task.id.slice(0, 8)}`;
|
|
114
157
|
// Build Docker run arguments
|
|
115
|
-
|
|
158
|
+
// Only pull from registry for remote images; local images (no '/' in name) are already on disk
|
|
159
|
+
const isLocalImage = !config.workerImage.includes("/");
|
|
160
|
+
const dockerArgs = ["run", "--rm", ...(isLocalImage ? [] : ["--pull", "always"]), "--name", containerName];
|
|
116
161
|
// Resource limits — 6GB memory with swap for overflow.
|
|
117
162
|
// NODE_OPTIONS caps V8 heap at 2GB; the extra room is for git, npm, Claude CLI subprocesses.
|
|
118
163
|
const totalRamGB = Math.round(os.totalmem() / (1024 * 1024 * 1024));
|
|
@@ -125,9 +170,10 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
125
170
|
else {
|
|
126
171
|
dockerArgs.push("--memory", "6g", "--memory-swap", "12g", "--cpus", "4");
|
|
127
172
|
}
|
|
128
|
-
// Network mode
|
|
173
|
+
// Network mode — WSL2: host-gateway resolves to Docker VM, not WSL2, so use actual WSL IP
|
|
129
174
|
if (isDockerDesktop) {
|
|
130
|
-
|
|
175
|
+
const wslIP = getWSLHostIP();
|
|
176
|
+
dockerArgs.push(`--add-host=host.docker.internal:${wslIP || "host-gateway"}`);
|
|
131
177
|
}
|
|
132
178
|
else {
|
|
133
179
|
dockerArgs.push("--network", "host");
|
|
@@ -158,8 +204,18 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
158
204
|
console.log(`${ts()} ${taskLabel} ${chalk.dim("Skipping Claude mount (non-Anthropic worker)")}`);
|
|
159
205
|
}
|
|
160
206
|
// Build environment variables — KEY DIFFERENCE: API_BASE_URL points to cloud
|
|
207
|
+
// Docker containers can't reach host via "localhost" — translate for Docker networking
|
|
208
|
+
const containerApiUrl = config.apiUrl.replace(/localhost|127\.0\.0\.1/, "host.docker.internal");
|
|
161
209
|
const scmProvider = (task.scmProvider || "github");
|
|
162
|
-
const scmToken = getScmToken(scmProvider, config);
|
|
210
|
+
const scmToken = getScmToken(scmProvider, config, credentials);
|
|
211
|
+
// Derive per-provider tokens: prefer org credentials, fall back to local config
|
|
212
|
+
const githubToken = credentials?.githubToken || config.githubToken;
|
|
213
|
+
const bitbucketToken = scmProvider === "bitbucket"
|
|
214
|
+
? credentials?.scmToken || config.bitbucketToken
|
|
215
|
+
: config.bitbucketToken;
|
|
216
|
+
const gitlabToken = scmProvider === "gitlab"
|
|
217
|
+
? credentials?.scmToken || config.gitlabToken
|
|
218
|
+
: config.gitlabToken;
|
|
163
219
|
const envVars = {
|
|
164
220
|
// Cap V8 heap to 3GB — forces aggressive GC instead of bloating to fill container.
|
|
165
221
|
// Each Claude CLI subprocess inherits this, preventing unbounded heap growth.
|
|
@@ -178,18 +234,19 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
178
234
|
RETRY_NUMBER: String(task.retryCount ?? 0),
|
|
179
235
|
TICKET_KEY: task.jiraIssueKey || "",
|
|
180
236
|
// Cloud API — this is what makes remote agent mode work
|
|
181
|
-
|
|
237
|
+
// Use containerApiUrl so Docker containers reach the host via host.docker.internal
|
|
238
|
+
API_BASE_URL: containerApiUrl,
|
|
182
239
|
ORG_API_KEY: config.apiKey,
|
|
183
|
-
// SCM configuration
|
|
240
|
+
// SCM configuration — org credentials from API are primary, local config is fallback
|
|
184
241
|
SCM_PROVIDER: scmProvider,
|
|
185
242
|
SCM_TOKEN: scmToken,
|
|
186
243
|
SCM_BASE_URL: credentials?.scmBaseUrl || "",
|
|
187
|
-
GITHUB_TOKEN:
|
|
188
|
-
GH_TOKEN:
|
|
244
|
+
GITHUB_TOKEN: githubToken,
|
|
245
|
+
GH_TOKEN: githubToken,
|
|
189
246
|
GITHUB_REVIEWER_TOKEN: credentials?.githubReviewerToken || "",
|
|
190
|
-
BITBUCKET_TOKEN:
|
|
191
|
-
BITBUCKET_USERNAME: "x-token-auth",
|
|
192
|
-
GITLAB_TOKEN:
|
|
247
|
+
BITBUCKET_TOKEN: bitbucketToken,
|
|
248
|
+
BITBUCKET_USERNAME: credentials?.bitbucketUsername || "x-token-auth",
|
|
249
|
+
GITLAB_TOKEN: gitlabToken,
|
|
193
250
|
// Target repository
|
|
194
251
|
TARGET_REPO: task.githubRepo || "",
|
|
195
252
|
GITHUB_REPO: task.githubRepo || "",
|
|
@@ -269,8 +326,12 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
269
326
|
dockerArgs.push("-e", `${k}=${v}`);
|
|
270
327
|
}
|
|
271
328
|
}
|
|
272
|
-
// Worker image
|
|
273
|
-
|
|
329
|
+
// Worker image — private ECR requires auth (ensureEcrLogin handles it)
|
|
330
|
+
const workerImage = config.workerImage || `${PRIVATE_ECR_REGISTRY}/workermill-dev/worker:latest`;
|
|
331
|
+
if (workerImage.includes(PRIVATE_ECR_REGISTRY)) {
|
|
332
|
+
ensureEcrLogin();
|
|
333
|
+
}
|
|
334
|
+
dockerArgs.push(workerImage);
|
|
274
335
|
const reviewEnabled = task.skipManagerReview === false;
|
|
275
336
|
console.log(`${ts()} ${taskLabel} ${chalk.dim("Starting container")} ${chalk.yellow(containerName)}`);
|
|
276
337
|
console.log(`${ts()} ${taskLabel} ${chalk.dim(` skipManagerReview=${task.skipManagerReview} → REVIEW_ENABLED=${reviewEnabled}`)}`);
|
|
@@ -425,13 +486,29 @@ export async function spawnManagerWorker(task, config, credentials) {
|
|
|
425
486
|
"--memory=4g",
|
|
426
487
|
"--cpus=2",
|
|
427
488
|
];
|
|
489
|
+
// Network mode — same as main worker spawn
|
|
490
|
+
if (isDockerDesktop) {
|
|
491
|
+
const wslIP = getWSLHostIP();
|
|
492
|
+
dockerArgs.push(`--add-host=host.docker.internal:${wslIP || "host-gateway"}`);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
dockerArgs.push("--network", "host");
|
|
496
|
+
}
|
|
428
497
|
if (claudeConfigDir) {
|
|
429
498
|
const dockerClaudeDir = toDockerPath(claudeConfigDir);
|
|
430
499
|
dockerArgs.push("-v", `${dockerClaudeDir}:/home/worker/.claude`);
|
|
431
500
|
}
|
|
432
501
|
// Manager-specific env vars (match ECS runManagerTask)
|
|
502
|
+
const containerApiUrl = config.apiUrl.replace(/localhost|127\.0\.0\.1/, "host.docker.internal");
|
|
433
503
|
const scmProvider = (task.scmProvider || "github");
|
|
434
|
-
const scmToken = getScmToken(scmProvider, config);
|
|
504
|
+
const scmToken = getScmToken(scmProvider, config, credentials);
|
|
505
|
+
const githubToken = credentials?.githubToken || config.githubToken;
|
|
506
|
+
const bitbucketToken = scmProvider === "bitbucket"
|
|
507
|
+
? credentials?.scmToken || config.bitbucketToken
|
|
508
|
+
: config.bitbucketToken;
|
|
509
|
+
const gitlabToken = scmProvider === "gitlab"
|
|
510
|
+
? credentials?.scmToken || config.gitlabToken
|
|
511
|
+
: config.gitlabToken;
|
|
435
512
|
const envVars = {
|
|
436
513
|
NODE_OPTIONS: "--max-old-space-size=3072",
|
|
437
514
|
TASK_ID: task.id,
|
|
@@ -442,17 +519,17 @@ export async function spawnManagerWorker(task, config, credentials) {
|
|
|
442
519
|
GITHUB_REPO: task.githubRepo || "",
|
|
443
520
|
PR_URL: task.githubPrUrl || "",
|
|
444
521
|
PR_NUMBER: task.githubPrNumber ? String(task.githubPrNumber) : "",
|
|
445
|
-
// Cloud API
|
|
446
|
-
API_BASE_URL:
|
|
522
|
+
// Cloud API — use containerApiUrl for Docker networking
|
|
523
|
+
API_BASE_URL: containerApiUrl,
|
|
447
524
|
ORG_API_KEY: config.apiKey,
|
|
448
|
-
// SCM configuration
|
|
525
|
+
// SCM configuration — org credentials from API are primary, local config is fallback
|
|
449
526
|
SCM_PROVIDER: scmProvider,
|
|
450
527
|
SCM_TOKEN: scmToken,
|
|
451
|
-
GITHUB_TOKEN:
|
|
452
|
-
GH_TOKEN:
|
|
453
|
-
BITBUCKET_TOKEN:
|
|
454
|
-
BITBUCKET_USERNAME: "x-token-auth",
|
|
455
|
-
GITLAB_TOKEN:
|
|
528
|
+
GITHUB_TOKEN: githubToken,
|
|
529
|
+
GH_TOKEN: githubToken,
|
|
530
|
+
BITBUCKET_TOKEN: bitbucketToken,
|
|
531
|
+
BITBUCKET_USERNAME: credentials?.bitbucketUsername || "x-token-auth",
|
|
532
|
+
GITLAB_TOKEN: gitlabToken,
|
|
456
533
|
// Manager provider and model
|
|
457
534
|
MANAGER_PROVIDER: credentials?.managerProvider || "anthropic",
|
|
458
535
|
MANAGER_MODEL: credentials?.managerModelId || "",
|
|
@@ -473,8 +550,11 @@ export async function spawnManagerWorker(task, config, credentials) {
|
|
|
473
550
|
dockerArgs.push("-e", `${k}=${v}`);
|
|
474
551
|
}
|
|
475
552
|
}
|
|
476
|
-
// Worker image with manager entrypoint override
|
|
477
|
-
const workerImage = config.workerImage ||
|
|
553
|
+
// Worker image with manager entrypoint override — private ECR requires auth
|
|
554
|
+
const workerImage = config.workerImage || `${PRIVATE_ECR_REGISTRY}/workermill-dev/worker:latest`;
|
|
555
|
+
if (workerImage.includes(PRIVATE_ECR_REGISTRY)) {
|
|
556
|
+
ensureEcrLogin();
|
|
557
|
+
}
|
|
478
558
|
dockerArgs.push("--entrypoint", "/bin/bash");
|
|
479
559
|
dockerArgs.push(workerImage);
|
|
480
560
|
dockerArgs.push("/app/manager-entrypoint.sh");
|