mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-05 00:45:29 +08:00
chore: 将 .claude/ 和 CLAUDE.local.md 从 git 跟踪中排除
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
---
|
||||
description: 执行带有请求节流的任务,可以控制工具调用的频率
|
||||
---
|
||||
|
||||
# 节流任务执行
|
||||
|
||||
你现在进入了节流模式。在这个模式下,你需要:
|
||||
|
||||
## 节流规则
|
||||
|
||||
1. **工具调用间隔**:每次调用工具后,等待至少 2 秒再调用下一个工具
|
||||
2. **并行限制**:同时最多只能并行调用 2 个工具(原本可能更多)
|
||||
3. **批处理优化**:优先将相关的操作合并到一个工具调用中
|
||||
4. **进度提示**:每次等待时向用户说明正在节流等待
|
||||
|
||||
## 执行方式
|
||||
|
||||
- 对于读取操作(Read, Glob, Grep),可以适当放宽并行限制
|
||||
- 对于写入操作(Write, Edit),严格遵守间隔要求
|
||||
- 对于 API 调用(Bash 中的 API 请求),必须串行执行
|
||||
|
||||
## 用户任务
|
||||
|
||||
请按照上述节流规则执行以下任务:
|
||||
|
||||
{{PROMPT}}
|
||||
|
||||
---
|
||||
|
||||
**注意**:完成任务后,你将自动退出节流模式,恢复正常的工具调用频率。
|
||||
@@ -1,407 +0,0 @@
|
||||
# 心跳配置功能重构计划
|
||||
|
||||
## 概述
|
||||
|
||||
将心跳配置从"选择curl命令"模式重构为"基于URL的可配置心跳"模式。
|
||||
|
||||
**核心变化**:
|
||||
- ✅ 支持多个URL同时发送心跳
|
||||
- ✅ 每个URL独立配置间隔时间
|
||||
- ✅ curl命令作为导入模板,可解析为URL配置
|
||||
- ✅ 完全替换旧的基于curl选择的方式
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 数据模型
|
||||
|
||||
**新表:heartbeat_url_configs**
|
||||
```typescript
|
||||
{
|
||||
id: number;
|
||||
name: string; // URL配置名称
|
||||
url: string; // 目标URL
|
||||
method: string; // HTTP方法(GET/POST/PUT/DELETE)
|
||||
headers: Record<string, string>; // 请求头(JSONB)
|
||||
body: string | null; // 请求体
|
||||
intervalSeconds: number; // 独立的心跳间隔(10-3600秒)
|
||||
isEnabled: boolean; // 是否启用此配置
|
||||
lastSuccessAt: Date | null; // 统计:上次成功时间
|
||||
lastErrorAt: Date | null; // 统计:上次失败时间
|
||||
lastErrorMessage: string | null; // 统计:上次错误信息
|
||||
successCount: number; // 统计:成功次数
|
||||
failureCount: number; // 统计:失败次数
|
||||
providerId: number | null; // 关联的供应商ID(可选)
|
||||
model: string | null; // 模型名称(展示用)
|
||||
endpoint: string | null; // 端点路径(展示用)
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
```
|
||||
|
||||
**修改表:heartbeat_settings**
|
||||
```typescript
|
||||
{
|
||||
id: number;
|
||||
enabled: boolean; // 全局开关(保留)
|
||||
// 删除:intervalSeconds, savedCurls, selectedCurlIndex
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
```
|
||||
|
||||
### 心跳执行逻辑
|
||||
|
||||
**ProviderHeartbeat类重构**:
|
||||
```typescript
|
||||
class ProviderHeartbeat {
|
||||
// 多定时器管理:Map<configId, timer>
|
||||
private static timers: Map<number, NodeJS.Timeout> = new Map();
|
||||
|
||||
// 启动:为每个启用的URL配置创建独立定时器
|
||||
static async start() {
|
||||
const configs = await findEnabledHeartbeatUrlConfigs();
|
||||
for (const config of configs) {
|
||||
this.startConfigTimer(config);
|
||||
}
|
||||
}
|
||||
|
||||
// 停止:清除所有定时器
|
||||
static stop() {
|
||||
for (const timer of this.timers.values()) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
this.timers.clear();
|
||||
}
|
||||
|
||||
// 单个配置的定时器
|
||||
private static startConfigTimer(config: HeartbeatUrlConfig) {
|
||||
const interval = setInterval(() => {
|
||||
this.sendHeartbeat(config);
|
||||
}, config.intervalSeconds * 1000);
|
||||
this.timers.set(config.id, interval);
|
||||
}
|
||||
|
||||
// 发送心跳并记录成功/失败
|
||||
private static async sendHeartbeat(config: HeartbeatUrlConfig) {
|
||||
const response = await fetch(config.url, {
|
||||
method: config.method,
|
||||
headers: config.headers,
|
||||
body: config.body,
|
||||
signal: AbortSignal.timeout(10000),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await recordHeartbeatSuccess(config.id);
|
||||
} else {
|
||||
await recordHeartbeatFailure(config.id, errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 前端UI设计
|
||||
|
||||
**页面布局**:
|
||||
```
|
||||
/settings/heartbeat/page.tsx
|
||||
├── GlobalSettingsCard(全局开关)
|
||||
├── CurlHistorySection(curl历史记录 + 导入按钮)
|
||||
└── UrlConfigsSection(URL配置列表 + 新建/编辑/删除)
|
||||
```
|
||||
|
||||
**组件拆分**:
|
||||
- `global-settings-card.tsx` - 全局开关卡片
|
||||
- `curl-history-section.tsx` - curl历史记录区域
|
||||
- `curl-history-card.tsx` - 单个curl历史卡片
|
||||
- `url-configs-section.tsx` - URL配置列表区域
|
||||
- `url-config-card.tsx` - 单个URL配置卡片
|
||||
- `url-config-dialog.tsx` - 新建/编辑对话框
|
||||
- `_lib/hooks.ts` - 自定义hooks(useHeartbeatPageData)
|
||||
|
||||
**curl导入流程**:
|
||||
1. 用户点击curl历史卡片上的"导入"按钮
|
||||
2. 使用`parseCurlCommand()`解析curl命令
|
||||
3. 自动打开新建对话框,表单预填充解析后的数据
|
||||
4. 用户修改后保存,创建URL配置
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### 阶段1:数据库和Repository层
|
||||
|
||||
1. **修改schema.ts**
|
||||
- 添加`heartbeatUrlConfigs`表定义
|
||||
- 修改`heartbeatSettings`表定义(删除3个字段)
|
||||
|
||||
2. **生成和审查迁移**
|
||||
```bash
|
||||
bun run db:generate
|
||||
# 检查生成的 drizzle/0061_*.sql
|
||||
# 确保数据迁移逻辑正确(将选中的curl转为第一个URL配置)
|
||||
```
|
||||
|
||||
3. **创建repository/heartbeat-url-configs.ts**
|
||||
- 接口:`HeartbeatUrlConfig`、`CreateHeartbeatUrlConfigInput`、`UpdateHeartbeatUrlConfigInput`
|
||||
- 函数:
|
||||
- `findAllHeartbeatUrlConfigs()` - 获取所有配置
|
||||
- `findEnabledHeartbeatUrlConfigs()` - 获取启用的配置
|
||||
- `findHeartbeatUrlConfigById(id)` - 根据ID获取
|
||||
- `createHeartbeatUrlConfig(input)` - 创建配置
|
||||
- `updateHeartbeatUrlConfig(id, input)` - 更新配置
|
||||
- `deleteHeartbeatUrlConfig(id)` - 删除配置
|
||||
- `recordHeartbeatSuccess(id)` - 记录成功
|
||||
- `recordHeartbeatFailure(id, errorMessage)` - 记录失败
|
||||
|
||||
4. **修改repository/heartbeat-settings.ts**
|
||||
- 简化为只管理全局开关
|
||||
- 删除`savedCurls`和`selectedCurlIndex`相关逻辑
|
||||
- 保持`getHeartbeatSettings()`和`updateHeartbeatSettings()`接口
|
||||
|
||||
5. **运行迁移**
|
||||
```bash
|
||||
bun run db:migrate
|
||||
```
|
||||
|
||||
### 阶段2:Action层
|
||||
|
||||
6. **创建actions/heartbeat-url-configs.ts**
|
||||
- `fetchHeartbeatUrlConfigs()` - 获取所有配置
|
||||
- `createHeartbeatUrlConfigAction(input)` - 创建配置
|
||||
- `updateHeartbeatUrlConfigAction(id, input)` - 更新配置
|
||||
- `deleteHeartbeatUrlConfigAction(id)` - 删除配置
|
||||
- 验证规则:
|
||||
- 名称不能为空
|
||||
- URL不能为空
|
||||
- 间隔时间范围:10-3600秒
|
||||
- 权限检查:仅admin可操作
|
||||
- 副作用:修改配置后重启心跳任务
|
||||
|
||||
7. **修改actions/heartbeat-settings.ts**
|
||||
- 简化为只管理全局开关
|
||||
- 保持`fetchHeartbeatSettings()`和`saveHeartbeatSettings()`
|
||||
- 开关变化时重启心跳任务
|
||||
|
||||
### 阶段3:心跳执行逻辑
|
||||
|
||||
8. **重构lib/provider-heartbeat.ts**
|
||||
- 添加`timers: Map<number, NodeJS.Timeout>`
|
||||
- 修改`start()`:为每个启用的配置创建定时器
|
||||
- 修改`stop()`:清除所有定时器
|
||||
- 新增`startConfigTimer(config)`:创建单个配置的定时器
|
||||
- 新增`stopConfigTimer(configId)`:停止单个配置的定时器
|
||||
- 修改`sendHeartbeat(config)`:发送请求并记录结果
|
||||
- 删除curl解析逻辑(不再需要)
|
||||
|
||||
9. **修改app/v1/_lib/proxy/forwarder.ts**
|
||||
- 删除或注释掉`addSuccessfulCurl()`调用(第357-367行)
|
||||
- curl历史功能迁移到独立模块(可选)
|
||||
|
||||
### 阶段4:i18n文案
|
||||
|
||||
10. **更新翻译文件**
|
||||
- `messages/zh-CN/settings/heartbeat.json`
|
||||
- `messages/zh-TW/settings/heartbeat.json`
|
||||
- `messages/en/settings/heartbeat.json`
|
||||
- `messages/ja/settings/heartbeat.json`
|
||||
- `messages/ru/settings/heartbeat.json`
|
||||
|
||||
新增key:
|
||||
- `section.global.*` - 全局设置区域
|
||||
- `section.curlHistory.*` - curl历史区域
|
||||
- `section.urlConfigs.*` - URL配置区域
|
||||
- `form.name.*` - 配置名称字段
|
||||
- `form.url.*` - URL字段
|
||||
- `form.method.*` - HTTP方法字段
|
||||
- `form.headers.*` - 请求头字段
|
||||
- `form.body.*` - 请求体字段
|
||||
- `form.isEnabled.*` - 启用开关
|
||||
- `form.stats.*` - 统计信息
|
||||
- `form.createButton`、`importButton`等
|
||||
|
||||
### 阶段5:前端UI
|
||||
|
||||
11. **创建组件**
|
||||
- `app/[locale]/settings/heartbeat/_components/global-settings-card.tsx`
|
||||
- Switch组件:全局开关
|
||||
- 说明文字
|
||||
|
||||
- `app/[locale]/settings/heartbeat/_components/curl-history-section.tsx`
|
||||
- 区域标题和描述
|
||||
- curl历史卡片列表
|
||||
- 空状态提示
|
||||
|
||||
- `app/[locale]/settings/heartbeat/_components/curl-history-card.tsx`
|
||||
- 显示:供应商名、端点、模型、时间
|
||||
- 导入按钮
|
||||
|
||||
- `app/[locale]/settings/heartbeat/_components/url-configs-section.tsx`
|
||||
- 区域标题和描述
|
||||
- 新建按钮
|
||||
- URL配置卡片列表
|
||||
- 空状态提示
|
||||
|
||||
- `app/[locale]/settings/heartbeat/_components/url-config-card.tsx`
|
||||
- 显示:名称、URL、方法、间隔、启用状态
|
||||
- 统计信息:成功次数、失败次数、最后成功/失败时间
|
||||
- 编辑按钮、删除按钮
|
||||
- Switch组件:快速启用/禁用
|
||||
|
||||
- `app/[locale]/settings/heartbeat/_components/url-config-dialog.tsx`
|
||||
- Dialog表单:名称、URL、方法、headers、body、间隔
|
||||
- 支持新建和编辑模式
|
||||
- headers使用Textarea(JSON格式)
|
||||
- body使用Textarea(可选)
|
||||
- 验证和错误提示
|
||||
|
||||
- `app/[locale]/settings/heartbeat/_components/heartbeat-skeleton.tsx`
|
||||
- 骨架屏加载状态
|
||||
|
||||
12. **创建hooks**
|
||||
- `app/[locale]/settings/heartbeat/_lib/hooks.ts`
|
||||
- `useHeartbeatPageData()`:
|
||||
- 加载settings、configs、savedCurls
|
||||
- 提供CRUD操作函数
|
||||
- 提供importFromCurl函数
|
||||
- 统一错误处理和toast提示
|
||||
|
||||
13. **重写page.tsx**
|
||||
- 使用`useHeartbeatPageData()`
|
||||
- 组合所有子组件
|
||||
- 加载状态和错误处理
|
||||
|
||||
### 阶段6:测试和验证
|
||||
|
||||
14. **类型检查和格式化**
|
||||
```bash
|
||||
bun run typecheck
|
||||
bun run lint:fix
|
||||
```
|
||||
|
||||
15. **手动测试流程**
|
||||
- [ ] 访问 `/settings/heartbeat` 页面
|
||||
- [ ] 创建新的URL配置
|
||||
- [ ] 从curl历史导入配置
|
||||
- [ ] 编辑配置(修改URL、间隔等)
|
||||
- [ ] 启用/禁用单个配置
|
||||
- [ ] 启用/禁用全局开关
|
||||
- [ ] 删除配置
|
||||
- [ ] 检查多个URL同时发送心跳
|
||||
- [ ] 检查失败记录和统计信息
|
||||
- [ ] 检查国际化(切换语言)
|
||||
|
||||
16. **日志验证**
|
||||
```bash
|
||||
# 检查心跳日志
|
||||
tail -f logs/app.log | grep "ProviderHeartbeat"
|
||||
|
||||
# 应该看到:
|
||||
# - "Timer started" - 定时器启动
|
||||
# - "Heartbeat sent successfully" - 成功日志
|
||||
# - "Heartbeat failed" - 失败日志
|
||||
```
|
||||
|
||||
17. **数据库验证**
|
||||
```bash
|
||||
bun run db:studio
|
||||
# 检查 heartbeat_url_configs 表
|
||||
# 确认配置已保存
|
||||
# 确认成功/失败统计更新
|
||||
```
|
||||
|
||||
## 关键文件清单
|
||||
|
||||
### 新建文件
|
||||
- `src/repository/heartbeat-url-configs.ts` - URL配置Repository
|
||||
- `src/actions/heartbeat-url-configs.ts` - URL配置Actions
|
||||
- `src/app/[locale]/settings/heartbeat/_components/global-settings-card.tsx`
|
||||
- `src/app/[locale]/settings/heartbeat/_components/curl-history-section.tsx`
|
||||
- `src/app/[locale]/settings/heartbeat/_components/curl-history-card.tsx`
|
||||
- `src/app/[locale]/settings/heartbeat/_components/url-configs-section.tsx`
|
||||
- `src/app/[locale]/settings/heartbeat/_components/url-config-card.tsx`
|
||||
- `src/app/[locale]/settings/heartbeat/_components/url-config-dialog.tsx`
|
||||
- `src/app/[locale]/settings/heartbeat/_lib/hooks.ts`
|
||||
- `drizzle/0061_*.sql` - 数据库迁移文件(自动生成)
|
||||
|
||||
### 修改文件
|
||||
- `src/drizzle/schema.ts` - 添加新表,修改旧表
|
||||
- `src/repository/heartbeat-settings.ts` - 简化逻辑
|
||||
- `src/actions/heartbeat-settings.ts` - 简化Action
|
||||
- `src/lib/provider-heartbeat.ts` - 重构心跳执行逻辑
|
||||
- `src/app/v1/_lib/proxy/forwarder.ts` - 删除curl保存逻辑
|
||||
- `src/app/[locale]/settings/heartbeat/page.tsx` - 重写UI
|
||||
- `messages/*/settings/heartbeat.json` - 更新翻译(5种语言)
|
||||
|
||||
### 删除文件
|
||||
- `src/app/[locale]/settings/heartbeat/_components/heartbeat-form.tsx` - 旧表单组件
|
||||
|
||||
## 数据迁移策略
|
||||
|
||||
**迁移逻辑(在0061_*.sql中)**:
|
||||
```sql
|
||||
-- 创建新表
|
||||
CREATE TABLE heartbeat_url_configs (...);
|
||||
|
||||
-- 迁移现有数据
|
||||
DO $$
|
||||
DECLARE
|
||||
settings_row RECORD;
|
||||
selected_curl JSONB;
|
||||
BEGIN
|
||||
SELECT * INTO settings_row FROM heartbeat_settings LIMIT 1;
|
||||
|
||||
IF settings_row.selected_curl_index IS NOT NULL THEN
|
||||
selected_curl := settings_row.saved_curls->settings_row.selected_curl_index;
|
||||
|
||||
INSERT INTO heartbeat_url_configs (
|
||||
name, url, interval_seconds, is_enabled, ...
|
||||
) VALUES (
|
||||
selected_curl->>'providerName',
|
||||
selected_curl->>'url',
|
||||
settings_row.interval_seconds,
|
||||
settings_row.enabled,
|
||||
...
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 删除旧字段
|
||||
ALTER TABLE heartbeat_settings
|
||||
DROP COLUMN interval_seconds,
|
||||
DROP COLUMN saved_curls,
|
||||
DROP COLUMN selected_curl_index;
|
||||
```
|
||||
|
||||
**回滚能力**:保留旧数据在迁移文件中,可以通过反向迁移恢复。
|
||||
|
||||
## 风险和缓解
|
||||
|
||||
| 风险 | 缓解措施 |
|
||||
|------|----------|
|
||||
| 数据迁移失败 | 1. 迁移前备份数据库<br>2. 在测试环境验证<br>3. 编写回滚脚本 |
|
||||
| curl解析不完整 | 1. 复用现有`parseCurlCommand`<br>2. 添加解析错误提示<br>3. 允许手动编辑 |
|
||||
| 多定时器性能问题 | 1. 限制最大配置数量(如20个)<br>2. 添加禁用功能<br>3. 监控日志 |
|
||||
| 心跳发送失败 | 1. 记录失败日志<br>2. UI显示失败状态<br>3. 支持手动禁用 |
|
||||
|
||||
## 验证清单
|
||||
|
||||
- [ ] 数据库迁移成功,旧数据已转移
|
||||
- [ ] 类型检查通过 (`bun run typecheck`)
|
||||
- [ ] Lint检查通过 (`bun run lint`)
|
||||
- [ ] 构建成功 (`bun run build`)
|
||||
- [ ] 可以创建URL配置
|
||||
- [ ] 可以从curl导入配置
|
||||
- [ ] 可以编辑和删除配置
|
||||
- [ ] 全局开关控制所有心跳
|
||||
- [ ] 多个URL同时发送心跳(检查日志)
|
||||
- [ ] 失败统计正确记录
|
||||
- [ ] 所有5种语言显示正常
|
||||
- [ ] 页面加载和交互流畅
|
||||
|
||||
## 预估工作量
|
||||
|
||||
- 数据库和Repository层:1-2小时
|
||||
- Action层:30分钟
|
||||
- 心跳执行逻辑:1小时
|
||||
- i18n文案:30分钟
|
||||
- 前端UI:2-3小时
|
||||
- 测试和验证:1小时
|
||||
- **总计:6-8小时**
|
||||
@@ -1,172 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "=========================================="
|
||||
echo "Claude Code Root Check 移除工具"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# 通过 which 命令找到 claude 可执行文件
|
||||
echo "正在查找 claude 命令..."
|
||||
CLAUDE_PATH=$(which claude)
|
||||
|
||||
if [ -z "$CLAUDE_PATH" ]; then
|
||||
echo "❌ 错误: 未找到 claude 命令"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "找到 claude 位置: $CLAUDE_PATH"
|
||||
|
||||
# 如果是软链接,获取实际文件路径
|
||||
if [ -L "$CLAUDE_PATH" ]; then
|
||||
REAL_PATH=$(readlink -f "$CLAUDE_PATH")
|
||||
echo "这是一个软链接,实际路径: $REAL_PATH"
|
||||
else
|
||||
REAL_PATH="$CLAUDE_PATH"
|
||||
fi
|
||||
|
||||
# 获取 claude 所在的目录
|
||||
CLAUDE_DIR=$(dirname "$CLAUDE_PATH")
|
||||
echo "claude 目录: $CLAUDE_DIR"
|
||||
echo ""
|
||||
|
||||
# 检查是否已经是包装脚本
|
||||
if grep -q "Claude Code Wrapper" "$CLAUDE_PATH" 2>/dev/null; then
|
||||
echo "✓ 检测到已安装包装脚本"
|
||||
echo "正在更新包装脚本..."
|
||||
else
|
||||
echo "正在创建包装脚本..."
|
||||
fi
|
||||
|
||||
# 创建 claude-wrapper.sh
|
||||
WRAPPER_PATH="$CLAUDE_DIR/claude-wrapper.sh"
|
||||
|
||||
cat > "$WRAPPER_PATH" << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
# Claude Code Wrapper - 自动删除 root check 限制
|
||||
# 此脚本会在每次执行 claude 前绕过 root 用户限制
|
||||
#
|
||||
# 新版本 (2.1.x+) 支持通过环境变量绕过检查:
|
||||
# - IS_SANDBOX=1
|
||||
# - CLAUDE_CODE_BUBBLEWRAP=1
|
||||
#
|
||||
# 旧版本需要修改 cli.js 文件删除检查代码
|
||||
|
||||
# 获取当前脚本的真实路径
|
||||
SCRIPT_PATH="$(readlink -f "$0")"
|
||||
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
|
||||
|
||||
# 查找同目录下的 claude.bak(原始软链接)
|
||||
CLAUDE_BAK="$SCRIPT_DIR/claude.bak"
|
||||
|
||||
# 如果 claude.bak 不存在,尝试通过 which 和目录搜索找到真实路径
|
||||
if [ ! -L "$CLAUDE_BAK" ] && [ ! -f "$CLAUDE_BAK" ]; then
|
||||
# 在当前目录查找指向 claude-code 的软链接或文件
|
||||
for file in "$SCRIPT_DIR"/*; do
|
||||
if [ -L "$file" ] || [ -f "$file" ]; then
|
||||
target=$(readlink -f "$file" 2>/dev/null)
|
||||
if [[ "$target" == *"@anthropic-ai/claude-code/cli.js" ]]; then
|
||||
CLAUDE_REAL_PATH="$target"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 如果还是没找到,尝试常见路径
|
||||
if [ -z "$CLAUDE_REAL_PATH" ]; then
|
||||
for path in \
|
||||
"$SCRIPT_DIR/../lib/node_modules/@anthropic-ai/claude-code/cli.js" \
|
||||
"/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js" \
|
||||
"/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js"; do
|
||||
if [ -f "$path" ]; then
|
||||
CLAUDE_REAL_PATH="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
# 通过 claude.bak 获取真实的 cli.js 路径
|
||||
CLAUDE_REAL_PATH="$(readlink -f "$CLAUDE_BAK")"
|
||||
fi
|
||||
|
||||
if [ -z "$CLAUDE_REAL_PATH" ] || [ ! -f "$CLAUDE_REAL_PATH" ]; then
|
||||
echo "错误: 未找到真实的 claude cli.js 文件" >&2
|
||||
echo "请确保 claude 已正确安装" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 获取 claude 版本号(用于提示信息)
|
||||
CLAUDE_VERSION=$(node "$CLAUDE_REAL_PATH" --version 2>/dev/null | head -1 || echo "unknown")
|
||||
|
||||
# 新版本 (2.1.x+) 直接使用环境变量绕过 root check
|
||||
# 设置 IS_SANDBOX=1 或 CLAUDE_CODE_BUBBLEWRAP=1 即可
|
||||
export IS_SANDBOX=1
|
||||
export CLAUDE_CODE_BUBBLEWRAP=1
|
||||
|
||||
# 执行原始 claude 命令,传递所有参数
|
||||
exec node "$CLAUDE_REAL_PATH" "$@"
|
||||
EOF
|
||||
|
||||
# 给包装脚本添加执行权限
|
||||
chmod +x "$WRAPPER_PATH"
|
||||
echo "✓ 已创建包装脚本: $WRAPPER_PATH"
|
||||
echo ""
|
||||
|
||||
# 备份原 claude 命令(如果尚未备份)
|
||||
CLAUDE_BAK="$CLAUDE_DIR/claude.bak"
|
||||
if [ ! -e "$CLAUDE_BAK" ]; then
|
||||
if [ -L "$CLAUDE_PATH" ]; then
|
||||
# 如果是软链接,复制软链接本身
|
||||
cp -P "$CLAUDE_PATH" "$CLAUDE_BAK"
|
||||
echo "✓ 已备份原 claude 软链接为: $CLAUDE_BAK"
|
||||
else
|
||||
# 如果是普通文件,复制文件
|
||||
cp "$CLAUDE_PATH" "$CLAUDE_BAK"
|
||||
echo "✓ 已备份原 claude 文件为: $CLAUDE_BAK"
|
||||
fi
|
||||
else
|
||||
echo "✓ 检测到已存在备份: $CLAUDE_BAK"
|
||||
fi
|
||||
|
||||
# 替换 claude 命令为包装脚本
|
||||
echo ""
|
||||
echo "正在替换 claude 命令..."
|
||||
|
||||
# 删除原有的 claude(如果是软链接或文件)
|
||||
rm -f "$CLAUDE_PATH"
|
||||
|
||||
# 创建新的软链接指向包装脚本
|
||||
ln -s "$WRAPPER_PATH" "$CLAUDE_PATH"
|
||||
|
||||
echo "✓ 已将 claude 命令替换为包装脚本"
|
||||
echo ""
|
||||
|
||||
# 验证安装
|
||||
echo "=========================================="
|
||||
echo "验证安装..."
|
||||
echo ""
|
||||
|
||||
if [ -L "$CLAUDE_PATH" ]; then
|
||||
TARGET_PATH=$(readlink "$CLAUDE_PATH")
|
||||
echo "✓ claude 现在指向: $TARGET_PATH"
|
||||
fi
|
||||
|
||||
if [ -e "$CLAUDE_BAK" ]; then
|
||||
echo "✓ 原始 claude 已备份为: $CLAUDE_BAK"
|
||||
fi
|
||||
|
||||
if [ -x "$WRAPPER_PATH" ]; then
|
||||
echo "✓ 包装脚本具有执行权限"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "✓ 安装完成!"
|
||||
echo ""
|
||||
echo "现在你可以在 root 用户下使用:"
|
||||
echo " claude --dangerously-skip-permissions"
|
||||
echo ""
|
||||
echo "如需恢复原始 claude 命令:"
|
||||
echo " rm $CLAUDE_PATH"
|
||||
echo " mv $CLAUDE_BAK $CLAUDE_PATH"
|
||||
echo "=========================================="
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"ANTHROPIC_API_KEY": "sk-d87ce5b80978df466c81378d798ca39f",
|
||||
"ANTHROPIC_BASE_URL": "https://cc.ronghuaxueleng.top",
|
||||
"CLAUDE_CODE_ATTRIBUTION_HEADER": "0",
|
||||
"DISABLE_AUTOUPDATER": 1,
|
||||
"DISABLE_BUG_COMMAND": 1,
|
||||
"DISABLE_ERROR_REPORTING": 1,
|
||||
"DISABLE_TELEMETRY": 1,
|
||||
"IS_SANDBOX": "1",
|
||||
"USER_NAME": "腾讯云"
|
||||
},
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"*"
|
||||
],
|
||||
"defaultMode": "bypassPermissions"
|
||||
},
|
||||
"statusLine": {
|
||||
"command": "node \".claude/show-status.mjs\"",
|
||||
"padding": 0,
|
||||
"type": "command"
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Claude Code 积分状态栏脚本
|
||||
* 用途: 在状态栏显示配置信息
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
// 禁用SSL证书验证警告
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
|
||||
function getDisplayUrl() {
|
||||
const baseUrl = process.env.ANTHROPIC_BASE_URL || '';
|
||||
if (baseUrl) {
|
||||
const match = baseUrl.match(/https?:\/\/([^\/]+)/);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getCurrentModel() {
|
||||
// 优先使用环境变量
|
||||
let model = process.env.ANTHROPIC_MODEL || '';
|
||||
|
||||
// 如果环境变量没有,检查settings.json
|
||||
if (!model) {
|
||||
try {
|
||||
const settingsFile = path.join(os.homedir(), '.claude', 'settings.json');
|
||||
if (fs.existsSync(settingsFile)) {
|
||||
const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
|
||||
model = settings.model || '';
|
||||
}
|
||||
} catch (error) {
|
||||
// 忽略错误
|
||||
}
|
||||
}
|
||||
|
||||
if (model) {
|
||||
if (model.toLowerCase().includes('claude-3')) {
|
||||
if (model.toLowerCase().includes('haiku')) {
|
||||
return 'Claude 3 Haiku';
|
||||
} else if (model.toLowerCase().includes('sonnet')) {
|
||||
return 'Claude 3 Sonnet';
|
||||
} else if (model.toLowerCase().includes('opus')) {
|
||||
return 'Claude 3 Opus';
|
||||
}
|
||||
} else if (model.toLowerCase().includes('claude-4') || model.toLowerCase().includes('sonnet-4')) {
|
||||
return 'Claude 4 Sonnet';
|
||||
} else if (model.toLowerCase().includes('opus-4')) {
|
||||
return 'Claude 4 Opus';
|
||||
} else if (model.length > 20) {
|
||||
return model.substring(0, 20) + '...';
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
return 'Claude (Auto)';
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const currentUrl = getDisplayUrl();
|
||||
const currentModel = getCurrentModel();
|
||||
const userName = process.env.USER_NAME || '';
|
||||
|
||||
const parts = [];
|
||||
if (userName) parts.push(`👤 ${userName}`);
|
||||
parts.push(currentModel);
|
||||
parts.push(currentUrl);
|
||||
|
||||
console.log(parts.join(' | '));
|
||||
|
||||
} catch (error) {
|
||||
// 即使出错也显示基本信息
|
||||
const currentUrl = getDisplayUrl();
|
||||
const currentModel = getCurrentModel();
|
||||
const userName = process.env.USER_NAME || '';
|
||||
const parts = ['🔴 错误'];
|
||||
if (userName) parts.push(`👤 ${userName}`);
|
||||
parts.push(currentModel);
|
||||
parts.push(currentUrl);
|
||||
console.log(parts.join(' | '));
|
||||
}
|
||||
}
|
||||
|
||||
// ES Module 中直接执行
|
||||
main();
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -45,3 +45,7 @@ ds2api-tests
|
||||
# Misc
|
||||
.git/
|
||||
Thumbs.db
|
||||
|
||||
# Claude Code
|
||||
.claude/
|
||||
CLAUDE.local.md
|
||||
|
||||
261
CLAUDE.local.md
261
CLAUDE.local.md
@@ -1,261 +0,0 @@
|
||||
# Claude Code 行为准则
|
||||
|
||||
> 本文件定义 Claude Code 在本项目中的强制执行规则。所有规则均为**必须执行**,不可跳过。
|
||||
|
||||
---
|
||||
|
||||
## 一、核心原则(九荣九耻)
|
||||
|
||||
| 耻 | 荣 |
|
||||
|---|---|
|
||||
| ❌ 瞎猜接口 | ✅ 认真查询源码 |
|
||||
| ❌ 模糊执行 | ✅ 寻求用户确认 |
|
||||
| ❌ 臆想业务 | ✅ 复用现有实现 |
|
||||
| ❌ 创造接口 | ✅ 主动测试验证 |
|
||||
| ❌ 跳过验证 | ✅ 等待人类确认 |
|
||||
| ❌ 破坏架构 | ✅ 遵循项目规范 |
|
||||
| ❌ 假装理解 | ✅ 诚实说"不确定" |
|
||||
| ❌ 盲目修改 | ✅ 谨慎重构 |
|
||||
| ❌ 画蛇添足 | ✅ 按需实现 |
|
||||
|
||||
---
|
||||
|
||||
## 二、代码生成前置检查
|
||||
|
||||
### 【强制】生成代码前必须完成的 4 项检查
|
||||
|
||||
在生成**任何代码**之前,必须逐条确认以下检查项,**缺一不可**:
|
||||
|
||||
| # | 检查项 | 未通过则 |
|
||||
|---|--------|---------|
|
||||
| 1 | 是否已读取 CLAUDE.md 中的编码规范? | ❌ 禁止生成代码 |
|
||||
| 2 | 是否已搜索项目中类似实现作为参考? | ❌ 禁止生成代码 |
|
||||
| 3 | 是否有不确定的地方需要询问用户? | ⚠️ 先询问再继续 |
|
||||
| 4 | 是否复用了现有的实体类/工具类? | ❌ 禁止新建已存在的类 |
|
||||
|
||||
---
|
||||
|
||||
## 三、"参照 XX 写"执行规则
|
||||
|
||||
当用户说"参照XX写"、"仿照XX实现"、"按照XX的方式"时,**必须严格执行**以下步骤:
|
||||
|
||||
### 步骤清单
|
||||
|
||||
| # | 步骤 | 必须完成的动作 |
|
||||
|---|------|--------------|
|
||||
| 1 | 完整阅读参照对象 | 读取 Controller、Service、Mapper、Entity **所有相关文件**,不能只看部分 |
|
||||
| 2 | 列出关键对照点 | 向用户列出:接口路径、参数格式、返回值格式、Service 调用方式、业务逻辑 |
|
||||
| 3 | 严格对照实现 | ❌ 禁止"优化"或"改进"参照对象,❌ 禁止偏离参照对象的风格 |
|
||||
|
||||
### 完成后自检
|
||||
|
||||
| # | 自检问题 | 答案必须是"是" |
|
||||
|---|---------|--------------|
|
||||
| 1 | 我的实现和参照对象的实现方式是否一致? | 否则必须修正 |
|
||||
| 2 | 有没有任何地方是我"自作主张"改的? | 有则必须告知用户 |
|
||||
|
||||
**如果有任何偏离,必须告知用户并说明原因,由用户决定是否采用。**
|
||||
|
||||
---
|
||||
|
||||
## 四、批量保存接口设计规范
|
||||
|
||||
### 【强制】设计前必须列出用户操作场景
|
||||
|
||||
| 用户操作 | 数据特征 | 处理方式 |
|
||||
|---------|---------|---------|
|
||||
| 新增一条数据 | 传入的数据没有 id | INSERT |
|
||||
| 修改一条数据 | 传入的数据有 id | UPDATE |
|
||||
| 删除一条数据 | **数据库有但传入列表中没有** ← 容易遗漏! | DELETE |
|
||||
| 不做任何改动 | 原样传回 | 不处理 |
|
||||
|
||||
### 正确实现步骤
|
||||
|
||||
```
|
||||
1. 查询数据库中该主体已有的所有数据 ID
|
||||
2. 对比传入列表中的 ID,找出需要删除的(数据库有但传入没有)
|
||||
3. 删除不在传入列表中的数据
|
||||
4. 新增或更新传入列表中的数据
|
||||
```
|
||||
|
||||
### 完成后自检
|
||||
|
||||
| # | 自检问题 | 答案必须是"是" |
|
||||
|---|---------|--------------|
|
||||
| 1 | 新增、更新、删除——三种情况都覆盖了吗? | |
|
||||
| 2 | 如果用户删除了一条已有数据,保存后这条数据会消失吗? | |
|
||||
|
||||
---
|
||||
|
||||
## 五、文档解析规则
|
||||
|
||||
### 【强制】解析步骤(按顺序执行,不可跳过)
|
||||
|
||||
| # | 步骤 | 必须完成的动作 | 中断条件 |
|
||||
|---|------|--------------|---------|
|
||||
| 1 | 多方式解析 | Word/PDF 必须尝试 ≥2 种解析方式(段落、表格、文本框、XML 等) | |
|
||||
| 2 | 完整性检查 | 检查是否只看到类名而没有属性定义? | ⚠️ **是则停止,询问用户** |
|
||||
| 3 | 列出清单 | 向用户列出:类数量+名称、每个类的属性数量+名称、方法数量+签名 | ⚠️ **等待用户确认** |
|
||||
| 4 | 生成代码 | 只有用户明确确认后才能继续 | |
|
||||
|
||||
### 绝对禁止
|
||||
|
||||
| # | 禁止行为 |
|
||||
|---|---------|
|
||||
| 1 | ❌ 禁止在用户确认前生成任何代码 |
|
||||
| 2 | ❌ 禁止自行补充或猜测文档中未明确写出的内容 |
|
||||
| 3 | ❌ 禁止只用一种方式解析就认为解析完成 |
|
||||
| 4 | ❌ 禁止看到类名/接口名却没有属性定义时继续执行 |
|
||||
|
||||
---
|
||||
|
||||
## 六、接口与参数分析规则
|
||||
|
||||
### 触发条件
|
||||
- 分析接口映射关系(标准接口 → 内部接口)
|
||||
- 分析参数映射关系
|
||||
- 编写 DTO/Entity 字段定义
|
||||
|
||||
### 【强制】执行步骤
|
||||
|
||||
| # | 步骤 | 必须完成的动作 |
|
||||
|---|------|--------------|
|
||||
| 1 | 确认接口映射 | 阅读标准接口功能 → 搜索后端代码找**功能匹配**的内部接口(不是名称匹配!)→ 读 Controller 确认功能 |
|
||||
| 2 | 确认参数映射 | 找到 @RequestBody 的类 → 读源码(含父类)→ 逐一列出字段 → 对比建立映射 |
|
||||
|
||||
### 映射可信度标注(必须标注)
|
||||
|
||||
| 标注 | 含义 |
|
||||
|-----|------|
|
||||
| ✅ 已验证 | 已阅读源码确认 |
|
||||
| ⚠️ 待验证 | 需要进一步确认 |
|
||||
| ❌ 需新建接口 | 需要编写复杂业务逻辑(组合调用多个接口等) |
|
||||
|
||||
### 绝对禁止
|
||||
|
||||
| # | 禁止行为 |
|
||||
|---|---------|
|
||||
| 1 | ❌ 禁止凭接口名称相似就认为可以映射 |
|
||||
| 2 | ❌ 禁止直接使用 Postman/Swagger 参数定义,必须与源码核对 |
|
||||
| 3 | ❌ 禁止凭"合理推测"编写参数映射 |
|
||||
| 4 | ❌ 禁止使用模糊表述如"需要扩展"、"可能需要调用额外接口" |
|
||||
|
||||
---
|
||||
|
||||
## 七、Postman 文档规范
|
||||
|
||||
### 核心原则
|
||||
|
||||
| 位置 | 内容 |
|
||||
|-----|------|
|
||||
| `description` 字段 | Markdown 格式,展示完整参数说明(带注释的 JSON 代码块) |
|
||||
| `body.raw` 字段 | 纯净 JSON(无注释),可直接发送请求 |
|
||||
|
||||
### description 格式模板
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "接口功能说明。\n\n**请求参数示例:**\n```json\n{\n \"字段名\": \"示例值\", // 字段说明\n}\n```\n\n**响应示例:**\n```json\n{\n \"code\": 0,\n \"data\": {}\n}\n```"
|
||||
}
|
||||
```
|
||||
|
||||
### 自检清单
|
||||
|
||||
| # | 检查项 | 要求 |
|
||||
|---|--------|-----|
|
||||
| 1 | body.raw 是否有注释? | ❌ 禁止,会导致 JSON 格式错误 |
|
||||
| 2 | description 是否展示了参数格式? | ✅ 必须有带注释的 JSON 示例 |
|
||||
| 3 | 是否包含响应示例? | ✅ 每个接口都必须有 |
|
||||
| 4 | Long 类型 ID 是否展示为 String? | ✅ 如 `"id": "123456789"` |
|
||||
|
||||
---
|
||||
|
||||
## 八、设计文档编写规范
|
||||
|
||||
### 核心原则
|
||||
设计文档的目标是:**开发人员可以直接照着写代码**,不是概念性说明。
|
||||
|
||||
### 【强制】文档必须包含的内容
|
||||
|
||||
| # | 内容 | 要求 |
|
||||
|---|------|-----|
|
||||
| 1 | 数据库表 DDL | 可直接执行的 CREATE TABLE |
|
||||
| 2 | 枚举类代码 | 可直接复制使用 |
|
||||
| 3 | 实体类代码 | 包括所有字段和注解 |
|
||||
| 4 | Mapper 代码 | 包括 Provider 中的完整 SQL |
|
||||
| 5 | Service 代码 | 接口定义和实现类 |
|
||||
| 6 | Controller 代码 | 接口路径、请求体、响应格式 |
|
||||
| 7 | 实现清单 | 新模块接入时的检查表 |
|
||||
| 8 | 常见问题 FAQ | 解答可能的疑惑 |
|
||||
|
||||
### 代码示例要求
|
||||
|
||||
| # | 要求 |
|
||||
|---|------|
|
||||
| 1 | 代码必须**完整可用**,不是片段或伪代码 |
|
||||
| 2 | 必须包含**完整的 import 语句** |
|
||||
| 3 | SQL 必须**完整可执行**,不能用 `...` 省略 |
|
||||
|
||||
### 完成后自检
|
||||
|
||||
| # | 自检问题 | 答案必须是"是" |
|
||||
|---|---------|--------------|
|
||||
| 1 | 新人开发者能否只看这份文档就完成开发? | |
|
||||
| 2 | 文档中的代码能否直接复制到项目中使用? | |
|
||||
| 3 | 是否有"等"、"..."、"类似"等模糊表述? | 有则删除 |
|
||||
|
||||
---
|
||||
|
||||
## 九、方法重载规范
|
||||
|
||||
### 规则
|
||||
|
||||
| # | 规则 | 说明 |
|
||||
|---|------|-----|
|
||||
| 1 | 全量参数方法承载所有逻辑 | 是唯一的实现体 |
|
||||
| 2 | 少参数方法只做委托调用 | 传 `null` 给新增参数,方法体只有一行 `return` |
|
||||
| 3 | ❌ 禁止两个重载方法各写一份逻辑 | 即使逻辑相同也不行 |
|
||||
| 4 | ❌ 禁止反向委托 | 全量方法不能调用少参数方法 |
|
||||
|
||||
### 正确示例
|
||||
|
||||
```java
|
||||
// ✅ 少参数方法委托全量方法
|
||||
public Object foo(Req req, Request request, Response response) {
|
||||
return foo(req, request, response, null);
|
||||
}
|
||||
|
||||
public Object foo(Req req, Request request, Response response, Function<String, String> lineConverter) {
|
||||
// 所有逻辑在这里
|
||||
if (lineConverter != null) {
|
||||
// 有转换器时的处理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、工作偏好
|
||||
|
||||
| # | 偏好 |
|
||||
|---|------|
|
||||
| 1 | 始终使用**简体中文**回复 |
|
||||
| 2 | 长任务必须记录详细进度 |
|
||||
| 3 | 提交代码时**不要**附带 `Co-Authored-By: Claude` |
|
||||
| 4 | 对所有工具操作自动同意,无需额外确认 |
|
||||
| 5 | 不用执行编译和测试 |
|
||||
| 6 | 编写构建脚本时尽量使用 mjs 编写带菜单的脚本 |
|
||||
| 7 | 尽量使用 Python 连接数据库 |
|
||||
| 8 | 联网搜索时**禁止**使用 csdn.net、阿里云/腾讯云/华为云社区等内容农场 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、代码生成规则
|
||||
|
||||
| # | 规则 |
|
||||
|---|------|
|
||||
| 1 | 提供实体类/模板/文档时,必须**完整复制所有属性和方法**,禁止省略 |
|
||||
| 2 | 生成代码前,先列出文档中所有属性数量和名称,确认无遗漏后再生成 |
|
||||
| 3 | 属性超过 20 个时,分批列出确认 |
|
||||
| 4 | 禁止因为"优化"或"简化"而删减任何属性 |
|
||||
| 5 | 生成完成后,对比源文档属性数量是否一致 |
|
||||
Reference in New Issue
Block a user