mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 18:15:48 +00:00
fix(websearch): honor disabled steering per launch
This commit is contained in:
1 parent
09757b418e
commit
abc3002e89
18 files changed
+165
-76
No files matched your search
@@ -15,6 +15,7 @@ import {
|
|||||||
appendThirdPartyWebSearchToolArgs,
|
appendThirdPartyWebSearchToolArgs,
|
||||||
createWebSearchTraceContext,
|
createWebSearchTraceContext,
|
||||||
} from '../../utils/websearch-manager';
|
} from '../../utils/websearch-manager';
|
||||||
|
import type { WebSearchLaunchState } from '../../utils/websearch-manager';
|
||||||
import { appendThirdPartyImageAnalysisToolArgs } from '../../utils/image-analysis';
|
import { appendThirdPartyImageAnalysisToolArgs } from '../../utils/image-analysis';
|
||||||
import { appendBrowserToolArgs } from '../../utils/browser';
|
import { appendBrowserToolArgs } from '../../utils/browser';
|
||||||
import { getDefaultAccount } from '../accounts/account-manager';
|
import { getDefaultAccount } from '../accounts/account-manager';
|
||||||
@@ -51,6 +52,8 @@ export interface ClaudeLaunchContext {
|
|||||||
sessionId: string | undefined;
|
sessionId: string | undefined;
|
||||||
/** Whether image analysis MCP is ready */
|
/** Whether image analysis MCP is ready */
|
||||||
imageAnalysisMcpReady: boolean;
|
imageAnalysisMcpReady: boolean;
|
||||||
|
/** WebSearch state captured when launch provisioning ran */
|
||||||
|
webSearchLaunch: WebSearchLaunchState;
|
||||||
/** Browser runtime environment variables (undefined if browser not active) */
|
/** Browser runtime environment variables (undefined if browser not active) */
|
||||||
browserRuntimeEnv: NodeJS.ProcessEnv | undefined;
|
browserRuntimeEnv: NodeJS.ProcessEnv | undefined;
|
||||||
/** Inherited Claude config dir for continuity */
|
/** Inherited Claude config dir for continuity */
|
||||||
@@ -82,6 +85,7 @@ export async function launchClaude(context: ClaudeLaunchContext): Promise<ChildP
|
|||||||
skipLocalAuth,
|
skipLocalAuth,
|
||||||
sessionId,
|
sessionId,
|
||||||
imageAnalysisMcpReady,
|
imageAnalysisMcpReady,
|
||||||
|
webSearchLaunch,
|
||||||
browserRuntimeEnv,
|
browserRuntimeEnv,
|
||||||
inheritedClaudeConfigDir,
|
inheritedClaudeConfigDir,
|
||||||
codexReasoningProxy,
|
codexReasoningProxy,
|
||||||
@@ -124,8 +128,12 @@ export async function launchClaude(context: ClaudeLaunchContext): Promise<ChildP
|
|||||||
? appendBrowserToolArgs(imageAnalysisArgs)
|
? appendBrowserToolArgs(imageAnalysisArgs)
|
||||||
: imageAnalysisArgs;
|
: imageAnalysisArgs;
|
||||||
const launchArgs = isSubcommand
|
const launchArgs = isSubcommand
|
||||||
? appendThirdPartyWebSearchToolArgs(browserArgs)
|
? appendThirdPartyWebSearchToolArgs(browserArgs, webSearchLaunch.enabled)
|
||||||
: ['--settings', settingsPath, ...appendThirdPartyWebSearchToolArgs(browserArgs)];
|
: [
|
||||||
|
'--settings',
|
||||||
|
settingsPath,
|
||||||
|
...appendThirdPartyWebSearchToolArgs(browserArgs, webSearchLaunch.enabled),
|
||||||
|
];
|
||||||
|
|
||||||
// Inject web search trace context into env
|
// Inject web search trace context into env
|
||||||
const traceEnv = createWebSearchTraceContext({
|
const traceEnv = createWebSearchTraceContext({
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import {
|
|||||||
import { applyExtendedContextConfig } from '../config/extended-context-config';
|
import { applyExtendedContextConfig } from '../config/extended-context-config';
|
||||||
import { CLIProxyProvider } from '../types';
|
import { CLIProxyProvider } from '../types';
|
||||||
import { CompositeTierConfig } from '../../config/unified-config-types';
|
import { CompositeTierConfig } from '../../config/unified-config-types';
|
||||||
import { getWebSearchHookEnv } from '../../utils/websearch-manager';
|
|
||||||
import {
|
import {
|
||||||
applyImageAnalysisRuntimeOverrides,
|
applyImageAnalysisRuntimeOverrides,
|
||||||
getImageAnalysisHookEnv,
|
getImageAnalysisHookEnv,
|
||||||
@@ -78,6 +77,8 @@ export interface ProxyChainConfig {
|
|||||||
claudeConfigDir?: string;
|
claudeConfigDir?: string;
|
||||||
/** Execution-aware image analysis env prepared by the caller */
|
/** Execution-aware image analysis env prepared by the caller */
|
||||||
imageAnalysisEnv?: Record<string, string>;
|
imageAnalysisEnv?: Record<string, string>;
|
||||||
|
/** WebSearch hook env captured from the launch configuration snapshot. */
|
||||||
|
webSearchEnv?: Record<string, string>;
|
||||||
/** Optional browser runtime env for Claude browser MCP reuse. */
|
/** Optional browser runtime env for Claude browser MCP reuse. */
|
||||||
browserRuntimeEnv?: Record<string, string>;
|
browserRuntimeEnv?: Record<string, string>;
|
||||||
}
|
}
|
||||||
@@ -246,6 +247,7 @@ export function buildClaudeEnvironment(config: ProxyChainConfig): Record<string,
|
|||||||
compositeDefaultTier,
|
compositeDefaultTier,
|
||||||
claudeConfigDir,
|
claudeConfigDir,
|
||||||
imageAnalysisEnv: resolvedImageAnalysisEnv,
|
imageAnalysisEnv: resolvedImageAnalysisEnv,
|
||||||
|
webSearchEnv = {},
|
||||||
browserRuntimeEnv,
|
browserRuntimeEnv,
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
@@ -386,7 +388,6 @@ export function buildClaudeEnvironment(config: ProxyChainConfig): Record<string,
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add hook environment variables
|
// Add hook environment variables
|
||||||
const webSearchEnv = getWebSearchHookEnv();
|
|
||||||
const imageAnalysisEnv = resolvedImageAnalysisEnv ?? getImageAnalysisHookEnv(provider);
|
const imageAnalysisEnv = resolvedImageAnalysisEnv ?? getImageAnalysisHookEnv(provider);
|
||||||
|
|
||||||
// Merge all environment variables (filter undefined values)
|
// Merge all environment variables (filter undefined values)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ import {
|
|||||||
resolveCliproxyImageAnalysisEnv,
|
resolveCliproxyImageAnalysisEnv,
|
||||||
} from './env-resolver';
|
} from './env-resolver';
|
||||||
import { checkOrJoinProxy, registerProxySession } from './session-bridge';
|
import { checkOrJoinProxy, registerProxySession } from './session-bridge';
|
||||||
import { getWebSearchHookEnv } from '../../utils/websearch-manager';
|
import { resolveWebSearchLaunchState } from '../../utils/websearch-manager';
|
||||||
import {
|
import {
|
||||||
handleLogout,
|
handleLogout,
|
||||||
handleImport,
|
handleImport,
|
||||||
@@ -276,10 +276,9 @@ export async function execClaudeWithCLIProxy(
|
|||||||
await handleImport(authCtx);
|
await handleImport(authCtx);
|
||||||
|
|
||||||
// Setup first-class CCS WebSearch runtime for non-strict user launches.
|
// Setup first-class CCS WebSearch runtime for non-strict user launches.
|
||||||
const shouldDisplayWebSearchStatus = ensureWebSearchMcpForLaunch();
|
const webSearchLaunch = resolveWebSearchLaunchState();
|
||||||
if (shouldDisplayWebSearchStatus) {
|
ensureWebSearchMcpForLaunch(webSearchLaunch.config);
|
||||||
displayWebSearchStatus();
|
displayWebSearchStatus(webSearchLaunch.config);
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Ensure OAuth completed (if provider requires it)
|
// 3. Ensure OAuth completed (if provider requires it)
|
||||||
const remoteAuthToken = proxyConfig.authToken?.trim();
|
const remoteAuthToken = proxyConfig.authToken?.trim();
|
||||||
@@ -483,6 +482,7 @@ export async function execClaudeWithCLIProxy(
|
|||||||
compositeDefaultTier: cfg.compositeDefaultTier,
|
compositeDefaultTier: cfg.compositeDefaultTier,
|
||||||
claudeConfigDir: inheritedClaudeConfigDir,
|
claudeConfigDir: inheritedClaudeConfigDir,
|
||||||
imageAnalysisEnv,
|
imageAnalysisEnv,
|
||||||
|
webSearchEnv: webSearchLaunch.hookEnv,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 9b. Build env-dependent proxy chain (tool-sanitization + codex-reasoning)
|
// 9b. Build env-dependent proxy chain (tool-sanitization + codex-reasoning)
|
||||||
@@ -527,6 +527,7 @@ export async function execClaudeWithCLIProxy(
|
|||||||
compositeDefaultTier: cfg.compositeDefaultTier,
|
compositeDefaultTier: cfg.compositeDefaultTier,
|
||||||
claudeConfigDir: inheritedClaudeConfigDir,
|
claudeConfigDir: inheritedClaudeConfigDir,
|
||||||
imageAnalysisEnv,
|
imageAnalysisEnv,
|
||||||
|
webSearchEnv: webSearchLaunch.hookEnv,
|
||||||
browserRuntimeEnv,
|
browserRuntimeEnv,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -542,7 +543,7 @@ export async function execClaudeWithCLIProxy(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const webSearchEnv = getWebSearchHookEnv();
|
const webSearchEnv = webSearchLaunch.hookEnv;
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
logger.info('browser-env-keys', 'CCS_BROWSER_* keys in environment', {
|
logger.info('browser-env-keys', 'CCS_BROWSER_* keys in environment', {
|
||||||
keys: Object.keys(env)
|
keys: Object.keys(env)
|
||||||
@@ -580,6 +581,7 @@ export async function execClaudeWithCLIProxy(
|
|||||||
skipLocalAuth,
|
skipLocalAuth,
|
||||||
sessionId,
|
sessionId,
|
||||||
imageAnalysisMcpReady,
|
imageAnalysisMcpReady,
|
||||||
|
webSearchLaunch,
|
||||||
browserRuntimeEnv,
|
browserRuntimeEnv,
|
||||||
inheritedClaudeConfigDir,
|
inheritedClaudeConfigDir,
|
||||||
codexReasoningProxy,
|
codexReasoningProxy,
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ import { normalizeCopilotConfigWithWarnings } from './copilot-model-normalizer';
|
|||||||
import { CopilotStatus } from './types';
|
import { CopilotStatus } from './types';
|
||||||
import { fail, info, ok, warn } from '../utils/ui';
|
import { fail, info, ok, warn } from '../utils/ui';
|
||||||
import {
|
import {
|
||||||
getWebSearchHookEnv,
|
|
||||||
appendThirdPartyWebSearchToolArgs,
|
appendThirdPartyWebSearchToolArgs,
|
||||||
createWebSearchTraceContext,
|
createWebSearchTraceContext,
|
||||||
syncWebSearchMcpToConfigDir,
|
syncWebSearchMcpToConfigDir,
|
||||||
} from '../utils/websearch-manager';
|
} from '../utils/websearch-manager';
|
||||||
|
import type { WebSearchLaunchState } from '../utils/websearch-manager';
|
||||||
import {
|
import {
|
||||||
appendThirdPartyImageAnalysisToolArgs,
|
appendThirdPartyImageAnalysisToolArgs,
|
||||||
ensureImageAnalysisMcpOrThrow,
|
ensureImageAnalysisMcpOrThrow,
|
||||||
@@ -71,6 +71,17 @@ export async function getCopilotStatus(config: CopilotConfig): Promise<CopilotSt
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildCopilotClaudeLaunchArgs(
|
||||||
|
claudeArgs: string[],
|
||||||
|
imageAnalysisMcpReady: boolean,
|
||||||
|
webSearchEnabled: boolean
|
||||||
|
): string[] {
|
||||||
|
const imageAnalysisArgs = imageAnalysisMcpReady
|
||||||
|
? appendThirdPartyImageAnalysisToolArgs(claudeArgs)
|
||||||
|
: claudeArgs;
|
||||||
|
return appendThirdPartyWebSearchToolArgs(imageAnalysisArgs, webSearchEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate environment variables for Claude Code to use copilot-api.
|
* Generate environment variables for Claude Code to use copilot-api.
|
||||||
* Uses model mapping for opus/sonnet/haiku tiers if configured.
|
* Uses model mapping for opus/sonnet/haiku tiers if configured.
|
||||||
@@ -185,7 +196,8 @@ export async function executeCopilotProfile(
|
|||||||
config: CopilotConfig,
|
config: CopilotConfig,
|
||||||
claudeArgs: string[],
|
claudeArgs: string[],
|
||||||
claudeConfigDir?: string,
|
claudeConfigDir?: string,
|
||||||
claudeCliPath: string = 'claude'
|
claudeCliPath: string = 'claude',
|
||||||
|
webSearchLaunch?: WebSearchLaunchState
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const { config: normalizedConfig, warnings } = normalizeCopilotConfigWithWarnings(config);
|
const { config: normalizedConfig, warnings } = normalizeCopilotConfigWithWarnings(config);
|
||||||
|
|
||||||
@@ -276,7 +288,7 @@ export async function executeCopilotProfile(
|
|||||||
syncImageAnalysisMcpToConfigDir(claudeConfigDir);
|
syncImageAnalysisMcpToConfigDir(claudeConfigDir);
|
||||||
|
|
||||||
// Merge with current environment (global env first, copilot overrides, then hook env vars)
|
// Merge with current environment (global env first, copilot overrides, then hook env vars)
|
||||||
const webSearchEnv = getWebSearchHookEnv();
|
const webSearchEnv = webSearchLaunch?.hookEnv ?? {};
|
||||||
const imageAnalysisResolution = await resolveCopilotImageAnalysisEnv();
|
const imageAnalysisResolution = await resolveCopilotImageAnalysisEnv();
|
||||||
const imageAnalysisProvisioningFailed =
|
const imageAnalysisProvisioningFailed =
|
||||||
!imageAnalysisMcpReady && imageAnalysisResolution.env.CCS_IMAGE_ANALYSIS_ENABLED === '1';
|
!imageAnalysisMcpReady && imageAnalysisResolution.env.CCS_IMAGE_ANALYSIS_ENABLED === '1';
|
||||||
@@ -305,10 +317,11 @@ export async function executeCopilotProfile(
|
|||||||
// Spawn Claude CLI
|
// Spawn Claude CLI
|
||||||
const spawnStartedAt = Date.now();
|
const spawnStartedAt = Date.now();
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const imageAnalysisArgs = imageAnalysisMcpReady
|
const launchArgs = buildCopilotClaudeLaunchArgs(
|
||||||
? appendThirdPartyImageAnalysisToolArgs(claudeArgs)
|
claudeArgs,
|
||||||
: claudeArgs;
|
imageAnalysisMcpReady,
|
||||||
const launchArgs = appendThirdPartyWebSearchToolArgs(imageAnalysisArgs);
|
webSearchLaunch?.enabled ?? true
|
||||||
|
);
|
||||||
const traceEnv = createWebSearchTraceContext({
|
const traceEnv = createWebSearchTraceContext({
|
||||||
launcher: 'copilot.executor',
|
launcher: 'copilot.executor',
|
||||||
args: launchArgs,
|
args: launchArgs,
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import { fail, info, ok } from '../utils/ui';
|
|||||||
import {
|
import {
|
||||||
appendThirdPartyWebSearchToolArgs,
|
appendThirdPartyWebSearchToolArgs,
|
||||||
createWebSearchTraceContext,
|
createWebSearchTraceContext,
|
||||||
getWebSearchHookEnv,
|
|
||||||
syncWebSearchMcpToConfigDir,
|
syncWebSearchMcpToConfigDir,
|
||||||
} from '../utils/websearch-manager';
|
} from '../utils/websearch-manager';
|
||||||
|
import type { WebSearchLaunchState } from '../utils/websearch-manager';
|
||||||
import { getImageAnalysisHookEnv, resolveImageAnalysisRuntimeStatus } from '../utils/hooks';
|
import { getImageAnalysisHookEnv, resolveImageAnalysisRuntimeStatus } from '../utils/hooks';
|
||||||
import { stripClaudeCodeEnv } from '../utils/shell-executor';
|
import { stripClaudeCodeEnv } from '../utils/shell-executor';
|
||||||
import { checkAuthStatus } from './cursor-auth';
|
import { checkAuthStatus } from './cursor-auth';
|
||||||
@@ -106,11 +106,19 @@ export async function resolveCursorImageAnalysisEnv(
|
|||||||
return { env, warning: null };
|
return { env, warning: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildCursorClaudeLaunchArgs(
|
||||||
|
claudeArgs: string[],
|
||||||
|
webSearchEnabled: boolean
|
||||||
|
): string[] {
|
||||||
|
return appendThirdPartyWebSearchToolArgs(claudeArgs, webSearchEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
export async function executeCursorProfile(
|
export async function executeCursorProfile(
|
||||||
config: CursorConfig,
|
config: CursorConfig,
|
||||||
claudeArgs: string[],
|
claudeArgs: string[],
|
||||||
claudeConfigDir?: string,
|
claudeConfigDir?: string,
|
||||||
claudeCliPath = 'claude'
|
claudeCliPath = 'claude',
|
||||||
|
webSearchLaunch?: WebSearchLaunchState
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
if (!config.enabled) {
|
if (!config.enabled) {
|
||||||
process.stderr.write(fail('Cursor integration is not enabled.') + '\n');
|
process.stderr.write(fail('Cursor integration is not enabled.') + '\n');
|
||||||
@@ -163,7 +171,7 @@ export async function executeCursorProfile(
|
|||||||
const cursorEnv = generateCursorEnv(config, daemonToken, claudeConfigDir);
|
const cursorEnv = generateCursorEnv(config, daemonToken, claudeConfigDir);
|
||||||
const globalEnvConfig = getGlobalEnvConfig();
|
const globalEnvConfig = getGlobalEnvConfig();
|
||||||
const globalEnv = globalEnvConfig.enabled ? globalEnvConfig.env : {};
|
const globalEnv = globalEnvConfig.enabled ? globalEnvConfig.env : {};
|
||||||
const webSearchEnv = getWebSearchHookEnv();
|
const webSearchEnv = webSearchLaunch?.hookEnv ?? {};
|
||||||
const { env: imageAnalysisEnv, warning: imageAnalysisWarning } =
|
const { env: imageAnalysisEnv, warning: imageAnalysisWarning } =
|
||||||
await resolveCursorImageAnalysisEnv();
|
await resolveCursorImageAnalysisEnv();
|
||||||
const env = stripClaudeCodeEnv({
|
const env = stripClaudeCodeEnv({
|
||||||
@@ -184,7 +192,7 @@ export async function executeCursorProfile(
|
|||||||
syncWebSearchMcpToConfigDir(claudeConfigDir);
|
syncWebSearchMcpToConfigDir(claudeConfigDir);
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const launchArgs = appendThirdPartyWebSearchToolArgs(claudeArgs);
|
const launchArgs = buildCursorClaudeLaunchArgs(claudeArgs, webSearchLaunch?.enabled ?? true);
|
||||||
const traceEnv = createWebSearchTraceContext({
|
const traceEnv = createWebSearchTraceContext({
|
||||||
launcher: 'cursor.executor',
|
launcher: 'cursor.executor',
|
||||||
args: launchArgs,
|
args: launchArgs,
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ import {
|
|||||||
appendWebSearchTrace,
|
appendWebSearchTrace,
|
||||||
createWebSearchTraceContext,
|
createWebSearchTraceContext,
|
||||||
ensureWebSearchMcpForLaunch,
|
ensureWebSearchMcpForLaunch,
|
||||||
getWebSearchHookEnv,
|
|
||||||
readWebSearchTraceRecords,
|
readWebSearchTraceRecords,
|
||||||
|
resolveWebSearchLaunchState,
|
||||||
syncWebSearchMcpToConfigDir,
|
syncWebSearchMcpToConfigDir,
|
||||||
} from '../utils/websearch-manager';
|
} from '../utils/websearch-manager';
|
||||||
import { getCcsDir, getGlobalEnvConfig, loadSettings } from '../config/config-loader-facade';
|
import { getCcsDir, getGlobalEnvConfig, loadSettings } from '../config/config-loader-facade';
|
||||||
@@ -159,7 +159,8 @@ export class HeadlessExecutor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureWebSearchMcpForLaunch();
|
const webSearchLaunch = resolveWebSearchLaunchState();
|
||||||
|
ensureWebSearchMcpForLaunch(webSearchLaunch.config);
|
||||||
const imageAnalysisMcpReady = ensureImageAnalysisMcpOrThrow();
|
const imageAnalysisMcpReady = ensureImageAnalysisMcpOrThrow();
|
||||||
syncWebSearchMcpToConfigDir(inheritedClaudeConfigDir);
|
syncWebSearchMcpToConfigDir(inheritedClaudeConfigDir);
|
||||||
syncImageAnalysisMcpToConfigDir(inheritedClaudeConfigDir);
|
syncImageAnalysisMcpToConfigDir(inheritedClaudeConfigDir);
|
||||||
@@ -257,6 +258,7 @@ export class HeadlessExecutor {
|
|||||||
|
|
||||||
let runtimeEnvVars: NodeJS.ProcessEnv = {
|
let runtimeEnvVars: NodeJS.ProcessEnv = {
|
||||||
...stripAnthropicRoutingEnv({ ...globalEnv, ...settingsEnv }, settingsEnv),
|
...stripAnthropicRoutingEnv({ ...globalEnv, ...settingsEnv }, settingsEnv),
|
||||||
|
...webSearchLaunch.hookEnv,
|
||||||
...(inheritedClaudeConfigDir ? { CLAUDE_CONFIG_DIR: inheritedClaudeConfigDir } : {}),
|
...(inheritedClaudeConfigDir ? { CLAUDE_CONFIG_DIR: inheritedClaudeConfigDir } : {}),
|
||||||
CCS_PROFILE_TYPE: 'settings',
|
CCS_PROFILE_TYPE: 'settings',
|
||||||
CCS_STRIP_INHERITED_ANTHROPIC_ENV: '1',
|
CCS_STRIP_INHERITED_ANTHROPIC_ENV: '1',
|
||||||
@@ -380,7 +382,10 @@ export class HeadlessExecutor {
|
|||||||
const imageAnalysisArgs = imageAnalysisMcpReady
|
const imageAnalysisArgs = imageAnalysisMcpReady
|
||||||
? appendThirdPartyImageAnalysisToolArgs(args)
|
? appendThirdPartyImageAnalysisToolArgs(args)
|
||||||
: args;
|
: args;
|
||||||
const launchArgs = appendThirdPartyWebSearchToolArgs(imageAnalysisArgs);
|
const launchArgs = appendThirdPartyWebSearchToolArgs(
|
||||||
|
imageAnalysisArgs,
|
||||||
|
webSearchLaunch.enabled
|
||||||
|
);
|
||||||
const traceEnv = createWebSearchTraceContext({
|
const traceEnv = createWebSearchTraceContext({
|
||||||
launcher: 'delegation.headless-executor',
|
launcher: 'delegation.headless-executor',
|
||||||
args: launchArgs,
|
args: launchArgs,
|
||||||
@@ -467,7 +472,6 @@ export class HeadlessExecutor {
|
|||||||
const cleanEnv = stripClaudeCodeEnv({
|
const cleanEnv = stripClaudeCodeEnv({
|
||||||
...stripAnthropicRoutingEnv(process.env),
|
...stripAnthropicRoutingEnv(process.env),
|
||||||
...getClaudeLaunchEnvOverrides(),
|
...getClaudeLaunchEnvOverrides(),
|
||||||
...getWebSearchHookEnv(),
|
|
||||||
...runtimeEnvVars,
|
...runtimeEnvVars,
|
||||||
...imageAnalysisEnv,
|
...imageAnalysisEnv,
|
||||||
...traceEnv,
|
...traceEnv,
|
||||||
|
|||||||
@@ -5,7 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { fail, info } from '../../utils/ui';
|
import { fail, info } from '../../utils/ui';
|
||||||
import { ensureWebSearchMcpForLaunch } from '../../utils/websearch-manager';
|
import {
|
||||||
|
ensureWebSearchMcpForLaunch,
|
||||||
|
resolveWebSearchLaunchState,
|
||||||
|
} from '../../utils/websearch-manager';
|
||||||
import { ensureImageAnalysisMcpOrThrow } from '../../utils/image-analysis';
|
import { ensureImageAnalysisMcpOrThrow } from '../../utils/image-analysis';
|
||||||
import {
|
import {
|
||||||
ensureProfileHooks as ensureImageAnalyzerHooks,
|
ensureProfileHooks as ensureImageAnalyzerHooks,
|
||||||
@@ -23,7 +26,8 @@ export async function runCopilotFlow(ctx: ProfileDispatchContext): Promise<void>
|
|||||||
resolveProfileContinuityInheritance,
|
resolveProfileContinuityInheritance,
|
||||||
} = ctx;
|
} = ctx;
|
||||||
|
|
||||||
ensureWebSearchMcpForLaunch();
|
const webSearchLaunch = resolveWebSearchLaunchState();
|
||||||
|
ensureWebSearchMcpForLaunch(webSearchLaunch.config);
|
||||||
const imageAnalysisMcpReady = ensureImageAnalysisMcpOrThrow();
|
const imageAnalysisMcpReady = ensureImageAnalysisMcpOrThrow();
|
||||||
if (resolvedTarget === 'claude') {
|
if (resolvedTarget === 'claude') {
|
||||||
if (imageAnalysisMcpReady) {
|
if (imageAnalysisMcpReady) {
|
||||||
@@ -60,7 +64,8 @@ export async function runCopilotFlow(ctx: ProfileDispatchContext): Promise<void>
|
|||||||
copilotConfig,
|
copilotConfig,
|
||||||
remainingArgs,
|
remainingArgs,
|
||||||
continuityInheritance.claudeConfigDir,
|
continuityInheritance.claudeConfigDir,
|
||||||
claudeCli
|
claudeCli,
|
||||||
|
webSearchLaunch
|
||||||
);
|
);
|
||||||
process.exit(exitCode);
|
process.exit(exitCode);
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { fail, info } from '../../utils/ui';
|
import { fail, info } from '../../utils/ui';
|
||||||
import { ensureWebSearchMcpForLaunch } from '../../utils/websearch-manager';
|
import {
|
||||||
|
ensureWebSearchMcpForLaunch,
|
||||||
|
resolveWebSearchLaunchState,
|
||||||
|
} from '../../utils/websearch-manager';
|
||||||
import { ensureProfileHooks as ensureImageAnalyzerHooks } from '../../utils/hooks/image-analyzer-profile-hook-injector';
|
import { ensureProfileHooks as ensureImageAnalyzerHooks } from '../../utils/hooks/image-analyzer-profile-hook-injector';
|
||||||
import { installImageAnalyzerHook } from '../../utils/hooks';
|
import { installImageAnalyzerHook } from '../../utils/hooks';
|
||||||
import type { ProfileDispatchContext } from '../dispatcher-context';
|
import type { ProfileDispatchContext } from '../dispatcher-context';
|
||||||
@@ -19,7 +22,8 @@ export async function runCursorFlow(ctx: ProfileDispatchContext): Promise<void>
|
|||||||
resolveProfileContinuityInheritance,
|
resolveProfileContinuityInheritance,
|
||||||
} = ctx;
|
} = ctx;
|
||||||
|
|
||||||
ensureWebSearchMcpForLaunch();
|
const webSearchLaunch = resolveWebSearchLaunchState();
|
||||||
|
ensureWebSearchMcpForLaunch(webSearchLaunch.config);
|
||||||
installImageAnalyzerHook();
|
installImageAnalyzerHook();
|
||||||
ensureImageAnalyzerHooks({
|
ensureImageAnalyzerHooks({
|
||||||
profileName: profileInfo.name,
|
profileName: profileInfo.name,
|
||||||
@@ -48,7 +52,8 @@ export async function runCursorFlow(ctx: ProfileDispatchContext): Promise<void>
|
|||||||
cursorConfig,
|
cursorConfig,
|
||||||
remainingArgs,
|
remainingArgs,
|
||||||
continuityInheritance.claudeConfigDir,
|
continuityInheritance.claudeConfigDir,
|
||||||
claudeCli
|
claudeCli,
|
||||||
|
webSearchLaunch
|
||||||
);
|
);
|
||||||
process.exit(exitCode);
|
process.exit(exitCode);
|
||||||
}
|
}
|
||||||
@@ -16,10 +16,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
ensureWebSearchMcpForLaunch,
|
ensureWebSearchMcpForLaunch,
|
||||||
displayWebSearchStatus,
|
displayWebSearchStatus,
|
||||||
getWebSearchHookEnv,
|
|
||||||
syncWebSearchMcpToConfigDir,
|
syncWebSearchMcpToConfigDir,
|
||||||
appendThirdPartyWebSearchToolArgs,
|
appendThirdPartyWebSearchToolArgs,
|
||||||
createWebSearchTraceContext,
|
createWebSearchTraceContext,
|
||||||
|
resolveWebSearchLaunchState,
|
||||||
} from '../../utils/websearch-manager';
|
} from '../../utils/websearch-manager';
|
||||||
import {
|
import {
|
||||||
ensureImageAnalysisMcpOrThrow,
|
ensureImageAnalysisMcpOrThrow,
|
||||||
@@ -94,18 +94,16 @@ export async function runSettingsFlow(ctx: ProfileDispatchContext): Promise<void
|
|||||||
if (browserAttachRuntime?.warning) {
|
if (browserAttachRuntime?.warning) {
|
||||||
process.stderr.write(`${warn(browserAttachRuntime.warning)}\n`);
|
process.stderr.write(`${warn(browserAttachRuntime.warning)}\n`);
|
||||||
}
|
}
|
||||||
let shouldDisplayWebSearchStatus = true;
|
const webSearchLaunch = resolveWebSearchLaunchState();
|
||||||
if (resolvedTarget === 'claude') {
|
if (resolvedTarget === 'claude') {
|
||||||
shouldDisplayWebSearchStatus = ensureWebSearchMcpForLaunch();
|
ensureWebSearchMcpForLaunch(webSearchLaunch.config);
|
||||||
if (browserRuntimeEnv) {
|
if (browserRuntimeEnv) {
|
||||||
ensureBrowserMcpOrThrow();
|
ensureBrowserMcpOrThrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display WebSearch status (single line, equilibrium UX)
|
// Display WebSearch status (single line, equilibrium UX)
|
||||||
if (shouldDisplayWebSearchStatus) {
|
displayWebSearchStatus(webSearchLaunch.config);
|
||||||
displayWebSearchStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
const continuityInheritance =
|
const continuityInheritance =
|
||||||
resolvedTarget === 'claude'
|
resolvedTarget === 'claude'
|
||||||
@@ -275,7 +273,7 @@ export async function runSettingsFlow(ctx: ProfileDispatchContext): Promise<void
|
|||||||
targetRemainingArgs,
|
targetRemainingArgs,
|
||||||
});
|
});
|
||||||
|
|
||||||
const webSearchEnv = getWebSearchHookEnv();
|
const webSearchEnv = webSearchLaunch.hookEnv;
|
||||||
|
|
||||||
// Get global env vars (DISABLE_TELEMETRY, etc.) for third-party profiles
|
// Get global env vars (DISABLE_TELEMETRY, etc.) for third-party profiles
|
||||||
const globalEnvConfig = getGlobalEnvConfig();
|
const globalEnvConfig = getGlobalEnvConfig();
|
||||||
@@ -395,11 +393,11 @@ export async function runSettingsFlow(ctx: ProfileDispatchContext): Promise<void
|
|||||||
? stripClaudeSubcommandSessionArgs(browserArgs)
|
? stripClaudeSubcommandSessionArgs(browserArgs)
|
||||||
: browserArgs;
|
: browserArgs;
|
||||||
const launchArgs = isSubcommand
|
const launchArgs = isSubcommand
|
||||||
? appendThirdPartyWebSearchToolArgs(subcommandArgs)
|
? appendThirdPartyWebSearchToolArgs(subcommandArgs, webSearchLaunch.enabled)
|
||||||
: [
|
: [
|
||||||
'--settings',
|
'--settings',
|
||||||
launchSettings.settingsPath,
|
launchSettings.settingsPath,
|
||||||
...appendThirdPartyWebSearchToolArgs(browserArgs),
|
...appendThirdPartyWebSearchToolArgs(browserArgs, webSearchLaunch.enabled),
|
||||||
];
|
];
|
||||||
const traceEnv = createWebSearchTraceContext({
|
const traceEnv = createWebSearchTraceContext({
|
||||||
launcher: 'ccs.settings-profile.proxy',
|
launcher: 'ccs.settings-profile.proxy',
|
||||||
@@ -418,8 +416,12 @@ export async function runSettingsFlow(ctx: ProfileDispatchContext): Promise<void
|
|||||||
const isSubcommand = isClaudeSubcommandInvocation(browserArgs);
|
const isSubcommand = isClaudeSubcommandInvocation(browserArgs);
|
||||||
const subcommandArgs = isSubcommand ? stripClaudeSubcommandSessionArgs(browserArgs) : browserArgs;
|
const subcommandArgs = isSubcommand ? stripClaudeSubcommandSessionArgs(browserArgs) : browserArgs;
|
||||||
const launchArgs = isSubcommand
|
const launchArgs = isSubcommand
|
||||||
? appendThirdPartyWebSearchToolArgs(subcommandArgs)
|
? appendThirdPartyWebSearchToolArgs(subcommandArgs, webSearchLaunch.enabled)
|
||||||
: ['--settings', expandedSettingsPath, ...appendThirdPartyWebSearchToolArgs(browserArgs)];
|
: [
|
||||||
|
'--settings',
|
||||||
|
expandedSettingsPath,
|
||||||
|
...appendThirdPartyWebSearchToolArgs(browserArgs, webSearchLaunch.enabled),
|
||||||
|
];
|
||||||
const traceEnv = createWebSearchTraceContext({
|
const traceEnv = createWebSearchTraceContext({
|
||||||
launcher: 'ccs.settings-profile',
|
launcher: 'ccs.settings-profile',
|
||||||
args: launchArgs,
|
args: launchArgs,
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ export {
|
|||||||
|
|
||||||
// Re-export Claude launch arg helpers
|
// Re-export Claude launch arg helpers
|
||||||
export { appendThirdPartyWebSearchToolArgs } from './websearch/claude-tool-args';
|
export { appendThirdPartyWebSearchToolArgs } from './websearch/claude-tool-args';
|
||||||
|
export { resolveWebSearchLaunchState } from './websearch/launch-state';
|
||||||
|
export type { WebSearchConfigSnapshot, WebSearchLaunchState } from './websearch/launch-state';
|
||||||
|
|
||||||
// Re-export trace helpers
|
// Re-export trace helpers
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -135,9 +135,14 @@ function ensureWebSearchSteeringPrompt(args: string[]): string[] {
|
|||||||
return [...optionArgs, ...steeringArgs, ...trailingArgs];
|
return [...optionArgs, ...steeringArgs, ...trailingArgs];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function appendThirdPartyWebSearchToolArgs(args: string[]): string[] {
|
export function appendThirdPartyWebSearchToolArgs(
|
||||||
|
args: string[],
|
||||||
|
webSearchEnabled = true
|
||||||
|
): string[] {
|
||||||
// Claude subcommands (agents, doctor, mcp, ...) reject top-level session flags
|
// Claude subcommands (agents, doctor, mcp, ...) reject top-level session flags
|
||||||
// like `--append-system-prompt` and `--disallowedTools`. Issue #1218.
|
// like `--append-system-prompt` and `--disallowedTools`. Issue #1218.
|
||||||
if (isClaudeSubcommandInvocation(args)) return args;
|
if (isClaudeSubcommandInvocation(args)) return args;
|
||||||
return ensureWebSearchSteeringPrompt(ensureDisallowedNativeWebSearchTool(args));
|
|
||||||
|
const disallowedArgs = ensureDisallowedNativeWebSearchTool(args);
|
||||||
|
return webSearchEnabled ? ensureWebSearchSteeringPrompt(disallowedArgs) : disallowedArgs;
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ import { getCcsHooksDir } from '../config-manager';
|
|||||||
import { getClaudeSettingsPath } from '../claude-config-path';
|
import { getClaudeSettingsPath } from '../claude-config-path';
|
||||||
import { isCcsWebSearchHook, deduplicateCcsHooks } from './hook-utils';
|
import { isCcsWebSearchHook, deduplicateCcsHooks } from './hook-utils';
|
||||||
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
||||||
|
import type { WebSearchConfigSnapshot } from './launch-state';
|
||||||
|
|
||||||
// Hook file name
|
// Hook file name
|
||||||
const WEBSEARCH_HOOK = 'websearch-transformer.cjs';
|
const WEBSEARCH_HOOK = 'websearch-transformer.cjs';
|
||||||
@@ -35,9 +36,10 @@ export function getHookPath(): string {
|
|||||||
* Get WebSearch hook configuration for settings.json
|
* Get WebSearch hook configuration for settings.json
|
||||||
* Timeout is computed from max provider timeout in config.yaml + buffer
|
* Timeout is computed from max provider timeout in config.yaml + buffer
|
||||||
*/
|
*/
|
||||||
export function getWebSearchHookConfig(): Record<string, unknown> {
|
export function getWebSearchHookConfig(
|
||||||
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): Record<string, unknown> {
|
||||||
const hookPath = getHookPath();
|
const hookPath = getHookPath();
|
||||||
const wsConfig = getWebSearchConfig();
|
|
||||||
|
|
||||||
// Compute max timeout from enabled providers
|
// Compute max timeout from enabled providers
|
||||||
const timeouts: number[] = [];
|
const timeouts: number[] = [];
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import { normalizeSearxngBaseUrl } from './types';
|
import { normalizeSearxngBaseUrl } from './types';
|
||||||
import { resolveAllowedWebSearchTraceFile } from './trace';
|
import { resolveAllowedWebSearchTraceFile } from './trace';
|
||||||
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
||||||
|
import type { WebSearchConfigSnapshot } from './launch-state';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get environment variables for WebSearch hook configuration.
|
* Get environment variables for WebSearch hook configuration.
|
||||||
@@ -17,8 +18,9 @@ import { getWebSearchConfig } from '../../config/config-loader-facade';
|
|||||||
*
|
*
|
||||||
* @returns Record of environment variables to set before spawning Claude
|
* @returns Record of environment variables to set before spawning Claude
|
||||||
*/
|
*/
|
||||||
export function getWebSearchHookEnv(): Record<string, string> {
|
export function getWebSearchHookEnv(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): Record<string, string> {
|
||||||
const env: Record<string, string> = {
|
const env: Record<string, string> = {
|
||||||
CCS_WEBSEARCH_ENABLED: '0',
|
CCS_WEBSEARCH_ENABLED: '0',
|
||||||
CCS_WEBSEARCH_SKIP: '0',
|
CCS_WEBSEARCH_SKIP: '0',
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { info, warn } from '../ui';
|
|||||||
import { getCcsDir, getCcsHooksDir } from '../config-manager';
|
import { getCcsDir, getCcsHooksDir } from '../config-manager';
|
||||||
import { getHookPath } from './hook-config';
|
import { getHookPath } from './hook-config';
|
||||||
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
||||||
|
import type { WebSearchConfigSnapshot } from './launch-state';
|
||||||
|
|
||||||
// Re-export from hook-config for backward compatibility
|
// Re-export from hook-config for backward compatibility
|
||||||
export { getHookPath, getWebSearchHookConfig } from './hook-config';
|
export { getHookPath, getWebSearchHookConfig } from './hook-config';
|
||||||
@@ -76,10 +77,10 @@ export function hasWebSearchHook(): boolean {
|
|||||||
*
|
*
|
||||||
* @returns true if hook installed successfully
|
* @returns true if hook installed successfully
|
||||||
*/
|
*/
|
||||||
export function installWebSearchHook(): boolean {
|
export function installWebSearchHook(
|
||||||
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): boolean {
|
||||||
try {
|
try {
|
||||||
const wsConfig = getWebSearchConfig();
|
|
||||||
|
|
||||||
// Skip if disabled
|
// Skip if disabled
|
||||||
if (!wsConfig.enabled) {
|
if (!wsConfig.enabled) {
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ export {
|
|||||||
|
|
||||||
// Claude launch args
|
// Claude launch args
|
||||||
export { appendThirdPartyWebSearchToolArgs } from './claude-tool-args';
|
export { appendThirdPartyWebSearchToolArgs } from './claude-tool-args';
|
||||||
|
export { resolveWebSearchLaunchState } from './launch-state';
|
||||||
|
export type { WebSearchConfigSnapshot, WebSearchLaunchState } from './launch-state';
|
||||||
|
|
||||||
// Trace helpers
|
// Trace helpers
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
||||||
|
import { getWebSearchHookEnv } from './hook-env';
|
||||||
|
|
||||||
|
export type WebSearchConfigSnapshot = ReturnType<typeof getWebSearchConfig>;
|
||||||
|
|
||||||
|
export interface WebSearchLaunchState {
|
||||||
|
config: WebSearchConfigSnapshot;
|
||||||
|
enabled: boolean;
|
||||||
|
hookEnv: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveWebSearchLaunchState(): WebSearchLaunchState {
|
||||||
|
const config = getWebSearchConfig();
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
enabled: config.enabled,
|
||||||
|
hookEnv: getWebSearchHookEnv(config),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
isClaudeUserConfigLockUnavailableError as isLockUnavailableError,
|
isClaudeUserConfigLockUnavailableError as isLockUnavailableError,
|
||||||
withClaudeUserConfigLock,
|
withClaudeUserConfigLock,
|
||||||
} from '../claude-user-config-lock';
|
} from '../claude-user-config-lock';
|
||||||
|
import type { WebSearchConfigSnapshot } from './launch-state';
|
||||||
|
|
||||||
const WEBSEARCH_MCP_SERVER = 'ccs-websearch-server.cjs';
|
const WEBSEARCH_MCP_SERVER = 'ccs-websearch-server.cjs';
|
||||||
const WEBSEARCH_MCP_SERVER_NAME = 'ccs-websearch';
|
const WEBSEARCH_MCP_SERVER_NAME = 'ccs-websearch';
|
||||||
@@ -189,14 +190,15 @@ function removeManagedServerConfig(configPath: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function installWebSearchMcpServer(): boolean {
|
export function installWebSearchMcpServer(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): boolean {
|
||||||
if (!wsConfig.enabled) {
|
if (!wsConfig.enabled) {
|
||||||
appendWebSearchTrace('websearch_mcp_install_skipped', { reason: 'disabled' });
|
appendWebSearchTrace('websearch_mcp_install_skipped', { reason: 'disabled' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!installWebSearchHook()) {
|
if (!installWebSearchHook(wsConfig)) {
|
||||||
appendWebSearchTrace('websearch_mcp_install_failed', { reason: 'hook_unavailable' });
|
appendWebSearchTrace('websearch_mcp_install_failed', { reason: 'hook_unavailable' });
|
||||||
if (process.env.CCS_DEBUG) {
|
if (process.env.CCS_DEBUG) {
|
||||||
process.stderr.write(
|
process.stderr.write(
|
||||||
@@ -267,8 +269,9 @@ export function installWebSearchMcpServer(): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureWebSearchMcpConfig(): boolean {
|
export function ensureWebSearchMcpConfig(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): boolean {
|
||||||
if (!wsConfig.enabled) {
|
if (!wsConfig.enabled) {
|
||||||
appendWebSearchTrace('websearch_mcp_config_skipped', { reason: 'disabled' });
|
appendWebSearchTrace('websearch_mcp_config_skipped', { reason: 'disabled' });
|
||||||
return false;
|
return false;
|
||||||
@@ -366,15 +369,16 @@ export function ensureWebSearchMcpConfig(): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureWebSearchMcp(): boolean {
|
export function ensureWebSearchMcp(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): boolean {
|
||||||
if (!wsConfig.enabled) {
|
if (!wsConfig.enabled) {
|
||||||
appendWebSearchTrace('websearch_mcp_ensure_skipped', { reason: 'disabled' });
|
appendWebSearchTrace('websearch_mcp_ensure_skipped', { reason: 'disabled' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const installed = installWebSearchMcpServer();
|
const installed = installWebSearchMcpServer(wsConfig);
|
||||||
const configured = installed && ensureWebSearchMcpConfig();
|
const configured = installed && ensureWebSearchMcpConfig(wsConfig);
|
||||||
appendWebSearchTrace('websearch_mcp_ensure_result', { installed, configured });
|
appendWebSearchTrace('websearch_mcp_ensure_result', { installed, configured });
|
||||||
return installed && configured;
|
return installed && configured;
|
||||||
}
|
}
|
||||||
@@ -428,13 +432,14 @@ export function uninstallWebSearchMcp(): boolean {
|
|||||||
return removedConfig || removedServer;
|
return removedConfig || removedServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureWebSearchMcpOrThrow(): void {
|
export function ensureWebSearchMcpOrThrow(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): void {
|
||||||
if (!wsConfig.enabled) {
|
if (!wsConfig.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ensureWebSearchMcp()) {
|
if (!ensureWebSearchMcp(wsConfig)) {
|
||||||
throw new Error('WebSearch is enabled, but CCS could not prepare the local WebSearch tool.');
|
throw new Error('WebSearch is enabled, but CCS could not prepare the local WebSearch tool.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,7 +452,6 @@ export function ensureWebSearchMcpOrThrow(): void {
|
|||||||
* native WebSearch and inject fallback steering while the constrained MCP
|
* native WebSearch and inject fallback steering while the constrained MCP
|
||||||
* search path is unavailable.
|
* search path is unavailable.
|
||||||
*/
|
*/
|
||||||
export function ensureWebSearchMcpForLaunch(): boolean {
|
export function ensureWebSearchMcpForLaunch(wsConfig: WebSearchConfigSnapshot): void {
|
||||||
ensureWebSearchMcpOrThrow();
|
ensureWebSearchMcpOrThrow(wsConfig);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ import { getOpenCodeCliStatus } from './opencode-cli';
|
|||||||
import { getWebSearchApiKeyStates } from './provider-secrets';
|
import { getWebSearchApiKeyStates } from './provider-secrets';
|
||||||
import { normalizeSearxngBaseUrl, type WebSearchCliInfo, type WebSearchStatus } from './types';
|
import { normalizeSearxngBaseUrl, type WebSearchCliInfo, type WebSearchStatus } from './types';
|
||||||
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
import { getWebSearchConfig } from '../../config/config-loader-facade';
|
||||||
|
import type { WebSearchConfigSnapshot } from './launch-state';
|
||||||
|
|
||||||
const PROVIDER_STATE_FILE = 'websearch-provider-state.json';
|
const PROVIDER_STATE_FILE = 'websearch-provider-state.json';
|
||||||
|
|
||||||
@@ -112,8 +113,7 @@ function applyCooldownStatus(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLegacyProviderStatuses(): WebSearchCliInfo[] {
|
function getLegacyProviderStatuses(wsConfig: WebSearchConfigSnapshot): WebSearchCliInfo[] {
|
||||||
const wsConfig = getWebSearchConfig();
|
|
||||||
const agyStatus = getAgyCliStatus();
|
const agyStatus = getAgyCliStatus();
|
||||||
const geminiStatus = getGeminiCliStatus();
|
const geminiStatus = getGeminiCliStatus();
|
||||||
const grokStatus = getGrokCliStatus();
|
const grokStatus = getGrokCliStatus();
|
||||||
@@ -197,8 +197,9 @@ function getLegacyProviderStatuses(): WebSearchCliInfo[] {
|
|||||||
/**
|
/**
|
||||||
* Get all WebSearch providers with their current status.
|
* Get all WebSearch providers with their current status.
|
||||||
*/
|
*/
|
||||||
export function getWebSearchCliProviders(): WebSearchCliInfo[] {
|
export function getWebSearchCliProviders(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): WebSearchCliInfo[] {
|
||||||
const apiKeyStates = getWebSearchApiKeyStates();
|
const apiKeyStates = getWebSearchApiKeyStates();
|
||||||
const cooldowns = readProviderCooldowns();
|
const cooldowns = readProviderCooldowns();
|
||||||
const providers: WebSearchCliInfo[] = [
|
const providers: WebSearchCliInfo[] = [
|
||||||
@@ -283,7 +284,7 @@ export function getWebSearchCliProviders(): WebSearchCliInfo[] {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return [...providers, ...getLegacyProviderStatuses()].map((provider) =>
|
return [...providers, ...getLegacyProviderStatuses(wsConfig)].map((provider) =>
|
||||||
applyCooldownStatus(provider, cooldowns)
|
applyCooldownStatus(provider, cooldowns)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -355,17 +356,20 @@ export function buildWebSearchReadiness(
|
|||||||
/**
|
/**
|
||||||
* Get WebSearch readiness status for display.
|
* Get WebSearch readiness status for display.
|
||||||
*/
|
*/
|
||||||
export function getWebSearchReadiness(): WebSearchStatus {
|
export function getWebSearchReadiness(
|
||||||
const wsConfig = getWebSearchConfig();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
const providers = getWebSearchCliProviders();
|
): WebSearchStatus {
|
||||||
|
const providers = getWebSearchCliProviders(wsConfig);
|
||||||
return buildWebSearchReadiness(wsConfig.enabled, providers);
|
return buildWebSearchReadiness(wsConfig.enabled, providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display WebSearch status (single line, equilibrium UX).
|
* Display WebSearch status (single line, equilibrium UX).
|
||||||
*/
|
*/
|
||||||
export function displayWebSearchStatus(): void {
|
export function displayWebSearchStatus(
|
||||||
const status = getWebSearchReadiness();
|
wsConfig: WebSearchConfigSnapshot = getWebSearchConfig()
|
||||||
|
): void {
|
||||||
|
const status = getWebSearchReadiness(wsConfig);
|
||||||
|
|
||||||
switch (status.readiness) {
|
switch (status.readiness) {
|
||||||
case 'ready':
|
case 'ready':
|
||||||
|
|||||||
Reference in new issue
Block a user