Skip to content

fix(installer): surface manage.sh stderr when Pulse install fails#1311

Closed
stevetr68 wants to merge 1 commit into
danielmiessler:mainfrom
stevetr68:fix/installpulse-surface-stderr
Closed

fix(installer): surface manage.sh stderr when Pulse install fails#1311
stevetr68 wants to merge 1 commit into
danielmiessler:mainfrom
stevetr68:fix/installpulse-surface-stderr

Conversation

@stevetr68

Copy link
Copy Markdown

Problem

When Pulse fails to install, installPulse() reports a generic message and discards the
real cause. It spawns manage.sh install with stderr piped, but never reads the pipe:

const installOk = await new Promise<boolean>((resolve) => {
  const child = spawn("bash", [manageScript, "install"], {
    cwd: pulseDir,
    stdio: ["ignore", "pipe", "pipe"],   // stderr piped...
  });
  const timer = setTimeout(() => { child.kill(); resolve(false); }, 30000);
  child.on("close", (code) => { clearTimeout(timer); resolve(code === 0); });  // ...but never read
  child.on("error", () => { clearTimeout(timer); resolve(false); });
});

if (!installOk) {
  await emit({ event: "message", content: "Pulse install command failed. Voice notifications will not be available." });
  return false;
}

So a real failure inside manage.sh (missing ~/Library/LaunchAgents, a sed/launchctl
error, etc.) is swallowed — the installer prints "install command failed" with no detail
and the user is left guessing.

Fix

Accumulate the already-piped stderr and include its tail in the failure message. No new
process behavior, no extra spawn — just stop throwing away output we're already capturing.

let installStderr = "";
// ...
child.stderr?.on("data", (chunk) => { installStderr += chunk.toString(); });
// ...
if (!installOk) {
  const tail = installStderr.trim().split("\n").slice(-20).join("\n");
  await emit({ event: "message", content: "Pulse install command failed. Voice notifications will not be available." + (tail ? "\nmanage.sh stderr (last lines):\n" + tail : "") });
  return false;
}

Pairs with #1310 — that fixes one common cause of the silent failure; this makes any
remaining cause visible instead of opaque.

@danielmiessler

Copy link
Copy Markdown
Owner

Hey @stevetr68, thanks for raising this, and sorry it sat for a while.

We're changing how LifeOS ships. Instead of cloning a full ~/.claude directory and running it as a complete system, LifeOS is becoming a skill you install through an agentic installer. The installer hands integration to your own AI, which reads your actual machine (your OS, your paths, your harness) and wires the hooks and system prompt in where they belong.

That's aimed right at what you hit here. The old "one directory, one layout, hope it matches your setup" approach is exactly what broke for so many people, and the new model should handle it far better because your AI does the integration per machine instead of us guessing.

So we're closing this in prep for that release. If it still bites you once the skill-based version is out, reopen or file a fresh one and we'll jump on it. Appreciate you taking the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants