Files
claude-mem/src/hooks/user-message-hook.ts
T

117 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* User Message Hook - SessionStart
* Displays context information to the user via stderr
*
* This hook runs in parallel with context-hook to show users what context
* has been loaded into their session. Uses stderr as the communication channel
* since it's currently the only way to display messages in Claude Code UI.
*/
import { join, basename } from "path";
import { homedir } from "os";
import { existsSync } from "fs";
import { ensureWorkerRunning, getWorkerPort } from "../shared/worker-utils.js";
// Check if node_modules exists - if not, this is first run
const pluginDir = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
const nodeModulesPath = join(pluginDir, 'node_modules');
if (!existsSync(nodeModulesPath)) {
// First-time installation - dependencies not yet installed
console.error(`
---
🎉 Note: This appears under Plugin Hook Error, but it's not an error. That's the only option for
user messages in Claude Code UI until a better method is provided.
---
⚠️ Claude-Mem: First-Time Setup
Dependencies have been installed in the background. This only happens once.
💡 TIPS:
• Memories will start generating while you work
• Use /init to write or update your CLAUDE.md for better project context
• Try /clear after one session to see what context looks like
Thank you for installing Claude-Mem!
This message was not added to your startup context, so you can continue working as normal.
`);
process.exit(3);
}
try {
// Ensure worker is running
await ensureWorkerRunning();
const port = getWorkerPort();
const project = basename(process.cwd());
// Fetch formatted context directly from worker API
const response = await fetch(
`http://127.0.0.1:${port}/api/context/inject?project=${encodeURIComponent(project)}&colors=true`,
{ method: 'GET', signal: AbortSignal.timeout(5000) }
);
if (!response.ok) {
throw new Error(`Worker error ${response.status}`);
}
const output = await response.text();
// If it's after Dec 5, 2025 7pm EST, patch this out
const now = new Date();
const amaEndDate = new Date('2025-12-06T00:00:00Z'); // Dec 5, 2025 7pm EST
// Product Hunt launch announcement - expires Dec 5, 2025 12am EST (05:00 UTC)
const phLaunchEndDate = new Date('2025-12-05T05:00:00Z');
let productHuntAnnouncement = "";
if (now < phLaunchEndDate) {
productHuntAnnouncement = `
🚀 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🚀
We launched on Product Hunt!
https://tinyurl.com/claude-mem-ph
⭐ Your upvote means the world - thank you!
🚀 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🚀
`;
}
let amaAnnouncement = "";
if (now < amaEndDate) {
// Check if we're during the live event (Dec 1-5, 5pm-7pm EST daily)
const estOffset = 5 * 60; // EST is UTC-5
const nowUtcMinutes = now.getUTCHours() * 60 + now.getUTCMinutes();
const estHour = Math.floor((nowUtcMinutes - estOffset + 1440) % 1440 / 60);
const day = now.getUTCDate();
const month = now.getUTCMonth();
const year = now.getUTCFullYear();
const isDec1to5 = year === 2025 && month === 11 && day >= 1 && day <= 5;
const isDuringLiveHours = estHour >= 17 && estHour < 19; // 5pm-7pm EST
if (isDec1to5 && isDuringLiveHours) {
amaAnnouncement = "\n 🔴 LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST\n";
} else {
amaAnnouncement = "\n LIVE AMA w/ Dev (@thedotmack) Dec 1st5th, 5pm to 7pm EST\n";
}
}
console.error(
"\n\n📝 Claude-Mem Context Loaded\n" +
" ️ Note: This appears as stderr but is informational only\n\n" +
output +
"\n\n💡 New! Wrap all or part of any message with <private> ... </private> to prevent storing sensitive information in your observation history.\n" +
"\n💬 Community https://discord.gg/J4wttp9vDu" +
productHuntAnnouncement +
amaAnnouncement +
`\n📺 Watch live in browser http://localhost:${port}/\n`
);
} catch (error) {
console.error(`❌ Failed to load context display: ${error}`);
}
process.exit(3);