mirror of
https://gitee.com/nicefold/seewis-soybean-plus.git
synced 2026-10-14 03:52:28 +08:00
chore(projects): release v2.1.0
This commit is contained in:
@@ -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 {库名}`)
|
||||
@@ -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]
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: explorer
|
||||
model: haiku
|
||||
description: 代码库调研 + 文档查询 (只读)
|
||||
effort: medium
|
||||
maxTurns: 15
|
||||
---
|
||||
你是 explorer agent。职责:
|
||||
1. 搜索项目中与任务相关的代码
|
||||
2. 查询依赖库文档 (context7)
|
||||
3. 输出调研结果 (不修改任何文件)
|
||||
@@ -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. 输出审查意见 (严格, 不放水)
|
||||
@@ -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 不可用 → 输出提示, 不执行。
|
||||
@@ -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"
|
||||
@@ -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 开始开发"
|
||||
@@ -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
|
||||
@@ -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 运行中?
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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 {}
|
||||
@@ -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);
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
## 铁律
|
||||
- 设计未确认前**不写任何代码**
|
||||
@@ -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: 全部通过
|
||||
@@ -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
|
||||
};
|
||||
@@ -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**: 基础设施代码化? 可重复部署?
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: context7
|
||||
description: 库文档按需拉取
|
||||
---
|
||||
# Context7 (库文档查询)
|
||||
|
||||
需要查询依赖库文档时:
|
||||
1. 优先: `npx ctx7 resolve {库名}` CLI 查询
|
||||
2. 备选: web search 查最新 API
|
||||
3. 缓存: 查过的 API 结论写入当前阶段笔记, 避免重复查询
|
||||
|
||||
## 触发时机
|
||||
- R 阶段: 验证技术方案可行性
|
||||
- E 阶段: 实现时遇到不确定的 API
|
||||
- T 阶段: 验证 API 用法正确性
|
||||
@@ -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 吗?"
|
||||
@@ -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 框架
|
||||
- 手动验证清单: 列出关键用户流程 + 验证步骤
|
||||
@@ -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}`
|
||||
@@ -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. 产出摘要给用户
|
||||
@@ -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 自审:
|
||||
"作为审查者, 这个计划有哪些漏洞/模糊/不可执行的部分?"
|
||||
@@ -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。
|
||||
@@ -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
|
||||
@@ -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 填入验证结果 + 未满足标准
|
||||
@@ -0,0 +1,12 @@
|
||||
# Conventions
|
||||
|
||||
## 项目编码规范
|
||||
{由 vibe-init 自动检测并填入, 或手动编写}
|
||||
|
||||
## 依赖版本
|
||||
{关键依赖 + 版本号}
|
||||
|
||||
## Agent 易犯错误
|
||||
> 由 reflexion/kaizen 自动追加, 帮助 agent 避免重复犯错
|
||||
|
||||
- (初始为空, 使用过程中逐渐积累)
|
||||
@@ -0,0 +1,24 @@
|
||||
# Design Spec
|
||||
|
||||
## 需求 (MUST/SHOULD/COULD)
|
||||
|
||||
### MUST (必须实现)
|
||||
- {核心功能 1}
|
||||
- {核心功能 2}
|
||||
|
||||
### SHOULD (应该实现)
|
||||
- {重要功能}
|
||||
|
||||
### COULD (可以实现)
|
||||
- {锦上添花}
|
||||
|
||||
## 技术方案
|
||||
{架构 + 关键设计决策}
|
||||
|
||||
## 验收标准
|
||||
- [ ] {标准 1: 具体可验证的条件}
|
||||
- [ ] {标准 2: 具体可验证的条件}
|
||||
|
||||
## 非功能需求
|
||||
- 性能: {指标}
|
||||
- 安全: {要求}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Doing
|
||||
|
||||
## 当前执行
|
||||
- [ ] {当前步骤描述}
|
||||
|
||||
## 执行历史
|
||||
{自动追加完成的步骤}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Lessons Learned
|
||||
|
||||
## 技术陷阱
|
||||
{Reflexion/Kaizen 发现的技术问题}
|
||||
|
||||
## 有效模式
|
||||
{本项目中验证有效的解决方案}
|
||||
|
||||
## 项目特有知识
|
||||
{不在文档中但很重要的隐性知识}
|
||||
@@ -0,0 +1,14 @@
|
||||
# Plan
|
||||
|
||||
## 任务列表
|
||||
|
||||
- [ ] T-001: {动作动词} + {目标} + {验收条件}
|
||||
文件: {涉及文件}
|
||||
依赖: 无
|
||||
|
||||
- [ ] T-002: {动作动词} + {目标} + {验收条件}
|
||||
文件: {涉及文件}
|
||||
依赖: T-001
|
||||
|
||||
## 对抗审查记录
|
||||
{Codex 审查结果摘要, 或 "CC 独立审查"}
|
||||
@@ -0,0 +1,18 @@
|
||||
# Quality Report
|
||||
|
||||
## 验证结果
|
||||
- 测试: {通过/失败} ({覆盖率}%)
|
||||
- TypeScript: {通过/失败}
|
||||
- Lint: {通过/失败}
|
||||
|
||||
## 验收标准确认
|
||||
- [x] {标准 1}: 满足, 证据: {测试名/文件位置}
|
||||
- [ ] {标准 2}: 未满足, 原因: {说明}
|
||||
|
||||
## 代码审查
|
||||
- 审查者: {CC / Codex / 互审}
|
||||
- 发现问题: {数量}
|
||||
- 已修复: {数量}
|
||||
|
||||
## 未满足验收标准
|
||||
{列出未满足的标准 + 原因}
|
||||
@@ -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}
|
||||
@@ -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。
|
||||
@@ -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 不可用时: 直接输出确认提示)
|
||||
@@ -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) |
|
||||
@@ -0,0 +1,4 @@
|
||||
[agent]
|
||||
name = "builder"
|
||||
model = "gpt-5.4"
|
||||
description = "实现代码 + 测试 (TDD: RED→GREEN→REFACTOR)"
|
||||
@@ -0,0 +1,4 @@
|
||||
[agent]
|
||||
name = "explorer"
|
||||
model = "gpt-5.4-mini"
|
||||
description = "代码库调研 + 文档查询 (只读)"
|
||||
@@ -0,0 +1,4 @@
|
||||
[agent]
|
||||
name = "validator"
|
||||
model = "gpt-5.4"
|
||||
description = "代码审查 + Plan Review"
|
||||
@@ -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", ""]
|
||||
@@ -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
|
||||
铁律: 设计未确认前不写代码
|
||||
@@ -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 自审
|
||||
@@ -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": "..."}
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: context7
|
||||
description: 库文档查询
|
||||
---
|
||||
# Context7
|
||||
|
||||
1. 优先: `npx ctx7 resolve {库名}`
|
||||
2. 备选: web search
|
||||
3. 缓存: 查过的结论写入当前笔记
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: debugging
|
||||
description: 系统化调试 4 阶段
|
||||
---
|
||||
# Systematic Debugging
|
||||
|
||||
必须按 4 阶段执行, 禁止跳步:
|
||||
|
||||
## 1. 复现 — 最小用例, 记录输入/期望/实际
|
||||
## 2. 定位 — 从错误点向上追溯, 用证据不用直觉
|
||||
## 3. 修复 — 只改根因, 有对应测试, 禁止 as any / 空 catch
|
||||
## 4. 验证 — 复现通过 + 全量无回归 + Reflexion: 值得记录?
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: e2e
|
||||
description: 端到端测试
|
||||
---
|
||||
# E2E Testing
|
||||
|
||||
前置: 有 E2E 框架 (Playwright/Cypress) 且 Path C+ 或用户要求
|
||||
流程: 基于验收标准写用例 → 运行 → 结果入 quality.md
|
||||
无框架: 手动验证清单
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: finish-branch
|
||||
description: V 阶段分支收尾
|
||||
---
|
||||
# Finish Branch
|
||||
|
||||
V 阶段 kaizen 后, 交付确认前。
|
||||
|
||||
## 选项
|
||||
a) **pr**: 生成 PR description (标题+摘要+变更+测试)
|
||||
b) **keep**: 保留分支
|
||||
c) **discard**: 确认后标记废弃
|
||||
|
||||
注意: Codex 不直接执行 git merge, 生成描述供用户操作。
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: kaizen
|
||||
description: V 阶段回顾
|
||||
---
|
||||
# Kaizen
|
||||
|
||||
## 流程
|
||||
1. 回顾: 好的保持, 差的改进, 模式性错误?
|
||||
2. 更新 lessons.md
|
||||
3. 更新 conventions.md "## Agent 易犯错误" (如发现模式性错误)
|
||||
4. 摘要给用户
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: plan-first
|
||||
description: P 阶段计划生成
|
||||
---
|
||||
# Plan-First (P 阶段)
|
||||
|
||||
## 流程
|
||||
1. 读 design.md
|
||||
2. 分解为可执行任务:
|
||||
```
|
||||
- [ ] T-001: {动作} + {目标} + {验收条件}
|
||||
文件: {涉及文件}
|
||||
依赖: {前置任务}
|
||||
```
|
||||
3. 排序: 依赖拓扑 → 风险高先做
|
||||
4. 写入 plan.md
|
||||
|
||||
## 质量检查
|
||||
- 每个任务有"完成"定义
|
||||
- 无模糊词
|
||||
- 超过 15 个任务考虑拆分
|
||||
@@ -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 易犯错误"
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: security-review
|
||||
description: 安全审查
|
||||
---
|
||||
# Security Review
|
||||
|
||||
检查: 认证/授权, 输入验证, 密钥管理, 依赖漏洞, 日志安全, CORS/CSP
|
||||
产出: 追加到 quality.md
|
||||
@@ -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 (如有框架)
|
||||
@@ -0,0 +1,9 @@
|
||||
# Conventions
|
||||
|
||||
## 项目编码规范
|
||||
{自动检测或手动填写}
|
||||
|
||||
## Agent 易犯错误
|
||||
> 由 reflexion/kaizen 自动追加
|
||||
|
||||
- (初始为空)
|
||||
@@ -0,0 +1,19 @@
|
||||
# Design Spec
|
||||
|
||||
## 需求 (MUST/SHOULD/COULD)
|
||||
|
||||
### MUST
|
||||
- {核心功能}
|
||||
|
||||
### SHOULD
|
||||
- {重要功能}
|
||||
|
||||
### COULD
|
||||
- {锦上添花}
|
||||
|
||||
## 技术方案
|
||||
{架构}
|
||||
|
||||
## 验收标准
|
||||
- [ ] {标准 1}
|
||||
- [ ] {标准 2}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Doing
|
||||
|
||||
## 当前执行
|
||||
- [ ] {当前步骤}
|
||||
|
||||
## 历史
|
||||
{自动追加}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Lessons Learned
|
||||
|
||||
## 技术陷阱
|
||||
{发现的问题}
|
||||
|
||||
## 有效模式
|
||||
{有效的解决方案}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Plan
|
||||
|
||||
## 任务列表
|
||||
|
||||
- [ ] T-001: {动作} + {目标} + {验收条件}
|
||||
文件: {文件}
|
||||
依赖: 无
|
||||
@@ -0,0 +1,13 @@
|
||||
# Quality Report
|
||||
|
||||
## 验证结果
|
||||
- 测试: {通过/失败}
|
||||
- 类型检查: {通过/失败}
|
||||
|
||||
## 验收标准确认
|
||||
- [x] {标准}: 满足
|
||||
- [ ] {标准}: 未满足
|
||||
|
||||
## 代码审查
|
||||
- 发现: {数量}
|
||||
- 已修复: {数量}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Session
|
||||
|
||||
## 任务
|
||||
{任务描述}
|
||||
|
||||
## 路径
|
||||
P.A.C.E. Path: {A|B|C|D}
|
||||
|
||||
## 当前阶段
|
||||
RIPER-7: {R₀|R|D|P|E|T|V}
|
||||
@@ -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。
|
||||
@@ -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,7 +1,7 @@
|
||||
name: 🐞 Bug提交
|
||||
description: 在使用软件或功能的过程中遇到了错误
|
||||
title: '[Bug]: '
|
||||
labels: [ "bug?" ]
|
||||
labels: ['bug?']
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -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,7 +1,7 @@
|
||||
name: 🐞 Bug提交
|
||||
description: 在使用软件或功能的过程中遇到了错误
|
||||
title: '[Bug]: '
|
||||
labels: [ "bug?" ]
|
||||
labels: ['bug?']
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -6,7 +6,7 @@ permissions:
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
|
||||
@@ -33,3 +33,6 @@ package-lock.json
|
||||
yarn.lock
|
||||
|
||||
.VSCodeCounter
|
||||
|
||||
# VibeCoding state
|
||||
.ai_state/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
Vendored
+5
-19
@@ -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
@@ -1,5 +1,98 @@
|
||||
# 更新日志
|
||||
|
||||
## [v2.1.0](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v2.0.0...v2.1.0) (2026-03-27)
|
||||
|
||||
### 🚨 重大变更
|
||||
|
||||
- **projects**: integrate oxlint and oxfmt - by **soybeanfe** [<samp>(6ff74)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6ff74c0c)
|
||||
|
||||
### 🚀 新功能
|
||||
|
||||
- **components**:
|
||||
- 列设置新增滚动条处理 - by @m-xlsea [<samp>(6696d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6696da52)
|
||||
- 因包体积过大,使用 wangeditor-next 替换 umodoc - by @m-xlsea [<samp>(c47dd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/c47dd291)
|
||||
- Column settings support fixed columns. - by @m-xlsea [<samp>(70658)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/70658643)
|
||||
- Add “Select All” to TableColumnSetting - by @wenyuanw [<samp>(0081b)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/0081b9c0)
|
||||
- **docs**:
|
||||
- 新增 GitCode star 徽章 - by @m-xlsea [<samp>(5310d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/5310d352)
|
||||
- **logo**:
|
||||
- use new logo - by @soybeanjs [<samp>(5aac5)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/5aac540a)
|
||||
- **projects**:
|
||||
- 客户端管理新增状态修改开关 - by @m-xlsea [<samp>(ea6a9)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ea6a92cd)
|
||||
- Iframe 类型菜单传参更改 - by @m-xlsea [<samp>(bf3d5)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/bf3d5cb3)
|
||||
- 新增同步租户参数配置功能 - 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. - by **Azir-11** [<samp>(30e3c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/30e3cdc7)
|
||||
- 适配新图片验证码样式 - by @m-xlsea [<samp>(1472c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/1472cc92)
|
||||
- 新增字典类型时默认选择该类型 - by @m-xlsea [<samp>(2f9cd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/2f9cdfc5)
|
||||
- **types**:
|
||||
- Added type definition `force` to router push options. - 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 - by @soybeanjs [<samp>(dacee)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dacee143)
|
||||
|
||||
### 🐞 Bug 修复
|
||||
|
||||
- **components**:
|
||||
- 修复合并时 logo 被替换问题 - by @m-xlsea [<samp>(9954f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9954f0e3)
|
||||
- 修复列设置的滚动条颜色不随主题切换问题 - by **AN** [<samp>(9b4dd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9b4dd764)
|
||||
- correction of wrong label bar configuration explanation. - by **Azir-11** [<samp>(6887b)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6887b016)
|
||||
- **projects**:
|
||||
- 修复代码生成模板未判断树类型问题 - by **AN** [<samp>(ae440)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/ae440204)
|
||||
- 修复保存表单时提示错误问题 - by **AN** [<samp>(dbbcf)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dbbcf186)
|
||||
- 修复菜单管理左侧树过滤问题 - by **AN** [<samp>(0ef9f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/0ef9f601)
|
||||
- fix the long list TableColumnSetting component exceeds the viewport. - by **skyfeiz** [<samp>(cbfb9)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/cbfb932f)
|
||||
- fix NButton props conflicts. - by **skyfeiz** [<samp>(54107)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/54107aca)
|
||||
- 修复表单校验提示重复问题 - by **AN** [<samp>(12c73)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/12c73bd8)
|
||||
- ensure HTML lang attribute is updated when setting locale - by @pan0xc [<samp>(f96c3)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/f96c3c9e)
|
||||
- correct HTML lang attribute to standard format - by @pan0xc [<samp>(b520d)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b520db3e)
|
||||
- resolve width abnormal issue of NColorPicker. - by **Azir-11** [<samp>(75ccd)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/75ccd008)
|
||||
- fix wrong new tab opening for external link navigation. - 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 - by **soybeanfe** [<samp>(3c2cb)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/3c2cbb74)
|
||||
- **utils**:
|
||||
- 忽略请求取消错误提示 - by @m-xlsea [<samp>(88c61)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/88c614e8)
|
||||
|
||||
### 🛠 优化
|
||||
|
||||
- **projects**:
|
||||
- 修复菜单代码质量问题 - by @m-xlsea [<samp>(6f349)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6f34956e)
|
||||
- modify the injection location of the token. - by **Azir-11** [<samp>(9d48c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/9d48ca5f)
|
||||
- optimize unocss config - by **soybeanfe** [<samp>(6fc6f)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/6fc6f1c9)
|
||||
- optimize oxlint config - by @m-xlsea [<samp>(7cdcf)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/7cdcfb59)
|
||||
|
||||
### 💅 重构
|
||||
|
||||
- **projects**: 优化调整保存更新成功提示代码 - by **AN** [<samp>(7a6ee)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/7a6ee7a1)
|
||||
|
||||
### 📖 文档
|
||||
|
||||
- **other**:
|
||||
- 修复 IFrame 类型菜单无法使用问题 - by @m-xlsea [<samp>(87e3c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/87e3c06a)
|
||||
- 新增 QQ 交流群说明 - by @m-xlsea [<samp>(b5551)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b5551355)
|
||||
- 新增 Vibe Coding Claude Code 配置 - by @m-xlsea [<samp>(da015)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/da01523e)
|
||||
- 更新 Vibe Coding 配置 - by @m-xlsea [<samp>(340e6)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/340e6daf)
|
||||
- **projects**:
|
||||
- V2 has been released. - by **skyfeiz** [<samp>(d7394)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/d73947a5)
|
||||
|
||||
### 🏡 杂务
|
||||
|
||||
- **deps**:
|
||||
- update deps - by @soybeanjs [<samp>(232e1)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/232e1ac4)
|
||||
- update deps - by @soybeanjs [<samp>(2a023)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/2a0231da)
|
||||
- update deps - by **soybeanfe** [<samp>(b867c)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/b867c290)
|
||||
- **merge**:
|
||||
- Merge Soybean branch 'dev' - by @m-xlsea [<samp>(dfe77)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/dfe77ade)
|
||||
- Merge Soybean v2.1.0 - by @m-xlsea [<samp>(3c977)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/3c9770a1)
|
||||
|
||||
### 🎨 样式
|
||||
|
||||
- **projects**:
|
||||
- 优化注释规范 - by @m-xlsea [<samp>(4139a)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/4139a729)
|
||||
- fix lint code and format code - by **soybeanfe** [<samp>(781a1)</samp>](https://gitee.com/xlsea/ruoyi-plus-soybean/commit/781a18f4)
|
||||
|
||||
### ❤️ 贡献者
|
||||
|
||||
[](https://github.com/m-xlsea) [](https://gitee.com/elio-an) [](https://github.com/pan0xc) [](https://github.com/soybeanjs) [](https://github.com/wenyuanw) [](https://github.com/Azir-11) [soybeanfe](mailto:honghuangdc@gmail.com), [skyfeiz](mailto:webzhangfei@163.com),
|
||||
|
||||
## [v2.0.0](https://gitee.com/xlsea/ruoyi-plus-soybean/compare/v1.2.1...v2.0.0) (2025-12-25)
|
||||
|
||||
### 🚀 新功能
|
||||
@@ -487,7 +580,6 @@
|
||||
[](https://gitee.com/xlsea) [](https://github.com/soybeanjs) [](https://github.com/wenyuanw) [](https://gitee.com/elio-an) [](https://github.com/chen-ziwen)
|
||||
[](https://gitee.com/wangzhongqi0917) [](https://gitee.com/qq1822213252) [](https://gitee.com/tangzc), [metabytes](https://gitee.com/metabytes)
|
||||
|
||||
|
||||
## [v1.0.0](https://gitee.com/xlsea/ruoyi-plus-soybean/releases/tag/v1.0.0) (2025-06-05)
|
||||
|
||||
### 🚀 新功能
|
||||
|
||||
@@ -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" />
|
||||
|
||||
## 🧧 捐献作者
|
||||
|
||||
作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:*"
|
||||
|
||||
@@ -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
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user