diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/Observability/observability.ts b/Releases/v5.0.0/.claude/PAI/PULSE/Observability/observability.ts index 984c1b4486..0718699c7b 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/Observability/observability.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/Observability/observability.ts @@ -24,7 +24,7 @@ * GET /, /work, /telos, /health, etc. — Static Next.js pages (fallback handler) */ -import { join, extname } from "path" +import { join, extname, isAbsolute } from "path" import { readFileSync, readdirSync, existsSync, realpathSync } from "fs" import YAML from "yaml" @@ -66,7 +66,7 @@ const SECURITY_LOG_DIR = join(MEMORY_DIR, "SECURITY") const SETTINGS_PATH = join(HOME, ".claude", "settings.json") const LADDER_DIR = join(HOME, "Projects", "Ladder") -const DEFAULT_DASHBOARD_DIR = join(PAI_DIR, "Pulse", "Observability", "out") +const DEFAULT_DASHBOARD_DIR = join(PAI_DIR, "PULSE", "Observability", "out") // ── In-Memory Store (hook-pushed state/events) ── @@ -147,9 +147,11 @@ function existsSafe(path: string): boolean { function getDashboardDir(): string { const dir = config.dashboard_dir ?? DEFAULT_DASHBOARD_DIR - // Resolve relative paths against Pulse directory - if (!dir.startsWith("/")) { - return join(HOME, ".claude", "PAI", "Pulse", dir) + // Resolve relative paths against the Pulse directory. + // Use path.isAbsolute() so Windows absolute paths (C:\..., D:\...) are + // detected correctly — startsWith("/") only matches POSIX absolute paths. + if (!isAbsolute(dir)) { + return join(HOME, ".claude", "PAI", "PULSE", dir) } return dir } @@ -1647,7 +1649,7 @@ function readDirMdFiles(dir: string): { name: string, content: string, sections: function handleUserIndexApi(filter: string | null): Response { try { const PAI_DIR = process.env.PAI_DIR || join(process.env.HOME || "", ".claude", "PAI") - const indexPath = join(PAI_DIR, "Pulse", "state", "user-index.json") + const indexPath = join(PAI_DIR, "PULSE", "state", "user-index.json") const raw = Bun.file(indexPath) if (!raw.size) { return Response.json( diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/Performance/cost-aggregator.ts b/Releases/v5.0.0/.claude/PAI/PULSE/Performance/cost-aggregator.ts index f6c5af5ce0..727620fab6 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/Performance/cost-aggregator.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/Performance/cost-aggregator.ts @@ -17,7 +17,7 @@ const HOME = process.env.HOME ?? "" const PAI_DIR = join(HOME, ".claude", "PAI") const PROJECTS_DIR = join(HOME, ".claude", "projects") const OUTPUT_FILE = join(PAI_DIR, "MEMORY", "OBSERVABILITY", "session-costs.jsonl") -const STATE_FILE = join(PAI_DIR, "Pulse", "Performance", "aggregator-state.json") +const STATE_FILE = join(PAI_DIR, "PULSE", "Performance", "aggregator-state.json") // Model pricing per million tokens (as of 2026-04) const MODEL_PRICING: Record = { diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/checks/github-work.ts b/Releases/v5.0.0/.claude/PAI/PULSE/checks/github-work.ts index 78782f17d7..79ad449534 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/checks/github-work.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/checks/github-work.ts @@ -14,7 +14,7 @@ import { parse } from "smol-toml" import { SignJWT, importPKCS8 } from "jose" const HOME = process.env.HOME ?? "" -const PULSE_DIR = join(HOME, ".claude", "PAI", "Pulse") +const PULSE_DIR = join(HOME, ".claude", "PAI", "PULSE") const STATE_FILE = join(PULSE_DIR, "state", "work-token.json") // ── Worker Config (from PULSE.toml [worker] section) ── diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/checks/notification-governor.ts b/Releases/v5.0.0/.claude/PAI/PULSE/checks/notification-governor.ts index fb1a62ea36..6947efa481 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/checks/notification-governor.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/checks/notification-governor.ts @@ -34,7 +34,7 @@ import { createHash } from "crypto"; const HOME = process.env.HOME || ""; const PAI_DIR = process.env.PAI_DIR || join(HOME, ".claude", "PAI"); -const STATE_FILE = join(PAI_DIR, "Pulse", "state", "notification-governor.json"); +const STATE_FILE = join(PAI_DIR, "PULSE", "state", "notification-governor.json"); const LOG_FILE = join(PAI_DIR, "MEMORY", "OBSERVABILITY", "notification-governor.jsonl"); const NOTIFY_URL = "http://localhost:31337/notify"; const VOICE_ID = "fTtv3eikoepIosk8dTZ5"; diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/checks/poller-meta-monitor.ts b/Releases/v5.0.0/.claude/PAI/PULSE/checks/poller-meta-monitor.ts index 5ca27d1c6d..7340c80547 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/checks/poller-meta-monitor.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/checks/poller-meta-monitor.ts @@ -20,8 +20,8 @@ import { join } from "path"; const HOME = process.env.HOME || ""; const PAI_DIR = process.env.PAI_DIR || join(HOME, ".claude", "PAI"); -const PULSE_STATE = join(PAI_DIR, "Pulse", "state", "state.json"); -const PULSE_TOML = join(PAI_DIR, "Pulse", "PULSE.toml"); +const PULSE_STATE = join(PAI_DIR, "PULSE", "state", "state.json"); +const PULSE_TOML = join(PAI_DIR, "PULSE", "PULSE.toml"); // Jobs we specifically monitor — the Current→Ideal pipeline ones. const WATCHED_JOBS = [ diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/lib.ts b/Releases/v5.0.0/.claude/PAI/PULSE/lib.ts index 93d77fac60..8889825be1 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/lib.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/lib.ts @@ -246,7 +246,7 @@ export async function spawnScript(command: string, timeoutMs = 60_000): Promise< const proc = Bun.spawn(["bash", "-c", command], { stdout: "pipe", stderr: "pipe", - cwd: join(process.env.HOME ?? "~", ".claude", "PAI", "Pulse"), + cwd: join(process.env.HOME ?? "~", ".claude", "PAI", "PULSE"), env: { ...process.env }, }) diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/modules/imessage.ts b/Releases/v5.0.0/.claude/PAI/PULSE/modules/imessage.ts index c6fe58bce2..32e3d3a991 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/modules/imessage.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/modules/imessage.ts @@ -60,8 +60,8 @@ export interface IMessageHealth { const HOME = process.env.HOME ?? "" const CWD = join(HOME, ".claude") -const STATE_DIR = join(HOME, ".claude", "PAI", "Pulse", "state", "imessage") -const LOGS_DIR = join(HOME, ".claude", "PAI", "Pulse", "logs", "imessage") +const STATE_DIR = join(HOME, ".claude", "PAI", "PULSE", "state", "imessage") +const LOGS_DIR = join(HOME, ".claude", "PAI", "PULSE", "logs", "imessage") let pollTimer: ReturnType | null = null let running = false diff --git a/Releases/v5.0.0/.claude/PAI/PULSE/modules/user-index.ts b/Releases/v5.0.0/.claude/PAI/PULSE/modules/user-index.ts index 7ee19c5013..aac3f1ddae 100644 --- a/Releases/v5.0.0/.claude/PAI/PULSE/modules/user-index.ts +++ b/Releases/v5.0.0/.claude/PAI/PULSE/modules/user-index.ts @@ -25,7 +25,7 @@ import { join, relative, basename, dirname } from "path" const HOME = process.env.HOME ?? "" const PAI_DIR = process.env.PAI_DIR || join(HOME, ".claude", "PAI") const USER_DIR = join(PAI_DIR, "USER") -const STATE_DIR = join(PAI_DIR, "Pulse", "state") +const STATE_DIR = join(PAI_DIR, "PULSE", "state") const INDEX_PATH = join(STATE_DIR, "user-index.json") const MODULE_NAME = "user-index"