From c19b43f4723d5023dea3ca9aeff9123b498b676a Mon Sep 17 00:00:00 2001 From: Gaubee Date: Thu, 25 Dec 2025 08:48:59 +0800 Subject: [PATCH 1/2] feat(agent): manage best practices --- AGENTS.md | 5 + .../best-practices.md" | 13 ++ .../00-\345\277\205\350\257\273/index.md" | 12 +- .../update-agent-practices/proposal.md | 14 ++ .../specs/agent-cli/spec.md | 20 +++ .../changes/update-agent-practices/tasks.md | 6 + scripts/agent/cli.ts | 43 +++++ scripts/agent/practice.ts | 162 ++++++++++++++++++ scripts/agent/readme.ts | 17 +- scripts/agent/utils.ts | 1 + 10 files changed, 272 insertions(+), 21 deletions(-) create mode 100644 "docs/white-book/00-\345\277\205\350\257\273/best-practices.md" create mode 100644 openspec/changes/update-agent-practices/proposal.md create mode 100644 openspec/changes/update-agent-practices/specs/agent-cli/spec.md create mode 100644 openspec/changes/update-agent-practices/tasks.md create mode 100644 scripts/agent/practice.ts diff --git a/AGENTS.md b/AGENTS.md index 98a0d901..4b6e18f7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,7 @@ pnpm agent readme ``` `pnpm agent readme` 是白皮书导览入口,白皮书具体路径与阅读建议以该命令输出为准。 +最佳实践文件位于 `docs/white-book/00-必读/best-practices.md`,由 `pnpm agent practice` 维护。 常用命令: @@ -35,6 +36,10 @@ pnpm agent --help # 查看帮助 pnpm agent roadmap current # 当前 Roadmap pnpm agent toc # 白皮书目录 pnpm agent chapter <路径> # 读取白皮书章节 +pnpm agent practice list # 最佳实践列表 +pnpm agent practice add "<内容>" +pnpm agent practice remove <序号|内容> +pnpm agent practice update <序号> "<内容>" pnpm agent claim # 领取任务 pnpm agent worktree create --branch --base main pnpm agent worktree list diff --git "a/docs/white-book/00-\345\277\205\350\257\273/best-practices.md" "b/docs/white-book/00-\345\277\205\350\257\273/best-practices.md" new file mode 100644 index 00000000..0441f065 --- /dev/null +++ "b/docs/white-book/00-\345\277\205\350\257\273/best-practices.md" @@ -0,0 +1,13 @@ +# 最佳实践 + +> 由 `pnpm agent practice` 维护。 + +## 列表 + +- ❌ Radix Dialog / position:fixed → ✅ Stackflow BottomSheet/Modal +- ❌ React Router → ✅ Stackflow push/pop/replace +- ❌ 复制 mpay 代码 → ✅ 理解后用 React/TS 重写 +- ❌ 随意创建 store → ✅ 遵循 stores/ 现有模式 +- ❌ 明文选择器 → ✅ data-testid +- ❌ 安装新 UI 库 → ✅ shadcn/ui(已集成) +- ❌ 新建 CSS → ✅ Tailwind CSS diff --git "a/docs/white-book/00-\345\277\205\350\257\273/index.md" "b/docs/white-book/00-\345\277\205\350\257\273/index.md" index f7a0df40..adddd97e 100644 --- "a/docs/white-book/00-\345\277\205\350\257\273/index.md" +++ "b/docs/white-book/00-\345\277\205\350\257\273/index.md" @@ -10,14 +10,10 @@ AI 模型在开发移动端 Web 应用时,往往会基于通用 Web 开发经 ### 🚫 常见错误直觉 -| 场景 | ❌ 错误直觉 | ✅ 正确做法 | -|------|------------|------------| -| 弹出层/Sheet | 使用 Radix Dialog、自定义 `position: fixed` | 使用 Stackflow 的 `BottomSheet` 或 `Modal` 组件 | -| 居中对话框 | 使用 Radix AlertDialog | 使用 Stackflow 的 `Modal` Activity | -| 页面导航 | 使用 React Router | 使用 Stackflow 的 `push()`、`pop()` | -| 状态管理 | 使用 Redux、Zustand 随意创建 store | 遵循 `stores/` 目录下的现有模式 | -| 样式 | 随意使用 inline style 或新建 CSS 文件 | 使用 Tailwind CSS 类名 | -| 组件库 | 随意安装 Ant Design、Material UI | 使用 shadcn/ui(已集成) | +最佳实践已独立维护在: + +- `00-必读/best-practices.md` +- `pnpm agent practice list` ### 📚 为什么会出错? diff --git a/openspec/changes/update-agent-practices/proposal.md b/openspec/changes/update-agent-practices/proposal.md new file mode 100644 index 00000000..5237ca06 --- /dev/null +++ b/openspec/changes/update-agent-practices/proposal.md @@ -0,0 +1,14 @@ +# Change: Extract best practices and add practice subcommand + +## Why +最佳实践需要独立文件并可由子命令管理(读取/添加/删除/修改),当前实践内容散落在 `readme` 输出和 00-必读中,无法结构化维护。 + +## What Changes +- 新增独立文件 `docs/white-book/00-必读/best-practices.md`。 +- 新增 `pnpm agent practice` 子命令,支持 list/add/remove/update。 +- `pnpm agent readme` 的最佳实践从文件读取。 +- 更新白皮书索引与文档提示,引用新的最佳实践文件与命令。 + +## Impact +- Affected specs: agent-cli +- Affected code: scripts/agent/cli.ts, scripts/agent/readme.ts, scripts/agent/practice.ts (new), scripts/agent/utils.ts, docs/white-book/00-必读/index.md, docs/white-book/00-必读/best-practices.md, AGENTS.md diff --git a/openspec/changes/update-agent-practices/specs/agent-cli/spec.md b/openspec/changes/update-agent-practices/specs/agent-cli/spec.md new file mode 100644 index 00000000..02cf32b7 --- /dev/null +++ b/openspec/changes/update-agent-practices/specs/agent-cli/spec.md @@ -0,0 +1,20 @@ +## ADDED Requirements + +### Requirement: Practice subcommand +`pnpm agent practice` SHALL manage a standalone best-practices file and support list/add/remove/update. + +#### Scenario: List practices +- **WHEN** the user runs `pnpm agent practice list` +- **THEN** the CLI prints the current best-practices items + +#### Scenario: Add practice +- **WHEN** the user runs `pnpm agent practice add "..."` +- **THEN** the CLI appends the new practice item to the file + +#### Scenario: Remove practice +- **WHEN** the user runs `pnpm agent practice remove 3` +- **THEN** the CLI removes the third practice item + +#### Scenario: Update practice +- **WHEN** the user runs `pnpm agent practice update 2 "..."` +- **THEN** the CLI replaces the second practice item with the new content diff --git a/openspec/changes/update-agent-practices/tasks.md b/openspec/changes/update-agent-practices/tasks.md new file mode 100644 index 00000000..b9c1eb3a --- /dev/null +++ b/openspec/changes/update-agent-practices/tasks.md @@ -0,0 +1,6 @@ +## 1. Implementation +- [x] 1.1 新增最佳实践独立文件并迁移内容 +- [x] 1.2 新增 `pnpm agent practice` 子命令(list/add/remove/update) +- [x] 1.3 readme 输出改为读取最佳实践文件 +- [x] 1.4 更新 AGENTS/白皮书索引提示 +- [x] 1.5 验证:运行 `pnpm agent practice list` 与 `pnpm agent readme` diff --git a/scripts/agent/cli.ts b/scripts/agent/cli.ts index 92c69958..c64bdd5e 100644 --- a/scripts/agent/cli.ts +++ b/scripts/agent/cli.ts @@ -19,6 +19,7 @@ * pnpm agent worktree create --branch [--base main] * pnpm agent worktree delete [--force] * pnpm agent worktree list + * pnpm agent practice list|add|remove|update */ import { log } from './utils' @@ -39,6 +40,7 @@ import { } from './epic' import { printWhiteBookToc, printChapterContent } from './whitebook' import { createWorktree, deleteWorktree, listWorktrees } from './worktree' +import { addPractice, listPractices, removePractice, updatePractice } from './practice' function printHelp(): void { console.log(` @@ -70,6 +72,12 @@ Worktree 管理: pnpm agent worktree list 分支前缀仅允许: feat/, fix/, docs/, test/, refactor/, chore/, ci/, openspec/, release/ +最佳实践管理: + pnpm agent practice list + pnpm agent practice add "<内容>" + pnpm agent practice remove <序号|内容> + pnpm agent practice update <序号> "<内容>" + Aliases: CURRENT -> V1, NEXT -> V2 Examples: @@ -79,6 +87,7 @@ Examples: pnpm agent create "修复某个问题" --category bug --roadmap v1 pnpm agent epic create "大功能" --roadmap v1 --issues 44,45,46 pnpm agent worktree create issue-28 --branch feat/issue-28 + pnpm agent practice list `) } @@ -255,6 +264,36 @@ function handleWorktree(args: string[]): void { } } +function handlePractice(args: string[]): void { + const subCommand = args[0] + + switch (subCommand) { + case 'list': + listPractices() + break + + case 'add': + addPractice(args.slice(1).join(' ')) + break + + case 'remove': + removePractice(args.slice(1).join(' ')) + break + + case 'update': { + const index = args[1] + const text = args.slice(2).join(' ') + updatePractice(index, text) + break + } + + default: + log.error(`未知的 practice 子命令: ${subCommand}`) + console.log('可用命令: list, add, remove, update') + process.exit(1) + } +} + function main(): void { const args = process.argv.slice(2) @@ -344,6 +383,10 @@ function main(): void { handleWorktree(rest) break + case 'practice': + handlePractice(rest) + break + case 'help': log.error('请使用 --help 查看帮助') printHelp() diff --git a/scripts/agent/practice.ts b/scripts/agent/practice.ts new file mode 100644 index 00000000..05a6ca6f --- /dev/null +++ b/scripts/agent/practice.ts @@ -0,0 +1,162 @@ +/** + * 最佳实践管理 + */ + +import { readFileSync, writeFileSync, existsSync } from 'node:fs' +import { BEST_PRACTICES_FILE, log } from './utils' + +interface PracticeDocument { + headerLines: string[] + items: string[] + footerLines: string[] +} + +function readDocument(): PracticeDocument { + if (!existsSync(BEST_PRACTICES_FILE)) { + log.error(`最佳实践文件不存在: ${BEST_PRACTICES_FILE}`) + process.exit(1) + } + + const raw = readFileSync(BEST_PRACTICES_FILE, 'utf-8') + const lines = raw.split('\n') + const listIndex = lines.findIndex(line => line.trim() === '## 列表') + + if (listIndex === -1) { + log.error('最佳实践文件缺少 "## 列表" 标记') + process.exit(1) + } + + const headerLines = lines.slice(0, listIndex + 1) + const itemLines: string[] = [] + const footerLines: string[] = [] + + let inItems = true + for (let i = listIndex + 1; i < lines.length; i += 1) { + const line = lines[i] + if (inItems) { + if (line.startsWith('## ') && line.trim() !== '## 列表') { + inItems = false + footerLines.push(line) + continue + } + if (line.trim().startsWith('- ')) { + itemLines.push(line.trim().slice(2)) + continue + } + if (line.trim().length === 0) { + continue + } + itemLines.push(line.trim()) + continue + } + footerLines.push(line) + } + + return { + headerLines, + items: itemLines, + footerLines, + } +} + +function writeDocument(doc: PracticeDocument): void { + const lines = [...doc.headerLines] + lines.push('') + for (const item of doc.items) { + lines.push(`- ${item}`) + } + if (doc.footerLines.length > 0) { + lines.push('') + lines.push(...doc.footerLines) + } + const content = lines.join('\n').trimEnd() + '\n' + writeFileSync(BEST_PRACTICES_FILE, content) +} + +export function listPractices(): void { + const doc = readDocument() + if (doc.items.length === 0) { + console.log('暂无最佳实践') + return + } + console.log('# 最佳实践\n') + doc.items.forEach((item, index) => { + console.log(`${index + 1}. ${item}`) + }) + console.log() +} + +export function addPractice(text?: string): void { + const value = text?.trim() + if (!value) { + log.error('请提供要添加的最佳实践文本') + process.exit(1) + } + const doc = readDocument() + doc.items.push(value) + writeDocument(doc) + log.success('已添加最佳实践') +} + +export function removePractice(target?: string): void { + const value = target?.trim() + if (!value) { + log.error('请提供要删除的序号或文本') + process.exit(1) + } + + const doc = readDocument() + const index = Number.parseInt(value, 10) + if (!Number.isNaN(index)) { + if (index < 1 || index > doc.items.length) { + log.error(`序号超出范围: ${index}`) + process.exit(1) + } + doc.items.splice(index - 1, 1) + writeDocument(doc) + log.success('已删除最佳实践') + return + } + + const matchIndex = doc.items.findIndex(item => item === value) + if (matchIndex === -1) { + log.error('未找到匹配的最佳实践') + process.exit(1) + } + doc.items.splice(matchIndex, 1) + writeDocument(doc) + log.success('已删除最佳实践') +} + +export function updatePractice(indexText?: string, text?: string): void { + const indexValue = indexText?.trim() + const value = text?.trim() + if (!indexValue || !value) { + log.error('请提供序号与新的最佳实践文本') + process.exit(1) + } + + const index = Number.parseInt(indexValue, 10) + if (Number.isNaN(index)) { + log.error('序号必须是数字') + process.exit(1) + } + + const doc = readDocument() + if (index < 1 || index > doc.items.length) { + log.error(`序号超出范围: ${index}`) + process.exit(1) + } + + doc.items[index - 1] = value + writeDocument(doc) + log.success('已更新最佳实践') +} + +export function printBestPracticesContent(): void { + if (!existsSync(BEST_PRACTICES_FILE)) { + log.warn(`最佳实践文件缺失: ${BEST_PRACTICES_FILE}`) + return + } + console.log(readFileSync(BEST_PRACTICES_FILE, 'utf-8')) +} diff --git a/scripts/agent/readme.ts b/scripts/agent/readme.ts index 77c3996e..7cec6347 100644 --- a/scripts/agent/readme.ts +++ b/scripts/agent/readme.ts @@ -4,21 +4,11 @@ import { fetchRoadmap, printStats } from './roadmap' import { resolveRelease } from './utils' +import { printBestPracticesContent } from './practice' export function printBestPractices(): void { - console.log(` -# 最佳实践 - -❌ Radix Dialog / position:fixed → ✅ Stackflow BottomSheet/Modal -❌ React Router → ✅ Stackflow push/pop/replace -❌ 复制 mpay 代码 → ✅ 理解后用 React/TS 重写 -❌ 随意创建 store → ✅ 遵循 stores/ 现有模式 -❌ 明文选择器 → ✅ data-testid -❌ 安装新 UI 库 → ✅ shadcn/ui(已集成) -❌ 新建 CSS → ✅ Tailwind CSS - -详见: pnpm agent chapter 00-必读 -`) + printBestPracticesContent() + console.log('详见: pnpm agent chapter 00-必读\n') } export function printKnowledgeMap(): void { @@ -89,6 +79,7 @@ export function printWorkflow(): void { # 工作流 pnpm agent readme 启动入口(索引 + 知识地图 + 最佳实践) +pnpm agent practice list 最佳实践列表 pnpm agent claim <#> 领取任务 (自动分配+worktree指引) pnpm agent create "x" 创建任务 (--category bug --roadmap v1) pnpm agent epic create "x" 创建 Epic (--roadmap v1) diff --git a/scripts/agent/utils.ts b/scripts/agent/utils.ts index 4a42a006..3ca58bed 100644 --- a/scripts/agent/utils.ts +++ b/scripts/agent/utils.ts @@ -14,6 +14,7 @@ export const WORKTREE_DIR = (() => { } return resolve(ROOT, '.git-worktree') })() +export const BEST_PRACTICES_FILE = resolve(WHITE_BOOK_DIR, '00-必读', 'best-practices.md') export const PROJECT_NUMBER = 5 export const PROJECT_OWNER = 'BioforestChain' From 8b70107f384e1fffe65bf5f9a0233f20c6816d8a Mon Sep 17 00:00:00 2001 From: Gaubee Date: Thu, 25 Dec 2025 08:55:57 +0800 Subject: [PATCH 2/2] fix(agent): default practice list --- scripts/agent/cli.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/agent/cli.ts b/scripts/agent/cli.ts index c64bdd5e..e1c06a3c 100644 --- a/scripts/agent/cli.ts +++ b/scripts/agent/cli.ts @@ -267,6 +267,16 @@ function handleWorktree(args: string[]): void { function handlePractice(args: string[]): void { const subCommand = args[0] + if (!subCommand) { + listPractices() + return + } + + if (subCommand === '--help' || subCommand === '-h') { + console.log('用法: pnpm agent practice list|add|remove|update') + return + } + switch (subCommand) { case 'list': listPractices()