@pushpalsdev/cli 1.0.7 → 1.0.8
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 +128 -18
- package/package.json +1 -1
package/dist/pushpals-cli.js
CHANGED
|
@@ -1425,9 +1425,10 @@ function runtimeBinaryFilename(serviceName, platformKey) {
|
|
|
1425
1425
|
return `pushpals-runtime-${serviceToken}-${platformKey}${extension}`;
|
|
1426
1426
|
}
|
|
1427
1427
|
function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
1428
|
+
const env = normalizeChildProcessEnv(baseEnv);
|
|
1428
1429
|
const useRuntimeConfig = opts.useRuntimeConfig !== false;
|
|
1429
1430
|
return {
|
|
1430
|
-
...
|
|
1431
|
+
...env,
|
|
1431
1432
|
PUSHPALS_REPO_ROOT_OVERRIDE: opts.repoRoot,
|
|
1432
1433
|
PUSHPALS_PROJECT_ROOT_OVERRIDE: opts.repoRoot,
|
|
1433
1434
|
...useRuntimeConfig ? {
|
|
@@ -1436,9 +1437,61 @@ function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
|
1436
1437
|
} : {
|
|
1437
1438
|
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.repoRoot
|
|
1438
1439
|
},
|
|
1439
|
-
PUSHPALS_PROTOCOL_SCHEMAS_DIR: join2(opts.runtimeRoot, "protocol", "schemas")
|
|
1440
|
+
PUSHPALS_PROTOCOL_SCHEMAS_DIR: join2(opts.runtimeRoot, "protocol", "schemas"),
|
|
1441
|
+
...typeof env.PUSHPALS_GIT_BIN === "string" && env.PUSHPALS_GIT_BIN.trim() ? { PUSHPALS_GIT_BIN: env.PUSHPALS_GIT_BIN.trim() } : {}
|
|
1440
1442
|
};
|
|
1441
1443
|
}
|
|
1444
|
+
function normalizeChildProcessEnv(baseEnv, platform = process.platform) {
|
|
1445
|
+
const env = {};
|
|
1446
|
+
for (const [key, value] of Object.entries(baseEnv)) {
|
|
1447
|
+
if (typeof value === "string")
|
|
1448
|
+
env[key] = value;
|
|
1449
|
+
}
|
|
1450
|
+
if (platform === "win32") {
|
|
1451
|
+
const resolvedPath = String(env.Path ?? env.PATH ?? process.env.Path ?? process.env.PATH ?? "").trim();
|
|
1452
|
+
if (resolvedPath) {
|
|
1453
|
+
env.Path = resolvedPath;
|
|
1454
|
+
env.PATH = resolvedPath;
|
|
1455
|
+
}
|
|
1456
|
+
const systemRoot = String(env.SystemRoot ?? env.SYSTEMROOT ?? process.env.SystemRoot ?? process.env.SYSTEMROOT ?? "").trim();
|
|
1457
|
+
if (systemRoot) {
|
|
1458
|
+
env.SystemRoot = systemRoot;
|
|
1459
|
+
env.SYSTEMROOT = systemRoot;
|
|
1460
|
+
}
|
|
1461
|
+
const comSpec = String(env.ComSpec ?? env.COMSPEC ?? process.env.ComSpec ?? process.env.COMSPEC ?? "").trim();
|
|
1462
|
+
if (comSpec) {
|
|
1463
|
+
env.ComSpec = comSpec;
|
|
1464
|
+
env.COMSPEC = comSpec;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
return env;
|
|
1468
|
+
}
|
|
1469
|
+
async function resolveCommandPath(command, cwd, env) {
|
|
1470
|
+
const lookupCommands = process.platform === "win32" ? [
|
|
1471
|
+
["where.exe", command],
|
|
1472
|
+
["where", command]
|
|
1473
|
+
] : [["which", command]];
|
|
1474
|
+
for (const lookup of lookupCommands) {
|
|
1475
|
+
try {
|
|
1476
|
+
const proc = Bun.spawn(lookup, {
|
|
1477
|
+
cwd,
|
|
1478
|
+
env,
|
|
1479
|
+
stdout: "pipe",
|
|
1480
|
+
stderr: "ignore"
|
|
1481
|
+
});
|
|
1482
|
+
const [stdout, exitCode] = await Promise.all([
|
|
1483
|
+
new Response(proc.stdout).text(),
|
|
1484
|
+
proc.exited
|
|
1485
|
+
]);
|
|
1486
|
+
if (exitCode !== 0)
|
|
1487
|
+
continue;
|
|
1488
|
+
const resolved = stdout.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0);
|
|
1489
|
+
if (resolved)
|
|
1490
|
+
return resolved;
|
|
1491
|
+
} catch {}
|
|
1492
|
+
}
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1442
1495
|
function timestampFileToken() {
|
|
1443
1496
|
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
1444
1497
|
}
|
|
@@ -1546,11 +1599,18 @@ function spawnRuntimeService(name, command, cwd, env, logPath) {
|
|
|
1546
1599
|
});
|
|
1547
1600
|
return service;
|
|
1548
1601
|
}
|
|
1602
|
+
function buildServiceStopCommand(pid, platform = process.platform) {
|
|
1603
|
+
if (platform === "win32" && typeof pid === "number" && pid > 0) {
|
|
1604
|
+
return ["taskkill", "/PID", String(pid), "/T", "/F"];
|
|
1605
|
+
}
|
|
1606
|
+
return null;
|
|
1607
|
+
}
|
|
1549
1608
|
function stopRuntimeServices(services) {
|
|
1550
1609
|
for (const service of services) {
|
|
1551
1610
|
try {
|
|
1552
|
-
|
|
1553
|
-
|
|
1611
|
+
const stopCommand = buildServiceStopCommand(service.proc.pid, process.platform);
|
|
1612
|
+
if (stopCommand) {
|
|
1613
|
+
Bun.spawnSync(stopCommand, {
|
|
1554
1614
|
stdin: "ignore",
|
|
1555
1615
|
stdout: "ignore",
|
|
1556
1616
|
stderr: "ignore"
|
|
@@ -1561,6 +1621,24 @@ function stopRuntimeServices(services) {
|
|
|
1561
1621
|
} catch {}
|
|
1562
1622
|
}
|
|
1563
1623
|
}
|
|
1624
|
+
function isOptionalEmbeddedService(name) {
|
|
1625
|
+
return name === "source_control_manager";
|
|
1626
|
+
}
|
|
1627
|
+
async function canSpawnCommand(command, cwd, env) {
|
|
1628
|
+
try {
|
|
1629
|
+
const proc = Bun.spawn(command, {
|
|
1630
|
+
cwd,
|
|
1631
|
+
env,
|
|
1632
|
+
stdin: "ignore",
|
|
1633
|
+
stdout: "ignore",
|
|
1634
|
+
stderr: "ignore"
|
|
1635
|
+
});
|
|
1636
|
+
const exitCode = await proc.exited;
|
|
1637
|
+
return exitCode === 0;
|
|
1638
|
+
} catch {
|
|
1639
|
+
return false;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1564
1642
|
async function repoHasRemote(repoRoot, remote) {
|
|
1565
1643
|
const normalizedRemote = remote.trim();
|
|
1566
1644
|
if (!normalizedRemote)
|
|
@@ -1630,6 +1708,10 @@ async function autoStartRuntimeServices(opts) {
|
|
|
1630
1708
|
runtimeRoot,
|
|
1631
1709
|
useRuntimeConfig: opts.preparedRuntime.preflightUsesEmbeddedRuntime
|
|
1632
1710
|
});
|
|
1711
|
+
const resolvedGitBinary = await resolveCommandPath("git", opts.repoRoot, normalizeChildProcessEnv(process.env));
|
|
1712
|
+
if (resolvedGitBinary) {
|
|
1713
|
+
runtimeEnv.PUSHPALS_GIT_BIN = resolvedGitBinary;
|
|
1714
|
+
}
|
|
1633
1715
|
const services = [];
|
|
1634
1716
|
const runToken = timestampFileToken();
|
|
1635
1717
|
const logDir = join2(runtimeRoot, "logs", "bootstrap");
|
|
@@ -1678,13 +1760,24 @@ ${tail}` : ""}`);
|
|
|
1678
1760
|
console.log(`[pushpals] remotebuddy log: ${remotebuddyService.logPath}`);
|
|
1679
1761
|
const scmHealthy = await probeSourceControlManager(opts.sourceControlManagerPort);
|
|
1680
1762
|
const scmRemoteAvailable = await repoHasRemote(opts.repoRoot, opts.sourceControlManagerRemote);
|
|
1763
|
+
const gitProbeCommand = typeof runtimeEnv.PUSHPALS_GIT_BIN === "string" && runtimeEnv.PUSHPALS_GIT_BIN.trim() ? [runtimeEnv.PUSHPALS_GIT_BIN.trim(), "--version"] : ["git", "--version"];
|
|
1764
|
+
const gitAvailableForScm = await canSpawnCommand(gitProbeCommand, opts.repoRoot, runtimeEnv);
|
|
1681
1765
|
if (!scmHealthy && scmRemoteAvailable) {
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1766
|
+
if (!gitAvailableForScm) {
|
|
1767
|
+
console.warn("[pushpals] Git is not available to embedded SourceControlManager; skipping SCM startup.");
|
|
1768
|
+
} else {
|
|
1769
|
+
if (runtimeEnv.PUSHPALS_GIT_BIN) {
|
|
1770
|
+
console.log(`[pushpals] Embedded SourceControlManager git=${runtimeEnv.PUSHPALS_GIT_BIN}`);
|
|
1771
|
+
}
|
|
1772
|
+
console.log("[pushpals] Starting embedded SourceControlManager...");
|
|
1773
|
+
const sourceControlManagerService = spawnRuntimeService("source_control_manager", [runtimeBinaries.sourceControlManager, "--skip-clean-check"], opts.repoRoot, runtimeEnv, logPathFor("source_control_manager"));
|
|
1774
|
+
services.push(sourceControlManagerService);
|
|
1775
|
+
console.log(`[pushpals] source_control_manager log: ${sourceControlManagerService.logPath}`);
|
|
1776
|
+
}
|
|
1686
1777
|
} else if (!scmRemoteAvailable) {
|
|
1687
1778
|
console.log(`[pushpals] Repo has no git remote "${opts.sourceControlManagerRemote}"; skipping embedded SourceControlManager.`);
|
|
1779
|
+
} else if (!gitAvailableForScm) {
|
|
1780
|
+
console.warn("[pushpals] Git is not available to embedded SourceControlManager; skipping SCM startup.");
|
|
1688
1781
|
} else {
|
|
1689
1782
|
console.log("[pushpals] SourceControlManager already healthy; skipping embedded start.");
|
|
1690
1783
|
}
|
|
@@ -1693,7 +1786,7 @@ ${tail}` : ""}`);
|
|
|
1693
1786
|
for (let i = services.length - 1;i >= 0; i--) {
|
|
1694
1787
|
const service = services[i];
|
|
1695
1788
|
if (service.exited) {
|
|
1696
|
-
if (service.name
|
|
1789
|
+
if (isOptionalEmbeddedService(service.name)) {
|
|
1697
1790
|
console.warn(`[pushpals] Embedded ${service.name} exited during startup (code=${service.exitCode ?? "unknown"}); continuing without SCM.`);
|
|
1698
1791
|
const tail2 = readLogTail(service.logPath);
|
|
1699
1792
|
if (tail2) {
|
|
@@ -1714,9 +1807,20 @@ ${tail}` : ""}`);
|
|
|
1714
1807
|
if (health?.ok) {
|
|
1715
1808
|
const stabilityDeadline = Date.now() + DEFAULT_SERVICE_STABILITY_GRACE_MS;
|
|
1716
1809
|
while (Date.now() < stabilityDeadline) {
|
|
1717
|
-
for (
|
|
1810
|
+
for (let i = services.length - 1;i >= 0; i--) {
|
|
1811
|
+
const service = services[i];
|
|
1718
1812
|
if (!service.exited)
|
|
1719
1813
|
continue;
|
|
1814
|
+
if (isOptionalEmbeddedService(service.name)) {
|
|
1815
|
+
const tail2 = readLogTail(service.logPath);
|
|
1816
|
+
console.warn(`[pushpals] Embedded ${service.name} exited immediately after bootstrap (code=${service.exitCode ?? "unknown"}); continuing without SCM.`);
|
|
1817
|
+
if (tail2) {
|
|
1818
|
+
console.warn(`[pushpals] ${service.name} log tail:
|
|
1819
|
+
${tail2}`);
|
|
1820
|
+
}
|
|
1821
|
+
services.splice(i, 1);
|
|
1822
|
+
continue;
|
|
1823
|
+
}
|
|
1720
1824
|
const tail = readLogTail(service.logPath);
|
|
1721
1825
|
stopRuntimeServices(services);
|
|
1722
1826
|
throw new Error(`Embedded ${service.name} exited immediately after bootstrap (code=${service.exitCode ?? "unknown"}). ` + `See ${service.logPath}${tail ? `
|
|
@@ -2163,15 +2267,17 @@ async function runSessionStream(serverUrl, sessionId, authToken, print, signal)
|
|
|
2163
2267
|
}
|
|
2164
2268
|
}
|
|
2165
2269
|
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
} else {
|
|
2173
|
-
cmd = ["xdg-open", url];
|
|
2270
|
+
function buildOpenMonitoringHubCommand(url, platform = process.platform) {
|
|
2271
|
+
if (platform === "win32") {
|
|
2272
|
+
return ["cmd", "/c", "start", "", url];
|
|
2273
|
+
}
|
|
2274
|
+
if (platform === "darwin") {
|
|
2275
|
+
return ["open", url];
|
|
2174
2276
|
}
|
|
2277
|
+
return ["xdg-open", url];
|
|
2278
|
+
}
|
|
2279
|
+
async function openMonitoringHub(url) {
|
|
2280
|
+
const cmd = buildOpenMonitoringHubCommand(url, process.platform);
|
|
2175
2281
|
const proc = Bun.spawn(cmd, {
|
|
2176
2282
|
stdin: "ignore",
|
|
2177
2283
|
stdout: "ignore",
|
|
@@ -2395,8 +2501,12 @@ if (import.meta.main) {
|
|
|
2395
2501
|
}
|
|
2396
2502
|
export {
|
|
2397
2503
|
startEmbeddedMonitoringHub,
|
|
2504
|
+
resolveCommandPath,
|
|
2398
2505
|
resolveBundledRuntimeAssetSource,
|
|
2399
2506
|
prepareCliRuntime,
|
|
2507
|
+
normalizeChildProcessEnv,
|
|
2508
|
+
buildServiceStopCommand,
|
|
2509
|
+
buildOpenMonitoringHubCommand,
|
|
2400
2510
|
buildEmbeddedRuntimeEnv,
|
|
2401
2511
|
buildEmbeddedMonitoringHubHtml
|
|
2402
2512
|
};
|