@pushpalsdev/cli 1.0.18 → 1.0.20
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/pushpals-cli.js +291 -44
- package/package.json +1 -1
- package/runtime/configs/backend.toml +1 -1
- package/runtime/configs/default.toml +1 -1
- package/runtime/sandbox/apps/workerpals/.python-version +1 -0
- package/runtime/sandbox/apps/workerpals/Dockerfile.sandbox +71 -0
- package/runtime/sandbox/apps/workerpals/package.json +25 -0
- package/runtime/sandbox/apps/workerpals/pyproject.toml +8 -0
- package/runtime/sandbox/apps/workerpals/src/backends/backend_config.ts +119 -0
- package/runtime/sandbox/apps/workerpals/src/backends/miniswe/miniswe_executor.py +2029 -0
- package/runtime/sandbox/apps/workerpals/src/backends/miniswe_backend.ts +48 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openai_codex/openai_codex_executor.py +1259 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openai_codex/test_openai_codex_runtime_config.py +110 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openai_codex_backend.ts +67 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openhands/openhands_executor.py +563 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openhands_backend.ts +161 -0
- package/runtime/sandbox/apps/workerpals/src/backends/openhands_task_execute.ts +536 -0
- package/runtime/sandbox/apps/workerpals/src/backends/shared/executor_base.py +746 -0
- package/runtime/sandbox/apps/workerpals/src/backends/shared/test_settings_resolver.py +60 -0
- package/runtime/sandbox/apps/workerpals/src/backends/task_execute_registry.ts +21 -0
- package/runtime/sandbox/apps/workerpals/src/backends/types.ts +52 -0
- package/runtime/sandbox/apps/workerpals/src/common/execution_utils.ts +149 -0
- package/runtime/sandbox/apps/workerpals/src/common/executor_backend.ts +15 -0
- package/runtime/sandbox/apps/workerpals/src/common/generic_python_executor.ts +210 -0
- package/runtime/sandbox/apps/workerpals/src/common/logger.ts +65 -0
- package/runtime/sandbox/apps/workerpals/src/common/types.ts +9 -0
- package/runtime/sandbox/apps/workerpals/src/common/worktree_cleanup.ts +66 -0
- package/runtime/sandbox/apps/workerpals/src/context_manager.ts +45 -0
- package/runtime/sandbox/apps/workerpals/src/docker_executor.ts +1842 -0
- package/runtime/sandbox/apps/workerpals/src/execute_job.ts +3063 -0
- package/runtime/sandbox/apps/workerpals/src/job_runner.ts +194 -0
- package/runtime/sandbox/apps/workerpals/src/shell_manager.ts +210 -0
- package/runtime/sandbox/apps/workerpals/src/timeout_policy.ts +24 -0
- package/runtime/sandbox/apps/workerpals/src/workerpals_main.ts +1436 -0
- package/runtime/sandbox/apps/workerpals/tsconfig.json +15 -0
- package/runtime/sandbox/apps/workerpals/uv.lock +2014 -0
- package/runtime/sandbox/bun.lock +2591 -0
- package/runtime/sandbox/configs/backend.toml +79 -0
- package/runtime/sandbox/configs/default.toml +260 -0
- package/runtime/sandbox/configs/dev.toml +2 -0
- package/runtime/sandbox/configs/local.example.toml +129 -0
- package/runtime/sandbox/package.json +65 -0
- package/runtime/sandbox/packages/protocol/README.md +168 -0
- package/runtime/sandbox/packages/protocol/package.json +37 -0
- package/runtime/sandbox/packages/protocol/scripts/copy-schemas.js +17 -0
- package/runtime/sandbox/packages/protocol/src/a2a/README.md +52 -0
- package/runtime/sandbox/packages/protocol/src/a2a/mapping.ts +55 -0
- package/runtime/sandbox/packages/protocol/src/index.browser.ts +25 -0
- package/runtime/sandbox/packages/protocol/src/index.ts +25 -0
- package/runtime/sandbox/packages/protocol/src/schemas/approvals.schema.json +6 -0
- package/runtime/sandbox/packages/protocol/src/schemas/envelope.schema.json +96 -0
- package/runtime/sandbox/packages/protocol/src/schemas/events.schema.json +679 -0
- package/runtime/sandbox/packages/protocol/src/schemas/http.schema.json +50 -0
- package/runtime/sandbox/packages/protocol/src/types.ts +267 -0
- package/runtime/sandbox/packages/protocol/src/validate.browser.ts +154 -0
- package/runtime/sandbox/packages/protocol/src/validate.ts +233 -0
- package/runtime/sandbox/packages/protocol/src/version.ts +1 -0
- package/runtime/sandbox/packages/protocol/tsconfig.json +20 -0
- package/runtime/sandbox/packages/shared/package.json +19 -0
- package/runtime/sandbox/packages/shared/src/autonomy_policy.ts +400 -0
- package/runtime/sandbox/packages/shared/src/client_preflight.ts +286 -0
- package/runtime/sandbox/packages/shared/src/communication.ts +313 -0
- package/runtime/sandbox/packages/shared/src/config.ts +2180 -0
- package/runtime/sandbox/packages/shared/src/config_template_parity.ts +70 -0
- package/runtime/sandbox/packages/shared/src/git_backend.ts +205 -0
- package/runtime/sandbox/packages/shared/src/index.ts +101 -0
- package/runtime/sandbox/packages/shared/src/local_network.ts +101 -0
- package/runtime/sandbox/packages/shared/src/localbuddy_runtime.ts +314 -0
- package/runtime/sandbox/packages/shared/src/prompts.ts +64 -0
- package/runtime/sandbox/packages/shared/src/repo.ts +134 -0
- package/runtime/sandbox/packages/shared/src/session_event_visibility.ts +25 -0
- package/runtime/sandbox/packages/shared/src/vision.ts +247 -0
- package/runtime/sandbox/packages/shared/tsconfig.json +16 -0
- package/runtime/sandbox/prompts/workerpals/codex_quality_critic_instruction_prompt.md +14 -0
- package/runtime/sandbox/prompts/workerpals/commit_message_prompt.md +36 -0
- package/runtime/sandbox/prompts/workerpals/commit_message_user_prompt.md +7 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_broker_system_prompt.md +33 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_broker_task_prompt.md +5 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_completion_requirement.md +1 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_context_compaction_retry_prompt.md +1 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_explicit_targets_block.md +2 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_recovery_guidance_base.md +4 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_recovery_guidance_blocker_line.md +1 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_strict_tool_use_guidance.md +6 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_supplemental_guidance_section.md +2 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_timeout_note.md +1 -0
- package/runtime/sandbox/prompts/workerpals/miniswe_toolcall_retry_guidance.md +1 -0
- package/runtime/sandbox/prompts/workerpals/openai_codex_default_system_prompt.md +4 -0
- package/runtime/sandbox/prompts/workerpals/openai_codex_instruction_wrapper.md +5 -0
- package/runtime/sandbox/prompts/workerpals/openai_codex_runtime_policy_appendix.md +5 -0
- package/runtime/sandbox/prompts/workerpals/openai_codex_supplemental_guidance_section.md +2 -0
- package/runtime/sandbox/prompts/workerpals/openai_codex_task_execute_system_prompt.md +12 -0
- package/runtime/sandbox/prompts/workerpals/openhands_minimal_security_policy.j2 +8 -0
- package/runtime/sandbox/prompts/workerpals/openhands_minimal_system_prompt.j2 +20 -0
- package/runtime/sandbox/prompts/workerpals/openhands_strict_tool_use_message.md +1 -0
- package/runtime/sandbox/prompts/workerpals/openhands_supplemental_guidance_message.md +2 -0
- package/runtime/sandbox/prompts/workerpals/openhands_task_execute_fallback_system_prompt.md +1 -0
- package/runtime/sandbox/prompts/workerpals/openhands_task_execute_system_prompt.md +21 -0
- package/runtime/sandbox/prompts/workerpals/openhands_task_user_prompt.md +6 -0
- package/runtime/sandbox/prompts/workerpals/openhands_timeout_note.md +1 -0
- package/runtime/sandbox/prompts/workerpals/pr_description.md +42 -0
- package/runtime/sandbox/prompts/workerpals/task_quality_critic_system_prompt.md +9 -0
- package/runtime/sandbox/prompts/workerpals/task_quality_critic_user_prompt.md +17 -0
- package/runtime/sandbox/prompts/workerpals/workerpals_system_prompt.md +115 -0
- package/runtime/sandbox/protocol/schemas/approvals.schema.json +6 -0
- package/runtime/sandbox/protocol/schemas/envelope.schema.json +96 -0
- package/runtime/sandbox/protocol/schemas/events.schema.json +679 -0
- package/runtime/sandbox/protocol/schemas/http.schema.json +50 -0
package/dist/pushpals-cli.js
CHANGED
|
@@ -101,7 +101,6 @@ function normalizeLoopbackHttpUrl(value, fallbackPort) {
|
|
|
101
101
|
// ../shared/src/config.ts
|
|
102
102
|
var PROJECT_ROOT = resolve(import.meta.dir, "..", "..", "..");
|
|
103
103
|
var DEFAULT_CONFIG_DIR = "configs";
|
|
104
|
-
var LEGACY_CONFIG_DIR = "config";
|
|
105
104
|
var TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
106
105
|
var FALSY = new Set(["0", "false", "no", "off"]);
|
|
107
106
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE = 8;
|
|
@@ -114,6 +113,7 @@ var DEFAULT_WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS = 180000;
|
|
|
114
113
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS = 45000;
|
|
115
114
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MAX_DIFF_CHARS = 16000;
|
|
116
115
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MAX_VALIDATION_OUTPUT_CHARS = 8000;
|
|
116
|
+
var DEFAULT_WORKERPALS_EXECUTOR = "openai_codex";
|
|
117
117
|
var DEFAULT_WORKERPALS_EXECUTOR_RESULT_PREFIX = "__PUSHPALS_OH_RESULT__ ";
|
|
118
118
|
var DEFAULT_REMOTEBUDDY_MEMORY_MAX_RECALL_ITEMS = 12;
|
|
119
119
|
var DEFAULT_REMOTEBUDDY_MEMORY_MAX_RECALL_CHARS = 2400;
|
|
@@ -155,6 +155,12 @@ function parseTomlFile(path) {
|
|
|
155
155
|
return {};
|
|
156
156
|
return parsed;
|
|
157
157
|
}
|
|
158
|
+
function parseRequiredTomlFile(path) {
|
|
159
|
+
if (!existsSync(path)) {
|
|
160
|
+
throw new Error(`Missing required runtime config file: ${path}`);
|
|
161
|
+
}
|
|
162
|
+
return parseTomlFile(path);
|
|
163
|
+
}
|
|
158
164
|
function isObject(value) {
|
|
159
165
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
160
166
|
}
|
|
@@ -260,20 +266,7 @@ function resolveRuntimeConfigDir(projectRoot, configuredDir) {
|
|
|
260
266
|
if (configuredDir && configuredDir.trim()) {
|
|
261
267
|
return resolvePathFromRoot(projectRoot, configuredDir);
|
|
262
268
|
}
|
|
263
|
-
|
|
264
|
-
const legacyDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
265
|
-
if (existsSync(join(canonicalDir, "default.toml")))
|
|
266
|
-
return canonicalDir;
|
|
267
|
-
if (existsSync(join(legacyDir, "default.toml")))
|
|
268
|
-
return legacyDir;
|
|
269
|
-
return canonicalDir;
|
|
270
|
-
}
|
|
271
|
-
function parseTomlWithLegacyFallback(primaryPath, fallbackPath) {
|
|
272
|
-
if (existsSync(primaryPath))
|
|
273
|
-
return parseTomlFile(primaryPath);
|
|
274
|
-
if (fallbackPath && existsSync(fallbackPath))
|
|
275
|
-
return parseTomlFile(fallbackPath);
|
|
276
|
-
return {};
|
|
269
|
+
return resolvePathFromRoot(projectRoot, DEFAULT_CONFIG_DIR);
|
|
277
270
|
}
|
|
278
271
|
function normalizeBackend(value) {
|
|
279
272
|
const text = value.trim().toLowerCase();
|
|
@@ -345,17 +338,15 @@ function loadPushPalsConfig(options = {}) {
|
|
|
345
338
|
const projectRoot = resolve(projectRootOverride);
|
|
346
339
|
const configDirOverride = firstNonEmpty(options.configDir, process.env.PUSHPALS_CONFIG_DIR_OVERRIDE, "");
|
|
347
340
|
const configDir = resolveRuntimeConfigDir(projectRoot, configDirOverride);
|
|
348
|
-
const legacyConfigDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
349
|
-
const fallbackConfigDir = !configDirOverride && configDir !== legacyConfigDir ? legacyConfigDir : "";
|
|
350
341
|
const cacheKey = `${projectRoot}::${configDir}::${process.env.PUSHPALS_PROFILE ?? ""}`;
|
|
351
342
|
if (!options.reload && cachedConfig && cachedConfigKey === cacheKey) {
|
|
352
343
|
return cachedConfig;
|
|
353
344
|
}
|
|
354
|
-
const defaultToml =
|
|
345
|
+
const defaultToml = parseRequiredTomlFile(join(configDir, "default.toml"));
|
|
355
346
|
const preferredProfile = firstNonEmpty(process.env.PUSHPALS_PROFILE, asString(defaultToml.profile, "dev"), "dev");
|
|
356
|
-
const profileToml =
|
|
357
|
-
const localExampleToml =
|
|
358
|
-
const localToml =
|
|
347
|
+
const profileToml = parseTomlFile(join(configDir, `${preferredProfile}.toml`));
|
|
348
|
+
const localExampleToml = parseTomlFile(join(configDir, "local.example.toml"));
|
|
349
|
+
const localToml = parseTomlFile(join(configDir, "local.toml"));
|
|
359
350
|
const merged = mergeDeep(mergeDeep(mergeDeep(defaultToml, profileToml), localExampleToml), localToml);
|
|
360
351
|
const profile = firstNonEmpty(process.env.PUSHPALS_PROFILE, asString(merged.profile, preferredProfile), preferredProfile);
|
|
361
352
|
const sessionId = firstNonEmpty(process.env.PUSHPALS_SESSION_ID, asString(merged.session_id, "dev"), "dev");
|
|
@@ -462,7 +453,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
462
453
|
const workerOpenHandsNode = getObject(workerNode, "openhands");
|
|
463
454
|
const workerPollMs = Math.max(200, asInt(parseIntEnv("WORKERPALS_POLL_MS") ?? workerNode.poll_ms, 2000));
|
|
464
455
|
const workerHeartbeatMs = Math.max(200, asInt(parseIntEnv("WORKERPALS_HEARTBEAT_MS") ?? workerNode.heartbeat_ms, 5000));
|
|
465
|
-
const workerExecutor = firstNonEmpty(process.env.WORKERPALS_EXECUTOR, asString(workerNode.executor,
|
|
456
|
+
const workerExecutor = firstNonEmpty(process.env.WORKERPALS_EXECUTOR, asString(workerNode.executor, DEFAULT_WORKERPALS_EXECUTOR), DEFAULT_WORKERPALS_EXECUTOR).toLowerCase();
|
|
466
457
|
const workerOpenHandsPython = firstNonEmpty(process.env.WORKERPALS_OPENHANDS_PYTHON, asString(workerNode.openhands_python, "python"), "python");
|
|
467
458
|
const workerOpenHandsTimeoutMs = Math.max(1e4, asInt(parseIntEnv("WORKERPALS_OPENHANDS_TIMEOUT_MS") ?? workerNode.openhands_timeout_ms, 1800000));
|
|
468
459
|
const workerMiniswePython = firstNonEmpty(process.env.WORKERPALS_MINISWE_PYTHON, asString(workerNode.miniswe_python, "python"), "python");
|
|
@@ -964,18 +955,10 @@ function resolveClientConfigDir(projectRoot, runtimeRoot, explicitConfigDir) {
|
|
|
964
955
|
if (runtimeHasConfigDir(runtimeRoot, "configs")) {
|
|
965
956
|
return runtimeCanonical;
|
|
966
957
|
}
|
|
967
|
-
const runtimeLegacy = resolve2(runtimeRoot, "config");
|
|
968
|
-
if (runtimeHasConfigDir(runtimeRoot, "config")) {
|
|
969
|
-
return runtimeLegacy;
|
|
970
|
-
}
|
|
971
958
|
const projectCanonical = resolve2(projectRoot, "configs");
|
|
972
959
|
if (runtimeHasConfigDir(projectRoot, "configs")) {
|
|
973
960
|
return projectCanonical;
|
|
974
961
|
}
|
|
975
|
-
const projectLegacy = resolve2(projectRoot, "config");
|
|
976
|
-
if (runtimeHasConfigDir(projectRoot, "config")) {
|
|
977
|
-
return projectLegacy;
|
|
978
|
-
}
|
|
979
962
|
return runtimeCanonical;
|
|
980
963
|
}
|
|
981
964
|
function toDisplayPath(currentRoot, pathValue) {
|
|
@@ -1025,8 +1008,7 @@ function evaluateClientRuntimePreflight(options) {
|
|
|
1025
1008
|
});
|
|
1026
1009
|
}
|
|
1027
1010
|
const localTomlPath = resolve2(runtimeRoot, "configs", "local.toml");
|
|
1028
|
-
|
|
1029
|
-
if (!existsSync2(localTomlPath) && !existsSync2(legacyLocalTomlPath)) {
|
|
1011
|
+
if (!existsSync2(localTomlPath)) {
|
|
1030
1012
|
const localExamplePath = resolve2(runtimeRoot, "configs", "local.example.toml");
|
|
1031
1013
|
issues.push({
|
|
1032
1014
|
code: "missing_local_toml",
|
|
@@ -1472,6 +1454,130 @@ function buildRuntimeAssetSource(root, protocolSchemasDir) {
|
|
|
1472
1454
|
protocolSchemasDir
|
|
1473
1455
|
};
|
|
1474
1456
|
}
|
|
1457
|
+
function buildWorkerpalSandboxPaths(runtimeRoot) {
|
|
1458
|
+
const root = join2(runtimeRoot, "sandbox");
|
|
1459
|
+
return {
|
|
1460
|
+
root,
|
|
1461
|
+
dockerfilePath: join2(root, "apps", "workerpals", "Dockerfile.sandbox"),
|
|
1462
|
+
packageJsonPath: join2(root, "package.json"),
|
|
1463
|
+
workerpalsDir: join2(root, "apps", "workerpals"),
|
|
1464
|
+
sharedDir: join2(root, "packages", "shared"),
|
|
1465
|
+
protocolDir: join2(root, "packages", "protocol"),
|
|
1466
|
+
configsDir: join2(root, "configs"),
|
|
1467
|
+
workerpalsPromptsDir: join2(root, "prompts", "workerpals"),
|
|
1468
|
+
protocolSchemasDir: join2(root, "protocol", "schemas")
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
function normalizeGitTrackedPath(pathValue) {
|
|
1472
|
+
return String(pathValue ?? "").trim().replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
1473
|
+
}
|
|
1474
|
+
function listTrackedRepoFilesForPath(repoRoot, sourcePath) {
|
|
1475
|
+
const normalizedSource = normalizeGitTrackedPath(sourcePath);
|
|
1476
|
+
if (!normalizedSource)
|
|
1477
|
+
return [];
|
|
1478
|
+
const proc = Bun.spawnSync(["git", "ls-files", "-z", "--", normalizedSource], {
|
|
1479
|
+
cwd: repoRoot,
|
|
1480
|
+
stdout: "pipe",
|
|
1481
|
+
stderr: "pipe",
|
|
1482
|
+
env: {
|
|
1483
|
+
...process.env,
|
|
1484
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
1485
|
+
GCM_INTERACTIVE: "Never"
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1488
|
+
if (proc.exitCode !== 0) {
|
|
1489
|
+
const stderr = Buffer.from(proc.stderr ?? []).toString("utf8").trim();
|
|
1490
|
+
throw new Error(`git ls-files failed for ${normalizedSource}${stderr ? `: ${stderr}` : ""}`);
|
|
1491
|
+
}
|
|
1492
|
+
return Buffer.from(proc.stdout ?? []).toString("utf8").split("\x00").map(normalizeGitTrackedPath).filter(Boolean);
|
|
1493
|
+
}
|
|
1494
|
+
function copyTrackedRepoPath(repoRoot, sourcePath, destinationPath, force = true) {
|
|
1495
|
+
const normalizedSource = normalizeGitTrackedPath(sourcePath);
|
|
1496
|
+
if (!normalizedSource) {
|
|
1497
|
+
throw new Error("sourcePath is required");
|
|
1498
|
+
}
|
|
1499
|
+
const absoluteSource = resolve4(repoRoot, normalizedSource);
|
|
1500
|
+
if (!existsSync4(absoluteSource)) {
|
|
1501
|
+
throw new Error(`tracked repo source is missing: ${absoluteSource}`);
|
|
1502
|
+
}
|
|
1503
|
+
const trackedFiles = listTrackedRepoFilesForPath(repoRoot, normalizedSource);
|
|
1504
|
+
const sourceStat = lstatSync(absoluteSource);
|
|
1505
|
+
if (!sourceStat.isDirectory()) {
|
|
1506
|
+
if (!trackedFiles.includes(normalizedSource)) {
|
|
1507
|
+
throw new Error(`tracked repo file is not tracked by git: ${normalizedSource}`);
|
|
1508
|
+
}
|
|
1509
|
+
mkdirSync(dirname(destinationPath), { recursive: true });
|
|
1510
|
+
cpSync(absoluteSource, destinationPath, {
|
|
1511
|
+
recursive: false,
|
|
1512
|
+
force,
|
|
1513
|
+
errorOnExist: false
|
|
1514
|
+
});
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
if (trackedFiles.length === 0) {
|
|
1518
|
+
throw new Error(`tracked repo directory has no tracked files: ${normalizedSource}`);
|
|
1519
|
+
}
|
|
1520
|
+
for (const trackedFile of trackedFiles) {
|
|
1521
|
+
const relativePath = trackedFile === normalizedSource ? basename(trackedFile) : trackedFile.slice(normalizedSource.length + 1);
|
|
1522
|
+
const sourceFile = resolve4(repoRoot, trackedFile);
|
|
1523
|
+
const targetFile = join2(destinationPath, relativePath);
|
|
1524
|
+
mkdirSync(dirname(targetFile), { recursive: true });
|
|
1525
|
+
cpSync(sourceFile, targetFile, {
|
|
1526
|
+
recursive: false,
|
|
1527
|
+
force,
|
|
1528
|
+
errorOnExist: false
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
function isCompleteWorkerpalSandboxRoot(root) {
|
|
1533
|
+
return existsSync4(join2(root, "package.json")) && existsSync4(join2(root, "apps", "workerpals", "Dockerfile.sandbox")) && existsSync4(join2(root, "packages", "shared", "package.json")) && existsSync4(join2(root, "packages", "protocol", "package.json")) && existsSync4(join2(root, "configs", "default.toml")) && existsSync4(join2(root, "prompts", "workerpals")) && existsSync4(join2(root, "protocol", "schemas", "envelope.schema.json")) && existsSync4(join2(root, "protocol", "schemas", "events.schema.json"));
|
|
1534
|
+
}
|
|
1535
|
+
function populateWorkerpalSandboxRuntimeAssets(runtimeRoot, force) {
|
|
1536
|
+
const sandbox = buildWorkerpalSandboxPaths(runtimeRoot);
|
|
1537
|
+
cpSync(join2(runtimeRoot, "configs"), sandbox.configsDir, {
|
|
1538
|
+
recursive: true,
|
|
1539
|
+
force,
|
|
1540
|
+
errorOnExist: false
|
|
1541
|
+
});
|
|
1542
|
+
cpSync(join2(runtimeRoot, "prompts", "workerpals"), sandbox.workerpalsPromptsDir, {
|
|
1543
|
+
recursive: true,
|
|
1544
|
+
force,
|
|
1545
|
+
errorOnExist: false
|
|
1546
|
+
});
|
|
1547
|
+
cpSync(join2(runtimeRoot, "protocol", "schemas"), sandbox.protocolSchemasDir, {
|
|
1548
|
+
recursive: true,
|
|
1549
|
+
force,
|
|
1550
|
+
errorOnExist: false
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
function copySourceCheckoutWorkerpalSandboxBuildContext(sourceRoot, runtimeRoot, force) {
|
|
1554
|
+
const sandbox = buildWorkerpalSandboxPaths(runtimeRoot);
|
|
1555
|
+
const copyPairs = [
|
|
1556
|
+
["package.json", sandbox.packageJsonPath],
|
|
1557
|
+
["apps/workerpals", sandbox.workerpalsDir],
|
|
1558
|
+
["packages/shared", sandbox.sharedDir],
|
|
1559
|
+
["packages/protocol", sandbox.protocolDir]
|
|
1560
|
+
];
|
|
1561
|
+
for (const [fromPath, toPath] of copyPairs) {
|
|
1562
|
+
copyTrackedRepoPath(sourceRoot, fromPath, toPath, force);
|
|
1563
|
+
}
|
|
1564
|
+
if (existsSync4(join2(sourceRoot, "bun.lock"))) {
|
|
1565
|
+
copyTrackedRepoPath(sourceRoot, "bun.lock", join2(sandbox.root, "bun.lock"), force);
|
|
1566
|
+
}
|
|
1567
|
+
populateWorkerpalSandboxRuntimeAssets(runtimeRoot, force);
|
|
1568
|
+
}
|
|
1569
|
+
function copyWorkerpalSandboxBuildContext(source, runtimeRoot, force) {
|
|
1570
|
+
const packagedSandboxRoot = join2(source.root, "sandbox");
|
|
1571
|
+
if (isCompleteWorkerpalSandboxRoot(packagedSandboxRoot)) {
|
|
1572
|
+
cpSync(packagedSandboxRoot, join2(runtimeRoot, "sandbox"), {
|
|
1573
|
+
recursive: true,
|
|
1574
|
+
force,
|
|
1575
|
+
errorOnExist: false
|
|
1576
|
+
});
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
copySourceCheckoutWorkerpalSandboxBuildContext(source.root, runtimeRoot, force);
|
|
1580
|
+
}
|
|
1475
1581
|
function isCompleteRuntimeAssetSource(source) {
|
|
1476
1582
|
return existsSync4(source.envExamplePath) && existsSync4(source.visionExamplePath) && existsSync4(join2(source.configsDir, "default.toml")) && existsSync4(source.promptsDir) && existsSync4(join2(source.protocolSchemasDir, "envelope.schema.json")) && existsSync4(join2(source.protocolSchemasDir, "events.schema.json"));
|
|
1477
1583
|
}
|
|
@@ -1658,6 +1764,7 @@ function copyRuntimeAssetBundle(source, runtimeRoot, force) {
|
|
|
1658
1764
|
force,
|
|
1659
1765
|
errorOnExist: false
|
|
1660
1766
|
});
|
|
1767
|
+
copyWorkerpalSandboxBuildContext(source, runtimeRoot, force);
|
|
1661
1768
|
}
|
|
1662
1769
|
function copyBundledRuntimeAssets(runtimeRoot, force = true) {
|
|
1663
1770
|
const bundledSource = resolveBundledRuntimeAssetSource();
|
|
@@ -1693,7 +1800,7 @@ async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
|
1693
1800
|
throw new Error(`Failed to fetch runtime source tree for ${tag} (HTTP ${treeResponse.status})`);
|
|
1694
1801
|
}
|
|
1695
1802
|
const treePayload = await treeResponse.json();
|
|
1696
|
-
const paths = (treePayload.tree ?? []).filter((entry) => entry.type === "blob" && typeof entry.path === "string").map((entry) => String(entry.path)).filter((pathValue) => pathValue === ".env.example" || pathValue === "vision.example.md" || pathValue.startsWith("configs/") || pathValue.startsWith("prompts/") || pathValue.startsWith("packages/protocol/src/schemas/"));
|
|
1803
|
+
const paths = (treePayload.tree ?? []).filter((entry) => entry.type === "blob" && typeof entry.path === "string").map((entry) => String(entry.path)).filter((pathValue) => pathValue === ".env.example" || pathValue === "vision.example.md" || pathValue === "package.json" || pathValue === "bun.lock" || pathValue.startsWith("configs/") || pathValue.startsWith("prompts/workerpals/") || pathValue.startsWith("prompts/") || pathValue.startsWith("apps/workerpals/") || pathValue.startsWith("packages/shared/") || pathValue.startsWith("packages/protocol/") || pathValue.startsWith("packages/protocol/src/schemas/"));
|
|
1697
1804
|
if (paths.length === 0) {
|
|
1698
1805
|
throw new Error(`Runtime source tree for ${tag} did not include prompts/config assets`);
|
|
1699
1806
|
}
|
|
@@ -1701,10 +1808,16 @@ async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
|
1701
1808
|
for (const pathValue of sorted) {
|
|
1702
1809
|
const rawUrl = `https://raw.githubusercontent.com/${GITHUB_OWNER}/${GITHUB_REPO}/${encodeURIComponent(tag)}/${pathValue}`;
|
|
1703
1810
|
const body = await fetchTextFromUrl(rawUrl, 20000);
|
|
1704
|
-
const outPath = pathValue.
|
|
1811
|
+
const outPath = pathValue === "package.json" || pathValue === "bun.lock" ? join2(runtimeRoot, "sandbox", pathValue) : pathValue.startsWith("apps/workerpals/") || pathValue.startsWith("packages/shared/") || pathValue.startsWith("packages/protocol/") ? join2(runtimeRoot, "sandbox", pathValue) : join2(runtimeRoot, pathValue);
|
|
1705
1812
|
mkdirSync(dirname(outPath), { recursive: true });
|
|
1706
1813
|
writeFileSync(outPath, body, "utf8");
|
|
1814
|
+
if (pathValue.startsWith("packages/protocol/src/schemas/")) {
|
|
1815
|
+
const runtimeSchemaPath = join2(runtimeRoot, "protocol", "schemas", pathValue.slice("packages/protocol/src/schemas/".length));
|
|
1816
|
+
mkdirSync(dirname(runtimeSchemaPath), { recursive: true });
|
|
1817
|
+
writeFileSync(runtimeSchemaPath, body, "utf8");
|
|
1818
|
+
}
|
|
1707
1819
|
}
|
|
1820
|
+
populateWorkerpalSandboxRuntimeAssets(runtimeRoot, true);
|
|
1708
1821
|
}
|
|
1709
1822
|
async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
1710
1823
|
console.log(`[pushpals] Preparing embedded runtime assets for ${runtimeTag}...`);
|
|
@@ -1712,12 +1825,12 @@ async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
|
1712
1825
|
const currentTag = existsSync4(markerPath) ? readFileSync4(markerPath, "utf8").trim() : "";
|
|
1713
1826
|
const protocolSchemasDir = join2(runtimeRoot, "protocol", "schemas");
|
|
1714
1827
|
const hasProtocolSchemas = existsSync4(join2(protocolSchemasDir, "envelope.schema.json")) && existsSync4(join2(protocolSchemasDir, "events.schema.json"));
|
|
1715
|
-
const hasAssets = existsSync4(join2(runtimeRoot, ".env.example")) && existsSync4(join2(runtimeRoot, "vision.example.md")) && existsSync4(join2(runtimeRoot, "configs", "default.toml")) && existsSync4(join2(runtimeRoot, "prompts")) && hasProtocolSchemas;
|
|
1828
|
+
const hasAssets = existsSync4(join2(runtimeRoot, ".env.example")) && existsSync4(join2(runtimeRoot, "vision.example.md")) && existsSync4(join2(runtimeRoot, "configs", "default.toml")) && existsSync4(join2(runtimeRoot, "prompts")) && hasProtocolSchemas && isCompleteWorkerpalSandboxRoot(join2(runtimeRoot, "sandbox"));
|
|
1716
1829
|
if (!hasAssets || currentTag !== runtimeTag) {
|
|
1717
1830
|
console.log(`[pushpals] Embedded runtime assets ${hasAssets ? "are stale" : "are missing"}; refreshing bundle...`);
|
|
1718
1831
|
copyBundledRuntimeAssets(runtimeRoot);
|
|
1719
1832
|
const hasProtocolSchemasAfterCopy = existsSync4(join2(protocolSchemasDir, "envelope.schema.json")) && existsSync4(join2(protocolSchemasDir, "events.schema.json"));
|
|
1720
|
-
const hasAssetsAfterCopy = existsSync4(join2(runtimeRoot, ".env.example")) && existsSync4(join2(runtimeRoot, "vision.example.md")) && existsSync4(join2(runtimeRoot, "configs", "default.toml")) && existsSync4(join2(runtimeRoot, "prompts")) && hasProtocolSchemasAfterCopy;
|
|
1833
|
+
const hasAssetsAfterCopy = existsSync4(join2(runtimeRoot, ".env.example")) && existsSync4(join2(runtimeRoot, "vision.example.md")) && existsSync4(join2(runtimeRoot, "configs", "default.toml")) && existsSync4(join2(runtimeRoot, "prompts")) && hasProtocolSchemasAfterCopy && isCompleteWorkerpalSandboxRoot(join2(runtimeRoot, "sandbox"));
|
|
1721
1834
|
if (!hasAssetsAfterCopy) {
|
|
1722
1835
|
console.log("[pushpals] Bundled runtime assets are incomplete; falling back to release source downloads...");
|
|
1723
1836
|
await downloadRuntimeAssetsFromSourceTag(runtimeRoot, runtimeTag);
|
|
@@ -1787,7 +1900,9 @@ function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
|
1787
1900
|
PUSHPALS_PROJECT_ROOT_OVERRIDE: opts.repoRoot,
|
|
1788
1901
|
...useRuntimeConfig ? {
|
|
1789
1902
|
PUSHPALS_CONFIG_DIR_OVERRIDE: join2(opts.runtimeRoot, "configs"),
|
|
1790
|
-
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.runtimeRoot
|
|
1903
|
+
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.runtimeRoot,
|
|
1904
|
+
PUSHPALS_WORKERPALS_SANDBOX_ROOT: join2(opts.runtimeRoot, "sandbox"),
|
|
1905
|
+
...typeof opts.runtimeTag === "string" && opts.runtimeTag.trim() ? { PUSHPALS_RUNTIME_TAG: opts.runtimeTag.trim() } : {}
|
|
1791
1906
|
} : {
|
|
1792
1907
|
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.repoRoot
|
|
1793
1908
|
},
|
|
@@ -2263,6 +2378,116 @@ async function resolveWorkerpalDockerProbe(cwd, env, platform = process.platform
|
|
|
2263
2378
|
detail: failures.join(" | ") || "docker"
|
|
2264
2379
|
};
|
|
2265
2380
|
}
|
|
2381
|
+
var WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL = "pushpals.runtime_tag";
|
|
2382
|
+
var WORKERPAL_SANDBOX_COMPONENT_LABEL = "pushpals.component=workerpals-sandbox";
|
|
2383
|
+
function resolveConfiguredDockerExecutable(env, platform = process.platform) {
|
|
2384
|
+
const configured = String(env.PUSHPALS_DOCKER_BIN_ABSOLUTE ?? env.PUSHPALS_DOCKER_BIN ?? (platform === "win32" ? "docker.exe" : "docker")).trim();
|
|
2385
|
+
return configured || (platform === "win32" ? "docker.exe" : "docker");
|
|
2386
|
+
}
|
|
2387
|
+
async function inspectDockerImageRuntimeTag(dockerExecutable, imageName, cwd, env) {
|
|
2388
|
+
const inspect = await runCommandWithEnv([
|
|
2389
|
+
dockerExecutable,
|
|
2390
|
+
"image",
|
|
2391
|
+
"inspect",
|
|
2392
|
+
"--format",
|
|
2393
|
+
`{{ index .Config.Labels "${WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL}" }}`,
|
|
2394
|
+
imageName
|
|
2395
|
+
], cwd, env);
|
|
2396
|
+
if (!inspect.ok)
|
|
2397
|
+
return "";
|
|
2398
|
+
const value = inspect.stdout.trim();
|
|
2399
|
+
return value === "<no value>" ? "" : value;
|
|
2400
|
+
}
|
|
2401
|
+
async function ensureWorkerpalDockerImageReady(opts) {
|
|
2402
|
+
const runtimeTag = String(opts.runtimeTag ?? "").trim();
|
|
2403
|
+
if (!runtimeTag) {
|
|
2404
|
+
return {
|
|
2405
|
+
ok: false,
|
|
2406
|
+
detail: "embedded runtime tag is required to prepare the WorkerPal sandbox image"
|
|
2407
|
+
};
|
|
2408
|
+
}
|
|
2409
|
+
await (opts.ensureRuntimeAssetsFn ?? ensureRuntimeAssets)(opts.runtimeRoot, runtimeTag);
|
|
2410
|
+
const sandbox = buildWorkerpalSandboxPaths(opts.runtimeRoot);
|
|
2411
|
+
if (!isCompleteWorkerpalSandboxRoot(sandbox.root)) {
|
|
2412
|
+
return {
|
|
2413
|
+
ok: false,
|
|
2414
|
+
detail: `embedded WorkerPal sandbox assets are incomplete at ${sandbox.root}`
|
|
2415
|
+
};
|
|
2416
|
+
}
|
|
2417
|
+
const dockerExecutable = resolveConfiguredDockerExecutable(opts.env, opts.platform ?? process.platform);
|
|
2418
|
+
const inspectImageRuntimeTagFn = opts.inspectImageRuntimeTagFn ?? inspectDockerImageRuntimeTag;
|
|
2419
|
+
const runCommandWithEnvFn = opts.runCommandWithEnvFn ?? runCommandWithEnv;
|
|
2420
|
+
const existingRuntimeTag = await inspectImageRuntimeTagFn(dockerExecutable, opts.dockerImage, sandbox.root, opts.env);
|
|
2421
|
+
if (existingRuntimeTag === runtimeTag) {
|
|
2422
|
+
return {
|
|
2423
|
+
ok: true,
|
|
2424
|
+
detail: `WorkerPal sandbox image is ready locally (${opts.dockerImage}, runtimeTag=${runtimeTag})`
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
console.log(existingRuntimeTag ? `[pushpals] WorkerPal sandbox image ${opts.dockerImage} is stale (runtimeTag=${existingRuntimeTag}); rebuilding locally...` : `[pushpals] WorkerPal sandbox image ${opts.dockerImage} is missing; building locally...`);
|
|
2428
|
+
const build = await runCommandWithEnvFn([
|
|
2429
|
+
dockerExecutable,
|
|
2430
|
+
"build",
|
|
2431
|
+
"-f",
|
|
2432
|
+
"apps/workerpals/Dockerfile.sandbox",
|
|
2433
|
+
"--label",
|
|
2434
|
+
`${WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL}=${runtimeTag}`,
|
|
2435
|
+
"--label",
|
|
2436
|
+
WORKERPAL_SANDBOX_COMPONENT_LABEL,
|
|
2437
|
+
"-t",
|
|
2438
|
+
opts.dockerImage,
|
|
2439
|
+
"."
|
|
2440
|
+
], sandbox.root, opts.env);
|
|
2441
|
+
if (!build.ok) {
|
|
2442
|
+
const detail = build.stderr || build.stdout || `docker build exited ${build.exitCode}`;
|
|
2443
|
+
return {
|
|
2444
|
+
ok: false,
|
|
2445
|
+
detail: `failed to build local WorkerPal sandbox image ${opts.dockerImage}: ${detail}`
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
return {
|
|
2449
|
+
ok: true,
|
|
2450
|
+
detail: `built local WorkerPal sandbox image ${opts.dockerImage} for runtimeTag=${runtimeTag}`
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
async function prepareEmbeddedWorkerpalDockerImageIfNeeded(opts) {
|
|
2454
|
+
if (!opts.preparedRuntime.preflightUsesEmbeddedRuntime) {
|
|
2455
|
+
return {
|
|
2456
|
+
status: "skipped",
|
|
2457
|
+
detail: "repo is using source-checkout runtime assets",
|
|
2458
|
+
runtimeTag: ""
|
|
2459
|
+
};
|
|
2460
|
+
}
|
|
2461
|
+
if (!opts.config.remotebuddy.autoSpawnWorkerpals || !opts.config.remotebuddy.workerpalDocker || !opts.config.remotebuddy.workerpalRequireDocker) {
|
|
2462
|
+
return {
|
|
2463
|
+
status: "skipped",
|
|
2464
|
+
detail: "embedded docker-backed WorkerPal auto-spawn is not required",
|
|
2465
|
+
runtimeTag: ""
|
|
2466
|
+
};
|
|
2467
|
+
}
|
|
2468
|
+
if (opts.dockerPrecheck.status === "failed") {
|
|
2469
|
+
return {
|
|
2470
|
+
status: "failed",
|
|
2471
|
+
detail: opts.dockerPrecheck.detail,
|
|
2472
|
+
runtimeTag: ""
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
const runtimeTag = opts.preparedRuntime.runtimeTag || String(opts.runtimeTagHint ?? "").trim() || await (opts.resolveRuntimeReleaseTagFn ?? resolveRuntimeReleaseTag)(opts.runtimeTagHint);
|
|
2476
|
+
if (!runtimeTag) {
|
|
2477
|
+
return {
|
|
2478
|
+
status: "failed",
|
|
2479
|
+
detail: "embedded runtime tag is required to prepare the WorkerPal sandbox image",
|
|
2480
|
+
runtimeTag: ""
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
const ensureResult = await (opts.ensureWorkerpalDockerImageReadyFn ?? ensureWorkerpalDockerImageReady)({
|
|
2484
|
+
runtimeRoot: opts.preparedRuntime.runtimeRoot,
|
|
2485
|
+
runtimeTag,
|
|
2486
|
+
dockerImage: opts.config.remotebuddy.workerpalImage ?? opts.config.workerpals.dockerImage,
|
|
2487
|
+
env: opts.dockerPrecheck.env
|
|
2488
|
+
});
|
|
2489
|
+
return ensureResult.ok ? { status: "ok", detail: ensureResult.detail, runtimeTag } : { status: "failed", detail: ensureResult.detail, runtimeTag };
|
|
2490
|
+
}
|
|
2266
2491
|
async function precheckSourceControlManagerGitAvailability(opts) {
|
|
2267
2492
|
const platform = opts.platform ?? process.platform;
|
|
2268
2493
|
const env = buildEmbeddedRuntimeEnv(opts.baseEnv ?? process.env, {
|
|
@@ -2824,7 +3049,8 @@ async function autoStartRuntimeServices(opts) {
|
|
|
2824
3049
|
repoRoot: opts.repoRoot,
|
|
2825
3050
|
runtimeRoot,
|
|
2826
3051
|
useRuntimeConfig: opts.preparedRuntime.preflightUsesEmbeddedRuntime,
|
|
2827
|
-
sessionId: opts.sessionId
|
|
3052
|
+
sessionId: opts.sessionId,
|
|
3053
|
+
runtimeTag
|
|
2828
3054
|
});
|
|
2829
3055
|
runtimeEnv.PUSHPALS_WORKERPALS_BIN = runtimeBinaries.workerpals;
|
|
2830
3056
|
const preconfiguredRuntimeGitBinary = runtimeEnv.PUSHPALS_GIT_BIN_ABSOLUTE ?? runtimeEnv.PUSHPALS_GIT_BIN;
|
|
@@ -3642,6 +3868,7 @@ async function main() {
|
|
|
3642
3868
|
};
|
|
3643
3869
|
let autoStartedServices = [];
|
|
3644
3870
|
let pushpalsLogPath;
|
|
3871
|
+
let resolvedRuntimeTagForAutoStart = preparedRuntime.runtimeTag || parsed.runtimeTag || "";
|
|
3645
3872
|
const stopAutoStartedServices = () => {
|
|
3646
3873
|
if (autoStartedServices.length === 0)
|
|
3647
3874
|
return;
|
|
@@ -3650,17 +3877,32 @@ async function main() {
|
|
|
3650
3877
|
};
|
|
3651
3878
|
let serverHealthy = await probeServer(serverUrl);
|
|
3652
3879
|
const serverWasAlreadyHealthy = serverHealthy;
|
|
3880
|
+
if (!serverHealthy && workerpalDockerPrecheck.status === "failed") {
|
|
3881
|
+
console.error(`[pushpals] Precheck failed: Docker-backed WorkerPal auto-spawn is required but Docker is unavailable (${workerpalDockerPrecheck.detail}).`);
|
|
3882
|
+
console.error("[pushpals] Precheck failed: start Docker Desktop or the Docker daemon, then retry pushpals.");
|
|
3883
|
+
process.exit(1);
|
|
3884
|
+
}
|
|
3885
|
+
if (workerpalDockerPrecheck.status !== "failed") {
|
|
3886
|
+
const workerpalImagePrecheck = await prepareEmbeddedWorkerpalDockerImageIfNeeded({
|
|
3887
|
+
preparedRuntime,
|
|
3888
|
+
config,
|
|
3889
|
+
dockerPrecheck: workerpalDockerPrecheck,
|
|
3890
|
+
runtimeTagHint: resolvedRuntimeTagForAutoStart || parsed.runtimeTag
|
|
3891
|
+
});
|
|
3892
|
+
if (workerpalImagePrecheck.status === "failed") {
|
|
3893
|
+
console.error(`[pushpals] Precheck failed: ${workerpalImagePrecheck.detail}.`);
|
|
3894
|
+
process.exit(1);
|
|
3895
|
+
}
|
|
3896
|
+
if (workerpalImagePrecheck.runtimeTag) {
|
|
3897
|
+
resolvedRuntimeTagForAutoStart = workerpalImagePrecheck.runtimeTag;
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3653
3900
|
let remoteBuddyConsumerHealth = {
|
|
3654
3901
|
ok: false,
|
|
3655
3902
|
detail: `No connected RemoteBuddy session consumer found for session ${sessionId}`
|
|
3656
3903
|
};
|
|
3657
3904
|
if (!serverHealthy) {
|
|
3658
3905
|
if (!parsed.noAutoStart) {
|
|
3659
|
-
if (workerpalDockerPrecheck.status === "failed") {
|
|
3660
|
-
console.error(`[pushpals] Precheck failed: Docker-backed WorkerPal auto-spawn is required but Docker is unavailable (${workerpalDockerPrecheck.detail}).`);
|
|
3661
|
-
console.error("[pushpals] Precheck failed: start Docker Desktop or the Docker daemon, then retry pushpals.");
|
|
3662
|
-
process.exit(1);
|
|
3663
|
-
}
|
|
3664
3906
|
try {
|
|
3665
3907
|
const startedRuntime = await autoStartRuntimeServices({
|
|
3666
3908
|
repoRoot,
|
|
@@ -3670,7 +3912,7 @@ async function main() {
|
|
|
3670
3912
|
sourceControlManagerPort: config.sourceControlManager.port,
|
|
3671
3913
|
sourceControlManagerRemote: config.sourceControlManager.remote,
|
|
3672
3914
|
preparedRuntime,
|
|
3673
|
-
requestedRuntimeTag: parsed.runtimeTag,
|
|
3915
|
+
requestedRuntimeTag: resolvedRuntimeTagForAutoStart || parsed.runtimeTag,
|
|
3674
3916
|
startLocalBuddy: resolveCliLocalBuddyAutostart(parsed.runtimeOnly, Boolean(config.localbuddy.enabled)),
|
|
3675
3917
|
baseEnv: workerpalDockerPrecheck.env
|
|
3676
3918
|
});
|
|
@@ -3929,6 +4171,7 @@ export {
|
|
|
3929
4171
|
resolveCliLocalBuddyAutostart,
|
|
3930
4172
|
resolveBundledRuntimeAssetSource,
|
|
3931
4173
|
resolveBundledMonitoringHubRoot,
|
|
4174
|
+
prepareEmbeddedWorkerpalDockerImageIfNeeded,
|
|
3932
4175
|
prepareCliRuntime,
|
|
3933
4176
|
precheckWorkerpalDockerAvailability,
|
|
3934
4177
|
precheckSourceControlManagerGitAvailability,
|
|
@@ -3941,7 +4184,11 @@ export {
|
|
|
3941
4184
|
formatSessionEventLine,
|
|
3942
4185
|
extractRemoteBuddySessionConsumerHealth,
|
|
3943
4186
|
extractRemoteBuddyAutonomousEngineState,
|
|
4187
|
+
ensureWorkerpalDockerImageReady,
|
|
4188
|
+
downloadRuntimeAssetsFromSourceTag,
|
|
4189
|
+
copyTrackedRepoPath,
|
|
3944
4190
|
bundledMonitoringHubNeedsRefresh,
|
|
4191
|
+
buildWorkerpalSandboxPaths,
|
|
3945
4192
|
buildServiceStopCommand,
|
|
3946
4193
|
buildRuntimeServiceLogPaths,
|
|
3947
4194
|
buildOpenMonitoringHubCommand,
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# PushPals Worker Sandbox Dockerfile
|
|
2
|
+
# This image provides an isolated environment for job execution
|
|
3
|
+
# The entire monorepo is available in the container for job execution
|
|
4
|
+
|
|
5
|
+
FROM oven/bun:1-debian AS base
|
|
6
|
+
|
|
7
|
+
# Install git and other essential tools
|
|
8
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
9
|
+
git \
|
|
10
|
+
curl \
|
|
11
|
+
ca-certificates \
|
|
12
|
+
openssh-client \
|
|
13
|
+
grep \
|
|
14
|
+
jq \
|
|
15
|
+
ripgrep \
|
|
16
|
+
fd-find \
|
|
17
|
+
less \
|
|
18
|
+
unzip \
|
|
19
|
+
zip \
|
|
20
|
+
procps \
|
|
21
|
+
dnsutils \
|
|
22
|
+
iputils-ping \
|
|
23
|
+
python3 \
|
|
24
|
+
python3-venv \
|
|
25
|
+
python3-pip \
|
|
26
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
27
|
+
|
|
28
|
+
# Worker runtime in one shared venv (uv default layout).
|
|
29
|
+
# Keep the venv at /workspace/.venv so all backends use the same Python runtime.
|
|
30
|
+
RUN mkdir -p /workspace \
|
|
31
|
+
&& python3 -m venv /workspace/.venv \
|
|
32
|
+
&& /workspace/.venv/bin/pip install --no-cache-dir --upgrade pip \
|
|
33
|
+
&& /workspace/.venv/bin/pip install --no-cache-dir \
|
|
34
|
+
openhands-sdk \
|
|
35
|
+
openhands-agent-server \
|
|
36
|
+
openhands-workspace \
|
|
37
|
+
openhands-tools \
|
|
38
|
+
mini-swe-agent \
|
|
39
|
+
playwright \
|
|
40
|
+
&& bun add -g @openai/codex \
|
|
41
|
+
&& /workspace/.venv/bin/playwright install --with-deps chromium
|
|
42
|
+
|
|
43
|
+
ENV PATH="/workspace/.venv/bin:/root/.bun/bin:${PATH}"
|
|
44
|
+
ENV WORKERPALS_OPENHANDS_PYTHON="/workspace/.venv/bin/python"
|
|
45
|
+
ENV WORKERPALS_OPENHANDS_WORKSPACE_PYTHON="/workspace/.venv/bin/python"
|
|
46
|
+
ENV WORKERPALS_MINISWE_PYTHON="/workspace/.venv/bin/python"
|
|
47
|
+
ENV PUSHPALS_OPENAI_CODEX_PYTHON="/workspace/.venv/bin/python"
|
|
48
|
+
|
|
49
|
+
# Configure git for the worker
|
|
50
|
+
RUN git config --global user.name "PushPals Worker" \
|
|
51
|
+
&& git config --global user.email "worker@pushpals.local" \
|
|
52
|
+
&& git config --global safe.directory '*' \
|
|
53
|
+
&& git config --global core.autocrlf input
|
|
54
|
+
|
|
55
|
+
# Set up the full monorepo structure
|
|
56
|
+
WORKDIR /workspace
|
|
57
|
+
|
|
58
|
+
# Copy entire repository (build context should be repo root)
|
|
59
|
+
COPY . .
|
|
60
|
+
|
|
61
|
+
# Install workspace dependencies (including devDeps needed for protocol build)
|
|
62
|
+
RUN bun install
|
|
63
|
+
|
|
64
|
+
# Build protocol package (needed by worker)
|
|
65
|
+
RUN cd packages/protocol && bun run build
|
|
66
|
+
|
|
67
|
+
# Set working directory for job execution
|
|
68
|
+
WORKDIR /workspace
|
|
69
|
+
|
|
70
|
+
# Default entrypoint runs the job runner with base64-encoded job spec
|
|
71
|
+
ENTRYPOINT ["bun", "run", "/workspace/apps/workerpals/src/job_runner.ts"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "workerpals",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "bun --watch --no-clear-screen src/workerpals_main.ts",
|
|
7
|
+
"start": "bun run src/workerpals_main.ts",
|
|
8
|
+
"build:sandbox": "docker build -f Dockerfile.sandbox -t pushpals-worker-sandbox:latest ../..",
|
|
9
|
+
"docker:build": "docker build -f Dockerfile.sandbox -t pushpals-worker-sandbox:latest ../..",
|
|
10
|
+
"docker:build:local": "docker build -f Dockerfile.sandbox -t pushpals-worker-sandbox:local ../..",
|
|
11
|
+
"docker:run": "docker run --rm -it pushpals-worker-sandbox:latest",
|
|
12
|
+
"dev:docker": "bun run src/workerpals_main.ts --docker",
|
|
13
|
+
"workerpals:docker": "bun run src/workerpals_main.ts --docker",
|
|
14
|
+
"workerpals:docker:local": "bun run src/workerpals_main.ts --docker --docker-image pushpals-worker-sandbox:local"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"protocol": "workspace:*",
|
|
18
|
+
"shared": "workspace:*"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "~5.9.2",
|
|
22
|
+
"@types/bun": "latest"
|
|
23
|
+
},
|
|
24
|
+
"private": true
|
|
25
|
+
}
|