@pushpalsdev/cli 1.0.28 → 1.0.29
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 +127 -1
- package/package.json +1 -1
package/dist/pushpals-cli.js
CHANGED
|
@@ -1946,8 +1946,14 @@ function cleanupLegacyRuntimeBinaryLayouts(runtimeRoot, platformKey, activeBinDi
|
|
|
1946
1946
|
function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
1947
1947
|
const env = normalizeChildProcessEnv(baseEnv);
|
|
1948
1948
|
const useRuntimeConfig = opts.useRuntimeConfig !== false;
|
|
1949
|
+
const inherited = { ...env };
|
|
1950
|
+
if (!useRuntimeConfig) {
|
|
1951
|
+
delete inherited.PUSHPALS_CONFIG_DIR_OVERRIDE;
|
|
1952
|
+
delete inherited.PUSHPALS_WORKERPALS_SANDBOX_ROOT;
|
|
1953
|
+
delete inherited.PUSHPALS_RUNTIME_TAG;
|
|
1954
|
+
}
|
|
1949
1955
|
return {
|
|
1950
|
-
...
|
|
1956
|
+
...inherited,
|
|
1951
1957
|
PUSHPALS_REPO_ROOT_OVERRIDE: opts.repoRoot,
|
|
1952
1958
|
PUSHPALS_PROJECT_ROOT_OVERRIDE: opts.repoRoot,
|
|
1953
1959
|
...useRuntimeConfig ? {
|
|
@@ -2484,6 +2490,36 @@ async function resolveWorkerpalDockerProbe(cwd, env, platform = process.platform
|
|
|
2484
2490
|
var WORKERPAL_SANDBOX_RUNTIME_TAG_LABEL = "pushpals.runtime_tag";
|
|
2485
2491
|
var WORKERPAL_SANDBOX_COMPONENT_LABEL = "pushpals.component=workerpals-sandbox";
|
|
2486
2492
|
var WORKERPAL_WARM_COMPONENT_LABEL = "pushpals.component=workerpals-warm";
|
|
2493
|
+
var SOURCE_CONTROL_MANAGER_TEMP_BRANCH_PREFIX = "_source_control_manager/";
|
|
2494
|
+
function normalizeFsPathForComparison(value) {
|
|
2495
|
+
const resolved = resolve4(String(value ?? "").trim()).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
2496
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
2497
|
+
}
|
|
2498
|
+
function parseGitWorktreeListPorcelain(stdout) {
|
|
2499
|
+
const entries = [];
|
|
2500
|
+
const blocks = String(stdout ?? "").split(/\r?\n\r?\n/g).map((block) => block.trim()).filter(Boolean);
|
|
2501
|
+
for (const block of blocks) {
|
|
2502
|
+
const lines = block.split(/\r?\n/g);
|
|
2503
|
+
const pathLine = lines.find((line) => line.startsWith("worktree "));
|
|
2504
|
+
if (!pathLine)
|
|
2505
|
+
continue;
|
|
2506
|
+
const branchLine = lines.find((line) => line.startsWith("branch "));
|
|
2507
|
+
entries.push({
|
|
2508
|
+
path: pathLine.slice("worktree ".length).trim(),
|
|
2509
|
+
branch: branchLine ? branchLine.slice("branch ".length).trim() : null,
|
|
2510
|
+
detached: lines.includes("detached")
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
return entries;
|
|
2514
|
+
}
|
|
2515
|
+
function isWorkerpalEphemeralWorktreePath(repoRoot, worktreePath) {
|
|
2516
|
+
const expectedPrefix = `${normalizeFsPathForComparison(join2(repoRoot, ".worktrees"))}/`;
|
|
2517
|
+
const normalizedPath = normalizeFsPathForComparison(worktreePath);
|
|
2518
|
+
if (!normalizedPath.startsWith(expectedPrefix))
|
|
2519
|
+
return false;
|
|
2520
|
+
const leaf = basename(normalizedPath);
|
|
2521
|
+
return /^(job|selfcheck)-.*-workerpal-[a-z0-9._-]+/i.test(leaf);
|
|
2522
|
+
}
|
|
2487
2523
|
function resolveConfiguredDockerExecutable(env, platform = process.platform) {
|
|
2488
2524
|
const configured = String(env.PUSHPALS_DOCKER_BIN_ABSOLUTE ?? env.PUSHPALS_DOCKER_BIN ?? (platform === "win32" ? "docker.exe" : "docker")).trim();
|
|
2489
2525
|
return configured || (platform === "win32" ? "docker.exe" : "docker");
|
|
@@ -2531,6 +2567,80 @@ async function cleanupLingeringWorkerpalWarmContainers(opts) {
|
|
|
2531
2567
|
removed: containerIds.length
|
|
2532
2568
|
};
|
|
2533
2569
|
}
|
|
2570
|
+
async function cleanupLingeringPushPalsGitWorktrees(opts) {
|
|
2571
|
+
const runCommandWithEnvFn = opts.runCommandWithEnvFn ?? runCommandWithEnv;
|
|
2572
|
+
const list = await runCommandWithEnvFn(["git", "worktree", "list", "--porcelain"], opts.repoRoot, opts.env);
|
|
2573
|
+
if (!list.ok) {
|
|
2574
|
+
const detail = list.stderr || list.stdout || `exit ${list.exitCode}`;
|
|
2575
|
+
return {
|
|
2576
|
+
ok: false,
|
|
2577
|
+
detail: `failed to inspect lingering PushPals git artifacts: ${detail}`,
|
|
2578
|
+
removed: 0
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
const currentRepoPath = normalizeFsPathForComparison(opts.repoRoot);
|
|
2582
|
+
const removable = parseGitWorktreeListPorcelain(list.stdout).filter((entry) => {
|
|
2583
|
+
const normalizedPath = normalizeFsPathForComparison(entry.path);
|
|
2584
|
+
if (normalizedPath === currentRepoPath)
|
|
2585
|
+
return false;
|
|
2586
|
+
if (entry.branch?.startsWith(`refs/heads/${SOURCE_CONTROL_MANAGER_TEMP_BRANCH_PREFIX}`)) {
|
|
2587
|
+
return true;
|
|
2588
|
+
}
|
|
2589
|
+
return isWorkerpalEphemeralWorktreePath(opts.repoRoot, entry.path);
|
|
2590
|
+
});
|
|
2591
|
+
let removed = 0;
|
|
2592
|
+
const failures = [];
|
|
2593
|
+
for (const entry of removable) {
|
|
2594
|
+
const remove = await runCommandWithEnvFn(["git", "worktree", "remove", "--force", "--force", entry.path], opts.repoRoot, opts.env);
|
|
2595
|
+
if (remove.ok) {
|
|
2596
|
+
removed += 1;
|
|
2597
|
+
continue;
|
|
2598
|
+
}
|
|
2599
|
+
failures.push(`${entry.path}: ${remove.stderr || remove.stdout || `exit ${remove.exitCode}`}`);
|
|
2600
|
+
}
|
|
2601
|
+
const prune = await runCommandWithEnvFn(["git", "worktree", "prune"], opts.repoRoot, opts.env);
|
|
2602
|
+
if (!prune.ok) {
|
|
2603
|
+
failures.push(`prune: ${prune.stderr || prune.stdout || `exit ${prune.exitCode}`}`);
|
|
2604
|
+
}
|
|
2605
|
+
const deleteTempBranches = await runCommandWithEnvFn([
|
|
2606
|
+
"git",
|
|
2607
|
+
"for-each-ref",
|
|
2608
|
+
"--format=%(refname:short)",
|
|
2609
|
+
`refs/heads/${SOURCE_CONTROL_MANAGER_TEMP_BRANCH_PREFIX}`
|
|
2610
|
+
], opts.repoRoot, opts.env);
|
|
2611
|
+
if (!deleteTempBranches.ok) {
|
|
2612
|
+
failures.push(`list temp branches: ${deleteTempBranches.stderr || deleteTempBranches.stdout || `exit ${deleteTempBranches.exitCode}`}`);
|
|
2613
|
+
} else {
|
|
2614
|
+
const branches = deleteTempBranches.stdout.split(/\r?\n/g).map((value) => value.trim()).filter(Boolean);
|
|
2615
|
+
for (const branch of branches) {
|
|
2616
|
+
const deleteResult = await runCommandWithEnvFn(["git", "branch", "-D", branch], opts.repoRoot, opts.env);
|
|
2617
|
+
if (!deleteResult.ok) {
|
|
2618
|
+
failures.push(`${branch}: ${deleteResult.stderr || deleteResult.stdout || `exit ${deleteResult.exitCode}`}`);
|
|
2619
|
+
} else {
|
|
2620
|
+
removed += 1;
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
if (removed === 0 && failures.length === 0) {
|
|
2625
|
+
return {
|
|
2626
|
+
ok: true,
|
|
2627
|
+
detail: "no lingering PushPals git artifacts found",
|
|
2628
|
+
removed: 0
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
if (failures.length > 0) {
|
|
2632
|
+
return {
|
|
2633
|
+
ok: false,
|
|
2634
|
+
detail: `removed ${removed} lingering PushPals git artifact(s), but cleanup was incomplete: ${failures.join(" | ")}`,
|
|
2635
|
+
removed
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
return {
|
|
2639
|
+
ok: true,
|
|
2640
|
+
detail: `removed ${removed} lingering PushPals git artifact(s)`,
|
|
2641
|
+
removed
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2534
2644
|
async function inspectDockerImageRuntimeTag(dockerExecutable, imageName, cwd, env) {
|
|
2535
2645
|
const inspect = await runCommandWithEnv([
|
|
2536
2646
|
dockerExecutable,
|
|
@@ -4034,6 +4144,19 @@ async function main() {
|
|
|
4034
4144
|
console.log(`[pushpals] ${cleanup.detail} (${phase}).`);
|
|
4035
4145
|
}
|
|
4036
4146
|
};
|
|
4147
|
+
const cleanupPushPalsGitWorktreesIfNeeded = async (phase) => {
|
|
4148
|
+
const cleanup = await cleanupLingeringPushPalsGitWorktrees({
|
|
4149
|
+
repoRoot,
|
|
4150
|
+
env: workerpalDockerPrecheck.env
|
|
4151
|
+
});
|
|
4152
|
+
if (!cleanup.ok) {
|
|
4153
|
+
console.warn(`[pushpals] PushPals worktree cleanup warning (${phase}): ${cleanup.detail}`);
|
|
4154
|
+
return;
|
|
4155
|
+
}
|
|
4156
|
+
if (cleanup.removed > 0) {
|
|
4157
|
+
console.log(`[pushpals] ${cleanup.detail} (${phase}).`);
|
|
4158
|
+
}
|
|
4159
|
+
};
|
|
4037
4160
|
const stopAutoStartedServices = () => {
|
|
4038
4161
|
if (autoStartedServices.length === 0)
|
|
4039
4162
|
return;
|
|
@@ -4056,6 +4179,7 @@ async function main() {
|
|
|
4056
4179
|
}
|
|
4057
4180
|
await stopRuntimeServicesGracefully(services);
|
|
4058
4181
|
await cleanupWorkerpalWarmContainersIfNeeded("cli shutdown");
|
|
4182
|
+
await cleanupPushPalsGitWorktreesIfNeeded("cli shutdown");
|
|
4059
4183
|
};
|
|
4060
4184
|
let serverHealthy = await probeServer(serverUrl);
|
|
4061
4185
|
const serverWasAlreadyHealthy = serverHealthy;
|
|
@@ -4085,6 +4209,7 @@ async function main() {
|
|
|
4085
4209
|
};
|
|
4086
4210
|
if (!serverHealthy) {
|
|
4087
4211
|
await cleanupWorkerpalWarmContainersIfNeeded("startup preflight");
|
|
4212
|
+
await cleanupPushPalsGitWorktreesIfNeeded("startup preflight");
|
|
4088
4213
|
if (!parsed.noAutoStart) {
|
|
4089
4214
|
try {
|
|
4090
4215
|
const startedRuntime = await autoStartRuntimeServices({
|
|
@@ -4383,6 +4508,7 @@ export {
|
|
|
4383
4508
|
downloadRuntimeAssetsFromSourceTag,
|
|
4384
4509
|
copyTrackedRepoPath,
|
|
4385
4510
|
cleanupLingeringWorkerpalWarmContainers,
|
|
4511
|
+
cleanupLingeringPushPalsGitWorktrees,
|
|
4386
4512
|
bundledMonitoringHubNeedsRefresh,
|
|
4387
4513
|
buildWorkerpalSandboxPaths,
|
|
4388
4514
|
buildServiceStopCommand,
|