Skip to content

fix(pulse): cross-platform Windows + case-sensitive filesystem compatibility#1274

Closed
alexgordon25 wants to merge 1 commit into
danielmiessler:mainfrom
alexgordon25:windows-cross-platform-fixes
Closed

fix(pulse): cross-platform Windows + case-sensitive filesystem compatibility#1274
alexgordon25 wants to merge 1 commit into
danielmiessler:mainfrom
alexgordon25:windows-cross-platform-fixes

Conversation

@alexgordon25

Copy link
Copy Markdown

@

Summary

Two minor cross-platform fixes surfaced while running PAI v5.0.0 on Windows 11 (Pulse as a Windows service under NSSM). Both also help case-sensitive Linux / case-sensitive macOS filesystems.

Fix 1 — PulsePULSE directory casing (11 occurrences, 8 files)

Directory on disk is PAI/PULSE/ (uppercase), but several modules reference it as PAI/Pulse/ (lowercase). Works on case-insensitive Windows NTFS / macOS HFS+ default, fails silently on case-sensitive Linux and APFS-case-sensitive Mac. In particular getDashboardDir() in observability.ts resolved to a missing path, producing 404 at the dashboard root.

Files touched:

  • Observability/observability.ts (×3)
  • Performance/cost-aggregator.ts
  • checks/github-work.ts
  • checks/notification-governor.ts
  • checks/poller-meta-monitor.ts (×2)
  • lib.ts
  • modules/imessage.ts (×2)
  • modules/user-index.ts

Fix 2 — path.isAbsolute() for Windows path detection

getDashboardDir() in Observability/observability.ts used dir.startsWith("/") to detect absolute paths. POSIX-only — Windows absolute paths begin with a drive letter (C:\…). Replaced with path.isAbsolute() which handles both.

Testing

Both patches running in production on a Windows 11 desktop install for ~6 days under NSSM (PaiPulse service). Dashboard at localhost:31337/ serves all routes; cron jobs run clean; cloud-sync events continue posting.

Scope

PR intentionally excludes identical occurrences in standalone scripts not imported from the live daemon (pulse-old.ts, pulse-unified.ts, run-job.ts, setup.ts). Happy to extend if you would like the sweep to include them.

Diff stats

8 files changed, +17 / −15. No new dependencies. No behavior change on case-insensitive filesystems.
@

PAI Pulse references its own directory as both "Pulse" (in code) and
"PULSE" (on disk). On case-insensitive filesystems (Windows NTFS, macOS
HFS+/APFS in default config) this is invisible, but on Linux and any
case-sensitive macOS volume every join(..., "Pulse", ...) resolves to a
non-existent path — silently returning 404s, broken state files, and
empty cron job state.

The Observability dashboard root path also fails to detect Windows
absolute paths because it uses startsWith("/") instead of
path.isAbsolute(), so configuring a dashboard_dir like
"C:\Users\me\dashboard" on Windows joins it onto HOME instead of
treating it as absolute.

Both issues hit me when porting Pulse to Windows 11 last weekend.
Patches are minimal — string-literal swap and one stdlib swap.

Changes:
- 8 "Pulse" -> "PULSE" in active code paths
  (Observability/observability.ts x3, checks/github-work.ts,
   checks/notification-governor.ts, checks/poller-meta-monitor.ts x2,
   lib.ts, modules/imessage.ts x2, modules/user-index.ts,
   Performance/cost-aggregator.ts)
- 1 startsWith("/") -> isAbsolute() in observability.ts getDashboardDir
- Add path.isAbsolute import

Verified on Windows 11 with NSSM-managed Pulse service: dashboard now
loads at localhost:31337, all 4 cron jobs (healthcheck, airgradient-poll,
cost-aggregation, cost-tracker) execute successfully against the new
PULSE-cased state paths.

Scope intentionally excludes pulse-old.ts, pulse-unified.ts, run-job.ts,
setup.ts — none are imported from the live daemon and you may have
separate plans for those.
@danielmiessler

Copy link
Copy Markdown
Owner

Hey @alexgordon25, 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