mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 08:45:50 +00:00
chore: 移除 src/ 下多处未引用的导出
涉及 18 个文件,每处均为独立的 unreferenced export 删除或 export 关键字冗余移除: - bridge/bridgeStatusUtil.ts、components/TrustDialog/utils.ts、context/stats.tsx - keybindings/loadUserBindings.ts、memdir/paths.ts、remote/sdkMessageAdapter.ts - services/acp/utils.ts(删除 nodeToWebReadable,全仓零引用) - services/api/metricsOptOut.ts、services/lsp/LSPDiagnosticRegistry.ts、services/lsp/manager.ts - services/mcp/utils.ts、services/skillLearning/projectContext.ts - services/teamMemorySync/secretScanner.ts、services/teamMemorySync/watcher.ts - skills/loadSkillsDir.ts、utils/attachments.ts、utils/filePersistence/filePersistence.ts - utils/messageQueueManager.ts Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
This commit is contained in:
@@ -28,11 +28,6 @@ export function timestamp(): string {
|
|||||||
|
|
||||||
export { formatDuration, truncateToWidth as truncatePrompt }
|
export { formatDuration, truncateToWidth as truncatePrompt }
|
||||||
|
|
||||||
/** Abbreviate a tool activity summary for the trail display. */
|
|
||||||
export function abbreviateActivity(summary: string): string {
|
|
||||||
return truncateToWidth(summary, 30)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Build the connect URL shown when the bridge is idle. */
|
/** Build the connect URL shown when the bridge is idle. */
|
||||||
export function buildBridgeConnectUrl(
|
export function buildBridgeConnectUrl(
|
||||||
environmentId: string,
|
environmentId: string,
|
||||||
|
|||||||
@@ -71,38 +71,6 @@ export function getBashPermissionSources(): string[] {
|
|||||||
return sources
|
return sources
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a list of items with proper "and" conjunction.
|
|
||||||
* @param items - Array of items to format
|
|
||||||
* @param limit - Optional limit for how many items to show before summarizing (ignored if 0)
|
|
||||||
*/
|
|
||||||
export function formatListWithAnd(items: string[], limit?: number): string {
|
|
||||||
if (items.length === 0) return ''
|
|
||||||
|
|
||||||
// Ignore limit if it's 0
|
|
||||||
const effectiveLimit = limit === 0 ? undefined : limit
|
|
||||||
|
|
||||||
// If no limit or items are within limit, use normal formatting
|
|
||||||
if (!effectiveLimit || items.length <= effectiveLimit) {
|
|
||||||
if (items.length === 1) return items[0]!
|
|
||||||
if (items.length === 2) return `${items[0]} and ${items[1]}`
|
|
||||||
|
|
||||||
const lastItem = items[items.length - 1]!
|
|
||||||
const allButLast = items.slice(0, -1)
|
|
||||||
return `${allButLast.join(', ')}, and ${lastItem}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have more items than the limit, show first few and count the rest
|
|
||||||
const shown = items.slice(0, effectiveLimit)
|
|
||||||
const remaining = items.length - effectiveLimit
|
|
||||||
|
|
||||||
if (shown.length === 1) {
|
|
||||||
return `${shown[0]} and ${remaining} more`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${shown.join(', ')}, and ${remaining} more`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if settings have otelHeadersHelper configured
|
* Check if settings have otelHeadersHelper configured
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -137,11 +137,6 @@ export function useStats(): StatsStore {
|
|||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCounter(name: string): (value?: number) => void {
|
|
||||||
const store = useStats();
|
|
||||||
return useCallback((value?: number) => store.increment(name, value), [store, name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useGauge(name: string): (value: number) => void {
|
export function useGauge(name: string): (value: number) => void {
|
||||||
const store = useStats();
|
const store = useStats();
|
||||||
return useCallback((value: number) => store.set(name, value), [store, name]);
|
return useCallback((value: number) => store.set(name, value), [store, name]);
|
||||||
|
|||||||
@@ -454,19 +454,3 @@ function handleDelete(path: string): void {
|
|||||||
export function getCachedKeybindingWarnings(): KeybindingWarning[] {
|
export function getCachedKeybindingWarnings(): KeybindingWarning[] {
|
||||||
return cachedWarnings
|
return cachedWarnings
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset internal state for testing.
|
|
||||||
*/
|
|
||||||
export function resetKeybindingLoaderForTesting(): void {
|
|
||||||
initialized = false
|
|
||||||
disposed = false
|
|
||||||
cachedBindings = null
|
|
||||||
cachedWarnings = []
|
|
||||||
lastCustomBindingsLogDate = null
|
|
||||||
if (watcher) {
|
|
||||||
void watcher.close()
|
|
||||||
watcher = null
|
|
||||||
}
|
|
||||||
keybindingsChanged.clear()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -234,22 +234,6 @@ export const getAutoMemPath = memoize(
|
|||||||
() => getProjectRoot(),
|
() => getProjectRoot(),
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the daily log file path for the given date (defaults to today).
|
|
||||||
* Shape: <autoMemPath>/logs/YYYY/MM/YYYY-MM-DD.md
|
|
||||||
*
|
|
||||||
* Used by assistant mode (feature('KAIROS')): rather than maintaining
|
|
||||||
* MEMORY.md as a live index, the agent appends to a date-named log file
|
|
||||||
* as it works. A separate nightly /dream skill distills these logs into
|
|
||||||
* topic files + MEMORY.md.
|
|
||||||
*/
|
|
||||||
export function getAutoMemDailyLogPath(date: Date = new Date()): string {
|
|
||||||
const yyyy = date.getFullYear().toString()
|
|
||||||
const mm = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
||||||
const dd = date.getDate().toString().padStart(2, '0')
|
|
||||||
return join(getAutoMemPath(), 'logs', yyyy, mm, `${yyyy}-${mm}-${dd}.md`)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the auto-memory entrypoint (MEMORY.md inside the auto-memory dir).
|
* Returns the auto-memory entrypoint (MEMORY.md inside the auto-memory dir).
|
||||||
* Follows the same resolution order as getAutoMemPath().
|
* Follows the same resolution order as getAutoMemPath().
|
||||||
|
|||||||
@@ -313,13 +313,3 @@ export function isSessionEndMessage(msg: SDKMessage): boolean {
|
|||||||
export function isSuccessResult(msg: SDKResultMessage): boolean {
|
export function isSuccessResult(msg: SDKResultMessage): boolean {
|
||||||
return msg.subtype === 'success'
|
return msg.subtype === 'success'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract the result text from a successful SDKResultMessage
|
|
||||||
*/
|
|
||||||
export function getResultText(msg: SDKResultMessage): string | null {
|
|
||||||
if (msg.subtype === 'success') {
|
|
||||||
return msg.result ?? null
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Shared utilities for the ACP service.
|
* Shared utilities for the ACP service.
|
||||||
* Ported from claude-agent-acp-main/src/utils.ts and acp-agent.ts helpers.
|
* Ported from claude-agent-acp-main/src/utils.ts and acp-agent.ts helpers.
|
||||||
*/
|
*/
|
||||||
import { Readable, Writable } from 'node:stream'
|
import { Writable } from 'node:stream'
|
||||||
import type { PermissionMode } from '../../entrypoints/sdk/coreTypes.generated.js'
|
import type { PermissionMode } from '../../entrypoints/sdk/coreTypes.generated.js'
|
||||||
|
|
||||||
// ── Pushable ──────────────────────────────────────────────────────
|
// ── Pushable ──────────────────────────────────────────────────────
|
||||||
@@ -71,20 +71,6 @@ export function nodeToWebWritable(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nodeToWebReadable(
|
|
||||||
nodeStream: Readable,
|
|
||||||
): ReadableStream<Uint8Array> {
|
|
||||||
return new ReadableStream<Uint8Array>({
|
|
||||||
start(controller) {
|
|
||||||
nodeStream.on('data', (chunk: Buffer) => {
|
|
||||||
controller.enqueue(new Uint8Array(chunk))
|
|
||||||
})
|
|
||||||
nodeStream.on('end', () => controller.close())
|
|
||||||
nodeStream.on('error', err => controller.error(err))
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── unreachable ───────────────────────────────────────────────────
|
// ── unreachable ───────────────────────────────────────────────────
|
||||||
|
|
||||||
export function unreachable(
|
export function unreachable(
|
||||||
|
|||||||
@@ -152,8 +152,3 @@ export async function checkMetricsEnabled(): Promise<MetricsStatus> {
|
|||||||
// First-ever run on this machine: block on the network to populate disk.
|
// First-ever run on this machine: block on the network to populate disk.
|
||||||
return refreshMetricsStatus()
|
return refreshMetricsStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export for testing purposes only
|
|
||||||
export const _clearMetricsEnabledCacheForTesting = (): void => {
|
|
||||||
memoizedCheckMetrics.cache.clear()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -377,10 +377,3 @@ export function clearDeliveredDiagnosticsForFile(fileUri: string): void {
|
|||||||
deliveredDiagnostics.delete(fileUri)
|
deliveredDiagnostics.delete(fileUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get count of pending diagnostics (for monitoring)
|
|
||||||
*/
|
|
||||||
export function getPendingLSPDiagnosticCount(): number {
|
|
||||||
return pendingDiagnostics.size
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -39,19 +39,6 @@ let initializationGeneration = 0
|
|||||||
*/
|
*/
|
||||||
let initializationPromise: Promise<void> | undefined
|
let initializationPromise: Promise<void> | undefined
|
||||||
|
|
||||||
/**
|
|
||||||
* Test-only sync reset. shutdownLspServerManager() is async and tears down
|
|
||||||
* real connections; this only clears the module-scope singleton state so
|
|
||||||
* reinitializeLspServerManager() early-returns on 'not-started' in downstream
|
|
||||||
* tests on the same shard.
|
|
||||||
*/
|
|
||||||
export function _resetLspManagerForTesting(): void {
|
|
||||||
initializationState = 'not-started'
|
|
||||||
initializationError = undefined
|
|
||||||
initializationPromise = undefined
|
|
||||||
initializationGeneration++
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the singleton LSP server manager instance.
|
* Get the singleton LSP server manager instance.
|
||||||
* Returns undefined if not yet initialized, initialization failed, or still pending.
|
* Returns undefined if not yet initialized, initialization failed, or still pending.
|
||||||
|
|||||||
@@ -246,15 +246,6 @@ export function isMcpTool(tool: Tool): boolean {
|
|||||||
return tool.name?.startsWith('mcp__') || tool.isMcp === true
|
return tool.name?.startsWith('mcp__') || tool.isMcp === true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a command belongs to any MCP server
|
|
||||||
* @param command The command to check
|
|
||||||
* @returns True if the command is from an MCP server
|
|
||||||
*/
|
|
||||||
export function isMcpCommand(command: Command): boolean {
|
|
||||||
return command.name?.startsWith('mcp__') || command.isMcp === true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describe the file path for a given MCP config scope.
|
* Describe the file path for a given MCP config scope.
|
||||||
* @param scope The config scope ('user', 'project', 'local', or 'dynamic')
|
* @param scope The config scope ('user', 'project', 'local', or 'dynamic')
|
||||||
|
|||||||
@@ -100,11 +100,6 @@ export function resolveProjectContext(
|
|||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resetProjectContextCacheForTest(): void {
|
|
||||||
contextCache.clear()
|
|
||||||
lastPersistAt = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
export function listKnownProjects(): SkillLearningProjectRecord[] {
|
export function listKnownProjects(): SkillLearningProjectRecord[] {
|
||||||
const registry = readProjectsRegistry(getProjectsRegistryPath())
|
const registry = readProjectsRegistry(getProjectsRegistryPath())
|
||||||
return Object.values(registry.projects).sort((a, b) =>
|
return Object.values(registry.projects).sort((a, b) =>
|
||||||
|
|||||||
@@ -301,24 +301,3 @@ export function scanForSecrets(content: string): SecretMatch[] {
|
|||||||
export function getSecretLabel(ruleId: string): string {
|
export function getSecretLabel(ruleId: string): string {
|
||||||
return ruleIdToLabel(ruleId)
|
return ruleIdToLabel(ruleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Redact any matched secrets in-place with [REDACTED].
|
|
||||||
* Unlike scanForSecrets, this returns the content with spans replaced
|
|
||||||
* so the surrounding text can still be written to disk safely.
|
|
||||||
*/
|
|
||||||
let redactRules: RegExp[] | null = null
|
|
||||||
|
|
||||||
export function redactSecrets(content: string): string {
|
|
||||||
redactRules ??= SECRET_RULES.map(
|
|
||||||
r => new RegExp(r.source, (r.flags ?? '').replace('g', '') + 'g'),
|
|
||||||
)
|
|
||||||
for (const re of redactRules) {
|
|
||||||
// Replace only the captured group, not the full match — patterns include
|
|
||||||
// boundary chars (space, quote, ;) outside the group that must survive.
|
|
||||||
content = content.replace(re, (match, g1) =>
|
|
||||||
typeof g1 === 'string' ? match.replace(g1, '[REDACTED]') : '[REDACTED]',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -350,38 +350,3 @@ export async function stopTeamMemoryWatcher(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test-only: reset module state and optionally seed syncState.
|
|
||||||
* The feature('TEAMMEM') gate at the top of startTeamMemoryWatcher() is
|
|
||||||
* always false in bun test, so tests can't set syncState through the normal
|
|
||||||
* path. This helper lets tests drive notifyTeamMemoryWrite() /
|
|
||||||
* stopTeamMemoryWatcher() directly.
|
|
||||||
*
|
|
||||||
* `skipWatcher: true` marks the watcher as already-started without actually
|
|
||||||
* starting it. Tests that only exercise the schedulePush/flush path don't
|
|
||||||
* need a real watcher.
|
|
||||||
*/
|
|
||||||
export function _resetWatcherStateForTesting(opts?: {
|
|
||||||
syncState?: SyncState
|
|
||||||
skipWatcher?: boolean
|
|
||||||
pushSuppressedReason?: string | null
|
|
||||||
}): void {
|
|
||||||
watcher = null
|
|
||||||
debounceTimer = null
|
|
||||||
pushInProgress = false
|
|
||||||
hasPendingChanges = false
|
|
||||||
currentPushPromise = null
|
|
||||||
watcherStarted = opts?.skipWatcher ?? false
|
|
||||||
pushSuppressedReason = opts?.pushSuppressedReason ?? null
|
|
||||||
syncState = opts?.syncState ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test-only: start the real fs.watch on a specified directory.
|
|
||||||
* Used by the fd-count regression test — startTeamMemoryWatcher() is gated
|
|
||||||
* by feature('TEAMMEM') which is false under bun test.
|
|
||||||
*/
|
|
||||||
export function _startFileWatcherForTesting(dir: string): Promise<void> {
|
|
||||||
return startFileWatcher(dir)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1057,13 +1057,6 @@ export function activateConditionalSkillsForPaths(
|
|||||||
return activated
|
return activated
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of pending conditional skills (for testing/debugging).
|
|
||||||
*/
|
|
||||||
export function getConditionalSkillCount(): number {
|
|
||||||
return conditionalSkills.size
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears dynamic skill state (for testing).
|
* Clears dynamic skill state (for testing).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1106,7 +1106,7 @@ export async function getQueuedCommandAttachments(
|
|||||||
// Include both 'prompt' and 'task-notification' commands as attachments.
|
// Include both 'prompt' and 'task-notification' commands as attachments.
|
||||||
// During proactive agentic loops, task-notification commands would otherwise
|
// During proactive agentic loops, task-notification commands would otherwise
|
||||||
// stay in the queue permanently (useQueueProcessor can't run while a query
|
// stay in the queue permanently (useQueueProcessor can't run while a query
|
||||||
// is active), causing hasPendingNotifications() to return true and Sleep to
|
// is active), causing hasCommandsInQueue() to return true and Sleep to
|
||||||
// wake immediately with 0ms duration in an infinite loop.
|
// wake immediately with 0ms duration in an infinite loop.
|
||||||
const filtered = queuedCommands.filter(_ =>
|
const filtered = queuedCommands.filter(_ =>
|
||||||
INLINE_NOTIFICATION_MODES.has(_.mode),
|
INLINE_NOTIFICATION_MODES.has(_.mode),
|
||||||
|
|||||||
@@ -91,17 +91,13 @@ export async function runFilePersistence(
|
|||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result: FilesPersistedEventData
|
// environmentKind === 'byoc' is guaranteed by the early return above
|
||||||
if (environmentKind === 'byoc') {
|
const result = await executeBYOCPersistence(
|
||||||
result = await executeBYOCPersistence(
|
turnStartTime,
|
||||||
turnStartTime,
|
config,
|
||||||
config,
|
outputsDir,
|
||||||
outputsDir,
|
signal,
|
||||||
signal,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
result = await executeCloudPersistence()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing to report
|
// Nothing to report
|
||||||
if (result.files.length === 0 && result.failed.length === 0) {
|
if (result.files.length === 0 && result.failed.length === 0) {
|
||||||
@@ -240,16 +236,6 @@ async function executeBYOCPersistence(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute Cloud (1P) mode persistence.
|
|
||||||
* TODO: Read file_id from xattr on output files. xattr-based file IDs are
|
|
||||||
* currently being added for 1P environments.
|
|
||||||
*/
|
|
||||||
function executeCloudPersistence(): FilesPersistedEventData {
|
|
||||||
logDebug('Cloud mode: xattr-based file ID reading not yet implemented')
|
|
||||||
return { files: [], failed: [] }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute file persistence and emit result via callback.
|
* Execute file persistence and emit result via callback.
|
||||||
* Handles errors internally.
|
* Handles errors internally.
|
||||||
|
|||||||
@@ -485,38 +485,6 @@ export function popAllEditable(
|
|||||||
return { text: newInput, cursorOffset, images }
|
return { text: newInput, cursorOffset, images }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Backward-compatible aliases (deprecated — prefer new names)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/** @deprecated Use subscribeToCommandQueue */
|
|
||||||
export const subscribeToPendingNotifications = subscribeToCommandQueue
|
|
||||||
|
|
||||||
/** @deprecated Use getCommandQueueSnapshot */
|
|
||||||
export function getPendingNotificationsSnapshot(): readonly QueuedCommand[] {
|
|
||||||
return snapshot
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use hasCommandsInQueue */
|
|
||||||
export const hasPendingNotifications = hasCommandsInQueue
|
|
||||||
|
|
||||||
/** @deprecated Use getCommandQueueLength */
|
|
||||||
export const getPendingNotificationsCount = getCommandQueueLength
|
|
||||||
|
|
||||||
/** @deprecated Use recheckCommandQueue */
|
|
||||||
export const recheckPendingNotifications = recheckCommandQueue
|
|
||||||
|
|
||||||
/** @deprecated Use dequeue */
|
|
||||||
export function dequeuePendingNotification(): QueuedCommand | undefined {
|
|
||||||
return dequeue()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use resetCommandQueue */
|
|
||||||
export const resetPendingNotifications = resetCommandQueue
|
|
||||||
|
|
||||||
/** @deprecated Use clearCommandQueue */
|
|
||||||
export const clearPendingNotifications = clearCommandQueue
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get commands at or above a given priority level without removing them.
|
* Get commands at or above a given priority level without removing them.
|
||||||
* Useful for mid-chain draining where only urgent items should be processed.
|
* Useful for mid-chain draining where only urgent items should be processed.
|
||||||
|
|||||||
Reference in New Issue
Block a user