mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-05 00:18:05 +00:00
fix(websearch): stop polluting global ~/.claude/settings.json with hooks
Remove global hook registration from installWebSearchHook() - now only copies hook file to ~/.ccs/hooks/. Hook registration handled by ensureProfileHooks() which writes to per-profile settings. Changes: - hook-installer.ts: Remove ensureHookConfig() call - ccs.ts: Remove redundant installWebSearchHook() call - hook-config.ts: Add getClaudeSettingsPath() for test isolation
This commit is contained in:
@@ -8,7 +8,6 @@ import { ErrorManager } from './utils/error-manager';
|
|||||||
import { execClaudeWithCLIProxy, CLIProxyProvider } from './cliproxy';
|
import { execClaudeWithCLIProxy, CLIProxyProvider } from './cliproxy';
|
||||||
import {
|
import {
|
||||||
ensureMcpWebSearch,
|
ensureMcpWebSearch,
|
||||||
installWebSearchHook,
|
|
||||||
displayWebSearchStatus,
|
displayWebSearchStatus,
|
||||||
getWebSearchHookEnv,
|
getWebSearchHookEnv,
|
||||||
ensureProfileHooks,
|
ensureProfileHooks,
|
||||||
@@ -549,7 +548,6 @@ async function main(): Promise<void> {
|
|||||||
ensureProfileHooks(profileInfo.name);
|
ensureProfileHooks(profileInfo.name);
|
||||||
|
|
||||||
ensureMcpWebSearch();
|
ensureMcpWebSearch();
|
||||||
installWebSearchHook();
|
|
||||||
|
|
||||||
// Display WebSearch status (single line, equilibrium UX)
|
// Display WebSearch status (single line, equilibrium UX)
|
||||||
displayWebSearchStatus();
|
displayWebSearchStatus();
|
||||||
|
|||||||
@@ -13,12 +13,24 @@ import { info, warn } from '../ui';
|
|||||||
import { getWebSearchConfig } from '../../config/unified-config-loader';
|
import { getWebSearchConfig } from '../../config/unified-config-loader';
|
||||||
import { getCcsDir } from '../config-manager';
|
import { getCcsDir } from '../config-manager';
|
||||||
|
|
||||||
// Path to Claude settings.json (intentionally uses real homedir for global settings)
|
|
||||||
const CLAUDE_SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json');
|
|
||||||
|
|
||||||
// Hook file name
|
// Hook file name
|
||||||
const WEBSEARCH_HOOK = 'websearch-transformer.cjs';
|
const WEBSEARCH_HOOK = 'websearch-transformer.cjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Claude settings path (respects CCS_HOME for test isolation)
|
||||||
|
* In tests, returns path under CCS_HOME; in production, uses real ~/.claude/
|
||||||
|
*/
|
||||||
|
function getClaudeSettingsPath(): string {
|
||||||
|
const ccsHome = process.env.CCS_HOME;
|
||||||
|
if (ccsHome) {
|
||||||
|
// Test mode: use CCS_HOME parent for .claude directory
|
||||||
|
// This prevents tests from modifying user's real settings
|
||||||
|
return path.join(path.dirname(ccsHome), '.claude', 'settings.json');
|
||||||
|
}
|
||||||
|
// Production: use real home directory
|
||||||
|
return path.join(os.homedir(), '.claude', 'settings.json');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get CCS hooks directory (respects CCS_HOME for test isolation)
|
* Get CCS hooks directory (respects CCS_HOME for test isolation)
|
||||||
*/
|
*/
|
||||||
@@ -92,9 +104,9 @@ export function ensureHookConfig(): boolean {
|
|||||||
|
|
||||||
// Read existing settings or start fresh
|
// Read existing settings or start fresh
|
||||||
let settings: Record<string, unknown> = {};
|
let settings: Record<string, unknown> = {};
|
||||||
if (fs.existsSync(CLAUDE_SETTINGS_PATH)) {
|
if (fs.existsSync(getClaudeSettingsPath())) {
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf8');
|
const content = fs.readFileSync(getClaudeSettingsPath(), 'utf8');
|
||||||
settings = JSON.parse(content);
|
settings = JSON.parse(content);
|
||||||
} catch {
|
} catch {
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
@@ -136,7 +148,7 @@ export function ensureHookConfig(): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needsUpdate) {
|
if (needsUpdate) {
|
||||||
fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf8');
|
fs.writeFileSync(getClaudeSettingsPath(), JSON.stringify(settings, null, 2), 'utf8');
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
console.error(info('Updated WebSearch hook config in settings.json'));
|
console.error(info('Updated WebSearch hook config in settings.json'));
|
||||||
}
|
}
|
||||||
@@ -163,13 +175,13 @@ export function ensureHookConfig(): boolean {
|
|||||||
settingsHooks.PreToolUse.push(...preToolUseHooks);
|
settingsHooks.PreToolUse.push(...preToolUseHooks);
|
||||||
|
|
||||||
// Ensure ~/.claude directory exists
|
// Ensure ~/.claude directory exists
|
||||||
const claudeDir = path.dirname(CLAUDE_SETTINGS_PATH);
|
const claudeDir = path.dirname(getClaudeSettingsPath());
|
||||||
if (!fs.existsSync(claudeDir)) {
|
if (!fs.existsSync(claudeDir)) {
|
||||||
fs.mkdirSync(claudeDir, { recursive: true, mode: 0o700 });
|
fs.mkdirSync(claudeDir, { recursive: true, mode: 0o700 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write updated settings
|
// Write updated settings
|
||||||
fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf8');
|
fs.writeFileSync(getClaudeSettingsPath(), JSON.stringify(settings, null, 2), 'utf8');
|
||||||
|
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
console.error(info('Added WebSearch hook to settings.json'));
|
console.error(info('Added WebSearch hook to settings.json'));
|
||||||
@@ -191,11 +203,11 @@ export function ensureHookConfig(): boolean {
|
|||||||
*/
|
*/
|
||||||
export function removeHookConfig(): boolean {
|
export function removeHookConfig(): boolean {
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(CLAUDE_SETTINGS_PATH)) {
|
if (!fs.existsSync(getClaudeSettingsPath())) {
|
||||||
return true; // Nothing to remove
|
return true; // Nothing to remove
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf8');
|
const content = fs.readFileSync(getClaudeSettingsPath(), 'utf8');
|
||||||
let settings: Record<string, unknown>;
|
let settings: Record<string, unknown>;
|
||||||
try {
|
try {
|
||||||
settings = JSON.parse(content);
|
settings = JSON.parse(content);
|
||||||
@@ -232,7 +244,7 @@ export function removeHookConfig(): boolean {
|
|||||||
delete settings.hooks;
|
delete settings.hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf8');
|
fs.writeFileSync(getClaudeSettingsPath(), JSON.stringify(settings, null, 2), 'utf8');
|
||||||
|
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
console.error(info('Removed WebSearch hook from settings.json'));
|
console.error(info('Removed WebSearch hook from settings.json'));
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as fs from 'fs';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { info, warn } from '../ui';
|
import { info, warn } from '../ui';
|
||||||
import { getWebSearchConfig } from '../../config/unified-config-loader';
|
import { getWebSearchConfig } from '../../config/unified-config-loader';
|
||||||
import { getHookPath, ensureHookConfig, getCcsHooksDir } from './hook-config';
|
import { getHookPath, getCcsHooksDir } from './hook-config';
|
||||||
import { removeMigrationMarker } from './profile-hook-injector';
|
import { removeMigrationMarker } from './profile-hook-injector';
|
||||||
|
|
||||||
// Re-export from hook-config for backward compatibility
|
// Re-export from hook-config for backward compatibility
|
||||||
@@ -85,8 +85,9 @@ export function installWebSearchHook(): boolean {
|
|||||||
console.error(info(`Installed WebSearch hook: ${hookPath}`));
|
console.error(info(`Installed WebSearch hook: ${hookPath}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure hook is configured in settings.json
|
// Note: Hook registration is handled by ensureProfileHooks() in profile-hook-injector.ts
|
||||||
ensureHookConfig();
|
// which writes to per-profile settings (~/.ccs/<profile>.settings.json)
|
||||||
|
// Global settings (~/.claude/settings.json) are NOT modified here
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user