@pushpalsdev/cli 1.1.4 → 1.1.5
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 +80 -69
- package/package.json +1 -1
package/dist/pushpals-cli.js
CHANGED
|
@@ -1620,6 +1620,8 @@ var DEFAULT_RUNTIME_BOOT_TIMEOUT_MS = 90000;
|
|
|
1620
1620
|
var DEFAULT_RUNTIME_BOOT_POLL_MS = 1000;
|
|
1621
1621
|
var DEFAULT_SERVER_BOOT_TIMEOUT_MS = 20000;
|
|
1622
1622
|
var DEFAULT_SERVICE_STABILITY_GRACE_MS = 4000;
|
|
1623
|
+
var DEFAULT_STARTUP_GIT_PROBE_TIMEOUT_MS = 5000;
|
|
1624
|
+
var DEFAULT_STARTUP_GIT_REMOTE_TIMEOUT_MS = 1e4;
|
|
1623
1625
|
var EMBEDDED_SERVICE_RESTART_MAX_ATTEMPTS = 4;
|
|
1624
1626
|
var WORKERPAL_STARTUP_READINESS_PROBE_MAX_MS = 15000;
|
|
1625
1627
|
var EMBEDDED_RUNTIME_SAFETY_CAP_DISABLE_ENV = "PUSHPALS_DISABLE_EMBEDDED_SAFETY_CAPS";
|
|
@@ -1917,6 +1919,31 @@ function parsePositiveInt(value, fallback) {
|
|
|
1917
1919
|
return fallback;
|
|
1918
1920
|
return parsed;
|
|
1919
1921
|
}
|
|
1922
|
+
function clampPositiveInt(value, min, max) {
|
|
1923
|
+
if (!Number.isFinite(value))
|
|
1924
|
+
return min;
|
|
1925
|
+
return Math.max(min, Math.min(max, Math.trunc(value)));
|
|
1926
|
+
}
|
|
1927
|
+
function resolveStartupGitProbeTimeoutMs(env) {
|
|
1928
|
+
return clampPositiveInt(parsePositiveInt(env.PUSHPALS_STARTUP_GIT_PROBE_TIMEOUT_MS, DEFAULT_STARTUP_GIT_PROBE_TIMEOUT_MS), 1000, 30000);
|
|
1929
|
+
}
|
|
1930
|
+
function resolveStartupGitRemoteTimeoutMs(env) {
|
|
1931
|
+
return clampPositiveInt(parsePositiveInt(env.PUSHPALS_STARTUP_GIT_REMOTE_TIMEOUT_MS, DEFAULT_STARTUP_GIT_REMOTE_TIMEOUT_MS), 1000, 60000);
|
|
1932
|
+
}
|
|
1933
|
+
async function withStartupTimeout(promise, timeoutMs, timeoutValue) {
|
|
1934
|
+
let timer = null;
|
|
1935
|
+
try {
|
|
1936
|
+
return await Promise.race([
|
|
1937
|
+
promise,
|
|
1938
|
+
new Promise((resolveTimeout) => {
|
|
1939
|
+
timer = setTimeout(() => resolveTimeout(timeoutValue()), Math.max(1, timeoutMs));
|
|
1940
|
+
})
|
|
1941
|
+
]);
|
|
1942
|
+
} finally {
|
|
1943
|
+
if (timer)
|
|
1944
|
+
clearTimeout(timer);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1920
1947
|
function jsonHtmlBootstrap(value) {
|
|
1921
1948
|
return JSON.stringify(value).replace(/</g, "\\u003c");
|
|
1922
1949
|
}
|
|
@@ -2000,15 +2027,15 @@ function withWindowsGitSchannelEnv(env, platform = process.platform) {
|
|
|
2000
2027
|
return env;
|
|
2001
2028
|
return appendGitConfigEnv(env, "http.sslBackend", "schannel");
|
|
2002
2029
|
}
|
|
2003
|
-
async function runGitWithEnv(args, cwd, env) {
|
|
2004
|
-
return await runCommandWithEnv(["git", ...args], cwd, withWindowsGitSchannelEnv(env));
|
|
2030
|
+
async function runGitWithEnv(args, cwd, env, timeoutMs) {
|
|
2031
|
+
return await runCommandWithEnv(["git", ...args], cwd, withWindowsGitSchannelEnv(env), timeoutMs);
|
|
2005
2032
|
}
|
|
2006
|
-
async function runGit(args, cwd) {
|
|
2033
|
+
async function runGit(args, cwd, timeoutMs) {
|
|
2007
2034
|
return await runGitWithEnv(args, cwd, {
|
|
2008
2035
|
...process.env,
|
|
2009
2036
|
GIT_TERMINAL_PROMPT: "0",
|
|
2010
2037
|
GCM_INTERACTIVE: "Never"
|
|
2011
|
-
});
|
|
2038
|
+
}, timeoutMs);
|
|
2012
2039
|
}
|
|
2013
2040
|
async function resolveCurrentGitRepoRoot(cwd) {
|
|
2014
2041
|
const inside = await runGit(["rev-parse", "--is-inside-work-tree"], cwd);
|
|
@@ -2738,20 +2765,14 @@ function normalizeChildProcessEnv(baseEnv, platform = process.platform) {
|
|
|
2738
2765
|
}
|
|
2739
2766
|
return env;
|
|
2740
2767
|
}
|
|
2741
|
-
async function resolveCommandPath(command, cwd, env) {
|
|
2768
|
+
async function resolveCommandPath(command, cwd, env, timeoutMs = resolveStartupGitProbeTimeoutMs(env)) {
|
|
2742
2769
|
const lookupCommands = process.platform === "win32" ? resolveWindowsWhereExecutableCandidatesForEnv(env, process.platform).map((lookup) => [lookup, command]) : [["which", command]];
|
|
2743
2770
|
for (const lookup of lookupCommands) {
|
|
2744
2771
|
try {
|
|
2745
|
-
const
|
|
2746
|
-
|
|
2747
|
-
env,
|
|
2748
|
-
stdout: "pipe",
|
|
2749
|
-
stderr: "ignore"
|
|
2750
|
-
});
|
|
2751
|
-
const [stdout, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
2752
|
-
if (exitCode !== 0)
|
|
2772
|
+
const result = await runCommandWithEnv(lookup, cwd, env, timeoutMs);
|
|
2773
|
+
if (!result.ok)
|
|
2753
2774
|
continue;
|
|
2754
|
-
const resolved = stdout.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0);
|
|
2775
|
+
const resolved = result.stdout.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0);
|
|
2755
2776
|
if (resolved)
|
|
2756
2777
|
return resolved;
|
|
2757
2778
|
} catch {}
|
|
@@ -3159,50 +3180,31 @@ function computeEmbeddedServiceRestartBackoffMs(attempt) {
|
|
|
3159
3180
|
function shouldRestartEmbeddedService(attempts, maxAttempts = EMBEDDED_SERVICE_RESTART_MAX_ATTEMPTS) {
|
|
3160
3181
|
return shouldRestartService(attempts, maxAttempts);
|
|
3161
3182
|
}
|
|
3162
|
-
async function canSpawnCommand(command, cwd, env) {
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
cwd,
|
|
3166
|
-
env,
|
|
3167
|
-
stdin: "ignore",
|
|
3168
|
-
stdout: "ignore",
|
|
3169
|
-
stderr: "ignore"
|
|
3170
|
-
});
|
|
3171
|
-
const exitCode = await proc.exited;
|
|
3172
|
-
return exitCode === 0;
|
|
3173
|
-
} catch {
|
|
3174
|
-
return false;
|
|
3175
|
-
}
|
|
3183
|
+
async function canSpawnCommand(command, cwd, env, timeoutMs = resolveStartupGitProbeTimeoutMs(env)) {
|
|
3184
|
+
const result = await runCommandWithEnv(command, cwd, env, timeoutMs);
|
|
3185
|
+
return result.ok;
|
|
3176
3186
|
}
|
|
3177
|
-
async function canSpawnGitViaWindowsShell(commandArgs, cwd, env, platform = process.platform) {
|
|
3187
|
+
async function canSpawnGitViaWindowsShell(commandArgs, cwd, env, platform = process.platform, timeoutMs = resolveStartupGitProbeTimeoutMs(env)) {
|
|
3178
3188
|
if (platform !== "win32")
|
|
3179
3189
|
return false;
|
|
3180
3190
|
const commandLine = commandArgs.map((arg) => quoteWindowsCmdArg(arg)).join(" ");
|
|
3181
3191
|
for (const shellExecutable of resolveWindowsShellExecutableCandidatesForEnv(env, platform)) {
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
env,
|
|
3186
|
-
stdin: "ignore",
|
|
3187
|
-
stdout: "ignore",
|
|
3188
|
-
stderr: "ignore"
|
|
3189
|
-
});
|
|
3190
|
-
const exitCode = await proc.exited;
|
|
3191
|
-
return exitCode === 0;
|
|
3192
|
-
} catch {}
|
|
3192
|
+
const result = await runCommandWithEnv([shellExecutable, "/d", "/s", "/c", commandLine], cwd, env, timeoutMs);
|
|
3193
|
+
if (result.ok)
|
|
3194
|
+
return true;
|
|
3193
3195
|
}
|
|
3194
3196
|
return false;
|
|
3195
3197
|
}
|
|
3196
|
-
async function resolveSourceControlManagerGitProbe(cwd, env, platform = process.platform) {
|
|
3198
|
+
async function resolveSourceControlManagerGitProbe(cwd, env, platform = process.platform, timeoutMs = resolveStartupGitProbeTimeoutMs(env)) {
|
|
3197
3199
|
const candidates = resolveRuntimeGitExecutableCandidates(env, platform);
|
|
3198
3200
|
for (const candidate of candidates) {
|
|
3199
|
-
if (await canSpawnCommand([candidate, "--version"], cwd, env)) {
|
|
3201
|
+
if (await canSpawnCommand([candidate, "--version"], cwd, env, timeoutMs)) {
|
|
3200
3202
|
return { ok: true, detail: candidate };
|
|
3201
3203
|
}
|
|
3202
3204
|
}
|
|
3203
3205
|
if (platform === "win32") {
|
|
3204
3206
|
for (const candidate of candidates) {
|
|
3205
|
-
if (await canSpawnGitViaWindowsShell([candidate, "--version"], cwd, env, platform)) {
|
|
3207
|
+
if (await canSpawnGitViaWindowsShell([candidate, "--version"], cwd, env, platform, timeoutMs)) {
|
|
3206
3208
|
return { ok: true, detail: `${candidate} via shell` };
|
|
3207
3209
|
}
|
|
3208
3210
|
}
|
|
@@ -3630,7 +3632,12 @@ async function precheckSourceControlManagerGitAvailability(opts) {
|
|
|
3630
3632
|
if (preconfiguredGitBinary) {
|
|
3631
3633
|
applyResolvedGitBinaryToRuntimeEnv(env, preconfiguredGitBinary, platform);
|
|
3632
3634
|
}
|
|
3633
|
-
const
|
|
3635
|
+
const remoteTimeoutMs = resolveStartupGitRemoteTimeoutMs(env);
|
|
3636
|
+
const remoteStatus = await withStartupTimeout(opts.gitRemoteCheckFn ? opts.gitRemoteCheckFn(opts.repoRoot, opts.remote, env) : opts.repoHasRemoteFn ? opts.repoHasRemoteFn(opts.repoRoot, opts.remote).then((hasRemote) => hasRemote ? { status: "ok", remote: opts.remote } : { status: "missing_remote", remote: opts.remote }) : checkGitRemoteConfigured(opts.repoRoot, opts.remote, env, remoteTimeoutMs), remoteTimeoutMs, () => ({
|
|
3637
|
+
status: "error",
|
|
3638
|
+
remote: opts.remote,
|
|
3639
|
+
detail: `timed out after ${remoteTimeoutMs}ms`
|
|
3640
|
+
}));
|
|
3634
3641
|
if (remoteStatus.status === "missing_remote") {
|
|
3635
3642
|
return {
|
|
3636
3643
|
status: "skipped",
|
|
@@ -3719,7 +3726,7 @@ function resolveWorkerpalStartupReadinessProbeTimeoutMs(config) {
|
|
|
3719
3726
|
function shouldRunEmbeddedRuntimeStartupPrechecks(opts) {
|
|
3720
3727
|
return !opts.serverHealthy && !opts.noAutoStart;
|
|
3721
3728
|
}
|
|
3722
|
-
async function checkGitRemoteConfigured(repoRoot, remote, env) {
|
|
3729
|
+
async function checkGitRemoteConfigured(repoRoot, remote, env, timeoutMs = resolveStartupGitRemoteTimeoutMs(env ?? process.env)) {
|
|
3723
3730
|
const normalizedRemote = String(remote ?? "").trim();
|
|
3724
3731
|
if (!normalizedRemote) {
|
|
3725
3732
|
return { status: "missing_remote", remote: normalizedRemote };
|
|
@@ -3728,7 +3735,7 @@ async function checkGitRemoteConfigured(repoRoot, remote, env) {
|
|
|
3728
3735
|
...process.env,
|
|
3729
3736
|
GIT_TERMINAL_PROMPT: "0",
|
|
3730
3737
|
GCM_INTERACTIVE: "Never"
|
|
3731
|
-
});
|
|
3738
|
+
}, timeoutMs);
|
|
3732
3739
|
if (result.ok && result.stdout) {
|
|
3733
3740
|
return { status: "ok", remote: normalizedRemote };
|
|
3734
3741
|
}
|
|
@@ -3757,7 +3764,7 @@ async function checkPushpalsBranchOnRemote(repoRoot, remote, branch) {
|
|
|
3757
3764
|
};
|
|
3758
3765
|
}
|
|
3759
3766
|
const ref = `refs/heads/${normalizedBranch}`;
|
|
3760
|
-
const result = await runGit(["ls-remote", "--heads", normalizedRemote, ref], repoRoot);
|
|
3767
|
+
const result = await runGit(["ls-remote", "--heads", normalizedRemote, ref], repoRoot, resolveStartupGitRemoteTimeoutMs(process.env));
|
|
3761
3768
|
if (!result.ok) {
|
|
3762
3769
|
const detail = result.stderr || result.stdout || `exit ${result.exitCode}`;
|
|
3763
3770
|
return {
|
|
@@ -3789,8 +3796,9 @@ async function enforcePushpalsRemoteBranchPrecheck(repoRoot, remote, branch) {
|
|
|
3789
3796
|
console.error("[pushpals] Precheck failed: create/push that branch first or set source_control_manager.pushpals_branch to an existing remote branch.");
|
|
3790
3797
|
return false;
|
|
3791
3798
|
}
|
|
3792
|
-
console.
|
|
3793
|
-
|
|
3799
|
+
console.warn(`[pushpals] Precheck warning: could not verify remote branch "${result.remote}/${result.branch}": ${result.detail}`);
|
|
3800
|
+
console.warn("[pushpals] Precheck warning: continuing startup without SourceControlManager branch verification because the remote check was inconclusive.");
|
|
3801
|
+
return true;
|
|
3794
3802
|
}
|
|
3795
3803
|
function isPathEqualOrWithin(parentPath, childPath) {
|
|
3796
3804
|
const parent = normalizeRepoPathForComparison(parentPath);
|
|
@@ -4459,31 +4467,35 @@ ${tail}` : ""}`);
|
|
|
4459
4467
|
recordStartupPhase("workerpal", Date.now(), "disabled");
|
|
4460
4468
|
}
|
|
4461
4469
|
const scmHealthy = await probeSourceControlManager(opts.sourceControlManagerPort);
|
|
4462
|
-
const scmGitProbe = await resolveSourceControlManagerGitProbe(opts.repoRoot, runtimeEnv, process.platform);
|
|
4463
|
-
const scmRemoteStatus = await checkGitRemoteConfigured(opts.repoRoot, opts.sourceControlManagerRemote, runtimeEnv);
|
|
4464
4470
|
if (!scmHealthy) {
|
|
4465
4471
|
const scmPhaseStartedAt = Date.now();
|
|
4472
|
+
console.log("[pushpals] Checking embedded SourceControlManager git/remote preflight...");
|
|
4473
|
+
appendRuntimeServicesLogLine(runtimeServicesLogPath, "[pushpals] checking embedded source_control_manager git/remote preflight.");
|
|
4474
|
+
const scmGitProbe = await resolveSourceControlManagerGitProbe(opts.repoRoot, runtimeEnv, process.platform);
|
|
4466
4475
|
if (!scmGitProbe.ok) {
|
|
4467
4476
|
console.warn("[pushpals] Git is not available to embedded SourceControlManager; skipping SCM startup.");
|
|
4468
4477
|
appendRuntimeServicesLogLine(runtimeServicesLogPath, `[pushpals] source_control_manager skipped: git is unavailable in embedded runtime env (${scmGitProbe.detail}).`);
|
|
4469
4478
|
recordStartupPhase("source_control_manager", scmPhaseStartedAt, "skipped_no_git");
|
|
4470
|
-
} else if (scmRemoteStatus.status === "error") {
|
|
4471
|
-
console.warn(`[pushpals] Could not inspect SourceControlManager git remote "${opts.sourceControlManagerRemote}"; skipping SCM startup.`);
|
|
4472
|
-
appendRuntimeServicesLogLine(runtimeServicesLogPath, `[pushpals] source_control_manager skipped: remote "${opts.sourceControlManagerRemote}" could not be inspected (${scmRemoteStatus.detail}).`);
|
|
4473
|
-
recordStartupPhase("source_control_manager", scmPhaseStartedAt, "skipped_remote_error");
|
|
4474
|
-
} else if (scmRemoteStatus.status === "ok") {
|
|
4475
|
-
console.log(`[pushpals] Embedded SourceControlManager git=${scmGitProbe.detail}`);
|
|
4476
|
-
console.log("[pushpals] Starting embedded SourceControlManager...");
|
|
4477
|
-
const sourceControlManagerService = launchService("source_control_manager", [
|
|
4478
|
-
runtimeBinaries.sourceControlManager,
|
|
4479
|
-
"--skip-clean-check"
|
|
4480
|
-
]);
|
|
4481
|
-
console.log(`[pushpals] source_control_manager log: ${sourceControlManagerService.logPath ?? serviceLogPaths.source_control_manager}`);
|
|
4482
|
-
recordStartupPhase("source_control_manager", scmPhaseStartedAt, "started");
|
|
4483
4479
|
} else {
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4480
|
+
const scmRemoteStatus = await checkGitRemoteConfigured(opts.repoRoot, opts.sourceControlManagerRemote, runtimeEnv);
|
|
4481
|
+
if (scmRemoteStatus.status === "error") {
|
|
4482
|
+
console.warn(`[pushpals] Could not inspect SourceControlManager git remote "${opts.sourceControlManagerRemote}"; skipping SCM startup.`);
|
|
4483
|
+
appendRuntimeServicesLogLine(runtimeServicesLogPath, `[pushpals] source_control_manager skipped: remote "${opts.sourceControlManagerRemote}" could not be inspected (${scmRemoteStatus.detail}).`);
|
|
4484
|
+
recordStartupPhase("source_control_manager", scmPhaseStartedAt, "skipped_remote_error");
|
|
4485
|
+
} else if (scmRemoteStatus.status === "ok") {
|
|
4486
|
+
console.log(`[pushpals] Embedded SourceControlManager git=${scmGitProbe.detail}`);
|
|
4487
|
+
console.log("[pushpals] Starting embedded SourceControlManager...");
|
|
4488
|
+
const sourceControlManagerService = launchService("source_control_manager", [
|
|
4489
|
+
runtimeBinaries.sourceControlManager,
|
|
4490
|
+
"--skip-clean-check"
|
|
4491
|
+
]);
|
|
4492
|
+
console.log(`[pushpals] source_control_manager log: ${sourceControlManagerService.logPath ?? serviceLogPaths.source_control_manager}`);
|
|
4493
|
+
recordStartupPhase("source_control_manager", scmPhaseStartedAt, "started");
|
|
4494
|
+
} else {
|
|
4495
|
+
console.log(`[pushpals] Repo has no git remote "${opts.sourceControlManagerRemote}"; skipping embedded SourceControlManager.`);
|
|
4496
|
+
appendRuntimeServicesLogLine(runtimeServicesLogPath, `[pushpals] source_control_manager skipped: repo has no remote "${opts.sourceControlManagerRemote}".`);
|
|
4497
|
+
recordStartupPhase("source_control_manager", scmPhaseStartedAt, "skipped_no_remote");
|
|
4498
|
+
}
|
|
4487
4499
|
}
|
|
4488
4500
|
} else {
|
|
4489
4501
|
recordStartupPhase("source_control_manager", Date.now(), "reused");
|
|
@@ -5249,8 +5261,7 @@ async function main() {
|
|
|
5249
5261
|
sessionId
|
|
5250
5262
|
});
|
|
5251
5263
|
if (scmGitPrecheck.status === "failed") {
|
|
5252
|
-
console.
|
|
5253
|
-
process.exit(1);
|
|
5264
|
+
console.warn(`[pushpals] Embedded SourceControlManager precheck failed (${scmGitPrecheck.detail}); continuing startup without blocking on SCM.`);
|
|
5254
5265
|
}
|
|
5255
5266
|
workerpalDockerPrecheck = await precheckWorkerpalDockerAvailability({
|
|
5256
5267
|
repoRoot,
|