@pushpalsdev/cli 1.0.7 → 1.0.9
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 +300 -33
- package/monitor-ui/+not-found.html +440 -0
- package/monitor-ui/_expo/.routes.json +3 -0
- package/monitor-ui/_expo/static/js/web/entry-7e55666b7443eef13f7696e8d422e8cf.js +1218 -0
- package/monitor-ui/_expo/static/js/web/index-04194fb85c12ac46718492c2ff687e6c.js +6 -0
- package/monitor-ui/_sitemap.html +440 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
- package/monitor-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
- package/monitor-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
- package/monitor-ui/favicon.ico +0 -0
- package/monitor-ui/index.html +440 -0
- package/monitor-ui/modal.html +440 -0
- package/package.json +3 -2
package/dist/pushpals-cli.js
CHANGED
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// ../../scripts/pushpals-cli.ts
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
appendFileSync,
|
|
7
|
+
chmodSync,
|
|
8
|
+
cpSync,
|
|
9
|
+
existsSync as existsSync3,
|
|
10
|
+
mkdirSync,
|
|
11
|
+
readFileSync as readFileSync3,
|
|
12
|
+
writeFileSync
|
|
13
|
+
} from "fs";
|
|
14
|
+
import { dirname, extname, join as join2, resolve as resolve3 } from "path";
|
|
7
15
|
import { createInterface } from "readline";
|
|
8
16
|
|
|
9
17
|
// ../shared/src/client_preflight.ts
|
|
@@ -1228,6 +1236,56 @@ function resolveBundledRuntimeAssetSource() {
|
|
|
1228
1236
|
}
|
|
1229
1237
|
return null;
|
|
1230
1238
|
}
|
|
1239
|
+
function looksLikeMonitoringHubBuild(root) {
|
|
1240
|
+
return existsSync3(join2(root, "index.html")) && existsSync3(join2(root, "_expo"));
|
|
1241
|
+
}
|
|
1242
|
+
function resolveBundledMonitoringHubRoot() {
|
|
1243
|
+
const candidates = [
|
|
1244
|
+
resolve3(import.meta.dir, "..", "monitor-ui"),
|
|
1245
|
+
resolve3(import.meta.dir, "..", "packages", "cli", "monitor-ui")
|
|
1246
|
+
];
|
|
1247
|
+
for (const candidate of candidates) {
|
|
1248
|
+
if (looksLikeMonitoringHubBuild(candidate))
|
|
1249
|
+
return candidate;
|
|
1250
|
+
}
|
|
1251
|
+
return null;
|
|
1252
|
+
}
|
|
1253
|
+
function resolveCliSourceCheckoutRoot() {
|
|
1254
|
+
const candidates = [
|
|
1255
|
+
resolve3(import.meta.dir, ".."),
|
|
1256
|
+
resolve3(import.meta.dir, "..", ".."),
|
|
1257
|
+
resolve3(import.meta.dir, "..", "..", "..")
|
|
1258
|
+
];
|
|
1259
|
+
for (const candidate of candidates) {
|
|
1260
|
+
if (existsSync3(join2(candidate, "package.json")) && existsSync3(join2(candidate, "apps", "client", "app.json")) && existsSync3(join2(candidate, "scripts", "sync-cli-monitor-ui.ts"))) {
|
|
1261
|
+
return candidate;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1266
|
+
function exportBundledMonitoringHubFromSourceCheckout(sourceRoot) {
|
|
1267
|
+
const exportScriptPath = join2(sourceRoot, "scripts", "sync-cli-monitor-ui.ts");
|
|
1268
|
+
console.log("[pushpals] Packaged monitor UI missing; exporting the shared client monitor...");
|
|
1269
|
+
const proc = Bun.spawnSync([process.execPath, exportScriptPath], {
|
|
1270
|
+
cwd: sourceRoot,
|
|
1271
|
+
stdout: "inherit",
|
|
1272
|
+
stderr: "inherit",
|
|
1273
|
+
env: process.env
|
|
1274
|
+
});
|
|
1275
|
+
if (proc.exitCode !== 0) {
|
|
1276
|
+
throw new Error(`Failed to export packaged monitor UI from source checkout (exit ${proc.exitCode || 1})`);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
async function ensureBundledMonitoringHubRoot() {
|
|
1280
|
+
const existingRoot = resolveBundledMonitoringHubRoot();
|
|
1281
|
+
if (existingRoot)
|
|
1282
|
+
return existingRoot;
|
|
1283
|
+
const sourceRoot = resolveCliSourceCheckoutRoot();
|
|
1284
|
+
if (!sourceRoot)
|
|
1285
|
+
return null;
|
|
1286
|
+
exportBundledMonitoringHubFromSourceCheckout(sourceRoot);
|
|
1287
|
+
return resolveBundledMonitoringHubRoot();
|
|
1288
|
+
}
|
|
1231
1289
|
function repoLooksLikePushPalsSourceCheckout(repoRoot) {
|
|
1232
1290
|
return existsSync3(join2(repoRoot, "configs", "default.toml")) || existsSync3(join2(repoRoot, "config", "default.toml"));
|
|
1233
1291
|
}
|
|
@@ -1425,9 +1483,10 @@ function runtimeBinaryFilename(serviceName, platformKey) {
|
|
|
1425
1483
|
return `pushpals-runtime-${serviceToken}-${platformKey}${extension}`;
|
|
1426
1484
|
}
|
|
1427
1485
|
function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
1486
|
+
const env = normalizeChildProcessEnv(baseEnv);
|
|
1428
1487
|
const useRuntimeConfig = opts.useRuntimeConfig !== false;
|
|
1429
1488
|
return {
|
|
1430
|
-
...
|
|
1489
|
+
...env,
|
|
1431
1490
|
PUSHPALS_REPO_ROOT_OVERRIDE: opts.repoRoot,
|
|
1432
1491
|
PUSHPALS_PROJECT_ROOT_OVERRIDE: opts.repoRoot,
|
|
1433
1492
|
...useRuntimeConfig ? {
|
|
@@ -1436,9 +1495,58 @@ function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
|
1436
1495
|
} : {
|
|
1437
1496
|
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.repoRoot
|
|
1438
1497
|
},
|
|
1439
|
-
PUSHPALS_PROTOCOL_SCHEMAS_DIR: join2(opts.runtimeRoot, "protocol", "schemas")
|
|
1498
|
+
PUSHPALS_PROTOCOL_SCHEMAS_DIR: join2(opts.runtimeRoot, "protocol", "schemas"),
|
|
1499
|
+
...typeof env.PUSHPALS_GIT_BIN === "string" && env.PUSHPALS_GIT_BIN.trim() ? { PUSHPALS_GIT_BIN: env.PUSHPALS_GIT_BIN.trim() } : {}
|
|
1440
1500
|
};
|
|
1441
1501
|
}
|
|
1502
|
+
function normalizeChildProcessEnv(baseEnv, platform = process.platform) {
|
|
1503
|
+
const env = {};
|
|
1504
|
+
for (const [key, value] of Object.entries(baseEnv)) {
|
|
1505
|
+
if (typeof value === "string")
|
|
1506
|
+
env[key] = value;
|
|
1507
|
+
}
|
|
1508
|
+
if (platform === "win32") {
|
|
1509
|
+
const resolvedPath = String(env.Path ?? env.PATH ?? process.env.Path ?? process.env.PATH ?? "").trim();
|
|
1510
|
+
if (resolvedPath) {
|
|
1511
|
+
env.Path = resolvedPath;
|
|
1512
|
+
env.PATH = resolvedPath;
|
|
1513
|
+
}
|
|
1514
|
+
const systemRoot = String(env.SystemRoot ?? env.SYSTEMROOT ?? process.env.SystemRoot ?? process.env.SYSTEMROOT ?? "").trim();
|
|
1515
|
+
if (systemRoot) {
|
|
1516
|
+
env.SystemRoot = systemRoot;
|
|
1517
|
+
env.SYSTEMROOT = systemRoot;
|
|
1518
|
+
}
|
|
1519
|
+
const comSpec = String(env.ComSpec ?? env.COMSPEC ?? process.env.ComSpec ?? process.env.COMSPEC ?? "").trim();
|
|
1520
|
+
if (comSpec) {
|
|
1521
|
+
env.ComSpec = comSpec;
|
|
1522
|
+
env.COMSPEC = comSpec;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
return env;
|
|
1526
|
+
}
|
|
1527
|
+
async function resolveCommandPath(command, cwd, env) {
|
|
1528
|
+
const lookupCommands = process.platform === "win32" ? [
|
|
1529
|
+
["where.exe", command],
|
|
1530
|
+
["where", command]
|
|
1531
|
+
] : [["which", command]];
|
|
1532
|
+
for (const lookup of lookupCommands) {
|
|
1533
|
+
try {
|
|
1534
|
+
const proc = Bun.spawn(lookup, {
|
|
1535
|
+
cwd,
|
|
1536
|
+
env,
|
|
1537
|
+
stdout: "pipe",
|
|
1538
|
+
stderr: "ignore"
|
|
1539
|
+
});
|
|
1540
|
+
const [stdout, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
1541
|
+
if (exitCode !== 0)
|
|
1542
|
+
continue;
|
|
1543
|
+
const resolved = stdout.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0);
|
|
1544
|
+
if (resolved)
|
|
1545
|
+
return resolved;
|
|
1546
|
+
} catch {}
|
|
1547
|
+
}
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1442
1550
|
function timestampFileToken() {
|
|
1443
1551
|
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
1444
1552
|
}
|
|
@@ -1546,11 +1654,18 @@ function spawnRuntimeService(name, command, cwd, env, logPath) {
|
|
|
1546
1654
|
});
|
|
1547
1655
|
return service;
|
|
1548
1656
|
}
|
|
1657
|
+
function buildServiceStopCommand(pid, platform = process.platform) {
|
|
1658
|
+
if (platform === "win32" && typeof pid === "number" && pid > 0) {
|
|
1659
|
+
return ["taskkill", "/PID", String(pid), "/T", "/F"];
|
|
1660
|
+
}
|
|
1661
|
+
return null;
|
|
1662
|
+
}
|
|
1549
1663
|
function stopRuntimeServices(services) {
|
|
1550
1664
|
for (const service of services) {
|
|
1551
1665
|
try {
|
|
1552
|
-
|
|
1553
|
-
|
|
1666
|
+
const stopCommand = buildServiceStopCommand(service.proc.pid, process.platform);
|
|
1667
|
+
if (stopCommand) {
|
|
1668
|
+
Bun.spawnSync(stopCommand, {
|
|
1554
1669
|
stdin: "ignore",
|
|
1555
1670
|
stdout: "ignore",
|
|
1556
1671
|
stderr: "ignore"
|
|
@@ -1561,6 +1676,24 @@ function stopRuntimeServices(services) {
|
|
|
1561
1676
|
} catch {}
|
|
1562
1677
|
}
|
|
1563
1678
|
}
|
|
1679
|
+
function isOptionalEmbeddedService(name) {
|
|
1680
|
+
return name === "source_control_manager";
|
|
1681
|
+
}
|
|
1682
|
+
async function canSpawnCommand(command, cwd, env) {
|
|
1683
|
+
try {
|
|
1684
|
+
const proc = Bun.spawn(command, {
|
|
1685
|
+
cwd,
|
|
1686
|
+
env,
|
|
1687
|
+
stdin: "ignore",
|
|
1688
|
+
stdout: "ignore",
|
|
1689
|
+
stderr: "ignore"
|
|
1690
|
+
});
|
|
1691
|
+
const exitCode = await proc.exited;
|
|
1692
|
+
return exitCode === 0;
|
|
1693
|
+
} catch {
|
|
1694
|
+
return false;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1564
1697
|
async function repoHasRemote(repoRoot, remote) {
|
|
1565
1698
|
const normalizedRemote = remote.trim();
|
|
1566
1699
|
if (!normalizedRemote)
|
|
@@ -1630,6 +1763,10 @@ async function autoStartRuntimeServices(opts) {
|
|
|
1630
1763
|
runtimeRoot,
|
|
1631
1764
|
useRuntimeConfig: opts.preparedRuntime.preflightUsesEmbeddedRuntime
|
|
1632
1765
|
});
|
|
1766
|
+
const resolvedGitBinary = await resolveCommandPath("git", opts.repoRoot, normalizeChildProcessEnv(process.env));
|
|
1767
|
+
if (resolvedGitBinary) {
|
|
1768
|
+
runtimeEnv.PUSHPALS_GIT_BIN = resolvedGitBinary;
|
|
1769
|
+
}
|
|
1633
1770
|
const services = [];
|
|
1634
1771
|
const runToken = timestampFileToken();
|
|
1635
1772
|
const logDir = join2(runtimeRoot, "logs", "bootstrap");
|
|
@@ -1678,13 +1815,24 @@ ${tail}` : ""}`);
|
|
|
1678
1815
|
console.log(`[pushpals] remotebuddy log: ${remotebuddyService.logPath}`);
|
|
1679
1816
|
const scmHealthy = await probeSourceControlManager(opts.sourceControlManagerPort);
|
|
1680
1817
|
const scmRemoteAvailable = await repoHasRemote(opts.repoRoot, opts.sourceControlManagerRemote);
|
|
1818
|
+
const gitProbeCommand = typeof runtimeEnv.PUSHPALS_GIT_BIN === "string" && runtimeEnv.PUSHPALS_GIT_BIN.trim() ? [runtimeEnv.PUSHPALS_GIT_BIN.trim(), "--version"] : ["git", "--version"];
|
|
1819
|
+
const gitAvailableForScm = await canSpawnCommand(gitProbeCommand, opts.repoRoot, runtimeEnv);
|
|
1681
1820
|
if (!scmHealthy && scmRemoteAvailable) {
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1821
|
+
if (!gitAvailableForScm) {
|
|
1822
|
+
console.warn("[pushpals] Git is not available to embedded SourceControlManager; skipping SCM startup.");
|
|
1823
|
+
} else {
|
|
1824
|
+
if (runtimeEnv.PUSHPALS_GIT_BIN) {
|
|
1825
|
+
console.log(`[pushpals] Embedded SourceControlManager git=${runtimeEnv.PUSHPALS_GIT_BIN}`);
|
|
1826
|
+
}
|
|
1827
|
+
console.log("[pushpals] Starting embedded SourceControlManager...");
|
|
1828
|
+
const sourceControlManagerService = spawnRuntimeService("source_control_manager", [runtimeBinaries.sourceControlManager, "--skip-clean-check"], opts.repoRoot, runtimeEnv, logPathFor("source_control_manager"));
|
|
1829
|
+
services.push(sourceControlManagerService);
|
|
1830
|
+
console.log(`[pushpals] source_control_manager log: ${sourceControlManagerService.logPath}`);
|
|
1831
|
+
}
|
|
1686
1832
|
} else if (!scmRemoteAvailable) {
|
|
1687
1833
|
console.log(`[pushpals] Repo has no git remote "${opts.sourceControlManagerRemote}"; skipping embedded SourceControlManager.`);
|
|
1834
|
+
} else if (!gitAvailableForScm) {
|
|
1835
|
+
console.warn("[pushpals] Git is not available to embedded SourceControlManager; skipping SCM startup.");
|
|
1688
1836
|
} else {
|
|
1689
1837
|
console.log("[pushpals] SourceControlManager already healthy; skipping embedded start.");
|
|
1690
1838
|
}
|
|
@@ -1693,7 +1841,7 @@ ${tail}` : ""}`);
|
|
|
1693
1841
|
for (let i = services.length - 1;i >= 0; i--) {
|
|
1694
1842
|
const service = services[i];
|
|
1695
1843
|
if (service.exited) {
|
|
1696
|
-
if (service.name
|
|
1844
|
+
if (isOptionalEmbeddedService(service.name)) {
|
|
1697
1845
|
console.warn(`[pushpals] Embedded ${service.name} exited during startup (code=${service.exitCode ?? "unknown"}); continuing without SCM.`);
|
|
1698
1846
|
const tail2 = readLogTail(service.logPath);
|
|
1699
1847
|
if (tail2) {
|
|
@@ -1714,9 +1862,20 @@ ${tail}` : ""}`);
|
|
|
1714
1862
|
if (health?.ok) {
|
|
1715
1863
|
const stabilityDeadline = Date.now() + DEFAULT_SERVICE_STABILITY_GRACE_MS;
|
|
1716
1864
|
while (Date.now() < stabilityDeadline) {
|
|
1717
|
-
for (
|
|
1865
|
+
for (let i = services.length - 1;i >= 0; i--) {
|
|
1866
|
+
const service = services[i];
|
|
1718
1867
|
if (!service.exited)
|
|
1719
1868
|
continue;
|
|
1869
|
+
if (isOptionalEmbeddedService(service.name)) {
|
|
1870
|
+
const tail2 = readLogTail(service.logPath);
|
|
1871
|
+
console.warn(`[pushpals] Embedded ${service.name} exited immediately after bootstrap (code=${service.exitCode ?? "unknown"}); continuing without SCM.`);
|
|
1872
|
+
if (tail2) {
|
|
1873
|
+
console.warn(`[pushpals] ${service.name} log tail:
|
|
1874
|
+
${tail2}`);
|
|
1875
|
+
}
|
|
1876
|
+
services.splice(i, 1);
|
|
1877
|
+
continue;
|
|
1878
|
+
}
|
|
1720
1879
|
const tail = readLogTail(service.logPath);
|
|
1721
1880
|
stopRuntimeServices(services);
|
|
1722
1881
|
throw new Error(`Embedded ${service.name} exited immediately after bootstrap (code=${service.exitCode ?? "unknown"}). ` + `See ${service.logPath}${tail ? `
|
|
@@ -1778,6 +1937,91 @@ async function looksLikeMonitoringHub(url) {
|
|
|
1778
1937
|
return false;
|
|
1779
1938
|
}
|
|
1780
1939
|
}
|
|
1940
|
+
function buildMonitoringHubRuntimeBootstrap(opts) {
|
|
1941
|
+
return {
|
|
1942
|
+
serverUrl: opts.serverUrl,
|
|
1943
|
+
localAgentUrl: opts.localAgentUrl,
|
|
1944
|
+
sessionId: opts.sessionId,
|
|
1945
|
+
authToken: opts.authToken
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
function injectMonitoringHubBootstrap(html, bootstrap) {
|
|
1949
|
+
const payload = jsonHtmlBootstrap(bootstrap);
|
|
1950
|
+
const script = `<script>globalThis.__PUSHPALS_WEB_BOOTSTRAP__=${payload};</script>`;
|
|
1951
|
+
if (html.includes("</head>")) {
|
|
1952
|
+
return html.replace("</head>", `${script}</head>`);
|
|
1953
|
+
}
|
|
1954
|
+
return `${script}${html}`;
|
|
1955
|
+
}
|
|
1956
|
+
function monitoringHubContentType(pathValue) {
|
|
1957
|
+
switch (extname(pathValue).toLowerCase()) {
|
|
1958
|
+
case ".html":
|
|
1959
|
+
return "text/html; charset=utf-8";
|
|
1960
|
+
case ".js":
|
|
1961
|
+
return "application/javascript; charset=utf-8";
|
|
1962
|
+
case ".css":
|
|
1963
|
+
return "text/css; charset=utf-8";
|
|
1964
|
+
case ".json":
|
|
1965
|
+
return "application/json; charset=utf-8";
|
|
1966
|
+
case ".svg":
|
|
1967
|
+
return "image/svg+xml";
|
|
1968
|
+
case ".png":
|
|
1969
|
+
return "image/png";
|
|
1970
|
+
case ".jpg":
|
|
1971
|
+
case ".jpeg":
|
|
1972
|
+
return "image/jpeg";
|
|
1973
|
+
case ".ico":
|
|
1974
|
+
return "image/x-icon";
|
|
1975
|
+
case ".woff2":
|
|
1976
|
+
return "font/woff2";
|
|
1977
|
+
case ".ttf":
|
|
1978
|
+
return "font/ttf";
|
|
1979
|
+
case ".map":
|
|
1980
|
+
return "application/json; charset=utf-8";
|
|
1981
|
+
default:
|
|
1982
|
+
return "application/octet-stream";
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
function resolveMonitoringHubAssetPath(assetRoot, pathname) {
|
|
1986
|
+
const root = resolve3(assetRoot);
|
|
1987
|
+
const rootPrefix = `${root}${root.endsWith("\\") || root.endsWith("/") ? "" : process.platform === "win32" ? "\\" : "/"}`;
|
|
1988
|
+
const decodedPath = decodeURIComponent(pathname);
|
|
1989
|
+
const trimmedPath = decodedPath === "/" ? "/index.html" : decodedPath;
|
|
1990
|
+
const relativePath = trimmedPath.replace(/^\/+/, "");
|
|
1991
|
+
const candidatePath = resolve3(root, relativePath);
|
|
1992
|
+
if (candidatePath !== root && !candidatePath.startsWith(rootPrefix))
|
|
1993
|
+
return null;
|
|
1994
|
+
if (existsSync3(candidatePath))
|
|
1995
|
+
return candidatePath;
|
|
1996
|
+
if (!extname(relativePath)) {
|
|
1997
|
+
const nestedIndexPath = resolve3(root, relativePath, "index.html");
|
|
1998
|
+
if ((nestedIndexPath === root || nestedIndexPath.startsWith(rootPrefix)) && existsSync3(nestedIndexPath)) {
|
|
1999
|
+
return nestedIndexPath;
|
|
2000
|
+
}
|
|
2001
|
+
return join2(root, "index.html");
|
|
2002
|
+
}
|
|
2003
|
+
return null;
|
|
2004
|
+
}
|
|
2005
|
+
async function serveBundledMonitoringHub(assetRoot, pathname, bootstrap) {
|
|
2006
|
+
const assetPath = resolveMonitoringHubAssetPath(assetRoot, pathname);
|
|
2007
|
+
if (!assetPath || !existsSync3(assetPath))
|
|
2008
|
+
return null;
|
|
2009
|
+
if (assetPath.endsWith("index.html")) {
|
|
2010
|
+
const html = injectMonitoringHubBootstrap(readFileSync3(assetPath, "utf8"), bootstrap);
|
|
2011
|
+
return new Response(html, {
|
|
2012
|
+
headers: {
|
|
2013
|
+
"content-type": "text/html; charset=utf-8",
|
|
2014
|
+
"cache-control": "no-store"
|
|
2015
|
+
}
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
return new Response(Bun.file(assetPath), {
|
|
2019
|
+
headers: {
|
|
2020
|
+
"content-type": monitoringHubContentType(assetPath),
|
|
2021
|
+
"cache-control": "no-store"
|
|
2022
|
+
}
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
1781
2025
|
function buildEmbeddedMonitoringHubHtml(opts) {
|
|
1782
2026
|
const bootstrap = jsonHtmlBootstrap(opts);
|
|
1783
2027
|
return `<!doctype html>
|
|
@@ -1925,10 +2169,16 @@ async function proxyMonitoringHubRequest(serverUrl, authToken, pathValue) {
|
|
|
1925
2169
|
});
|
|
1926
2170
|
}
|
|
1927
2171
|
async function startEmbeddedMonitoringHub(opts) {
|
|
1928
|
-
const
|
|
2172
|
+
const monitoringHubAssetRoot = opts.assetRoot === undefined ? await ensureBundledMonitoringHubRoot() : opts.assetRoot;
|
|
2173
|
+
if (!monitoringHubAssetRoot || !looksLikeMonitoringHubBuild(monitoringHubAssetRoot)) {
|
|
2174
|
+
console.error("[pushpals] Unified monitoring hub assets are unavailable; build or export the packaged client monitor first.");
|
|
2175
|
+
return null;
|
|
2176
|
+
}
|
|
2177
|
+
const bootstrap = buildMonitoringHubRuntimeBootstrap({
|
|
1929
2178
|
serverUrl: opts.serverUrl,
|
|
1930
2179
|
localAgentUrl: opts.localAgentUrl,
|
|
1931
|
-
sessionId: opts.sessionId
|
|
2180
|
+
sessionId: opts.sessionId,
|
|
2181
|
+
authToken: opts.authToken
|
|
1932
2182
|
});
|
|
1933
2183
|
const candidatePorts = Array.from({ length: MONITOR_SCAN_PORTS }, (_, index) => opts.preferredPort + index).concat(0);
|
|
1934
2184
|
for (const port of candidatePorts) {
|
|
@@ -1938,16 +2188,13 @@ async function startEmbeddedMonitoringHub(opts) {
|
|
|
1938
2188
|
idleTimeout: 30,
|
|
1939
2189
|
fetch: async (req) => {
|
|
1940
2190
|
const url = new URL(req.url);
|
|
1941
|
-
if (url.pathname === "/") {
|
|
1942
|
-
return new Response(html, {
|
|
1943
|
-
headers: {
|
|
1944
|
-
"content-type": "text/html; charset=utf-8",
|
|
1945
|
-
"cache-control": "no-store"
|
|
1946
|
-
}
|
|
1947
|
-
});
|
|
1948
|
-
}
|
|
1949
2191
|
if (url.pathname === "/healthz") {
|
|
1950
|
-
return Response.json({
|
|
2192
|
+
return Response.json({
|
|
2193
|
+
ok: true,
|
|
2194
|
+
port,
|
|
2195
|
+
serverUrl: opts.serverUrl,
|
|
2196
|
+
sessionId: opts.sessionId
|
|
2197
|
+
});
|
|
1951
2198
|
}
|
|
1952
2199
|
if (url.pathname === "/api/status") {
|
|
1953
2200
|
return await proxyMonitoringHubRequest(opts.serverUrl, opts.authToken, "/system/status");
|
|
@@ -1961,6 +2208,9 @@ async function startEmbeddedMonitoringHub(opts) {
|
|
|
1961
2208
|
if (url.pathname === "/api/completions") {
|
|
1962
2209
|
return await proxyMonitoringHubRequest(opts.serverUrl, opts.authToken, "/completions?status=all&limit=20");
|
|
1963
2210
|
}
|
|
2211
|
+
const bundledResponse = await serveBundledMonitoringHub(monitoringHubAssetRoot, url.pathname, bootstrap);
|
|
2212
|
+
if (bundledResponse)
|
|
2213
|
+
return bundledResponse;
|
|
1964
2214
|
return new Response("Not found", { status: 404 });
|
|
1965
2215
|
}
|
|
1966
2216
|
});
|
|
@@ -2163,15 +2413,17 @@ async function runSessionStream(serverUrl, sessionId, authToken, print, signal)
|
|
|
2163
2413
|
}
|
|
2164
2414
|
}
|
|
2165
2415
|
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
cmd = ["cmd", "/c", "start", "", url];
|
|
2170
|
-
} else if (process.platform === "darwin") {
|
|
2171
|
-
cmd = ["open", url];
|
|
2172
|
-
} else {
|
|
2173
|
-
cmd = ["xdg-open", url];
|
|
2416
|
+
function buildOpenMonitoringHubCommand(url, platform = process.platform) {
|
|
2417
|
+
if (platform === "win32") {
|
|
2418
|
+
return ["cmd", "/c", "start", "", url];
|
|
2174
2419
|
}
|
|
2420
|
+
if (platform === "darwin") {
|
|
2421
|
+
return ["open", url];
|
|
2422
|
+
}
|
|
2423
|
+
return ["xdg-open", url];
|
|
2424
|
+
}
|
|
2425
|
+
async function openMonitoringHub(url) {
|
|
2426
|
+
const cmd = buildOpenMonitoringHubCommand(url, process.platform);
|
|
2175
2427
|
const proc = Bun.spawn(cmd, {
|
|
2176
2428
|
stdin: "ignore",
|
|
2177
2429
|
stdout: "ignore",
|
|
@@ -2180,6 +2432,10 @@ async function openMonitoringHub(url) {
|
|
|
2180
2432
|
const code = await proc.exited;
|
|
2181
2433
|
return code === 0;
|
|
2182
2434
|
}
|
|
2435
|
+
function isCliExitCommand(text) {
|
|
2436
|
+
const normalized = String(text ?? "").trim().toLowerCase();
|
|
2437
|
+
return normalized === "/exit" || normalized === "/quit" || normalized === "exit" || normalized === "quit";
|
|
2438
|
+
}
|
|
2183
2439
|
async function main() {
|
|
2184
2440
|
const argv = process.argv.slice(2);
|
|
2185
2441
|
logCliInvocation(argv);
|
|
@@ -2304,7 +2560,7 @@ async function main() {
|
|
|
2304
2560
|
console.log(`sessionId=${localBuddySessionId}`);
|
|
2305
2561
|
console.log(`repoRoot=${repoRoot}`);
|
|
2306
2562
|
console.log(`cliStateFile=${statePath}`);
|
|
2307
|
-
console.log("[pushpals] Type a message and press Enter. Use /exit to quit.");
|
|
2563
|
+
console.log("[pushpals] Type a message and press Enter. Use /exit or exit to quit.");
|
|
2308
2564
|
const streamAbort = new AbortController;
|
|
2309
2565
|
let rl = null;
|
|
2310
2566
|
const printIncoming = (line) => {
|
|
@@ -2325,12 +2581,16 @@ ${line}
|
|
|
2325
2581
|
if (shuttingDown)
|
|
2326
2582
|
return;
|
|
2327
2583
|
shuttingDown = true;
|
|
2584
|
+
console.log("[pushpals] Shutting down CLI session...");
|
|
2328
2585
|
streamAbort.abort();
|
|
2329
2586
|
if (rl)
|
|
2330
2587
|
rl.close();
|
|
2331
2588
|
try {
|
|
2332
2589
|
monitoringHub?.stop();
|
|
2333
2590
|
} catch {}
|
|
2591
|
+
if (autoStartedServices.length > 0) {
|
|
2592
|
+
console.log("[pushpals] Stopping embedded runtime services...");
|
|
2593
|
+
}
|
|
2334
2594
|
stopAutoStartedServices();
|
|
2335
2595
|
};
|
|
2336
2596
|
process.once("SIGINT", requestStop);
|
|
@@ -2349,7 +2609,7 @@ ${line}
|
|
|
2349
2609
|
rl.prompt();
|
|
2350
2610
|
continue;
|
|
2351
2611
|
}
|
|
2352
|
-
if (text
|
|
2612
|
+
if (isCliExitCommand(text)) {
|
|
2353
2613
|
requestStop();
|
|
2354
2614
|
break;
|
|
2355
2615
|
}
|
|
@@ -2395,8 +2655,15 @@ if (import.meta.main) {
|
|
|
2395
2655
|
}
|
|
2396
2656
|
export {
|
|
2397
2657
|
startEmbeddedMonitoringHub,
|
|
2658
|
+
resolveCommandPath,
|
|
2398
2659
|
resolveBundledRuntimeAssetSource,
|
|
2660
|
+
resolveBundledMonitoringHubRoot,
|
|
2399
2661
|
prepareCliRuntime,
|
|
2662
|
+
normalizeChildProcessEnv,
|
|
2663
|
+
isCliExitCommand,
|
|
2664
|
+
injectMonitoringHubBootstrap,
|
|
2665
|
+
buildServiceStopCommand,
|
|
2666
|
+
buildOpenMonitoringHubCommand,
|
|
2400
2667
|
buildEmbeddedRuntimeEnv,
|
|
2401
2668
|
buildEmbeddedMonitoringHubHtml
|
|
2402
2669
|
};
|