@pushpalsdev/cli 1.0.83 → 1.0.85
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 +11 -1
- package/package.json +1 -1
- package/runtime/configs/default.toml +8 -1
- package/runtime/configs/local.example.toml +8 -1
- package/runtime/sandbox/.pushpals-remotebuddy-fallback.js +21 -1
- package/runtime/sandbox/apps/workerpals/src/backends/openhands_task_execute.ts +2 -1
- package/runtime/sandbox/apps/workerpals/src/common/generic_python_executor.ts +2 -1
- package/runtime/sandbox/apps/workerpals/src/common/sandbox_env.ts +76 -0
- package/runtime/sandbox/apps/workerpals/src/execute_job.ts +348 -133
- package/runtime/sandbox/configs/default.toml +8 -1
- package/runtime/sandbox/configs/local.example.toml +8 -1
- package/runtime/sandbox/packages/shared/src/config.ts +34 -1
- package/runtime/sandbox/packages/shared/src/toolchain.ts +207 -15
package/dist/pushpals-cli.js
CHANGED
|
@@ -450,7 +450,7 @@ var DEFAULT_CONFIG_DIR = "configs";
|
|
|
450
450
|
var TRUTHY2 = new Set(["1", "true", "yes", "on"]);
|
|
451
451
|
var FALSY2 = new Set(["0", "false", "no", "off"]);
|
|
452
452
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE = 8;
|
|
453
|
-
var DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS =
|
|
453
|
+
var DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS = 3;
|
|
454
454
|
var DEFAULT_WORKERPALS_FILE_MODIFYING_JOBS = ["task.execute"];
|
|
455
455
|
var DEFAULT_WORKERPALS_OUTPUT_MAX_CHARS = 192 * 1024;
|
|
456
456
|
var DEFAULT_WORKERPALS_OUTPUT_MAX_LINES = 600;
|
|
@@ -817,6 +817,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
817
817
|
const workerOpenAICodexPython = firstNonEmpty(process.env.PUSHPALS_OPENAI_CODEX_PYTHON, asString(workerNode.openai_codex_python, "python"), "python");
|
|
818
818
|
const workerOpenAICodexTimeoutMs = Math.max(1e4, asInt(workerNode.openai_codex_timeout_ms, 7200000));
|
|
819
819
|
const workerQualityMaxAutoRevisions = Math.max(0, Math.min(10, asInt(parseIntEnv("WORKERPALS_QUALITY_MAX_AUTO_REVISIONS") ?? workerNode.quality_max_auto_revisions, DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS)));
|
|
820
|
+
const workerQualityValidationMaxAutoRevisions = Math.max(0, Math.min(10, asInt(parseIntEnv("WORKERPALS_QUALITY_VALIDATION_MAX_AUTO_REVISIONS") ?? workerNode.quality_validation_max_auto_revisions, DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS)));
|
|
820
821
|
const workerFileModifyingJobs = (() => {
|
|
821
822
|
const envRaw = firstNonEmpty(process.env.WORKERPALS_FILE_MODIFYING_JOBS);
|
|
822
823
|
const parsed = envRaw ? envRaw.split(",").map((entry) => entry.trim()).filter(Boolean) : asStringArray(workerNode.file_modifying_jobs);
|
|
@@ -829,6 +830,10 @@ function loadPushPalsConfig(options = {}) {
|
|
|
829
830
|
const workerQualityValidationStepTimeoutMs = Math.max(1000, asInt(parseIntEnv("WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS") ?? workerNode.quality_validation_step_timeout_ms, DEFAULT_WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS));
|
|
830
831
|
const workerQualityCriticTimeoutMs = Math.max(1000, asInt(parseIntEnv("WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS") ?? workerNode.quality_critic_timeout_ms, DEFAULT_WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS));
|
|
831
832
|
const workerQualitySoftPassOnExhausted = parseBoolEnv("WORKERPALS_QUALITY_SOFT_PASS_ON_EXHAUSTED") ?? asBoolean(workerNode.quality_soft_pass_on_exhausted, true);
|
|
833
|
+
const workerQualityScopeGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_SCOPE_GATE_ENABLED") ?? asBoolean(workerNode.quality_scope_gate_enabled, true);
|
|
834
|
+
const workerQualityValidationGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_VALIDATION_GATE_ENABLED") ?? asBoolean(workerNode.quality_validation_gate_enabled, true);
|
|
835
|
+
const workerQualityCriticGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_CRITIC_GATE_ENABLED") ?? asBoolean(workerNode.quality_critic_gate_enabled, true);
|
|
836
|
+
const workerQualityPublishGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_PUBLISH_GATE_ENABLED") ?? asBoolean(workerNode.quality_publish_gate_enabled, true);
|
|
832
837
|
const workerQualityCriticMinScore = (() => {
|
|
833
838
|
const configThresholdRaw = workerNode.quality_critic_min_score == null ? "" : String(workerNode.quality_critic_min_score);
|
|
834
839
|
const raw = firstNonEmpty(process.env.WORKERPALS_QUALITY_CRITIC_MIN_SCORE, configThresholdRaw, String(DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE));
|
|
@@ -1119,6 +1124,11 @@ function loadPushPalsConfig(options = {}) {
|
|
|
1119
1124
|
outputMaxLines: workerOutputMaxLines,
|
|
1120
1125
|
outputMaxHeadLines: workerOutputMaxHeadLines,
|
|
1121
1126
|
qualityMaxAutoRevisions: workerQualityMaxAutoRevisions,
|
|
1127
|
+
qualityValidationMaxAutoRevisions: workerQualityValidationMaxAutoRevisions,
|
|
1128
|
+
qualityScopeGateEnabled: workerQualityScopeGateEnabled,
|
|
1129
|
+
qualityValidationGateEnabled: workerQualityValidationGateEnabled,
|
|
1130
|
+
qualityCriticGateEnabled: workerQualityCriticGateEnabled,
|
|
1131
|
+
qualityPublishGateEnabled: workerQualityPublishGateEnabled,
|
|
1122
1132
|
qualityValidationStepTimeoutMs: workerQualityValidationStepTimeoutMs,
|
|
1123
1133
|
qualityCriticTimeoutMs: workerQualityCriticTimeoutMs,
|
|
1124
1134
|
qualitySoftPassOnExhausted: workerQualitySoftPassOnExhausted,
|
package/package.json
CHANGED
|
@@ -150,7 +150,14 @@ file_modifying_jobs = ["task.execute"]
|
|
|
150
150
|
output_max_chars = 196608
|
|
151
151
|
output_max_lines = 600
|
|
152
152
|
output_max_head_lines = 120
|
|
153
|
-
quality_max_auto_revisions =
|
|
153
|
+
quality_max_auto_revisions = 3
|
|
154
|
+
quality_validation_max_auto_revisions = 3
|
|
155
|
+
quality_scope_gate_enabled = true
|
|
156
|
+
quality_validation_gate_enabled = true
|
|
157
|
+
quality_critic_gate_enabled = true
|
|
158
|
+
quality_publish_gate_enabled = true
|
|
159
|
+
# Browser/e2e validation commands get a longer built-in floor (10m) because they
|
|
160
|
+
# may need to start a dev server and run browser automation.
|
|
154
161
|
quality_validation_step_timeout_ms = 180000
|
|
155
162
|
quality_critic_timeout_ms = 45000
|
|
156
163
|
quality_soft_pass_on_exhausted = true
|
|
@@ -66,7 +66,14 @@ file_modifying_jobs = ["task.execute"]
|
|
|
66
66
|
output_max_chars = 196608
|
|
67
67
|
output_max_lines = 600
|
|
68
68
|
output_max_head_lines = 120
|
|
69
|
-
quality_max_auto_revisions =
|
|
69
|
+
quality_max_auto_revisions = 3
|
|
70
|
+
quality_validation_max_auto_revisions = 3
|
|
71
|
+
quality_scope_gate_enabled = true
|
|
72
|
+
quality_validation_gate_enabled = true
|
|
73
|
+
quality_critic_gate_enabled = true
|
|
74
|
+
quality_publish_gate_enabled = true
|
|
75
|
+
# Browser/e2e validation commands get a longer built-in floor (10m) because they
|
|
76
|
+
# may need to start a dev server and run browser automation.
|
|
70
77
|
quality_validation_step_timeout_ms = 180000
|
|
71
78
|
quality_critic_timeout_ms = 45000
|
|
72
79
|
quality_soft_pass_on_exhausted = true
|
|
@@ -734,7 +734,7 @@ var DEFAULT_CONFIG_DIR = "configs";
|
|
|
734
734
|
var TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
735
735
|
var FALSY = new Set(["0", "false", "no", "off"]);
|
|
736
736
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE = 8;
|
|
737
|
-
var DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS =
|
|
737
|
+
var DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS = 3;
|
|
738
738
|
var DEFAULT_WORKERPALS_FILE_MODIFYING_JOBS = ["task.execute"];
|
|
739
739
|
var DEFAULT_WORKERPALS_OUTPUT_MAX_CHARS = 192 * 1024;
|
|
740
740
|
var DEFAULT_WORKERPALS_OUTPUT_MAX_LINES = 600;
|
|
@@ -1103,6 +1103,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
1103
1103
|
const workerOpenAICodexPython = firstNonEmpty(process.env.PUSHPALS_OPENAI_CODEX_PYTHON, asString(workerNode.openai_codex_python, "python"), "python");
|
|
1104
1104
|
const workerOpenAICodexTimeoutMs = Math.max(1e4, asInt(workerNode.openai_codex_timeout_ms, 7200000));
|
|
1105
1105
|
const workerQualityMaxAutoRevisions = Math.max(0, Math.min(10, asInt(parseIntEnv("WORKERPALS_QUALITY_MAX_AUTO_REVISIONS") ?? workerNode.quality_max_auto_revisions, DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS)));
|
|
1106
|
+
const workerQualityValidationMaxAutoRevisions = Math.max(0, Math.min(10, asInt(parseIntEnv("WORKERPALS_QUALITY_VALIDATION_MAX_AUTO_REVISIONS") ?? workerNode.quality_validation_max_auto_revisions, DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS)));
|
|
1106
1107
|
const workerFileModifyingJobs = (() => {
|
|
1107
1108
|
const envRaw = firstNonEmpty(process.env.WORKERPALS_FILE_MODIFYING_JOBS);
|
|
1108
1109
|
const parsed = envRaw ? envRaw.split(",").map((entry) => entry.trim()).filter(Boolean) : asStringArray(workerNode.file_modifying_jobs);
|
|
@@ -1115,6 +1116,10 @@ function loadPushPalsConfig(options = {}) {
|
|
|
1115
1116
|
const workerQualityValidationStepTimeoutMs = Math.max(1000, asInt(parseIntEnv("WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS") ?? workerNode.quality_validation_step_timeout_ms, DEFAULT_WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS));
|
|
1116
1117
|
const workerQualityCriticTimeoutMs = Math.max(1000, asInt(parseIntEnv("WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS") ?? workerNode.quality_critic_timeout_ms, DEFAULT_WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS));
|
|
1117
1118
|
const workerQualitySoftPassOnExhausted = parseBoolEnv("WORKERPALS_QUALITY_SOFT_PASS_ON_EXHAUSTED") ?? asBoolean(workerNode.quality_soft_pass_on_exhausted, true);
|
|
1119
|
+
const workerQualityScopeGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_SCOPE_GATE_ENABLED") ?? asBoolean(workerNode.quality_scope_gate_enabled, true);
|
|
1120
|
+
const workerQualityValidationGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_VALIDATION_GATE_ENABLED") ?? asBoolean(workerNode.quality_validation_gate_enabled, true);
|
|
1121
|
+
const workerQualityCriticGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_CRITIC_GATE_ENABLED") ?? asBoolean(workerNode.quality_critic_gate_enabled, true);
|
|
1122
|
+
const workerQualityPublishGateEnabled = parseBoolEnv("WORKERPALS_QUALITY_PUBLISH_GATE_ENABLED") ?? asBoolean(workerNode.quality_publish_gate_enabled, true);
|
|
1118
1123
|
const workerQualityCriticMinScore = (() => {
|
|
1119
1124
|
const configThresholdRaw = workerNode.quality_critic_min_score == null ? "" : String(workerNode.quality_critic_min_score);
|
|
1120
1125
|
const raw = firstNonEmpty(process.env.WORKERPALS_QUALITY_CRITIC_MIN_SCORE, configThresholdRaw, String(DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE));
|
|
@@ -1405,6 +1410,11 @@ function loadPushPalsConfig(options = {}) {
|
|
|
1405
1410
|
outputMaxLines: workerOutputMaxLines,
|
|
1406
1411
|
outputMaxHeadLines: workerOutputMaxHeadLines,
|
|
1407
1412
|
qualityMaxAutoRevisions: workerQualityMaxAutoRevisions,
|
|
1413
|
+
qualityValidationMaxAutoRevisions: workerQualityValidationMaxAutoRevisions,
|
|
1414
|
+
qualityScopeGateEnabled: workerQualityScopeGateEnabled,
|
|
1415
|
+
qualityValidationGateEnabled: workerQualityValidationGateEnabled,
|
|
1416
|
+
qualityCriticGateEnabled: workerQualityCriticGateEnabled,
|
|
1417
|
+
qualityPublishGateEnabled: workerQualityPublishGateEnabled,
|
|
1408
1418
|
qualityValidationStepTimeoutMs: workerQualityValidationStepTimeoutMs,
|
|
1409
1419
|
qualityCriticTimeoutMs: workerQualityCriticTimeoutMs,
|
|
1410
1420
|
qualitySoftPassOnExhausted: workerQualitySoftPassOnExhausted,
|
|
@@ -1763,6 +1773,16 @@ var NODE_BACKED_CLI_NAMES = new Set([
|
|
|
1763
1773
|
"vitest",
|
|
1764
1774
|
"webpack"
|
|
1765
1775
|
]);
|
|
1776
|
+
var BUN_OPTIONS_WITH_VALUE = new Set(["--cwd", "-C"]);
|
|
1777
|
+
var PACKAGE_MANAGER_OPTIONS_WITH_VALUE = new Set([
|
|
1778
|
+
"--cwd",
|
|
1779
|
+
"--dir",
|
|
1780
|
+
"--filter",
|
|
1781
|
+
"--prefix",
|
|
1782
|
+
"--workspace",
|
|
1783
|
+
"-C",
|
|
1784
|
+
"-F"
|
|
1785
|
+
]);
|
|
1766
1786
|
// packages/shared/src/session_event_visibility.ts
|
|
1767
1787
|
var ALWAYS_VISIBLE_EVENT_TYPES = new Set(["question_asked"]);
|
|
1768
1788
|
// packages/shared/src/localbuddy_runtime.ts
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
parseStructuredResult,
|
|
17
17
|
filterResultLines,
|
|
18
18
|
} from "../common/execution_utils.js";
|
|
19
|
+
import { buildWorkerSandboxWritableEnv } from "../common/sandbox_env.js";
|
|
19
20
|
import { computeTimeoutWarningWindow } from "../timeout_policy.js";
|
|
20
21
|
|
|
21
22
|
// ---- Script path (resolved relative to this file) ----------------------------
|
|
@@ -286,7 +287,7 @@ export async function executeWithOpenHands(
|
|
|
286
287
|
stdout: "pipe",
|
|
287
288
|
stderr: "pipe",
|
|
288
289
|
env: {
|
|
289
|
-
...
|
|
290
|
+
...buildWorkerSandboxWritableEnv(repo),
|
|
290
291
|
PUSHPALS_REPO_PATH: repo,
|
|
291
292
|
PUSHPALS_ASSIGNED_REPO_ROOT: repo,
|
|
292
293
|
PYTHONIOENCODING: "utf-8",
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
filterResultLines,
|
|
19
19
|
streamLines,
|
|
20
20
|
} from "./execution_utils.js";
|
|
21
|
+
import { buildWorkerSandboxWritableEnv } from "./sandbox_env.js";
|
|
21
22
|
|
|
22
23
|
interface GenericPythonExecutorConfig {
|
|
23
24
|
backendName: string;
|
|
@@ -180,7 +181,7 @@ export function createGenericPythonExecutor(
|
|
|
180
181
|
stdout: "pipe",
|
|
181
182
|
stderr: "pipe",
|
|
182
183
|
env: {
|
|
183
|
-
...
|
|
184
|
+
...buildWorkerSandboxWritableEnv(repo),
|
|
184
185
|
PUSHPALS_REPO_PATH: repo,
|
|
185
186
|
PUSHPALS_ASSIGNED_REPO_ROOT: repo,
|
|
186
187
|
PYTHONIOENCODING: "utf-8",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { existsSync, mkdirSync } from "fs";
|
|
3
|
+
import { homedir, tmpdir } from "os";
|
|
4
|
+
import { basename, resolve } from "path";
|
|
5
|
+
|
|
6
|
+
function stringEnv(source: NodeJS.ProcessEnv = process.env): Record<string, string> {
|
|
7
|
+
const env: Record<string, string> = {};
|
|
8
|
+
for (const [key, value] of Object.entries(source)) {
|
|
9
|
+
if (typeof value === "string") env[key] = value;
|
|
10
|
+
}
|
|
11
|
+
return env;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function safeRepoSlug(repo: string): string {
|
|
15
|
+
const leaf = basename(resolve(repo)).replace(/[^A-Za-z0-9_.-]+/g, "-") || "repo";
|
|
16
|
+
const hash = createHash("sha256").update(resolve(repo)).digest("hex").slice(0, 12);
|
|
17
|
+
return `${leaf}-${hash}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function defaultExpoPortForRepo(repo: string): string {
|
|
21
|
+
const hashPrefix = createHash("sha256").update(resolve(repo)).digest("hex").slice(0, 8);
|
|
22
|
+
const offset = Number.parseInt(hashPrefix, 16) % 1_000;
|
|
23
|
+
return String(19_006 + offset);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function ensureDirs(paths: string[]): void {
|
|
27
|
+
for (const path of paths) {
|
|
28
|
+
try {
|
|
29
|
+
mkdirSync(path, { recursive: true });
|
|
30
|
+
} catch {
|
|
31
|
+
// Best effort: command output will expose any remaining filesystem blocker.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveOriginalHome(env: Record<string, string>): string {
|
|
37
|
+
return env.HOME || env.USERPROFILE || homedir();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolveCodexHome(env: Record<string, string>, originalHome: string): string | undefined {
|
|
41
|
+
if (env.CODEX_HOME) return env.CODEX_HOME;
|
|
42
|
+
const defaultCodexHome = resolve(originalHome, ".codex");
|
|
43
|
+
return existsSync(defaultCodexHome) ? defaultCodexHome : undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function buildWorkerSandboxWritableEnv(
|
|
47
|
+
repo: string,
|
|
48
|
+
sourceEnv: NodeJS.ProcessEnv = process.env,
|
|
49
|
+
): Record<string, string> {
|
|
50
|
+
const env = stringEnv(sourceEnv);
|
|
51
|
+
const originalHome = resolveOriginalHome(env);
|
|
52
|
+
const codexHome = resolveCodexHome(env, originalHome);
|
|
53
|
+
const baseDir = resolve(tmpdir(), "pushpals-worker-env", safeRepoSlug(repo));
|
|
54
|
+
const homeDir = resolve(baseDir, "home");
|
|
55
|
+
const cacheDir = resolve(baseDir, "cache");
|
|
56
|
+
const expoDir = resolve(baseDir, "expo");
|
|
57
|
+
const defaultExpoPort = defaultExpoPortForRepo(repo);
|
|
58
|
+
ensureDirs([homeDir, cacheDir, expoDir, resolve(cacheDir, "npm")]);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
...env,
|
|
62
|
+
...(codexHome ? { CODEX_HOME: codexHome } : {}),
|
|
63
|
+
HOME: homeDir,
|
|
64
|
+
USERPROFILE: homeDir,
|
|
65
|
+
XDG_CACHE_HOME: cacheDir,
|
|
66
|
+
npm_config_cache: resolve(cacheDir, "npm"),
|
|
67
|
+
EXPO_HOME: expoDir,
|
|
68
|
+
EXPO_NO_TELEMETRY: env.EXPO_NO_TELEMETRY ?? "1",
|
|
69
|
+
EXPO_NO_INTERACTIVE: env.EXPO_NO_INTERACTIVE ?? "1",
|
|
70
|
+
CI: env.CI ?? "1",
|
|
71
|
+
BROWSER: env.BROWSER ?? "none",
|
|
72
|
+
EXPO_DEV_SERVER_PORT: env.EXPO_DEV_SERVER_PORT ?? defaultExpoPort,
|
|
73
|
+
RCT_METRO_PORT: env.RCT_METRO_PORT ?? defaultExpoPort,
|
|
74
|
+
PUSHPALS_VALIDATION_REPO: repo,
|
|
75
|
+
};
|
|
76
|
+
}
|