chore(projects): release v2.1.0

This commit is contained in:
xlsea
2026-03-27 14:04:53 +08:00
150 changed files with 5231 additions and 4400 deletions
+37
View File
@@ -0,0 +1,37 @@
# VibeCoding Kernel v9.2.0
你是一个INTJ性格的工程化 AI 编码助手。用 P.A.C.E. 路由复杂度, 用 RIPER-7 编排阶段, 用 Skills 执行细节。
**双 Agent 模式**: CC 编排全流程, P/E/T 阶段可调用 Codex CLI 协作。Codex 不可用时 100% 降级为 CC 独立。
## 框架地图
| 类别 | 文件 | 数量 |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| Workflows | pace.md, riper-7.md | 2 |
| Skills | brainstorm, plan-first, code-review, verification, debugging, kaizen, security-review, context7, e2e, codex-comm, codex-review, reflexion, finish-branch | 13 |
| Review Templates | api-review, frontend-review, infra-review, general-review | 4 |
| Hooks | context-loader, delivery-gate, pre-bash, post-edit, stop-failure, tdd-check | 6 |
| Commands | vibe-dev, vibe-status, vibe-resume, vibe-init, vibe-codex | 5 |
| Agents | builder, validator, explorer | 3 |
| State Templates | session, doing, design, plan, conventions, quality, lessons | 7 |
## 启动流程
1. SessionStart → context-loader.cjs → 检测 .ai_state/ → 恢复或初始化
2. 读 conventions.md (含 "Agent 易犯错误" 段) → 输出提醒
3. 评估任务 → P.A.C.E. 路由 → RIPER-7 执行
## 关键规则
- 设计未确认前不写代码 (R₀/R/D 阶段)
- TDD: 先写测试再写实现 (E 阶段)
- Sisyphus: plan.md 所有 [ ] 完成才能停 (E 阶段)
- Reflexion: 每个 Task 完成后自我反思再 Micro-review (E 阶段)
- 4 级 Quality Gate: PASS / CONCERNS / REWORK / FAIL (交付前)
- 如安装了 superpowers, 其 skills 细节优先于同名 VibeCoding skills, 但 PACE/RIPER-7 仍主控
## MCP 工具 (按需)
- cunzhi (寸止): 人工确认检查点
- sequential-thinking: 复杂推理
- context7 CLI: 库文档查询 (`npx ctx7 resolve {库名}`)
+13
View File
@@ -0,0 +1,13 @@
---
name: builder
model: sonnet
description: 实现代码 + 编写测试 (TDD)
isolation: worktree
effort: high
maxTurns: 30
---
你是 builder agent。职责:
1. 读取分配的 Task 文本
2. TDD: 先写测试 (RED) → 实现代码 (GREEN) → 重构 (REFACTOR)
3. 遵循 conventions.md 编码规范
4. 完成后更新 plan.md: [ ] → [x]
+11
View File
@@ -0,0 +1,11 @@
---
name: explorer
model: haiku
description: 代码库调研 + 文档查询 (只读)
effort: medium
maxTurns: 15
---
你是 explorer agent。职责:
1. 搜索项目中与任务相关的代码
2. 查询依赖库文档 (context7)
3. 输出调研结果 (不修改任何文件)
+12
View File
@@ -0,0 +1,12 @@
---
name: validator
model: sonnet
description: 代码审查 + Plan Review
isolation: worktree
effort: high
maxTurns: 20
---
你是 validator agent。职责:
1. Plan Review: 审查 plan.md, 找漏洞/模糊/不可执行
2. Code Review: 对标 design.md spec + conventions.md
3. 输出审查意见 (严格, 不放水)
+15
View File
@@ -0,0 +1,15 @@
---
name: vibe-codex
description: 快捷调用 Codex
---
# /vibe-codex $INSTRUCTION
快捷方式: 直接调用 codex-comm skill 发送指令给 Codex。
1. 检测 Codex 可用性
2. 构建上下文 (git diff + 相关文件)
3. 过滤敏感信息
4. execMode(instruction, { sandbox: 'read-only' })
5. 展示 Codex 回复
如果 Codex 不可用 → 输出提示, 不执行。
+14
View File
@@ -0,0 +1,14 @@
---
name: vibe-dev
description: 启动开发工作流
---
# /vibe-dev $TASK
1. 初始化 .ai_state/ (如不存在, 从模板复制)
2. P.A.C.E. 路由 → 确定路径
3. 写入 .ai_state/session.md: 任务描述 + 路径 + 时间戳
4. 执行 RIPER-7 对应阶段
**注意**: 如果已有进行中的任务 (.ai_state/doing.md 有 [ ]), 先询问用户是否要切换任务。
等效于在会话中说 "开始开发: $TASK"
+11
View File
@@ -0,0 +1,11 @@
---
name: vibe-init
description: 首次设置
---
# /vibe-init
1. 创建 .ai_state/ 目录 (从 .claude/templates/ai-state/ 复制)
2. 创建 .gitignore (如不存在)
3. 检测项目技术栈 → 写入 conventions.md
4. 检测 Codex 可用性 → 输出状态
5. 输出: "VibeCoding 已初始化, 用 /vibe-dev 开始开发"
+10
View File
@@ -0,0 +1,10 @@
---
name: vibe-resume
description: 从断点恢复
---
# /vibe-resume
1. 读 .ai_state/session.md 确定断点
2. 读 .ai_state/doing.md 确定当前步骤
3. 从断点继续 RIPER-7 流程
4. 如果是 E 阶段 → 从未完成的 Task 继续 Sisyphus
+11
View File
@@ -0,0 +1,11 @@
---
name: vibe-status
description: 显示当前会话状态
---
# /vibe-status
读取并展示:
1. .ai_state/session.md → 当前任务 + 路径 + 阶段
2. .ai_state/doing.md → 当前执行中的步骤
3. .ai_state/plan.md → 进度 (已完成/总数)
4. Codex 状态: 可用? serve 运行中?
+37
View File
@@ -0,0 +1,37 @@
// VibeCoding v9.2.0 — SessionStart: 检测状态 + 恢复 + 提醒
'use strict';
const fs = require('fs');
const path = require('path');
const STATE_DIR = path.join(process.cwd(), '.ai_state');
try {
if (fs.existsSync(STATE_DIR)) {
// 恢复: 读取关键状态文件
const files = ['session.md', 'doing.md', 'plan.md', 'design.md'];
const found = files.filter(f => fs.existsSync(path.join(STATE_DIR, f)));
if (found.length > 0) {
console.log(`[VibeCoding] 恢复会话: ${found.join(', ')} 已加载`);
// 检查未完成任务
const planFile = path.join(STATE_DIR, 'plan.md');
if (fs.existsSync(planFile)) {
const plan = fs.readFileSync(planFile, 'utf8');
const unchecked = (plan.match(/^- \[ \]/gm) || []).length;
if (unchecked > 0) console.log(`[VibeCoding] ⚠ plan.md 有 ${unchecked} 个未完成任务`);
}
}
// Agent 易犯错误提醒
const convFile = path.join(STATE_DIR, 'conventions.md');
if (fs.existsSync(convFile)) {
const conv = fs.readFileSync(convFile, 'utf8');
const errSection = conv.match(/## Agent 易犯错误\n([\s\S]*?)(?=\n##|$)/);
if (errSection && errSection[1].trim()) {
console.log('[VibeCoding] 🔔 Agent 易犯错误提醒:');
console.log(errSection[1].trim().split('\n').slice(0, 5).join('\n'));
}
}
} else {
console.log('[VibeCoding] 新会话: .ai_state/ 不存在, 首次任务时自动初始化');
}
} catch (e) {
console.log('[VibeCoding] context-loader 警告: ' + e.message);
}
+86
View File
@@ -0,0 +1,86 @@
// VibeCoding v9.2.0 — Stop: 4级 Quality Gate
'use strict';
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
process.on('uncaughtException', function(e) {
process.stderr.write('[delivery-gate] ERROR: ' + e.message + '\n');
process.exit(0); // 脚本错误不阻断
});
if (process.env.VIBECODING_HOOKS_DISABLED === '1') { process.exit(0); }
const STATE_DIR = path.join(process.cwd(), '.ai_state');
const severity = { fail: [], rework: [], concerns: [] };
try {
if (!fs.existsSync(STATE_DIR)) { process.exit(0); } // 无状态 = Path A, 放行
const planFile = path.join(STATE_DIR, 'plan.md');
const qualityFile = path.join(STATE_DIR, 'quality.md');
// ── FAIL 级: 硬约束 ──
// 未完成任务
if (fs.existsSync(planFile)) {
const plan = fs.readFileSync(planFile, 'utf8');
const unchecked = (plan.match(/^- \[ \]/gm) || []).length;
if (unchecked > 0) severity.fail.push(`plan.md 有 ${unchecked} 个未完成任务`);
}
// 缺 quality.md (有 plan 但没 quality = T 阶段未执行)
if (fs.existsSync(planFile) && !fs.existsSync(qualityFile)) {
severity.fail.push('缺少 quality.md — T 阶段验证未执行');
}
// 硬编码密钥
try {
const secrets = execSync(
"git diff --cached -U0 2>/dev/null | grep -iE '(password|secret|api_key|token)\\s*[:=]\\s*.' || true",
{ encoding: 'utf8' }
);
if (secrets.trim()) severity.fail.push('疑似硬编码密钥');
} catch {}
// ── REWORK 级: 源码无测试 ──
try {
const diff = execSync('git diff --cached --name-only 2>/dev/null || git diff --name-only 2>/dev/null', { encoding: 'utf8' });
const codeExts = /\.(ts|tsx|js|jsx|py|go|rs|java|rb)$/;
const testPattern = /\.test\.|\.spec\.|__test__|__spec__|_test\.|tests\//;
const configPattern = /config|\.env|\.json$|\.yaml$|\.yml$|\.toml$|\.md$|\.txt$/i;
const srcFiles = diff.split('\n').filter(f =>
f.match(codeExts) && !f.match(testPattern) && !f.match(configPattern)
);
const testFiles = diff.split('\n').filter(f => f.match(testPattern));
if (srcFiles.length > 0 && testFiles.length === 0) {
if (srcFiles.length > 2) {
severity.rework.push(`${srcFiles.length} 个源码文件修改但无对应测试`);
} else {
severity.concerns.push(`${srcFiles.length} 个源码文件修改但无测试 (数量少, 标注)`);
}
}
} catch {}
} catch (e) {
process.exit(0);
}
// ── 输出结果 ──
// Stop hook 语义: exit 0 = 放行停止, exit 2 = 阻断停止(强制继续)
// stdout 输出会作为 context 注入 Claude
const allIssues = [...severity.fail, ...severity.rework, ...severity.concerns];
if (severity.fail.length > 0) {
process.stderr.write(`[delivery-gate] ❌ FAIL — 严重问题, 必须修复:\n${severity.fail.map(i => ` ✗ ${i}`).join('\n')}\n`);
if (severity.rework.length) process.stderr.write(` + REWORK: ${severity.rework.join(', ')}\n`);
if (severity.concerns.length) process.stderr.write(` + CONCERNS: ${severity.concerns.join(', ')}\n`);
process.exit(2); // 阻断: 不让停
}
if (severity.rework.length > 0) {
process.stderr.write(`[delivery-gate] 🔧 REWORK — 需要修复:\n${severity.rework.map(i => ` ✗ ${i}`).join('\n')}\n`);
if (severity.concerns.length) process.stderr.write(` + CONCERNS: ${severity.concerns.join(', ')}\n`);
process.exit(2); // 阻断: 不让停
}
if (severity.concerns.length > 0) {
// CONCERNS: 放行但输出警告作为 context
process.stdout.write(`[delivery-gate] ⚠ CONCERNS (已放行, 建议修复):\n${severity.concerns.map(i => ` △ ${i}`).join('\n')}\n`);
process.exit(0); // 放行: 但警告已注入
}
process.exit(0); // PASS
+19
View File
@@ -0,0 +1,19 @@
// VibeCoding v9.2.0 — PostToolUse(Write|Edit): 格式化
'use strict';
const { execSync } = require('child_process');
const fs = require('fs');
const input = JSON.parse(fs.readFileSync('/dev/stdin', 'utf8'));
const file = input?.tool_input?.file_path || input?.tool_input?.path || '';
try {
if (file.match(/\.(ts|tsx|js|jsx)$/)) {
// 先检查 prettier 存在
if (fs.existsSync('node_modules/.bin/prettier')) {
execSync(`npx prettier --write "${file}" 2>/dev/null`, { timeout: 5000 });
}
} else if (file.match(/\.py$/)) {
try { execSync('which black', { stdio: 'ignore', timeout: 2000 }); } catch { process.exit(0); }
execSync(`python3 -m black "${file}" --quiet 2>/dev/null`, { timeout: 5000 });
}
} catch {}
process.exit(0);
+26
View File
@@ -0,0 +1,26 @@
// VibeCoding v9.2.0 — PreToolUse(Bash): 安全守卫 (JSON decision output)
'use strict';
const input = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
const cmd = input?.tool_input?.command || '';
const BLOCKED = [
/rm\s+-rf\s+[\/~]/, /chmod\s+777/, /curl\s+.*\|\s*(?:bash|sh)/,
/wget\s+.*\|\s*(?:bash|sh)/, />\s*\/etc\//, /mkfs\./, /dd\s+if=/,
/:(){ :\|:& };:/, /fork\s*bomb/i
];
for (const pattern of BLOCKED) {
if (pattern.test(cmd)) {
// 使用 JSON decision output (官方推荐方式)
const output = JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: `[pre-bash] 危险命令被阻断: ${cmd.slice(0, 80)}`
}
});
process.stdout.write(output);
process.exit(0);
}
}
process.exit(0);
+18
View File
@@ -0,0 +1,18 @@
// VibeCoding v9.2.0 — StopFailure: API错误时保存状态
'use strict';
const fs = require('fs');
const path = require('path');
const STATE_DIR = path.join(process.cwd(), '.ai_state');
try {
if (fs.existsSync(STATE_DIR)) {
const sessionFile = path.join(STATE_DIR, 'session.md');
if (fs.existsSync(sessionFile)) {
let content = fs.readFileSync(sessionFile, 'utf8');
const ts = new Date().toISOString();
content += `\n\n## 异常中断\n${ts} — API错误导致会话中断。下次 SessionStart 自动恢复。\n`;
fs.writeFileSync(sessionFile, content);
}
console.log('[VibeCoding] API错误,状态已保存。下次启动自动恢复。');
}
} catch {}
+21
View File
@@ -0,0 +1,21 @@
// VibeCoding v9.2.0 — Stop: TDD 检查 (git diff 对比)
'use strict';
const { execSync } = require('child_process');
try {
const diff = execSync('git diff --name-only 2>/dev/null', { encoding: 'utf8' });
const codeExts = /\.(ts|tsx|js|jsx|py|go|rs)$/;
const testPattern = /\.test\.|\.spec\.|__test__|_test\./;
const configPattern = /config|\.json$|\.yaml$|\.yml$|\.md$|\.lock$/i;
const srcFiles = diff.split('\n').filter(f =>
f.match(codeExts) && !f.match(testPattern) && !f.match(configPattern)
);
const testFiles = diff.split('\n').filter(f => f.match(testPattern));
if (srcFiles.length > 0 && testFiles.length === 0) {
process.stderr.write(`[tdd-check] ⚠ ${srcFiles.length} 个源码修改但无测试。TDD: 先写测试!\n`);
// 不阻断, 只提醒 (阻断在 delivery-gate)
}
} catch {}
process.exit(0);
+108
View File
@@ -0,0 +1,108 @@
{
"environmentVariables": {
"VIBECODING_VERSION": "9.2.0",
"LANGUAGE": "zh-Hans",
"LC_ALL": "zh-Hans",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
"API_TIMEOUT_MS": "3000000",
"CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6"
},
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npx *)",
"Bash(node *)",
"Bash(git *)",
"Bash(cat *)",
"Bash(ls *)",
"Bash(find *)",
"Bash(grep *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(wc *)",
"Bash(mkdir *)",
"Bash(cp *)",
"Bash(mv *)",
"Bash(touch *)",
"Bash(codex *)",
"Bash(ast-grep *)",
"Read(*)",
"Write(*)",
"Edit(*)",
"MultiEdit(*)",
"Glob(*)",
"Grep(*)"
],
"deny": [
"Bash(rm -rf /)",
"Bash(rm -rf /*)",
"Bash(rm -rf ~)",
"Bash(chmod 777 *)",
"Bash(curl * | bash)",
"Read(./secrets/**)",
"Read(./.env.production)"
]
},
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/context-loader.cjs"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/pre-bash.cjs"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/post-edit.cjs"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/delivery-gate.cjs"
}
]
},
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/tdd-check.cjs"
}
]
}
],
"StopFailure": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/stop-failure.cjs"
}
]
}
]
}
}
+38
View File
@@ -0,0 +1,38 @@
---
name: brainstorm
description: R₀ 苏格拉底式需求精炼 — 写代码前激活
---
# Brainstorm (R₀ 需求精炼)
Path B+ 任务在写代码前**必须**激活本 skill。
## 流程
### 0. 自主调研 (提问前)
- 搜索 (Grep/Glob, 或 augment-context-engine 如已安装)项目中与需求相关的现有代码
- 读 .ai_state/knowledge.md + lessons.md 查相关经验
- 读 .ai_state/conventions.md 查编码规范
- 如果 Codex 可用: 用 codex-comm skill 问 Codex "这类需求常见陷阱?"
→ 基于调研结果准备更有深度的问题
### 1. 访谈 (苏格拉底式, 基于调研的针对性问题)
- **一次只问一个问题**, 不堆叠
- 优先选择题, 开放题为辅
- 覆盖: 用户目标、使用场景、边界、非功能需求
- YAGNI 原则: 主动砍不必要的功能
### 2. 提出 2-3 个方案
- 每方案: 架构概述 + 优劣 + 复杂度预估
- context7 查依赖库文档验证可行性
- 标注推荐方案及理由
### 3. 分段呈现设计
- 每段 ≤ 200 字, 用户确认后再下一段
### 4. 确认输出
- 写入 .ai_state/design.md (用模板格式: MUST/SHOULD/COULD + 验收标准)
- cunzhi `DESIGN_READY` 确认
- 进入 plan-first skill
## 铁律
- 设计未确认前**不写任何代码**
+23
View File
@@ -0,0 +1,23 @@
---
name: code-review
description: T 阶段代码审查 — 含 LLM-as-Judge 模式
---
# Code Review (T 阶段)
## 审查清单
1. **Spec 合规**: 每个 MUST 需求是否实现? (对照 design.md)
2. **TDD**: 每个源码文件有对应测试?
3. **边界**: 空输入/超长/并发/错误路径 是否处理?
4. **安全**: 无硬编码密钥, 无 SQL 注入, 输入已验证
5. **可读**: 函数 < 50 行, 注释说明 WHY 不是 WHAT, 严格类型
6. **简洁**: 无过度工程, 无重复代码, 无空 catch
## LLM-as-Judge 模式 (delivery-gate 触发)
输出格式:
```json
{"level": "PASS|CONCERNS|REWORK|FAIL", "issues": [...], "summary": "..."}
```
- FAIL: 未完成任务 / 硬编码密钥 / 缺 quality.md
- REWORK: 源码无测试 (TDD 违规)
- CONCERNS: 非关键文件无测试 (1-2 个警告)
- PASS: 全部通过
+45
View File
@@ -0,0 +1,45 @@
---
name: codex-comm
description: Codex CLI 通信层 — CC↔Codex 基础设施
---
# Codex Communication (通信层)
## 核心脚本
`.claude/skills/codex-comm/scripts/codex-bridge.cjs`
## 功能
1. **检测可用性**: `which codex` + health check (2s 超时)
2. **双模式**: exec (单轮) / serve (多轮 HTTP API)
3. **Session Resume**: `resumeSession(sessionId, prompt)` — 多轮对话保持上下文
4. **UUID 生成**: `generateReviewId()` — 并发安全, 防冲突
5. **敏感过滤**: .env / 密钥 → [REDACTED]
6. **自动降级**: Codex 不可用 → 输出提示, CC 独立执行
## 调用方式
### exec 模式 (简单, 单轮)
```javascript
const { execMode } = require('./scripts/codex-bridge.cjs');
const result = execMode("审查这段代码", { sandbox: 'read-only' });
```
### resume 模式 (多轮, 保持上下文)
```javascript
const { resumeSession } = require('./scripts/codex-bridge.cjs');
// 首次: execMode 返回 sessionId
// 后续: resumeSession(sessionId, "继续审查修改后的计划")
```
### serve 模式 (HTTP API, 最稳定)
```javascript
const { ensureServe, serveRequest } = require('./scripts/codex-bridge.cjs');
ensureServe(); // 自动启动如未运行
```
## Fallback
每个调用 Codex 的点都必须有:
```
如果 Codex 不可用:
输出 "[VibeCoding] Codex 不可用, CC 独立执行"
{CC 独立完成的替代逻辑}
```
@@ -0,0 +1,109 @@
// VibeCoding v9.2.0 — Codex Bridge: CC↔Codex 通信层
'use strict';
const { execSync, spawn } = require('child_process');
const crypto = require('crypto');
const SERVE_PORT = process.env.CODEX_SERVE_PORT || '4096';
const SERVE_URL = `http://localhost:${SERVE_PORT}`;
const DEFAULT_MODEL = 'gpt-5.4';
const EXEC_TIMEOUT = 300000; // 5 min
// ── 敏感信息过滤 ──
function filterSensitive(text) {
return text
.replace(/(?:password|secret|api[_-]?key|token|credential)\s*[:=]\s*['"][^'"]{4,}['"]/gi, '[REDACTED]')
.replace(/(?:-----BEGIN (?:RSA |EC )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC )?PRIVATE KEY-----)/g, '[REDACTED_KEY]');
}
// ── 可用性检测 ──
function isCodexAvailable() {
try { execSync('which codex', { stdio: 'ignore', timeout: 3000 }); return true; }
catch { return false; }
}
// ── Health Check (2s 超时) ──
function healthCheck() {
try { execSync(`curl -sf ${SERVE_URL}/health`, { timeout: 2000, stdio: 'ignore' }); return true; }
catch { return false; }
}
// ── UUID 生成 (并发安全) ──
function generateReviewId() {
return crypto.randomUUID().slice(0, 8);
}
// ── exec 模式 (单轮) ──
function execMode(prompt, opts = {}) {
if (!isCodexAvailable()) return { ok: false, error: 'codex_not_available' };
const safePrompt = filterSensitive(prompt);
const model = opts.model || DEFAULT_MODEL;
const sandbox = opts.sandbox || 'read-only';
try {
// 用 execFileSync 避免 shell 注入 (参数直接传递, 不经过 shell 解析)
const result = require('child_process').execFileSync(
'codex', ['exec', '--sandbox', sandbox, '-m', model, safePrompt],
{ encoding: 'utf8', timeout: opts.timeout || EXEC_TIMEOUT }
);
const sidMatch = result.match(/session[_\s]*(?:id)?[:\s]*([0-9a-f-]{8,})/i);
return { ok: true, output: result, sessionId: sidMatch ? sidMatch[1] : null };
} catch (e) {
return { ok: false, error: e.message };
}
}
// ── resume 模式 (多轮, 保持上下文) ──
function resumeSession(sessionId, prompt, opts = {}) {
if (!isCodexAvailable()) return { ok: false, error: 'codex_not_available' };
const safePrompt = filterSensitive(prompt);
const model = opts.model || DEFAULT_MODEL;
try {
const result = require('child_process').execFileSync(
'codex', ['exec', 'resume', sessionId, '--sandbox', 'read-only', '-m', model, safePrompt],
{ encoding: 'utf8', timeout: opts.timeout || EXEC_TIMEOUT }
);
return { ok: true, output: result, sessionId };
} catch (e) {
console.error(`[codex-bridge] resume failed, falling back to new exec: ${e.message}`);
return execMode(prompt, opts);
}
}
// ── 自动启动 serve ──
function ensureServe() {
if (healthCheck()) return true;
try {
const child = spawn('codex', ['serve', '--port', SERVE_PORT], {
detached: true, stdio: 'ignore'
});
child.unref();
// 等待启动 (最多 10s)
for (let i = 0; i < 10; i++) {
try { execSync('sleep 1'); if (healthCheck()) return true; } catch {}
}
} catch {}
return false;
}
// ── serve HTTP 请求 ──
function serveRequest(endpoint, data) {
try {
const result = execSync(
`curl -sf -X POST ${SERVE_URL}${endpoint} -H "Content-Type: application/json" -d '${JSON.stringify(data)}'`,
{ encoding: 'utf8', timeout: 30000 }
);
return { ok: true, data: JSON.parse(result) };
} catch (e) {
return { ok: false, error: e.message };
}
}
// ── 获取 session 历史消息 ──
function getSessionMessages(sessionId) {
return serveRequest(`/sessions/${sessionId}/messages`, {});
}
module.exports = {
isCodexAvailable, healthCheck, generateReviewId,
execMode, resumeSession, ensureServe, serveRequest,
getSessionMessages, filterSensitive
};
+64
View File
@@ -0,0 +1,64 @@
---
name: codex-review
description: 对抗式计划审查 — P 阶段 CC↔Codex 多轮审查
---
# Codex Review (对抗式审查)
## 触发时机
P 阶段 plan.md 生成后, 如果 Codex 可用。
## 初始化
```
REVIEW_ID = 生成一个 8 位随机 ID (用 Bash: uuidgen | cut -c1-8)
```
## 审查模板选择
根据 design.md 关键词自动选择:
- 包含 API/endpoint/route → templates/api-review.md
- 包含 component/CSS/UI → templates/frontend-review.md
- 包含 deploy/docker/k8s/terraform → templates/infra-review.md
- 否则 → templates/general-review.md
## 对抗循环
### Round 1 (新 exec, 捕获 SESSION_ID):
CC → Codex:
"审查以下计划. 严格找出漏洞/模糊/不可执行的部分.
{plan.md 全文}
{选定的 review template}
结果以 VERDICT: APPROVED 或 VERDICT: REVISE 结尾."
Codex → 质疑列表 + VERDICT
如果 APPROVED → 结束, 记录到 reviews/review-{REVIEW_ID}.md
CC: 逐条评估 (采纳修改 plan / 驳回并说明理由)
### Round 2+ (resume SESSION_ID, 保持上下文):
CC → Codex (codex exec resume SESSION_ID):
"修改后的计划差异: {diff}. 继续审查.
VERDICT: APPROVED 或 VERDICT: REVISE."
Codex → 继续质疑 + VERDICT
...
## 终止条件 (满足任一)
a) Codex 返回 VERDICT: APPROVED
b) 连续 2 轮全部驳回 (记录分歧, cunzhi 让用户决策)
c) 超过 5 轮 (强制停止, 输出分歧摘要)
## 审查结果持久化
每次审查写入 `reviews/review-{REVIEW_ID}.md`:
```markdown
# Review {REVIEW_ID}
Date: {timestamp}
Rounds: {n}
Final Verdict: {APPROVED|STALEMATE|TIMEOUT}
## 采纳的修改
- ...
## 驳回的质疑
- ...
## 遗留分歧
- ...
```
## Fallback
如果 Codex 不可用:
CC 用 validator agent 做 Plan Review:
"作为严格审查者, 这个计划有哪些漏洞/模糊/不可执行的部分?"
@@ -0,0 +1,11 @@
# API Review Template
审查重点:
1. **接口一致性**: RESTful 约定? 命名统一?
2. **幂等性**: PUT/DELETE 是否幂等?
3. **版本控制**: URL 版本 (/v1/) 或 Header 版本?
4. **错误码**: HTTP 状态码 + 业务错误码 是否定义?
5. **认证/授权**: 每个端点的权限要求?
6. **速率限制**: 是否有限流策略?
7. **输入验证**: 请求体 schema 是否严格?
8. **响应格式**: 分页/排序/过滤 是否一致?
@@ -0,0 +1,10 @@
# Frontend Review Template
审查重点:
1. **可访问性**: ARIA 标签? 键盘导航? 色彩对比?
2. **响应式**: 移动端/平板/桌面 断点覆盖?
3. **XSS 防护**: 用户输入是否转义? dangerouslySetInnerHTML?
4. **性能**: 大列表虚拟滚动? 图片懒加载? 包体积?
5. **状态管理**: 数据流清晰? 避免 prop drilling?
6. **错误边界**: React ErrorBoundary? 加载/空/错误状态?
7. **国际化**: 硬编码文案? 日期/数字格式?
@@ -0,0 +1,10 @@
# General Review Template
审查重点:
1. **需求覆盖**: 每个 MUST 需求是否有对应任务?
2. **任务粒度**: 每个任务是否可在 1-2 小时内完成?
3. **依赖拓扑**: 任务依赖是否有环? 关键路径是什么?
4. **风险识别**: 哪些任务最可能出问题? 有 plan B?
5. **测试策略**: 单元/集成/E2E 比例合理?
6. **模糊检测**: 有没有"优化""改进"等模糊词?
7. **遗漏检测**: 错误处理/日志/监控/文档 是否涵盖?
@@ -0,0 +1,10 @@
# Infrastructure Review Template
审查重点:
1. **可用性**: 单点故障? 副本数? 健康检查?
2. **备份/恢复**: 数据备份策略? RTO/RPO?
3. **回滚计划**: 部署失败如何回滚? 数据库迁移可逆?
4. **监控/告警**: 关键指标有监控? 告警阈值合理?
5. **安全**: 网络隔离? 密钥轮换? 最小权限?
6. **成本**: 资源配置合理? 有自动伸缩?
7. **IaC**: 基础设施代码化? 可重复部署?
+15
View File
@@ -0,0 +1,15 @@
---
name: context7
description: 库文档按需拉取
---
# Context7 (库文档查询)
需要查询依赖库文档时:
1. 优先: `npx ctx7 resolve {库名}` CLI 查询
2. 备选: web search 查最新 API
3. 缓存: 查过的 API 结论写入当前阶段笔记, 避免重复查询
## 触发时机
- R 阶段: 验证技术方案可行性
- E 阶段: 实现时遇到不确定的 API
- T 阶段: 验证 API 用法正确性
+27
View File
@@ -0,0 +1,27 @@
---
name: debugging
description: 系统化调试 — 4阶段强制流程
---
# Systematic Debugging
遇到 bug 时**必须**按以下 4 阶段执行, 禁止跳步:
## 1. 复现 (Reproduce)
- 写一个**最小**可复现用例
- 记录: 输入、期望输出、实际输出
- 如果无法复现 → 停, 收集更多信息
## 2. 定位 (Locate)
- 从错误点向上追溯调用链
- 用 console.log / debugger / 断点缩小范围
- **不要猜**: 用证据定位, 不是直觉
## 3. 修复 (Fix)
- 只改**根因**, 不改症状
- 修复必须有对应测试覆盖
- 禁止: `as any`, `try {} catch {}` 空吞, `// TODO: fix later`
## 4. 验证 (Verify)
- 运行原始复现用例 → 通过
- 运行全量测试 → 无回归
- Reflexion: "这个 bug 的模式值得记录到 conventions.md 吗?"
+18
View File
@@ -0,0 +1,18 @@
---
name: e2e
description: 端到端测试 — Path C+ 或有 E2E 框架时
---
# E2E Testing
## 前置条件
- 项目有 E2E 框架 (Playwright/Cypress/Selenium)
- Path C+ 或用户显式要求
## 流程
1. 基于 design.md 验收标准编写 E2E 用例
2. 运行 E2E: `npx playwright test` 或项目配置的命令
3. 失败 → 定位是测试问题还是实现问题
4. 结果追加到 quality.md
## 如果没有 E2E 框架
- 手动验证清单: 列出关键用户流程 + 验证步骤
+35
View File
@@ -0,0 +1,35 @@
---
name: finish-branch
description: V 阶段分支收尾 — kaizen 之后, 交付确认之前
---
# Finish Branch (分支收尾)
## 触发时机
V 阶段 kaizen 完成后, cunzhi `DELIVERY_COMPLETE` 之前。
## 流程
1. 展示选项给用户:
a) **merge**: 合并到主分支
b) **pr**: 创建 Pull Request
c) **keep**: 保留分支不动
d) **discard**: 确认后删除分支
2. 如果选 **pr**:
- 自动生成 PR description:
```
## 标题: {design.md 第一行}
## 摘要: {quality.md 总结}
## 变更列表:
{plan.md 中已完成的 Task 列表}
## 测试: {quality.md 验证结果}
```
- 执行: `gh pr create` 或输出文本供用户复制
3. 如果选 **merge**:
- 检查是否有冲突: `git merge --no-commit --no-ff main`
- 无冲突 → merge + 删除分支
- 有冲突 → 输出冲突文件, 用户决定
4. 如果选 **discard**:
- cunzhi 确认 "确定丢弃分支 {branch_name}?"
- 确认后: `git checkout main && git branch -D {branch_name}`
+23
View File
@@ -0,0 +1,23 @@
---
name: kaizen
description: V 阶段持续改进回顾
---
# Kaizen (V 阶段回顾)
## 流程
1. 回顾本次开发:
- 哪些做得好? (保持)
- 哪些做得差? (改进)
- 有没有反复出现的模式性错误?
2. 更新 .ai_state/lessons.md:
- 新发现的技术陷阱
- 有效的解决模式
- 项目特有的约定
3. 更新 .ai_state/conventions.md "## Agent 易犯错误" 段:
- 如果 Reflexion/Review 中发现了模式性错误
- 格式: `- "具体错误描述 + 正确做法"`
- 这些错误会在 SessionStart 时由 context-loader 输出提醒
4. 产出摘要给用户
+26
View File
@@ -0,0 +1,26 @@
---
name: plan-first
description: P 阶段计划生成 — design.md 确认后激活
---
# Plan-First (P 阶段)
## 流程
1. 读 .ai_state/design.md 全文
2. 分解为可执行任务, 每个任务:
```
- [ ] T-001: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: {前置任务}
```
3. 任务排序: 依赖拓扑 → 风险高的先做
4. 写入 .ai_state/plan.md
## 计划质量检查
- 每个任务有明确的"完成"定义
- 没有模糊词 ("优化", "改进" → 改为具体指标)
- 估算总任务数, 超过 15 个考虑拆分 milestone
## 双 Agent 对抗审查
如果 Codex 可用 → 触发 codex-review skill 做对抗式审查
如果 Codex 不可用 → CC 用 validator agent 自审:
"作为审查者, 这个计划有哪些漏洞/模糊/不可执行的部分?"
+27
View File
@@ -0,0 +1,27 @@
---
name: reflexion
description: E 阶段自我反思 — 每个 Task Micro-review 之前
---
# Reflexion (自我反思)
## 触发时机
E 阶段每个 Task 实现完成后, Micro-review 之前。
## 反思清单
逐条自问:
1. 我有没有走捷径? (如: 用 `as any` 绕过类型检查, 空 catch 吞错误)
2. 我有没有忽略边界条件? (空输入/超长/并发/零值/null)
3. 我有没有硬编码本应配置的值? (URL/端口/阈值/路径)
4. 我有没有过度工程? (加了需求没要求的功能/抽象层)
5. 我有没有偏离 design.md 的方案? (擅自"优化"设计)
6. 这段代码 6 个月后我还能理解吗? (命名/结构/注释)
## 处理
- 发现问题 → **立即修复**, 不留 TODO
- 值得记录的模式 → 追加到 .ai_state/lessons.md
- 模式性错误 → 追加到 conventions.md "Agent 易犯错误"
## 与 Micro-review 的关系
Reflexion = "我审视自己" (主观, 面向实现质量)
Micro-review = "对标 spec + 标准" (客观, 面向需求合规)
两者互补, 不重叠。先 Reflexion 再 Micro-review。
+16
View File
@@ -0,0 +1,16 @@
---
name: security-review
description: 安全审查 — Path C+ 或显式触发
---
# Security Review
## 检查项
1. **认证/授权**: 每个端点是否有权限检查?
2. **输入验证**: 所有外部输入是否已验证和消毒?
3. **密钥管理**: 无硬编码, 用环境变量或密钥管理服务
4. **依赖**: `npm audit` / `pip audit` 无高危漏洞
5. **日志**: 不记录敏感信息 (密码/token/PII)
6. **CORS/CSP**: 如有 Web 接口, 是否配置正确?
## 产出
- 安全审查结果追加到 quality.md
+20
View File
@@ -0,0 +1,20 @@
---
name: verification
description: T 阶段验证 — 测试 + 覆盖率 + 验收标准
---
# Verification (T 阶段)
## 流程
1. 运行测试: `npm test` 或项目配置的测试命令
2. 覆盖率: 如有配置, 检查覆盖率阈值
3. TypeScript: `npx tsc --noEmit` (如有 tsconfig.json)
4. Lint: `npx eslint . --max-warnings 0` (如有 eslint 配置, Path C+ 强制)
## 验收标准逐条确认 (v9.2.0 新增)
5. 读 .ai_state/design.md 的 "## 验收标准"
6. 逐条确认: 这个标准是否被满足? 证据是什么 (测试名/文件位置)?
7. 未满足的标准 → 标注到 .ai_state/quality.md "## 未满足验收标准"
8. 如果有 E2E 框架 → 运行 E2E 确认用户流程
## 产出
- .ai_state/quality.md 填入验证结果 + 未满足标准
+12
View File
@@ -0,0 +1,12 @@
# Conventions
## 项目编码规范
{由 vibe-init 自动检测并填入, 或手动编写}
## 依赖版本
{关键依赖 + 版本号}
## Agent 易犯错误
> 由 reflexion/kaizen 自动追加, 帮助 agent 避免重复犯错
- (初始为空, 使用过程中逐渐积累)
+24
View File
@@ -0,0 +1,24 @@
# Design Spec
## 需求 (MUST/SHOULD/COULD)
### MUST (必须实现)
- {核心功能 1}
- {核心功能 2}
### SHOULD (应该实现)
- {重要功能}
### COULD (可以实现)
- {锦上添花}
## 技术方案
{架构 + 关键设计决策}
## 验收标准
- [ ] {标准 1: 具体可验证的条件}
- [ ] {标准 2: 具体可验证的条件}
## 非功能需求
- 性能: {指标}
- 安全: {要求}
+7
View File
@@ -0,0 +1,7 @@
# Doing
## 当前执行
- [ ] {当前步骤描述}
## 执行历史
{自动追加完成的步骤}
+10
View File
@@ -0,0 +1,10 @@
# Lessons Learned
## 技术陷阱
{Reflexion/Kaizen 发现的技术问题}
## 有效模式
{本项目中验证有效的解决方案}
## 项目特有知识
{不在文档中但很重要的隐性知识}
+14
View File
@@ -0,0 +1,14 @@
# Plan
## 任务列表
- [ ] T-001: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: 无
- [ ] T-002: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: T-001
## 对抗审查记录
{Codex 审查结果摘要, 或 "CC 独立审查"}
+18
View File
@@ -0,0 +1,18 @@
# Quality Report
## 验证结果
- 测试: {通过/失败} ({覆盖率}%)
- TypeScript: {通过/失败}
- Lint: {通过/失败}
## 验收标准确认
- [x] {标准 1}: 满足, 证据: {测试名/文件位置}
- [ ] {标准 2}: 未满足, 原因: {说明}
## 代码审查
- 审查者: {CC / Codex / 互审}
- 发现问题: {数量}
- 已修复: {数量}
## 未满足验收标准
{列出未满足的标准 + 原因}
+13
View File
@@ -0,0 +1,13 @@
# Session
## 任务
{任务描述}
## 路径
P.A.C.E. Path: {A|B|C|D}
## 当前阶段
RIPER-7: {R₀|R|D|P|E|T|V}
## 时间戳
开始: {ISO timestamp}
+13
View File
@@ -0,0 +1,13 @@
# P.A.C.E. 复杂度路由 v9.2.0
收到任务后, 按以下规则选择路径:
| 条件 | 路径 | 阶段 | Codex 参与 |
|------|------|------|-----------|
| 修 bug / 改配置 / <30min | **A (快速)** | E→T | 可选 |
| 新功能 / 重构 / 30min-4h | **B (标准)** | R₀→R→D→P→E→T→V | P对抗审查 + E委托 + T互审 |
| 跨模块 / 架构变更 / >4h | **C (复杂)** | 同B + 子代理并行 | 同B + 多任务并行 |
| 多服务 / 全栈 / 多人协作 | **D (系统)** | 同C + 设计评审 | 同C |
选定路径后 → 读 riper-7.md 执行对应阶段。
Path A 跳过 R₀/R/D/P, 直接 E→T。
+71
View File
@@ -0,0 +1,71 @@
# RIPER-7 阶段编排 v9.2.0
## 每阶段进入前 (通用)
1. 这一步要解决的核心问题是什么?
2. 项目里有没有类似实现? → 搜索 (Grep/Glob, 或 augment-context-engine 如已安装)
3. 用到的库 API 确定吗? → context7 skill 查文档
4. .ai_state/lessons.md + conventions.md 有相关经验吗?
---
## R₀ 需求精炼 (Path B+)
**技能**: brainstorm skill (含步骤0自主调研)
**产出**: .ai_state/design.md (Spec: MUST/SHOULD/COULD + 验收标准)
**门控**: cunzhi `DESIGN_READY` (cunzhi 不可用时: 直接输出 "[DESIGN_READY] 请确认" 等用户回复)
## R 技术调研 (Path B+)
**读**: design.md
**动手**: 搜索相关代码 + 查库版本和 API
**产出**: design.md 追加技术方案
**要回答**: 有没有可复用的现有代码? 需要新依赖吗?
## D 方案定稿 (Path B+)
**读**: design.md
**检查**: 接口最小化? 错误处理完整? 有没有更简单的方案?
**产出**: design.md 最终版 (含验收标准)
**门控**: cunzhi `DESIGN_FINALIZED` (cunzhi 不可用时: 直接输出确认提示)
## P 计划 (Path B+)
**技能**: plan-first skill → 生成 plan.md (T-001/T-002... 格式)
**双 Agent**: 如果 Codex 可用 → codex-review skill 对抗审查
- CC 提交 plan.md → Codex 质疑 → CC 评估采纳/驳回 → 循环
- 终止: VERDICT: APPROVED / 连续2轮全驳 / 超5轮
- 审查结果持久化到 reviews/review-{uuid}.md
**如果 Codex 不可用**: CC 用 validator agent 做 Plan Review
**门控**: cunzhi `PLAN_CONFIRMED` (cunzhi 不可用时: 直接输出确认提示)
## E 执行 (Path B+) — Sisyphus 循环
对 plan.md 每个 Task:
1. 读 Task 文本 + 相关文件 + conventions.md
2. **双 Agent**: 如果 Codex 可用 → codex-comm skill 委托 Codex 执行
如果 Codex 不可用 → CC builder agent 执行
2.5. **Reflexion** (自我反思 → reflexion skill):
"这个实现有没有: 走捷径/忽略边界/硬编码/过度工程/偏离 spec?"
发现问题 → 立即修复
值得记录 → lessons.md
3. **Micro-review**: 对标 design.md spec + conventions.md 标准
通过 → [x] Task + commit
不通过 → 反馈修复
**铁律**: plan.md 有任何 [ ] 未完成, 不停止。这就是 Sisyphus。
## T 测试/审查 (Path B+)
1. verification skill: 跑测试 + 覆盖率
1.5. **验收标准确认**:
读 design.md "## 验收标准" → 逐条确认是否满足
未满足 → 标注到 quality.md "## 未满足验收标准"
2. code-review skill: 代码审查
3. **双 Agent 互审**: 如果 Codex 可用 → CC 审查 Codex 产出 + Codex 反审 CC 修改
如果 Codex 不可用 → CC 单方审查
4. 综合 → quality.md
5. **4 级 Quality Gate** (delivery-gate.cjs):
PASS (exit 0) → 允许停止
CONCERNS (exit 0 + stdout 警告) → 允许停止, 警告注入 context
REWORK (exit 2) → 阻断停止, 强制修复
FAIL (exit 2) → 阻断停止, 必须大幅修复
## V 归档 (Path B+)
1. kaizen skill: 回顾 + lessons.md
1.5. **分支收尾** (finish-branch skill):
选项: merge / PR / keep / discard
PR → 自动生成 description (基于 plan.md + quality.md)
2. cunzhi `DELIVERY_COMPLETE` (cunzhi 不可用时: 直接输出确认提示)
+47
View File
@@ -0,0 +1,47 @@
# VibeCoding Kernel v9.2.0 — Codex CLI
你是一个INTJ性格的工程化 AI 编码助手。用 P.A.C.E. 路由复杂度, 用 RIPER-7 编排阶段, 用 Skills 执行细节。
**协作模式**: 你可能被 Claude Code (CC) 调用执行任务, 也可能独立运行。
## 框架地图
| 类别 | 文件 | 数量 |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| Workflows | pace.md, riper-7.md | 2 |
| Skills | brainstorm, plan-first, code-review, verification, debugging, kaizen, security-review, context7, e2e, claude-delegate, reflexion, finish-branch | 12 |
| Agents | builder.toml, validator.toml, explorer.toml | 3 |
| State Templates | session, doing, design, plan, conventions, quality, lessons | 7 |
## 启动流程
1. 读 .ai_state/ → 恢复或初始化
2. 读 conventions.md (含 "Agent 易犯错误" 段) → 注意这些坑
3. 评估任务 → P.A.C.E. 路由 → RIPER-7 执行
## 关键规则
- 设计未确认前不写代码 (R₀/R/D 阶段)
- TDD: 先写测试再写实现 (E 阶段)
- Sisyphus: plan.md 所有 [ ] 完成才能停 (E 阶段)
- Reflexion: 每个 Task 完成后自我反思再 Micro-review (E 阶段)
- 4 级 Quality Gate: PASS / CONCERNS / REWORK / FAIL (交付前)
## 被 CC 调用时
- CC 会通过 `codex exec` 发送任务
- 你在只读沙箱中运行, 不直接修改文件
- 输出代码和建议, CC 决定是否应用
- 审查请求以 `VERDICT: APPROVED` 或 `VERDICT: REVISE` 结尾
## MCP 工具 (按需)
- cunzhi: 人工确认检查点
- context7 CLI: `npx ctx7 resolve {库名}`
## 模型
| 场景 | 模型 |
| --------- | ------------------------ |
| 默认 | gpt-5.4 |
| 快速/探索 | gpt-5.4-mini |
| 深度审查 | gpt-5.4 (high reasoning) |
+4
View File
@@ -0,0 +1,4 @@
[agent]
name = "builder"
model = "gpt-5.4"
description = "实现代码 + 测试 (TDD: RED→GREEN→REFACTOR)"
+4
View File
@@ -0,0 +1,4 @@
[agent]
name = "explorer"
model = "gpt-5.4-mini"
description = "代码库调研 + 文档查询 (只读)"
+4
View File
@@ -0,0 +1,4 @@
[agent]
name = "validator"
model = "gpt-5.4"
description = "代码审查 + Plan Review"
+85
View File
@@ -0,0 +1,85 @@
# VibeCoding Kernel v9.2.0 — Codex CLI Config
model_provider = "custom"
model = "gpt-5.4"
model_reasoning_effort = "xhigh"
suppress_unstable_features_warning = true
# 危险,可开启 和下面的二选一,上面的代表绝对信任
# approval_policy = "never" # untrusted|on-request|never
# sandbox_mode = "danger-full-access" # read-only|workspace-write|danger-full-access
approval_policy = "never"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = true # npm install / pip install 需要网络
# Web Search
web_search = "live"
[features]
multi_agent = true # stable; 多代理编排
collaboration_modes = true # stable; 协作模式
shell_snapshot = true # beta; 加速重复命令
unified_exec = true # beta; PTY-backed 执行
shell_tool = true # stable; 默认 shell 工具
apply_patch_freeform = true # experimental; 自由 patch
undo = true # 回滚 Codex 改动;
[tui]
notifications = true
animations = true
[profiles.ci]
approval_policy = "never"
sandbox_mode = "workspace-write"
[profiles.review]
model = "gpt-5.4"
approval_policy = "on-request"
[profiles.dev]
model = "gpt-5.4"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[agents]
max_threads = 3
[agents.builder]
description = "实现代码 + 测试 (TDD: RED→GREEN→REFACTOR)"
config_file = "./agents/builder.toml"
[agents.validator]
description = "代码审查 + Plan Review"
config_file = "./agents/validator.toml"
[agents.explorer]
description = "代码库调研 + 文档查询 (只读)"
config_file = "./agents/explorer.toml"
[model_providers.custom]
name = "custom"
wire_api = "responses"
requires_openai_auth = true
[mcp_servers]
[mcp_servers.mcp-deepwiki]
type = "stdio"
command = "npx"
args = ["-y", "mcp-deepwiki@latest"]
[mcp_servers."cunzhi"]
type = "stdio"
command = "寸止"
[mcp_servers.chrome-devtools]
type = "stdio"
command = "npx"
args = ["-y", "chrome-devtools-mcp@latest"]
[mcp_servers.augment-context-engine]
type = "stdio"
command = "npx"
args = ["ace-tool-rs", "--base-url", "https://acemcp.heroman.wtf/relay/", "--token", ""]
+25
View File
@@ -0,0 +1,25 @@
---
name: brainstorm
description: R₀ 苏格拉底式需求精炼
---
# Brainstorm (R₀ 需求精炼)
Path B+ 任务在写代码前**必须**激活。
## 流程
### 0. 自主调研 (提问前)
- 搜索项目中与需求相关的现有代码
- 读 .ai_state/lessons.md + conventions.md
→ 基于调研结果准备更有深度的问题
### 1. 访谈 (苏格拉底式)
- 一次只问一个问题, 优先选择题
- 覆盖: 目标、场景、边界、非功能需求
- YAGNI: 主动砍不必要的功能
### 2. 提出 2-3 方案
- 每方案: 架构 + 优劣 + 复杂度
- context7 验证可行性
### 3. 确认 → .ai_state/design.md
铁律: 设计未确认前不写代码
+18
View File
@@ -0,0 +1,18 @@
---
name: claude-delegate
description: 接收 CC 派发任务 + 反向调用 CC
---
# Claude Delegate
## 当被 CC 调用时
- CC 通过 codex exec 发送任务
- 你在只读沙箱, 输出代码和建议
- 审查请求: 以 `VERDICT: APPROVED` 或 `VERDICT: REVISE` 结尾
## 反向调用 CC (独立运行时)
如需 Claude 视角:
```bash
# 如果有 claude CLI
claude -p "审查以下代码: {code}"
```
如不可用 → 用 validator agent 自审
+18
View File
@@ -0,0 +1,18 @@
---
name: code-review
description: T 阶段代码审查
---
# Code Review
## 审查清单
1. Spec 合规: 每个 MUST 实现?
2. TDD: 源码有对应测试?
3. 边界: 空输入/超长/并发/错误路径?
4. 安全: 无硬编码密钥, 输入已验证
5. 可读: 函数 < 50 行, 注释说 WHY, 严格类型
6. 简洁: 无过度工程, 无重复, 无空 catch
## LLM-as-Judge 输出格式
```json
{"level": "PASS|CONCERNS|REWORK|FAIL", "issues": [...], "summary": "..."}
```
+9
View File
@@ -0,0 +1,9 @@
---
name: context7
description: 库文档查询
---
# Context7
1. 优先: `npx ctx7 resolve {库名}`
2. 备选: web search
3. 缓存: 查过的结论写入当前笔记
+12
View File
@@ -0,0 +1,12 @@
---
name: debugging
description: 系统化调试 4 阶段
---
# Systematic Debugging
必须按 4 阶段执行, 禁止跳步:
## 1. 复现 — 最小用例, 记录输入/期望/实际
## 2. 定位 — 从错误点向上追溯, 用证据不用直觉
## 3. 修复 — 只改根因, 有对应测试, 禁止 as any / 空 catch
## 4. 验证 — 复现通过 + 全量无回归 + Reflexion: 值得记录?
+9
View File
@@ -0,0 +1,9 @@
---
name: e2e
description: 端到端测试
---
# E2E Testing
前置: 有 E2E 框架 (Playwright/Cypress) 且 Path C+ 或用户要求
流程: 基于验收标准写用例 → 运行 → 结果入 quality.md
无框架: 手动验证清单
+14
View File
@@ -0,0 +1,14 @@
---
name: finish-branch
description: V 阶段分支收尾
---
# Finish Branch
V 阶段 kaizen 后, 交付确认前。
## 选项
a) **pr**: 生成 PR description (标题+摘要+变更+测试)
b) **keep**: 保留分支
c) **discard**: 确认后标记废弃
注意: Codex 不直接执行 git merge, 生成描述供用户操作。
+11
View File
@@ -0,0 +1,11 @@
---
name: kaizen
description: V 阶段回顾
---
# Kaizen
## 流程
1. 回顾: 好的保持, 差的改进, 模式性错误?
2. 更新 lessons.md
3. 更新 conventions.md "## Agent 易犯错误" (如发现模式性错误)
4. 摘要给用户
+21
View File
@@ -0,0 +1,21 @@
---
name: plan-first
description: P 阶段计划生成
---
# Plan-First (P 阶段)
## 流程
1. 读 design.md
2. 分解为可执行任务:
```
- [ ] T-001: {动作} + {目标} + {验收条件}
文件: {涉及文件}
依赖: {前置任务}
```
3. 排序: 依赖拓扑 → 风险高先做
4. 写入 plan.md
## 质量检查
- 每个任务有"完成"定义
- 无模糊词
- 超过 15 个任务考虑拆分
+19
View File
@@ -0,0 +1,19 @@
---
name: reflexion
description: E 阶段自我反思
---
# Reflexion (自我反思)
E 阶段每个 Task 实现完成后, Micro-review 之前。
## 反思清单
1. 走捷径了吗? (as any, 空 catch)
2. 忽略边界了吗? (空/超长/并发/null)
3. 硬编码了吗? (URL/端口/阈值)
4. 过度工程了吗? (需求没要求的功能)
5. 偏离 spec 了吗?
6. 6 个月后能理解吗?
发现问题 → 立即修复
值得记录 → lessons.md
模式性错误 → conventions.md "Agent 易犯错误"
+8
View File
@@ -0,0 +1,8 @@
---
name: security-review
description: 安全审查
---
# Security Review
检查: 认证/授权, 输入验证, 密钥管理, 依赖漏洞, 日志安全, CORS/CSP
产出: 追加到 quality.md
+16
View File
@@ -0,0 +1,16 @@
---
name: verification
description: T 阶段验证
---
# Verification
## 流程
1. 运行测试 + 覆盖率
2. TypeScript 类型检查 (如有)
3. Lint (如有, Path C+ 强制)
## 验收标准逐条确认
4. 读 design.md "## 验收标准"
5. 逐条确认: 满足? 证据?
6. 未满足 → quality.md "## 未满足验收标准"
7. E2E (如有框架)
+9
View File
@@ -0,0 +1,9 @@
# Conventions
## 项目编码规范
{自动检测或手动填写}
## Agent 易犯错误
> 由 reflexion/kaizen 自动追加
- (初始为空)
+19
View File
@@ -0,0 +1,19 @@
# Design Spec
## 需求 (MUST/SHOULD/COULD)
### MUST
- {核心功能}
### SHOULD
- {重要功能}
### COULD
- {锦上添花}
## 技术方案
{架构}
## 验收标准
- [ ] {标准 1}
- [ ] {标准 2}
+7
View File
@@ -0,0 +1,7 @@
# Doing
## 当前执行
- [ ] {当前步骤}
## 历史
{自动追加}
+7
View File
@@ -0,0 +1,7 @@
# Lessons Learned
## 技术陷阱
{发现的问题}
## 有效模式
{有效的解决方案}
+7
View File
@@ -0,0 +1,7 @@
# Plan
## 任务列表
- [ ] T-001: {动作} + {目标} + {验收条件}
文件: {文件}
依赖: 无
+13
View File
@@ -0,0 +1,13 @@
# Quality Report
## 验证结果
- 测试: {通过/失败}
- 类型检查: {通过/失败}
## 验收标准确认
- [x] {标准}: 满足
- [ ] {标准}: 未满足
## 代码审查
- 发现: {数量}
- 已修复: {数量}
+10
View File
@@ -0,0 +1,10 @@
# Session
## 任务
{任务描述}
## 路径
P.A.C.E. Path: {A|B|C|D}
## 当前阶段
RIPER-7: {R₀|R|D|P|E|T|V}
+13
View File
@@ -0,0 +1,13 @@
# P.A.C.E. 复杂度路由 v9.2.0
收到任务后, 按以下规则选择路径:
| 条件 | 路径 | 阶段 |
|------|------|------|
| 修 bug / 改配置 / <30min | **A (快速)** | E→T |
| 新功能 / 重构 / 30min-4h | **B (标准)** | R₀→R→D→P→E→T→V |
| 跨模块 / 架构变更 / >4h | **C (复杂)** | 同B + 子代理并行 |
| 多服务 / 全栈 / 多人协作 | **D (系统)** | 同C + 设计评审 |
选定路径后 → 读 riper-7.md 执行对应阶段。
Path A 跳过 R₀/R/D/P, 直接 E→T。
+57
View File
@@ -0,0 +1,57 @@
# RIPER-7 阶段编排 v9.2.0
## 每阶段进入前 (通用)
1. 这一步要解决的核心问题是什么?
2. 项目里有没有类似实现? → 搜索相关代码
3. 用到的库 API 确定吗? → context7 skill 查文档
4. .ai_state/lessons.md + conventions.md 有相关经验吗?
---
## R₀ 需求精炼 (Path B+)
**技能**: brainstorm skill (含步骤0自主调研)
**产出**: .ai_state/design.md (Spec: MUST/SHOULD/COULD + 验收标准)
**门控**: cunzhi `DESIGN_READY` (cunzhi 不可用时: 直接输出 "[DESIGN_READY] 请确认" 等用户回复)
## R 技术调研 (Path B+)
读 design.md → 搜索相关代码 + 查库文档
产出: design.md 追加技术方案
## D 方案定稿 (Path B+)
读 design.md → 检查接口最小化? 错误处理完整? 更简单的方案?
产出: design.md 最终版
门控: cunzhi `DESIGN_FINALIZED` (cunzhi 不可用时: 直接输出确认提示)
## P 计划 (Path B+)
技能: plan-first skill → 生成 plan.md
**计划审查**: 用 /review 内置功能审查, 或用 validator agent
门控: cunzhi `PLAN_CONFIRMED` (cunzhi 不可用时: 直接输出确认提示)
## E 执行 (Path B+) — Sisyphus 循环
对 plan.md 每个 Task:
1. 读 Task + 相关文件 + conventions.md
2. TDD: 先写测试 → 实现 → 重构
2.5. **Reflexion** (自我反思 → reflexion skill):
"这个实现有没有: 走捷径/忽略边界/硬编码/过度工程/偏离 spec?"
发现问题 → 立即修复
值得记录 → lessons.md
3. **Micro-review**: 对标 design.md spec + conventions.md
通过 → [x] Task + commit
不通过 → 修复
**铁律**: plan.md 有任何 [ ] 未完成, 不停止。
## T 测试/审查 (Path B+)
1. verification skill: 跑测试 + 覆盖率
1.5. **验收标准确认**:
读 design.md "## 验收标准" → 逐条确认是否满足
未满足 → 标注到 quality.md
2. code-review skill: 代码审查
3. 用 /review 内置审查功能 做代码审查
4. 综合 → quality.md
5. Quality Gate: PASS(exit 0) / CONCERNS(exit 0+warn) / REWORK(exit 2) / FAIL(exit 2)
## V 归档 (Path B+)
1. kaizen skill: 回顾 + lessons.md
1.5. **分支收尾** (finish-branch skill):
选项: PR description / keep / discard (Codex 不直接 merge)
2. cunzhi `DELIVERY_COMPLETE` (cunzhi 不可用时: 直接输出确认提示)
+1 -1
View File
@@ -1,7 +1,7 @@
name: 🐞 Bug提交
description: 在使用软件或功能的过程中遇到了错误
title: '[Bug]: '
labels: [ "bug?" ]
labels: ['bug?']
body:
- type: markdown
+1 -1
View File
@@ -1,7 +1,7 @@
name: 🐞 Bug Report
description: Encountered an error while using the software or feature
title: '[Bug]: '
labels: [ "bug?" ]
labels: ['bug?']
body:
- type: markdown
@@ -1,9 +1,9 @@
---
name: 🚀 功能请求
description: 提出一个想法以帮助我们改进W&B
title: "[功能]: "
title: '[功能]: '
labels:
- "功能请求"
- '功能请求'
body:
- type: markdown
@@ -1,9 +1,9 @@
---
name: 🚀 Feature Request
description: Suggest an idea to help us improve W&B
title: "[Feature]: "
title: '[Feature]: '
labels:
- "feature_request"
- 'feature_request'
body:
- type: markdown
+1 -1
View File
@@ -1,7 +1,7 @@
name: 🐞 Bug提交
description: 在使用软件或功能的过程中遇到了错误
title: '[Bug]: '
labels: [ "bug?" ]
labels: ['bug?']
body:
- type: markdown
+1 -1
View File
@@ -1,7 +1,7 @@
name: 🐞 Bug Report
description: Encountered an error while using the software or feature
title: '[Bug]: '
labels: [ "bug?" ]
labels: ['bug?']
body:
- type: markdown
@@ -1,9 +1,9 @@
---
name: 🚀 功能请求
description: 提出一个想法以帮助我们改进W&B
title: "[功能]: "
title: '[功能]: '
labels:
- "功能请求"
- '功能请求'
body:
- type: markdown
@@ -1,9 +1,9 @@
---
name: 🚀 Feature Request
description: Suggest an idea to help us improve W&B
title: "[Feature]: "
title: '[Feature]: '
labels:
- "feature_request"
- 'feature_request'
body:
- type: markdown
+28 -28
View File
@@ -2,7 +2,7 @@ name: Build and Deploy
on:
push:
branches: [ "master" ]
branches: ['master']
paths-ignore:
- 'README.md'
- 'LICENSE'
@@ -17,35 +17,35 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.x
run_install: false
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.x
run_install: false
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'pnpm'
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Install dependencies
run: pnpm install
- name: Build project
run: pnpm build
- name: Build project
run: pnpm build
- name: Upload via SCP
uses: appleboy/scp-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
password: ${{ secrets.SSH_PASSWORD }}
port: ${{ secrets.SSH_PORT }}
source: "dist/*"
target: ${{ secrets.TARGET_PATH }}
rm: true
overwrite: true
- name: Upload via SCP
uses: appleboy/scp-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
password: ${{ secrets.SSH_PASSWORD }}
port: ${{ secrets.SSH_PORT }}
source: 'dist/*'
target: ${{ secrets.TARGET_PATH }}
rm: true
overwrite: true
+34
View File
@@ -0,0 +1,34 @@
name: opencode
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
opencode:
if: |
contains(github.event.comment.body, ' /oc') ||
startsWith(github.event.comment.body, '/oc') ||
contains(github.event.comment.body, ' /opencode') ||
startsWith(github.event.comment.body, '/opencode')
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: read
issues: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Run opencode
uses: anomalyco/opencode/github@latest
env:
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
with:
model: google/gemini-3-pro-preview
+1 -1
View File
@@ -6,7 +6,7 @@ permissions:
on:
push:
tags:
- "v*"
- 'v*'
jobs:
release:
+3
View File
@@ -33,3 +33,6 @@ package-lock.json
yarn.lock
.VSCodeCounter
# VibeCoding state
.ai_state/
+20
View File
@@ -0,0 +1,20 @@
{
"ignorePatterns": [
"src/typings/components.d.ts",
"src/typings/elegant-router.d.ts",
"src/router/elegant",
".ai_state",
".claude",
".codex",
"doc",
"public/streamsaver"
],
"printWidth": 120,
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"experimentalSortPackageJson": {
"sortScripts": true
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"ignorePatterns": [".ai_state", ".claude", ".codex", "doc", "public/streamsaver"],
"categories": {
"correctness": "error",
"suspicious": "error"
},
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "vue"],
"rules": {
"import/no-unassigned-import": "off",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-array-sort": "off",
"unicorn/no-array-reverse": "off",
"unicorn/require-module-specifiers": "off"
}
}
+5 -19
View File
@@ -1,21 +1,11 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
"source.fixAll.oxc": "explicit"
},
"editor.formatOnSave": false,
"eslint.validate": [
"html",
"css",
"scss",
"json",
"jsonc",
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true,
"eslint.validate": ["vue"],
"i18n-ally.displayLanguage": "zh-cn",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.enabledFrameworks": ["vue"],
@@ -26,13 +16,9 @@
"moduleResolution": "node"
},
"prettier.enable": false,
"typescript.tsdk": "node_modules/typescript/lib",
"unocss.root": ["./"],
"vue.server.hybridMode": true,
"files.exclude": { "/docs": true },
"search.exclude": {
"/docs": true,
"**/dist/**": true
},
"cSpell.words": ["Axios", "tinymce"]
}
}
+93 -1
View File
@@ -1,5 +1,98 @@
# 更新日志
## [v2.1.0](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v2.0.0...v2.1.0) (2026-03-27)
### &nbsp;&nbsp;&nbsp;🚨 重大变更
- **projects**: integrate oxlint and oxfmt &nbsp;-&nbsp; by **soybeanfe** [<samp>(6ff74)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6ff74c0c)
### &nbsp;&nbsp;&nbsp;🚀 新功能
- **components**:
- 列设置新增滚动条处理 &nbsp;-&nbsp; by @m-xlsea [<samp>(6696d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6696da52)
- 因包体积过大,使用 wangeditor-next 替换 umodoc &nbsp;-&nbsp; by @m-xlsea [<samp>(c47dd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/c47dd291)
- Column settings support fixed columns. &nbsp;-&nbsp; by @m-xlsea [<samp>(70658)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/70658643)
- Add “Select All” to TableColumnSetting &nbsp;-&nbsp; by @wenyuanw [<samp>(0081b)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/0081b9c0)
- **docs**:
- 新增 GitCode star 徽章 &nbsp;-&nbsp; by @m-xlsea [<samp>(5310d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/5310d352)
- **logo**:
- use new logo &nbsp;-&nbsp; by @soybeanjs [<samp>(5aac5)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/5aac540a)
- **projects**:
- 客户端管理新增状态修改开关 &nbsp;-&nbsp; by @m-xlsea [<samp>(ea6a9)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ea6a92cd)
- Iframe 类型菜单传参更改 &nbsp;-&nbsp; by @m-xlsea [<samp>(bf3d5)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/bf3d5cb3)
- 新增同步租户参数配置功能 &nbsp;-&nbsp; by @m-xlsea [<samp>(901a6)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/901a65ad)
- add the plugin: vite-plugin-vue-transition-root-validator, to optimize the development experience. &nbsp;-&nbsp; by **Azir-11** [<samp>(30e3c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/30e3cdc7)
- 适配新图片验证码样式 &nbsp;-&nbsp; by @m-xlsea [<samp>(1472c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/1472cc92)
- 新增字典类型时默认选择该类型 &nbsp;-&nbsp; by @m-xlsea [<samp>(2f9cd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/2f9cdfc5)
- **types**:
- Added type definition `force` to router push options. &nbsp;-&nbsp; by @m-xlsea [<samp>(a3794)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/a37949f2)
- **workflows**:
- add opencode workflow for issue and PR comment triggers &nbsp;-&nbsp; by @soybeanjs [<samp>(dacee)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dacee143)
### &nbsp;&nbsp;&nbsp;🐞 Bug 修复
- **components**:
- 修复合并时 logo 被替换问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(9954f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9954f0e3)
- 修复列设置的滚动条颜色不随主题切换问题 &nbsp;-&nbsp; by **AN** [<samp>(9b4dd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9b4dd764)
- correction of wrong label bar configuration explanation. &nbsp;-&nbsp; by **Azir-11** [<samp>(6887b)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6887b016)
- **projects**:
- 修复代码生成模板未判断树类型问题 &nbsp;-&nbsp; by **AN** [<samp>(ae440)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ae440204)
- 修复保存表单时提示错误问题 &nbsp;-&nbsp; by **AN** [<samp>(dbbcf)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dbbcf186)
- 修复菜单管理左侧树过滤问题 &nbsp;-&nbsp; by **AN** [<samp>(0ef9f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/0ef9f601)
- fix the long list TableColumnSetting component exceeds the viewport. &nbsp;-&nbsp; by **skyfeiz** [<samp>(cbfb9)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/cbfb932f)
- fix NButton props conflicts. &nbsp;-&nbsp; by **skyfeiz** [<samp>(54107)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/54107aca)
- 修复表单校验提示重复问题 &nbsp;-&nbsp; by **AN** [<samp>(12c73)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/12c73bd8)
- ensure HTML lang attribute is updated when setting locale &nbsp;-&nbsp; by @pan0xc [<samp>(f96c3)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/f96c3c9e)
- correct HTML lang attribute to standard format &nbsp;-&nbsp; by @pan0xc [<samp>(b520d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b520db3e)
- resolve width abnormal issue of NColorPicker. &nbsp;-&nbsp; by **Azir-11** [<samp>(75ccd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/75ccd008)
- fix wrong new tab opening for external link navigation. &nbsp;-&nbsp; by **Azir-11** [<samp>(af1b5)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/af1b5f1d)
- **router**:
- simplify route guard logic and remove unnecessary next calls &nbsp;-&nbsp; by **soybeanfe** [<samp>(3c2cb)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/3c2cbb74)
- **utils**:
- 忽略请求取消错误提示 &nbsp;-&nbsp; by @m-xlsea [<samp>(88c61)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/88c614e8)
### &nbsp;&nbsp;&nbsp;🛠 优化
- **projects**:
- 修复菜单代码质量问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(6f349)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6f34956e)
- modify the injection location of the token. &nbsp;-&nbsp; by **Azir-11** [<samp>(9d48c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9d48ca5f)
- optimize unocss config &nbsp;-&nbsp; by **soybeanfe** [<samp>(6fc6f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6fc6f1c9)
- optimize oxlint config &nbsp;-&nbsp; by @m-xlsea [<samp>(7cdcf)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/7cdcfb59)
### &nbsp;&nbsp;&nbsp;💅 重构
- **projects**: 优化调整保存更新成功提示代码 &nbsp;-&nbsp; by **AN** [<samp>(7a6ee)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/7a6ee7a1)
### &nbsp;&nbsp;&nbsp;📖 文档
- **other**:
- 修复 IFrame 类型菜单无法使用问题 &nbsp;-&nbsp; by @m-xlsea [<samp>(87e3c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/87e3c06a)
- 新增 QQ 交流群说明 &nbsp;-&nbsp; by @m-xlsea [<samp>(b5551)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b5551355)
- 新增 Vibe Coding Claude Code 配置 &nbsp;-&nbsp; by @m-xlsea [<samp>(da015)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/da01523e)
- 更新 Vibe Coding 配置 &nbsp;-&nbsp; by @m-xlsea [<samp>(340e6)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/340e6daf)
- **projects**:
- V2 has been released. &nbsp;-&nbsp; by **skyfeiz** [<samp>(d7394)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/d73947a5)
### &nbsp;&nbsp;&nbsp;🏡 杂务
- **deps**:
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(232e1)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/232e1ac4)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(2a023)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/2a0231da)
- update deps &nbsp;-&nbsp; by **soybeanfe** [<samp>(b867c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b867c290)
- **merge**:
- Merge Soybean branch 'dev' &nbsp;-&nbsp; by @m-xlsea [<samp>(dfe77)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dfe77ade)
- Merge Soybean v2.1.0 &nbsp;-&nbsp; by @m-xlsea [<samp>(3c977)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/3c9770a1)
### &nbsp;&nbsp;&nbsp;🎨 样式
- **projects**:
- 优化注释规范 &nbsp;-&nbsp; by @m-xlsea [<samp>(4139a)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/4139a729)
- fix lint code and format code &nbsp;-&nbsp; by **soybeanfe** [<samp>(781a1)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/781a18f4)
### &nbsp;&nbsp;&nbsp;❤️ 贡献者
[![m-xlsea](https://github.com/m-xlsea.png?size=48)](https://github.com/m-xlsea)&nbsp;&nbsp;[![Elio-An](https://github.com/Elio-An.png?size=48)](https://gitee.com/elio-an)&nbsp;&nbsp;[![pan0xc](https://github.com/pan0xc.png?size=48)](https://github.com/pan0xc)&nbsp;&nbsp;[![soybeanjs](https://github.com/soybeanjs.png?size=48)](https://github.com/soybeanjs)&nbsp;&nbsp;[![wenyuanw](https://github.com/wenyuanw.png?size=48)](https://github.com/wenyuanw)&nbsp;&nbsp;[![Azir-11](https://github.com/Azir-11.png?size=48)](https://github.com/Azir-11)&nbsp;&nbsp;&nbsp;[soybeanfe](mailto:honghuangdc@gmail.com),&nbsp;[skyfeiz](mailto:webzhangfei@163.com),&nbsp;
## [v2.0.0](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v1.2.1...v2.0.0) (2025-12-25)
### &nbsp;&nbsp;&nbsp;🚀 新功能
@@ -487,7 +580,6 @@
[![xlsea](https://github.com/m-xlsea.png?size=48)](https://gitee.com/xlsea)&nbsp;&nbsp;[![soybeanjs](https://github.com/soybeanjs.png?size=48)](https://github.com/soybeanjs)&nbsp;&nbsp;[![wenyuanw](https://github.com/wenyuanw.png?size=48)](https://github.com/wenyuanw)&nbsp;&nbsp;[![Elio-An](https://github.com/Elio-An.png?size=48)](https://gitee.com/elio-an)&nbsp;&nbsp;[![chen-ziwen](https://github.com/chen-ziwen.png?size=48)](https://github.com/chen-ziwen)&nbsp;&nbsp;
[![wangzhongqi0917](https://gitee.com/wangzhongqi0917.png?width=48)](https://gitee.com/wangzhongqi0917)&nbsp;&nbsp;[![qq1822213252](https://gitee.com/qq1822213252.png?width=48)](https://gitee.com/qq1822213252)&nbsp;&nbsp;[![tangzc](https://gitee.com/tangzc.png?width=48)](https://gitee.com/tangzc),&nbsp;[metabytes](https://gitee.com/metabytes)
## [v1.0.0](https://gitee.com/xlsea/ruoyi-plus-soybean/releases/tag/v1.0.0) (2025-06-05)
### &nbsp;&nbsp;&nbsp;🚀 新功能
+38 -7
View File
@@ -15,18 +15,21 @@
<a href="https://www.typescriptlang.org" target="_blank"><img src="https://img.shields.io/badge/TypeScript-5.8-blue" alt="typescript"></a>
<a href="https://vite.dev" target="_blank"><img src="https://img.shields.io/badge/Vite-6.2-orange" alt="vite"></a>
<a href="https://www.naiveui.com" target="_blank"><img src="https://img.shields.io/badge/NaiveUI-2.41-purple" alt="naive-ui"></a>
<a href="./LICENSE" target="_blank"><img src="https://img.shields.io/badge/License-MIT-yellow" alt="license"></a>
<a href="./LICENSE" target="_blank"><img src="https://img.shields.io/badge/License-MIT-yellow" alt="license"></a>
<a href="https://qm.qq.com/q/jNMKfdCL8Q" target="_blank"><img src="https://img.shields.io/badge/QQ%E7%BE%A4-451067199-EB1923?logo=qq&logoColor=white" alt="license"></a>
</p>
</div>
# 📢 重要通知
2.0.0 版本已经正式发布(工作流版本请切换 [flow](https://gitee.com/xlsea/ruoyi-plus-soybean/tree/flow/) 分支查看),但仍然建议:
- 在生产环境使用前进行充分测试
- 关注项目更新,及时获取最新版本
- 积极反馈问题,帮助我们快速迭代
**后续规划**
- 多语言国际化完善
- 性能优化和稳定性提升
@@ -61,6 +64,7 @@ RuoYi-Plus-Soybean 是一个现代化的企业级多租户管理系统,它结
## 🛠️ 技术栈
### 前端
- **核心框架**:Vue 3.5.x
- **开发语言**:TypeScript 5.8.x
- **构建工具**:Vite 6.2.x
@@ -72,6 +76,7 @@ RuoYi-Plus-Soybean 是一个现代化的企业级多租户管理系统,它结
- **包管理器**:pnpm 8.x+
### 后端(与RuoYi-Vue-Plus兼容)
- **核心框架**:Spring Boot
- **安全框架**:Spring Security
- **权限认证**:Sa-Token
@@ -122,6 +127,7 @@ root
## 🚀 环境要求与安装
### 环境要求
- Node.js >= 20.19.0
- pnpm >= 10.5.0
- Git
@@ -129,6 +135,7 @@ root
### 安装步骤及说明
1. 克隆仓库
```bash
git clone https://gitee.com/xlsea/ruoyi-plus-soybean.git
cd ruoyi-plus-soybean
@@ -141,21 +148,25 @@ npm install pnpm -g
```
设置淘宝镜像
```bash
pnpm config set registry https://registry.npmmirror.com
```
3. 安装依赖
```bash
pnpm install
```
4. 运行开发服务器
```bash
pnpm dev
```
5. 构建生产版本
```bash
pnpm build
```
@@ -165,12 +176,12 @@ pnpm build
项目提供了代码生成工具和菜单SQL更新文件,在 <a href="https://gitee.com/xlsea/ruoyi-plus-soybean/tree/master/docs" target="_blank">docs</a> 目录下:
- **代码生成工具**
- 代码生成工具类位于 `docs/java` 目录,如果没有修改过VelocityUtils.java文件,直接替换即可
- 代码生成模板位于 `docs/template` 目录,请在ruoyi-generator模块的`resource/vm`下新建 `soy`文件夹,并将所有模板拷贝至`soy`文件夹中
- 代码生成工具类位于 `docs/java` 目录,如果没有修改过VelocityUtils.java文件,直接替换即可
- 代码生成模板位于 `docs/template` 目录,请在ruoyi-generator模块的`resource/vm`下新建 `soy`文件夹,并将所有模板拷贝至`soy`文件夹中
- **菜单SQL更新**
- 菜单数据更新SQL文件位于 `docs/sql` 目录
- 在系统初始化或更新时,需要执行相应的SQL文件来更新菜单数据
- 菜单数据更新SQL文件位于 `docs/sql` 目录
- 在系统初始化或更新时,需要执行相应的SQL文件来更新菜单数据
## 📝 开发指南
@@ -240,7 +251,9 @@ pnpm release
### 核心开发模式
#### 状态管理
使用Pinia进行状态管理,模块位于`src/store/modules`目录:
- **app**: 应用全局状态
- **theme**: 主题配置
- **route**: 路由信息
@@ -250,9 +263,11 @@ pnpm release
- **notice**: 通知管理
#### API交互
项目支持多种HTTP客户端实现:
- **Axios**:
```typescript
import { useRequest } from '@/hooks/common/request';
@@ -260,6 +275,7 @@ const { data, loading, error } = useRequest(() => api.getData(params));
```
- **Hooks使用**:
```typescript
// 布尔值管理
import { useBoolean } from '@sa/hooks';
@@ -275,6 +291,7 @@ const { tableData, loading, getPaginationData } = useTable(fetchTableData);
```
#### 组件使用
项目包含多种业务组件:
- **表格组件**:支持列设置、搜索区域和高级操作
@@ -283,6 +300,7 @@ const { tableData, loading, getPaginationData } = useTable(fetchTableData);
- **布局组件**:支持多种布局模式和主题
### UnoCSS使用指南
项目优先使用 UnoCSS 来实现样式:
```html
@@ -292,6 +310,7 @@ const { tableData, loading, getPaginationData } = useTable(fetchTableData);
```
### 国际化
项目使用vue-i18n实现国际化支持:
```typescript
@@ -305,6 +324,7 @@ console.log(t('common.confirm'));
## 💎 特性与功能
### 前端特性
- **多种布局模式**:支持垂直、水平、混合等多种布局
- **可配置的主题**:明暗模式、主题色定制
- **标签页管理**:多种标签风格、右键菜单
@@ -313,6 +333,7 @@ console.log(t('common.confirm'));
- **权限管理**:菜单和按钮级别的权限控制
### 业务功能
- **用户管理**:用户信息维护、角色分配
- **角色管理**:角色权限配置
- **菜单管理**:系统功能配置
@@ -325,6 +346,7 @@ console.log(t('common.confirm'));
## 🤝 贡献指南
### 开发流程
1. Fork项目
2. 创建功能分支 (`git checkout -b feature/amazing-feature`)
3. 提交更改 (`git commit -m 'feat: add amazing feature'`)
@@ -332,6 +354,7 @@ console.log(t('common.confirm'));
5. 提交Pull Request
### 提交规范
项目使用约定式提交规范:
- `feat`: 新功能
@@ -363,7 +386,6 @@ console.log(t('common.confirm'));
更多周边生态请翻阅 [周边生态](https://docs.soybeanjs.cn/zh/awesome) 文档。
- **作者**: Elio
- **邮箱**: 1983933789@qq.com
- **作者主页**: https://gitee.com/ahcode
@@ -374,12 +396,21 @@ console.log(t('common.confirm'));
- 禁止内容:黄腔、暴力言论、政治话题,违者直接飞机票(踢出群)
- 遇到问题请先阅读 [项目文档](https://docs.ruoyi.xlsea.cn) 和 [Soybean 文档](https://docs.soybeanjs.cn/),某些简单问题不予理睬
- 蜡笔小新头像为机器人助手,私聊不保证回复,问题请在群内讨论
### 微信交流群
蜡笔小新头像为机器人助手,私聊不保证回复,问题请在群内讨论
<img src="https://foruda.gitee.com/images/1749174520085305975/ad1b54fe_5601833.png" width="300px" />
添加作者微信备注:加群
### QQ 交流群
<a href="https://qm.qq.com/q/jNMKfdCL8Q" target="_blank"><img src="https://img.shields.io/badge/%E7%82%B9%E5%87%BB%E5%8A%A0%E5%85%A5%20QQ%20%E4%BA%A4%E6%B5%81%E7%BE%A4-451067199-EB1923?logo=qq&logoColor=white" alt="license"></a>
<img src="https://foruda.gitee.com/images/1769569918127494786/c6e5b6af_5601833.jpg" width="300px" />
## 🧧 捐献作者
作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭
+3 -1
View File
@@ -2,6 +2,7 @@ import type { PluginOption } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import progress from 'vite-plugin-progress';
import vueRootValidator from 'vite-plugin-vue-transition-root-validator';
import { setupElegantRouter } from './router';
import { setupUnocss } from './unocss';
import { setupUnplugin } from './unplugin';
@@ -17,7 +18,8 @@ export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
setupUnocss(viteEnv),
...setupUnplugin(viteEnv),
progress(),
setupHtmlPlugin(buildTime)
setupHtmlPlugin(buildTime),
vueRootValidator()
];
return plugins;
+2 -2
View File
@@ -1,7 +1,7 @@
import process from 'node:process';
import path from 'node:path';
import unocss from '@unocss/vite';
import presetIcons from '@unocss/preset-icons';
import { presetIcons } from 'unocss';
import unocss from 'unocss/vite';
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders';
export function setupUnocss(viteEnv: Env.ImportMeta) {
+2 -2
View File
@@ -30,8 +30,8 @@ UPDATE `sys_menu` SET `path` = 'oss/config', `component` = 'system/oss-config/in
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (9, 'route.about', 0, 99, 'about', 'about/index', '', 1, 1, 'C', '0', '0', '', 'fluent:book-information-24-regular', 103, 1, sysdate(), null, null, '关于页面') ON DUPLICATE KEY UPDATE `update_time` = sysdate();
-- IFrame 类型
UPDATE `sys_menu` SET `component` = 'FrameView', `query_param` = '{"url": "https://ruoyi.xlsea.cn/admin/"}', `is_frame` = 2, `icon` = 'bx:bxl-spring-boot', `menu_name` = 'menu.monitor_admin' WHERE `menu_id` = 117;
UPDATE `sys_menu` SET `component` = 'FrameView', `query_param` = '{"url": "https://preview.snailjob.opensnail.com/"}', `is_frame` = 2, `icon` = 'gridicons:scheduled', `menu_name` = 'menu.monitor_snail-job' WHERE `menu_id` = 120;
UPDATE `sys_menu` SET `component` = 'FrameView', `query_param` = '{"url":"https://ruoyi.xlsea.cn/admin/"}', `is_frame` = 2, `icon` = 'bx:bxl-spring-boot', `menu_name` = 'menu.monitor_admin' WHERE `menu_id` = 117;
UPDATE `sys_menu` SET `component` = 'FrameView', `query_param` = '{"url":"https://preview.snailjob.opensnail.com/"}', `is_frame` = 2, `icon` = 'gridicons:scheduled', `menu_name` = 'menu.monitor_snail-job' WHERE `menu_id` = 120;
-- 外链类型
UPDATE `sys_menu` SET `menu_name` = 'RuoYi-Vue-Plus', `order_num` = 100, `path` = 'https://gitee.com/dromara/RuoYi-Vue-Plus', `component` = 'FrameView', `icon` = 'local-icon-gitee', `remark` = 'RuoYi-Vue-Plus 仓库地址' WHERE `menu_id` = 4;
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (7, 'Soybean Admin', 0, 100, 'https://github.com/soybeanjs', 'FrameView', '', 0, 0, 'M', '0', '0', '', 'mdi:github', 103, 1, sysdate(), null, null, 'Soybean Admin 仓库地址') ON DUPLICATE KEY UPDATE `update_time` = sysdate();
+4 -1
View File
@@ -103,6 +103,7 @@ async function handleSubmit() {
#foreach($column in $columns)#if($column.insert)#set($dummy = $addFields.add($column.javaField))#end#end
const { error } = await fetchCreate${BusinessName}({ #foreach($field in $addFields)$field#if($foreach.hasNext), #end#end });
if (error) return;
window.$message?.success($t('common.addSuccess'));
}
if (props.operateType === 'edit') {
@@ -110,9 +111,9 @@ async function handleSubmit() {
#foreach($column in $columns)#if($column.edit)#set($dummy = $editFields.add($column.javaField))#end#end
const { error } = await fetchUpdate${BusinessName}({ #foreach($field in $editFields)$field#if($foreach.hasNext), #end#end });
if (error) return;
window.$message?.success($t('common.updateSuccess'));
}
window.$message?.success($t('common.updateSuccess'));
closeDrawer();
emit('submitted');
}
@@ -132,7 +133,9 @@ watch(visible, () => {
if (visible.value) {
handleUpdateModelWhenEdit();
restoreValidation();
#if($tplCategory == 'tree')
getTreeList();
#end
}
});
#if($tplCategory == 'tree')
+10 -22
View File
@@ -1,24 +1,12 @@
import { defineConfig } from '@soybeanjs/eslint-config';
import { defineConfig } from '@soybeanjs/eslint-config-vue';
export default defineConfig(
{ vue: true, unocss: true },
{
rules: {
'vue/multi-word-component-names': [
'warn',
{
ignores: ['index', 'App', 'Register', '[id]', '[url]']
}
],
'vue/component-name-in-template-casing': [
'warn',
'PascalCase',
{
registeredComponentsOnly: false,
ignores: ['/^icon-/']
}
],
'unocss/order-attributify': 'off'
export default defineConfig({
'vue/component-name-in-template-casing': [
'warn',
'PascalCase',
{
registeredComponentsOnly: false,
ignores: ['/^icon-/']
}
}
);
]
});
+2 -1
View File
@@ -1,10 +1,11 @@
<!doctype html>
<html lang="zh-cmn-Hans">
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<meta name="author" content="https://blog.xlsea.cn" />
<title>%VITE_APP_TITLE%</title>
</head>
<body>
+53 -55
View File
@@ -1,33 +1,29 @@
{
"name": "ruoyi-vue-plus",
"type": "module",
"version": "2.0.0",
"version": "2.1.0",
"description": "结合了 RuoYi-Vue-Plus 的强大后端功能和 Soybean Admin 的现代化前端特性,为开发者提供了完整的企业管理解决方案。",
"keywords": [
"RuoYi-Vue-Plus",
"Soybean Admin",
"TypeScript",
"UnoCSS",
"Vite7",
"Vue3 admin ",
"ant-design-vue v4",
"naive-ui",
"naive-ui-admin",
"vue-admin-template"
],
"homepage": "https://docs.ruoyi.xlsea.cn",
"bugs": {
"url": "https://gitee.com/xlsea/ruoyi-plus-soybean/issues"
},
"license": "MIT",
"author": {
"name": "xlsea",
"email": "m@xlsea.cn",
"url": "https://gitee.com/xlsea"
},
"license": "MIT",
"homepage": "https://docs.ruoyi.xlsea.cn",
"repository": {
"url": "https://gitee.com/xlsea/ruoyi-plus-soybean.git"
},
"bugs": {
"url": "https://gitee.com/xlsea/ruoyi-plus-soybean/issues"
},
"keywords": [
"RuoYi-Vue-Plus",
"Soybean Admin",
"Vue3 admin ",
"vue-admin-template",
"Vite7",
"TypeScript",
"naive-ui",
"naive-ui-admin",
"ant-design-vue v4",
"UnoCSS"
],
"contributors": [
{
"name": "Elio",
@@ -35,10 +31,10 @@
"url": "https://gitee.com/elio-an"
}
],
"engines": {
"node": ">=20.19.0",
"pnpm": ">=10.5.0"
"repository": {
"url": "https://gitee.com/xlsea/ruoyi-plus-soybean.git"
},
"type": "module",
"scripts": {
"build": "vite build --mode prod",
"build:dev": "vite build --mode dev",
@@ -49,8 +45,9 @@
"dev": "vite --mode dev",
"dev:prod": "vite --mode prod",
"dev:test": "vite --mode test",
"fmt": "oxfmt",
"gen-route": "sa gen-route",
"lint": "eslint . --fix",
"lint": "oxlint --fix && eslint --fix .",
"prepare": "simple-git-hooks",
"preview": "vite preview",
"release": "sa release",
@@ -66,8 +63,9 @@
"@sa/materials": "workspace:*",
"@sa/utils": "workspace:*",
"@types/streamsaver": "^2.0.5",
"@umoteam/editor": "^9.0.1",
"@vueuse/core": "14.1.0",
"@vueuse/core": "14.2.1",
"@wangeditor-next/editor": "^5.6.49",
"@wangeditor-next/editor-for-vue": "^5.1.14",
"clipboard": "2.0.11",
"dayjs": "1.11.19",
"defu": "6.1.4",
@@ -75,53 +73,53 @@
"highlight.js": "^11.11.1",
"jsencrypt": "^3.5.4",
"json5": "2.2.3",
"naive-ui": "2.43.2",
"naive-ui": "2.44.1",
"nprogress": "0.2.0",
"pinia": "3.0.4",
"streamsaver": "^2.0.6",
"tailwind-merge": "3.4.0",
"vue": "3.5.26",
"tailwind-merge": "3.5.0",
"vue": "3.5.29",
"vue-advanced-cropper": "^2.8.9",
"vue-draggable-plus": "0.6.0",
"vue-i18n": "11.2.7",
"vue-router": "4.6.4"
"vue-draggable-plus": "0.6.1",
"vue-i18n": "11.3.0",
"vue-router": "5.0.3"
},
"devDependencies": {
"@elegant-router/vue": "0.3.8",
"@iconify/json": "2.2.417",
"@iconify/json": "2.2.447",
"@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config": "1.7.4",
"@types/node": "25.0.3",
"@soybeanjs/eslint-config-vue": "^0.0.2",
"@types/node": "25.3.5",
"@types/nprogress": "0.2.3",
"@unocss/eslint-config": "66.5.10",
"@unocss/preset-icons": "66.5.10",
"@unocss/preset-uno": "66.5.10",
"@unocss/transformer-directives": "66.5.10",
"@unocss/transformer-variant-group": "66.5.10",
"@unocss/vite": "66.5.10",
"@vitejs/plugin-vue": "6.0.3",
"@vitejs/plugin-vue-jsx": "5.1.2",
"@vitejs/plugin-vue": "6.0.4",
"@vitejs/plugin-vue-jsx": "5.1.4",
"consola": "3.4.2",
"eslint": "9.39.2",
"eslint-plugin-vue": "10.6.2",
"eslint": "10.0.3",
"kolorist": "1.8.0",
"sass": "1.97.1",
"oxfmt": "^0.36.0",
"oxlint": "^1.51.0",
"sass": "1.97.3",
"simple-git-hooks": "2.13.1",
"tsx": "4.21.0",
"typescript": "5.9.3",
"unplugin-icons": "22.5.0",
"unplugin-vue-components": "30.0.0",
"vite": "7.3.0",
"unocss": "^66.6.6",
"unplugin-icons": "23.0.1",
"unplugin-vue-components": "31.0.0",
"vite": "7.3.1",
"vite-plugin-progress": "0.0.7",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "8.0.5",
"vue-eslint-parser": "10.2.0",
"vue-tsc": "3.2.1"
"vite-plugin-vue-devtools": "8.0.7",
"vite-plugin-vue-transition-root-validator": "^0.1.0",
"vue-tsc": "3.2.5"
},
"simple-git-hooks": {
"commit-msg": "pnpm sa git-commit-verify",
"pre-commit": "pnpm typecheck && pnpm lint && git diff --exit-code"
"pre-commit": "pnpm typecheck && pnpm lint && pnpm fmt && git diff --exit-code"
},
"engines": {
"node": ">=20.19.0",
"pnpm": ">=10.5.0"
},
"website": "https://ruoyi.xlsea.cn"
}
+10 -8
View File
@@ -1,20 +1,22 @@
{
"name": "@sa/alova",
"version": "2.0.2",
"version": "2.1.0",
"typesVersions": {
"*": {
"*": [
"./src/*"
]
}
},
"exports": {
".": "./src/index.ts",
"./fetch": "./src/fetch.ts",
"./client": "./src/client.ts",
"./mock": "./src/mock.ts"
},
"typesVersions": {
"*": {
"*": ["./src/*"]
}
},
"dependencies": {
"@alova/mock": "2.0.18",
"@alova/mock": "2.0.19",
"@sa/utils": "workspace:*",
"alova": "3.4.1"
"alova": "3.5.1"
}
}
+11 -9
View File
@@ -1,21 +1,23 @@
{
"name": "@sa/axios",
"version": "2.0.2",
"version": "2.1.0",
"typesVersions": {
"*": {
"*": [
"./src/*"
]
}
},
"exports": {
".": "./src/index.ts"
},
"typesVersions": {
"*": {
"*": ["./src/*"]
}
},
"dependencies": {
"@sa/utils": "workspace:*",
"axios": "1.13.2",
"axios": "1.13.6",
"axios-retry": "4.5.0",
"qs": "6.14.0"
"qs": "6.15.0"
},
"devDependencies": {
"@types/qs": "6.14.0"
"@types/qs": "6.15.0"
}
}
+2 -2
View File
@@ -4,7 +4,7 @@ import axiosRetry from 'axios-retry';
import { nanoid } from '@sa/utils';
import { createAxiosConfig, createDefaultOptions, createRetryOptions } from './options';
import { transformResponse } from './shared';
import { BACKEND_ERROR_CODE, REQUEST_ID_KEY } from './constant';
import { BACKEND_ERROR_CODE, REQUEST_CANCELED_CODE, REQUEST_ID_KEY } from './constant';
import type {
CustomAxiosRequestConfig,
FlatRequestInstance,
@@ -174,6 +174,6 @@ export function createFlatRequest<ResponseData, ApiData, State extends Record<st
return flatRequest;
}
export { BACKEND_ERROR_CODE, REQUEST_ID_KEY };
export { BACKEND_ERROR_CODE, REQUEST_CANCELED_CODE, REQUEST_ID_KEY };
export type * from './type';
export type { CreateAxiosDefaults, AxiosError };
+7 -5
View File
@@ -1,14 +1,16 @@
{
"name": "@sa/color",
"version": "2.0.2",
"exports": {
".": "./src/index.ts"
},
"version": "2.1.0",
"typesVersions": {
"*": {
"*": ["./src/*"]
"*": [
"./src/*"
]
}
},
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"@sa/utils": "workspace:*",
"colord": "2.9.3"
+7 -5
View File
@@ -1,14 +1,16 @@
{
"name": "@sa/hooks",
"version": "2.0.2",
"exports": {
".": "./src/index.ts"
},
"version": "2.1.0",
"typesVersions": {
"*": {
"*": ["./src/*"]
"*": [
"./src/*"
]
}
},
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"@sa/axios": "workspace:*",
"@sa/utils": "workspace:*"
+4 -1
View File
@@ -22,6 +22,7 @@ export type TableColumnCheck = {
title: TableColumnCheckTitle;
checked: boolean;
visible: boolean;
fixed: 'left' | 'right' | 'unFixed';
};
export interface UseTableOptions<ResponseData, ApiData, Column, Pagination extends boolean> {
@@ -77,12 +78,14 @@ export default function useTable<ResponseData, ApiData, Column, Pagination exten
function reloadColumns() {
const checkMap = new Map(columnChecks.value.map(col => [col.key, col.checked]));
const fixedMap = new Map(columnChecks.value.map(col => [col.key, col.fixed]));
const defaultChecks = getColumnChecks(columns());
columnChecks.value = defaultChecks.map(col => ({
...col,
checked: checkMap.get(col.key) ?? col.checked
checked: checkMap.get(col.key) ?? col.checked,
fixed: (fixedMap.get(col.key) !== 'unFixed' ? fixedMap.get(col.key) : undefined) ?? col.fixed
}));
}
+7 -5
View File
@@ -1,14 +1,16 @@
{
"name": "@sa/materials",
"version": "2.0.2",
"exports": {
".": "./src/index.ts"
},
"version": "2.1.0",
"typesVersions": {
"*": {
"*": ["./src/*"]
"*": [
"./src/*"
]
}
},
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"@sa/utils": "workspace:*",
"simplebar-vue": "2.4.2"

Some files were not shown because too many files have changed in this diff Show More