mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 22:35:51 +00:00
* style(B1-1): 格式化 ink/buddy/cli/context/screens/tasks/services/keybindings/state (43 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 修复了 Box.tsx 和 ScrollBox.tsx 中无效的 global.d.ts import。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-2): 格式化 commands (79 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-3): 格式化 components/messages,permissions,mcp,sandbox,shell (104 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-4): 格式化 components/PromptInput,FeedbackSurvey,tasks,agents,skills,design-system,wizard (73 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-5): 格式化 components其余 + hooks + tools (232 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-6): 格式化 main/entrypoints/utils/moreright (21 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 更新 README,新增 Run.ps1/TODO.md,删除 V6.md - README.md: 大幅重写,更详细版本历史和配置示例 - Run.ps1: 新增 Windows 启动脚本 - TODO.md: 新增包完成清单 - V6.md: 删除(架构重构规划已不适用) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复以前的问题 * fix: 修复 login 面板的问题 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
166 lines
5.0 KiB
TypeScript
166 lines
5.0 KiB
TypeScript
import * as React from 'react'
|
|
import { useCallback } from 'react'
|
|
import { Select } from '../../../components/CustomSelect/select.js'
|
|
import { Box, Text } from '../../../ink.js'
|
|
import type { ToolPermissionContext } from '../../../Tool.js'
|
|
import type {
|
|
PermissionBehavior,
|
|
PermissionRule,
|
|
PermissionRuleValue,
|
|
} from '../../../utils/permissions/PermissionRule.js'
|
|
import {
|
|
applyPermissionUpdate,
|
|
persistPermissionUpdate,
|
|
} from '../../../utils/permissions/PermissionUpdate.js'
|
|
import { permissionRuleValueToString } from '../../../utils/permissions/permissionRuleParser.js'
|
|
import {
|
|
detectUnreachableRules,
|
|
type UnreachableRule,
|
|
} from '../../../utils/permissions/shadowedRuleDetection.js'
|
|
import { SandboxManager } from '../../../utils/sandbox/sandbox-adapter.js'
|
|
import {
|
|
type EditableSettingSource,
|
|
SOURCES,
|
|
} from '../../../utils/settings/constants.js'
|
|
import { getRelativeSettingsFilePathForSource } from '../../../utils/settings/settings.js'
|
|
import { plural } from '../../../utils/stringUtils.js'
|
|
import type { OptionWithDescription } from '../../CustomSelect/select.js'
|
|
import { Dialog } from '../../design-system/Dialog.js'
|
|
import { PermissionRuleDescription } from './PermissionRuleDescription.js'
|
|
|
|
export function optionForPermissionSaveDestination(
|
|
saveDestination: EditableSettingSource,
|
|
): OptionWithDescription {
|
|
switch (saveDestination) {
|
|
case 'localSettings':
|
|
return {
|
|
label: 'Project settings (local)',
|
|
description: `Saved in ${getRelativeSettingsFilePathForSource('localSettings')}`,
|
|
value: saveDestination,
|
|
}
|
|
case 'projectSettings':
|
|
return {
|
|
label: 'Project settings',
|
|
description: `Checked in at ${getRelativeSettingsFilePathForSource('projectSettings')}`,
|
|
value: saveDestination,
|
|
}
|
|
case 'userSettings':
|
|
return {
|
|
label: 'User settings',
|
|
description: `Saved in at ~/.claude/settings.json`,
|
|
value: saveDestination,
|
|
}
|
|
}
|
|
}
|
|
|
|
type Props = {
|
|
onAddRules: (rules: PermissionRule[], unreachable?: UnreachableRule[]) => void
|
|
onCancel: () => void
|
|
ruleValues: PermissionRuleValue[]
|
|
ruleBehavior: PermissionBehavior
|
|
initialContext: ToolPermissionContext
|
|
setToolPermissionContext: (newContext: ToolPermissionContext) => void
|
|
}
|
|
|
|
export function AddPermissionRules({
|
|
onAddRules,
|
|
onCancel,
|
|
ruleValues,
|
|
ruleBehavior,
|
|
initialContext,
|
|
setToolPermissionContext,
|
|
}: Props): React.ReactNode {
|
|
const allOptions = SOURCES.map(optionForPermissionSaveDestination)
|
|
|
|
const onSelect = useCallback(
|
|
(selectedValue: string) => {
|
|
if (selectedValue === 'cancel') {
|
|
onCancel()
|
|
return
|
|
} else if ((SOURCES as readonly string[]).includes(selectedValue)) {
|
|
const destination = selectedValue as EditableSettingSource
|
|
|
|
const updatedContext = applyPermissionUpdate(initialContext, {
|
|
type: 'addRules',
|
|
rules: ruleValues,
|
|
behavior: ruleBehavior,
|
|
destination,
|
|
})
|
|
|
|
// Persist to settings
|
|
persistPermissionUpdate({
|
|
type: 'addRules',
|
|
rules: ruleValues,
|
|
behavior: ruleBehavior,
|
|
destination,
|
|
})
|
|
|
|
setToolPermissionContext(updatedContext)
|
|
|
|
const rules: PermissionRule[] = ruleValues.map(ruleValue => ({
|
|
ruleValue,
|
|
ruleBehavior,
|
|
source: destination,
|
|
}))
|
|
|
|
// Check for unreachable rules among the ones we just added
|
|
const sandboxAutoAllowEnabled =
|
|
SandboxManager.isSandboxingEnabled() &&
|
|
SandboxManager.isAutoAllowBashIfSandboxedEnabled()
|
|
const allUnreachable = detectUnreachableRules(updatedContext, {
|
|
sandboxAutoAllowEnabled,
|
|
})
|
|
|
|
// Filter to only rules we just added
|
|
const newUnreachable = allUnreachable.filter(u =>
|
|
ruleValues.some(
|
|
rv =>
|
|
rv.toolName === u.rule.ruleValue.toolName &&
|
|
rv.ruleContent === u.rule.ruleValue.ruleContent,
|
|
),
|
|
)
|
|
|
|
onAddRules(
|
|
rules,
|
|
newUnreachable.length > 0 ? newUnreachable : undefined,
|
|
)
|
|
}
|
|
},
|
|
[
|
|
onAddRules,
|
|
onCancel,
|
|
ruleValues,
|
|
ruleBehavior,
|
|
initialContext,
|
|
setToolPermissionContext,
|
|
],
|
|
)
|
|
|
|
const title = `Add ${ruleBehavior} permission ${plural(ruleValues.length, 'rule')}`
|
|
|
|
return (
|
|
<Dialog title={title} onCancel={onCancel} color="permission">
|
|
<Box flexDirection="column" paddingX={2}>
|
|
{ruleValues.map(ruleValue => (
|
|
<Box
|
|
flexDirection="column"
|
|
key={permissionRuleValueToString(ruleValue)}
|
|
>
|
|
<Text bold>{permissionRuleValueToString(ruleValue)}</Text>
|
|
<PermissionRuleDescription ruleValue={ruleValue} />
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
|
|
<Box flexDirection="column" marginY={1}>
|
|
<Text>
|
|
{ruleValues.length === 1
|
|
? 'Where should this rule be saved?'
|
|
: 'Where should these rules be saved?'}
|
|
</Text>
|
|
<Select options={allOptions} onChange={onSelect} />
|
|
</Box>
|
|
</Dialog>
|
|
)
|
|
}
|