style: 完成所有文件的lint

This commit is contained in:
claude-code-best
2026-05-01 21:39:30 +08:00
parent d136872cc9
commit 6182015005
1333 changed files with 68255 additions and 77882 deletions

View File

@@ -1,72 +1,54 @@
import { feature } from 'bun:bundle'
import { APIUserAbortError } from '@anthropic-ai/sdk'
import * as React from 'react'
import { useCallback } from 'react'
import { feature } from 'bun:bundle';
import { APIUserAbortError } from '@anthropic-ai/sdk';
import * as React from 'react';
import { useCallback } from 'react';
import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent,
} from 'src/services/analytics/index.js'
import { sanitizeToolNameForAnalytics } from 'src/services/analytics/metadata.js'
import type { ToolUseConfirm } from '../components/permissions/PermissionRequest.js'
import { Text } from '@anthropic/ink'
import type {
ToolPermissionContext,
Tool as ToolType,
ToolUseContext,
} from '../Tool.js'
} from 'src/services/analytics/index.js';
import { sanitizeToolNameForAnalytics } from 'src/services/analytics/metadata.js';
import type { ToolUseConfirm } from '../components/permissions/PermissionRequest.js';
import { Text } from '@anthropic/ink';
import type { ToolPermissionContext, Tool as ToolType, ToolUseContext } from '../Tool.js';
import {
consumeSpeculativeClassifierCheck,
peekSpeculativeClassifierCheck,
} from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js'
import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js'
import type { AssistantMessage } from '../types/message.js'
import { recordAutoModeDenial } from '../utils/autoModeDenials.js'
} from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js';
import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js';
import type { AssistantMessage } from '../types/message.js';
import { recordAutoModeDenial } from '../utils/autoModeDenials.js';
import {
clearClassifierChecking,
setClassifierApproval,
setYoloClassifierApproval,
} from '../utils/classifierApprovals.js'
import { logForDebugging } from '../utils/debug.js'
import { AbortError } from '../utils/errors.js'
import { logError } from '../utils/log.js'
import type { PermissionDecision } from '../utils/permissions/PermissionResult.js'
import { hasPermissionsToUseTool } from '../utils/permissions/permissions.js'
import { jsonStringify } from '../utils/slowOperations.js'
import { handleCoordinatorPermission } from './toolPermission/handlers/coordinatorHandler.js'
import { handleInteractivePermission } from './toolPermission/handlers/interactiveHandler.js'
import { handleSwarmWorkerPermission } from './toolPermission/handlers/swarmWorkerHandler.js'
import {
createPermissionContext,
createPermissionQueueOps,
} from './toolPermission/PermissionContext.js'
import { logPermissionDecision } from './toolPermission/permissionLogging.js'
} from '../utils/classifierApprovals.js';
import { logForDebugging } from '../utils/debug.js';
import { AbortError } from '../utils/errors.js';
import { logError } from '../utils/log.js';
import type { PermissionDecision } from '../utils/permissions/PermissionResult.js';
import { hasPermissionsToUseTool } from '../utils/permissions/permissions.js';
import { jsonStringify } from '../utils/slowOperations.js';
import { handleCoordinatorPermission } from './toolPermission/handlers/coordinatorHandler.js';
import { handleInteractivePermission } from './toolPermission/handlers/interactiveHandler.js';
import { handleSwarmWorkerPermission } from './toolPermission/handlers/swarmWorkerHandler.js';
import { createPermissionContext, createPermissionQueueOps } from './toolPermission/PermissionContext.js';
import { logPermissionDecision } from './toolPermission/permissionLogging.js';
export type CanUseToolFn<
Input extends Record<string, unknown> = Record<string, unknown>,
> = (
export type CanUseToolFn<Input extends Record<string, unknown> = Record<string, unknown>> = (
tool: ToolType,
input: Input,
toolUseContext: ToolUseContext,
assistantMessage: AssistantMessage,
toolUseID: string,
forceDecision?: PermissionDecision<Input>,
) => Promise<PermissionDecision<Input>>
) => Promise<PermissionDecision<Input>>;
function useCanUseTool(
setToolUseConfirmQueue: React.Dispatch<
React.SetStateAction<ToolUseConfirm[]>
>,
setToolUseConfirmQueue: React.Dispatch<React.SetStateAction<ToolUseConfirm[]>>,
setToolPermissionContext: (context: ToolPermissionContext) => void,
): CanUseToolFn {
return useCallback<CanUseToolFn>(
async (
tool,
input,
toolUseContext,
assistantMessage,
toolUseID,
forceDecision,
) => {
async (tool, input, toolUseContext, assistantMessage, toolUseID, forceDecision) => {
return new Promise(resolve => {
const ctx = createPermissionContext(
tool,
@@ -76,20 +58,14 @@ function useCanUseTool(
toolUseID,
setToolPermissionContext,
createPermissionQueueOps(setToolUseConfirmQueue),
)
);
if (ctx.resolveIfAborted(resolve)) return
if (ctx.resolveIfAborted(resolve)) return;
const decisionPromise =
forceDecision !== undefined
? Promise.resolve(forceDecision)
: hasPermissionsToUseTool(
tool,
input,
toolUseContext,
assistantMessage,
toolUseID,
)
: hasPermissionsToUseTool(tool, input, toolUseContext, assistantMessage, toolUseID);
return decisionPromise
.then(async result => {
@@ -97,52 +73,44 @@ function useCanUseTool(
if (process.env.USER_TYPE === 'ant') {
logEvent('tengu_internal_tool_permission_decision', {
toolName: sanitizeToolNameForAnalytics(tool.name),
behavior:
result.behavior as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
behavior: result.behavior as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
// Note: input contains code/filepaths, only log for ants
input: jsonStringify(
input,
) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
messageID:
ctx.messageId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
input: jsonStringify(input) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
messageID: ctx.messageId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
isMcp: tool.isMcp ?? false,
})
});
}
// Has permissions to use tool, granted in config
if (result.behavior === 'allow') {
if (ctx.resolveIfAborted(resolve)) return
if (ctx.resolveIfAborted(resolve)) return;
// Track auto mode classifier approvals for UI display
if (
feature('TRANSCRIPT_CLASSIFIER') &&
result.decisionReason?.type === 'classifier' &&
result.decisionReason.classifier === 'auto-mode'
) {
setYoloClassifierApproval(
toolUseID,
result.decisionReason.reason,
)
setYoloClassifierApproval(toolUseID, result.decisionReason.reason);
}
ctx.logDecision({ decision: 'accept', source: 'config' })
ctx.logDecision({ decision: 'accept', source: 'config' });
resolve(
ctx.buildAllow(result.updatedInput ?? input, {
decisionReason: result.decisionReason,
}),
)
return
);
return;
}
const appState = toolUseContext.getAppState()
const appState = toolUseContext.getAppState();
const description = await tool.description(input as never, {
isNonInteractiveSession:
toolUseContext.options.isNonInteractiveSession,
isNonInteractiveSession: toolUseContext.options.isNonInteractiveSession,
toolPermissionContext: appState.toolPermissionContext,
tools: toolUseContext.options.tools,
})
});
if (ctx.resolveIfAborted(resolve)) return
if (ctx.resolveIfAborted(resolve)) return;
// Does not have permissions to use tool, check the behavior
switch (result.behavior) {
@@ -156,7 +124,7 @@ function useCanUseTool(
toolUseID,
},
{ decision: 'reject', source: 'config' },
)
);
if (
feature('TRANSCRIPT_CLASSIFIER') &&
result.decisionReason?.type === 'classifier' &&
@@ -167,49 +135,40 @@ function useCanUseTool(
display: description,
reason: result.decisionReason.reason ?? '',
timestamp: Date.now(),
})
});
toolUseContext.addNotification?.({
key: 'auto-mode-denied',
priority: 'immediate',
jsx: (
<>
<Text color="error">
{tool.userFacingName(input).toLowerCase()} denied by
auto mode
</Text>
<Text color="error">{tool.userFacingName(input).toLowerCase()} denied by auto mode</Text>
<Text dimColor> · /permissions</Text>
</>
),
})
});
}
resolve(result)
return
resolve(result);
return;
}
case 'ask': {
// For coordinator workers, await automated checks before showing dialog.
// Background workers should only interrupt the user when automated checks can't decide.
if (
appState.toolPermissionContext
.awaitAutomatedChecksBeforeDialog
) {
const coordinatorDecision = await handleCoordinatorPermission(
{
ctx,
...(feature('BASH_CLASSIFIER')
? {
pendingClassifierCheck:
result.pendingClassifierCheck,
}
: {}),
updatedInput: result.updatedInput,
suggestions: result.suggestions,
permissionMode: appState.toolPermissionContext.mode,
},
)
if (appState.toolPermissionContext.awaitAutomatedChecksBeforeDialog) {
const coordinatorDecision = await handleCoordinatorPermission({
ctx,
...(feature('BASH_CLASSIFIER')
? {
pendingClassifierCheck: result.pendingClassifierCheck,
}
: {}),
updatedInput: result.updatedInput,
suggestions: result.suggestions,
permissionMode: appState.toolPermissionContext.mode,
});
if (coordinatorDecision) {
resolve(coordinatorDecision)
return
resolve(coordinatorDecision);
return;
}
// null means neither automated check resolved -- fall through to dialog below.
// Hooks already ran, classifier already consumed.
@@ -217,7 +176,7 @@ function useCanUseTool(
// After awaiting automated checks, verify the request wasn't aborted
// while we were waiting. Without this check, a stale dialog could appear.
if (ctx.resolveIfAborted(resolve)) return
if (ctx.resolveIfAborted(resolve)) return;
// For swarm workers, try classifier auto-approval then
// forward permission requests to the leader via mailbox.
@@ -231,10 +190,10 @@ function useCanUseTool(
: {}),
updatedInput: result.updatedInput,
suggestions: result.suggestions,
})
});
if (swarmDecision) {
resolve(swarmDecision)
return
resolve(swarmDecision);
return;
}
// Grace period: wait up to 2s for speculative classifier
@@ -243,12 +202,9 @@ function useCanUseTool(
feature('BASH_CLASSIFIER') &&
result.pendingClassifierCheck &&
tool.name === BASH_TOOL_NAME &&
!appState.toolPermissionContext
.awaitAutomatedChecksBeforeDialog
!appState.toolPermissionContext.awaitAutomatedChecksBeforeDialog
) {
const speculativePromise = peekSpeculativeClassifierCheck(
(input as { command: string }).command,
)
const speculativePromise = peekSpeculativeClassifierCheck((input as { command: string }).command);
if (speculativePromise) {
const raceResult = await Promise.race([
speculativePromise.then(r => ({
@@ -259,9 +215,9 @@ function useCanUseTool(
// eslint-disable-next-line no-restricted-syntax -- resolves with a value, not void
setTimeout(res, 2000, { type: 'timeout' as const }),
),
])
]);
if (ctx.resolveIfAborted(resolve)) return
if (ctx.resolveIfAborted(resolve)) return;
if (
raceResult.type === 'result' &&
@@ -270,34 +226,27 @@ function useCanUseTool(
feature('BASH_CLASSIFIER')
) {
// Classifier approved within grace period — skip dialog
void consumeSpeculativeClassifierCheck(
(input as { command: string }).command,
)
void consumeSpeculativeClassifierCheck((input as { command: string }).command);
const matchedRule =
raceResult.result.matchedDescription ?? undefined
const matchedRule = raceResult.result.matchedDescription ?? undefined;
if (matchedRule) {
setClassifierApproval(toolUseID, matchedRule)
setClassifierApproval(toolUseID, matchedRule);
}
ctx.logDecision({
decision: 'accept',
source: { type: 'classifier' },
})
});
resolve(
ctx.buildAllow(
result.updatedInput ??
(input as Record<string, unknown>),
{
decisionReason: {
type: 'classifier' as const,
classifier: 'bash_allow' as const,
reason: `Allowed by prompt rule: "${raceResult.result.matchedDescription}"`,
},
ctx.buildAllow(result.updatedInput ?? (input as Record<string, unknown>), {
decisionReason: {
type: 'classifier' as const,
classifier: 'bash_allow' as const,
reason: `Allowed by prompt rule: "${raceResult.result.matchedDescription}"`,
},
),
)
return
}),
);
return;
}
// Timeout or no match — fall through to show dialog
}
@@ -309,46 +258,37 @@ function useCanUseTool(
ctx,
description,
result,
awaitAutomatedChecksBeforeDialog:
appState.toolPermissionContext
.awaitAutomatedChecksBeforeDialog,
bridgeCallbacks: feature('BRIDGE_MODE')
? appState.replBridgePermissionCallbacks
: undefined,
awaitAutomatedChecksBeforeDialog: appState.toolPermissionContext.awaitAutomatedChecksBeforeDialog,
bridgeCallbacks: feature('BRIDGE_MODE') ? appState.replBridgePermissionCallbacks : undefined,
channelCallbacks:
feature('KAIROS') || feature('KAIROS_CHANNELS')
? appState.channelPermissionCallbacks
: undefined,
feature('KAIROS') || feature('KAIROS_CHANNELS') ? appState.channelPermissionCallbacks : undefined,
},
resolve,
)
);
return
return;
}
}
})
.catch(error => {
if (
error instanceof AbortError ||
error instanceof APIUserAbortError
) {
if (error instanceof AbortError || error instanceof APIUserAbortError) {
logForDebugging(
`Permission check threw ${error.constructor.name} for tool=${tool.name}: ${error.message}`,
)
ctx.logCancelled()
resolve(ctx.cancelAndAbort(undefined, true))
);
ctx.logCancelled();
resolve(ctx.cancelAndAbort(undefined, true));
} else {
logError(error)
resolve(ctx.cancelAndAbort(undefined, true))
logError(error);
resolve(ctx.cancelAndAbort(undefined, true));
}
})
.finally(() => {
clearClassifierChecking(toolUseID)
})
})
clearClassifierChecking(toolUseID);
});
});
},
[setToolUseConfirmQueue, setToolPermissionContext],
)
);
}
export default useCanUseTool
export default useCanUseTool;