@pushpalsdev/cli 1.0.9 → 1.0.11
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 +411 -128
- package/monitor-ui/+not-found.html +1 -1
- package/monitor-ui/_expo/static/js/web/{entry-7e55666b7443eef13f7696e8d422e8cf.js → entry-1d5a07c47473852fe9754bfe3e6da301.js} +177 -176
- package/monitor-ui/_expo/static/js/web/{index-04194fb85c12ac46718492c2ff687e6c.js → index-5650b6cee60075cb63c1efc40dcf7683.js} +4 -4
- package/monitor-ui/_sitemap.html +1 -1
- package/monitor-ui/index.html +1 -1
- package/monitor-ui/modal.html +1 -1
- package/package.json +1 -1
- package/runtime/.env.example +4 -4
- package/runtime/configs/default.toml +5 -4
- package/runtime/configs/local.example.toml +6 -1
package/dist/pushpals-cli.js
CHANGED
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
appendFileSync,
|
|
7
7
|
chmodSync,
|
|
8
8
|
cpSync,
|
|
9
|
-
existsSync as
|
|
9
|
+
existsSync as existsSync4,
|
|
10
10
|
mkdirSync,
|
|
11
|
-
readFileSync as
|
|
11
|
+
readFileSync as readFileSync4,
|
|
12
12
|
writeFileSync
|
|
13
13
|
} from "fs";
|
|
14
|
-
import { dirname, extname, join as join2, resolve as
|
|
14
|
+
import { basename, delimiter, dirname, extname, join as join2, resolve as resolve4 } from "path";
|
|
15
15
|
import { createInterface } from "readline";
|
|
16
16
|
|
|
17
17
|
// ../shared/src/client_preflight.ts
|
|
@@ -21,12 +21,53 @@ import { relative, resolve as resolve2 } from "path";
|
|
|
21
21
|
// ../shared/src/config.ts
|
|
22
22
|
import { existsSync, readFileSync } from "fs";
|
|
23
23
|
import { join, resolve, isAbsolute } from "path";
|
|
24
|
+
|
|
25
|
+
// ../shared/src/local_network.ts
|
|
26
|
+
var DEFAULT_LOCAL_LOOPBACK_HOST = "127.0.0.1";
|
|
27
|
+
function isLoopbackHost(hostname) {
|
|
28
|
+
const normalized = String(hostname ?? "").trim().toLowerCase().replace(/^\[(.*)\]$/, "$1");
|
|
29
|
+
return normalized === "127.0.0.1" || normalized === "::1" || normalized === "localhost";
|
|
30
|
+
}
|
|
31
|
+
function normalizeLoopbackHost(hostname) {
|
|
32
|
+
const normalized = String(hostname ?? "").trim().toLowerCase().replace(/^\[(.*)\]$/, "$1");
|
|
33
|
+
if (isLoopbackHost(normalized))
|
|
34
|
+
return DEFAULT_LOCAL_LOOPBACK_HOST;
|
|
35
|
+
return DEFAULT_LOCAL_LOOPBACK_HOST;
|
|
36
|
+
}
|
|
37
|
+
function normalizeLoopbackHttpUrl(value, fallbackPort) {
|
|
38
|
+
const fallback = `http://${DEFAULT_LOCAL_LOOPBACK_HOST}:${Math.max(1, fallbackPort)}`;
|
|
39
|
+
const text = String(value ?? "").trim();
|
|
40
|
+
if (!text)
|
|
41
|
+
return fallback;
|
|
42
|
+
try {
|
|
43
|
+
const parsed = new URL(text);
|
|
44
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
45
|
+
return fallback;
|
|
46
|
+
}
|
|
47
|
+
parsed.protocol = "http:";
|
|
48
|
+
parsed.username = "";
|
|
49
|
+
parsed.password = "";
|
|
50
|
+
parsed.hostname = normalizeLoopbackHost(parsed.hostname);
|
|
51
|
+
parsed.pathname = "/";
|
|
52
|
+
parsed.search = "";
|
|
53
|
+
parsed.hash = "";
|
|
54
|
+
if (!parsed.port) {
|
|
55
|
+
parsed.port = String(Math.max(1, fallbackPort));
|
|
56
|
+
}
|
|
57
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
58
|
+
} catch {
|
|
59
|
+
return fallback;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ../shared/src/config.ts
|
|
24
64
|
var PROJECT_ROOT = resolve(import.meta.dir, "..", "..", "..");
|
|
25
65
|
var DEFAULT_CONFIG_DIR = "configs";
|
|
26
66
|
var LEGACY_CONFIG_DIR = "config";
|
|
27
67
|
var TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
28
68
|
var FALSY = new Set(["0", "false", "no", "off"]);
|
|
29
69
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE = 8;
|
|
70
|
+
var DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS = 1;
|
|
30
71
|
var DEFAULT_WORKERPALS_FILE_MODIFYING_JOBS = ["task.execute"];
|
|
31
72
|
var DEFAULT_WORKERPALS_OUTPUT_MAX_CHARS = 192 * 1024;
|
|
32
73
|
var DEFAULT_WORKERPALS_OUTPUT_MAX_LINES = 600;
|
|
@@ -294,13 +335,14 @@ function loadPushPalsConfig(options = {}) {
|
|
|
294
335
|
const remotebuddyDbPath = resolvePathFromRoot(projectRoot, firstNonEmpty(process.env.REMOTEBUDDY_DB_PATH, asString(pathsNode.remotebuddy_db_path, join(dataDir, "remotebuddy-state.db"))));
|
|
295
336
|
const serverNode = getObject(merged, "server");
|
|
296
337
|
const serverPort = Math.max(1, asInt(parseIntEnv("PUSHPALS_PORT") ?? serverNode.port, 3001));
|
|
297
|
-
const serverUrl = firstNonEmpty(process.env.PUSHPALS_SERVER_URL, asString(serverNode.url, `http://
|
|
298
|
-
const serverHost = asString(serverNode.host, "
|
|
338
|
+
const serverUrl = normalizeLoopbackHttpUrl(firstNonEmpty(process.env.PUSHPALS_SERVER_URL, asString(serverNode.url, `http://127.0.0.1:${serverPort}`), `http://127.0.0.1:${serverPort}`), serverPort);
|
|
339
|
+
const serverHost = normalizeLoopbackHost(firstNonEmpty(process.env.PUSHPALS_HOST, asString(serverNode.host, "127.0.0.1")));
|
|
299
340
|
const debugHttp = parseBoolEnv("PUSHPALS_DEBUG_HTTP") ?? asBoolean(serverNode.debug_http, false);
|
|
300
341
|
const staleClaimTtlMs = Math.max(5000, asInt(parseIntEnv("PUSHPALS_STALE_CLAIM_TTL_MS") ?? serverNode.stale_claim_ttl_ms, 120000));
|
|
301
342
|
const staleClaimSweepIntervalMs = Math.max(1000, asInt(parseIntEnv("PUSHPALS_STALE_CLAIM_SWEEP_INTERVAL_MS") ?? serverNode.stale_claim_sweep_interval_ms, 5000));
|
|
302
343
|
const globalStatusHeartbeatMs = parseIntEnv("PUSHPALS_STATUS_HEARTBEAT_MS");
|
|
303
344
|
const localNode = getObject(merged, "localbuddy");
|
|
345
|
+
const localEnabled = parseBoolEnv("LOCALBUDDY_ENABLED") ?? asBoolean(localNode.enabled, false);
|
|
304
346
|
const localPort = Math.max(1, asInt(parseIntEnv("LOCAL_AGENT_PORT") ?? localNode.port, 3003));
|
|
305
347
|
const localStatusHeartbeatMs = Math.max(0, asInt(parseIntEnv("LOCALBUDDY_STATUS_HEARTBEAT_MS") ?? globalStatusHeartbeatMs ?? localNode.status_heartbeat_ms, 120000));
|
|
306
348
|
const localLlm = resolveLlmConfig(localNode, "LOCALBUDDY", {
|
|
@@ -377,7 +419,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
377
419
|
const workerMinisweTimeoutMs = Math.max(1e4, asInt(parseIntEnv("WORKERPALS_MINISWE_TIMEOUT_MS") ?? workerNode.miniswe_timeout_ms, 1800000));
|
|
378
420
|
const workerOpenAICodexPython = firstNonEmpty(process.env.PUSHPALS_OPENAI_CODEX_PYTHON, asString(workerNode.openai_codex_python, "python"), "python");
|
|
379
421
|
const workerOpenAICodexTimeoutMs = Math.max(1e4, asInt(workerNode.openai_codex_timeout_ms, 7200000));
|
|
380
|
-
const workerQualityMaxAutoRevisions = Math.max(0, Math.min(10, asInt(parseIntEnv("WORKERPALS_QUALITY_MAX_AUTO_REVISIONS") ?? workerNode.quality_max_auto_revisions,
|
|
422
|
+
const workerQualityMaxAutoRevisions = Math.max(0, Math.min(10, asInt(parseIntEnv("WORKERPALS_QUALITY_MAX_AUTO_REVISIONS") ?? workerNode.quality_max_auto_revisions, DEFAULT_WORKERPALS_QUALITY_MAX_AUTO_REVISIONS)));
|
|
381
423
|
const workerFileModifyingJobs = (() => {
|
|
382
424
|
const envRaw = firstNonEmpty(process.env.WORKERPALS_FILE_MODIFYING_JOBS);
|
|
383
425
|
const parsed = envRaw ? envRaw.split(",").map((entry) => entry.trim()).filter(Boolean) : asStringArray(workerNode.file_modifying_jobs);
|
|
@@ -539,6 +581,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
539
581
|
staleClaimSweepIntervalMs
|
|
540
582
|
},
|
|
541
583
|
localbuddy: {
|
|
584
|
+
enabled: localEnabled,
|
|
542
585
|
port: localPort,
|
|
543
586
|
statusHeartbeatMs: localStatusHeartbeatMs,
|
|
544
587
|
llm: localLlm
|
|
@@ -742,7 +785,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
742
785
|
portConflictPolicy: startupPortConflictPolicy
|
|
743
786
|
},
|
|
744
787
|
client: {
|
|
745
|
-
localAgentUrl: firstNonEmpty(process.env.EXPO_PUBLIC_LOCAL_AGENT_URL, asString(clientNode.local_agent_url, `http://
|
|
788
|
+
localAgentUrl: normalizeLoopbackHttpUrl(firstNonEmpty(process.env.EXPO_PUBLIC_LOCAL_AGENT_URL, asString(clientNode.local_agent_url, `http://127.0.0.1:${localPort}`), `http://127.0.0.1:${localPort}`), localPort),
|
|
746
789
|
traceTailLines: Math.max(10, asInt(parseIntEnv("EXPO_PUBLIC_PUSHPALS_TRACE_TAIL_LINES") ?? clientNode.trace_tail_lines, 100))
|
|
747
790
|
}
|
|
748
791
|
};
|
|
@@ -1061,6 +1104,46 @@ function formatClientRuntimePreflightLines(result, prefix) {
|
|
|
1061
1104
|
return lines;
|
|
1062
1105
|
}
|
|
1063
1106
|
|
|
1107
|
+
// ../shared/src/repo.ts
|
|
1108
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, statSync } from "fs";
|
|
1109
|
+
import { resolve as resolve3 } from "path";
|
|
1110
|
+
function resolveDotGitEntry(repoRoot) {
|
|
1111
|
+
return resolve3(repoRoot, ".git");
|
|
1112
|
+
}
|
|
1113
|
+
function resolveGitMetadataDir(repoRoot) {
|
|
1114
|
+
const dotGitPath = resolveDotGitEntry(repoRoot);
|
|
1115
|
+
if (!existsSync3(dotGitPath))
|
|
1116
|
+
return null;
|
|
1117
|
+
try {
|
|
1118
|
+
const stat = statSync(dotGitPath);
|
|
1119
|
+
if (stat.isDirectory()) {
|
|
1120
|
+
return dotGitPath;
|
|
1121
|
+
}
|
|
1122
|
+
if (!stat.isFile()) {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
} catch {
|
|
1126
|
+
return null;
|
|
1127
|
+
}
|
|
1128
|
+
try {
|
|
1129
|
+
const firstLine = readFileSync3(dotGitPath, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
|
1130
|
+
const match = firstLine.match(/^gitdir:\s*(.+)\s*$/i);
|
|
1131
|
+
if (!match)
|
|
1132
|
+
return null;
|
|
1133
|
+
const gitDir = resolve3(repoRoot, match[1].trim());
|
|
1134
|
+
return existsSync3(gitDir) ? gitDir : null;
|
|
1135
|
+
} catch {
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
function resolveGitStateFilePath(repoRoot, fileName) {
|
|
1140
|
+
const gitMetadataDir = resolveGitMetadataDir(repoRoot);
|
|
1141
|
+
const normalizedFileName = String(fileName ?? "").trim();
|
|
1142
|
+
if (!gitMetadataDir || !normalizedFileName)
|
|
1143
|
+
return null;
|
|
1144
|
+
return resolve3(gitMetadataDir, normalizedFileName);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1064
1147
|
// ../../scripts/pushpals-cli.ts
|
|
1065
1148
|
var DEFAULT_MONITOR_PORT = 8081;
|
|
1066
1149
|
var MONITOR_SCAN_PORTS = 32;
|
|
@@ -1081,6 +1164,29 @@ var GITHUB_HEADERS = {
|
|
|
1081
1164
|
"User-Agent": "pushpals-cli"
|
|
1082
1165
|
};
|
|
1083
1166
|
var stateVersion = 1;
|
|
1167
|
+
var cliTimestampedConsoleInstalled = false;
|
|
1168
|
+
function formatTimestampedCliLine(line, at = new Date) {
|
|
1169
|
+
const text = String(line ?? "");
|
|
1170
|
+
if (!text.startsWith("[pushpals]") && !text.startsWith("[localbuddy]")) {
|
|
1171
|
+
return text;
|
|
1172
|
+
}
|
|
1173
|
+
return `[${at.toISOString()}]${text}`;
|
|
1174
|
+
}
|
|
1175
|
+
function installTimestampedCliConsole() {
|
|
1176
|
+
if (cliTimestampedConsoleInstalled)
|
|
1177
|
+
return;
|
|
1178
|
+
cliTimestampedConsoleInstalled = true;
|
|
1179
|
+
const patch = (original) => (...args) => {
|
|
1180
|
+
if (args.length > 0 && typeof args[0] === "string") {
|
|
1181
|
+
args[0] = formatTimestampedCliLine(args[0]);
|
|
1182
|
+
}
|
|
1183
|
+
return original(...args);
|
|
1184
|
+
};
|
|
1185
|
+
console.log = patch(console.log.bind(console));
|
|
1186
|
+
console.warn = patch(console.warn.bind(console));
|
|
1187
|
+
console.error = patch(console.error.bind(console));
|
|
1188
|
+
}
|
|
1189
|
+
installTimestampedCliConsole();
|
|
1084
1190
|
function logCliInvocation(argv) {
|
|
1085
1191
|
const startedAt = new Date().toISOString();
|
|
1086
1192
|
const cliVersion = String(process.env.PUSHPALS_CLI_PACKAGE_VERSION ?? "").trim() || "unknown";
|
|
@@ -1106,6 +1212,7 @@ function printUsage() {
|
|
|
1106
1212
|
console.log(" --runtime-tag <tag> Override runtime release tag (e.g. v1.0.2)");
|
|
1107
1213
|
console.log(" --no-auto-start Disable runtime auto-start when LocalBuddy is down");
|
|
1108
1214
|
console.log(" --no-stream Disable live session event stream");
|
|
1215
|
+
console.log(" --runtime-only Start the local runtime and wait for shutdown without opening the interactive chat");
|
|
1109
1216
|
console.log(" -h, --help Show this help");
|
|
1110
1217
|
console.log("");
|
|
1111
1218
|
console.log("Chat commands:");
|
|
@@ -1120,7 +1227,7 @@ function printUsage() {
|
|
|
1120
1227
|
console.log(" - LocalBuddy must be attached to the same repo root.");
|
|
1121
1228
|
}
|
|
1122
1229
|
function parseArgs(argv) {
|
|
1123
|
-
const options = { noAutoStart: false, noStream: false };
|
|
1230
|
+
const options = { noAutoStart: false, noStream: false, runtimeOnly: false };
|
|
1124
1231
|
for (let i = 0;i < argv.length; i++) {
|
|
1125
1232
|
const arg = argv[i];
|
|
1126
1233
|
if (arg === "-h" || arg === "--help") {
|
|
@@ -1135,6 +1242,10 @@ function parseArgs(argv) {
|
|
|
1135
1242
|
options.noAutoStart = true;
|
|
1136
1243
|
continue;
|
|
1137
1244
|
}
|
|
1245
|
+
if (arg === "--runtime-only") {
|
|
1246
|
+
options.runtimeOnly = true;
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1138
1249
|
if (arg === "--server-url") {
|
|
1139
1250
|
options.serverUrl = argv[++i];
|
|
1140
1251
|
continue;
|
|
@@ -1170,6 +1281,30 @@ function normalizeUrl(value, fallback = "") {
|
|
|
1170
1281
|
const selected = text || fallback;
|
|
1171
1282
|
return selected.replace(/\/+$/, "");
|
|
1172
1283
|
}
|
|
1284
|
+
function normalizeLoopbackUrl(value, fallback) {
|
|
1285
|
+
const selected = normalizeUrl(value, fallback);
|
|
1286
|
+
if (!selected)
|
|
1287
|
+
return "";
|
|
1288
|
+
try {
|
|
1289
|
+
const parsed = new URL(selected);
|
|
1290
|
+
parsed.protocol = "http:";
|
|
1291
|
+
parsed.username = "";
|
|
1292
|
+
parsed.password = "";
|
|
1293
|
+
parsed.hostname = "127.0.0.1";
|
|
1294
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
1295
|
+
} catch {
|
|
1296
|
+
return normalizeUrl(fallback);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
function isLoopbackUrl(value) {
|
|
1300
|
+
try {
|
|
1301
|
+
const parsed = new URL(normalizeUrl(value));
|
|
1302
|
+
const hostname = String(parsed.hostname ?? "").trim().toLowerCase();
|
|
1303
|
+
return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1";
|
|
1304
|
+
} catch {
|
|
1305
|
+
return false;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1173
1308
|
function parsePositiveInt(value, fallback) {
|
|
1174
1309
|
const parsed = Number.parseInt(String(value ?? "").trim(), 10);
|
|
1175
1310
|
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
@@ -1177,7 +1312,7 @@ function parsePositiveInt(value, fallback) {
|
|
|
1177
1312
|
return parsed;
|
|
1178
1313
|
}
|
|
1179
1314
|
function normalizePath(value) {
|
|
1180
|
-
const normalized =
|
|
1315
|
+
const normalized = resolve4(value).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1181
1316
|
if (process.platform === "win32")
|
|
1182
1317
|
return normalized.toLowerCase();
|
|
1183
1318
|
return normalized;
|
|
@@ -1205,11 +1340,11 @@ async function resolveCurrentGitRepoRoot(cwd) {
|
|
|
1205
1340
|
const root = await runGit(["rev-parse", "--show-toplevel"], cwd);
|
|
1206
1341
|
if (!root.ok || !root.stdout)
|
|
1207
1342
|
return null;
|
|
1208
|
-
return
|
|
1343
|
+
return resolve4(root.stdout);
|
|
1209
1344
|
}
|
|
1210
1345
|
function resolveDefaultRuntimeRoot() {
|
|
1211
1346
|
const home = process.env.USERPROFILE || process.env.HOME || process.cwd();
|
|
1212
|
-
return
|
|
1347
|
+
return resolve4(home, ".pushpals", "runtime");
|
|
1213
1348
|
}
|
|
1214
1349
|
function buildRuntimeAssetSource(root, protocolSchemasDir) {
|
|
1215
1350
|
return {
|
|
@@ -1222,13 +1357,13 @@ function buildRuntimeAssetSource(root, protocolSchemasDir) {
|
|
|
1222
1357
|
};
|
|
1223
1358
|
}
|
|
1224
1359
|
function isCompleteRuntimeAssetSource(source) {
|
|
1225
|
-
return
|
|
1360
|
+
return existsSync4(source.envExamplePath) && existsSync4(source.visionExamplePath) && existsSync4(join2(source.configsDir, "default.toml")) && existsSync4(source.promptsDir) && existsSync4(join2(source.protocolSchemasDir, "envelope.schema.json")) && existsSync4(join2(source.protocolSchemasDir, "events.schema.json"));
|
|
1226
1361
|
}
|
|
1227
1362
|
function resolveBundledRuntimeAssetSource() {
|
|
1228
1363
|
const candidates = [
|
|
1229
|
-
buildRuntimeAssetSource(
|
|
1230
|
-
buildRuntimeAssetSource(
|
|
1231
|
-
buildRuntimeAssetSource(
|
|
1364
|
+
buildRuntimeAssetSource(resolve4(import.meta.dir, "..", "runtime"), resolve4(import.meta.dir, "..", "runtime", "protocol", "schemas")),
|
|
1365
|
+
buildRuntimeAssetSource(resolve4(import.meta.dir, ".."), resolve4(import.meta.dir, "..", "packages", "protocol", "src", "schemas")),
|
|
1366
|
+
buildRuntimeAssetSource(resolve4(import.meta.dir, "..", "packages", "cli", "runtime"), resolve4(import.meta.dir, "..", "packages", "cli", "runtime", "protocol", "schemas"))
|
|
1232
1367
|
];
|
|
1233
1368
|
for (const candidate of candidates) {
|
|
1234
1369
|
if (isCompleteRuntimeAssetSource(candidate))
|
|
@@ -1237,12 +1372,12 @@ function resolveBundledRuntimeAssetSource() {
|
|
|
1237
1372
|
return null;
|
|
1238
1373
|
}
|
|
1239
1374
|
function looksLikeMonitoringHubBuild(root) {
|
|
1240
|
-
return
|
|
1375
|
+
return existsSync4(join2(root, "index.html")) && existsSync4(join2(root, "_expo"));
|
|
1241
1376
|
}
|
|
1242
1377
|
function resolveBundledMonitoringHubRoot() {
|
|
1243
1378
|
const candidates = [
|
|
1244
|
-
|
|
1245
|
-
|
|
1379
|
+
resolve4(import.meta.dir, "..", "monitor-ui"),
|
|
1380
|
+
resolve4(import.meta.dir, "..", "packages", "cli", "monitor-ui")
|
|
1246
1381
|
];
|
|
1247
1382
|
for (const candidate of candidates) {
|
|
1248
1383
|
if (looksLikeMonitoringHubBuild(candidate))
|
|
@@ -1252,12 +1387,12 @@ function resolveBundledMonitoringHubRoot() {
|
|
|
1252
1387
|
}
|
|
1253
1388
|
function resolveCliSourceCheckoutRoot() {
|
|
1254
1389
|
const candidates = [
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1390
|
+
resolve4(import.meta.dir, ".."),
|
|
1391
|
+
resolve4(import.meta.dir, "..", ".."),
|
|
1392
|
+
resolve4(import.meta.dir, "..", "..", "..")
|
|
1258
1393
|
];
|
|
1259
1394
|
for (const candidate of candidates) {
|
|
1260
|
-
if (
|
|
1395
|
+
if (existsSync4(join2(candidate, "package.json")) && existsSync4(join2(candidate, "apps", "client", "app.json")) && existsSync4(join2(candidate, "scripts", "sync-cli-monitor-ui.ts"))) {
|
|
1261
1396
|
return candidate;
|
|
1262
1397
|
}
|
|
1263
1398
|
}
|
|
@@ -1287,7 +1422,7 @@ async function ensureBundledMonitoringHubRoot() {
|
|
|
1287
1422
|
return resolveBundledMonitoringHubRoot();
|
|
1288
1423
|
}
|
|
1289
1424
|
function repoLooksLikePushPalsSourceCheckout(repoRoot) {
|
|
1290
|
-
return
|
|
1425
|
+
return existsSync4(join2(repoRoot, "configs", "default.toml")) || existsSync4(join2(repoRoot, "config", "default.toml"));
|
|
1291
1426
|
}
|
|
1292
1427
|
function parseSemverFromPackageVersion(value) {
|
|
1293
1428
|
const raw = String(value ?? "").trim();
|
|
@@ -1325,6 +1460,7 @@ async function resolveRuntimeReleaseTag(explicitTag) {
|
|
|
1325
1460
|
if (fromEnv)
|
|
1326
1461
|
return fromEnv;
|
|
1327
1462
|
const packageVersion = parseSemverFromPackageVersion(process.env.PUSHPALS_CLI_PACKAGE_VERSION);
|
|
1463
|
+
console.log("[pushpals] Resolving embedded runtime release tag from GitHub...");
|
|
1328
1464
|
try {
|
|
1329
1465
|
return await fetchLatestReleaseTag();
|
|
1330
1466
|
} catch (err) {
|
|
@@ -1337,7 +1473,7 @@ async function resolveRuntimeReleaseTag(explicitTag) {
|
|
|
1337
1473
|
}
|
|
1338
1474
|
}
|
|
1339
1475
|
function writeTextFileIfMissing(pathValue, text) {
|
|
1340
|
-
if (
|
|
1476
|
+
if (existsSync4(pathValue))
|
|
1341
1477
|
return;
|
|
1342
1478
|
mkdirSync(dirname(pathValue), { recursive: true });
|
|
1343
1479
|
writeFileSync(pathValue, text, "utf8");
|
|
@@ -1380,8 +1516,8 @@ function seedRuntimePreflightAssets(runtimeRoot) {
|
|
|
1380
1516
|
writeTextFileIfMissing(join2(runtimeRoot, ".env"), `# Local PushPals runtime environment
|
|
1381
1517
|
`);
|
|
1382
1518
|
const localExamplePath = join2(runtimeRoot, "configs", "local.example.toml");
|
|
1383
|
-
if (
|
|
1384
|
-
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"),
|
|
1519
|
+
if (existsSync4(localExamplePath)) {
|
|
1520
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), readFileSync4(localExamplePath, "utf8"));
|
|
1385
1521
|
} else {
|
|
1386
1522
|
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), `# Local PushPals runtime overrides
|
|
1387
1523
|
`);
|
|
@@ -1395,6 +1531,7 @@ async function fetchTextFromUrl(url, timeoutMs = 20000) {
|
|
|
1395
1531
|
return await response.text();
|
|
1396
1532
|
}
|
|
1397
1533
|
async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
1534
|
+
console.log(`[pushpals] Downloading embedded runtime assets from source tag ${tag}...`);
|
|
1398
1535
|
const treeUrl = `${GITHUB_API_URL}/git/trees/${encodeURIComponent(tag)}?recursive=1`;
|
|
1399
1536
|
const treeResponse = await fetchWithTimeout(treeUrl, { headers: GITHUB_HEADERS }, 30000);
|
|
1400
1537
|
if (!treeResponse.ok) {
|
|
@@ -1415,16 +1552,19 @@ async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
|
1415
1552
|
}
|
|
1416
1553
|
}
|
|
1417
1554
|
async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
1555
|
+
console.log(`[pushpals] Preparing embedded runtime assets for ${runtimeTag}...`);
|
|
1418
1556
|
const markerPath = join2(runtimeRoot, ".runtime-assets-tag");
|
|
1419
|
-
const currentTag =
|
|
1557
|
+
const currentTag = existsSync4(markerPath) ? readFileSync4(markerPath, "utf8").trim() : "";
|
|
1420
1558
|
const protocolSchemasDir = join2(runtimeRoot, "protocol", "schemas");
|
|
1421
|
-
const hasProtocolSchemas =
|
|
1422
|
-
const hasAssets =
|
|
1559
|
+
const hasProtocolSchemas = existsSync4(join2(protocolSchemasDir, "envelope.schema.json")) && existsSync4(join2(protocolSchemasDir, "events.schema.json"));
|
|
1560
|
+
const hasAssets = existsSync4(join2(runtimeRoot, ".env.example")) && existsSync4(join2(runtimeRoot, "vision.example.md")) && existsSync4(join2(runtimeRoot, "configs", "default.toml")) && existsSync4(join2(runtimeRoot, "prompts")) && hasProtocolSchemas;
|
|
1423
1561
|
if (!hasAssets || currentTag !== runtimeTag) {
|
|
1562
|
+
console.log(`[pushpals] Embedded runtime assets ${hasAssets ? "are stale" : "are missing"}; refreshing bundle...`);
|
|
1424
1563
|
copyBundledRuntimeAssets(runtimeRoot);
|
|
1425
|
-
const hasProtocolSchemasAfterCopy =
|
|
1426
|
-
const hasAssetsAfterCopy =
|
|
1564
|
+
const hasProtocolSchemasAfterCopy = existsSync4(join2(protocolSchemasDir, "envelope.schema.json")) && existsSync4(join2(protocolSchemasDir, "events.schema.json"));
|
|
1565
|
+
const hasAssetsAfterCopy = existsSync4(join2(runtimeRoot, ".env.example")) && existsSync4(join2(runtimeRoot, "vision.example.md")) && existsSync4(join2(runtimeRoot, "configs", "default.toml")) && existsSync4(join2(runtimeRoot, "prompts")) && hasProtocolSchemasAfterCopy;
|
|
1427
1566
|
if (!hasAssetsAfterCopy) {
|
|
1567
|
+
console.log("[pushpals] Bundled runtime assets are incomplete; falling back to release source downloads...");
|
|
1428
1568
|
await downloadRuntimeAssetsFromSourceTag(runtimeRoot, runtimeTag);
|
|
1429
1569
|
}
|
|
1430
1570
|
writeFileSync(markerPath, `${runtimeTag}
|
|
@@ -1433,18 +1573,19 @@ async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
|
1433
1573
|
writeTextFileIfMissing(join2(runtimeRoot, ".env"), `# Local PushPals runtime environment
|
|
1434
1574
|
`);
|
|
1435
1575
|
const localExamplePath = join2(runtimeRoot, "configs", "local.example.toml");
|
|
1436
|
-
if (
|
|
1437
|
-
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"),
|
|
1576
|
+
if (existsSync4(localExamplePath)) {
|
|
1577
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), readFileSync4(localExamplePath, "utf8"));
|
|
1438
1578
|
} else {
|
|
1439
1579
|
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), `# Local PushPals runtime overrides
|
|
1440
1580
|
`);
|
|
1441
1581
|
}
|
|
1582
|
+
console.log("[pushpals] Embedded runtime assets are ready.");
|
|
1442
1583
|
}
|
|
1443
1584
|
function resolveDeferredRuntimeTagHint(explicitTag) {
|
|
1444
1585
|
return String(explicitTag || process.env.PUSHPALS_RUNTIME_TAG || "").trim();
|
|
1445
1586
|
}
|
|
1446
1587
|
async function prepareCliRuntime(opts) {
|
|
1447
|
-
const runtimeRoot =
|
|
1588
|
+
const runtimeRoot = resolve4(opts.runtimeRoot || process.env.PUSHPALS_RUNTIME_ROOT || resolveDefaultRuntimeRoot());
|
|
1448
1589
|
if (repoLooksLikePushPalsSourceCheckout(opts.repoRoot)) {
|
|
1449
1590
|
return {
|
|
1450
1591
|
runtimeRoot,
|
|
@@ -1496,6 +1637,7 @@ function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
|
1496
1637
|
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.repoRoot
|
|
1497
1638
|
},
|
|
1498
1639
|
PUSHPALS_PROTOCOL_SCHEMAS_DIR: join2(opts.runtimeRoot, "protocol", "schemas"),
|
|
1640
|
+
...opts.forceLocalBuddyEnabled ? { LOCALBUDDY_ENABLED: "1" } : {},
|
|
1499
1641
|
...typeof env.PUSHPALS_GIT_BIN === "string" && env.PUSHPALS_GIT_BIN.trim() ? { PUSHPALS_GIT_BIN: env.PUSHPALS_GIT_BIN.trim() } : {}
|
|
1500
1642
|
};
|
|
1501
1643
|
}
|
|
@@ -1551,9 +1693,9 @@ function timestampFileToken() {
|
|
|
1551
1693
|
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
1552
1694
|
}
|
|
1553
1695
|
function readLogTail(logPath, maxLines = 40) {
|
|
1554
|
-
if (!
|
|
1696
|
+
if (!existsSync4(logPath))
|
|
1555
1697
|
return "";
|
|
1556
|
-
const raw =
|
|
1698
|
+
const raw = readFileSync4(logPath, "utf8");
|
|
1557
1699
|
const lines = raw.split(/\r?\n/).map((line) => line.trimEnd()).filter((line) => line.length > 0);
|
|
1558
1700
|
if (lines.length === 0)
|
|
1559
1701
|
return "";
|
|
@@ -1561,6 +1703,7 @@ function readLogTail(logPath, maxLines = 40) {
|
|
|
1561
1703
|
`);
|
|
1562
1704
|
}
|
|
1563
1705
|
async function downloadBinaryAsset(tag, assetName, outPath) {
|
|
1706
|
+
console.log(`[pushpals] Downloading embedded runtime binary ${assetName} from ${tag}...`);
|
|
1564
1707
|
const url = `${GITHUB_RELEASE_URL}/${encodeURIComponent(tag)}/${assetName}`;
|
|
1565
1708
|
const response = await fetchWithTimeout(url, { headers: GITHUB_HEADERS }, 60000);
|
|
1566
1709
|
if (!response.ok) {
|
|
@@ -1572,6 +1715,7 @@ async function downloadBinaryAsset(tag, assetName, outPath) {
|
|
|
1572
1715
|
}
|
|
1573
1716
|
async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
|
|
1574
1717
|
const platformKey = resolveRuntimePlatformKey();
|
|
1718
|
+
console.log(`[pushpals] Preparing embedded runtime binaries for ${runtimeTag} (${platformKey})...`);
|
|
1575
1719
|
const binDir = join2(runtimeRoot, "bin", `${runtimeTag}-${platformKey}`);
|
|
1576
1720
|
mkdirSync(binDir, { recursive: true });
|
|
1577
1721
|
const runtimeBinaries = {
|
|
@@ -1586,11 +1730,13 @@ async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
|
|
|
1586
1730
|
runtimeBinaries.remotebuddy,
|
|
1587
1731
|
runtimeBinaries.sourceControlManager
|
|
1588
1732
|
];
|
|
1733
|
+
let downloadedCount = 0;
|
|
1589
1734
|
for (const binaryPath of requiredAssets) {
|
|
1590
|
-
if (
|
|
1735
|
+
if (existsSync4(binaryPath))
|
|
1591
1736
|
continue;
|
|
1592
1737
|
const assetName = binaryPath.split(/[\\/]/).pop() || "";
|
|
1593
1738
|
await downloadBinaryAsset(runtimeTag, assetName, binaryPath);
|
|
1739
|
+
downloadedCount++;
|
|
1594
1740
|
}
|
|
1595
1741
|
if (process.platform !== "win32") {
|
|
1596
1742
|
for (const binaryPath of requiredAssets) {
|
|
@@ -1599,6 +1745,12 @@ async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
|
|
|
1599
1745
|
} catch {}
|
|
1600
1746
|
}
|
|
1601
1747
|
}
|
|
1748
|
+
if (downloadedCount === 0) {
|
|
1749
|
+
console.log("[pushpals] Embedded runtime binaries are already present.");
|
|
1750
|
+
} else {
|
|
1751
|
+
console.log(`[pushpals] Embedded runtime binaries downloaded: ${downloadedCount}.`);
|
|
1752
|
+
}
|
|
1753
|
+
console.log("[pushpals] Embedded runtime binaries are ready.");
|
|
1602
1754
|
return runtimeBinaries;
|
|
1603
1755
|
}
|
|
1604
1756
|
function spawnRuntimeService(name, command, cwd, env, logPath) {
|
|
@@ -1676,6 +1828,34 @@ function stopRuntimeServices(services) {
|
|
|
1676
1828
|
} catch {}
|
|
1677
1829
|
}
|
|
1678
1830
|
}
|
|
1831
|
+
function prependExecutableDirToPath(env, executablePath, platform = process.platform) {
|
|
1832
|
+
const resolvedPath = String(executablePath ?? "").trim();
|
|
1833
|
+
if (!resolvedPath)
|
|
1834
|
+
return env;
|
|
1835
|
+
if (!resolvedPath.includes("/") && !resolvedPath.includes("\\")) {
|
|
1836
|
+
return env;
|
|
1837
|
+
}
|
|
1838
|
+
const executableDir = dirname(resolvedPath);
|
|
1839
|
+
const existingPath = platform === "win32" ? String(env.Path ?? env.PATH ?? "") : String(env.PATH ?? "");
|
|
1840
|
+
const pathEntries = existingPath.split(delimiter).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
1841
|
+
const hasDir = pathEntries.some((entry) => entry.toLowerCase() === executableDir.toLowerCase());
|
|
1842
|
+
const nextPath = hasDir ? existingPath : [executableDir, ...pathEntries].join(delimiter);
|
|
1843
|
+
if (platform === "win32") {
|
|
1844
|
+
env.Path = nextPath;
|
|
1845
|
+
env.PATH = nextPath;
|
|
1846
|
+
} else {
|
|
1847
|
+
env.PATH = nextPath;
|
|
1848
|
+
}
|
|
1849
|
+
return env;
|
|
1850
|
+
}
|
|
1851
|
+
function applyResolvedGitBinaryToRuntimeEnv(env, resolvedGitBinary, platform = process.platform) {
|
|
1852
|
+
const resolvedPath = String(resolvedGitBinary ?? "").trim();
|
|
1853
|
+
if (!resolvedPath)
|
|
1854
|
+
return env;
|
|
1855
|
+
prependExecutableDirToPath(env, resolvedPath, platform);
|
|
1856
|
+
env.PUSHPALS_GIT_BIN = basename(resolvedPath);
|
|
1857
|
+
return env;
|
|
1858
|
+
}
|
|
1679
1859
|
function isOptionalEmbeddedService(name) {
|
|
1680
1860
|
return name === "source_control_manager";
|
|
1681
1861
|
}
|
|
@@ -1738,18 +1918,34 @@ async function fetchJsonWithTimeout(url, init = {}, timeoutMs = HTTP_TIMEOUT_MS)
|
|
|
1738
1918
|
return null;
|
|
1739
1919
|
}
|
|
1740
1920
|
}
|
|
1741
|
-
function
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1921
|
+
function buildClientTransportQuery(cursor, client) {
|
|
1922
|
+
const params = new URLSearchParams;
|
|
1923
|
+
if (cursor > 0)
|
|
1924
|
+
params.set("after", String(cursor));
|
|
1925
|
+
params.set("clientId", client.clientId);
|
|
1926
|
+
params.set("clientKind", client.kind);
|
|
1927
|
+
params.set("clientLabel", client.label);
|
|
1928
|
+
params.set("clientVersion", client.version);
|
|
1929
|
+
params.set("clientPlatform", client.platform);
|
|
1930
|
+
params.set("clientRepoRoot", client.repoRoot);
|
|
1931
|
+
const query = params.toString();
|
|
1932
|
+
return query ? `?${query}` : "";
|
|
1745
1933
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1934
|
+
function createRuntimeClientId(prefix) {
|
|
1935
|
+
if (typeof crypto?.randomUUID === "function") {
|
|
1936
|
+
return `${prefix}-${crypto.randomUUID()}`;
|
|
1937
|
+
}
|
|
1938
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
1939
|
+
}
|
|
1940
|
+
async function probeLocalBuddy(localAgentUrl) {
|
|
1941
|
+
return await fetchJsonWithTimeout(`${localAgentUrl}/healthz`, {}, LOCALBUDDY_TIMEOUT_MS);
|
|
1748
1942
|
}
|
|
1749
1943
|
async function autoStartRuntimeServices(opts) {
|
|
1750
1944
|
const { runtimePreflight } = opts.preparedRuntime;
|
|
1751
1945
|
const runtimeRoot = opts.preparedRuntime.runtimeRoot;
|
|
1752
1946
|
const runtimeTag = opts.preparedRuntime.runtimeTag || await resolveRuntimeReleaseTag(opts.requestedRuntimeTag);
|
|
1947
|
+
const requireLocalBuddy = opts.requireLocalBuddy ?? true;
|
|
1948
|
+
const localBuddyEnabled = requireLocalBuddy || Boolean(runtimePreflight.config.localbuddy.enabled);
|
|
1753
1949
|
console.log(`[pushpals] LocalBuddy unavailable. Auto-starting runtime for repo: ${opts.repoRoot}`);
|
|
1754
1950
|
console.log(`[pushpals] runtimeRoot=${runtimeRoot}`);
|
|
1755
1951
|
console.log(`[pushpals] runtimeTag=${runtimeTag}`);
|
|
@@ -1761,11 +1957,15 @@ async function autoStartRuntimeServices(opts) {
|
|
|
1761
1957
|
const runtimeEnv = buildEmbeddedRuntimeEnv(process.env, {
|
|
1762
1958
|
repoRoot: opts.repoRoot,
|
|
1763
1959
|
runtimeRoot,
|
|
1764
|
-
useRuntimeConfig: opts.preparedRuntime.preflightUsesEmbeddedRuntime
|
|
1960
|
+
useRuntimeConfig: opts.preparedRuntime.preflightUsesEmbeddedRuntime,
|
|
1961
|
+
forceLocalBuddyEnabled: requireLocalBuddy
|
|
1765
1962
|
});
|
|
1963
|
+
if (runtimeEnv.PUSHPALS_GIT_BIN) {
|
|
1964
|
+
applyResolvedGitBinaryToRuntimeEnv(runtimeEnv, runtimeEnv.PUSHPALS_GIT_BIN);
|
|
1965
|
+
}
|
|
1766
1966
|
const resolvedGitBinary = await resolveCommandPath("git", opts.repoRoot, normalizeChildProcessEnv(process.env));
|
|
1767
1967
|
if (resolvedGitBinary) {
|
|
1768
|
-
runtimeEnv
|
|
1968
|
+
applyResolvedGitBinaryToRuntimeEnv(runtimeEnv, resolvedGitBinary);
|
|
1769
1969
|
}
|
|
1770
1970
|
const services = [];
|
|
1771
1971
|
const runToken = timestampFileToken();
|
|
@@ -1805,10 +2005,17 @@ ${tail}` : ""}`);
|
|
|
1805
2005
|
} else {
|
|
1806
2006
|
console.log("[pushpals] Server already healthy; skipping embedded server start.");
|
|
1807
2007
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
2008
|
+
if (localBuddyEnabled) {
|
|
2009
|
+
if (requireLocalBuddy && !runtimePreflight.config.localbuddy.enabled) {
|
|
2010
|
+
console.log("[pushpals] LocalBuddy is disabled in config; forcing it on for this CLI session.");
|
|
2011
|
+
}
|
|
2012
|
+
console.log("[pushpals] Starting embedded LocalBuddy...");
|
|
2013
|
+
const localbuddyService = spawnRuntimeService("localbuddy", [runtimeBinaries.localbuddy], opts.repoRoot, runtimeEnv, logPathFor("localbuddy"));
|
|
2014
|
+
services.push(localbuddyService);
|
|
2015
|
+
console.log(`[pushpals] localbuddy log: ${localbuddyService.logPath}`);
|
|
2016
|
+
} else {
|
|
2017
|
+
console.log("[pushpals] Embedded LocalBuddy disabled by runtime config; skipping start.");
|
|
2018
|
+
}
|
|
1812
2019
|
console.log("[pushpals] Starting embedded RemoteBuddy...");
|
|
1813
2020
|
const remotebuddyService = spawnRuntimeService("remotebuddy", [runtimeBinaries.remotebuddy], opts.repoRoot, runtimeEnv, logPathFor("remotebuddy"));
|
|
1814
2021
|
services.push(remotebuddyService);
|
|
@@ -1858,8 +2065,8 @@ ${tail2}`);
|
|
|
1858
2065
|
${tail}` : ""}`);
|
|
1859
2066
|
}
|
|
1860
2067
|
}
|
|
1861
|
-
const health = await probeLocalBuddy(opts.localAgentUrl
|
|
1862
|
-
if (health?.ok) {
|
|
2068
|
+
const health = localBuddyEnabled ? await probeLocalBuddy(opts.localAgentUrl) : null;
|
|
2069
|
+
if (!requireLocalBuddy || localBuddyEnabled && health?.ok) {
|
|
1863
2070
|
const stabilityDeadline = Date.now() + DEFAULT_SERVICE_STABILITY_GRACE_MS;
|
|
1864
2071
|
while (Date.now() < stabilityDeadline) {
|
|
1865
2072
|
for (let i = services.length - 1;i >= 0; i--) {
|
|
@@ -1890,13 +2097,16 @@ ${tail}` : ""}`);
|
|
|
1890
2097
|
await Bun.sleep(DEFAULT_RUNTIME_BOOT_POLL_MS);
|
|
1891
2098
|
}
|
|
1892
2099
|
stopRuntimeServices(services);
|
|
2100
|
+
if (!localBuddyEnabled) {
|
|
2101
|
+
throw new Error(`Timed out waiting for embedded runtime readiness after ${DEFAULT_RUNTIME_BOOT_TIMEOUT_MS}ms`);
|
|
2102
|
+
}
|
|
1893
2103
|
throw new Error(`Timed out waiting for LocalBuddy at ${opts.localAgentUrl} after ${DEFAULT_RUNTIME_BOOT_TIMEOUT_MS}ms`);
|
|
1894
2104
|
}
|
|
1895
2105
|
function readCliState(pathValue) {
|
|
1896
|
-
if (!
|
|
2106
|
+
if (!existsSync4(pathValue))
|
|
1897
2107
|
return {};
|
|
1898
2108
|
try {
|
|
1899
|
-
const raw =
|
|
2109
|
+
const raw = readFileSync4(pathValue, "utf8");
|
|
1900
2110
|
const parsed = JSON.parse(raw);
|
|
1901
2111
|
if (!parsed || typeof parsed !== "object")
|
|
1902
2112
|
return {};
|
|
@@ -1922,6 +2132,9 @@ function writeCliState(pathValue, state) {
|
|
|
1922
2132
|
writeFileSync(pathValue, `${JSON.stringify(payload, null, 2)}
|
|
1923
2133
|
`, "utf8");
|
|
1924
2134
|
}
|
|
2135
|
+
function resolveCliStatePath(repoRoot) {
|
|
2136
|
+
return resolveGitStateFilePath(repoRoot, "pushpals-cli-state.json");
|
|
2137
|
+
}
|
|
1925
2138
|
async function looksLikeMonitoringHub(url) {
|
|
1926
2139
|
try {
|
|
1927
2140
|
const response = await fetchWithTimeout(url, {}, 700);
|
|
@@ -1942,7 +2155,9 @@ function buildMonitoringHubRuntimeBootstrap(opts) {
|
|
|
1942
2155
|
serverUrl: opts.serverUrl,
|
|
1943
2156
|
localAgentUrl: opts.localAgentUrl,
|
|
1944
2157
|
sessionId: opts.sessionId,
|
|
1945
|
-
|
|
2158
|
+
clientId: `cli-monitor-${opts.sessionId}`,
|
|
2159
|
+
clientKind: "cli_monitor",
|
|
2160
|
+
clientLabel: "CLI Monitor"
|
|
1946
2161
|
};
|
|
1947
2162
|
}
|
|
1948
2163
|
function injectMonitoringHubBootstrap(html, bootstrap) {
|
|
@@ -1983,19 +2198,19 @@ function monitoringHubContentType(pathValue) {
|
|
|
1983
2198
|
}
|
|
1984
2199
|
}
|
|
1985
2200
|
function resolveMonitoringHubAssetPath(assetRoot, pathname) {
|
|
1986
|
-
const root =
|
|
2201
|
+
const root = resolve4(assetRoot);
|
|
1987
2202
|
const rootPrefix = `${root}${root.endsWith("\\") || root.endsWith("/") ? "" : process.platform === "win32" ? "\\" : "/"}`;
|
|
1988
2203
|
const decodedPath = decodeURIComponent(pathname);
|
|
1989
2204
|
const trimmedPath = decodedPath === "/" ? "/index.html" : decodedPath;
|
|
1990
2205
|
const relativePath = trimmedPath.replace(/^\/+/, "");
|
|
1991
|
-
const candidatePath =
|
|
2206
|
+
const candidatePath = resolve4(root, relativePath);
|
|
1992
2207
|
if (candidatePath !== root && !candidatePath.startsWith(rootPrefix))
|
|
1993
2208
|
return null;
|
|
1994
|
-
if (
|
|
2209
|
+
if (existsSync4(candidatePath))
|
|
1995
2210
|
return candidatePath;
|
|
1996
2211
|
if (!extname(relativePath)) {
|
|
1997
|
-
const nestedIndexPath =
|
|
1998
|
-
if ((nestedIndexPath === root || nestedIndexPath.startsWith(rootPrefix)) &&
|
|
2212
|
+
const nestedIndexPath = resolve4(root, relativePath, "index.html");
|
|
2213
|
+
if ((nestedIndexPath === root || nestedIndexPath.startsWith(rootPrefix)) && existsSync4(nestedIndexPath)) {
|
|
1999
2214
|
return nestedIndexPath;
|
|
2000
2215
|
}
|
|
2001
2216
|
return join2(root, "index.html");
|
|
@@ -2004,10 +2219,10 @@ function resolveMonitoringHubAssetPath(assetRoot, pathname) {
|
|
|
2004
2219
|
}
|
|
2005
2220
|
async function serveBundledMonitoringHub(assetRoot, pathname, bootstrap) {
|
|
2006
2221
|
const assetPath = resolveMonitoringHubAssetPath(assetRoot, pathname);
|
|
2007
|
-
if (!assetPath || !
|
|
2222
|
+
if (!assetPath || !existsSync4(assetPath))
|
|
2008
2223
|
return null;
|
|
2009
2224
|
if (assetPath.endsWith("index.html")) {
|
|
2010
|
-
const html = injectMonitoringHubBootstrap(
|
|
2225
|
+
const html = injectMonitoringHubBootstrap(readFileSync4(assetPath, "utf8"), bootstrap);
|
|
2011
2226
|
return new Response(html, {
|
|
2012
2227
|
headers: {
|
|
2013
2228
|
"content-type": "text/html; charset=utf-8",
|
|
@@ -2156,9 +2371,9 @@ function buildEmbeddedMonitoringHubHtml(opts) {
|
|
|
2156
2371
|
</body>
|
|
2157
2372
|
</html>`;
|
|
2158
2373
|
}
|
|
2159
|
-
async function proxyMonitoringHubRequest(serverUrl,
|
|
2374
|
+
async function proxyMonitoringHubRequest(serverUrl, pathValue) {
|
|
2160
2375
|
const target = `${serverUrl}${pathValue}`;
|
|
2161
|
-
const upstream = await fetchWithTimeout(target, {
|
|
2376
|
+
const upstream = await fetchWithTimeout(target, {}, 1e4);
|
|
2162
2377
|
const body = await upstream.text();
|
|
2163
2378
|
return new Response(body, {
|
|
2164
2379
|
status: upstream.status,
|
|
@@ -2177,14 +2392,14 @@ async function startEmbeddedMonitoringHub(opts) {
|
|
|
2177
2392
|
const bootstrap = buildMonitoringHubRuntimeBootstrap({
|
|
2178
2393
|
serverUrl: opts.serverUrl,
|
|
2179
2394
|
localAgentUrl: opts.localAgentUrl,
|
|
2180
|
-
sessionId: opts.sessionId
|
|
2181
|
-
authToken: opts.authToken
|
|
2395
|
+
sessionId: opts.sessionId
|
|
2182
2396
|
});
|
|
2183
2397
|
const candidatePorts = Array.from({ length: MONITOR_SCAN_PORTS }, (_, index) => opts.preferredPort + index).concat(0);
|
|
2184
2398
|
for (const port of candidatePorts) {
|
|
2185
2399
|
try {
|
|
2186
2400
|
const server = Bun.serve({
|
|
2187
2401
|
port,
|
|
2402
|
+
hostname: "127.0.0.1",
|
|
2188
2403
|
idleTimeout: 30,
|
|
2189
2404
|
fetch: async (req) => {
|
|
2190
2405
|
const url = new URL(req.url);
|
|
@@ -2197,16 +2412,16 @@ async function startEmbeddedMonitoringHub(opts) {
|
|
|
2197
2412
|
});
|
|
2198
2413
|
}
|
|
2199
2414
|
if (url.pathname === "/api/status") {
|
|
2200
|
-
return await proxyMonitoringHubRequest(opts.serverUrl,
|
|
2415
|
+
return await proxyMonitoringHubRequest(opts.serverUrl, "/system/status");
|
|
2201
2416
|
}
|
|
2202
2417
|
if (url.pathname === "/api/requests") {
|
|
2203
|
-
return await proxyMonitoringHubRequest(opts.serverUrl,
|
|
2418
|
+
return await proxyMonitoringHubRequest(opts.serverUrl, "/requests?status=all&limit=20");
|
|
2204
2419
|
}
|
|
2205
2420
|
if (url.pathname === "/api/jobs") {
|
|
2206
|
-
return await proxyMonitoringHubRequest(opts.serverUrl,
|
|
2421
|
+
return await proxyMonitoringHubRequest(opts.serverUrl, "/jobs?status=all&limit=20");
|
|
2207
2422
|
}
|
|
2208
2423
|
if (url.pathname === "/api/completions") {
|
|
2209
|
-
return await proxyMonitoringHubRequest(opts.serverUrl,
|
|
2424
|
+
return await proxyMonitoringHubRequest(opts.serverUrl, "/completions?status=all&limit=20");
|
|
2210
2425
|
}
|
|
2211
2426
|
const bundledResponse = await serveBundledMonitoringHub(monitoringHubAssetRoot, url.pathname, bootstrap);
|
|
2212
2427
|
if (bundledResponse)
|
|
@@ -2227,10 +2442,13 @@ async function startEmbeddedMonitoringHub(opts) {
|
|
|
2227
2442
|
async function resolveMonitoringHub(opts) {
|
|
2228
2443
|
const explicit = normalizeUrl(opts.preferredUrl);
|
|
2229
2444
|
if (explicit) {
|
|
2230
|
-
if (
|
|
2445
|
+
if (!isLoopbackUrl(explicit)) {
|
|
2446
|
+
console.warn(`[pushpals] Preferred monitoring hub ${explicit} is not local; ignoring it and starting a local monitor instead.`);
|
|
2447
|
+
} else if (await looksLikeMonitoringHub(explicit)) {
|
|
2231
2448
|
return { url: explicit, port: 0, stop: () => {}, embedded: false };
|
|
2449
|
+
} else {
|
|
2450
|
+
console.warn(`[pushpals] Preferred monitoring hub ${explicit} is unavailable; starting embedded monitor instead.`);
|
|
2232
2451
|
}
|
|
2233
|
-
console.warn(`[pushpals] Preferred monitoring hub ${explicit} is unavailable; starting embedded monitor instead.`);
|
|
2234
2452
|
}
|
|
2235
2453
|
for (let port = opts.fallbackPort;port < opts.fallbackPort + MONITOR_SCAN_PORTS; port++) {
|
|
2236
2454
|
const candidate = `http://127.0.0.1:${port}`;
|
|
@@ -2350,12 +2568,11 @@ function formatSessionEventLine(event) {
|
|
|
2350
2568
|
}
|
|
2351
2569
|
return null;
|
|
2352
2570
|
}
|
|
2353
|
-
async function runSessionStream(serverUrl, sessionId,
|
|
2571
|
+
async function runSessionStream(serverUrl, sessionId, client, print, signal) {
|
|
2354
2572
|
let cursor = 0;
|
|
2355
2573
|
while (!signal.aborted) {
|
|
2356
|
-
const headers = authHeaders(authToken);
|
|
2357
2574
|
try {
|
|
2358
|
-
const response = await fetchWithTimeout(`${serverUrl}/sessions/${encodeURIComponent(sessionId)}/events${cursor
|
|
2575
|
+
const response = await fetchWithTimeout(`${serverUrl}/sessions/${encodeURIComponent(sessionId)}/events${buildClientTransportQuery(cursor, client)}`, {}, 15000);
|
|
2359
2576
|
if (!response.ok || !response.body) {
|
|
2360
2577
|
print(`[pushpals] Session stream unavailable: HTTP ${response.status}`);
|
|
2361
2578
|
await Bun.sleep(SSE_RECONNECT_MS);
|
|
@@ -2469,10 +2686,9 @@ async function main() {
|
|
|
2469
2686
|
process.exit(1);
|
|
2470
2687
|
}
|
|
2471
2688
|
const config = preparedRuntime.runtimePreflight.config;
|
|
2472
|
-
const serverUrl =
|
|
2473
|
-
const localAgentUrl =
|
|
2689
|
+
const serverUrl = normalizeLoopbackUrl(parsed.serverUrl ?? process.env.PUSHPALS_SERVER_URL, config.server.url);
|
|
2690
|
+
const localAgentUrl = normalizeLoopbackUrl(parsed.localAgentUrl ?? process.env.EXPO_PUBLIC_LOCAL_AGENT_URL, config.client.localAgentUrl);
|
|
2474
2691
|
const sessionId = String(parsed.sessionId ?? process.env.PUSHPALS_SESSION_ID ?? config.sessionId).trim();
|
|
2475
|
-
const authToken = config.authToken;
|
|
2476
2692
|
let autoStartedServices = [];
|
|
2477
2693
|
const stopAutoStartedServices = () => {
|
|
2478
2694
|
if (autoStartedServices.length === 0)
|
|
@@ -2480,8 +2696,10 @@ async function main() {
|
|
|
2480
2696
|
stopRuntimeServices(autoStartedServices);
|
|
2481
2697
|
autoStartedServices = [];
|
|
2482
2698
|
};
|
|
2483
|
-
let
|
|
2484
|
-
|
|
2699
|
+
let serverHealthy = await probeServer(serverUrl);
|
|
2700
|
+
let health = await probeLocalBuddy(localAgentUrl);
|
|
2701
|
+
const runtimeNeedsAutoStart = parsed.runtimeOnly ? !serverHealthy : !health?.ok;
|
|
2702
|
+
if (runtimeNeedsAutoStart && !parsed.noAutoStart) {
|
|
2485
2703
|
try {
|
|
2486
2704
|
autoStartedServices = await autoStartRuntimeServices({
|
|
2487
2705
|
repoRoot,
|
|
@@ -2489,45 +2707,58 @@ async function main() {
|
|
|
2489
2707
|
localAgentUrl,
|
|
2490
2708
|
sourceControlManagerPort: config.sourceControlManager.port,
|
|
2491
2709
|
sourceControlManagerRemote: config.sourceControlManager.remote,
|
|
2492
|
-
authToken,
|
|
2493
2710
|
preparedRuntime,
|
|
2494
|
-
requestedRuntimeTag: parsed.runtimeTag
|
|
2711
|
+
requestedRuntimeTag: parsed.runtimeTag,
|
|
2712
|
+
requireLocalBuddy: !parsed.runtimeOnly
|
|
2495
2713
|
});
|
|
2496
|
-
|
|
2714
|
+
serverHealthy = await probeServer(serverUrl);
|
|
2715
|
+
health = await probeLocalBuddy(localAgentUrl);
|
|
2497
2716
|
} catch (err) {
|
|
2498
2717
|
console.error(`[pushpals] Auto-start failed: ${String(err)}`);
|
|
2499
2718
|
stopAutoStartedServices();
|
|
2500
2719
|
}
|
|
2501
2720
|
}
|
|
2502
|
-
if (!
|
|
2503
|
-
console.error(`[pushpals]
|
|
2721
|
+
if (parsed.runtimeOnly && !serverHealthy) {
|
|
2722
|
+
console.error(`[pushpals] Server is unavailable at ${serverUrl}.`);
|
|
2504
2723
|
if (parsed.noAutoStart) {
|
|
2505
2724
|
console.error("[pushpals] Auto-start is disabled (--no-auto-start).");
|
|
2506
2725
|
} else {
|
|
2507
|
-
console.error("[pushpals] Auto-start could not bring
|
|
2726
|
+
console.error("[pushpals] Auto-start could not bring the embedded runtime online.");
|
|
2508
2727
|
}
|
|
2509
2728
|
process.exit(1);
|
|
2510
2729
|
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
stopAutoStartedServices();
|
|
2519
|
-
console.error("[pushpals] Repo mismatch detected.");
|
|
2520
|
-
console.error(`[pushpals] currentRepo=${repoRoot}`);
|
|
2521
|
-
console.error(`[pushpals] localBuddyRepo=${localBuddyRepo}`);
|
|
2522
|
-
console.error("[pushpals] LocalBuddy must run against the same repo. Start PushPals from this repo and retry.");
|
|
2730
|
+
if (!parsed.runtimeOnly && !health?.ok) {
|
|
2731
|
+
console.error(`[pushpals] LocalBuddy is unavailable at ${localAgentUrl}.`);
|
|
2732
|
+
if (parsed.noAutoStart) {
|
|
2733
|
+
console.error("[pushpals] Auto-start is disabled (--no-auto-start).");
|
|
2734
|
+
} else {
|
|
2735
|
+
console.error("[pushpals] Auto-start could not bring LocalBuddy online.");
|
|
2736
|
+
}
|
|
2523
2737
|
process.exit(1);
|
|
2524
2738
|
}
|
|
2525
|
-
|
|
2526
|
-
if (
|
|
2527
|
-
|
|
2739
|
+
let localBuddySessionId = sessionId;
|
|
2740
|
+
if (!parsed.runtimeOnly) {
|
|
2741
|
+
const localBuddyRepo = health?.repo ? resolve4(health.repo) : "";
|
|
2742
|
+
if (!localBuddyRepo) {
|
|
2743
|
+
stopAutoStartedServices();
|
|
2744
|
+
console.error("[pushpals] LocalBuddy health response did not include repo path.");
|
|
2745
|
+
process.exit(1);
|
|
2746
|
+
}
|
|
2747
|
+
if (normalizePath(localBuddyRepo) !== normalizePath(repoRoot)) {
|
|
2748
|
+
stopAutoStartedServices();
|
|
2749
|
+
console.error("[pushpals] Repo mismatch detected.");
|
|
2750
|
+
console.error(`[pushpals] currentRepo=${repoRoot}`);
|
|
2751
|
+
console.error(`[pushpals] localBuddyRepo=${localBuddyRepo}`);
|
|
2752
|
+
console.error("[pushpals] LocalBuddy must run against the same repo. Start PushPals from this repo and retry.");
|
|
2753
|
+
process.exit(1);
|
|
2754
|
+
}
|
|
2755
|
+
localBuddySessionId = health?.sessionId && String(health.sessionId).trim() ? String(health.sessionId).trim() : sessionId;
|
|
2756
|
+
if (sessionId && sessionId !== localBuddySessionId) {
|
|
2757
|
+
console.warn(`[pushpals] Requested sessionId=${sessionId}, but LocalBuddy is currently attached to sessionId=${localBuddySessionId}.`);
|
|
2758
|
+
}
|
|
2528
2759
|
}
|
|
2529
|
-
const statePath =
|
|
2530
|
-
const saved = readCliState(statePath);
|
|
2760
|
+
const statePath = resolveCliStatePath(repoRoot);
|
|
2761
|
+
const saved = statePath ? readCliState(statePath) : {};
|
|
2531
2762
|
const preferredHubUrl = normalizeUrl(parsed.monitoringHubUrl ?? process.env.PUSHPALS_MONITOR_URL ?? saved.monitoringHubUrl ?? "");
|
|
2532
2763
|
const monitorPort = parsePositiveInt(process.env.PUSHPALS_CLIENT_PORT, DEFAULT_MONITOR_PORT);
|
|
2533
2764
|
const monitoringHub = await resolveMonitoringHub({
|
|
@@ -2535,32 +2766,48 @@ async function main() {
|
|
|
2535
2766
|
fallbackPort: monitorPort,
|
|
2536
2767
|
serverUrl,
|
|
2537
2768
|
localAgentUrl,
|
|
2538
|
-
sessionId: localBuddySessionId
|
|
2539
|
-
authToken
|
|
2769
|
+
sessionId: localBuddySessionId
|
|
2540
2770
|
});
|
|
2541
2771
|
const monitoringHubUrl = monitoringHub?.url ?? "";
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2772
|
+
if (statePath) {
|
|
2773
|
+
writeCliState(statePath, {
|
|
2774
|
+
monitoringHubUrl: monitoringHubUrl || undefined,
|
|
2775
|
+
serverUrl,
|
|
2776
|
+
localAgentUrl,
|
|
2777
|
+
sessionId: localBuddySessionId,
|
|
2778
|
+
repoRoot
|
|
2779
|
+
});
|
|
2780
|
+
} else {
|
|
2781
|
+
console.warn("[pushpals] Could not resolve git metadata dir; skipping CLI state persistence.");
|
|
2782
|
+
}
|
|
2549
2783
|
console.log("[pushpals] Connected.");
|
|
2550
2784
|
if (monitoringHubUrl) {
|
|
2551
|
-
console.log(`monitoringHubUrl=${monitoringHubUrl}`);
|
|
2785
|
+
console.log(`[pushpals] monitoringHubUrl=${monitoringHubUrl}`);
|
|
2552
2786
|
if (monitoringHub?.embedded) {
|
|
2553
2787
|
console.log("[pushpals] Embedded monitoring hub is running.");
|
|
2554
2788
|
}
|
|
2555
2789
|
} else {
|
|
2556
|
-
console.log("monitoringHubUrl=unavailable");
|
|
2557
|
-
}
|
|
2558
|
-
console.log(`serverUrl=${serverUrl}`);
|
|
2559
|
-
console.log(`localAgentUrl=${localAgentUrl}`);
|
|
2560
|
-
console.log(`sessionId=${localBuddySessionId}`);
|
|
2561
|
-
console.log(`repoRoot=${repoRoot}`);
|
|
2562
|
-
console.log(`cliStateFile=${statePath}`);
|
|
2563
|
-
|
|
2790
|
+
console.log("[pushpals] monitoringHubUrl=unavailable");
|
|
2791
|
+
}
|
|
2792
|
+
console.log(`[pushpals] serverUrl=${serverUrl}`);
|
|
2793
|
+
console.log(`[pushpals] localAgentUrl=${localAgentUrl}`);
|
|
2794
|
+
console.log(`[pushpals] sessionId=${localBuddySessionId}`);
|
|
2795
|
+
console.log(`[pushpals] repoRoot=${repoRoot}`);
|
|
2796
|
+
console.log(`[pushpals] cliStateFile=${statePath ?? "unavailable"}`);
|
|
2797
|
+
if (parsed.runtimeOnly) {
|
|
2798
|
+
console.log("[pushpals] runtimeOnly=true");
|
|
2799
|
+
} else {
|
|
2800
|
+
console.log("[pushpals] Type a message and press Enter. Use /exit or exit to quit.");
|
|
2801
|
+
}
|
|
2802
|
+
const cliVersion = String(process.env.PUSHPALS_CLI_PACKAGE_VERSION ?? "").trim() || "unknown";
|
|
2803
|
+
const cliClient = {
|
|
2804
|
+
clientId: createRuntimeClientId("cli"),
|
|
2805
|
+
kind: "cli",
|
|
2806
|
+
label: "CLI",
|
|
2807
|
+
version: cliVersion,
|
|
2808
|
+
platform: `${process.platform}/${process.arch}`,
|
|
2809
|
+
repoRoot
|
|
2810
|
+
};
|
|
2564
2811
|
const streamAbort = new AbortController;
|
|
2565
2812
|
let rl = null;
|
|
2566
2813
|
const printIncoming = (line) => {
|
|
@@ -2575,7 +2822,7 @@ ${line}
|
|
|
2575
2822
|
}
|
|
2576
2823
|
console.log(line);
|
|
2577
2824
|
};
|
|
2578
|
-
const streamTask = parsed.noStream ? Promise.resolve() : runSessionStream(serverUrl, localBuddySessionId,
|
|
2825
|
+
const streamTask = parsed.noStream ? Promise.resolve() : parsed.runtimeOnly ? Promise.resolve() : runSessionStream(serverUrl, localBuddySessionId, cliClient, printIncoming, streamAbort.signal);
|
|
2579
2826
|
let shuttingDown = false;
|
|
2580
2827
|
const requestStop = () => {
|
|
2581
2828
|
if (shuttingDown)
|
|
@@ -2596,6 +2843,39 @@ ${line}
|
|
|
2596
2843
|
process.once("SIGINT", requestStop);
|
|
2597
2844
|
process.once("SIGTERM", requestStop);
|
|
2598
2845
|
process.once("exit", requestStop);
|
|
2846
|
+
if (parsed.runtimeOnly) {
|
|
2847
|
+
console.log("[pushpals] Runtime-only mode is active. Send `exit` on stdin or terminate the process to stop.");
|
|
2848
|
+
await new Promise((resolveStop) => {
|
|
2849
|
+
let resolved = false;
|
|
2850
|
+
const finish = () => {
|
|
2851
|
+
if (resolved)
|
|
2852
|
+
return;
|
|
2853
|
+
resolved = true;
|
|
2854
|
+
resolveStop();
|
|
2855
|
+
};
|
|
2856
|
+
process.once("SIGINT", finish);
|
|
2857
|
+
process.once("SIGTERM", finish);
|
|
2858
|
+
const runtimeOnlyInput = createInterface({
|
|
2859
|
+
input: process.stdin,
|
|
2860
|
+
output: process.stdout,
|
|
2861
|
+
terminal: false
|
|
2862
|
+
});
|
|
2863
|
+
runtimeOnlyInput.on("line", (line) => {
|
|
2864
|
+
if (!isCliExitCommand(line))
|
|
2865
|
+
return;
|
|
2866
|
+
requestStop();
|
|
2867
|
+
runtimeOnlyInput.close();
|
|
2868
|
+
finish();
|
|
2869
|
+
});
|
|
2870
|
+
runtimeOnlyInput.on("close", () => {
|
|
2871
|
+
requestStop();
|
|
2872
|
+
finish();
|
|
2873
|
+
});
|
|
2874
|
+
});
|
|
2875
|
+
requestStop();
|
|
2876
|
+
await Promise.race([streamTask, Bun.sleep(2000)]);
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2599
2879
|
rl = createInterface({
|
|
2600
2880
|
input: process.stdin,
|
|
2601
2881
|
output: process.stdout,
|
|
@@ -2614,16 +2894,16 @@ ${line}
|
|
|
2614
2894
|
break;
|
|
2615
2895
|
}
|
|
2616
2896
|
if (text === "/hub") {
|
|
2617
|
-
console.log(monitoringHubUrl ? `monitoringHubUrl=${monitoringHubUrl}` : "monitoringHubUrl=unavailable");
|
|
2897
|
+
console.log(monitoringHubUrl ? `[pushpals] monitoringHubUrl=${monitoringHubUrl}` : "[pushpals] monitoringHubUrl=unavailable");
|
|
2618
2898
|
rl.prompt();
|
|
2619
2899
|
continue;
|
|
2620
2900
|
}
|
|
2621
2901
|
if (text === "/status") {
|
|
2622
|
-
console.log(`serverUrl=${serverUrl}`);
|
|
2623
|
-
console.log(`localAgentUrl=${localAgentUrl}`);
|
|
2624
|
-
console.log(`sessionId=${localBuddySessionId}`);
|
|
2625
|
-
console.log(`repoRoot=${repoRoot}`);
|
|
2626
|
-
console.log(monitoringHubUrl ? `monitoringHubUrl=${monitoringHubUrl}` : "monitoringHubUrl=unavailable");
|
|
2902
|
+
console.log(`[pushpals] serverUrl=${serverUrl}`);
|
|
2903
|
+
console.log(`[pushpals] localAgentUrl=${localAgentUrl}`);
|
|
2904
|
+
console.log(`[pushpals] sessionId=${localBuddySessionId}`);
|
|
2905
|
+
console.log(`[pushpals] repoRoot=${repoRoot}`);
|
|
2906
|
+
console.log(monitoringHubUrl ? `[pushpals] monitoringHubUrl=${monitoringHubUrl}` : "[pushpals] monitoringHubUrl=unavailable");
|
|
2627
2907
|
rl.prompt();
|
|
2628
2908
|
continue;
|
|
2629
2909
|
}
|
|
@@ -2656,14 +2936,17 @@ if (import.meta.main) {
|
|
|
2656
2936
|
export {
|
|
2657
2937
|
startEmbeddedMonitoringHub,
|
|
2658
2938
|
resolveCommandPath,
|
|
2939
|
+
resolveCliStatePath,
|
|
2659
2940
|
resolveBundledRuntimeAssetSource,
|
|
2660
2941
|
resolveBundledMonitoringHubRoot,
|
|
2661
2942
|
prepareCliRuntime,
|
|
2662
2943
|
normalizeChildProcessEnv,
|
|
2663
2944
|
isCliExitCommand,
|
|
2664
2945
|
injectMonitoringHubBootstrap,
|
|
2946
|
+
formatTimestampedCliLine,
|
|
2665
2947
|
buildServiceStopCommand,
|
|
2666
2948
|
buildOpenMonitoringHubCommand,
|
|
2667
2949
|
buildEmbeddedRuntimeEnv,
|
|
2668
|
-
buildEmbeddedMonitoringHubHtml
|
|
2950
|
+
buildEmbeddedMonitoringHubHtml,
|
|
2951
|
+
applyResolvedGitBinaryToRuntimeEnv
|
|
2669
2952
|
};
|