@pushpalsdev/cli 1.0.2 → 1.0.3
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/README.md +3 -1
- package/bin/pushpals.cjs +18 -3
- package/dist/pushpals-cli.js +166 -78
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,9 @@ Behavior:
|
|
|
32
32
|
|
|
33
33
|
- If LocalBuddy is unavailable, CLI auto-start bootstraps embedded
|
|
34
34
|
`server + localbuddy + remotebuddy + source_control_manager`.
|
|
35
|
-
-
|
|
35
|
+
- Auto-start does not clone the PushPals repo; it downloads release-tagged runtime binaries
|
|
36
|
+
and prompt/config assets into `~/.pushpals/runtime`.
|
|
37
|
+
- Override runtime tag with `pushpals --runtime-tag vX.Y.Z`.
|
|
36
38
|
- Disable auto-start with `pushpals --no-auto-start`.
|
|
37
39
|
|
|
38
40
|
## No npm/Bun install
|
package/bin/pushpals.cjs
CHANGED
|
@@ -2,11 +2,21 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
const { spawn, spawnSync } = require("node:child_process");
|
|
5
|
-
const { existsSync } = require("node:fs");
|
|
5
|
+
const { existsSync, readFileSync } = require("node:fs");
|
|
6
6
|
const { resolve } = require("node:path");
|
|
7
7
|
|
|
8
8
|
const bundledCliPath = resolve(__dirname, "..", "dist", "pushpals-cli.js");
|
|
9
|
+
const packageJsonPath = resolve(__dirname, "..", "package.json");
|
|
9
10
|
const releaseUrl = "https://github.com/PushPalsDev/pushpals/releases";
|
|
11
|
+
let packageVersion = "";
|
|
12
|
+
if (existsSync(packageJsonPath)) {
|
|
13
|
+
try {
|
|
14
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
15
|
+
packageVersion = String(parsed?.version ?? "").trim();
|
|
16
|
+
} catch {
|
|
17
|
+
packageVersion = "";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
10
20
|
|
|
11
21
|
function fail(lines) {
|
|
12
22
|
for (const line of lines) {
|
|
@@ -41,10 +51,15 @@ if (!hasBunRuntime()) {
|
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
function spawnBunCli() {
|
|
54
|
+
const childEnv = {
|
|
55
|
+
...process.env,
|
|
56
|
+
PUSHPALS_CLI_PACKAGE_VERSION: packageVersion || process.env.PUSHPALS_CLI_PACKAGE_VERSION || "",
|
|
57
|
+
};
|
|
58
|
+
|
|
44
59
|
if (process.platform !== "win32") {
|
|
45
60
|
return spawn("bun", [bundledCliPath, ...process.argv.slice(2)], {
|
|
46
61
|
stdio: "inherit",
|
|
47
|
-
env:
|
|
62
|
+
env: childEnv,
|
|
48
63
|
});
|
|
49
64
|
}
|
|
50
65
|
|
|
@@ -57,7 +72,7 @@ function spawnBunCli() {
|
|
|
57
72
|
return spawn(commandLine, {
|
|
58
73
|
shell: true,
|
|
59
74
|
stdio: "inherit",
|
|
60
|
-
env:
|
|
75
|
+
env: childEnv,
|
|
61
76
|
});
|
|
62
77
|
}
|
|
63
78
|
|
package/dist/pushpals-cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// ../../scripts/pushpals-cli.ts
|
|
5
|
-
import {
|
|
5
|
+
import { chmodSync, cpSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
6
6
|
import { dirname, join as join2, resolve as resolve2 } from "path";
|
|
7
7
|
import { createInterface } from "readline";
|
|
8
8
|
|
|
@@ -250,10 +250,12 @@ function resolveLlmConfig(serviceNode, envPrefix, defaults, globalSessionId) {
|
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
function loadPushPalsConfig(options = {}) {
|
|
253
|
-
const
|
|
254
|
-
const
|
|
253
|
+
const projectRootOverride = firstNonEmpty(options.projectRoot, process.env.PUSHPALS_PROJECT_ROOT_OVERRIDE, PROJECT_ROOT);
|
|
254
|
+
const projectRoot = resolve(projectRootOverride);
|
|
255
|
+
const configDirOverride = firstNonEmpty(options.configDir, process.env.PUSHPALS_CONFIG_DIR_OVERRIDE, "");
|
|
256
|
+
const configDir = resolveRuntimeConfigDir(projectRoot, configDirOverride);
|
|
255
257
|
const legacyConfigDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
256
|
-
const fallbackConfigDir = !
|
|
258
|
+
const fallbackConfigDir = !configDirOverride && configDir !== legacyConfigDir ? legacyConfigDir : "";
|
|
257
259
|
const cacheKey = `${projectRoot}::${configDir}::${process.env.PUSHPALS_PROFILE ?? ""}`;
|
|
258
260
|
if (!options.reload && cachedConfig && cachedConfigKey === cacheKey) {
|
|
259
261
|
return cachedConfig;
|
|
@@ -745,7 +747,14 @@ var LOCALBUDDY_TIMEOUT_MS = 4000;
|
|
|
745
747
|
var SSE_RECONNECT_MS = 1500;
|
|
746
748
|
var DEFAULT_RUNTIME_BOOT_TIMEOUT_MS = 90000;
|
|
747
749
|
var DEFAULT_RUNTIME_BOOT_POLL_MS = 1000;
|
|
748
|
-
var
|
|
750
|
+
var GITHUB_OWNER = "PushPalsDev";
|
|
751
|
+
var GITHUB_REPO = "pushpals";
|
|
752
|
+
var GITHUB_API_URL = `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}`;
|
|
753
|
+
var GITHUB_RELEASE_URL = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/releases/download`;
|
|
754
|
+
var GITHUB_HEADERS = {
|
|
755
|
+
Accept: "application/vnd.github+json",
|
|
756
|
+
"User-Agent": "pushpals-cli"
|
|
757
|
+
};
|
|
749
758
|
var stateVersion = 1;
|
|
750
759
|
function printUsage() {
|
|
751
760
|
console.log("PushPals CLI");
|
|
@@ -759,7 +768,7 @@ function printUsage() {
|
|
|
759
768
|
console.log(" --session-id <id> Override session ID");
|
|
760
769
|
console.log(" --hub-url <url> Override monitoring hub URL");
|
|
761
770
|
console.log(" --runtime-root <path> Override embedded runtime directory for auto-start");
|
|
762
|
-
console.log(" --runtime-
|
|
771
|
+
console.log(" --runtime-tag <tag> Override runtime release tag (e.g. v1.0.2)");
|
|
763
772
|
console.log(" --no-auto-start Disable runtime auto-start when LocalBuddy is down");
|
|
764
773
|
console.log(" --no-stream Disable live session event stream");
|
|
765
774
|
console.log(" -h, --help Show this help");
|
|
@@ -811,8 +820,8 @@ function parseArgs(argv) {
|
|
|
811
820
|
options.runtimeRoot = argv[++i];
|
|
812
821
|
continue;
|
|
813
822
|
}
|
|
814
|
-
if (arg === "--runtime-
|
|
815
|
-
options.
|
|
823
|
+
if (arg === "--runtime-tag") {
|
|
824
|
+
options.runtimeTag = argv[++i];
|
|
816
825
|
continue;
|
|
817
826
|
}
|
|
818
827
|
console.error(`[pushpals] Unknown argument: ${arg}`);
|
|
@@ -860,69 +869,157 @@ async function resolveCurrentGitRepoRoot(cwd) {
|
|
|
860
869
|
return null;
|
|
861
870
|
return resolve2(root.stdout);
|
|
862
871
|
}
|
|
863
|
-
async function runCommand(command, cwd, timeoutMs = 120000) {
|
|
864
|
-
const proc = Bun.spawn(command, {
|
|
865
|
-
cwd,
|
|
866
|
-
stdout: "pipe",
|
|
867
|
-
stderr: "pipe"
|
|
868
|
-
});
|
|
869
|
-
const killTimer = setTimeout(() => {
|
|
870
|
-
try {
|
|
871
|
-
proc.kill();
|
|
872
|
-
} catch {}
|
|
873
|
-
}, timeoutMs);
|
|
874
|
-
try {
|
|
875
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
876
|
-
new Response(proc.stdout).text(),
|
|
877
|
-
new Response(proc.stderr).text(),
|
|
878
|
-
proc.exited
|
|
879
|
-
]);
|
|
880
|
-
return {
|
|
881
|
-
ok: exitCode === 0,
|
|
882
|
-
stdout: stdout.trim(),
|
|
883
|
-
stderr: stderr.trim(),
|
|
884
|
-
exitCode
|
|
885
|
-
};
|
|
886
|
-
} finally {
|
|
887
|
-
clearTimeout(killTimer);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
872
|
function resolveDefaultRuntimeRoot() {
|
|
891
873
|
const home = process.env.USERPROFILE || process.env.HOME || process.cwd();
|
|
892
874
|
return resolve2(home, ".pushpals", "runtime");
|
|
893
875
|
}
|
|
894
|
-
function
|
|
895
|
-
|
|
876
|
+
function parseSemverFromPackageVersion(value) {
|
|
877
|
+
const raw = String(value ?? "").trim();
|
|
878
|
+
if (!raw)
|
|
879
|
+
return "";
|
|
880
|
+
const match = raw.match(/^\d+\.\d+\.\d+(?:[-.][0-9A-Za-z.-]+)?$/);
|
|
881
|
+
return match ? raw : "";
|
|
882
|
+
}
|
|
883
|
+
function resolveRuntimePlatformKey() {
|
|
884
|
+
if (process.platform === "win32")
|
|
885
|
+
return "windows-x64";
|
|
886
|
+
if (process.platform === "linux")
|
|
887
|
+
return "linux-x64";
|
|
888
|
+
if (process.platform === "darwin") {
|
|
889
|
+
return process.arch === "arm64" ? "macos-arm64" : "macos-x64";
|
|
890
|
+
}
|
|
891
|
+
throw new Error(`Unsupported platform for embedded runtime binaries: ${process.platform}/${process.arch}`);
|
|
892
|
+
}
|
|
893
|
+
async function fetchLatestReleaseTag() {
|
|
894
|
+
const response = await fetchWithTimeout(`${GITHUB_API_URL}/releases/latest`, { headers: GITHUB_HEADERS }, 20000);
|
|
895
|
+
if (!response.ok) {
|
|
896
|
+
throw new Error(`Failed to resolve latest release tag (HTTP ${response.status})`);
|
|
897
|
+
}
|
|
898
|
+
const payload = await response.json();
|
|
899
|
+
const tagName = String(payload.tag_name ?? "").trim();
|
|
900
|
+
if (!tagName)
|
|
901
|
+
throw new Error("Latest release payload did not include tag_name");
|
|
902
|
+
return tagName;
|
|
903
|
+
}
|
|
904
|
+
async function resolveRuntimeReleaseTag(explicitTag) {
|
|
905
|
+
const fromArg = String(explicitTag ?? "").trim();
|
|
906
|
+
if (fromArg)
|
|
907
|
+
return fromArg;
|
|
908
|
+
const fromEnv = String(process.env.PUSHPALS_RUNTIME_TAG ?? "").trim();
|
|
909
|
+
if (fromEnv)
|
|
910
|
+
return fromEnv;
|
|
911
|
+
const packageVersion = parseSemverFromPackageVersion(process.env.PUSHPALS_CLI_PACKAGE_VERSION);
|
|
912
|
+
if (packageVersion)
|
|
913
|
+
return `v${packageVersion}`;
|
|
914
|
+
return await fetchLatestReleaseTag();
|
|
915
|
+
}
|
|
916
|
+
function writeTextFileIfMissing(pathValue, text) {
|
|
917
|
+
if (existsSync2(pathValue))
|
|
896
918
|
return;
|
|
897
|
-
mkdirSync(dirname(
|
|
898
|
-
|
|
919
|
+
mkdirSync(dirname(pathValue), { recursive: true });
|
|
920
|
+
writeFileSync(pathValue, text, "utf8");
|
|
899
921
|
}
|
|
900
|
-
|
|
901
|
-
|
|
922
|
+
function copyBundledRuntimeAssets(runtimeRoot) {
|
|
923
|
+
const bundledRoot = resolve2(import.meta.dir, "..", "runtime");
|
|
924
|
+
if (!existsSync2(bundledRoot))
|
|
902
925
|
return false;
|
|
903
|
-
|
|
904
|
-
const clone = await runCommand(["git", "clone", "--depth", "1", runtimeRepo, runtimeRoot], dirname(runtimeRoot), 300000);
|
|
905
|
-
if (!clone.ok) {
|
|
906
|
-
throw new Error(`Failed to clone PushPals runtime from ${runtimeRepo} (exit ${clone.exitCode}): ${clone.stderr || clone.stdout || "unknown error"}`);
|
|
907
|
-
}
|
|
926
|
+
cpSync(bundledRoot, runtimeRoot, { recursive: true, force: true });
|
|
908
927
|
return true;
|
|
909
928
|
}
|
|
910
|
-
async function
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
929
|
+
async function fetchTextFromUrl(url, timeoutMs = 20000) {
|
|
930
|
+
const response = await fetchWithTimeout(url, { headers: GITHUB_HEADERS }, timeoutMs);
|
|
931
|
+
if (!response.ok) {
|
|
932
|
+
throw new Error(`HTTP ${response.status} while fetching ${url}`);
|
|
933
|
+
}
|
|
934
|
+
return await response.text();
|
|
935
|
+
}
|
|
936
|
+
async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
937
|
+
const treeUrl = `${GITHUB_API_URL}/git/trees/${encodeURIComponent(tag)}?recursive=1`;
|
|
938
|
+
const treeResponse = await fetchWithTimeout(treeUrl, { headers: GITHUB_HEADERS }, 30000);
|
|
939
|
+
if (!treeResponse.ok) {
|
|
940
|
+
throw new Error(`Failed to fetch runtime source tree for ${tag} (HTTP ${treeResponse.status})`);
|
|
941
|
+
}
|
|
942
|
+
const treePayload = await treeResponse.json();
|
|
943
|
+
const paths = (treePayload.tree ?? []).filter((entry) => entry.type === "blob" && typeof entry.path === "string").map((entry) => String(entry.path)).filter((pathValue) => pathValue === ".env.example" || pathValue.startsWith("configs/") || pathValue.startsWith("prompts/"));
|
|
944
|
+
if (paths.length === 0) {
|
|
945
|
+
throw new Error(`Runtime source tree for ${tag} did not include prompts/config assets`);
|
|
946
|
+
}
|
|
947
|
+
const sorted = [...paths].sort((a, b) => a.localeCompare(b));
|
|
948
|
+
for (const pathValue of sorted) {
|
|
949
|
+
const rawUrl = `https://raw.githubusercontent.com/${GITHUB_OWNER}/${GITHUB_REPO}/${encodeURIComponent(tag)}/${pathValue}`;
|
|
950
|
+
const body = await fetchTextFromUrl(rawUrl, 20000);
|
|
951
|
+
const outPath = join2(runtimeRoot, pathValue);
|
|
952
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
953
|
+
writeFileSync(outPath, body, "utf8");
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
957
|
+
const markerPath = join2(runtimeRoot, ".runtime-assets-tag");
|
|
958
|
+
const currentTag = existsSync2(markerPath) ? readFileSync2(markerPath, "utf8").trim() : "";
|
|
959
|
+
const hasAssets = existsSync2(join2(runtimeRoot, ".env.example")) && existsSync2(join2(runtimeRoot, "configs", "default.toml")) && existsSync2(join2(runtimeRoot, "prompts"));
|
|
960
|
+
if (!hasAssets || currentTag !== runtimeTag) {
|
|
961
|
+
const copied = copyBundledRuntimeAssets(runtimeRoot);
|
|
962
|
+
if (!copied) {
|
|
963
|
+
await downloadRuntimeAssetsFromSourceTag(runtimeRoot, runtimeTag);
|
|
917
964
|
}
|
|
965
|
+
writeFileSync(markerPath, `${runtimeTag}
|
|
966
|
+
`, "utf8");
|
|
967
|
+
}
|
|
968
|
+
writeTextFileIfMissing(join2(runtimeRoot, ".env"), `# Local PushPals runtime environment
|
|
969
|
+
`);
|
|
970
|
+
const localExamplePath = join2(runtimeRoot, "configs", "local.example.toml");
|
|
971
|
+
if (existsSync2(localExamplePath)) {
|
|
972
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), readFileSync2(localExamplePath, "utf8"));
|
|
973
|
+
} else {
|
|
974
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), `# Local PushPals runtime overrides
|
|
975
|
+
`);
|
|
918
976
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
977
|
+
}
|
|
978
|
+
function runtimeBinaryFilename(serviceName, platformKey) {
|
|
979
|
+
const serviceToken = serviceName === "source_control_manager" ? "source-control-manager" : serviceName;
|
|
980
|
+
const extension = platformKey.startsWith("windows-") ? ".exe" : "";
|
|
981
|
+
return `pushpals-runtime-${serviceToken}-${platformKey}${extension}`;
|
|
982
|
+
}
|
|
983
|
+
async function downloadBinaryAsset(tag, assetName, outPath) {
|
|
984
|
+
const url = `${GITHUB_RELEASE_URL}/${encodeURIComponent(tag)}/${assetName}`;
|
|
985
|
+
const response = await fetchWithTimeout(url, { headers: GITHUB_HEADERS }, 60000);
|
|
986
|
+
if (!response.ok) {
|
|
987
|
+
throw new Error(`Failed to download ${assetName} from ${tag} (HTTP ${response.status})`);
|
|
988
|
+
}
|
|
989
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
990
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
991
|
+
await Bun.write(outPath, bytes);
|
|
992
|
+
}
|
|
993
|
+
async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
|
|
994
|
+
const platformKey = resolveRuntimePlatformKey();
|
|
995
|
+
const binDir = join2(runtimeRoot, "bin", `${runtimeTag}-${platformKey}`);
|
|
996
|
+
mkdirSync(binDir, { recursive: true });
|
|
997
|
+
const runtimeBinaries = {
|
|
998
|
+
server: join2(binDir, runtimeBinaryFilename("server", platformKey)),
|
|
999
|
+
localbuddy: join2(binDir, runtimeBinaryFilename("localbuddy", platformKey)),
|
|
1000
|
+
remotebuddy: join2(binDir, runtimeBinaryFilename("remotebuddy", platformKey)),
|
|
1001
|
+
sourceControlManager: join2(binDir, runtimeBinaryFilename("source_control_manager", platformKey))
|
|
1002
|
+
};
|
|
1003
|
+
const requiredAssets = [
|
|
1004
|
+
runtimeBinaries.server,
|
|
1005
|
+
runtimeBinaries.localbuddy,
|
|
1006
|
+
runtimeBinaries.remotebuddy,
|
|
1007
|
+
runtimeBinaries.sourceControlManager
|
|
1008
|
+
];
|
|
1009
|
+
for (const binaryPath of requiredAssets) {
|
|
1010
|
+
if (existsSync2(binaryPath))
|
|
1011
|
+
continue;
|
|
1012
|
+
const assetName = binaryPath.split(/[\\/]/).pop() || "";
|
|
1013
|
+
await downloadBinaryAsset(runtimeTag, assetName, binaryPath);
|
|
1014
|
+
}
|
|
1015
|
+
if (process.platform !== "win32") {
|
|
1016
|
+
for (const binaryPath of requiredAssets) {
|
|
1017
|
+
try {
|
|
1018
|
+
chmodSync(binaryPath, 493);
|
|
1019
|
+
} catch {}
|
|
924
1020
|
}
|
|
925
1021
|
}
|
|
1022
|
+
return runtimeBinaries;
|
|
926
1023
|
}
|
|
927
1024
|
function spawnRuntimeService(name, command, cwd, env) {
|
|
928
1025
|
const proc = Bun.spawn(command, {
|
|
@@ -997,44 +1094,35 @@ async function probeLocalBuddy(localAgentUrl, authToken) {
|
|
|
997
1094
|
}
|
|
998
1095
|
async function autoStartRuntimeServices(opts) {
|
|
999
1096
|
const runtimeRoot = resolve2(opts.runtimeRoot || process.env.PUSHPALS_RUNTIME_ROOT || resolveDefaultRuntimeRoot());
|
|
1000
|
-
const
|
|
1097
|
+
const runtimeTag = await resolveRuntimeReleaseTag(opts.runtimeTag);
|
|
1098
|
+
const runtimeBinaries = await ensureRuntimeBinaries(runtimeRoot, runtimeTag);
|
|
1099
|
+
await ensureRuntimeAssets(runtimeRoot, runtimeTag);
|
|
1001
1100
|
console.log(`[pushpals] LocalBuddy unavailable. Auto-starting runtime for repo: ${opts.repoRoot}`);
|
|
1002
1101
|
console.log(`[pushpals] runtimeRoot=${runtimeRoot}`);
|
|
1003
|
-
|
|
1004
|
-
if (cloned) {
|
|
1005
|
-
console.log(`[pushpals] Cloned runtime from ${runtimeRepo}`);
|
|
1006
|
-
}
|
|
1007
|
-
await ensureRuntimePrepared(runtimeRoot);
|
|
1102
|
+
console.log(`[pushpals] runtimeTag=${runtimeTag}`);
|
|
1008
1103
|
const runtimeEnv = {
|
|
1009
1104
|
...process.env,
|
|
1010
1105
|
PUSHPALS_REPO_ROOT_OVERRIDE: opts.repoRoot,
|
|
1106
|
+
PUSHPALS_PROJECT_ROOT_OVERRIDE: opts.repoRoot,
|
|
1107
|
+
PUSHPALS_CONFIG_DIR_OVERRIDE: join2(runtimeRoot, "configs"),
|
|
1011
1108
|
PUSHPALS_PROMPTS_ROOT_OVERRIDE: runtimeRoot
|
|
1012
1109
|
};
|
|
1013
1110
|
const services = [];
|
|
1014
1111
|
const serverHealthy = await probeServer(opts.serverUrl);
|
|
1015
1112
|
if (!serverHealthy) {
|
|
1016
1113
|
console.log("[pushpals] Starting embedded server...");
|
|
1017
|
-
services.push(spawnRuntimeService("server", [
|
|
1114
|
+
services.push(spawnRuntimeService("server", [runtimeBinaries.server], opts.repoRoot, runtimeEnv));
|
|
1018
1115
|
} else {
|
|
1019
1116
|
console.log("[pushpals] Server already healthy; skipping embedded server start.");
|
|
1020
1117
|
}
|
|
1021
1118
|
console.log("[pushpals] Starting embedded LocalBuddy...");
|
|
1022
|
-
services.push(spawnRuntimeService("localbuddy", [
|
|
1119
|
+
services.push(spawnRuntimeService("localbuddy", [runtimeBinaries.localbuddy], opts.repoRoot, runtimeEnv));
|
|
1023
1120
|
console.log("[pushpals] Starting embedded RemoteBuddy...");
|
|
1024
|
-
services.push(spawnRuntimeService("remotebuddy", [
|
|
1121
|
+
services.push(spawnRuntimeService("remotebuddy", [runtimeBinaries.remotebuddy], opts.repoRoot, runtimeEnv));
|
|
1025
1122
|
const scmHealthy = await probeSourceControlManager(opts.sourceControlManagerPort);
|
|
1026
1123
|
if (!scmHealthy) {
|
|
1027
1124
|
console.log("[pushpals] Starting embedded SourceControlManager...");
|
|
1028
|
-
services.push(spawnRuntimeService("source_control_manager", [
|
|
1029
|
-
"bun",
|
|
1030
|
-
"--cwd",
|
|
1031
|
-
"apps/source_control_manager",
|
|
1032
|
-
"--env-file",
|
|
1033
|
-
"../../.env",
|
|
1034
|
-
"start",
|
|
1035
|
-
"--",
|
|
1036
|
-
"--skip-clean-check"
|
|
1037
|
-
], runtimeRoot, runtimeEnv));
|
|
1125
|
+
services.push(spawnRuntimeService("source_control_manager", [runtimeBinaries.sourceControlManager, "--skip-clean-check"], opts.repoRoot, runtimeEnv));
|
|
1038
1126
|
} else {
|
|
1039
1127
|
console.log("[pushpals] SourceControlManager already healthy; skipping embedded start.");
|
|
1040
1128
|
}
|
|
@@ -1340,7 +1428,7 @@ async function main() {
|
|
|
1340
1428
|
sourceControlManagerPort: config.sourceControlManager.port,
|
|
1341
1429
|
authToken,
|
|
1342
1430
|
runtimeRoot: parsed.runtimeRoot,
|
|
1343
|
-
|
|
1431
|
+
runtimeTag: parsed.runtimeTag
|
|
1344
1432
|
});
|
|
1345
1433
|
health = await probeLocalBuddy(localAgentUrl, authToken);
|
|
1346
1434
|
} catch (err) {
|