Skip to content
Open
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
22 changes: 22 additions & 0 deletions LifeOS/Tools/InstallEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,28 @@ function normalizeCommand(cmd: string): string {
.trim();
}

/**
* Rewrite the default `~/.claude` config-root spellings inside hook commands to
* the actually-detected configRoot. The payload's hooks.json ships commands
* against the default root (`$HOME/.claude/...`); on a multi-profile setup
* (Claude Code's CLAUDE_CONFIG_DIR) those paths point at a different — usually
* nonexistent — profile, so every hook errors on startup. No-op when configRoot
* IS the default, keeping default installs byte-identical. Pure (no I/O).
*/
export function rewriteHooksConfigRoot(hooks: HooksMap, configRoot: string, homeDir: string): HooksMap {
if (resolve(configRoot) === resolve(join(homeDir, ".claude"))) return hooks;
const defaultRootPattern = /(\$\{HOME\}|\$HOME|~)\/\.claude(?=\/|\s|$)/g;
const rewritten: HooksMap = JSON.parse(JSON.stringify(hooks ?? {}));
for (const groups of Object.values(rewritten)) {
for (const group of groups) {
for (const h of group.hooks ?? []) {
if (typeof h.command === "string") h.command = h.command.replace(defaultRootPattern, configRoot);
}
}
}
return rewritten;
}

/** Identity key for a hook entry: http → url, else normalized command. */
function hookKey(h: HookEntry): string {
if (h.type === "http" && h.url) return `http:${h.url}`;
Expand Down
11 changes: 9 additions & 2 deletions LifeOS/Tools/InstallHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { detectDevTree, mergeHooks } from "./InstallEngine";
import { detectDevTree, mergeHooks, rewriteHooksConfigRoot } from "./InstallEngine";

interface Args { configRoot: string; skillRoot: string; apply: boolean; allowDev: boolean; }

Expand Down Expand Up @@ -59,7 +59,14 @@ function main(): void {
console.log(JSON.stringify({ ok: false, error: `payload hooks.json not found at ${hooksJsonPath}` }, null, 2));
process.exit(1);
}
const incoming = JSON.parse(readFileSync(hooksJsonPath, "utf-8"))?.hooks ?? {};
// Payload commands are written against the default ~/.claude root; retarget
// them at the detected configRoot so non-default CLAUDE_CONFIG_DIR profiles
// get hooks that point at the files this installer actually deploys.
const incoming = rewriteHooksConfigRoot(
JSON.parse(readFileSync(hooksJsonPath, "utf-8"))?.hooks ?? {},
configRoot,
process.env.HOME || "",
);

// The hook SCRIPTS (*.hook.ts|sh + lib/**) live beside hooks.json in the payload.
// Merging hooks.json into settings.json wires commands that point at these files,
Expand Down
16 changes: 14 additions & 2 deletions LifeOS/install/LIFEOS/LIFEOS_StatusLine.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ set -o pipefail
# CONFIGURATION
# ─────────────────────────────────────────────────────────────────────────────

LIFEOS_DIR="${LIFEOS_DIR:-$HOME/.claude/LIFEOS}"
CLAUDE_HOME="$HOME/.claude"
# CLAUDE_CONFIG_DIR is Claude Code's own config-dir override (multi-profile
# setups). Env values arriving from settings.json `env` are NOT shell-expanded
# by the harness, so a LIFEOS_DIR like `$HOME/.claude/LIFEOS` reaches us
# literally. expand_home() resolves the $HOME/${HOME}/~ prefix spellings
# (bash port of the TS helpers' expandPath) — no eval, env values are data.
expand_home() {
local p="$1"
p="${p/#\$HOME/$HOME}"
p="${p/#\$\{HOME\}/$HOME}"
p="${p/#\~/$HOME}"
printf '%s' "$p"
}
CLAUDE_HOME="$(expand_home "${CLAUDE_CONFIG_DIR:-$HOME/.claude}")"
LIFEOS_DIR="$(expand_home "${LIFEOS_DIR:-$CLAUDE_HOME/LIFEOS}")"
SETTINGS_FILE="$CLAUDE_HOME/settings.json"
RATINGS_FILE="$LIFEOS_DIR/MEMORY/LEARNING/SIGNALS/ratings.jsonl"
MODEL_CACHE="$LIFEOS_DIR/MEMORY/STATE/model-cache.txt"
Expand Down
2 changes: 1 addition & 1 deletion LifeOS/install/LIFEOS/PULSE/MenuBar/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ sed "s|__HOME__|$HOME_DIR|g" "$PLIST_SRC" > "$PLIST_DST"
echo " Installed $PLIST_DST"

# Ensure logs directory exists
mkdir -p "$HOME_DIR/.claude/LIFEOS/PULSE/logs"
mkdir -p "${CLAUDE_CONFIG_DIR:-$HOME_DIR/.claude}/LIFEOS/PULSE/logs"

launchctl load "$PLIST_DST"
echo " Loaded $PLIST_LABEL"
Expand Down
9 changes: 5 additions & 4 deletions LifeOS/install/LIFEOS/PULSE/Observability/observability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { join, extname } from "path"
import { readFileSync, readdirSync, existsSync, realpathSync, statSync, watch, type FSWatcher } from "fs"
import YAML from "yaml"
import { effortToCanonicalTierName } from "../../../hooks/lib/effort"
import { getClaudeDir } from "../../TOOLS/Paths";
// Growth is an OPTIONAL USER customization (USER/CUSTOMIZATIONS/TOOLS/Growth.ts): present on the
// principal's machine, absent on fresh installs (private code, not shipped). It is loaded via a
// guarded dynamic import in handleLifeGrowth so the Pulse server boots without it. A static import
Expand Down Expand Up @@ -55,7 +56,7 @@ export interface ObservabilityConfig {
// ── Path Construction ──

const HOME = process.env.HOME ?? ""
const LIFEOS_DIR = join(HOME, ".claude", "LIFEOS")
const LIFEOS_DIR = join(getClaudeDir(), "LIFEOS")
const MEMORY_DIR = join(LIFEOS_DIR, "MEMORY")

const WORK_JSON_PATH = join(MEMORY_DIR, "STATE", "work.json")
Expand All @@ -64,7 +65,7 @@ const SUBAGENT_EVENTS_PATH = join(MEMORY_DIR, "OBSERVABILITY", "subagent-events.
const VOICE_EVENTS_PATH = join(MEMORY_DIR, "VOICE", "voice-events.jsonl")
const TOOL_FAILURES_PATH = join(MEMORY_DIR, "OBSERVABILITY", "tool-failures.jsonl")
const TOOL_ACTIVITY_PATH = join(MEMORY_DIR, "OBSERVABILITY", "tool-activity.jsonl")
const SETTINGS_PATH = join(HOME, ".claude", "settings.json")
const SETTINGS_PATH = join(getClaudeDir(), "settings.json")
const LADDER_DIR = join(HOME, "Projects", "Ladder")

const DEFAULT_DASHBOARD_DIR = join(LIFEOS_DIR, "PULSE", "Observability", "out")
Expand Down Expand Up @@ -142,7 +143,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", "LIFEOS", "PULSE", dir)
return join(getClaudeDir(), "LIFEOS", "PULSE", dir)
}
return dir
}
Expand Down Expand Up @@ -1626,7 +1627,7 @@ function readDirMdFiles(dir: string): { name: string, content: string, sections:

function handleUserIndexApi(filter: string | null): Response {
try {
const LIFEOS_DIR = process.env.LIFEOS_DIR || join(process.env.HOME || "", ".claude", "LIFEOS")
const LIFEOS_DIR = process.env.LIFEOS_DIR || join(getClaudeDir(), "LIFEOS")
const indexPath = join(LIFEOS_DIR, "PULSE", "state", "user-index.json")
const raw = Bun.file(indexPath)
if (!raw.size) {
Expand Down
5 changes: 3 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/Performance/cost-aggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@

import { join, basename, dirname } from "path"
import { existsSync, readFileSync, writeFileSync, appendFileSync, readdirSync, statSync, mkdirSync } from "fs"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const LIFEOS_DIR = join(HOME, ".claude", "LIFEOS")
const PROJECTS_DIR = join(HOME, ".claude", "projects")
const LIFEOS_DIR = join(getClaudeDir(), "LIFEOS")
const PROJECTS_DIR = join(getClaudeDir(), "projects")
const OUTPUT_FILE = join(LIFEOS_DIR, "MEMORY", "OBSERVABILITY", "session-costs.jsonl")
const STATE_FILE = join(LIFEOS_DIR, "PULSE", "Performance", "aggregator-state.json")

Expand Down
5 changes: 3 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/Performance/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@

import { join } from "path"
import { existsSync, readFileSync } from "fs"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const LIFEOS_DIR = join(HOME, ".claude", "LIFEOS")
const LIFEOS_DIR = join(getClaudeDir(), "LIFEOS")
const MEMORY_DIR = join(LIFEOS_DIR, "MEMORY")
const SESSION_COSTS_PATH = join(MEMORY_DIR, "OBSERVABILITY", "session-costs.jsonl")
const TOOL_FAILURES_PATH = join(MEMORY_DIR, "OBSERVABILITY", "tool-failures.jsonl")
Expand Down Expand Up @@ -278,7 +279,7 @@ async function handleAnthropicCostApi(): Promise<Response> {
const { readFileSync, existsSync } = await import("fs")
const { join } = await import("path")
const home = process.env.HOME ?? ""
const obsDir = join(home, ".claude", "LIFEOS", "MEMORY", "OBSERVABILITY")
const obsDir = join(getClaudeDir(), "LIFEOS", "MEMORY", "OBSERVABILITY")
const ledgerPath = join(obsDir, "anthropic-cost.jsonl")
const sitesPath = join(obsDir, "anthropic-call-sites.json")

Expand Down
3 changes: 2 additions & 1 deletion LifeOS/install/LIFEOS/PULSE/Tools/ReleaseAudit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { readdirSync, statSync, readFileSync, existsSync } from "node:fs";
import { resolve, join, relative } from "node:path";
import { homedir } from "node:os";
import { parseFrontmatter } from "../lib/frontmatter";
import { getLifeosDir } from "../../TOOLS/Paths";

const args = process.argv.slice(2);
const stagingArg = args.find((a) => !a.startsWith("--"));
Expand Down Expand Up @@ -34,7 +35,7 @@ function loadProhibitedStrings(): string[] {
const candidates = [
process.env.LIFEOS_RELEASE_AUDIT_STRINGS,
join(homedir(), ".config/LIFEOS/USER/CONFIG/release-audit-strings.json"),
join(homedir(), ".claude/LIFEOS/USER/CONFIG/release-audit-strings.json"),
join(getLifeosDir(), "USER/CONFIG/release-audit-strings.json"),
].filter(Boolean) as string[];
for (const p of candidates) {
try {
Expand Down
6 changes: 3 additions & 3 deletions LifeOS/install/LIFEOS/PULSE/Tools/SnapshotFromFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { resolve, join, basename } from "node:path";
import { renderShell, renderPage } from "../ui/render";
import type { PageData } from "../Schema/PulseSchema";
import { PageDataSchema } from "../Schema/PulseSchema";
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME!;
const FIX_DIR = resolve(HOME, ".claude", "LIFEOS", "PULSE", "Schema", "Fixtures");
const OUT_DIR = resolve(HOME, ".claude", "LIFEOS", "PULSE", "Schema", "Snapshots");
const FIX_DIR = resolve(getClaudeDir(), "LIFEOS", "PULSE", "Schema", "Fixtures");
const OUT_DIR = resolve(getClaudeDir(), "LIFEOS", "PULSE", "Schema", "Snapshots");
mkdirSync(OUT_DIR, { recursive: true });

const fixtures = readdirSync(FIX_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("invalid"));
Expand Down
4 changes: 2 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/Tools/SnapshotPages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { readFileSync, existsSync } from "node:fs";
import { renderShell, renderPage, renderEmpty } from "../ui/render";
import { readIndex, readPage } from "../lib/data-plane";
import { loadAllManifests } from "../lib/manifest-loader";
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME!;
const SNAP_DIR = resolve(HOME, ".claude", "LIFEOS", "PULSE", "Schema", "Snapshots");
const SNAP_DIR = resolve(getClaudeDir(), "LIFEOS", "PULSE", "Schema", "Snapshots");
mkdirSync(SNAP_DIR, { recursive: true });

const idx = readIndex();
Expand Down
7 changes: 4 additions & 3 deletions LifeOS/install/LIFEOS/PULSE/VoiceServer/voice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { join } from "path"
import { existsSync, readFileSync } from "fs"
import { log } from "../lib"
import { disambiguateHomographs } from "../lib/homographs"
import { getClaudeDir } from "../../TOOLS/Paths";

// ── Public Config Interface ──

Expand Down Expand Up @@ -163,7 +164,7 @@ function escapeRegex(str: string): string {
}

function loadPronunciations(customPath?: string): void {
const paiDir = join(process.env.HOME ?? "~", ".claude", "LIFEOS")
const paiDir = join(getClaudeDir(), "LIFEOS")
const userPronPath = customPath ?? join(paiDir, "USER", "PRINCIPAL", "PRONUNCIATIONS.json")

try {
Expand Down Expand Up @@ -196,7 +197,7 @@ function applyPronunciations(text: string): string {
// ── Voice Config from settings.json ──

function loadVoiceConfigFromSettings(): LoadedVoiceConfig {
const settingsPath = join(process.env.HOME ?? "~", ".claude", "settings.json")
const settingsPath = join(getClaudeDir(), "settings.json")

try {
if (!existsSync(settingsPath)) {
Expand Down Expand Up @@ -655,7 +656,7 @@ export async function handleVoiceRequest(req: Request): Promise<Response | null>
// /notify/personality honest with whatever the user last selected.
let voiceId: string | null = null
try {
const settingsFile = join(process.env.HOME ?? "~", ".claude", "settings.json")
const settingsFile = join(getClaudeDir(), "settings.json")
const settings = JSON.parse(readFileSync(settingsFile, "utf-8"))
const main = settings?.daidentity?.voices?.main
const vid = (main?.voiceId || main?.VOICE_ID || main?.voice_id) as string | undefined
Expand Down
4 changes: 2 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/adapters/AdapterRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { hashFile, combineSourceHashes } from "../lib/cache";
import { writePage, writeError, clearError, readMeta, type DataPlaneFile, PULSE_DATA_DIR } from "../lib/data-plane";
import { getProvenance } from "../lib/frontmatter";
import { inference, type InferenceLevel } from "../../TOOLS/Inference";
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME!;
const OBSERVABILITY_DIR = resolve(HOME, ".claude", "LIFEOS", "MEMORY", "OBSERVABILITY");
const OBSERVABILITY_DIR = resolve(getClaudeDir(), "LIFEOS", "MEMORY", "OBSERVABILITY");
const RUNS_LOG = join(OBSERVABILITY_DIR, "adapter-runs.jsonl");

const ADAPTER_TIMEOUT_MS = 120_000;
Expand Down
5 changes: 3 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/checks/airgradient-poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@

import { join } from "node:path"
import { mkdirSync, writeFileSync, appendFileSync, readFileSync, existsSync } from "node:fs"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const CACHE_DIR = join(HOME, ".claude", "LIFEOS", "MEMORY", "_AIRGRADIENT")
const CACHE_DIR = join(getClaudeDir(), "LIFEOS", "MEMORY", "_AIRGRADIENT")
const LATEST = join(CACHE_DIR, "latest.json")
const HISTORY = join(CACHE_DIR, "history.jsonl")

Expand All @@ -23,7 +24,7 @@ const API_BASE = "https://api.airgradient.com/public/api/v1"
// Bun auto-loads .env from CWD only; Pulse cron runs from LIFEOS/PULSE/, so the
// symlink at ~/.claude/.env isn't picked up. Read it directly if env is empty.
function loadTokenFromDotenv(): string | null {
const envPath = join(HOME, ".claude", ".env")
const envPath = join(getClaudeDir(), ".env")
if (!existsSync(envPath)) return null
try {
const raw = readFileSync(envPath, "utf8")
Expand Down
3 changes: 2 additions & 1 deletion LifeOS/install/LIFEOS/PULSE/checks/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@

import { readFileSync } from "fs"
import { join } from "path"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const LOOKAHEAD_MS = 30 * 60 * 1000

function loadEnv(): Record<string, string> {
const env: Record<string, string> = {}
try {
const content = readFileSync(join(HOME, ".claude", ".env"), "utf-8")
const content = readFileSync(join(getClaudeDir(), ".env"), "utf-8")
for (const line of content.split("\n")) {
const match = line.match(/^([^#=]+)=(.*)$/)
if (match) {
Expand Down
3 changes: 2 additions & 1 deletion LifeOS/install/LIFEOS/PULSE/checks/github-work.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { join } from "path"
import { readFileSync } from "fs"
import { parse } from "smol-toml"
import { SignJWT, importPKCS8 } from "jose"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const PULSE_DIR = join(HOME, ".claude", "LIFEOS", "PULSE")
const PULSE_DIR = join(getClaudeDir(), "LIFEOS", "PULSE")
const STATE_FILE = join(PULSE_DIR, "state", "work-token.json")

// ── Worker Config (from PULSE.toml [worker] section) ──
Expand Down
5 changes: 3 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/checks/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@

import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs"
import { dirname, join } from "path"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const LEGACY_STATE_FILE = join(HOME, ".claude", "LIFEOS", "PULSE", "state", "github-seen.json")
const STATE_FILE = join(HOME, ".claude", "LIFEOS", "PULSE", "state", "github-seen.jsonl")
const LEGACY_STATE_FILE = join(getClaudeDir(), "LIFEOS", "PULSE", "state", "github-seen.json")
const STATE_FILE = join(getClaudeDir(), "LIFEOS", "PULSE", "state", "github-seen.jsonl")
// Repos to monitor for new issues / activity. Override via LIFEOS_PULSE_REPOS
// env var (comma-separated "owner/name" pairs). Empty default keeps fresh
// installs from polling repos the user hasn't opted into.
Expand Down
3 changes: 2 additions & 1 deletion LifeOS/install/LIFEOS/PULSE/checks/life-morning-brief.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@

import { join } from "path"
import { existsSync, readFileSync } from "fs"
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME ?? ""
const TELOS_DIR = join(HOME, ".claude", "LIFEOS", "USER", "TELOS")
const TELOS_DIR = join(getClaudeDir(), "LIFEOS", "USER", "TELOS")

function readFile(name: string): string {
const p = join(TELOS_DIR, name)
Expand Down
4 changes: 2 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/checks/notification-governor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } from "fs";
import { join, dirname } from "path";
import { createHash } from "crypto";
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME || "";
const LIFEOS_DIR = process.env.LIFEOS_DIR || join(HOME, ".claude", "LIFEOS");
const LIFEOS_DIR = process.env.LIFEOS_DIR || join(getClaudeDir(), "LIFEOS");
const STATE_FILE = join(LIFEOS_DIR, "PULSE", "state", "notification-governor.json");
const LOG_FILE = join(LIFEOS_DIR, "MEMORY", "OBSERVABILITY", "notification-governor.jsonl");
const NOTIFY_URL = "http://localhost:31337/notify";
Expand Down
4 changes: 2 additions & 2 deletions LifeOS/install/LIFEOS/PULSE/checks/poller-meta-monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

import { readFileSync, existsSync } from "fs";
import { join } from "path";
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME || "";
const LIFEOS_DIR = process.env.LIFEOS_DIR || join(HOME, ".claude", "LIFEOS");
const LIFEOS_DIR = process.env.LIFEOS_DIR || join(getClaudeDir(), "LIFEOS");
const PULSE_STATE = join(LIFEOS_DIR, "PULSE", "state", "state.json");
const PULSE_TOML = join(LIFEOS_DIR, "PULSE", "PULSE.toml");

Expand Down
8 changes: 4 additions & 4 deletions LifeOS/install/LIFEOS/PULSE/edit/edit-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { resolve, join } from "node:path";
import { atomicWriteText } from "../lib/atomic-write";
import { parseFrontmatter, serializeFrontmatter } from "../lib/frontmatter";
import { sha256Hex } from "../lib/cache";
import { getClaudeDir } from "../../TOOLS/Paths";

const HOME = process.env.HOME!;
const USER_ROOT = resolve(HOME, ".claude", "LIFEOS", "USER");
const EDITS_LOG = resolve(HOME, ".claude", "LIFEOS", "MEMORY", "OBSERVABILITY", "pulse-edits.jsonl");
const USER_ROOT = resolve(getClaudeDir(), "LIFEOS", "USER");
const EDITS_LOG = resolve(getClaudeDir(), "LIFEOS", "MEMORY", "OBSERVABILITY", "pulse-edits.jsonl");
const CONTAINMENT_PREFIX_DENY = ["MEMORY/PULSE_DATA", "MEMORY/OBSERVABILITY"];

export interface EditRequest {
Expand All @@ -32,7 +32,7 @@ function isInUserTree(absPath: string): boolean {
}

function isContainmentPath(absPath: string): boolean {
const rel = absPath.replace(resolve(HOME, ".claude", "LIFEOS") + "/", "");
const rel = absPath.replace(resolve(getClaudeDir(), "LIFEOS") + "/", "");
return CONTAINMENT_PREFIX_DENY.some((p) => rel.startsWith(p));
}

Expand Down
Loading