@pushpalsdev/cli 1.0.57 → 1.0.60

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.
@@ -146,6 +146,36 @@ class ServiceManager {
146
146
  this.services.set(spec.name, service);
147
147
  return service;
148
148
  }
149
+ replaceService(spec, options = {}) {
150
+ const existing = this.services.get(spec.name);
151
+ if (existing && !existing.exited) {
152
+ try {
153
+ const pid = existing.proc.pid;
154
+ if (process.platform === "win32" && typeof pid === "number" && pid > 0) {
155
+ Bun.spawnSync(["taskkill", "/PID", String(pid), "/T", "/F"], {
156
+ stdin: "ignore",
157
+ stdout: "ignore",
158
+ stderr: "ignore"
159
+ });
160
+ } else {
161
+ existing.proc.kill("SIGKILL");
162
+ }
163
+ } catch {}
164
+ }
165
+ const state = this.ensureState(spec.name);
166
+ if (state.pendingRestartTimer) {
167
+ clearTimeout(state.pendingRestartTimer);
168
+ state.pendingRestartTimer = null;
169
+ }
170
+ state.nextRestartAtMs = 0;
171
+ state.lastRestartReason = "";
172
+ if (options.resetAttempts !== false) {
173
+ state.attempts = 0;
174
+ }
175
+ this.degradedServiceReasons.delete(spec.name);
176
+ this.emitHealthChange();
177
+ return this.startService(spec);
178
+ }
149
179
  getServices() {
150
180
  return Array.from(this.services.values());
151
181
  }
@@ -1923,6 +1953,7 @@ function buildWorkerpalSandboxPaths(runtimeRoot) {
1923
1953
  dockerfilePath: join2(root, "apps", "workerpals", "Dockerfile.sandbox"),
1924
1954
  packageJsonPath: join2(root, "package.json"),
1925
1955
  workerpalsDir: join2(root, "apps", "workerpals"),
1956
+ remotebuddyFallbackBundlePath: join2(root, ".pushpals-remotebuddy-fallback.js"),
1926
1957
  sharedDir: join2(root, "packages", "shared"),
1927
1958
  protocolDir: join2(root, "packages", "protocol"),
1928
1959
  configsDir: join2(root, "configs"),
@@ -2558,6 +2589,9 @@ function readLogTail(logPath, maxLines = 40) {
2558
2589
  return lines.slice(-maxLines).join(`
2559
2590
  `);
2560
2591
  }
2592
+ function hasStandaloneBunCrashSignature(text) {
2593
+ return /\bpanic\(main thread\)|\bsegmentation fault\b|oh no:\s*bun has crashed\b/i.test(String(text ?? ""));
2594
+ }
2561
2595
  function extractRemoteBuddyAutonomousEngineState(logText) {
2562
2596
  const text = String(logText ?? "");
2563
2597
  if (!text)
@@ -3966,17 +4000,23 @@ async function autoStartRuntimeServices(opts) {
3966
4000
  }
3967
4001
  }
3968
4002
  });
3969
- const launchService = (name, command) => {
4003
+ const buildManagedServiceSpec = (name, command, launchOpts = {}) => {
4004
+ const cwd = launchOpts.cwd ?? opts.repoRoot;
3970
4005
  const logPath = serviceLogPaths[name];
3971
- const header = `[pushpals] service=${name} command=${command.join(" ")} cwd=${opts.repoRoot}`;
3972
- writeFileSync(logPath, `${header}
4006
+ const header = `[pushpals] service=${name} command=${command.join(" ")} cwd=${cwd}`;
4007
+ if (launchOpts.appendLog && existsSync5(logPath)) {
4008
+ appendFileSync(logPath, `${header}
3973
4009
  `, "utf8");
4010
+ } else {
4011
+ writeFileSync(logPath, `${header}
4012
+ `, "utf8");
4013
+ }
3974
4014
  appendRuntimeServicesLogLine(runtimeServicesLogPath, header);
3975
- return serviceManager.startService({
4015
+ return {
3976
4016
  name,
3977
4017
  color: "",
3978
4018
  command,
3979
- cwd: opts.repoRoot,
4019
+ cwd,
3980
4020
  env: runtimeEnv,
3981
4021
  logPath,
3982
4022
  onStdoutLine: (line) => {
@@ -3991,7 +4031,44 @@ async function autoStartRuntimeServices(opts) {
3991
4031
  `, "utf8");
3992
4032
  appendRuntimeServicesLogLine(runtimeServicesLogPath, `[${name}] ${serviceLine}`);
3993
4033
  }
4034
+ };
4035
+ };
4036
+ const launchService = (name, command, launchOpts) => {
4037
+ return serviceManager.startService(buildManagedServiceSpec(name, command, launchOpts));
4038
+ };
4039
+ const replaceService = (name, command, launchOpts) => {
4040
+ return serviceManager.replaceService(buildManagedServiceSpec(name, command, launchOpts));
4041
+ };
4042
+ const sandboxPaths = buildWorkerpalSandboxPaths(runtimeRoot);
4043
+ const remoteBuddyFallbackBun = process.platform === "win32" ? resolveEmbeddedBunExecutableFromEnv(runtimeEnv, process.platform, process.execPath) : "";
4044
+ const remoteBuddySourceFallback = process.platform === "win32" && remoteBuddyFallbackBun && existsSync5(sandboxPaths.remotebuddyFallbackBundlePath) ? {
4045
+ cwd: sandboxPaths.root,
4046
+ bunBin: remoteBuddyFallbackBun,
4047
+ bundlePath: sandboxPaths.remotebuddyFallbackBundlePath
4048
+ } : null;
4049
+ let remoteBuddyFallbackActivated = false;
4050
+ const maybeActivateRemoteBuddyWindowsFallback = () => {
4051
+ if (remoteBuddyFallbackActivated || !remoteBuddySourceFallback)
4052
+ return false;
4053
+ const tail = readLogTail(serviceLogPaths.remotebuddy, 120);
4054
+ if (!hasStandaloneBunCrashSignature(tail))
4055
+ return false;
4056
+ remoteBuddyFallbackActivated = true;
4057
+ lastReportedRemoteBuddyAutonomyState = "unknown";
4058
+ console.warn("[pushpals] Embedded RemoteBuddy standalone binary crashed on Windows; retrying with source fallback under bun.");
4059
+ appendRuntimeServicesLogLine(runtimeServicesLogPath, "[pushpals] embedded remotebuddy standalone binary crashed on Windows; retrying with source fallback under bun.");
4060
+ replaceService("remotebuddy", [
4061
+ remoteBuddySourceFallback.bunBin,
4062
+ remoteBuddySourceFallback.bundlePath,
4063
+ "--server",
4064
+ opts.serverUrl,
4065
+ "--sessionId",
4066
+ opts.sessionId
4067
+ ], {
4068
+ cwd: remoteBuddySourceFallback.cwd,
4069
+ appendLog: true
3994
4070
  });
4071
+ return true;
3995
4072
  };
3996
4073
  const serverHealthy = await probeServer(opts.serverUrl);
3997
4074
  if (!serverHealthy) {
@@ -4129,6 +4206,10 @@ ${tail}` : ""}`);
4129
4206
  reportRemoteBuddyAutonomousEngineState();
4130
4207
  for (const service of serviceManager.getServices()) {
4131
4208
  if (service.exited) {
4209
+ if (service.name === "remotebuddy" && maybeActivateRemoteBuddyWindowsFallback()) {
4210
+ await Bun.sleep(DEFAULT_RUNTIME_BOOT_POLL_MS);
4211
+ continue;
4212
+ }
4132
4213
  if (isOptionalEmbeddedService(service.name)) {
4133
4214
  const runtimeServiceName2 = service.name;
4134
4215
  const serviceLogPath2 = service.logPath ?? serviceLogPaths[runtimeServiceName2];
@@ -4168,6 +4249,10 @@ ${tail}` : ""}`);
4168
4249
  for (const service of serviceManager.getServices()) {
4169
4250
  if (!service.exited)
4170
4251
  continue;
4252
+ if (service.name === "remotebuddy" && maybeActivateRemoteBuddyWindowsFallback()) {
4253
+ await Bun.sleep(250);
4254
+ continue;
4255
+ }
4171
4256
  if (isOptionalEmbeddedService(service.name)) {
4172
4257
  const runtimeServiceName2 = service.name;
4173
4258
  const serviceLogPath2 = service.logPath ?? serviceLogPaths[runtimeServiceName2];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushpalsdev/cli",
3
- "version": "1.0.57",
3
+ "version": "1.0.60",
4
4
  "description": "PushPals terminal CLI for LocalBuddy -> RemoteBuddy orchestration",
5
5
  "license": "MIT",
6
6
  "repository": {