Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions PLATFORM.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ This document tracks all platform-specific code and dependencies across PAI, pro
- **Fix:** Updated to reflect Linux is fully supported
- **Status:** Documentation now accurate

6a. ✅ `Pulse` vs `PULSE` directory casing mismatch
- **Files:** `Releases/v5.0.0/.claude/PAI/PULSE/{run-job,lib,setup,pulse-unified}.ts`,
`PULSE/modules/{imessage,user-index}.ts`, `PULSE/Performance/cost-aggregator.ts`,
`PULSE/checks/{notification-governor,poller-meta-monitor,github-work}.ts`,
`PULSE/Observability/observability.ts` (11 files, 14 occurrences)
- **Issue:** Source referenced `~/.claude/PAI/Pulse/...` but directory on disk is `PULSE`. Worked on macOS APFS (case-insensitive default) but broke on Linux ext4 and case-sensitive APFS — config and state lookups silently missed.
- **Fix:** Aligned all `path.join(...)` literals to `"PULSE"`.
- **Tested:** Linux (Ubuntu, runtime-verified). Behavior unchanged on case-insensitive filesystems (macOS default, NTFS).

---

### 📋 ALREADY HANDLED (No Action Needed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) ──

Expand Down Expand Up @@ -149,7 +149,7 @@ 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)
return join(HOME, ".claude", "PAI", "PULSE", dir)
}
return dir
}
Expand Down Expand Up @@ -1647,7 +1647,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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, { input: number; output: number; cacheWrite: number; cacheRead: number }> = {
Expand Down
2 changes: 1 addition & 1 deletion Releases/v5.0.0/.claude/PAI/PULSE/checks/github-work.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) ──
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
2 changes: 1 addition & 1 deletion Releases/v5.0.0/.claude/PAI/PULSE/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
})

Expand Down
4 changes: 2 additions & 2 deletions Releases/v5.0.0/.claude/PAI/PULSE/modules/imessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof setInterval> | null = null
let running = false
Expand Down
2 changes: 1 addition & 1 deletion Releases/v5.0.0/.claude/PAI/PULSE/modules/user-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
2 changes: 1 addition & 1 deletion Releases/v5.0.0/.claude/PAI/PULSE/pulse-unified.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { parse } from "smol-toml"

const HOME = process.env.HOME ?? "~"
const PAI_DIR = join(HOME, ".claude", "PAI")
const PULSE_DIR = join(PAI_DIR, "Pulse")
const PULSE_DIR = join(PAI_DIR, "PULSE")

const envPath = join(HOME, ".claude", ".env")
try {
Expand Down
2 changes: 1 addition & 1 deletion Releases/v5.0.0/.claude/PAI/PULSE/run-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ if (!jobName) {
process.exit(1)
}

const PULSE_DIR = join(process.env.HOME ?? "~", ".claude", "PAI", "Pulse")
const PULSE_DIR = join(process.env.HOME ?? "~", ".claude", "PAI", "PULSE")
const config = await loadConfig(PULSE_DIR)
const job = config.jobs.find((j) => j.name === jobName)
if (!job) {
Expand Down
2 changes: 1 addition & 1 deletion Releases/v5.0.0/.claude/PAI/PULSE/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { existsSync, mkdirSync } from "fs"

const HOME = process.env.HOME ?? "~"
const PAI_DIR = join(HOME, ".claude", "PAI")
const PULSE_DIR = join(PAI_DIR, "Pulse")
const PULSE_DIR = join(PAI_DIR, "PULSE")

// ── Helpers ──

Expand Down