docs(other): 更新 Vibe Coding 配置

This commit is contained in:
xlsea
2026-05-23 10:25:03 +08:00
parent 7eeff925cb
commit 7fec02ff77
132 changed files with 4833 additions and 1519 deletions
+27 -32
View File
@@ -1,37 +1,32 @@
# VibeCoding Kernel v9.2.0
# VibeCoding Athena v9.6 — PACE Router & State Harness
你是一个INTJ性格的工程化 AI 编码助手。用 P.A.C.E. 路由复杂度, 用 RIPER-7 编排阶段, 用 Skills 执行细节。
**双 Agent 模式**: CC 编排全流程, P/E/T 阶段可调用 Codex CLI 协作。Codex 不可用时 100% 降级为 CC 独立。
<!--
本文件目标 altitude: 工程纪律的高信号宪法 (constitution)。
- 不规定操作步骤 → skills/pace/SKILL.md
- 不列插件命令 → skills/athena-setup/SKILL.md
- 不写安装/配置 → README.md
- 行数硬上限 30, 超过 build 阶段 wc -l 失败
-->
## 框架地图
<important>
你是 VibeCoding Athena 工程 Agent。CC 做事,Athena 把关。
- 收任务 → 走 PACE 路由 (Hotfix/Bugfix 直接做, Quick+ 走完整流程)
- 自己跑命令 / 跑测试 / 看输出, 证明工作完成
- 工具失败 → 三次重试附 stderr 报告, 不让用户代执行
- 技术结论 → 必须引用官方文档 / 源码 URL
- 调用 subagent 必须产生真实 tool_use, 不允许伪造完成
</important>
| 类别 | 文件 | 数量 |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| 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 |
## 铁律 (9 条)
## 启动流程
1. **设计先行** — 未确认不写代码 (Hotfix/Bugfix 例外)
2. **TDD 强制** — 先测试后实现
3. **Sisyphus** — tasks 全完成才进审查
4. **Review 强制** — Feature+ 至少一次交叉审查
5. **文档即真相** — 阶段转换前 .ai_state/ 必须同步, 单一入口 `.ai_state/_index.md`
6. **完成度证据** — 报告"完成"必须附 tool_use ID 或命令输出片段
7. **出处优先** — API 形态 / 配置字段 / 协议格式必须引用官方文档或源码 URL
8. **索引先行** — 进入决策先读 `.ai_state/_index.md`, 禁止 glob 全目录扫描
9. **Hook 是进化器** — 在 Stop 时反思并写 `.ai_state/details/proposals.md`
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 {库名}`)
设计原则: SRP · OCP · LSP · ISP · DIP · DRY · KISS · 第一性原理 · 先 WHY 后 HOW
-13
View File
@@ -1,13 +0,0 @@
---
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]
+54
View File
@@ -0,0 +1,54 @@
---
name: evaluator
description: >
代码审查评分员. PACE review 阶段调用, 读 _index.md 和 review 报告输出 VERDICT.
tools: Read, Glob, Grep, Bash
model: opus
---
# Evaluator Subagent (v9.6)
## 输入
- 当前 `.ai_state/_index.md` (path/stage/sprint/active_goal)
- `.ai_state/details/reviews/sprint-N.md` (本 sprint 审查报告)
- `.ai_state/details/design.md` (设计 vs 实际)
- `git diff` 本 sprint 提交
## 评分维度 (1-5 分)
```
Functionality (25%) // 是否实现了 design.md 中所有 MUST 项
Spec Compliance (25%) // 是否符合 design.md 的约束 (技术栈/接口/不做什么)
Boundary (15%) // 是否越出 File Structure Plan 边界
Craft (15%) // 代码质量 (命名/SRP/无 dead code)
Robustness (20%) // 边界处理/错误恢复/测试覆盖
```
均分 = F×0.25 + SC×0.25 + B×0.15 + C×0.15 + R×0.20
## VERDICT 规则
| 条件 | 判定 |
|---|---|
| 均分 ≥ 4.0 且**所有维度 ≥ 3** | PASS |
| 均分 ≥ 3.0 但某维度 = 2 | CONCERNS |
| 均分 < 3.0 或任一维度 = 1 | REWORK |
| 多个维度 = 1 或 Boundary 大幅越界 / 安全严重问题 | FAIL |
## 输出要求
- **每个维度评分必须附代码行号级证据** (file.ext:LN, 不是模糊"看起来不错")
- **不允许 Halo Effect**: 一个维度的分数不影响其他维度的独立评分顺序
- **不阻止 PASS 也不强制 CONCERNS**, 根据证据决定
## 协议约束
- 只读 (Read/Glob/Grep), 禁止 Edit/Write
- 输出预算 ≤ 2000 tokens (Anthropic 多 agent 经验: subagent 必须紧凑)
- 不读 .ai_state/.legacy-v9.5/ (那是迁移备份)
- 不要 glob 整个 .ai_state/, 按 _index.md.pointers 跳转
## 输出格式
直接覆盖写回 `.ai_state/details/reviews/sprint-N.md` 的 "## Step 6: @evaluator 评分" 段和 "## VERDICT:" 段。
-11
View File
@@ -1,11 +0,0 @@
---
name: explorer
model: haiku
description: 代码库调研 + 文档查询 (只读)
effort: medium
maxTurns: 15
---
你是 explorer agent。职责:
1. 搜索项目中与任务相关的代码
2. 查询依赖库文档 (context7)
3. 输出调研结果 (不修改任何文件)
+61
View File
@@ -0,0 +1,61 @@
---
name: generator
description: >
代码实现者 (隔离 worktree). 接 task spec, 实现 + TDD, 输出可被 reviewer 验证的 commit.
tools: Read, Write, Edit, MultiEdit, Bash, Glob, Grep
model: opus
isolation: worktree
---
# Generator Subagent (v9.6)
## 输入
- 单个或一组相关 task (来自 `tasks-current.md`)
- 项目 design.md (设计)
- `_index.md` (tech_stack, test_cmd, lint_cmd, conventions, gotchas)
## 工作流
1. **Get-bearings**:
- 读 `.ai_state/_index.md`
- 读 `.ai_state/details/design.md` 对应模块段
- 读 `.ai_state/details/tasks-current.md` 当前 task 的 Boundary/Depends
2. **TDD 强制** (铁律 2):
- 先写测试 (单测或集成测试, 视 task 性质)
- 跑测试确认 RED
- 实现
- 跑测试确认 GREEN
3. **Boundary 守则**:
- 仅修改 task 的 Boundary 段标注的文件路径
- 越界 → 停, 报告主 agent (可能需要升路径)
4. **执行 lint_cmd**:
- 失败 → 修
5. **更新文档**:
- `tasks-current.md` 勾选完成项 ([ ] → [x])
- `progress.md` 追加一行 (YYYY-MM-DD HH:MM [path/stage/sprint] Task N done: ...)
- design.md 不动 (除非发现 design 错; 那种情况报告主 agent 不要自己改)
6. **Commit**:
- `git add -p` 仅添加 Boundary 内文件
- `git commit -m "<task short summary>"`
7. **报告**:
- 输出 commit hash + 测试通过的命令输出片段 (铁律 6)
- 失败 → 完整 stderr (不允许 "I cannot")
## 隔离
- `isolation: worktree` (CC v2.1.121+): 自动创建 git worktree, 不污染主分支
- worktree.baseRef = "head" (settings.json 已配): 从当前 HEAD 创建
## 输出预算
≤ 2000 tokens (Anthropic 多 agent 经验). 详细日志写文件不写回主 agent.
## 失败协议
工具失败 → 三轮重试 (铁律 7):
1. 读 stderr, 尝试明显修复
2. 换参数/换工具
3. 仍失败 → 完整 stderr + exit code + 已尝试方案, 报告主 agent
**禁止**: "请你手动跑", "我没有权限" (没有就申请, 不是放弃).
-12
View File
@@ -1,12 +0,0 @@
---
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
@@ -1,15 +0,0 @@
---
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
@@ -1,14 +0,0 @@
---
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
@@ -1,11 +0,0 @@
---
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
@@ -1,10 +0,0 @@
---
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
@@ -1,11 +0,0 @@
---
name: vibe-status
description: 显示当前会话状态
---
# /vibe-status
读取并展示:
1. .ai_state/session.md → 当前任务 + 路径 + 阶段
2. .ai_state/doing.md → 当前执行中的步骤
3. .ai_state/plan.md → 进度 (已完成/总数)
4. Codex 状态: 可用? serve 运行中?
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PostCompact hook v9.6
// 协议: hookSpecificOutput.{hookEventName: "PostCompact", additionalContext}
// 参考: https://code.claude.com/docs/en/hooks#postcompact
//
// 设计:
// 读 compact-snapshot.md, 注入 _index.md frontmatter 摘要
// 提示 model: 详细内容按 _index.md.pointers lazy load, 不要 glob 全目录 (铁律 8)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const SNAPSHOT_PATH = path.join(STATE_DIR, 'compact-snapshot.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
if (!fs.existsSync(SNAPSHOT_PATH)) {
process.exit(0); return;
}
try {
const snapshot = fs.readFileSync(SNAPSHOT_PATH, 'utf8');
const fmMatch = snapshot.match(/---\n([\s\S]*?)\n---/);
if (!fmMatch) { process.exit(0); return; }
const additionalContext = `[Athena PostCompact 恢复]
上次 compact 前的项目状态 (_index.md frontmatter 快照):
\`\`\`yaml
${fmMatch[1].slice(0, 1500)}
\`\`\`
详细内容**按需** lazy load:
- progress 详情 → 按 pointers.latest_progress 读 progress.md 尾部
- lessons → 命中主题再按 pointers.latest_lesson 跳段
- 完整 _index.md → \`.ai_state/_index.md\`
⚠️ 禁止 glob 整个 .ai_state/ (铁律 8 索引先行)`;
process.stderr.write(`[compact-restore] injected ${additionalContext.length} chars\n`);
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PostCompact',
additionalContext
}
}));
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'compact-restore',
chars: additionalContext.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {
process.stderr.write(`[compact-restore] failed: ${e.message}\n`);
}
process.exit(0);
});
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PreCompact hook v9.6
// 协议: 不阻断, 写文件做副作用
// 参考: https://code.claude.com/docs/en/hooks#precompact
//
// v9.6 减薄设计 (L2.C):
// 旧版 v9.5 快照整个 .ai_state/{tasks,design,progress,lessons,handoff}.md 多个文件
// v9.6 仅快照 _index.md frontmatter (≤30 行), context 利用率提升数倍
// detail/* 内容在 PostCompact 时按需 lazy load (按 pointers 跳转)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const SNAPSHOT_PATH = path.join(STATE_DIR, 'compact-snapshot.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
const trigger = event.trigger || 'unknown'; // "manual" | "auto"
if (!fs.existsSync(INDEX_PATH)) {
process.stderr.write('[compact-snapshot] _index.md not found, skip\n');
process.exit(0); return;
}
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (!fmMatch) {
process.stderr.write('[compact-snapshot] _index.md frontmatter missing, skip\n');
process.exit(0); return;
}
const ts = new Date().toISOString();
const snapshot = `# Athena Compact Snapshot (${trigger})
# Saved at: ${ts}
# 仅快照 _index.md frontmatter (≤30 行). 详细内容按 pointers 在 PostCompact 后 lazy load.
---
${fmMatch[1]}
---
`;
fs.writeFileSync(SNAPSHOT_PATH, snapshot);
process.stderr.write(`[compact-snapshot] saved (${trigger}, ${snapshot.length} chars)\n`);
const trace = JSON.stringify({
ts, hook: 'compact-snapshot', trigger,
chars: snapshot.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {
process.stderr.write(`[compact-snapshot] failed: ${e.message}\n`);
}
process.exit(0);
});
-37
View File
@@ -1,37 +0,0 @@
// 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);
}
Regular → Executable
+175 -73
View File
@@ -1,86 +1,188 @@
// VibeCoding v9.2.0 — Stop: 4级 Quality Gate
#!/usr/bin/env node
'use strict';
// VibeCoding Athena Stop hook (delivery-gate) v9.6
// 协议:
// - block: stdout JSON { decision: "block", reason: "..." }
// - pass: exit 0 无输出
// 参考: https://code.claude.com/docs/en/hooks#stop
//
// v9.6 设计:
// 1. 只读 _index.md 不读单独文件 (铁律 8)
// 2. 适配 CC v2.1.x 的 Stop hook block-cap=8 (CLAUDE_CODE_STOP_HOOK_BLOCK_CAP)
// hook 自身计数 block 次数, 接近 8 时 warn 而非 block
// 3. 当平台支持 /goal (CC v2.1.139+) 时, 让位给 /goal evaluator, 仅作 fallback
// 4. CONCERNS 时仅 systemMessage 不阻断
//
// stop_hook_active 防递归: CC 已经在嵌套 Stop hook 时设置该字段为 true
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); // 脚本错误不阻断
});
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const HOME = process.env.HOME || require('os').homedir();
const COUNTER_PATH = path.join(HOME, '.claude', 'state', 'athena-block-counter.json');
if (process.env.VIBECODING_HOOKS_DISABLED === '1') { process.exit(0); }
const BLOCK_CAP_SAFE = 6; // 留 2 次冗余给 CC 的硬 cap 8
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 阶段验证未执行');
}
// 硬编码密钥
function trace(event) {
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 {}
const line = JSON.stringify({ ts: new Date().toISOString(), hook: 'delivery-gate', ...event }) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), line);
} catch (e) {}
}
// ── REWORK 级: 源码无测试 ──
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
// 防递归 (官方字段)
if (event.stop_hook_active) { process.exit(0); return; }
// 跳过 subagent
if (event.agent_type && event.agent_type !== 'main') { process.exit(0); return; }
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
let fm = '';
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} 个源码文件修改但无测试 (数量少, 标注)`);
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const m = content.match(/^---\n([\s\S]*?)\n---/);
if (!m) { process.exit(0); return; }
fm = m[1];
} catch (e) { process.exit(0); return; }
const getStr = k => {
const m = fm.match(new RegExp('^ ' + k + ': (.*)$', 'm'));
return m ? m[1].replace(/^["']|["']$/g, '').trim() : '';
};
const getNum = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const getBool = k => {
const m = fm.match(new RegExp('^ ' + k + ': (true|false)$', 'm'));
return m ? m[1] === 'true' : false;
};
const pathName = getStr('path');
const stage = getStr('stage');
const sprint = getNum('sprint');
const tasks_pending = getNum('tasks_pending');
const goal_supported = getBool('goal_supported');
const active_goal = getStr('active_goal');
// 仅在 review 阶段 + 非 Hotfix 时介入
if (!sprint || !stage || pathName === 'Hotfix' || pathName === 'Bugfix' || stage !== 'review') {
process.exit(0); return;
}
// 平台支持 /goal 且用户已设置 active_goal → 让位给 /goal evaluator
if (goal_supported && active_goal) {
process.stderr.write('[delivery-gate] defer to /goal evaluator (active goal detected)\n');
trace({ action: 'defer', reason: 'goal-active', sprint });
process.exit(0); return;
}
const needsExtReview = ['Feature', 'Refactor', 'System'].includes(pathName);
const issues = [];
// 1. tasks 全完成
if (tasks_pending > 0) {
issues.push(`${tasks_pending} Task 未完成`);
}
// 2. review report 存在
const reviewFile = path.join(STATE_DIR, 'details', 'reviews', `sprint-${sprint}.md`);
let rc = '';
try {
rc = fs.readFileSync(reviewFile, 'utf8');
} catch (e) {
issues.push('审查报告不存在');
}
// 3. Feature+ 外部审查
if (needsExtReview && rc &&
!/\/codex:review|\/codex:adversarial|reviewer|ecc-agentshield|codex unavailable/i.test(rc)) {
issues.push('无外部审查记录');
}
// 4. 测试通过记录
if (rc && !/test|测试|pass|通过|✅/i.test(rc)) {
issues.push('无测试通过记录');
}
// 5. VERDICT
let verdict = '';
if (rc) {
const m = rc.match(/VERDICT:\s*(PASS|CONCERNS|REWORK|FAIL)/i);
if (m) {
verdict = m[1].toUpperCase();
if (verdict === 'REWORK') issues.push('VERDICT=REWORK');
else if (verdict === 'FAIL') issues.push('VERDICT=FAIL');
else if (verdict === 'CONCERNS') {
process.stderr.write('[delivery-gate] CONCERNS: 建议修复后重新评分\n');
}
}
} catch {}
}
} catch (e) {
if (issues.length > 0) {
// 检查 block 次数, 接近 cap 时降级 systemMessage
fs.mkdirSync(path.dirname(COUNTER_PATH), { recursive: true });
let counter = {};
try { counter = JSON.parse(fs.readFileSync(COUNTER_PATH, 'utf8')); } catch (e) {}
const sessionId = event.session_id || 'unknown';
counter[sessionId] = (counter[sessionId] || 0) + 1;
try { fs.writeFileSync(COUNTER_PATH, JSON.stringify(counter)); } catch (e) {}
const count = counter[sessionId];
process.stderr.write(`[delivery-gate] block #${count}/${BLOCK_CAP_SAFE} ${pathName}/${stage}: ${issues.join(', ')}\n`);
trace({ action: 'block', count, pathName, stage, sprint, issues });
if (count >= BLOCK_CAP_SAFE) {
// 接近 cap, 改为 systemMessage 避免触发 CC 的 force-kill
process.stdout.write(JSON.stringify({
systemMessage: `[Athena] 已连续 block ${count} 次, 建议手动处理: ${issues.join('; ')} (剩余尝试: ${8 - count})`
}));
} else {
process.stdout.write(JSON.stringify({
decision: 'block',
reason: `[Athena delivery-gate] 阻断:\n${issues.map(i => '• ' + i).join('\n')}\n\n修复后再交付 (block ${count}/${BLOCK_CAP_SAFE}).`
}));
}
process.exit(0); return;
}
// 通过, 重置计数
try {
let counter = JSON.parse(fs.readFileSync(COUNTER_PATH, 'utf8'));
delete counter[event.session_id];
fs.writeFileSync(COUNTER_PATH, JSON.stringify(counter));
} catch (e) {}
if (verdict === 'PASS') {
// 检查是否做了 compound
const lessonsText = (() => {
try { return fs.readFileSync(path.join(STATE_DIR, 'details', 'lessons.md'), 'utf8'); }
catch (e) { return ''; }
})();
const compounded = lessonsText.includes(`Sprint ${sprint}`);
if (!compounded) {
const msg = `Sprint ${sprint} 通过但 details/lessons.md 无条目, 建议 /compound 沉淀经验`;
process.stderr.write(`[delivery-gate] PASS ${pathName}/${stage} · ${msg}\n`);
trace({ action: 'soft-warn', pathName, stage, sprint, reason: 'no compound' });
process.stdout.write(JSON.stringify({ systemMessage: `[Athena] ${msg}` }));
} else {
process.stderr.write(`[delivery-gate] PASS ${pathName}/${stage} · lessons ✓\n`);
trace({ action: 'pass', pathName, stage, sprint });
}
} else {
process.stderr.write(`[delivery-gate] 放行 ${pathName}/${stage}\n`);
trace({ action: 'pass', pathName, stage, sprint, verdict });
}
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
});
+175
View File
@@ -0,0 +1,175 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PostToolUse index-updater v9.6 ★新增
// 协议: 无输出即放行 (PostToolUse 不阻断)
// 参考: https://code.claude.com/docs/en/hooks#posttooluse
//
// 设计 (铁律 5 文档即真相 + 铁律 8 索引先行):
// 1. 检测 tool_input.file_path 是否在 .ai_state/details/
// 2. 若是 → 重新扫描 details/ 计算 counts/fingerprints/pointers
// 3. 原子写 _index.md (写 .tmp 后 rename)
// 4. 避免热路径: 同一秒内对同一文件多次触发只更新一次 (debounce by mtime)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const DETAILS_DIR = path.join(STATE_DIR, 'details');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
// 检测 file_path 是否在 details/
const filePath = (event.tool_input && (event.tool_input.file_path || event.tool_input.notebook_path)) || '';
if (!filePath || !filePath.includes('.ai_state/details/')) {
process.exit(0); return;
}
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
try {
updateIndex();
} catch (e) {
process.stderr.write(`[index-updater] failed: ${e.message}\n`);
}
process.exit(0);
});
function readFileSafe(p) {
try { return fs.readFileSync(p, 'utf8'); } catch (e) { return null; }
}
function mtime(p) {
try { return Math.floor(fs.statSync(p).mtimeMs); } catch (e) { return 0; }
}
function countMatches(text, regex) {
if (!text) return 0;
return (text.match(regex) || []).length;
}
function lastSectionLine(text, headPrefix) {
if (!text) return 0;
const lines = text.split('\n');
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].startsWith(headPrefix)) return i + 1;
}
return 0;
}
function lastNonEmptyLine(text) {
if (!text) return 0;
const lines = text.split('\n');
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].trim() && !lines[i].startsWith('<!--') && !lines[i].startsWith('-->')) return i + 1;
}
return 0;
}
function updateIndex() {
// 读 _index.md
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (!fmMatch) {
process.stderr.write('[index-updater] _index.md frontmatter parse failed\n');
return;
}
let fm = fmMatch[1];
const body = fmMatch[2];
// 扫描 details/
const tasksText = readFileSafe(path.join(DETAILS_DIR, 'tasks-current.md'));
const progressText = readFileSafe(path.join(DETAILS_DIR, 'progress.md'));
const lessonsText = readFileSafe(path.join(DETAILS_DIR, 'lessons.md'));
const designText = readFileSafe(path.join(DETAILS_DIR, 'design.md'));
const proposalsText = readFileSafe(path.join(DETAILS_DIR, 'proposals.md'));
// counts
const tasks_pending = countMatches(tasksText, /^- \[ \]/gm);
const tasks_done = countMatches(tasksText, /^- \[x\]/gm);
const tasks_blocked = countMatches(tasksText, /^- \[!\]/gm);
const lessons_lines = countMatches(lessonsText, /^## /gm);
// progress entries: 非空非注释非标题行
let progress_entries = 0;
if (progressText) {
progress_entries = progressText.split('\n')
.filter(l => l.trim() && !l.startsWith('<!--') && !l.startsWith('-->') && !l.startsWith('#'))
.length;
}
// reviews_count
let reviews_count = 0;
let latest_review = '';
try {
const files = fs.readdirSync(path.join(DETAILS_DIR, 'reviews'))
.filter(f => f.match(/^sprint-\d+\.md$/));
reviews_count = files.length;
if (files.length > 0) {
const sorted = files.sort((a, b) => {
const na = parseInt(a.match(/\d+/)[0], 10);
const nb = parseInt(b.match(/\d+/)[0], 10);
return na - nb;
});
latest_review = `details/reviews/${sorted[sorted.length - 1]}`;
}
} catch (e) {}
// pointers
const latest_progress = progressText ? `details/progress.md#L${lastNonEmptyLine(progressText)}` : '';
const latest_lesson = lessonsText ? `details/lessons.md#L${lastSectionLine(lessonsText, '## ')}` : '';
const latest_proposal = proposalsText ? `details/proposals.md#L${lastSectionLine(proposalsText, '## ')}` : '';
// fingerprints
const tasks_mtime = mtime(path.join(DETAILS_DIR, 'tasks-current.md'));
const design_mtime = mtime(path.join(DETAILS_DIR, 'design.md'));
const progress_mtime = mtime(path.join(DETAILS_DIR, 'progress.md'));
const lessons_mtime = mtime(path.join(DETAILS_DIR, 'lessons.md'));
// 替换 frontmatter 字段 (保留其他字段不动)
function replaceField(yaml, key, value, isNumeric) {
const re = new RegExp(`(^ ${key}: ).*$`, 'm');
const val = isNumeric ? value : `"${value}"`;
if (re.test(yaml)) return yaml.replace(re, `$1${val}`);
return yaml; // 不存在不创建, 等用户/init 加
}
fm = replaceField(fm, 'tasks_pending', tasks_pending, true);
fm = replaceField(fm, 'tasks_done', tasks_done, true);
fm = replaceField(fm, 'tasks_blocked', tasks_blocked, true);
fm = replaceField(fm, 'lessons_lines', lessons_lines, true);
fm = replaceField(fm, 'progress_entries', progress_entries, true);
fm = replaceField(fm, 'reviews_count', reviews_count, true);
fm = replaceField(fm, 'latest_progress', latest_progress, false);
fm = replaceField(fm, 'latest_review', latest_review, false);
fm = replaceField(fm, 'latest_lesson', latest_lesson, false);
fm = replaceField(fm, 'latest_proposal', latest_proposal, false);
fm = replaceField(fm, 'tasks_mtime', tasks_mtime, true);
fm = replaceField(fm, 'design_mtime', design_mtime, true);
fm = replaceField(fm, 'progress_mtime', progress_mtime, true);
fm = replaceField(fm, 'lessons_mtime', lessons_mtime, true);
const newContent = `---\n${fm}\n---\n${body}`;
// 原子写入
const tmpPath = INDEX_PATH + '.tmp';
fs.writeFileSync(tmpPath, newContent);
fs.renameSync(tmpPath, INDEX_PATH);
process.stderr.write(`[index-updater] _index.md updated (pending=${tasks_pending} done=${tasks_done})\n`);
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'index-updater',
tasks_pending, tasks_done, lessons_lines, reviews_count
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
}
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena Stop hook (pace-continuator) v9.6 ★新增
// 协议: 不阻断 (放在 delivery-gate 之后串联运行)
// - 写入 details/next.md (PACE-aware 下一动作建议)
// - 在检测到"反复试错/失败模式"时, append details/proposals.md (铁律 9)
// 参考: https://code.claude.com/docs/en/hooks#stop
//
// 不发明 "自动 PACE", 只是写"下一步可以做的"备忘, 等用户自己读或下次 SessionStart 注入
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const NEXT_PATH = path.join(STATE_DIR, 'details', 'next.md');
const PROPOSALS_PATH = path.join(STATE_DIR, 'details', 'proposals.md');
const HOOK_TRACE = path.join(STATE_DIR, 'hook-trace.jsonl');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
if (event.stop_hook_active) { process.exit(0); return; }
if (event.agent_type && event.agent_type !== 'main') { process.exit(0); return; }
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
let fm = '';
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const m = content.match(/^---\n([\s\S]*?)\n---/);
if (!m) { process.exit(0); return; }
fm = m[1];
} catch (e) { process.exit(0); return; }
const getStr = k => {
const m = fm.match(new RegExp('^ ' + k + ': (.*)$', 'm'));
return m ? m[1].replace(/^["']|["']$/g, '').trim() : '';
};
const getNum = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const pathName = getStr('path');
const stage = getStr('stage');
const sprint = getNum('sprint');
const tasks_pending = getNum('tasks_pending');
const tasks_done = getNum('tasks_done');
if (!pathName || !stage || pathName === 'Hotfix' || pathName === 'Bugfix') {
process.exit(0); return;
}
// 推断下一动作
const suggestions = nextActionSuggestions(pathName, stage, tasks_pending, tasks_done);
if (suggestions.length === 0) { process.exit(0); return; }
// 写 next.md (覆盖, 仅保留最新一条 + 历史移到顶部)
const ts = new Date().toISOString().replace('T', ' ').slice(0, 16);
const entry = `## ${ts}\n当前: ${pathName}/${stage}/sprint ${sprint}\n建议:\n${suggestions.map(s => '- ' + s).join('\n')}\n`;
let existing = '';
try { existing = fs.readFileSync(NEXT_PATH, 'utf8'); } catch (e) {}
// 去掉模板注释, 在顶部 append
existing = existing.replace(/<!--[\s\S]*?-->\s*/g, '').trim();
const newContent = `# 下一动作建议\n\n${entry}\n${existing ? '\n---\n\n' + existing : ''}`.trim() + '\n';
fs.writeFileSync(NEXT_PATH, newContent);
// 检测反复试错: 读 hook-trace 最近 20 条, 看 subagent-retry / delivery-gate block 是否高频
try {
const trace = fs.readFileSync(HOOK_TRACE, 'utf8').split('\n').filter(l => l).slice(-20);
const retryCount = trace.filter(l => l.includes('"subagent-retry"')).length;
const blockCount = trace.filter(l => l.includes('"delivery-gate"') && l.includes('"block"')).length;
if (retryCount >= 3 || blockCount >= 2) {
// append proposals.md (铁律 9 Hook 反思)
const proposalEntry = `\n## ${ts} (sprint ${sprint})\n- 观察: 最近 20 hook 事件含 subagent-retry × ${retryCount}, delivery-gate block × ${blockCount}\n- 假设: ${pathName}/${stage} 阶段流程可能不顺畅, 可能是 design 不足 / task 过大 / 验收标准模糊\n- 提议: 复盘当前 sprint 设计粒度, 考虑拆 task 或回 plan 阶段\n`;
fs.appendFileSync(PROPOSALS_PATH, proposalEntry);
process.stderr.write(`[pace-continuator] proposals.md +1 (retry=${retryCount}, block=${blockCount})\n`);
}
} catch (e) {}
process.stderr.write(`[pace-continuator] next.md updated (${pathName}/${stage})\n`);
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'pace-continuator',
path: pathName, stage, sprint,
suggestions_count: suggestions.length
}) + '\n';
fs.appendFileSync(HOOK_TRACE, trace);
} catch (e) {}
process.exit(0);
});
function nextActionSuggestions(path, stage, pending, done) {
const s = [];
if (stage === 'plan') {
s.push('完成 design.md 的 File Structure Plan 段');
s.push('和用户确认设计后 → 进入 stage=impl');
s.push('可选: /goal "design.md 含 File Structure Plan + tasks ≥ 1 + 用户确认"');
} else if (stage === 'design') {
s.push('锁定架构, 完成 details/tasks-current.md (每 Task 含 Boundary/Depends)');
s.push('用户确认 → 进入 stage=impl');
} else if (stage === 'impl') {
if (pending > 0) {
s.push(`完成剩余 ${pending} 个 Task (按 Boundary 拆分)`);
if (path === 'Refactor' || path === 'System') {
s.push('可选: /batch "<重构描述>" 并行加速 (CC v2.1.121+ 原生)');
}
s.push('每完成 Task → tasks-current.md 勾选 + progress.md 追加');
} else if (done > 0) {
s.push('所有 task 完成, 跑测试和 lint → 切 stage=review');
s.push('/simplify 清理冗余');
}
} else if (stage === 'review') {
s.push('运行 /review → 写 reviews/sprint-N.md');
if (path !== 'Quick') {
s.push('运行 /codex:review (跨模型审查)');
}
s.push('@evaluator 评分 → VERDICT');
s.push('PASS → /compound 沉淀 lessons → stage=ship');
} else if (stage === 'ship') {
s.push('superpowers /ship (Feature+) 或 git commit (Quick)');
s.push('归档 details/tasks-archive/sprint-N.md');
s.push('_index.md sprint += 1, stage="" ');
}
return s;
}
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PermissionDenied hook v9.6
// 协议: stdout JSON { retry: true } (CC v2.1.89+ 官方标准)
// 参考: https://code.claude.com/docs/en/hooks#permissiondenied
//
// 设计:
// 当 auto mode classifier 拒绝某个工具调用 → 提示 model 可以重试 (但只针对一次)
// 并 systemMessage 建议用户加入全局 deny (如果是反复出现的 pattern)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
const tool = event.tool_name || '';
const cmd = (event.tool_input && event.tool_input.command) || '';
const reason = event.reason || '';
// 软提示: 如果是 Bash + 看起来是项目本地命令 → 提示用户考虑加入项目 allow
let suggestion = '';
if (tool === 'Bash' && cmd) {
// 抽取命令名 (第一个 token)
const cmdName = cmd.trim().split(/\s+/)[0];
if (['npm', 'pnpm', 'yarn', 'pytest', 'cargo', 'go', 'make'].includes(cmdName)) {
suggestion = `如果这是项目常用命令, 可: /athena:remember-allow "Bash(${cmdName}:*)" 加入全局 allow`;
}
}
if (suggestion) {
process.stderr.write(`[permission-retry] suggest: ${suggestion}\n`);
process.stdout.write(JSON.stringify({
retry: true,
systemMessage: `[Athena] permission denied. ${suggestion}`
}));
} else {
// 默认让 model 知道可以一次性重试
process.stdout.write(JSON.stringify({ retry: true }));
}
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'permission-retry',
tool, cmd_head: cmd.slice(0, 60), reason: reason.slice(0, 100)
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});
-19
View File
@@ -1,19 +0,0 @@
// 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);
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PreToolUse Bash guard v9.6
// 协议: hookSpecificOutput.{hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason}
// 参考: https://code.claude.com/docs/en/hooks#pretooluse
//
// v9.6 设计:
// 配合 settings.json 的 if 字段做精细化拦截 (官方 if syntax: https://code.claude.com/docs/en/hooks#common-fields)
// settings.json 已用 if: "Bash(rm *)" / "Bash(curl *|wget *)" / "Bash(mkfs*|dd *)" 预过滤
// hook 内部做二次确认 + 提供具体的拒绝原因
//
// permissions.deny 已含 "Bash(rm -rf *)" 灾难规则, 这里是双重保险
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let cmd = '';
try {
const d = JSON.parse(input);
cmd = (d.tool_input && d.tool_input.command) || '';
} catch (e) { process.exit(0); return; }
if (!cmd) { process.exit(0); return; }
const deny = (reason) => {
process.stderr.write(`[bash-guard] deny: ${reason} (${cmd.slice(0, 60)})\n`);
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: `Athena bash-guard 阻断: ${reason}`
}
}));
process.exit(0);
};
// 灾难级 (3 条):
// 1. rm -rf 系统/用户根
if (/rm\s+-[rRf]+\s+(\/\s|\/\*|~\/?\s|~\s|\/$|~$)/.test(cmd) ||
/rm\s+-[rRf]+\s+\/\s*[;&|]/.test(cmd)) {
return deny('禁止删除系统/用户根目录');
}
// 2. 管道远程脚本
if (/(curl|wget)\s+[^|]*\|\s*(bash|sh|zsh|fish|ksh)/.test(cmd)) {
return deny('禁止管道执行远程脚本 (curl|wget ... | sh)');
}
// 3. 格式化磁盘 / 写设备
if (/\bmkfs\.|dd\s+if=.*of=\/dev\/sd|>\s*\/dev\/sd[a-z]/.test(cmd)) {
return deny('禁止格式化磁盘/写设备');
}
process.exit(0);
});
-26
View File
@@ -1,26 +0,0 @@
// 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);
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena SessionStart hook v9.6
// 协议: hookSpecificOutput.{hookEventName: "SessionStart", additionalContext}
// 参考: https://code.claude.com/docs/en/hooks#sessionstart
//
// 设计 (铁律 8 索引先行):
// 1. 唯一 IO: read .ai_state/_index.md (frontmatter)
// 2. 注入 context-essentials.md (静态文本)
// 3. 注入 _index.md 关键字段摘要 (path/stage/sprint/counts/active_goal)
// 4. effort=max 时跳过 PACE 状态注入 (高 effort 模型自己探索)
// 5. 不预加载 tasks/design/progress 内容
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const PROJECT_ESSENTIALS = path.join(PROJECT_DIR, '.claude', 'skills', 'pace', 'context-essentials.md');
const HOME = process.env.HOME || require('os').homedir();
const GLOBAL_ESSENTIALS = path.join(HOME, '.claude', 'skills', 'pace', 'context-essentials.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
const source = event.source || 'unknown';
// CC v2.1.133+ 注入 effort.level
const effort = (event.effort && event.effort.level) || process.env.CLAUDE_EFFORT || '';
const isMax = effort === 'max';
const lines = [];
// 1. 注入 context-essentials.md (优先项目级, 回落全局)
let essentialsText = '';
for (const p of [PROJECT_ESSENTIALS, GLOBAL_ESSENTIALS]) {
try {
const t = fs.readFileSync(p, 'utf8').trim();
if (t) { essentialsText = t; break; }
} catch (e) {}
}
if (essentialsText) {
lines.push(essentialsText);
} else {
lines.push('[VibeCoding Athena v9.6] TDD · Review · Sisyphus · 索引先行 · 完成度证据 · 出处优先\n[Get-bearings] read .ai_state/_index.md 然后按 pointers 跳转明细');
}
// 2. effort=max 时不注入 PACE 状态摘要 (高 effort 自己探索)
if (!isMax && fs.existsSync(INDEX_PATH)) {
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (fmMatch) {
const fm = fmMatch[1];
const getStr = k => {
const m = fm.match(new RegExp('^ ' + k + ': (.*)$', 'm'));
return m ? m[1].replace(/^["']|["']$/g, '').trim() : '';
};
const getNum = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const path_ = getStr('path');
const stage = getStr('stage');
const sprint = getNum('sprint');
const goal = getStr('active_goal');
const pending = getNum('tasks_pending');
const done = getNum('tasks_done');
const blocked = getNum('tasks_blocked');
if (path_ && stage) {
lines.push(`\n[PACE] Path:${path_} Stage:${stage} Sprint:${sprint}`);
}
if (goal) {
lines.push(`[/goal active] ${goal.slice(0, 120)}${goal.length > 120 ? '...' : ''}`);
}
if (pending + done + blocked > 0) {
lines.push(`[任务] ${done} 完成 ${pending} 待办 ${blocked} 阻塞 (详见 details/tasks-current.md)`);
}
// gotchas (按 YAML array 简单解析: 单行 [..] 或多行 - 形式)
const gotchasMatch = fm.match(/^gotchas:\s*(.+)$/m);
if (gotchasMatch) {
const g = gotchasMatch[1].trim();
if (g.startsWith('[') && !g.match(/^\[\s*\]$/)) {
lines.push(`[Gotchas] ${g.slice(1, -1).trim()}`);
}
}
}
} catch (e) {
process.stderr.write(`[session-start] _index.md parse failed: ${e.message}\n`);
}
}
if (lines.length === 0) { process.exit(0); return; }
const additionalContext = lines.join('\n');
process.stderr.write(`[session-start/${source}${isMax ? '/max' : ''}] injected ${additionalContext.length} chars\n`);
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'session-start',
source, effort, chars: additionalContext.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'SessionStart',
additionalContext
}
}));
process.exit(0);
});
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena ConfigChange hook v9.6 ★新增 (L2.G)
// 协议: 不阻断, additionalContext 注入 warning
// 参考: https://code.claude.com/docs/en/hooks#configchange
//
// 设计:
// ConfigChange 事件触发时 (settings.json/CLAUDE.md/MCP 等变更):
// 1. 重新读 _index.md, 验证 schema_version 仍是 "9.6"
// 2. 比对 fingerprints 段, 检测 details/* 是否被外部修改 (mtime 异常跳变)
// 3. 异常时注入 systemMessage 提醒 (而非 block, ConfigChange 不该 block)
//
// 用途场景: 用户用编辑器手改了 _index.md 导致 schema 损坏 / git checkout 切换分支后状态错位
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
const configSource = event.matcher || 'unknown';
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
const warnings = [];
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (!fmMatch) {
warnings.push('_index.md frontmatter 已损坏, 无法解析');
} else {
const fm = fmMatch[1];
// 1. schema_version 检查
const schemaMatch = fm.match(/^schema_version: "([^"]+)"$/m);
if (!schemaMatch || schemaMatch[1] !== '9.6') {
warnings.push(`schema_version 异常: ${schemaMatch ? schemaMatch[1] : 'missing'} (期望 "9.6", 可能需要 /athena-migrate)`);
}
// 2. fingerprints vs 实际 mtime 比对
const getFp = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const fpTasks = getFp('tasks_mtime');
const fpDesign = getFp('design_mtime');
const fpProgress = getFp('progress_mtime');
const fpLessons = getFp('lessons_mtime');
const checkFile = (name, fp) => {
try {
const actual = Math.floor(fs.statSync(path.join(STATE_DIR, 'details', name)).mtimeMs);
// 允许 fingerprint 落后于 actual (PostToolUse 还没跑), 但反过来不正常
if (fp > actual + 1000) {
warnings.push(`${name} fingerprint 比实际 mtime 新 (${fp - actual}ms), 可能被外部修改`);
}
} catch (e) {}
};
checkFile('tasks-current.md', fpTasks);
checkFile('design.md', fpDesign);
checkFile('progress.md', fpProgress);
checkFile('lessons.md', fpLessons);
}
} catch (e) {
warnings.push(`审计失败: ${e.message}`);
}
if (warnings.length === 0) { process.exit(0); return; }
const msg = `[Athena state-audit] ConfigChange (${configSource}) 检测到 ${warnings.length} 个潜在问题:\n${warnings.map(w => '• ' + w).join('\n')}`;
process.stderr.write(msg + '\n');
process.stdout.write(JSON.stringify({ systemMessage: msg }));
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'state-audit',
source: configSource,
warnings_count: warnings.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});
-18
View File
@@ -1,18 +0,0 @@
// 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 {}
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PostToolUse subagent-retry v9.6
// 协议: 不阻断 (additionalContext 注入 hint)
// 参考: https://code.claude.com/docs/en/hooks#posttooluse
//
// 设计:
// Task tool 调用 subagent. 若返回的 tool_response 里含"无法"/"无能力"等放弃语
// → 注入 systemMessage 提示 main agent 重试或亲自接管
// 防止 subagent 偷懒 (v9.5 实测问题)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
if (event.tool_name !== 'Task') { process.exit(0); return; }
const response = event.tool_response;
if (!response || typeof response !== 'object') { process.exit(0); return; }
// 提取 subagent 的完整响应内容
let text = '';
if (typeof response.content === 'string') text = response.content;
else if (Array.isArray(response.content)) text = response.content.map(c => c.text || '').join('\n');
else text = JSON.stringify(response);
// 放弃信号词
const giveupPatterns = [
/我(无法|不能|没法|无能力|不具备能力)/,
/I (cannot|can't|am not able to|don't have access)/i,
/no (capability|access|permission) to/i,
/unable to (read|write|execute|access)/i,
/tool not available/i,
/(请|你)(自己|手动|帮我)?(运行|执行|跑)/,
/please run (this|the command) (yourself|manually)/i
];
const found = giveupPatterns.find(p => p.test(text));
if (!found) { process.exit(0); return; }
process.stderr.write(`[subagent-retry] giveup detected: ${found}\n`);
const subagentType = (event.tool_input && event.tool_input.subagent_type) || 'subagent';
process.stdout.write(JSON.stringify({
systemMessage: `[Athena subagent-retry] ${subagentType} 返回了放弃信号. 协议: 1) 再尝试一次, 用不同参数或拆分任务 2) 仍失败则主 agent 接管, 不要让用户代执行 (铁律 6 完成度证据)`
}));
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'subagent-retry',
subagent_type: subagentType,
pattern: String(found)
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});
-21
View File
@@ -1,21 +0,0 @@
// 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);
+130 -50
View File
@@ -1,55 +1,65 @@
{
"environmentVariables": {
"VIBECODING_VERSION": "9.2.0",
"LANGUAGE": "zh-Hans",
"LC_ALL": "zh-Hans",
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"model": "opusplan",
"effortLevel": "xhigh",
"env": {
"VIBECODING_ATHENA_VERSION": "9.6.0",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-7",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6",
"CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
"API_TIMEOUT_MS": "3000000",
"CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6"
"DISABLE_NON_ESSENTIAL_MODEL_CALLS": "1",
"CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1",
"CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1",
"NEXT_TELEMETRY_DISABLED": "1",
"NUXT_TELEMETRY_DISABLED": "1",
"GATSBY_TELEMETRY_DISABLED": "1",
"ASTRO_TELEMETRY_DISABLED": "1",
"ANGULAR_CLI_ANALYTICS": "false",
"API_TIMEOUT_MS": "30000"
},
"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(*)"
"Bash(npm test:*)",
"Bash(npm run:*)",
"Bash(npx:*)",
"Bash(node:*)",
"Bash(python:*)",
"Bash(python3:*)",
"Bash(pytest:*)",
"Bash(uv run:*)",
"Bash(cargo:*)",
"Bash(go:*)",
"Bash(claude *)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git checkout:*)",
"Bash(git branch:*)",
"Bash(git worktree:*)",
"Read(.ai_state/**)",
"Write(.ai_state/**)"
],
"deny": [
"Bash(rm -rf /)",
"Bash(rm -rf /*)",
"Bash(rm -rf ~)",
"Bash(chmod 777 *)",
"Bash(curl * | bash)",
"Read(./secrets/**)",
"Read(./.env.production)"
"Bash(rm -rf *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
},
"worktree": {
"baseRef": "head"
},
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume|clear|compact",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/context-loader.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/session-start.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/session-start.cjs\" || true"
}
]
}
@@ -60,18 +70,38 @@
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/pre-bash.cjs"
"if": "Bash(rm *)",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" || true"
},
{
"type": "command",
"if": "Bash(curl *|wget *)",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" || true"
},
{
"type": "command",
"if": "Bash(mkfs*|dd *)",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" || true"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/post-edit.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/index-updater.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/index-updater.cjs\" || true"
}
]
},
{
"matcher": "Task",
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/subagent-retry.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/subagent-retry.cjs\" || true"
}
]
}
@@ -81,28 +111,78 @@
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/delivery-gate.cjs"
}
]
},
{
"hooks": [
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/delivery-gate.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/delivery-gate.cjs\" || true"
},
{
"type": "command",
"command": "node .claude/hooks/tdd-check.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pace-continuator.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pace-continuator.cjs\" || true"
}
]
}
],
"StopFailure": [
"PermissionDenied": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/stop-failure.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/permission-retry.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/permission-retry.cjs\" || true"
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-snapshot.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-snapshot.cjs\" || true"
}
]
}
],
"PostCompact": [
{
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-restore.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-restore.cjs\" || true"
}
]
}
],
"ConfigChange": [
{
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/state-audit.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/state-audit.cjs\" || true"
}
]
}
]
},
"extraKnownMarketplaces": {
"superpowers-marketplace": {
"source": {
"source": "github",
"repo": "obra/superpowers-marketplace"
}
},
"openai-codex": {
"source": {
"source": "github",
"repo": "openai/codex-plugin-cc"
}
}
},
"enabledPlugins": {
"superpowers@superpowers-marketplace": true,
"codex@openai-codex": true,
"feature-dev@claude-plugins-official": true,
"code-review@claude-plugins-official": true,
"commit-commands@claude-plugins-official": true,
"playwright-skill@playwright-skill": true,
"security-guidance@claude-plugins-official": true,
"frontend-design@claude-plugins-official": true
}
}
}
+30
View File
@@ -0,0 +1,30 @@
---
name: athena-dev
description: >
Athena 主入口。从需求到交付的完整工程化开发流程。
effort: xhigh
disable-model-invocation: true
argument-hint: "<需求描述>"
---
# /athena-dev
`.ai_state/` 不存在 → 提示 `/athena-init` 并停。
`.ai_state/_index.md.schema_version` != "9.6" → 提示 `/athena-migrate` 并停。
## Get-bearings (R₀, just-in-time, 铁律 8)
1. **必读**: `.ai_state/_index.md` (单一入口)
2. **按需**: stage=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
3. **按需**: 任务命中 lessons 主题 → pointers.latest_lesson 跳段
4. **按需**: `git log --oneline -10`
5. **按需**: impl/review 阶段 → `bash .ai_state/init.sh`
文件大就用 head/tail/grep。**禁止 glob 整个 .ai_state/** (铁律 8)。
## Dispatch
有进行中的 stage → 从当前阶段继续 (触发 pace skill)。
新需求 → 触发 pace skill 路由, 需求: $ARGUMENTS。
首次使用简短说明: "PACE 帮你路由——小事直接做, 大事加设计和审查。CC 原生 /goal /batch /background 已接入。"
+104
View File
@@ -0,0 +1,104 @@
---
name: athena-init
description: >
项目初始化。每个新项目首次使用 Athena 时运行。扫描项目、生成环境脚本、创建 .ai_state/ schema。
effort: xhigh
disable-model-invocation: true
---
# /athena-init — 项目初始化
参考: <https://code.claude.com/docs/en/skills>
## 1. CC 原生初始化
无 CLAUDE.md → 运行 `/init`, 生成后追加: "本项目使用 VibeCoding Athena, 开发用 `/athena-dev`"
已有 CLAUDE.md → 跳过。
## 2. 项目扫描
```bash
ls package.json pyproject.toml Cargo.toml go.mod build.gradle pom.xml 2>/dev/null
cat package.json 2>/dev/null | grep -A5 '"scripts"'
ls jest.config* vitest.config* pytest.ini .eslintrc* ruff.toml biome.json 2>/dev/null
```
## 3. 创建 .ai_state/ 目录树 (v9.6 schema)
```bash
mkdir -p .ai_state/details/reviews
mkdir -p .ai_state/details/tasks-archive
```
## 4. 拷贝模板到 .ai_state/
从 `~/.claude/skills/pace/templates/` 复制 (必须全部, 缺一不可):
- `_index.md` → `.ai_state/_index.md` (单一入口, 铁律 8)
- `details/tasks-current.md`
- `details/progress.md`
- `details/design.md`
- `details/handoff.md`
- `details/lessons.md`
- `details/review-report.md` → `.ai_state/details/reviews/template.md`
- `details/next.md`
- `details/proposals.md`
- `init.sh` → `.ai_state/init.sh`
## 5. 填充 _index.md frontmatter
把扫描结果写入:
- `tech_stack` (检测到的: node/python/rust/go)
- `test_cmd` (从 package.json scripts.test 或 pytest 等)
- `build_cmd`
- `lint_cmd`
- `dev_cmd`
填充 `platform_features` (用 `claude --version` 和 `codex --version 2>&1`):
- `cc_version`
- `cx_version`
- `goal_supported`: 解析 cc_version, ≥ "2.1.139" 即 true
- `batch_supported`: ≥ "2.1.121"
- `background_supported`: ≥ "2.1.139"
- `session_memory_active`: 检测 `~/.claude/projects/` 是否含 session-memory 子目录
- `cross_session_memory`: 检测 `~/.claude/plugins/` 含 claude-mem 则 "claude-mem", 含 superpowers 则 "superpowers", 否则 "none"
## 6. 生成 init.sh
根据扫描结果定制 `.ai_state/init.sh`:
- 依赖安装命令 (npm install / pip install / cargo build)
- dev server 启动 (如有)
- 基线测试命令
- `chmod +x .ai_state/init.sh`
## 7. .gitignore
```bash
grep -q '.ai_state' .gitignore 2>/dev/null || echo '.ai_state/' >> .gitignore
```
## 8. 跨项目记忆推荐 (替代删除的全局 lessons)
```bash
# 检测 claude-mem 或 superpowers, 缺则软提示
if ! ls ~/.claude/plugins/ 2>/dev/null | grep -iE 'claude-mem|superpowers' > /dev/null; then
echo "💡 推荐装 claude-mem (89k stars) 做跨项目记忆"
echo " /plugin install claude-mem (待加入官方 marketplace)"
echo " 或: /athena-setup 走完整推荐流"
fi
```
## 9. Git commit
```bash
git add .ai_state/ .gitignore
git commit -m "athena: project initialized (v9.6 schema)"
```
## 10. 验证
运行 `bash .ai_state/init.sh` 确认脚本正常。
告知用户: "Athena 已就绪。用 `/athena-dev <需求>` 开始开发, 或 `/athena-status` 看面板。"
已有 .ai_state/ 但 schema_version != "9.6" → 提示运行 `/athena-migrate` 升级。
已有 .ai_state/ 且 schema_version == "9.6" → 提示用户是否重新初始化 (会重置 _index.md)。
+203
View File
@@ -0,0 +1,203 @@
---
name: athena-migrate
description: >
把 v9.5.5 项目的 .ai_state/ 升级到 v9.6 schema (INDEX + details/ 重构)。
effort: xhigh
disable-model-invocation: true
---
# /athena-migrate — v9.5.5 → v9.6 迁移
参考: <https://code.claude.com/docs/en/skills>
## 前置检查
```bash
test -d .ai_state || { echo "[migrate] 无 .ai_state, 请先 /athena-init"; exit 1; }
test -f .ai_state/_index.md && grep -q 'schema_version: "9.6"' .ai_state/_index.md && {
echo "[migrate] 已是 v9.6 schema, 无需迁移"; exit 0;
}
```
## 迁移算法
### Step 1: 备份
```bash
mkdir -p .ai_state/.legacy-v9.5
cp -r .ai_state/{tasks.md,design.md,progress.md,lessons.md,handoff.md,project.json,reviews,hook-trace.jsonl,compact-snapshot.json} .ai_state/.legacy-v9.5/ 2>/dev/null || true
echo "[migrate] 旧文件已备份到 .ai_state/.legacy-v9.5/"
```
### Step 2: 创建 details/ 目录
```bash
mkdir -p .ai_state/details/reviews
mkdir -p .ai_state/details/tasks-archive
```
### Step 3: 迁移文件
| v9.5.5 路径 | v9.6 路径 | 备注 |
|---|---|---|
| `.ai_state/tasks.md` | `.ai_state/details/tasks-current.md` | 改名 |
| `.ai_state/design.md` | `.ai_state/details/design.md` | 平移 |
| `.ai_state/progress.md` | `.ai_state/details/progress.md` | 平移 |
| `.ai_state/lessons.md` | `.ai_state/details/lessons.md` | 平移 |
| `.ai_state/handoff.md` | `.ai_state/details/handoff.md` | 平移 |
| `.ai_state/reviews/sprint-N.md` | `.ai_state/details/reviews/sprint-N.md` | 平移 |
| `.ai_state/project.json` | (merge 到 _index.md frontmatter) | 转 markdown frontmatter |
| `.ai_state/hook-trace.jsonl` | `.ai_state/hook-trace.jsonl` | 保持原位置 |
| `.ai_state/compact-snapshot.json` | (删, v9.6 改写到 _index.md.snapshots) | 删除 |
```bash
# 平移
[ -f .ai_state/tasks.md ] && mv .ai_state/tasks.md .ai_state/details/tasks-current.md
for f in design.md progress.md lessons.md handoff.md; do
[ -f .ai_state/$f ] && mv .ai_state/$f .ai_state/details/$f
done
[ -d .ai_state/reviews ] && mv .ai_state/reviews .ai_state/details/reviews
[ -f .ai_state/compact-snapshot.json ] && rm .ai_state/compact-snapshot.json
```
### Step 4: 生成 _index.md
从 `.ai_state/project.json` 读 path/stage/sprint/tech_stack/test_cmd/build_cmd/lint_cmd/dev_cmd/conventions/gotchas, 写入新 _index.md frontmatter。
```bash
# 用 node 脚本生成 _index.md (避免手写 yaml escape 出错)
node -e '
const fs = require("fs");
const path = require("path");
let proj = {};
try { proj = JSON.parse(fs.readFileSync(".ai_state/.legacy-v9.5/project.json","utf8")); } catch(e) {}
const sprint = proj.sprint || 0;
// 计算 counts
let tasks_pending = 0, tasks_done = 0, tasks_blocked = 0;
try {
const t = fs.readFileSync(".ai_state/details/tasks-current.md","utf8");
tasks_pending = (t.match(/^- \[ \]/gm) || []).length;
tasks_done = (t.match(/^- \[x\]/gm) || []).length;
} catch(e) {}
let progress_entries = 0, latest_progress = "";
try {
const lines = fs.readFileSync(".ai_state/details/progress.md","utf8").split("\n").filter(l => l.trim().length > 0 && !l.startsWith("<!--") && !l.startsWith("#"));
progress_entries = lines.length;
if (lines.length > 0) latest_progress = `details/progress.md#L${lines.length}`;
} catch(e) {}
let lessons_lines = 0, latest_lesson = "";
try {
const lines = fs.readFileSync(".ai_state/details/lessons.md","utf8").split("\n");
lessons_lines = lines.filter(l => l.startsWith("##")).length;
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].startsWith("## ")) { latest_lesson = `details/lessons.md#L${i+1}`; break; }
}
} catch(e) {}
let reviews_count = 0, latest_review = "";
try {
const files = fs.readdirSync(".ai_state/details/reviews").filter(f => f.startsWith("sprint-") && f.endsWith(".md"));
reviews_count = files.length;
if (files.length > 0) {
const sorted = files.sort();
latest_review = `details/reviews/${sorted[sorted.length-1]}`;
}
} catch(e) {}
const idx = `---
schema_version: "9.6"
athena_version: "9.6.0"
project:
path: "${proj.path || ""}"
stage: "${proj.stage || ""}"
sprint: ${sprint}
active_goal: ""
counts:
tasks_pending: ${tasks_pending}
tasks_done: ${tasks_done}
tasks_blocked: ${tasks_blocked}
lessons_lines: ${lessons_lines}
progress_entries: ${progress_entries}
reviews_count: ${reviews_count}
pointers:
latest_progress: "${latest_progress}"
latest_review: "${latest_review}"
latest_lesson: "${latest_lesson}"
latest_proposal: ""
fingerprints:
tasks_mtime: 0
design_mtime: 0
progress_mtime: 0
lessons_mtime: 0
platform_features:
cc_version: ""
cx_version: ""
goal_supported: false
batch_supported: false
background_supported: false
session_memory_active: false
cross_session_memory: "none"
gotchas: ${JSON.stringify(proj.gotchas || [])}
conventions: ${JSON.stringify(proj.conventions || [])}
tech_stack: "${proj.tech_stack || ""}"
test_cmd: "${proj.test_cmd || ""}"
build_cmd: "${proj.build_cmd || ""}"
lint_cmd: "${proj.lint_cmd || ""}"
dev_cmd: "${proj.dev_cmd || ""}"
---
# 项目状态索引 (v9.6 migrated from v9.5.5)
## 最近活动
## 当前阻塞
## 下一动作 (PACE 建议)
## 反思建议 (Hook 沉淀)
`;
fs.writeFileSync(".ai_state/_index.md", idx);
console.log("[migrate] _index.md generated");
'
```
### Step 5: 创建空 next.md 和 proposals.md
```bash
touch .ai_state/details/next.md
touch .ai_state/details/proposals.md
```
### Step 6: 平台版本检测填入 _index.md
调用 `/athena-setup --detect-only`, 它会原地更新 `_index.md.platform_features`。
### Step 7: 提示用户
```
✓ 迁移完成。备份在 .ai_state/.legacy-v9.5/, 确认无问题可删除。
新增的文件: .ai_state/details/next.md, .ai_state/details/proposals.md
删除的文件: .ai_state/project.json (合并到 _index.md frontmatter)
.ai_state/compact-snapshot.json (改写到 _index.md.snapshots 数组)
下一步: /athena-status 查看新状态面板
```
### Step 8: Git commit
```bash
git add .ai_state/
git commit -m "athena: migrate state to v9.6 schema"
```
## 回滚 (如果出问题)
```bash
rm -rf .ai_state/details .ai_state/_index.md
cp -r .ai_state/.legacy-v9.5/* .ai_state/
```
+138
View File
@@ -0,0 +1,138 @@
---
name: athena-preferences
description: >
Athena 全局偏好便利层。直接操作 CC 原生 ~/.claude/settings.json 的 permissions.allow/deny 和全局 CLAUDE.md。
effort: medium
disable-model-invocation: true
argument-hint: "<subcommand> <args>"
---
# /athena-preferences (v9.6)
## 设计原则
**Athena 不造私有偏好文件**。所有写入都是 CC 原生位置:
| 偏好类型 | 落点 |
|---|---|
| 全局 allow | `~/.claude/settings.json` `permissions.allow[]` |
| 全局 deny | `~/.claude/settings.json` `permissions.deny[]` |
| 工具偏好 (pnpm/vitest) | `~/.claude/CLAUDE.md` "## Tool Preferences" 段 |
参考: <https://code.claude.com/docs/en/settings> + <https://code.claude.com/docs/en/permissions>
**永远不写**:
- ❌ `~/.claude/memory/athena-*.list` 类私有文件
- ❌ 项目特定的命令到全局 (路径泛化检查)
**永远不自动写**:
- ❌ 不监控命令频次自动建议 (隐私决定)
- ✅ 仅在用户**显式调用**本 skill 时写
## 子命令
### `/athena:remember-allow <pattern>`
参数: 标准 CC permission pattern, 如 `Bash(pnpm test:*)`.
```javascript
const fs = require('fs');
const os = require('os');
const path = require('path');
const settingsPath = path.join(os.homedir(), '.claude/settings.json');
let s = {};
try { s = JSON.parse(fs.readFileSync(settingsPath,'utf8')); } catch(e) {}
s.permissions = s.permissions || {};
s.permissions.allow = s.permissions.allow || [];
const pattern = process.argv[2];
// 路径泛化检查: 拒绝含项目特定路径的 pattern
if (/\/Users\/|\/home\/[^*/]|C:\\Users\\/.test(pattern) || /[\w-]+\.(com|cn|net)\//.test(pattern)) {
console.error('❌ 拒绝: pattern 含项目/用户特定路径, 不应写入全局');
console.error(' 如果只想本项目用, 写到 .claude/settings.local.json');
process.exit(1);
}
if (s.permissions.allow.includes(pattern)) {
console.log('✓ 已存在, 无需添加');
process.exit(0);
}
s.permissions.allow.push(pattern);
fs.writeFileSync(settingsPath, JSON.stringify(s,null,2));
console.log(`✓ 已加入全局 allow: ${pattern}`);
console.log(` 位置: ${settingsPath}`);
```
### `/athena:remember-deny <pattern>`
同 `remember-allow`, 写入 `permissions.deny[]`. 但**不做路径泛化拒绝**——deny 越严格越好。
### `/athena:remember-tool <key>=<value>`
写入 `~/.claude/CLAUDE.md` 的 "## Tool Preferences" 段 (无则创建):
```
## Tool Preferences
- 包管理器: pnpm
- 测试运行器: vitest
- Linter: biome
- 默认提交者: --signoff
```
### `/athena:show-preferences`
```bash
echo "=== Global allow (~/.claude/settings.json) ==="
node -e 'console.log((JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/settings.json")).permissions?.allow || []).join("\n"))'
echo ""
echo "=== Global deny ==="
node -e 'console.log((JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/settings.json")).permissions?.deny || []).join("\n"))'
echo ""
echo "=== Tool preferences (~/.claude/CLAUDE.md) ==="
sed -n '/^## Tool Preferences/,/^## /p' ~/.claude/CLAUDE.md 2>/dev/null | head -20
```
### `/athena:forget <pattern>`
从全局 allow/deny 中删除指定 pattern. 显示删除前后 diff.
```javascript
const fs = require('fs');
const os = require('os');
const path = require('path');
const settingsPath = path.join(os.homedir(), '.claude/settings.json');
const s = JSON.parse(fs.readFileSync(settingsPath,'utf8'));
const pattern = process.argv[2];
const beforeA = s.permissions?.allow?.length || 0;
const beforeD = s.permissions?.deny?.length || 0;
if (s.permissions?.allow) s.permissions.allow = s.permissions.allow.filter(p => p !== pattern);
if (s.permissions?.deny) s.permissions.deny = s.permissions.deny.filter(p => p !== pattern);
const afterA = s.permissions?.allow?.length || 0;
const afterD = s.permissions?.deny?.length || 0;
fs.writeFileSync(settingsPath, JSON.stringify(s,null,2));
console.log(`allow: ${beforeA} → ${afterA}`);
console.log(`deny: ${beforeD} → ${afterD}`);
```
## 安全约束
1. **不修改 managed-settings.json** (企业管理层)
2. **不修改项目 .claude/settings.json** (那是项目级, 用 settings.local.json 兜底)
3. **永远显示 diff** 在写入前——用户能看到改了什么
4. **永远说明落点** ("位置: ~/.claude/settings.json") 而不是含糊"已记住"
## Boundary
- ✅ 操作 `~/.claude/settings.json`
- ✅ 追加到 `~/.claude/CLAUDE.md` 末尾 "## Tool Preferences" 段
- ❌ 不读不写 `~/.claude/projects/` (那是 session memory, claude-mem 管)
- ❌ 不读不写 `~/.claude/memory/`
- ❌ 不创建 `~/.claude/athena-*.txt` 类文件
+15
View File
@@ -0,0 +1,15 @@
---
name: athena-review
description: >
单独运行质量审查, 不走完整开发流程。
effort: xhigh
disable-model-invocation: true
argument-hint: "[focus area]"
---
# /athena-review
有 `.ai_state/_index.md` → 按当前 Path 深度触发 pace skill 审查阶段。
无 → 快速审查: `/review`。
焦点: $ARGUMENTS
+154
View File
@@ -0,0 +1,154 @@
---
name: athena-setup
description: >
Athena 全局安装。检查 CC 版本、装插件、配置 Codex、部署 hooks、推 claude-mem。首次使用运行一次。
effort: xhigh
disable-model-invocation: true
---
# /athena-setup (v9.6)
## 设计哲学 (启动时告诉用户)
```
v9.6 原则:
- permissions.deny 仅保留 "Bash(rm -rf *)" + 机密文件 (sandbox 是正道)
参考: https://claude.com/blog/beyond-permission-prompts-making-claude-code-more-secure-and-autonomous
- 全局 lessons 已删, 跨项目记忆推 claude-mem (默认装)
- /goal /batch /background CC 原生, 不再造状态机驱动器
- 不维护插件推荐列表, 实时查 marketplace
```
## Step 0: CC 版本检查
参考: <https://code.claude.com/docs/en/changelog>
```bash
claude --version
```
要求 ≥ v2.1.121 (worktree isolation + updatedToolOutput 全工具). v2.1.139+ 解锁 /goal /background.
低于 → `claude update` 或 `npm install -g @anthropic-ai/claude-code@latest`.
把检测到的版本写入 `.ai_state/_index.md.platform_features.cc_version`. 解析后置 goal_supported/batch_supported/background_supported.
## Step 1: 插件安装 (按 PACE 节点 best-fit, 非强依赖)
每装一个问自己: "这个真的会用吗?" 多余 = context 浪费。
### 工程主线 (强烈推荐)
```
/plugin marketplace add obra/superpowers-marketplace
/plugin install superpowers@superpowers-marketplace
/plugin marketplace add openai/codex-plugin-cc
/plugin install codex@openai-codex
```
### 跨项目记忆 (v9.6 默认推 claude-mem)
claude-mem 89k stars, Apache-2.0, 自动捕获 tool use + 压缩摘要 + 注入下次 session.
参考: <https://github.com/thedotmack/claude-mem>
```
# 检测是否已装
if /plugin list | grep -iq claude-mem; then
echo "claude-mem ✓ 已装"
else
echo "推荐安装 claude-mem (跨 session 记忆):"
echo " /plugin marketplace add <claude-mem 所在 marketplace>"
echo " /plugin install claude-mem"
echo " (如不在 marketplace, 从 github.com/thedotmack/claude-mem 下载)"
fi
```
未装也行——Athena 仍可用, `_index.md.platform_features.cross_session_memory` 标 "none".
### PACE 节点 best-fit (按需, 实时查 marketplace)
athena-setup **不写死推荐列表**, 改用 `/plugin browse` + 关键词查询:
| 路径 | 关键词 (用 /plugin browse 查) |
|------|------------------------------|
| Bugfix | debugger / bug-fix / metronome |
| Feature 实现 | superpowers / dev-workflows / context7 |
| Feature 审查 | codex-plugin-cc / agent-peer-review / local-review |
| Refactor | TypeScript LSP / Rust LSP / ast-grep |
| Refactor 审查 | codex-plugin-cc / AgentLint |
| System | shipyard (IaC) / mcp-builder |
| 跨节点 | context-mode (大输出 sandbox 化) |
### 官方插件 (claude-plugins-official, 已在 settings.json 启用)
```
/plugin install feature-dev
/plugin install code-review
/plugin install commit-commands
```
`/reload-plugins` 后生效.
## Step 2: context7 (skill 模式)
```bash
npx ctx7 setup --claude
```
无需全局装 ctx7 CLI, npx 按需拉. OAuth 登录后 `~/.claude/skills/` 自动生成 context7 skill.
触发方式: "use context7" 或 "use context7 with /owner/repo for <query>".
## Step 3: Codex 配置
```
/codex:setup
```
未登录 → `!codex login`.
**不要启用 review gate** (`/codex:setup --enable-review-gate`) — 会 Claude ↔ Codex 死循环.
settings.json codex 权限 (已在 v9.6 默认 settings 含):
```json
"Bash(codex:*)",
"Bash(node:*)"
```
Codex 独立配置 `~/.codex/config.toml` (见本仓库 cx/.codex/config.toml).
## Step 4: Hooks 安装
```bash
mkdir -p ~/.claude/hooks
cp .claude/hooks/*.cjs ~/.claude/hooks/
chmod +x ~/.claude/hooks/*.cjs
```
v9.6 hook 列表 (8 个):
- session-start · pre-bash-guard · index-updater · subagent-retry
- delivery-gate · pace-continuator
- permission-retry · compact-snapshot · compact-restore · state-audit
## Step 5: 验证
```bash
claude --version # ≥ 2.1.121, 最佳 ≥ 2.1.139
/plugin list # superpowers / codex / claude-mem (推荐)
npx ctx7 library express # context7 CLI 通
/codex:setup # Codex ready
ls ~/.claude/hooks/*.cjs | wc -l # 应 = 10
cat .ai_state/_index.md | head -5 # 含 schema_version: "9.6"
```
通过 → "安装完成。每个新项目 `/athena-init`, 然后 `/athena-dev`."
## 为什么这样设计 (用户视角)
| v9.5 有 | v9.6 变化原因 |
|---|---|
| 18 → 0 条 deny | sandbox 是正道, 但 v9.6 再加回 "Bash(rm -rf *)" 兜底 |
| 全局 lessons 系统 | 删, 委外给 claude-mem (89k stars) |
| 手写 spawn_agent 协议 | 部分场景接入 /batch (CC v2.1.121+ 原生) |
| delivery-gate 自造 VERDICT 解析 | 接入 /goal evaluator (v2.1.139+), 旧版本兜底 |
| 写死的插件推荐列表 | 改为 /plugin browse 实时查 |
+119
View File
@@ -0,0 +1,119 @@
---
name: athena-status
description: >
Athena 状态面板。显示当前 PACE 状态、Hook 触发计数、claude-mem 状态、plugin 健康。
effort: medium
disable-model-invocation: true
---
# /athena-status (v9.6)
实时聚合 Athena 运行状态。无副作用, 只读 (铁律 8 索引先行)。
## 收集顺序
### 1. PACE 状态 (从 _index.md frontmatter)
```bash
# 用 node 解析 YAML frontmatter
node -e '
const fs = require("fs");
const content = fs.readFileSync(".ai_state/_index.md","utf8");
const fm = content.match(/^---\n([\s\S]*?)\n---/);
if (!fm) { console.log("_index.md frontmatter 缺失"); process.exit(1); }
// 简化 YAML 解析: 仅读关键字段, 不引入 yaml 依赖
const get = (k) => { const m = fm[1].match(new RegExp("^ " + k + ": (.*)$","m")); return m ? m[1].replace(/^["\x27]|["\x27]$/g,"") : ""; };
console.log("Path: ", get("path"));
console.log("Stage: ", get("stage"));
console.log("Sprint: ", get("sprint"));
console.log("Goal: ", get("active_goal"));
'
```
### 2. Sprint 进度 (counts 段)
```bash
grep -E "^ (tasks_pending|tasks_done|tasks_blocked):" .ai_state/_index.md
```
### 3. Hook 触发记录 (最近 50 条)
```bash
tail -50 .ai_state/hook-trace.jsonl 2>/dev/null | \
jq -r '.hook' 2>/dev/null | sort | uniq -c | sort -rn
```
按 hook 名分组统计:
- session-start: 注入次数
- index-updater: 更新次数
- pre-bash-guard: 拦截次数
- subagent-retry: 注入次数
- delivery-gate: 触发 (阻断/soft warn/pass)
- pace-continuator: 写入 next/proposals 次数
- compact-* : 注入次数
- state-audit: 漂移告警次数
### 4. Lessons 统计 (仅项目级)
```bash
grep "^ lessons_lines:" .ai_state/_index.md
grep "^## " .ai_state/details/lessons.md 2>/dev/null | tail -1
echo "[全局已删除, 跨项目记忆装 claude-mem]"
```
### 5. Platform 健康
```bash
grep "^ cc_version:" .ai_state/_index.md
grep "^ cx_version:" .ai_state/_index.md
grep -E "^ (goal|batch|background)_supported:" .ai_state/_index.md
grep "^ cross_session_memory:" .ai_state/_index.md
```
### 6. Plugin 状态
- codex: `which codex || codex --version 2>&1 | head -1`
- superpowers: `ls ~/.claude/plugins/cache/superpowers/ 2>/dev/null`
- claude-mem: `ls ~/.claude/plugins/ 2>/dev/null | grep -i claude-mem`
- context7: `npx ctx7 --version 2>&1 | head -1`
## 输出格式
```
=== VibeCoding Athena v9.6 Status ===
[PACE] Path: Feature Stage: impl Sprint: 3
Goal: tasks all checked + npm test exits 0
[Tasks] 3 done · 2 pending · 0 blocked
Latest: details/progress.md#L46 (Task 5 done)
[Hooks] 最近 50 次触发:
session-start ✓ 5 注入
index-updater ✓ 28 更新
delivery-gate ✓ 12 (阻断 2, soft 1)
pre-bash-guard ✓ 0 拦截
pace-continuator ✓ 5 (next: 5, proposals: 2)
subagent-retry ⚠ 3 注入
[Lessons] 项目: 4 条 (最新: "JWT refresh secret 分离")
[全局已删除, 跨项目记忆装 claude-mem]
[Platform]
CC version ✓ 2.1.140
CX version ✓ 0.130
/goal ✓ supported
/batch ✓ supported
/background ✓ supported
Session memory ✓ active
Cross-session ✓ claude-mem
[Plugins]
codex@1.0.4 ✓ ready
superpowers@5.x ✓ loaded
claude-mem ✓ active
context7 ✓ available
[Commands]
test_cmd: npm test
build_cmd: npm run build
lint_cmd: npm run lint
```
## 实现方式
纯 Bash + node + jq. 失败的项显示 "✗ 不可用". 不写文件, 不改状态。
-38
View File
@@ -1,38 +0,0 @@
---
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
@@ -1,23 +0,0 @@
---
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
@@ -1,45 +0,0 @@
---
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 独立完成的替代逻辑}
```
@@ -1,109 +0,0 @@
// 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
@@ -1,64 +0,0 @@
---
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:
"作为严格审查者, 这个计划有哪些漏洞/模糊/不可执行的部分?"
@@ -1,11 +0,0 @@
# API Review Template
审查重点:
1. **接口一致性**: RESTful 约定? 命名统一?
2. **幂等性**: PUT/DELETE 是否幂等?
3. **版本控制**: URL 版本 (/v1/) 或 Header 版本?
4. **错误码**: HTTP 状态码 + 业务错误码 是否定义?
5. **认证/授权**: 每个端点的权限要求?
6. **速率限制**: 是否有限流策略?
7. **输入验证**: 请求体 schema 是否严格?
8. **响应格式**: 分页/排序/过滤 是否一致?
@@ -1,10 +0,0 @@
# Frontend Review Template
审查重点:
1. **可访问性**: ARIA 标签? 键盘导航? 色彩对比?
2. **响应式**: 移动端/平板/桌面 断点覆盖?
3. **XSS 防护**: 用户输入是否转义? dangerouslySetInnerHTML?
4. **性能**: 大列表虚拟滚动? 图片懒加载? 包体积?
5. **状态管理**: 数据流清晰? 避免 prop drilling?
6. **错误边界**: React ErrorBoundary? 加载/空/错误状态?
7. **国际化**: 硬编码文案? 日期/数字格式?
@@ -1,10 +0,0 @@
# General Review Template
审查重点:
1. **需求覆盖**: 每个 MUST 需求是否有对应任务?
2. **任务粒度**: 每个任务是否可在 1-2 小时内完成?
3. **依赖拓扑**: 任务依赖是否有环? 关键路径是什么?
4. **风险识别**: 哪些任务最可能出问题? 有 plan B?
5. **测试策略**: 单元/集成/E2E 比例合理?
6. **模糊检测**: 有没有"优化""改进"等模糊词?
7. **遗漏检测**: 错误处理/日志/监控/文档 是否涵盖?
@@ -1,10 +0,0 @@
# Infrastructure Review Template
审查重点:
1. **可用性**: 单点故障? 副本数? 健康检查?
2. **备份/恢复**: 数据备份策略? RTO/RPO?
3. **回滚计划**: 部署失败如何回滚? 数据库迁移可逆?
4. **监控/告警**: 关键指标有监控? 告警阈值合理?
5. **安全**: 网络隔离? 密钥轮换? 最小权限?
6. **成本**: 资源配置合理? 有自动伸缩?
7. **IaC**: 基础设施代码化? 可重复部署?
+47
View File
@@ -0,0 +1,47 @@
---
name: compound
description: >
Sprint Quality Gate 通过后触发。提炼本 Sprint 学到的为结构化条目追加 lessons.md。
effort: xhigh
---
# /compound — 经验沉淀
Gate PASS 后触发 (或用户显式 `/compound`).
## 输入
- `.ai_state/details/reviews/sprint-N.md` (审查报告)
- `git diff` (本 Sprint 所有变更)
- `.ai_state/details/tasks-current.md` (完成项)
- `.ai_state/details/design.md` (设计 vs 实际实现对比)
## 提炼方法
从以上输入找**真实发现**, 不写仪式性废话。每 Sprint 0-N 条不强制。
- **Pattern**: 什么解法有效且可复用? (带代码行号 / 文件路径)
- **Pitfall**: 什么坑踩过? 未来同类场景要提前避开
- **Constraint**: 发现的新约束 (依赖版本、环境、性能边界、API 限制)
没发现可提炼的 → 不写, 直接告知用户 "no new lesson". **不允许编造**.
## 输出 (项目级)
追加到 `.ai_state/details/lessons.md` (append-only, 不修改历史).
格式见 `pace/templates/details/lessons.md`. **Athena 不做跨项目知识管理**——需要的话装 claude-mem 或 superpowers。
写入后同步更新 `_index.md`:
- `counts.lessons_lines` += 新增条目数 (按 `## ` 头计)
- `pointers.latest_lesson` = `details/lessons.md#L<新条目行号>`
- `fingerprints.lessons_mtime` = 当前时间戳
## 自检
写入后读回验证:
1. 条目有具体的文件/行号/版本引用 (不只是"要注意 X")
2. 一句话标题能让下次 R₀ 快速扫描命中
3. Pattern/Pitfall/Constraint 三段不强制全有, 但至少有一段
写完告知用户: "Lessons updated. Next sprint R₀ 会自动读取 (按 _index.md.pointers.latest_lesson 跳转)."
-15
View File
@@ -1,15 +0,0 @@
---
name: context7
description: 库文档按需拉取
---
# Context7 (库文档查询)
需要查询依赖库文档时:
1. 优先: `npx ctx7 resolve {库名}` CLI 查询
2. 备选: web search 查最新 API
3. 缓存: 查过的 API 结论写入当前阶段笔记, 避免重复查询
## 触发时机
- R 阶段: 验证技术方案可行性
- E 阶段: 实现时遇到不确定的 API
- T 阶段: 验证 API 用法正确性
-27
View File
@@ -1,27 +0,0 @@
---
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
@@ -1,18 +0,0 @@
---
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
@@ -1,35 +0,0 @@
---
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
@@ -1,23 +0,0 @@
---
name: kaizen
description: V 阶段持续改进回顾
---
# Kaizen (V 阶段回顾)
## 流程
1. 回顾本次开发:
- 哪些做得好? (保持)
- 哪些做得差? (改进)
- 有没有反复出现的模式性错误?
2. 更新 .ai_state/lessons.md:
- 新发现的技术陷阱
- 有效的解决模式
- 项目特有的约定
3. 更新 .ai_state/conventions.md "## Agent 易犯错误" 段:
- 如果 Reflexion/Review 中发现了模式性错误
- 格式: `- "具体错误描述 + 正确做法"`
- 这些错误会在 SessionStart 时由 context-loader 输出提醒
4. 产出摘要给用户
+304
View File
@@ -0,0 +1,304 @@
---
name: pace
description: >
工作流路由器。收到开发任务时触发。按任务复杂度路由到 6 条路径, 编排 CC 工具 + 增强节点。
effort: xhigh
---
# PACE — 6 路径路由器 (v9.6 Athena)
首先读 `.ai_state/_index.md` (铁律 8 索引先行)。有 stage → 从当前阶段继续。
.ai_state/ 不存在 → 提示 `/athena-init`。
## 路由
```
┌─ 1行/配置 ──────→ Hotfix
修复 ────┤
└─ 需要调试 ─────→ Bugfix
┌─ 需求清晰/小 ──→ Quick
新建 ────┤ 需要设计 ─────→ Feature
├─ 改现有结构 ───→ Refactor
└─ 跨模块/服务 ──→ System
```
| Path | 文件量 | CC 主力 | 增强 | 写 _index.md |
| -------- | ------ | ---------------------- | --------------------------------------- | ------------ |
| Hotfix | 1 | Edit | 无 | 否 |
| Bugfix | 1-5 | /debug | 无 | 否 |
| Quick | 1-10 | TDD | 可选交叉审查 | 是 |
| Feature | 5-20 | /feature-dev | brainstorming + 交叉审查 | 是 |
| Refactor | 10-50 | /batch | superpowers + 交叉审查 | 是 |
| System | 20+ | /batch + /feature-dev | 全增强 | 是 |
Quick+ 路由完成 → 更新 `_index.md` (path, stage, sprint) → 告知用户。
---
## CC 原生自动化接入 (v9.6 新)
v9.5 的"自动 PACE"借助 CC 原生 `/goal /batch /loop /background` 实现, **不再发明状态机驱动器**。
### `/goal` — 每 stage 一个 condition (autonomous loop)
参考: <https://code.claude.com/docs/en/goal>
每个 PACE stage 配套一个 condition 模板, 见 `templates/details/goal-conditions.md`:
- **plan**: `design.md 含 File Structure Plan + tasks-current.md ≥ 1 Task + 用户回过 confirm`
- **impl**: `tasks-current.md 所有 [ ] 变 [x] + <test_cmd> exits 0 + progress.md 每 task 一行`
- **review**: `reviews/sprint-N.md 含 VERDICT 字段 + /codex:review 或 reviewer 已跑`
- **ship**: `lessons.md 含 Sprint N 条目 + git push 完成 + _index.md sprint+=1`
启动方式: `/goal <condition>` (CC v2.1.139+) 或 `claude -p "/goal <condition>"` (非交互).
**降级**: CC < v2.1.139 时无 /goal, 由 delivery-gate hook 兜底判定 VERDICT.
### `/batch` — Refactor/System 并行实现
参考: CC v2.1.121+, `/batch` 自动 5-30 worktree subagent + PR.
适用场景: 大量同模式 task (重命名 / import 路径迁移 / 接口签名变更).
**降级**: 旧版本 → spawn_agent 手动 worktree.
### `/background` + `claude agents` 多会话编排
参考: CC v2.1.139+, agent view 看 Running / Blocked / Done 状态.
适用: System 阶段长跑 / 跨任务监控.
---
## 跨平台路由建议 (Codex Terminal-Bench SOTA)
某些任务在 Codex 上更优:
| 信号 | 建议 |
|------|------|
| 终端命令为主 (build/test/grep/sed) | Codex Terminal-Bench 2.0 SOTA 82.7% (GPT-5.5, April 2026), 委派 Codex |
| 大量重复改写 (100 个文件相同 import 路径) | Codex token 0.25-0.33×, 更经济 |
| 需要多 reviewer 互相 critique | CC 主跑 + /codex:adversarial-review 二审 |
| 设计/架构判断 | CC Opus 4.7 略强, 主跑 CC + Codex review |
不强制——是建议。
---
## 路径升级机制 (impl 阶段持续监测)
写代码过程中发现实际复杂度超出当前路径 → 暂停询问用户升级:
| 升级触发信号 | 当前 → 建议 |
|------------|-----------|
| 需要改数据库 schema | * → System |
| 跨 3+ 模块的接口变更 | Feature → System |
| 实际改文件数 > 当前路径上限的 50% | Quick → Feature, Feature → Refactor/System |
| Refactor 中发现需要新增模块 | Refactor → System |
升级流程: 用户确认 → _index.md path 升级 + stage 回到 design (System) 或 plan → progress.md 追加升级记录 → 重新 plan。
**不自动升级**, 避免 Athena 借机扩 scope。
---
## 共享协议
### 审查协议 (Quick/Feature/Refactor/System 的 review 阶段共用)
```
1. /review → 第一份审查 (CC 原生)
2. [Feature+] /codex:review [--base main] [--wait] → 跨模型审查
→ 必须看到真实 codex job ID 或命令输出 (铁律 6)
→ 调用失败 → 失败处理协议三轮 → 真失败则降级 + review-report.md 注明 "codex unavailable + stderr"
3. [System] 追加 /codex:adversarial-review + ECC AgentShield
4. [System UI 类] superpowers /qa + playwright E2E
5. /simplify
6. @evaluator → VERDICT
PASS → 触发 /compound → details/lessons.md 追加 → 停一轮让用户确认 → stage=ship
CONCERNS → 修复 → 重新评分
REWORK → stage=impl (Feature/Refactor) 或 stage=design (System)
FAIL → stage=plan
```
### 发布协议 (ship 阶段共用)
```
1. [Quick] git commit → 直接提交
2. [Feature+] superpowers /ship → 同步 main, 跑测试, 开 PR
3. [System] superpowers /retro → 工程回顾
4. details/lessons.md (compound 已追加) + progress.md 最终更新
5. _index.md: stage="", sprint+=1
6. /compact "Sprint N 完成"
```
---
## 失败处理协议 (落地铁律 6 完成度证据)
工具调用失败 (任意 Bash/Skill/Task):
```
Round 1: 读 stderr 和 exit code 分类:
- permission denied → 报具体规则, **继续尝试**:
a) 用 settings.local.json 临时绕过 (告知用户)
b) 换等价命令 (node 改 npx)
c) 拆到主 agent
- command not found → 装包 / 换工具
- subagent 报"无能力" → 实测一次 (echo 探测), 真不可用主 agent 接管
Round 2: 改参数 / 换路径 / 换工具
Round 3: 仍失败 → 报告每次的:
- 完整命令
- 完整 stderr
- exit code
- 已尝试的修复方式
→ 写入 review-report.md / progress.md 作为完成度证据
```
**绝对禁止**: "请你用 ! 前缀手动执行" 作为第一次响应。
**subagent 输出预算 ≤ 2000 tokens** (Anthropic 多 agent research 经验): 深入探索可以, 只回传关键发现。
---
## Hotfix — 无仪式
```
Edit → test_cmd (有就跑) → git commit → 完
```
## Bugfix — /debug + TDD (无 stage)
```
/debug → 定位根因
TDD: 写回归测试(复现) → 修复 → 测试通过
lint_cmd → /review → git commit
自愈: 修不好 → /debug 再来 (限 3 轮) → 3 轮后通知用户
```
## Quick
stages: impl → review → ship
```
stage=impl:
Explore: 读要改的文件 + 调用方
TDD 实现 (superpowers brainstorming 自动激活)
库文档不确定 → use context7
每完成 Task → tasks-current.md 勾选 + progress.md 追加一行 + index-updater 自动更 _index.md counts
路径升级监测
lint_cmd + test_cmd → /simplify → stage=review
stage=review: → 审查协议
stage=ship: → 发布协议
```
## Feature — /feature-dev + 增强
stages: plan → impl → review → ship
```
stage=plan:
R₀: 命中主题再读 details/lessons.md (just-in-time, 不预加载)
superpowers brainstorming → 发散 + 方向挑战
→ 合成 design.md (含 File Structure Plan 段)
用户确认 → tasks-current.md (Boundary/Depends 标注) → stage=impl
可选: /goal "tasks-current.md 全 [x] + npm test exits 0"
stage=impl:
/feature-dev "需求描述"
Phase 4 (架构) 前 → 用户确认
每完成 Task → tasks-current.md 勾选 + progress.md 追加
设计偏离 → 先改 design.md 再继续 (铁律 5)
库文档不确定 → use context7
路径升级监测 → 触发即停
/simplify → stage=review
stage=review: → 审查协议
stage=ship: → 发布协议
```
## Refactor — /batch + 增强
stages: plan → impl → review → ship
```
stage=plan:
R₀: 按需 read details/lessons.md
superpowers /plan-eng-review → 验证重构方案
用户确认 → design.md (含 before/after 边界) + tasks-current.md → stage=impl
stage=impl:
/batch "重构描述" ← CC v2.1.121+ 原生
CC 自动: Research → Plan → 用户确认 → 并行 worktree → 每 worker /simplify + 测试
每完成一组 Task → tasks-current.md 勾选 + progress.md 追加
路径升级: 发现需要新增模块 → 升 System
→ stage=review
```
## System — 全链
stages: plan → design → impl → review → ship
```
stage=plan:
R₀: 按需 read details/lessons.md
superpowers /office-hours → 需求提取
superpowers brainstorming → 发散 + 方向挑战
→ 合成 design.md → 用户确认 → stage=design
stage=design:
superpowers /plan-eng-review → 架构锁定
superpowers /plan-design-review → 设计审查 (有 UI 时)
design.md 必含 File Structure Plan → tasks 据此拆
→ 合成 tasks-current.md → 用户确认 → stage=impl
stage=impl:
按 Task 性质选工具:
批量同模式 → /batch 并行 (CC 原生)
复杂独立 → /feature-dev
跨模型委托 → /codex:rescue "<prompt 内容>"
每完成 Task → tasks-current.md 勾选 + progress.md 追加
全部完成 → /simplify → stage=review
stage=review: → 审查协议 (含 adversarial + ECC + /qa + E2E)
stage=ship: → 发布协议 (含 /retro)
```
---
## 状态管理 (铁律 5/8 文档即真相 + 索引先行)
`.ai_state/_index.md` frontmatter 字段: path, stage, sprint, active_goal, tech_stack, test_cmd, build_cmd, lint_cmd, dev_cmd, conventions, gotchas, counts, pointers, fingerprints, platform_features
合法 path: Quick, Feature, Refactor, System (Hotfix/Bugfix 不写 _index)
合法 stage: plan, design (System only), impl, review, ship, ""
**`.ai_state/` 文档职责 (just-in-time)**:
- 写端:
- `_index.md` ← athena-init + 路由 + index-updater hook (PostToolUse)
- `details/tasks-current.md` ← plan + impl 勾选
- `details/tasks-archive/sprint-N.md` ← ship 时归档
- `details/progress.md` ← impl 每 Task 追加 (append-only)
- `details/design.md` ← plan + impl 偏离时更新
- `details/handoff.md` ← 跨模型/跨 worker 临时
- `details/lessons.md` ← compound skill 写 (append-only)
- `details/reviews/sprint-N.md` ← V 阶段写
- `details/next.md` ← pace-continuator (Stop hook) 写下一步建议
- `details/proposals.md` ← Stop hook 反思沉淀 (铁律 9)
- `hook-trace.jsonl` ← hooks 自动
- 读端 (按 _index.md.pointers 跳转, 不预加载):
- 必读: `_index.md`
- 阶段=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
- 任务命中 lessons 主题 → pointers.latest_lesson 跳到段
- plan 阶段 → 命中再读 lessons / impl 读 design 对照 / review 读 design + previous reviews
**跨项目记忆已删除**: Athena 不做。推荐装 claude-mem (~/.claude/projects/ 已内置) 或 superpowers。
`delivery-gate` (Stop hook) 在 stage="review" 时检查质量门 (Feature+ 要求外部审查, Quick 不要求)。
阶段转换 + 长任务中 → 主动 `/compact`, 不等 context 满。
不间断工作: 不确定用什么库 → use context7。不确定现有代码 → Read 看。不确定测试怎么跑 → 读 _index.md test_cmd。
只在以下情况停: 方案需用户确认 (plan 阶段), VERDICT 需判断 (review 阶段), 真正的阻塞 (失败 3 次后)。
+44
View File
@@ -0,0 +1,44 @@
# VibeCoding Athena (SessionStart 自动注入)
你是 VibeCoding Athena 工程 Agent。CC 做事, Athena 把关。
**铁律 (9 条)**:
1. 设计先行 (Hotfix/Bugfix 例外)
2. TDD 强制
3. Sisyphus (tasks 全完成才进审查)
4. Review 强制 (Feature+ 至少一次交叉审查)
5. 文档即真相 (`.ai_state/_index.md` 单一入口)
6. 完成度证据 (报告"完成"必须附 tool_use ID 或命令输出)
7. 出处优先 (技术结论必须引用官方文档/源码 URL)
8. **索引先行** (进入决策先读 `.ai_state/_index.md`, 禁止 glob 全目录)
9. **Hook 是进化器** (Stop 时反思写 `details/proposals.md`)
工具报错 → 三次重试附 stderr 报告, 不让用户代执行。
/codex:* 必须产生真实 tool_use 响应。
## R₀ Get-bearings (just-in-time)
1. **必读**: `.ai_state/_index.md` (单一入口, 已自动注入)
2. **按需**: stage=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
3. **按需**: 任务命中 lessons 主题 → pointers.latest_lesson 跳段
4. **按需**: `git log --oneline -10` (涉及代码修改时)
文件大就用 head/tail/grep, 不要 cat 全文。**禁止 glob 整个 .ai_state/**。
## 文档写入义务 (铁律 5)
- impl 每完成 Task → tasks-current.md 勾选 + progress.md 追加一行 (index-updater hook 自动更 _index.md counts)
- 发现 design.md 错 → 先改 design.md 再继续写代码
- V 阶段 Gate 通过 → /compound 追加 details/lessons.md
## 6 路径
Hotfix (无仪式) · Bugfix (/debug+TDD) · Quick (TDD+收尾) · Feature (/feature-dev+增强) · Refactor (/batch+增强) · System (全链)
路径升级触发器: 改 schema / 跨 3+ 模块 / 文件数超 50% → 暂停询问升级。
## v9.6 新接入 (CC 原生)
- `/goal <condition>` (v2.1.139+): 每 stage 一个 goal, evaluator 自动判定
- `/batch`: Refactor/System 自动并行 worktree
- `/background` + `claude agents`: 多会话编排
+66
View File
@@ -0,0 +1,66 @@
---
schema_version: "9.6"
athena_version: "9.6.0"
project:
path: "" # Hotfix | Bugfix | Quick | Feature | Refactor | System | ""
stage: "" # plan | design | impl | review | ship | ""
sprint: 0
active_goal: "" # 当前 /goal condition (空 = 无活动 goal)
counts:
tasks_pending: 0
tasks_done: 0
tasks_blocked: 0
lessons_lines: 0
progress_entries: 0
reviews_count: 0
pointers:
latest_progress: "" # 如 "details/progress.md#L46"
latest_review: "" # 如 "details/reviews/sprint-3.md"
latest_lesson: "" # 如 "details/lessons.md#L98"
latest_proposal: "" # 如 "details/proposals.md#L12"
fingerprints:
tasks_mtime: 0
design_mtime: 0
progress_mtime: 0
lessons_mtime: 0
platform_features:
cc_version: "" # 由 athena-setup 检测填入
cx_version: "" # 同上
goal_supported: false # CC ≥ v2.1.139 时 true
batch_supported: false # CC ≥ v2.1.121 时 true
background_supported: false # CC ≥ v2.1.139 时 true
session_memory_active: false # ~/.claude/projects/ 自动摘要是否启用
cross_session_memory: "none" # "claude-mem" | "superpowers" | "none"
gotchas: [] # 项目特有的"小心点", PACE 会在 SessionStart 注入
conventions: [] # 项目约定 (pnpm vs npm 等)
tech_stack: ""
test_cmd: ""
build_cmd: ""
lint_cmd: ""
dev_cmd: ""
---
# 项目状态索引
<!--
本文件是 .ai_state/ 的单一入口 (铁律 8)。
SessionStart hook 只读这一个文件, 注入轻量 frontmatter 字段 + counts 摘要。
下游 (Edit/Read tools) 按 pointers 自取明细。
任何 detail/* 文件写入 → PostToolUse index-updater.cjs 原子更新本文件。
-->
## 最近活动
<!-- 由 pace-continuator hook 在 Stop 时维护, 保留最近 3 条 -->
## 当前阻塞
<!-- 由 PACE 流程在 stage=impl/review 时填写 -->
## 下一动作 (PACE 建议)
<!-- 由 pace-continuator 在 Stop 时根据 stage 推断, 写入 details/next.md 的摘要 -->
## 反思建议 (Hook 沉淀)
<!-- 引用 details/proposals.md 最近一条 (latest_proposal) -->
@@ -0,0 +1,28 @@
# 设计文档
## 需求摘要
## 功能分级
- **MUST**:
- **SHOULD**:
- **COULD**:
## 验收标准
- [ ]
## 技术方案
## File Structure Plan
<!--
模块/文件边界, 给 tasks-current.md 拆任务用 (boundary-first 设计)
示例:
- src/auth/ — JWT/refresh/session, owner: Task 1-3
- src/routes/user/ — user CRUD endpoints, owner: Task 4-5
- tests/auth/ — auth 单测 + 集成测试
边界外的文件 = 本 Sprint 不应触碰
-->
## 不做什么
@@ -0,0 +1,31 @@
# 跨模型/跨 worker 交接
<!--
本文件内容会作为 /codex:rescue "<内容>" 的 prompt 传入。Codex 不会自动读本文件。
构造完 handoff.md → Claude 把文件内容 Read 出来作为 /codex:rescue 的参数。
-->
## 当前任务
<!-- Task ID + 描述 + 验收标准 + Boundary 范围 -->
## 项目文件树
<!-- 必须包含实际文件列表, 用 find/ls 生成, 不要手写 -->
<!-- 示例: find . -name "*.py" -not -path "./venv/*" | head -50 -->
## 关键代码片段
<!-- 与本 Task 直接相关的代码文件内容 (关键函数/类, 不要全文) -->
## 项目背景
<!-- design.md 摘要 + 技术栈 -->
## 已完成
<!-- tasks-current.md 中完成的 Task -->
## 注意事项
<!-- _index.md.gotchas + conventions -->
@@ -0,0 +1,21 @@
# 项目级经验沉淀 (Lessons Learned)
<!--
每个 Sprint 通过 Gate 后由 compound skill 追加。append-only, 不删不改历史。
本文件存项目级业务代码经验 (Athena 不做跨项目知识管理)。
跨项目记忆请装 claude-mem 或 superpowers。
格式:
## [YYYY-MM-DD Sprint N] 一句话标题
- **Pattern**: 解法描述 (文件:行号)
- **Pitfall**: 坑点描述
- **Constraint**: 新约束
示例:
## [2026-05-21 Sprint 1] JWT refresh 不能和 access 共享 secret
- **Pattern**: 分开 secret + rotation key 在 env (src/auth/config.ts:15)
- **Pitfall**: Authorization header 大小写处理不一致, 用 lodash.toLower 前置
- **Constraint**: Redis 需要 ≥256MB 才放得下 session cache
-->
@@ -0,0 +1,15 @@
# 下一动作建议 (PACE-aware, Stop hook 维护)
<!--
本文件由 .claude/hooks/pace-continuator.cjs 在 Stop 事件时写入。
读 _index.md 的 path/stage/sprint, 推断"下一步该做什么", 给出具体的命令建议。
SessionStart 时 (如有 pace-resumer hook) 会读本文件作为"继续提示"。
格式:
## YYYY-MM-DD HH:MM
当前: <path>/<stage>/sprint <N>
建议:
- 命令 1
- 命令 2
理由: <一句话>
-->
@@ -0,0 +1,15 @@
# Progress Log
<!--
impl 阶段每完成一个 Task 追加一行 (铁律 5)。
格式: YYYY-MM-DD HH:MM [path/stage/sprint] action
示例:
2026-05-21 14:30 [Feature/impl/1] Task 3 done: auth middleware
2026-05-21 15:10 [Feature/impl/1] design.md updated: JWT expiry 15min
2026-05-21 15:30 [Feature/impl/1] PATH-UPGRADE Feature → System (发现需要改 schema)
2026-05-21 16:45 [Feature/review/1] /review 完成, 无阻塞问题
append-only: 不删历史, 不改既有行。
index-updater hook 会更新 _index.md.counts.progress_entries 和 pointers.latest_progress。
-->
@@ -0,0 +1,20 @@
# Hook 反思沉淀 (铁律 9: Hook 是进化器)
<!--
本文件由 .claude/hooks/pace-continuator.cjs 在 Stop 时维护。
当 hook 检测到"本 turn 有反复试错 / 阻塞 / 失败模式", append-only 一条反思。
不写"已知坑" (lessons.md 管那个), 写"流程级提议":
- "考虑把 X 加入 .ai_state/conventions"
- "delivery-gate 这条规则可能误伤, 下版本调整"
- "本 sprint 的 stage transition 太快, plan 阶段不充分"
人审完后可以手动迁移到 lessons.md 或者 conventions 列表。
hook 永远不替用户做决定, 只提供素材。
格式:
## YYYY-MM-DD HH:MM (sprint N)
- 观察: <事实>
- 假设: <可能原因>
- 提议: <改什么>
-->
@@ -0,0 +1,41 @@
# Sprint N 审查报告
## Step 1: 测试结果
<!-- 命令 + 实际输出 (不是"已跑通") -->
## Step 2: /codex:review (Feature+, Quick 可选)
<!-- 必须有以下证据之一, 防伪装 (铁律 4 反空跑 + 铁律 6 完成度证据):
- codex job ID
- codex CLI 真实命令行输出片段
- 不可用时明示 "codex unavailable" + 完整 stderr -->
## Step 3: /codex:adversarial-review (System)
<!-- 同上证据要求 -->
## Step 4: ECC 扫描 (System)
<!-- npx ecc-agentshield scan 实际输出摘要 -->
## Step 5: Claude 审查 (/review 内置)
<!-- /review 输出 -->
## Step 6: @evaluator 评分
| 维度 | 分数 | 证据 |
|------|------|------|
| Functionality | /5 | (代码行号) |
| Spec Compliance | /5 | (代码行号 vs design.md) |
| Boundary Adherence | /5 | (是否越出 File Structure Plan) |
| Craft | /5 | (代码行号) |
| Robustness | /5 | (边界用例覆盖) |
| **均分** | **/5** | |
均分 = F×0.25 + SC×0.25 + B×0.15 + C×0.15 + R×0.20
## VERDICT:
<!-- PASS (均分≥4.0 且所有维度≥3) | CONCERNS (均分≥3.0 有维度=2) | REWORK (均分<3.0 或任一=1) | FAIL (多维度=1 或安全/Boundary 大幅越界) -->
@@ -0,0 +1,19 @@
# Sprint 任务清单
<!--
每个 Task 的 Boundary/Depends 标注 (cc-sdd 边界优先, 防止越界)
格式:
- [ ] Task N: 简述
_Boundary:_ src/auth/, tests/auth/
_Depends:_ Task N-1 (空则 — )
PostToolUse hook (index-updater.cjs) 会:
- 检测本文件的 - [ ] / - [x] 数量变化
- 原子更 _index.md.counts.tasks_pending/done/blocked
-->
## 待办
## 完成
## 阻塞
@@ -0,0 +1,121 @@
# /goal Condition 模板库
每个 PACE stage 对应一个 condition 模板, 用 `/goal <condition>` 启动 autonomous loop。
参考: <https://code.claude.com/docs/en/goal>
## 写 condition 的四件套 (官方推荐)
```
End Goal + Verification + Constraints + Turn/Time Limit
```
- **End Goal**: 一个可测的终态 (test 通过 / 文件存在 / git log 含 commit)
- **Verification**: 如何证明 (npm test exits 0 / rg "X" 0 行)
- **Constraints**: 边界 (不动 X 文件 / 不引入新依赖)
- **Turn/Time Limit**: stop after 20 turns / stop after 60 minutes
---
## Feature/Refactor/System stage=plan
```
ALL of:
- .ai_state/details/design.md 含 "## File Structure Plan" 段且段下至少 3 个 owner 行
- .ai_state/details/tasks-current.md 至少 1 个 - [ ] Task
- 我已经 ask 用户确认且收到了 "yes" 或 "go" 回复
Constraints:
- 不修改 design.md 之外的源码文件
- 不超过 20 turns
```
## Quick/Feature stage=impl
```
ALL of:
- .ai_state/details/tasks-current.md 中所有 - [ ] 都变成 - [x]
- 运行 <test_cmd> 退出码 0 (从 _index.md.test_cmd 读)
- .ai_state/details/progress.md 在本 turn 序列至少新增 N 行 (N = 原待办 task 数)
- 没有任何对 design.md 的修改
Constraints:
- 不动 .ai_state/_index.md 以外的元数据
- 不超过 30 turns 或 90 分钟
```
## Refactor stage=impl (用 /batch)
```
ALL of:
- tasks-current.md 全部 - [x]
- 每个 worktree 的 lint_cmd 退出 0
- 每个 worktree 的 test_cmd 退出 0
- 主分支 git diff 显示预期的批量变更模式
Constraints:
- 不引入新依赖
- 不超过 60 minutes 或 50 turns
```
## System stage=design
```
ALL of:
- details/design.md 含 "## File Structure Plan" 且段下覆盖所有新增/修改的模块路径
- details/design.md 含 "## 验收标准" 段且至少 5 条 - [ ] (会在 impl 阶段勾选)
- details/tasks-current.md 至少 N 个 Task (N = design 模块数), 每个含 Boundary 和 Depends 注释
- 我已经 ask 用户对设计的最终确认
Constraints:
- 不超过 25 turns
```
## stage=review (Feature+)
```
ALL of:
- .ai_state/details/reviews/sprint-{sprint}.md 已存在且含 "VERDICT:" 行
- VERDICT 取值为 PASS / CONCERNS / REWORK / FAIL 之一
- 报告含至少一段 /codex:review 或 reviewer subagent 的真实输出 (codex job ID 或 thread ID)
- 报告含 test_cmd 实际输出
Constraints:
- 评分必须基于代码行号级证据
- 不超过 40 turns
```
## stage=ship
```
ALL of:
- details/lessons.md 末尾含 "## [{date} Sprint {sprint}]" 标题
- git log --oneline -1 显示本 sprint 的提交
- _index.md.project.sprint 已 +1 且 stage="" (由 athena-status 验证)
- details/tasks-archive/sprint-{sprint}.md 存在 (归档)
Constraints:
- 不超过 10 turns
```
---
## 启动方式
### 交互式
```
/goal <粘贴上面对应 stage 的 condition>
```
### 非交互式 (overnight 跑)
```bash
claude -p "/goal <condition>"
```
### 状态查询
```
/goal # 不带参数, 看 turns/tokens/最近 evaluator reason
/goal clear # 中止
```
## 注意事项 (官方文档)
- evaluator 只读 transcript, 不跑命令——condition 必须是"transcript 能证明的事"
- 一个 session 只能有一个 active goal, 设置新 goal 替换旧的
- condition ≤ 4000 字符
- v2.1.139+ 才有, 旧版本 delivery-gate hook 兜底
- "Vague in, vague out"——含糊的 condition = 含糊的 loop
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
# Athena init.sh — 启动开发环境 + 基线测试
# 由 /athena-init 根据项目类型生成具体命令
set -e
echo "[Athena] 启动开发环境..."
# 示例 (根据项目类型):
# npm install
# pip install -e .
# cargo build
echo "[Athena] 运行基线测试..."
# npm test
# pytest
# cargo test
echo "[Athena] 就绪。"
-26
View File
@@ -1,26 +0,0 @@
---
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
@@ -1,27 +0,0 @@
---
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
@@ -1,16 +0,0 @@
---
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
@@ -1,20 +0,0 @@
---
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
@@ -1,12 +0,0 @@
# Conventions
## 项目编码规范
{由 vibe-init 自动检测并填入, 或手动编写}
## 依赖版本
{关键依赖 + 版本号}
## Agent 易犯错误
> 由 reflexion/kaizen 自动追加, 帮助 agent 避免重复犯错
- (初始为空, 使用过程中逐渐积累)
-24
View File
@@ -1,24 +0,0 @@
# Design Spec
## 需求 (MUST/SHOULD/COULD)
### MUST (必须实现)
- {核心功能 1}
- {核心功能 2}
### SHOULD (应该实现)
- {重要功能}
### COULD (可以实现)
- {锦上添花}
## 技术方案
{架构 + 关键设计决策}
## 验收标准
- [ ] {标准 1: 具体可验证的条件}
- [ ] {标准 2: 具体可验证的条件}
## 非功能需求
- 性能: {指标}
- 安全: {要求}
-7
View File
@@ -1,7 +0,0 @@
# Doing
## 当前执行
- [ ] {当前步骤描述}
## 执行历史
{自动追加完成的步骤}
-10
View File
@@ -1,10 +0,0 @@
# Lessons Learned
## 技术陷阱
{Reflexion/Kaizen 发现的技术问题}
## 有效模式
{本项目中验证有效的解决方案}
## 项目特有知识
{不在文档中但很重要的隐性知识}
-14
View File
@@ -1,14 +0,0 @@
# Plan
## 任务列表
- [ ] T-001: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: 无
- [ ] T-002: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: T-001
## 对抗审查记录
{Codex 审查结果摘要, 或 "CC 独立审查"}
-18
View File
@@ -1,18 +0,0 @@
# Quality Report
## 验证结果
- 测试: {通过/失败} ({覆盖率}%)
- TypeScript: {通过/失败}
- Lint: {通过/失败}
## 验收标准确认
- [x] {标准 1}: 满足, 证据: {测试名/文件位置}
- [ ] {标准 2}: 未满足, 原因: {说明}
## 代码审查
- 审查者: {CC / Codex / 互审}
- 发现问题: {数量}
- 已修复: {数量}
## 未满足验收标准
{列出未满足的标准 + 原因}
-13
View File
@@ -1,13 +0,0 @@
# Session
## 任务
{任务描述}
## 路径
P.A.C.E. Path: {A|B|C|D}
## 当前阶段
RIPER-7: {R₀|R|D|P|E|T|V}
## 时间戳
开始: {ISO timestamp}
-13
View File
@@ -1,13 +0,0 @@
# 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
@@ -1,71 +0,0 @@
# 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 不可用时: 直接输出确认提示)