Upload 5 files
Browse files- Dockerfile +50 -46
- config.yaml +56 -31
- package-lock.json +0 -0
- package.json +34 -26
- tsconfig.json +22 -22
Dockerfile
CHANGED
|
@@ -1,46 +1,50 @@
|
|
| 1 |
-
# ==== Stage 1: 构建阶段 (Builder) ====
|
| 2 |
-
FROM node:22-alpine AS builder
|
| 3 |
-
|
| 4 |
-
# 设置工作目录
|
| 5 |
-
WORKDIR /app
|
| 6 |
-
|
| 7 |
-
# 仅拷贝包配置并安装所有依赖项(利用 Docker 缓存层)
|
| 8 |
-
COPY package.json package-lock.json ./
|
| 9 |
-
RUN npm ci
|
| 10 |
-
|
| 11 |
-
# 拷贝项目源代码并执行 TypeScript 编译
|
| 12 |
-
COPY tsconfig.json ./
|
| 13 |
-
COPY src ./src
|
| 14 |
-
RUN npm run build
|
| 15 |
-
|
| 16 |
-
# ==== Stage 2: 生产运行阶段 (Runner) ====
|
| 17 |
-
FROM node:22-alpine AS runner
|
| 18 |
-
|
| 19 |
-
WORKDIR /app
|
| 20 |
-
|
| 21 |
-
# 设置为生产环境
|
| 22 |
-
ENV NODE_ENV=production
|
| 23 |
-
|
| 24 |
-
#
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
#
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ==== Stage 1: 构建阶段 (Builder) ====
|
| 2 |
+
FROM node:22-alpine AS builder
|
| 3 |
+
|
| 4 |
+
# 设置工作目录
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# 仅拷贝包配置并安装所有依赖项(利用 Docker 缓存层)
|
| 8 |
+
COPY package.json package-lock.json ./
|
| 9 |
+
RUN npm ci
|
| 10 |
+
|
| 11 |
+
# 拷贝项目源代码并执行 TypeScript 编译
|
| 12 |
+
COPY tsconfig.json ./
|
| 13 |
+
COPY src ./src
|
| 14 |
+
RUN npm run build
|
| 15 |
+
|
| 16 |
+
# ==== Stage 2: 生产运行阶段 (Runner) ====
|
| 17 |
+
FROM node:22-alpine AS runner
|
| 18 |
+
|
| 19 |
+
WORKDIR /app
|
| 20 |
+
|
| 21 |
+
# 设置为生产环境
|
| 22 |
+
ENV NODE_ENV=production
|
| 23 |
+
|
| 24 |
+
# Hugging Face Spaces (Docker) 默认端口
|
| 25 |
+
# - Spaces 通常会注入 PORT=7860,但这里提供一个安全默认值
|
| 26 |
+
ENV PORT=7860
|
| 27 |
+
|
| 28 |
+
# 出于安全考虑,避免使用 root 用户运行服务
|
| 29 |
+
RUN addgroup --system --gid 1001 nodejs && \
|
| 30 |
+
adduser --system --uid 1001 cursor
|
| 31 |
+
|
| 32 |
+
# 拷贝包配置并仅安装生产环境依赖(极大减小镜像体积)
|
| 33 |
+
COPY package.json package-lock.json ./
|
| 34 |
+
RUN npm ci --omit=dev \
|
| 35 |
+
&& npm cache clean --force
|
| 36 |
+
|
| 37 |
+
# 从 builder 阶段拷贝编译后的产物
|
| 38 |
+
COPY --from=builder --chown=cursor:nodejs /app/dist ./dist
|
| 39 |
+
|
| 40 |
+
# 拷贝默认配置文件(可通过 volume 挂载覆盖)
|
| 41 |
+
COPY --chown=cursor:nodejs config.yaml ./config.yaml
|
| 42 |
+
|
| 43 |
+
# 切换到非 root 用户
|
| 44 |
+
USER cursor
|
| 45 |
+
|
| 46 |
+
# 声明对外暴露的端口
|
| 47 |
+
EXPOSE 7860
|
| 48 |
+
|
| 49 |
+
# 启动服务
|
| 50 |
+
CMD ["npm", "start"]
|
config.yaml
CHANGED
|
@@ -1,31 +1,56 @@
|
|
| 1 |
-
# Cursor2API v2 配置文件
|
| 2 |
-
|
| 3 |
-
# 服务端口
|
| 4 |
-
port: 3010
|
| 5 |
-
|
| 6 |
-
# 请求超时(秒)
|
| 7 |
-
timeout: 120
|
| 8 |
-
|
| 9 |
-
# 代理设置(可选)
|
| 10 |
-
#
|
| 11 |
-
|
| 12 |
-
#
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
#
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
mode: 'ocr'
|
| 27 |
-
|
| 28 |
-
#
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Cursor2API v2 配置文件
|
| 2 |
+
|
| 3 |
+
# 服务端口
|
| 4 |
+
port: 3010
|
| 5 |
+
|
| 6 |
+
# 请求超时(秒)
|
| 7 |
+
timeout: 120
|
| 8 |
+
|
| 9 |
+
# 代理设置(可选)
|
| 10 |
+
# ⚠️ Node.js fetch 不读取 HTTP_PROXY / HTTPS_PROXY 环境变量,
|
| 11 |
+
# 必须在此处或通过 PROXY 环境变量显式配置代理。
|
| 12 |
+
# 支持 http 代理,含认证格式: http://用户名:密码@代理地址:端口
|
| 13 |
+
# proxy: "http://127.0.0.1:7890"
|
| 14 |
+
|
| 15 |
+
# Cursor 使用的模型
|
| 16 |
+
cursor_model: "anthropic/claude-sonnet-4.6"
|
| 17 |
+
|
| 18 |
+
# 浏览器指纹配置
|
| 19 |
+
fingerprint:
|
| 20 |
+
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"
|
| 21 |
+
|
| 22 |
+
# 视觉处理降级配置(可选)
|
| 23 |
+
# 如果开启,可以拦截您发给大模型的图片进行降级处理(因为目前免费 Cursor 不支持视觉)。
|
| 24 |
+
vision:
|
| 25 |
+
enabled: true
|
| 26 |
+
# mode 选项: 'ocr' 或 'api'
|
| 27 |
+
# 'ocr': [默认模式] 彻底免 Key,零配置,完全依赖本机的 CPU 识图,提取文本、报错日志、代码段后发给大模型。
|
| 28 |
+
# 'api': 需要配置下方的 providers,把图发给外部视觉模型(如 Gemini、OpenRouter),能"看到"画面内容和色彩。
|
| 29 |
+
mode: 'ocr'
|
| 30 |
+
|
| 31 |
+
# ---------- 以下选项仅在 mode: 'api' 时才生效 ----------
|
| 32 |
+
|
| 33 |
+
# 是否在所有 API 都失败时兜底使用本地 OCR(默认: true)
|
| 34 |
+
# fallback_to_ocr: true
|
| 35 |
+
|
| 36 |
+
# API 提供者列表(按顺序尝试,第一个成功即返回,失败则自动尝试下一个)
|
| 37 |
+
# providers:
|
| 38 |
+
# - name: "openrouter-free" # 名称(仅用于日志显示)
|
| 39 |
+
# base_url: "https://openrouter.ai/api/v1/chat/completions"
|
| 40 |
+
# api_key: "sk-or-v1-..."
|
| 41 |
+
# model: "meta-llama/llama-3.2-11b-vision-instruct:free"
|
| 42 |
+
#
|
| 43 |
+
# - name: "gemini-backup"
|
| 44 |
+
# base_url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
|
| 45 |
+
# api_key: "AIza..."
|
| 46 |
+
# model: "gemini-2.0-flash"
|
| 47 |
+
#
|
| 48 |
+
# - name: "openai-premium"
|
| 49 |
+
# base_url: "https://api.openai.com/v1/chat/completions"
|
| 50 |
+
# api_key: "sk-..."
|
| 51 |
+
# model: "gpt-4o-mini"
|
| 52 |
+
|
| 53 |
+
# ---------- 兼容旧版单 API 写法(不推荐,建议改用 providers) ----------
|
| 54 |
+
# base_url: "https://openrouter.ai/api/v1/chat/completions"
|
| 55 |
+
# api_key: "sk-or-v1-..."
|
| 56 |
+
# model: "meta-llama/llama-3.2-11b-vision-instruct:free"
|
package-lock.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
CHANGED
|
@@ -1,26 +1,34 @@
|
|
| 1 |
-
{
|
| 2 |
-
"name": "cursor2api",
|
| 3 |
-
"version": "2.
|
| 4 |
-
"description": "Proxy Cursor docs AI to Anthropic Messages API for Claude Code",
|
| 5 |
-
"type": "module",
|
| 6 |
-
"scripts": {
|
| 7 |
-
"dev": "tsx watch src/index.ts",
|
| 8 |
-
"build": "tsc",
|
| 9 |
-
"start": "node dist/index.js"
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
"
|
| 13 |
-
"
|
| 14 |
-
"
|
| 15 |
-
"
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
"
|
| 21 |
-
"
|
| 22 |
-
"
|
| 23 |
-
"
|
| 24 |
-
"
|
| 25 |
-
}
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "cursor2api",
|
| 3 |
+
"version": "2.6.0",
|
| 4 |
+
"description": "Proxy Cursor docs AI to Anthropic Messages API for Claude Code",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "tsx watch src/index.ts",
|
| 8 |
+
"build": "tsc",
|
| 9 |
+
"start": "node dist/index.js",
|
| 10 |
+
"test:unit": "node test/unit-tolerant-parse.mjs",
|
| 11 |
+
"test:tool-fixer": "node test/unit-tool-fixer.mjs",
|
| 12 |
+
"test:openai-compat": "node test/unit-openai-compat.mjs",
|
| 13 |
+
"test:all": "node test/unit-tolerant-parse.mjs && node test/unit-tool-fixer.mjs && node test/unit-openai-compat.mjs && node test/unit-proxy-agent.mjs",
|
| 14 |
+
"test:e2e": "node test/e2e-chat.mjs",
|
| 15 |
+
"test:agentic": "node test/e2e-agentic.mjs"
|
| 16 |
+
},
|
| 17 |
+
"dependencies": {
|
| 18 |
+
"dotenv": "^16.5.0",
|
| 19 |
+
"eventsource-parser": "^3.0.1",
|
| 20 |
+
"express": "^5.1.0",
|
| 21 |
+
"tesseract.js": "^7.0.0",
|
| 22 |
+
"undici": "^7.22.0",
|
| 23 |
+
"uuid": "^11.1.0",
|
| 24 |
+
"yaml": "^2.7.1"
|
| 25 |
+
},
|
| 26 |
+
"devDependencies": {
|
| 27 |
+
"@types/express": "^5.0.2",
|
| 28 |
+
"@types/node": "^22.15.0",
|
| 29 |
+
"@types/uuid": "^10.0.0",
|
| 30 |
+
"ts-node": "^10.9.2",
|
| 31 |
+
"tsx": "^4.19.0",
|
| 32 |
+
"typescript": "^5.8.0"
|
| 33 |
+
}
|
| 34 |
+
}
|
tsconfig.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
| 1 |
-
{
|
| 2 |
-
"compilerOptions": {
|
| 3 |
-
"target": "ES2022",
|
| 4 |
-
"module": "NodeNext",
|
| 5 |
-
"moduleResolution": "NodeNext",
|
| 6 |
-
"outDir": "./dist",
|
| 7 |
-
"rootDir": "./src",
|
| 8 |
-
"strict": true,
|
| 9 |
-
"esModuleInterop": true,
|
| 10 |
-
"skipLibCheck": true,
|
| 11 |
-
"forceConsistentCasingInFileNames": true,
|
| 12 |
-
"resolveJsonModule": true,
|
| 13 |
-
"declaration": true,
|
| 14 |
-
"sourceMap": true
|
| 15 |
-
},
|
| 16 |
-
"include": [
|
| 17 |
-
"src/**/*"
|
| 18 |
-
],
|
| 19 |
-
"exclude": [
|
| 20 |
-
"node_modules",
|
| 21 |
-
"dist"
|
| 22 |
-
]
|
| 23 |
}
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"target": "ES2022",
|
| 4 |
+
"module": "NodeNext",
|
| 5 |
+
"moduleResolution": "NodeNext",
|
| 6 |
+
"outDir": "./dist",
|
| 7 |
+
"rootDir": "./src",
|
| 8 |
+
"strict": true,
|
| 9 |
+
"esModuleInterop": true,
|
| 10 |
+
"skipLibCheck": true,
|
| 11 |
+
"forceConsistentCasingInFileNames": true,
|
| 12 |
+
"resolveJsonModule": true,
|
| 13 |
+
"declaration": true,
|
| 14 |
+
"sourceMap": true
|
| 15 |
+
},
|
| 16 |
+
"include": [
|
| 17 |
+
"src/**/*"
|
| 18 |
+
],
|
| 19 |
+
"exclude": [
|
| 20 |
+
"node_modules",
|
| 21 |
+
"dist"
|
| 22 |
+
]
|
| 23 |
}
|