@pushpalsdev/cli 1.0.47 → 1.0.49
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
|
@@ -1523,6 +1523,9 @@ var MONITOR_POLL_MS = 2000;
|
|
|
1523
1523
|
var HTTP_TIMEOUT_MS = 2500;
|
|
1524
1524
|
var LOCALBUDDY_TIMEOUT_MS = 4000;
|
|
1525
1525
|
var SSE_RECONNECT_MS = 1500;
|
|
1526
|
+
var DOCKER_VERSION_PROBE_TIMEOUT_MS = 1e4;
|
|
1527
|
+
var WORKERPAL_IMAGE_INSPECT_TIMEOUT_MS = 15000;
|
|
1528
|
+
var WORKERPAL_IMAGE_BUILD_TIMEOUT_MS = 10 * 60000;
|
|
1526
1529
|
var DEFAULT_RUNTIME_BOOT_TIMEOUT_MS = 90000;
|
|
1527
1530
|
var DEFAULT_RUNTIME_BOOT_POLL_MS = 1000;
|
|
1528
1531
|
var DEFAULT_SERVER_BOOT_TIMEOUT_MS = 20000;
|
|
@@ -2948,7 +2951,7 @@ async function resolveWorkerpalDockerProbe(cwd, env, platform = process.platform
|
|
|
2948
2951
|
const candidates = resolveRuntimeDockerExecutableCandidates(env, platform);
|
|
2949
2952
|
const failures = [];
|
|
2950
2953
|
for (const candidate of candidates) {
|
|
2951
|
-
const result = await runCommandWithEnv([candidate, "version", "--format", "{{.Server.Version}}"], cwd, env);
|
|
2954
|
+
const result = await runCommandWithEnv([candidate, "version", "--format", "{{.Server.Version}}"], cwd, env, DOCKER_VERSION_PROBE_TIMEOUT_MS);
|
|
2952
2955
|
if (result.ok) {
|
|
2953
2956
|
const version = result.stdout.trim();
|
|
2954
2957
|
return {
|
|
@@ -3127,7 +3130,10 @@ async function cleanupLingeringPushPalsGitWorktrees(opts) {
|
|
|
3127
3130
|
removed
|
|
3128
3131
|
};
|
|
3129
3132
|
}
|
|
3130
|
-
|
|
3133
|
+
function isMissingDockerImageDetail(detail) {
|
|
3134
|
+
return /\b(no such object|no such image|not found)\b/i.test(String(detail ?? ""));
|
|
3135
|
+
}
|
|
3136
|
+
async function inspectDockerImageRuntimeTag(dockerExecutable, imageName, cwd, env, timeoutMs = WORKERPAL_IMAGE_INSPECT_TIMEOUT_MS) {
|
|
3131
3137
|
const inspect = await runCommandWithEnv([
|
|
3132
3138
|
dockerExecutable,
|
|
3133
3139
|
"image",
|
|
@@ -3135,11 +3141,23 @@ async function inspectDockerImageRuntimeTag(dockerExecutable, imageName, cwd, en
|
|
|
3135
3141
|
"--format",
|
|
3136
3142
|
`{{ index .Config.Labels "${WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL}" }}`,
|
|
3137
3143
|
imageName
|
|
3138
|
-
], cwd, env);
|
|
3139
|
-
if (!inspect.ok)
|
|
3140
|
-
|
|
3144
|
+
], cwd, env, timeoutMs);
|
|
3145
|
+
if (!inspect.ok) {
|
|
3146
|
+
const detail = inspect.stderr || inspect.stdout || `exit ${inspect.exitCode}`;
|
|
3147
|
+
if (isMissingDockerImageDetail(detail)) {
|
|
3148
|
+
return { status: "missing", runtimeTag: "" };
|
|
3149
|
+
}
|
|
3150
|
+
return {
|
|
3151
|
+
status: "failed",
|
|
3152
|
+
runtimeTag: "",
|
|
3153
|
+
detail: `failed to inspect local WorkerPal sandbox image ${imageName}: ${detail}`
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3141
3156
|
const value = inspect.stdout.trim();
|
|
3142
|
-
return
|
|
3157
|
+
return {
|
|
3158
|
+
status: "ok",
|
|
3159
|
+
runtimeTag: value === "<no value>" ? "" : value
|
|
3160
|
+
};
|
|
3143
3161
|
}
|
|
3144
3162
|
async function ensureWorkerpalDockerImageReady(opts) {
|
|
3145
3163
|
const runtimeTag = String(opts.runtimeTag ?? "").trim();
|
|
@@ -3160,14 +3178,20 @@ async function ensureWorkerpalDockerImageReady(opts) {
|
|
|
3160
3178
|
const dockerExecutable = resolveConfiguredDockerExecutable(opts.env, opts.platform ?? process.platform);
|
|
3161
3179
|
const inspectImageRuntimeTagFn = opts.inspectImageRuntimeTagFn ?? inspectDockerImageRuntimeTag;
|
|
3162
3180
|
const runCommandWithEnvFn = opts.runCommandWithEnvFn ?? runCommandWithEnv;
|
|
3163
|
-
|
|
3164
|
-
|
|
3181
|
+
console.log(`[pushpals] Checking WorkerPal sandbox image ${opts.dockerImage} for runtimeTag=${runtimeTag}...`);
|
|
3182
|
+
const inspection = await inspectImageRuntimeTagFn(dockerExecutable, opts.dockerImage, sandbox.root, opts.env);
|
|
3183
|
+
const inspectFailureDetail = inspection.status === "failed" ? inspection.detail : "";
|
|
3184
|
+
const existingRuntimeTag = inspection.status === "ok" ? inspection.runtimeTag : "";
|
|
3185
|
+
if (inspection.status === "ok" && existingRuntimeTag === runtimeTag) {
|
|
3165
3186
|
return {
|
|
3166
3187
|
ok: true,
|
|
3167
3188
|
detail: `WorkerPal sandbox image is ready locally (${opts.dockerImage}, runtimeTag=${runtimeTag})`
|
|
3168
3189
|
};
|
|
3169
3190
|
}
|
|
3170
|
-
|
|
3191
|
+
if (inspectFailureDetail) {
|
|
3192
|
+
console.warn(`[pushpals] ${inspectFailureDetail}`);
|
|
3193
|
+
}
|
|
3194
|
+
console.log(inspectFailureDetail ? `[pushpals] WorkerPal sandbox image ${opts.dockerImage} could not be inspected; attempting local rebuild...` : existingRuntimeTag ? `[pushpals] WorkerPal sandbox image ${opts.dockerImage} is stale (runtimeTag=${existingRuntimeTag}); rebuilding locally...` : `[pushpals] WorkerPal sandbox image ${opts.dockerImage} is missing; building locally...`);
|
|
3171
3195
|
const build = await runCommandWithEnvFn([
|
|
3172
3196
|
dockerExecutable,
|
|
3173
3197
|
"build",
|
|
@@ -3180,17 +3204,17 @@ async function ensureWorkerpalDockerImageReady(opts) {
|
|
|
3180
3204
|
"-t",
|
|
3181
3205
|
opts.dockerImage,
|
|
3182
3206
|
"."
|
|
3183
|
-
], sandbox.root, opts.env);
|
|
3207
|
+
], sandbox.root, opts.env, WORKERPAL_IMAGE_BUILD_TIMEOUT_MS);
|
|
3184
3208
|
if (!build.ok) {
|
|
3185
3209
|
const detail = build.stderr || build.stdout || `docker build exited ${build.exitCode}`;
|
|
3186
3210
|
return {
|
|
3187
3211
|
ok: false,
|
|
3188
|
-
detail: `failed to build local WorkerPal sandbox image ${opts.dockerImage}: ${detail}`
|
|
3212
|
+
detail: inspectFailureDetail ? `${inspectFailureDetail}; failed to build local WorkerPal sandbox image ${opts.dockerImage}: ${detail}` : `failed to build local WorkerPal sandbox image ${opts.dockerImage}: ${detail}`
|
|
3189
3213
|
};
|
|
3190
3214
|
}
|
|
3191
3215
|
return {
|
|
3192
3216
|
ok: true,
|
|
3193
|
-
detail: `built local WorkerPal sandbox image ${opts.dockerImage} for runtimeTag=${runtimeTag}`
|
|
3217
|
+
detail: inspectFailureDetail ? `rebuilt local WorkerPal sandbox image ${opts.dockerImage} for runtimeTag=${runtimeTag} after image inspection failed` : `built local WorkerPal sandbox image ${opts.dockerImage} for runtimeTag=${runtimeTag}`
|
|
3194
3218
|
};
|
|
3195
3219
|
}
|
|
3196
3220
|
async function prepareEmbeddedWorkerpalDockerImageIfNeeded(opts) {
|
package/package.json
CHANGED
|
@@ -40,6 +40,9 @@ const DEFAULT_CONFIG = loadPushPalsConfig();
|
|
|
40
40
|
const SHARED_CONTAINER_VENV_PYTHON = "/workspace/.venv/bin/python";
|
|
41
41
|
const WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL = "pushpals.runtime_tag";
|
|
42
42
|
const WORKERPAL_SANDBOX_COMPONENT_LABEL = "pushpals.component=workerpals-sandbox";
|
|
43
|
+
const DOCKER_IMAGE_INSPECT_TIMEOUT_MS = 15_000;
|
|
44
|
+
const DOCKER_IMAGE_BUILD_TIMEOUT_MS = 10 * 60_000;
|
|
45
|
+
const DOCKER_IMAGE_PULL_TIMEOUT_MS = 10 * 60_000;
|
|
43
46
|
|
|
44
47
|
function parseClampedInt(value: unknown, defaultValue: number, min: number, max: number): number {
|
|
45
48
|
const parsed =
|
|
@@ -99,6 +102,10 @@ function dockerBuildFileArg(root: string, dockerfilePath: string): string {
|
|
|
99
102
|
return relativePath || "apps/workerpals/Dockerfile.sandbox";
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
function isMissingDockerImageDetail(detail: string): boolean {
|
|
106
|
+
return /\b(no such object|no such image|not found)\b/i.test(String(detail ?? ""));
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
type ParsedWorktreeRecord = {
|
|
103
110
|
path: string;
|
|
104
111
|
detached: boolean;
|
|
@@ -1530,6 +1537,45 @@ export class DockerExecutor {
|
|
|
1530
1537
|
await new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
|
|
1531
1538
|
}
|
|
1532
1539
|
|
|
1540
|
+
private async runDockerCommandCapture(
|
|
1541
|
+
command: string[],
|
|
1542
|
+
opts: { cwd?: string; timeoutMs?: number } = {},
|
|
1543
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number; timedOut: boolean }> {
|
|
1544
|
+
const proc = Bun.spawn(command, {
|
|
1545
|
+
cwd: opts.cwd,
|
|
1546
|
+
stdout: "pipe",
|
|
1547
|
+
stderr: "pipe",
|
|
1548
|
+
});
|
|
1549
|
+
let timedOut = false;
|
|
1550
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
1551
|
+
if (
|
|
1552
|
+
typeof opts.timeoutMs === "number" &&
|
|
1553
|
+
Number.isFinite(opts.timeoutMs) &&
|
|
1554
|
+
opts.timeoutMs > 0
|
|
1555
|
+
) {
|
|
1556
|
+
timer = setTimeout(() => {
|
|
1557
|
+
timedOut = true;
|
|
1558
|
+
try {
|
|
1559
|
+
proc.kill();
|
|
1560
|
+
} catch {
|
|
1561
|
+
// best-effort timeout termination only
|
|
1562
|
+
}
|
|
1563
|
+
}, opts.timeoutMs);
|
|
1564
|
+
}
|
|
1565
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
1566
|
+
new Response(proc.stdout).text(),
|
|
1567
|
+
new Response(proc.stderr).text(),
|
|
1568
|
+
proc.exited,
|
|
1569
|
+
]);
|
|
1570
|
+
if (timer) clearTimeout(timer);
|
|
1571
|
+
return {
|
|
1572
|
+
stdout: stdout.trim(),
|
|
1573
|
+
stderr: stderr.trim(),
|
|
1574
|
+
exitCode,
|
|
1575
|
+
timedOut,
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1533
1579
|
private compactError(err: unknown): string {
|
|
1534
1580
|
const text = err instanceof Error ? err.message : String(err);
|
|
1535
1581
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
@@ -1862,19 +1908,21 @@ export class DockerExecutor {
|
|
|
1862
1908
|
console.log(
|
|
1863
1909
|
`[DockerExecutor] Local image is unavailable or unsuitable. Pulling: ${this.options.imageName}`,
|
|
1864
1910
|
);
|
|
1865
|
-
const
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
const exitCode = await proc.exited;
|
|
1871
|
-
if (exitCode === 0) {
|
|
1911
|
+
const pull = await this.runDockerCommandCapture(
|
|
1912
|
+
[resolveDockerExecutable(), "pull", this.options.imageName],
|
|
1913
|
+
{ timeoutMs: DOCKER_IMAGE_PULL_TIMEOUT_MS },
|
|
1914
|
+
);
|
|
1915
|
+
if (!pull.timedOut && pull.exitCode === 0) {
|
|
1872
1916
|
console.log(`[DockerExecutor] Image pulled successfully`);
|
|
1873
1917
|
return true;
|
|
1874
1918
|
}
|
|
1875
1919
|
|
|
1876
|
-
const
|
|
1877
|
-
console.error(
|
|
1920
|
+
const detail = pull.stderr || pull.stdout || `docker pull exited ${pull.exitCode}`;
|
|
1921
|
+
console.error(
|
|
1922
|
+
`[DockerExecutor] Failed to pull image: ${
|
|
1923
|
+
pull.timedOut ? `timed out after ${DOCKER_IMAGE_PULL_TIMEOUT_MS}ms` : detail
|
|
1924
|
+
}`,
|
|
1925
|
+
);
|
|
1878
1926
|
|
|
1879
1927
|
// Another process may have built/pulled the image while this pull was running.
|
|
1880
1928
|
if (await this.imageExists()) {
|
|
@@ -1891,19 +1939,21 @@ export class DockerExecutor {
|
|
|
1891
1939
|
* Check if the Docker image exists locally
|
|
1892
1940
|
*/
|
|
1893
1941
|
private async imageExists(): Promise<boolean> {
|
|
1894
|
-
const
|
|
1942
|
+
const result = await this.runDockerCommandCapture(
|
|
1895
1943
|
[resolveDockerExecutable(), "image", "inspect", this.options.imageName],
|
|
1896
|
-
{
|
|
1897
|
-
stdout: "pipe",
|
|
1898
|
-
stderr: "pipe",
|
|
1899
|
-
},
|
|
1944
|
+
{ timeoutMs: DOCKER_IMAGE_INSPECT_TIMEOUT_MS },
|
|
1900
1945
|
);
|
|
1901
|
-
|
|
1902
|
-
|
|
1946
|
+
if (result.timedOut) {
|
|
1947
|
+
console.warn(
|
|
1948
|
+
`[DockerExecutor] Timed out checking local image ${this.options.imageName}; treating it as unavailable and attempting rebuild.`,
|
|
1949
|
+
);
|
|
1950
|
+
return false;
|
|
1951
|
+
}
|
|
1952
|
+
return result.exitCode === 0;
|
|
1903
1953
|
}
|
|
1904
1954
|
|
|
1905
1955
|
private async inspectImageRuntimeTag(): Promise<string> {
|
|
1906
|
-
const
|
|
1956
|
+
const result = await this.runDockerCommandCapture(
|
|
1907
1957
|
[
|
|
1908
1958
|
resolveDockerExecutable(),
|
|
1909
1959
|
"image",
|
|
@@ -1912,14 +1962,24 @@ export class DockerExecutor {
|
|
|
1912
1962
|
`{{ index .Config.Labels "${WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL}" }}`,
|
|
1913
1963
|
this.options.imageName,
|
|
1914
1964
|
],
|
|
1915
|
-
{
|
|
1916
|
-
stdout: "pipe",
|
|
1917
|
-
stderr: "pipe",
|
|
1918
|
-
},
|
|
1965
|
+
{ timeoutMs: DOCKER_IMAGE_INSPECT_TIMEOUT_MS },
|
|
1919
1966
|
);
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1967
|
+
if (result.timedOut) {
|
|
1968
|
+
console.warn(
|
|
1969
|
+
`[DockerExecutor] Timed out inspecting runtime tag for ${this.options.imageName}; treating the local image as stale and attempting rebuild.`,
|
|
1970
|
+
);
|
|
1971
|
+
return "";
|
|
1972
|
+
}
|
|
1973
|
+
if (result.exitCode !== 0) {
|
|
1974
|
+
const detail = result.stderr || result.stdout || `exit ${result.exitCode}`;
|
|
1975
|
+
if (!isMissingDockerImageDetail(detail)) {
|
|
1976
|
+
console.warn(
|
|
1977
|
+
`[DockerExecutor] Failed to inspect runtime tag for ${this.options.imageName}: ${detail}`,
|
|
1978
|
+
);
|
|
1979
|
+
}
|
|
1980
|
+
return "";
|
|
1981
|
+
}
|
|
1982
|
+
const value = result.stdout.trim();
|
|
1923
1983
|
return value === "<no value>" ? "" : value;
|
|
1924
1984
|
}
|
|
1925
1985
|
|
|
@@ -1947,21 +2007,19 @@ export class DockerExecutor {
|
|
|
1947
2007
|
this.options.imageName,
|
|
1948
2008
|
".",
|
|
1949
2009
|
];
|
|
1950
|
-
const
|
|
2010
|
+
const build = await this.runDockerCommandCapture(args, {
|
|
1951
2011
|
cwd: sandboxContext.root,
|
|
1952
|
-
|
|
1953
|
-
stderr: "pipe",
|
|
2012
|
+
timeoutMs: DOCKER_IMAGE_BUILD_TIMEOUT_MS,
|
|
1954
2013
|
});
|
|
1955
|
-
|
|
1956
|
-
new Response(proc.stdout).text(),
|
|
1957
|
-
new Response(proc.stderr).text(),
|
|
1958
|
-
proc.exited,
|
|
1959
|
-
]);
|
|
1960
|
-
if (exitCode === 0) {
|
|
2014
|
+
if (!build.timedOut && build.exitCode === 0) {
|
|
1961
2015
|
return true;
|
|
1962
2016
|
}
|
|
1963
|
-
const detail = stderr
|
|
1964
|
-
console.error(
|
|
2017
|
+
const detail = build.stderr || build.stdout || `docker build exited ${build.exitCode}`;
|
|
2018
|
+
console.error(
|
|
2019
|
+
`[DockerExecutor] Failed to build local image: ${
|
|
2020
|
+
build.timedOut ? `timed out after ${DOCKER_IMAGE_BUILD_TIMEOUT_MS}ms` : detail
|
|
2021
|
+
}`,
|
|
2022
|
+
);
|
|
1965
2023
|
return false;
|
|
1966
2024
|
}
|
|
1967
2025
|
|