@pushpalsdev/cli 1.1.38 → 1.1.39
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
CHANGED
|
@@ -2169,6 +2169,97 @@ function withWindowsGitSchannelEnv(env, platform = process.platform) {
|
|
|
2169
2169
|
return env;
|
|
2170
2170
|
return appendGitConfigEnv(env, "http.sslBackend", "schannel");
|
|
2171
2171
|
}
|
|
2172
|
+
var WINDOWS_NODE_EXTRA_CA_CERTS_DISABLE_ENV = "PUSHPALS_DISABLE_WINDOWS_NODE_EXTRA_CA_CERTS";
|
|
2173
|
+
var WINDOWS_NODE_EXTRA_CA_CERTS_BUNDLE_RELATIVE_PATH = ["certs", "windows-root-ca.pem"];
|
|
2174
|
+
function resolveWindowsNodeExtraCaCertsBundlePath(runtimeRoot) {
|
|
2175
|
+
return join2(runtimeRoot, ...WINDOWS_NODE_EXTRA_CA_CERTS_BUNDLE_RELATIVE_PATH);
|
|
2176
|
+
}
|
|
2177
|
+
function hasUsablePemCertificate(pathValue) {
|
|
2178
|
+
try {
|
|
2179
|
+
return /-----BEGIN CERTIFICATE-----/.test(readFileSync4(pathValue, "utf8"));
|
|
2180
|
+
} catch {
|
|
2181
|
+
return false;
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
function ensureWindowsNodeExtraCaCertsBundle(outPath, env) {
|
|
2185
|
+
if (hasUsablePemCertificate(outPath))
|
|
2186
|
+
return outPath;
|
|
2187
|
+
const outDir = dirname(outPath);
|
|
2188
|
+
try {
|
|
2189
|
+
mkdirSync(outDir, { recursive: true });
|
|
2190
|
+
} catch {
|
|
2191
|
+
return "";
|
|
2192
|
+
}
|
|
2193
|
+
const script = String.raw`
|
|
2194
|
+
$ErrorActionPreference = "Stop"
|
|
2195
|
+
$outPath = $env:PUSHPALS_WINDOWS_NODE_EXTRA_CA_CERTS_OUT
|
|
2196
|
+
if (-not $outPath) { throw "PUSHPALS_WINDOWS_NODE_EXTRA_CA_CERTS_OUT is required" }
|
|
2197
|
+
$outDir = Split-Path -Parent $outPath
|
|
2198
|
+
if ($outDir) { [System.IO.Directory]::CreateDirectory($outDir) | Out-Null }
|
|
2199
|
+
$stores = @("Cert:\CurrentUser\Root", "Cert:\LocalMachine\Root")
|
|
2200
|
+
$seen = @{}
|
|
2201
|
+
$lines = New-Object System.Collections.Generic.List[string]
|
|
2202
|
+
foreach ($store in $stores) {
|
|
2203
|
+
if (-not (Test-Path $store)) { continue }
|
|
2204
|
+
foreach ($cert in Get-ChildItem $store) {
|
|
2205
|
+
if (-not $cert.RawData) { continue }
|
|
2206
|
+
if ($cert.NotAfter -lt (Get-Date)) { continue }
|
|
2207
|
+
$thumbprint = [string]$cert.Thumbprint
|
|
2208
|
+
if ($seen.ContainsKey($thumbprint)) { continue }
|
|
2209
|
+
$seen[$thumbprint] = $true
|
|
2210
|
+
$lines.Add("-----BEGIN CERTIFICATE-----")
|
|
2211
|
+
$encoded = [Convert]::ToBase64String($cert.RawData, [Base64FormattingOptions]::InsertLineBreaks)
|
|
2212
|
+
foreach ($line in [regex]::Split($encoded, '\r?\n')) {
|
|
2213
|
+
if ($line) { $lines.Add($line) }
|
|
2214
|
+
}
|
|
2215
|
+
$lines.Add("-----END CERTIFICATE-----")
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
if ($lines.Count -eq 0) { throw "No Windows root certificates found" }
|
|
2219
|
+
[System.IO.File]::WriteAllLines($outPath, $lines, [System.Text.Encoding]::ASCII)
|
|
2220
|
+
`;
|
|
2221
|
+
const encodedScript = Buffer.from(script, "utf16le").toString("base64");
|
|
2222
|
+
const childEnv = normalizeChildProcessEnv({
|
|
2223
|
+
...env,
|
|
2224
|
+
PUSHPALS_WINDOWS_NODE_EXTRA_CA_CERTS_OUT: outPath
|
|
2225
|
+
});
|
|
2226
|
+
const result = Bun.spawnSync([
|
|
2227
|
+
"powershell.exe",
|
|
2228
|
+
"-NoProfile",
|
|
2229
|
+
"-NonInteractive",
|
|
2230
|
+
"-ExecutionPolicy",
|
|
2231
|
+
"Bypass",
|
|
2232
|
+
"-EncodedCommand",
|
|
2233
|
+
encodedScript
|
|
2234
|
+
], {
|
|
2235
|
+
cwd: process.cwd(),
|
|
2236
|
+
env: childEnv,
|
|
2237
|
+
stdout: "pipe",
|
|
2238
|
+
stderr: "pipe"
|
|
2239
|
+
});
|
|
2240
|
+
if (result.exitCode !== 0)
|
|
2241
|
+
return "";
|
|
2242
|
+
return hasUsablePemCertificate(outPath) ? outPath : "";
|
|
2243
|
+
}
|
|
2244
|
+
function withWindowsNodeExtraCaCertsEnv(env, opts) {
|
|
2245
|
+
const platform = opts.platform ?? process.platform;
|
|
2246
|
+
if (platform !== "win32")
|
|
2247
|
+
return env;
|
|
2248
|
+
if (parseBooleanFlag(env[WINDOWS_NODE_EXTRA_CA_CERTS_DISABLE_ENV]) === true)
|
|
2249
|
+
return env;
|
|
2250
|
+
if (typeof env.NODE_EXTRA_CA_CERTS === "string" && env.NODE_EXTRA_CA_CERTS.trim())
|
|
2251
|
+
return env;
|
|
2252
|
+
const runtimeRoot = String(opts.runtimeRoot ?? "").trim();
|
|
2253
|
+
if (!runtimeRoot || !existsSync5(runtimeRoot))
|
|
2254
|
+
return env;
|
|
2255
|
+
const bundlePath = ensureWindowsNodeExtraCaCertsBundle(resolveWindowsNodeExtraCaCertsBundlePath(runtimeRoot), env);
|
|
2256
|
+
if (!bundlePath)
|
|
2257
|
+
return env;
|
|
2258
|
+
return {
|
|
2259
|
+
...env,
|
|
2260
|
+
NODE_EXTRA_CA_CERTS: bundlePath
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2172
2263
|
async function runGitWithEnv(args, cwd, env, timeoutMs) {
|
|
2173
2264
|
return await runCommandWithEnv(["git", ...args], cwd, withWindowsGitSchannelEnv(env), timeoutMs);
|
|
2174
2265
|
}
|
|
@@ -2844,7 +2935,11 @@ function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
|
2844
2935
|
...typeof env.PUSHPALS_DOCKER_BIN === "string" && env.PUSHPALS_DOCKER_BIN.trim() ? { PUSHPALS_DOCKER_BIN: env.PUSHPALS_DOCKER_BIN.trim() } : {},
|
|
2845
2936
|
...typeof env.PUSHPALS_DOCKER_BIN_ABSOLUTE === "string" && env.PUSHPALS_DOCKER_BIN_ABSOLUTE.trim() ? { PUSHPALS_DOCKER_BIN_ABSOLUTE: env.PUSHPALS_DOCKER_BIN_ABSOLUTE.trim() } : {}
|
|
2846
2937
|
};
|
|
2847
|
-
|
|
2938
|
+
const runtimeEnvWithWindowsCa = withWindowsNodeExtraCaCertsEnv(runtimeEnv, {
|
|
2939
|
+
platform,
|
|
2940
|
+
runtimeRoot: opts.runtimeRoot
|
|
2941
|
+
});
|
|
2942
|
+
return withWindowsGitSchannelEnv(runtimeEnvWithWindowsCa, platform);
|
|
2848
2943
|
}
|
|
2849
2944
|
function parseBooleanFlag(raw) {
|
|
2850
2945
|
const normalized = String(raw ?? "").trim().toLowerCase();
|
|
@@ -6034,10 +6129,13 @@ ${line}
|
|
|
6034
6129
|
console.log("[pushpals] Runtime-only mode is active. Send `exit` on stdin or terminate the process to stop.");
|
|
6035
6130
|
await new Promise((resolveStop) => {
|
|
6036
6131
|
let resolved = false;
|
|
6132
|
+
let exitRequestedFromInput = false;
|
|
6133
|
+
const keepAlive = setInterval(() => {}, 60000);
|
|
6037
6134
|
const finish = () => {
|
|
6038
6135
|
if (resolved)
|
|
6039
6136
|
return;
|
|
6040
6137
|
resolved = true;
|
|
6138
|
+
clearInterval(keepAlive);
|
|
6041
6139
|
resolveStop();
|
|
6042
6140
|
};
|
|
6043
6141
|
process.once("SIGINT", finish);
|
|
@@ -6050,13 +6148,17 @@ ${line}
|
|
|
6050
6148
|
runtimeOnlyInput.on("line", (line) => {
|
|
6051
6149
|
if (!isCliExitCommand(line))
|
|
6052
6150
|
return;
|
|
6151
|
+
exitRequestedFromInput = true;
|
|
6053
6152
|
requestStop();
|
|
6054
6153
|
runtimeOnlyInput.close();
|
|
6055
6154
|
finish();
|
|
6056
6155
|
});
|
|
6057
6156
|
runtimeOnlyInput.on("close", () => {
|
|
6058
|
-
|
|
6059
|
-
|
|
6157
|
+
if (exitRequestedFromInput || resolved) {
|
|
6158
|
+
finish();
|
|
6159
|
+
return;
|
|
6160
|
+
}
|
|
6161
|
+
console.log("[pushpals] Runtime-only stdin closed; continuing until terminated.");
|
|
6060
6162
|
});
|
|
6061
6163
|
});
|
|
6062
6164
|
await requestStop();
|
|
@@ -6138,6 +6240,7 @@ if (import.meta.main) {
|
|
|
6138
6240
|
});
|
|
6139
6241
|
}
|
|
6140
6242
|
export {
|
|
6243
|
+
withWindowsNodeExtraCaCertsEnv,
|
|
6141
6244
|
waitForWorkerpalCapacity,
|
|
6142
6245
|
waitForRemoteBuddySessionConsumer,
|
|
6143
6246
|
startEmbeddedMonitoringHub,
|
|
@@ -6154,6 +6257,7 @@ export {
|
|
|
6154
6257
|
resolveWorkerExecutionReadiness,
|
|
6155
6258
|
resolveWindowsWhereExecutableCandidatesForEnv,
|
|
6156
6259
|
resolveWindowsShellExecutableCandidatesForEnv,
|
|
6260
|
+
resolveWindowsNodeExtraCaCertsBundlePath,
|
|
6157
6261
|
resolveWindowsFreshRuntimeWorkerpalPrewarmDelayMs,
|
|
6158
6262
|
resolveRuntimeGitExecutableCandidates,
|
|
6159
6263
|
resolveRuntimeDockerExecutableCandidates,
|
package/package.json
CHANGED
|
@@ -127,6 +127,7 @@ _SMALL_TASK_ROLLOUT_WATCHDOG_S = 240
|
|
|
127
127
|
_NARROW_TEST_TASK_ROLLOUT_WATCHDOG_S = 150
|
|
128
128
|
_WEB_REVIEW_ROLLOUT_WATCHDOG_S = 180
|
|
129
129
|
_BACKGROUND_ROLLOUT_WATCHDOG_S = 90
|
|
130
|
+
_MIN_AUTO_WATCHDOG_TIMEOUT_S = 180
|
|
130
131
|
_MIN_CODEX_RECOVERY_ATTEMPT_S = 120
|
|
131
132
|
_NO_PUBLISHABLE_FAILURE_COOLDOWN_MS = 10 * 60 * 1000
|
|
132
133
|
_CODEX_STARTUP_ONLY_EVENT_TYPES = {"thread.started", "turn.started"}
|
|
@@ -664,6 +665,9 @@ def _looks_like_narrow_test_task_prompt(prompt: str) -> bool:
|
|
|
664
665
|
"ranking contract",
|
|
665
666
|
"regression coverage",
|
|
666
667
|
"focused coverage",
|
|
668
|
+
"focused test",
|
|
669
|
+
"focused tests",
|
|
670
|
+
"focused testing",
|
|
667
671
|
"focused regression",
|
|
668
672
|
"test-only",
|
|
669
673
|
"test only",
|
|
@@ -742,7 +746,7 @@ def _resolve_no_edit_watchdog_seconds(
|
|
|
742
746
|
else:
|
|
743
747
|
return max(1, min(parsed, max(1, communicate_timeout_s - 1)))
|
|
744
748
|
|
|
745
|
-
if communicate_timeout_s <
|
|
749
|
+
if communicate_timeout_s < _MIN_AUTO_WATCHDOG_TIMEOUT_S:
|
|
746
750
|
return None
|
|
747
751
|
|
|
748
752
|
prompt_text = str(prompt or "").lower()
|
|
@@ -887,7 +891,7 @@ def _resolve_rollout_watchdog_seconds(
|
|
|
887
891
|
communicate_timeout_s: Optional[int],
|
|
888
892
|
no_edit_watchdog_s: Optional[int],
|
|
889
893
|
) -> Optional[int]:
|
|
890
|
-
if not communicate_timeout_s or communicate_timeout_s <
|
|
894
|
+
if not communicate_timeout_s or communicate_timeout_s < _MIN_AUTO_WATCHDOG_TIMEOUT_S:
|
|
891
895
|
return None
|
|
892
896
|
|
|
893
897
|
raw = os.environ.get("WORKERPALS_OPENAI_CODEX_ROLLOUT_WATCHDOG_S", "").strip()
|
|
@@ -2156,6 +2156,24 @@ class OpenAICodexRuntimeConfigTests(unittest.TestCase):
|
|
|
2156
2156
|
|
|
2157
2157
|
self.assertEqual(watchdog_s, 180)
|
|
2158
2158
|
|
|
2159
|
+
def test_review_fix_child_budget_below_ten_minutes_still_uses_watchdogs(self) -> None:
|
|
2160
|
+
prompt = (
|
|
2161
|
+
"Rejected PR revision brief: Previous ReviewAgent score: 8.0 / 10. "
|
|
2162
|
+
"Add focused tests for createCleanupHarness.runTask covering successful execution, "
|
|
2163
|
+
"execute failure, cleanup failure, invalid task input, and cleanup execution after "
|
|
2164
|
+
"successful task completion."
|
|
2165
|
+
)
|
|
2166
|
+
env = {
|
|
2167
|
+
"WORKERPALS_OPENAI_CODEX_NO_EDIT_WATCHDOG_S": "",
|
|
2168
|
+
"WORKERPALS_OPENAI_CODEX_ROLLOUT_WATCHDOG_S": "",
|
|
2169
|
+
}
|
|
2170
|
+
with mock.patch.dict(os.environ, env, clear=False):
|
|
2171
|
+
no_edit_s = _resolve_no_edit_watchdog_seconds(prompt, 570)
|
|
2172
|
+
rollout_s = _resolve_rollout_watchdog_seconds(prompt, 570, no_edit_s)
|
|
2173
|
+
|
|
2174
|
+
self.assertEqual(no_edit_s, 180)
|
|
2175
|
+
self.assertEqual(rollout_s, 120)
|
|
2176
|
+
|
|
2159
2177
|
def test_no_edit_recovery_guidance_warns_against_artifact_only_progress(self) -> None:
|
|
2160
2178
|
guidance = _build_no_edit_recovery_guidance(
|
|
2161
2179
|
"item.completed | still inspecting",
|