mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
Implement hook token validation to secure session start requests. Each hook server generates a unique token that must be provided in the x-hapi-hook-token header. Updates hook-forwarder command to support both positional and named arguments for port and token.
78 lines
2.3 KiB
TypeScript
78 lines
2.3 KiB
TypeScript
/**
|
|
* Generate temporary settings file with Claude hooks for session tracking.
|
|
*
|
|
* Creates a settings.json file that configures Claude's SessionStart hook
|
|
* to notify our HTTP server when sessions change (new session, resume, compact, etc.).
|
|
*/
|
|
|
|
import { join } from 'node:path';
|
|
import { writeFileSync, mkdirSync, unlinkSync, existsSync } from 'node:fs';
|
|
import { configuration } from '@/configuration';
|
|
import { logger } from '@/ui/logger';
|
|
import { getHappyCliCommand } from '@/utils/spawnHappyCLI';
|
|
|
|
function shellQuote(value: string): string {
|
|
if (value.length === 0) {
|
|
return '""';
|
|
}
|
|
|
|
if (/^[A-Za-z0-9_\/:=-]+$/.test(value)) {
|
|
return value;
|
|
}
|
|
|
|
return '"' + value.replace(/(["\\$`])/g, '\\$1') + '"';
|
|
}
|
|
|
|
function shellJoin(parts: string[]): string {
|
|
return parts.map(shellQuote).join(' ');
|
|
}
|
|
|
|
/**
|
|
* Generate a temporary settings file with SessionStart hook configuration.
|
|
*/
|
|
export function generateHookSettingsFile(port: number, token: string): string {
|
|
const hooksDir = join(configuration.happyHomeDir, 'tmp', 'hooks');
|
|
mkdirSync(hooksDir, { recursive: true });
|
|
|
|
const filename = `session-hook-${process.pid}.json`;
|
|
const filepath = join(hooksDir, filename);
|
|
|
|
const { command, args } = getHappyCliCommand(['hook-forwarder', '--port', String(port), '--token', token]);
|
|
const hookCommand = shellJoin([command, ...args]);
|
|
|
|
const settings = {
|
|
hooks: {
|
|
SessionStart: [
|
|
{
|
|
matcher: '*',
|
|
hooks: [
|
|
{
|
|
type: 'command',
|
|
command: hookCommand
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
writeFileSync(filepath, JSON.stringify(settings, null, 4));
|
|
logger.debug(`[generateHookSettings] Created hook settings file: ${filepath}`);
|
|
|
|
return filepath;
|
|
}
|
|
|
|
/**
|
|
* Clean up the temporary hook settings file.
|
|
*/
|
|
export function cleanupHookSettingsFile(filepath: string): void {
|
|
try {
|
|
if (existsSync(filepath)) {
|
|
unlinkSync(filepath);
|
|
logger.debug(`[generateHookSettings] Cleaned up hook settings file: ${filepath}`);
|
|
}
|
|
} catch (error) {
|
|
logger.debug(`[generateHookSettings] Failed to cleanup hook settings file: ${error}`);
|
|
}
|
|
}
|