numerology/profile-manager.ts
rpriven fd6e171586
Add comprehensive numerology calculator with 10 specialized tools
- Core calculations (Life Path, Expression, Soul Urge, Birthday)
- Advanced numbers (Maturity, Personality, Hidden Passion, Karmic Lessons)
- Timing cycles and optimal days finder
- Compatibility analysis and name optimizer
- Telos integration for personal development
- Professional PDF report generation
- Profile management system
- Security fix: Add .claude/ to .gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 14:00:15 -06:00

153 lines
3.5 KiB
TypeScript

#!/usr/bin/env bun
/**
* Profile Management System
*
* Manages numerology profiles stored in ~/.numerology/profiles/
* Each profile contains name and birthdate for easy reuse across all tools.
*
* Usage:
* import { loadProfile, saveProfile, listProfiles, deleteProfile } from './profile-manager';
*/
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
export interface Profile {
name: string;
birthdate: string;
created: string;
updated: string;
}
const PROFILES_DIR = join(homedir(), '.numerology', 'profiles');
/**
* Ensure profiles directory exists
*/
function ensureProfilesDir(): void {
if (!existsSync(PROFILES_DIR)) {
mkdirSync(PROFILES_DIR, { recursive: true });
}
}
/**
* Generate profile filename from identifier
*/
function getProfilePath(identifier: string): string {
// Sanitize identifier to create safe filename
const safeName = identifier.toLowerCase().replace(/[^a-z0-9-_]/g, '-');
return join(PROFILES_DIR, `${safeName}.json`);
}
/**
* Save a profile
*/
export function saveProfile(identifier: string, name: string, birthdate: string): void {
ensureProfilesDir();
const profilePath = getProfilePath(identifier);
const now = new Date().toISOString();
// Check if profile exists to preserve created date
let created = now;
if (existsSync(profilePath)) {
try {
const existing = JSON.parse(readFileSync(profilePath, 'utf-8')) as Profile;
created = existing.created;
} catch {
// If file is corrupted, use current time
}
}
const profile: Profile = {
name,
birthdate,
created,
updated: now
};
writeFileSync(profilePath, JSON.stringify(profile, null, 2));
}
/**
* Load a profile
*/
export function loadProfile(identifier: string): Profile | null {
const profilePath = getProfilePath(identifier);
if (!existsSync(profilePath)) {
return null;
}
try {
const data = readFileSync(profilePath, 'utf-8');
return JSON.parse(data) as Profile;
} catch (error) {
console.error(`Error reading profile '${identifier}':`, error);
return null;
}
}
/**
* List all profiles
*/
export function listProfiles(): Array<{ identifier: string; profile: Profile }> {
ensureProfilesDir();
const profiles: Array<{ identifier: string; profile: Profile }> = [];
try {
const files = readdirSync(PROFILES_DIR);
for (const file of files) {
if (file.endsWith('.json')) {
const identifier = file.replace('.json', '');
const profile = loadProfile(identifier);
if (profile) {
profiles.push({ identifier, profile });
}
}
}
} catch (error) {
console.error('Error listing profiles:', error);
}
return profiles;
}
/**
* Delete a profile
*/
export function deleteProfile(identifier: string): boolean {
const profilePath = getProfilePath(identifier);
if (!existsSync(profilePath)) {
return false;
}
try {
unlinkSync(profilePath);
return true;
} catch (error) {
console.error(`Error deleting profile '${identifier}':`, error);
return false;
}
}
/**
* Check if a profile exists
*/
export function profileExists(identifier: string): boolean {
return existsSync(getProfilePath(identifier));
}
/**
* Get profile identifier from name (for auto-generation)
*/
export function generateIdentifier(name: string): string {
// Generate identifier from first name
const firstName = name.split(' ')[0];
return firstName.toLowerCase().replace(/[^a-z0-9]/g, '');
}