Skip to content

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

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

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.
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.

1 participant