
Workhub
- 11 installs
- 17 repo stars
- Updated July 25, 2026
- dwsy/agent
Manages project docs and tasks under a Single-Source-of-Truth model using GitHub-style Issues and PRs so documentation stays consistent and authoritative.
About
workhub is a documentation and task-tracking skill that enforces a Single Source of Truth using GitHub-style Issues and PR workflows. A solo builder reaches for it to keep project docs, decisions and open work organized in one authoritative place instead of scattering them across notes and chats.
- Single Source of Truth enforcement
- GitHub-style Issues and PRs workflow
- Centralized documentation management
- Standardized doc structure
Workhub by the numbers
- 11 all-time installs (skills.sh)
- Ranked #2,174 of 3,280 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dwsy/agent --skill workhubAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 11 |
|---|---|
| repo stars | ★ 17 |
| Last updated | July 25, 2026 |
| Repository | dwsy/agent ↗ |
What it does
Manages project docs and tasks under a Single-Source-of-Truth model using GitHub-style Issues and PRs so documentation stays consistent and authoritative.
Who is it for?
solo builders wanting organized docs and tasks
Skip if: heavy team PM suites
Files
Workhub
文档管理与任务跟踪工具,强制执行 SSOT(Single Source of Truth)原则,支持 GitHub 风格的 Issues 和 PRs 工作流。
执行环境
| 路径类型 | 路径 | 基准目录 |
|---|---|---|
| 技能目录 | ~/.pi/agent/skills/workhub/ | 固定位置 |
| 主脚本 | ~/.pi/agent/skills/workhub/lib.ts | 技能目录 |
| 项目文档目录 | ./docs/ | 工作目录 (执行命令时的当前目录) |
标准文档结构
docs/
├── adr/ # 架构决策记录
├── architecture/ # 架构设计文档
├── issues/ # 任务跟踪
│ ├── [模块分类]/ # 可选:按模块分类
│ │ └── yyyymmdd-[描述].md
│ └── yyyymmdd-[描述].md
├── pr/ # 变更记录
│ ├── [模块分类]/
│ │ └── yyyymmdd-[描述].md
│ └── yyyymmdd-[描述].md
└── guides/ # 使用指南调用命令
# 正确方式:从项目目录执行
cd /path/to/your/project
~/.pi/agent/skills/workhub/lib.ts <command>文档操作
1. 初始化 (init)
创建标准文档目录结构。
~/.pi/agent/skills/workhub/lib.ts init2. 查看结构 (tree)
显示文档目录树。
~/.pi/agent/skills/workhub/lib.ts tree3. 审计规范 (audit)
检查 docs/ 文件夹是否遵循标准规范。
~/.pi/agent/skills/workhub/lib.ts audit4. 读取文档 (read)
通过关键词或相对路径读取文档。
~/.pi/agent/skills/workhub/lib.ts read issues/20250106-添加深色模式.md5. 创建 Issue (create issue)
创建新的 Issue 文件,自动使用模板。
~/.pi/agent/skills/workhub/lib.ts create issue "添加深色模式" 前端6. 创建 PR (create pr)
创建新的 PR 文件,自动使用模板。
~/.pi/agent/skills/workhub/lib.ts create pr "修复登录bug" 后端7. 列出 Issues (list issues)
列出所有 Issues 及其状态。
~/.pi/agent/skills/workhub/lib.ts list issues8. 列出 PRs (list prs)
列出所有 PRs 及其状态。
~/.pi/agent/skills/workhub/lib.ts list prs9. 查看状态 (status)
显示所有 Issues 和 PRs 的状态概览。
~/.pi/agent/skills/workhub/lib.ts status10. 搜索内容 (search)
在 Issues 和 PRs 中搜索关键词。
~/.pi/agent/skills/workhub/lib.ts search "深色模式"GitHub 风格工作流
Issue 工作流
1. 创建 Issue 文件 (使用模板)
→ docs/issues/yyyymmdd-[描述].md
或 docs/issues/[模块分类]/yyyymmdd-[描述].md
2. 填写 Goal、Phases、Acceptance Criteria
3. 执行阶段:
- Read Issue 文件(刷新目标)
- 完成子任务 → 更新复选框 [x]
- 遇到错误 → 记录到 "Errors Encountered"
- 记录 Notes → 保存研究发现
4. 完成后创建 PR 文件
→ docs/pr/yyyymmdd-[描述].md
5. PR 文件关联 Issue 文件名
→ 包含回滚计划、测试验证PR 工作流
1. 创建 PR 文件 (使用模板)
→ docs/pr/yyyymmdd-[描述].md
或 docs/pr/[模块分类]/yyyymmdd-[描述].md
2. 填写背景、变更内容、测试验证、回滚计划
3. 关联 Issue 文件名
→ 在 "关联 Issue" 中填写完整路径
4. 代码审查和合并
→ 记录审查日志
→ 更新最终状态核心原则
1. SSOT (Single Source of Truth)
- 每个知识领域只有一个权威文档
- Issues 是任务跟踪的唯一来源
- PRs 是变更记录的唯一来源
2. 文件系统即记忆
- 大输出内容保存到文件,而非堆砌到上下文
- 工作记忆中只保留文件路径
- 需要时通过
workhub read读取
3. 状态管理
- 决策前读取 Issue:刷新目标,保持注意力
- 行动后更新 Issue:标记 [x],更新 Status
- 错误记录:在 Issue 的 "Errors Encountered" 中记录
4. 变更可追溯
- 每个 PR 必须关联 Issue
- Issue 记录完整决策过程
- PR 记录变更细节和回滚计划
最佳实践
创建 Issue
# 1. 初始化文档结构(首次)
~/.pi/agent/skills/workhub/lib.ts init
# 2. 创建 Issue 文件
~/.pi/agent/skills/workhub/lib.ts create issue "添加深色模式" 前端
# 3. 编辑文件,填写 Goal、Phases、Acceptance Criteria执行 Issue
# 1. 读取 Issue(刷新目标)
~/.pi/agent/skills/workhub/lib.ts read issues/前端/20250106-添加深色模式.md
# 2. 完成子任务后更新 Issue
# 编辑文件,标记复选框 [x]
# 3. 遇到错误时记录
# 在 "Errors Encountered" 表格中添加记录创建 PR
# 1. 创建 PR 文件
~/.pi/agent/skills/workhub/lib.ts create pr "添加深色模式" 前端
# 2. 编辑文件,填写变更内容、测试验证、回滚计划
# 3. 关联 Issue 文件名
# 在 "关联 Issue" 中填写完整路径错误恢复模式
# 1. 读取 Issue
~/.pi/agent/skills/workhub/lib.ts read issues/20250106-添加深色模式.md
# 2. 在 "Errors Encountered" 中记录
| 日期 | 错误 | 解决方案 |
| 2025-01-06 | FileNotFoundError | 创建默认配置 |
# 3. 执行解决方案
# 创建默认配置文件
# 4. 更新 Issue 的 NotesQuick Reference
| 命令 | 功能 | 示例 |
|---|---|---|
init | 初始化文档结构 | ~/.pi/agent/skills/workhub/lib.ts init |
tree | 查看文档结构 | ~/.pi/agent/skills/workhub/lib.ts tree |
audit | 审计文档规范 | ~/.pi/agent/skills/workhub/lib.ts audit |
read | 读取文档 | ~/.pi/agent/skills/workhub/lib.ts read issues/xxx.md |
create issue | 创建 Issue | ~/.pi/agent/skills/workhub/lib.ts create issue "描述" [分类] |
create pr | 创建 PR | ~/.pi/agent/skills/workhub/lib.ts create pr "描述" [分类] |
list issues | 列出所有 Issues | ~/.pi/agent/skills/workhub/lib.ts list issues |
list prs | 列出所有 PRs | ~/.pi/agent/skills/workhub/lib.ts list prs |
status | 查看整体状态 | ~/.pi/agent/skills/workhub/lib.ts status |
search | 搜索内容 | ~/.pi/agent/skills/workhub/lib.ts search "关键词" |
扩展计划
未来可能添加的功能:
- 交互式创建 Issue
- 交互式创建 PR
- 关联 Issue 和 PR
import { stat } from "fs/promises";
import { join } from "path";
const REQUIRED_DIRS = ["adr", "architecture", "issues", "pr"];
async function exists(path: string): Promise<boolean> {
try { await stat(path); return true; } catch { return false; }
}
const PURPOSE: Record<string, string> = {
adr: "Architecture Decision Records",
architecture: "System design & boundaries",
issues: "Task tracking (yyyymmdd-[描述].md)",
pr: "Change logs (yyyymmdd-[描述].md)"
};
export async function audit(docsRoot: string) {
console.log(`Auditing docs at: ${docsRoot}\n`);
if (!(await exists(docsRoot))) {
console.error("❌ Critical: 'docs/' directory is missing!");
process.exit(1);
}
let healthy = true;
for (const dir of REQUIRED_DIRS) {
const path = join(docsRoot, dir);
if (await exists(path)) {
console.log(`✅ [OK] ${dir}/`);
} else {
console.log(`❌ [Missing] ${dir}/ (${PURPOSE[dir]})`);
healthy = false;
}
}
console.log(healthy ? "\n✨ Documentation structure is healthy." : "\n⚠️ Needs improvement.");
}
import { stat, mkdir, readFile, writeFile } from "fs/promises";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const TEMPLATES_DIR = join(__dirname, "../templates");
async function exists(path: string): Promise<boolean> {
try { await stat(path); return true; } catch { return false; }
}
function getCurrentDateString(): string {
const now = new Date();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
return `${now.getFullYear()}${month}${day}`;
}
function getISODateString(): string {
const now = new Date();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
return `${now.getFullYear()}-${month}-${day}`;
}
function replace(content: string, date: string, desc: string, cat?: string) {
return content.replace(/{{date}}/g, date).replace(/{{description}}/g, desc).replace(/{{category}}/g, cat || "general");
}
async function readTemplate(name: string) {
const paths = [join(TEMPLATES_DIR, `${name}-updated.md`), join(TEMPLATES_DIR, `${name}.md`)];
for (const p of paths) {
if (await exists(p)) return await readFile(p, "utf-8");
}
throw new Error(`Template ${name} not found`);
}
export async function createIssue(description: string, category?: string) {
if (!description) throw new Error("Description required");
const date = getCurrentDateString();
const filename = `${date}-${description}.md`;
let targetDir = join(process.cwd(), "docs", "issues");
if (category) {
targetDir = join(targetDir, category);
await mkdir(targetDir, { recursive: true });
}
const targetPath = join(targetDir, filename);
if (await exists(targetPath)) throw new Error(`File exists: ${targetPath}`);
const template = await readTemplate("issue-template");
await writeFile(targetPath, replace(template, getISODateString(), description, category));
console.log(`✅ Created issue: ${targetPath}`);
}
export async function createPR(description: string, category?: string) {
if (!description) throw new Error("Description required");
const date = getCurrentDateString();
const filename = `${date}-${description}.md`;
let targetDir = join(process.cwd(), "docs", "pr");
if (category) {
targetDir = join(targetDir, category);
await mkdir(targetDir, { recursive: true });
}
const targetPath = join(targetDir, filename);
if (await exists(targetPath)) throw new Error(`File exists: ${targetPath}`);
const template = await readTemplate("pr-template");
await writeFile(targetPath, replace(template, getISODateString(), description, category));
console.log(`✅ Created PR: ${targetPath}`);
}
import { stat, mkdir } from "fs/promises";
import { join } from "path";
const REQUIRED_DIRS = ["adr", "architecture", "issues", "pr"];
async function exists(path: string): Promise<boolean> {
try { await stat(path); return true; } catch { return false; }
}
export async function init(docsRoot: string) {
console.log(`📦 Initializing docs at: ${docsRoot}\n`);
if (!(await exists(docsRoot))) {
await mkdir(docsRoot, { recursive: true });
console.log(`✅ Created: ${docsRoot}`);
}
for (const dir of REQUIRED_DIRS) {
const path = join(docsRoot, dir);
if (!(await exists(path))) {
await mkdir(path, { recursive: true });
console.log(`✅ Created: ${path}/`);
}
}
console.log("\n✨ Documentation structure initialized!");
}
import { readdir, stat, readFile } from "fs/promises";
import { join } from "path";
async function exists(path: string): Promise<boolean> {
try { await stat(path); return true; } catch { return false; }
}
async function collect(dir: string, type: "issue" | "pr", results: Array<{ path: string; content: string }>) {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith(".")) continue;
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
await collect(fullPath, type, results);
} else if (entry.name.endsWith(".md")) {
results.push({ path: fullPath, content: await readFile(fullPath, "utf-8") });
}
}
}
function extractStatus(content: string) {
return content.match(/状态[::]\s*[📝🚧✅⏸️❌]/) || "📝";
}
export async function listIssues() {
const issuesDir = join(process.cwd(), "docs", "issues");
if (!(await exists(issuesDir))) return console.log("No issues found.");
console.log(`📋 Issues:\n`);
const issues: Array<{ path: string; content: string }> = [];
await collect(issuesDir, "issue", issues);
for (const { path, content } of issues) {
const status = extractStatus(content);
const title = content.match(/^# Issue: (.+)$/m)?.[1] || path;
console.log(` [${status}] ${title}`);
console.log(` → ${path.replace(process.cwd() + "/", "")}\n`);
}
console.log(`Total: ${issues.length} issue(s)`);
}
export async function listPRs() {
const prDir = join(process.cwd(), "docs", "pr");
if (!(await exists(prDir))) return console.log("No PRs found.");
console.log(`🔀 PRs:\n`);
const prs: Array<{ path: string; content: string }> = [];
await collect(prDir, "pr", prs);
for (const { path, content } of prs) {
const status = extractStatus(content);
const title = content.match(/^# (.+)$/m)?.[1] || path;
console.log(` [${status}] ${title}`);
console.log(` → ${path.replace(process.cwd() + "/", "")}\n`);
}
console.log(`Total: ${prs.length} PR(s)`);
}
import { readFile } from "fs/promises";
import { join } from "path";
async function exists(path: string): Promise<boolean> {
try { await readFile(path); return true; } catch { return false; }
}
async function listFiles(dir: string, prefix = "") {
const { readdir, stat } = await import("fs/promises");
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith(".")) continue;
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
await listFiles(fullPath, prefix + entry.name + "/");
} else if (entry.name.endsWith(".md")) {
console.log(` ${prefix}${entry.name}`);
}
}
}
export async function read(target: string) {
const docsRoot = join(process.cwd(), "docs");
const fullPath = join(docsRoot, target);
if (await exists(fullPath)) {
const content = await readFile(fullPath, "utf-8");
console.log(`--- ${target} ---\n`);
console.log(content);
} else {
console.error(`File not found: ${target}`);
console.log(`\nAvailable files:`);
await listFiles(docsRoot);
}
}
import { readdir, stat, readFile } from "fs/promises";
import { join } from "path";
async function exists(path: string): Promise<boolean> {
try { await stat(path); return true; } catch { return false; }
}
async function searchDir(dir: string, type: string, keyword: string, results: Array<{ type: string; path: string; matches: string[] }>) {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith(".")) continue;
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
await searchDir(fullPath, type, keyword, results);
} else if (entry.name.endsWith(".md")) {
const content = await readFile(fullPath, "utf-8");
const relPath = fullPath.replace(process.cwd() + "/docs/", "");
const lines = content.split("\n");
const matches: string[] = [];
lines.forEach((line, i) => {
if (line.toLowerCase().includes(keyword.toLowerCase())) {
matches.push(`:${i + 1}: ${line.trim().substring(0, 100)}`);
}
});
if (matches.length > 0) results.push({ type, path: relPath, matches });
}
}
}
export async function search(keyword: string) {
if (!keyword) throw new Error("Keyword required");
console.log(`🔍 Searching for "${keyword}"...\n`);
const results: Array<{ type: string; path: string; matches: string[] }> = [];
const docsRoot = join(process.cwd(), "docs");
for (const [dir, type] of [["issues", "Issue"], ["pr", "PR"]] as const) {
const path = join(docsRoot, dir);
if (await exists(path)) await searchDir(path, type, keyword, results);
}
if (results.length === 0) {
console.log("No results found.");
} else {
console.log(`Found ${results.length} result(s):\n`);
for (const r of results) {
console.log(`[${r.type}] ${r.path}`);
r.matches.forEach(m => console.log(` ${m}`));
console.log();
}
}
}
import { readdir, stat } from "fs/promises";
import { join } from "path";
async function exists(path: string): Promise<boolean> {
try { await stat(path); return true; } catch { return false; }
}
async function treeRecursive(dir: string, prefix = "") {
const entries = await readdir(dir, { withFileTypes: true });
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
if (entry.name.startsWith(".")) continue;
const isLast = i === entries.length - 1;
const connector = isLast ? "└── " : "├── ";
console.log(`${prefix}${connector}${entry.name}`);
if (entry.isDirectory()) {
await treeRecursive(join(dir, entry.name), prefix + (isLast ? " " : "│ "));
}
}
}
export async function tree(docsRoot: string) {
console.log(`📦 Docs Root: ${docsRoot}`);
if (await exists(docsRoot)) {
await treeRecursive(docsRoot);
}
}
Issue: [标题]
元数据
| 字段 | 内容 |
|---|---|
| 文件名 | yyyymmdd-[描述].md |
| 创建时间 | [YYYY-MM-DD] |
| 状态 | 📝 待办 / 🚧 进行中 / ✅ 已完成 / ⏸️ 已暂停 |
| 优先级 | 🔴 P0 / 🟠 P1 / 🟡 P2 / 🟢 P3 |
| 负责人 | [可选] |
| 预计工时 | [可选] |
Goal
[一句话描述要达成的最终状态]
背景/问题
[描述为什么需要这个任务,当前的问题是什么]
验收标准 (Acceptance Criteria)
- [ ] WHEN [条件],系统 SHALL [行为]
- [ ] WHERE [上下文],系统 SHALL [行为]
- [ ] IF [条件],THEN 系统 SHALL [行为]
实施阶段
Phase 1: 规划和准备
- [ ] 分析需求和依赖
- [ ] 设计技术方案
- [ ] 确定实施计划
Phase 2: 执行
- [ ] [子任务 1]
- [ ] [子任务 2]
- [ ] [子任务 3]
Phase 3: 验证
- [ ] 单元测试
- [ ] 集成测试
- [ ] 代码审查
Phase 4: 交付
- [ ] 更新文档
- [ ] 创建 PR
- [ ] 合并主分支
关键决策
| 决策 | 理由 |
|---|---|
| [决策 1] | [理由] |
| [决策 2] | [理由] |
遇到的错误
| 日期 | 错误 | 解决方案 |
|---|---|---|
| [YYYY-MM-DD] | [错误描述] | [如何解决] |
相关资源
- [ ] 相关文档:
docs/architecture/xxx.md - [ ] 相关 Issue:
docs/issues/ISSUE-xxx.md - [ ] 参考资料: [链接]
Notes
[记录研究过程、临时想法、待确认事项]
---
Status 更新日志
- [YYYY-MM-DD HH:MM]: 状态变更 → [新状态],备注: [变更原因]
Issue: 修复前端构建错误并重新发布
元数据
| 字段 | 内容 |
|---|---|
| 文件名 | 20260107-修复前端构建错误并重新发布.md |
| 创建时间 | 2026-01-07 |
| 状态 | ✅ 已完成 |
| 优先级 | 🔴 P0 |
Goal
修复前端构建错误,清理所有历史构建产物和 release,并重新发布 v6.1 版本。
背景/问题
1. 前端构建失败:TypeScript 类型错误,提示 select_file_dialog 方法在 window.pywebview.api 类型定义中不存在 2. 需要清理所有历史 release 和构建产物 3. 重新发布新版本
验收标准 (Acceptance Criteria)
- [x] WHEN 前端构建执行时,系统 SHALL 成功完成构建无错误
- [x] WHEN TypeScript 类型检查执行时,系统 SHALL 通过所有类型检查
- [x] WHEN 清理历史构建时,系统 SHALL 删除所有 dist、__pycache__、build 目录
- [x] WHEN 清理历史 release 时,系统 SHALL 删除所有 GitHub release 和 tags
- [x] WHEN 重新发布时,系统 SHALL 创建新的 v6.1 tag 和 release
实施阶段
Phase 1: 修复前端构建错误
- [x] 分析构建错误:vite-env.d.ts 缺少 select_file_dialog 类型定义
- [x] 修复类型定义:在 vite-env.d.ts 中添加 select_file_dialog 方法
- [x] 验证构建:npm run build 成功
Phase 2: 清理历史构建产物
- [x] 删除所有 dist 目录(./out/build, ./src/frontend/dist, ./occt-import-js/dist)
- [x] 删除所有 __pycache__ 目录
- [x] 删除 build 目录
- [x] 删除历史 zip 文件(DeepFlyAutoQuote-Windows-x64.zip, project-latest.zip)
Phase 3: 清理 GitHub Release 和 Tags
- [x] 删除所有 GitHub release(v5.0, v5.1, v6.0)
- [x] 删除所有远程 tags
- [x] 删除所有本地 tags
Phase 4: 重新发布
- [x] 提交修复代码到 master 分支
- [x] 推送 master 分支到远程
- [x] 创建 v6.1 tag
- [x] 推送 v6.1 tag 到远程
- [x] 创建 GitHub Release v6.1
关键决策
| 决策 | 理由 |
|---|---|
| 添加 select_file_dialog 类型定义 | 后端 API 已实现该方法,前端类型定义缺失导致构建失败 |
| 删除所有历史 release | 清理历史版本,重新开始版本管理 |
| 创建 v6.1 版本 | 修复了构建错误,需要新版本号 |
遇到的错误
| 日期 | 错误 | 解决方案 |
|---|---|---|
| 2026-01-07 | TS2339: Property 'select_file_dialog' does not exist on type | 在 vite-env.d.ts 中添加 select_file_dialog 方法的类型定义 |
相关资源
- [ ] 相关文档:
docs/architecture/xxx.md - [ ] 相关 Issue: N/A
- [ ] 参考资料: N/A
Notes
- 前端构建成功后生成了 2.7MB 的 JS 文件,建议后续考虑代码分割优化
- 所有历史构建产物已清理干净
- 新版本 v6.1 已成功发布到 GitHub
---
Status 更新日志
- 2026-01-07 12:23: 状态变更 → 🚧 进行中,开始修复构建错误
- 2026-01-07 12:30: 状态变更 → ✅ 已完成,所有任务已完成
PR: 修复前端构建错误并重新发布 v6.1
修复前端 TypeScript 类型错误,清理历史构建产物和 release,重新发布 v6.1 版本
背景与目的 (Why)
前端构建失败,TypeScript 编译器报告 select_file_dialog 方法在 window.pywebview.api 类型定义中不存在。该方法已在后端实现,但前端类型定义文件缺失。同时需要清理所有历史 release 和构建产物,重新开始版本管理。
变更内容概述 (What)
代码变更
- 文件:
src/frontend/src/vite-env.d.ts - 变更: 在
Window.pywebview.api接口中添加select_file_dialog方法类型定义 - 签名:
(title: string, filters: Array<{name: string; extensions: string[]}>) => Promise<{success: boolean; filePath: string | null; message: string}>
清理操作
- 删除所有构建产物目录:
./out/build./src/frontend/dist./occt-import-js/dist./__pycache__./src/backend/__pycache__./src/cad_quote_bot/__pycache__./build- 删除历史发布文件:
out/DeepFlyAutoQuote-Windows-x64.zipproject-latest.zip
GitHub Release 清理
- 删除所有历史 release: v5.0, v5.1, v6.0
- 删除所有远程和本地 tags
重新发布
- 提交修复代码:
c620e287 - 推送到 master 分支
- 创建并推送 v6.1 tag
- 创建 GitHub Release v6.1
关联 Issue 与 ToDo 条目 (Links)
- Issues:
docs/issues/20260107-修复前端构建错误并重新发布.md
测试与验证结果 (Test Result)
- [x] 前端构建成功:
npm run build✓ - [x] TypeScript 类型检查通过:
tsc -b✓ - [x] 生成的构建文件:
dist/index.html(0.41 kB)dist/assets/index-CEh1oKqk.css(0.61 kB)dist/assets/index-C1eztoUY.js(2,735.97 kB)- [x] GitHub Release 创建成功: https://github.com/Dwsy/cad1222/releases/tag/v6.1
风险与影响评估 (Risk Assessment)
风险等级: 🟢 低风险
- 影响范围: 仅影响前端类型定义,不影响运行时逻辑
- 向后兼容: 完全向后兼容,仅添加缺失的类型定义
- 测试覆盖: 构建和类型检查已通过验证
注意事项:
- 前端构建产物较大(2.7MB JS),建议后续考虑代码分割优化
- 所有历史 release 已删除,如需回退需重新创建
回滚方案 (Rollback Plan)
如需回滚,执行以下步骤:
1. 代码回滚:
git revert c620e287
git push origin master2. 版本回退(如需要):
# 删除 v6.1
git tag -d v6.1
git push origin :refs/tags/v6.1
# 重新创建 v6.0
git tag v6.0 55e442b0
git push origin v6.0
# 重新创建 v6.0 release
gh release create v6.0 --notes "..."3. 恢复历史版本(如需要):
- 从之前的备份或 git 历史中恢复构建产物
- 重新构建历史 release
预计回滚时间: 5-10 分钟
import { join } from "path";
import { init } from "./commands/init";
import { tree } from "./commands/tree";
import { audit } from "./commands/audit";
import { read } from "./commands/read";
import { createIssue, createPR } from "./commands/create";
import { listIssues, listPRs } from "./commands/list";
import { search } from "./commands/search";
const DOCS_ROOT = join(process.cwd(), "docs");
const HELP = `
Workhub - Documentation & Task Management
Usage: bun lib.ts <command> [options]
Commands:
init Initialize docs structure
tree Show docs directory tree
audit Audit docs structure
read <file> Read a document file
create issue <desc> [category] Create a new issue
create pr <desc> [category] Create a new PR
list issues List all issues
list prs List all PRs
status Show overall status (issues + PRs)
search <keyword> Search issues and PRs
Examples:
bun lib.ts init
bun lib.ts create issue "添加深色模式" 前端
bun lib.ts create pr "修复登录bug" 后端
bun lib.ts list issues
bun lib.ts status
bun lib.ts search "深色模式"
`;
async function main() {
const [cmd, arg1, arg2, arg3] = process.argv.slice(2);
switch (cmd) {
case "init": await init(DOCS_ROOT); break;
case "tree": await tree(DOCS_ROOT); break;
case "audit": await audit(DOCS_ROOT); break;
case "read": await read(arg1); break;
case "create":
if (arg1 === "issue") await createIssue(arg2, arg3);
else if (arg1 === "pr") await createPR(arg2, arg3);
else { console.error("Usage: create [issue|pr] <desc> [cat]"); process.exit(1); }
break;
case "list":
if (arg1 === "issues") await listIssues();
else if (arg1 === "prs") await listPRs();
else { console.error("Usage: list [issues|prs]"); process.exit(1); }
break;
case "status":
await listIssues();
console.log();
await listPRs();
break;
case "search": await search(arg1); break;
default: console.log(HELP);
}
}
main().catch(e => { console.error(e.message); process.exit(1); });
Workhub 技能简化更新总结
日期: 2025-01-09 版本: v2.1 更新类型: 优化简化
---
📋 更新概述
根据用户反馈,将之前过度繁重的 YAML front matter 简化为最核心的字段,减少约束,提升使用灵活性。
---
✨ 主要变更
1. 简化 YAML Front Matter
将原来包含 30+ 字段的复杂元数据简化为仅 7 个核心字段:
Issue 元数据(简化后)
---
id: "2025-01-09-添加深色模式"
title: "[标题]"
status: "todo"
created: "2025-01-09"
updated: "2025-01-09"
category: "前端"
tags: ["workhub", "添加深色模式"]
---PR 元数据(简化后)
---
id: "2025-01-09-修复登录bug"
title: "[Pull Request 标题]"
status: "draft"
created: "2025-01-09"
updated: "2025-01-09"
category: "后端"
tags: ["workhub", "pr", "修复登录bug"]
---2. 移除的字段
移除的 Issue 字段:
- ❌ type(类型)
- ❌ priority(优先级)
- ❌ labels(标签数组)
- ❌ due_date(截止日期)
- ❌ estimated_hours(预估工时)
- ❌ assignees(负责人)
- ❌ reviewers(审查人)
- ❌ reporter(报告人)
- ❌ contributors(贡献者)
- ❌ related_issues(相关 Issue)
- ❌ blocked_by(被阻塞)
- ❌ blocks(阻塞)
- ❌ project(项目)
- ❌ milestone(里程碑)
- ❌ sprint(迭代周期)
- ❌ story_points(故事点数)
- ❌ complexity(复杂度)
- ❌ effort(工作量)
- ❌ risk_level(风险级别)
- ❌ dependencies(依赖项)
- ❌ created_by_ai(AI 创建标记)
- ❌ last_updated_by_ai(AI 更新标记)
- ❌ version(版本号)
移除的 PR 字段:
- ❌ type(类型)
- ❌ labels(标签数组)
- ❌ merged_at(合并时间)
- ❌ closed_at(关闭时间)
- ❌ author(作者)
- ❌ reviewers(审查人)
- ❌ assignees(负责人)
- ❌ related_prs(相关 PR)
- ❌ related_issues(关联 Issue)
- ❌ branch_from(源分支)
- ❌ branch_to(目标分支)
- ❌ project(项目)
- ❌ milestone(里程碑)
- ❌ linked_issues(链接 Issue)
- ❌ change_type(变更类型)
- ❌ size(变更规模)
- ❌ complexity(复杂度)
- ❌ risk_level(风险级别)
- ❌ created_by_ai(AI 创建标记)
- ❌ last_updated_by_ai(AI 更新标记)
- ❌ version(版本号)
- ❌ files_changed(文件变更数量)
- ❌ additions(新增行数)
- ❌ deletions(删除行数)
- ❌ commits(提交次数)
3. 保留的核心字段
| 字段 | 说明 | 自动生成 |
|---|---|---|
id | 唯一标识 | ✅ |
title | 标题 | ❌(用户填写) |
status | 状态 | ❌(用户填写) |
created | 创建时间 | ✅ |
updated | 更新时间 | ✅ |
category | 分类 | ✅ |
tags | 标签 | ✅ |
---
🎯 设计原则
1. 最小化原则
只保留最核心的元数据,避免过度设计。
2. 灵活性原则
用户可以根据需要在文档正文中添加任何额外信息,不受模板约束。
3. 实用性原则
保留的字段都是实际使用中最频繁需要的。
4. 可扩展性原则
如果需要更多字段,用户可以轻松在 YAML front matter 中添加。
---
📊 对比分析
之前(v2.0)- 过度繁重
优点:
- 信息完整
- 结构化程度高
- 支持复杂查询
缺点:
- ❌ 字段过多(30+)
- ❌ 约束太强
- ❌ 填写负担重
- ❌ 视觉干扰大
- ❌ 实际使用中很多字段用不到
现在(v2.1)- 简洁高效
优点:
- ✅ 字段精简(7个)
- ✅ 约束少,灵活度高
- ✅ 填写负担低
- ✅ 视觉清晰
- ✅ 覆盖核心需求
- ✅ 便于扩展
缺点:
- 一些高级查询功能需要额外实现
- 需要在文档正文中记录某些元数据
---
🚀 使用示例
# 创建 Issue
bun ~/.pi/agent/skills/workhub/lib.ts create issue "添加深色模式" 前端
# 创建 PR
bun ~/.pi/agent/skills/workhub/lib.ts create pr "修复登录bug" 后端生成的文件:
---
id: "2025-01-09-添加深色模式"
title: "[标题]"
status: "todo"
created: "2025-01-09"
updated: "2025-01-09"
category: "前端"
tags: ["workhub", "添加深色模式"]
------
📝 文件变更
更新的文件
1. `~/.pi/agent/skills/workhub/templates/issue-template.md`
- 简化 YAML front matter 为 7 个核心字段
- 保持正文内容不变
2. `~/.pi/agent/skills/workhub/templates/pr-template.md`
- 简化 YAML front matter 为 7 个核心字段
- 保持正文内容不变
3. `~/.pi/agent/skills/workhub/SKILL.md`
- 更新元数据字段说明
- 更新模板结构示例
未变更的文件
- `~/.pi/agent/skills/workhub/lib.ts`: 代码逻辑无需改动
- `~/.pi/agent/skills/workhub/lib.ts.backup`: 备份文件
---
✅ 测试验证
测试结果
1. ✅ 初始化文档结构成功 2. ✅ 创建 Issue 成功,简化版 YAML front matter 正确生成 3. ✅ 创建 PR 成功,简化版 YAML front matter 正确生成 4. ✅ 占位符替换正确 5. ✅ 自动生成标签正确 6. ✅ 模板结构清晰,无冗余信息
生成的文件示例
Issue 文件:
---
id: "2026-01-09-简化测试"
title: "[标题]"
status: "todo"
created: "2026-01-09"
updated: "2026-01-09"
category: "前端"
tags: ["workhub", "简化测试"]
---
# Issue: [标题]
## Goal
...PR 文件:
---
id: "2026-01-09-简化PR测试"
title: "[Pull Request 标题]"
status: "draft"
created: "2026-01-09"
updated: "2026-01-09"
category: "后端"
tags: ["workhub", "pr", "简化PR测试"]
---
# [Pull Request 标题]
...---
🔄 向后兼容性
- ✅ 完全向后兼容
- ✅ 现有文件不受影响
- ✅ 新创建的文件使用简化模板
- ✅ 用户可以手动将旧文件更新为简化格式(可选)
---
💡 使用建议
1. 如何添加额外元数据
如果需要记录更多元数据,可以直接在 YAML front matter 中添加:
---
id: "2025-01-09-添加深色模式"
title: "添加深色模式"
status: "todo"
created: "2025-01-09"
updated: "2025-01-09"
category: "前端"
tags: ["workhub", "添加深色模式"]
priority: "high" # 自定义字段
assignee: "John Doe" # 自定义字段
estimated_hours: 8 # 自定义字段
---2. 如何在正文中记录信息
将一些次重要的信息记录在文档正文中:
## 元数据
- **优先级**: P0
- **负责人**: John Doe
- **预估工时**: 8 小时
- **截止日期**: 2025-01-15
## Goal
...3. 如何扩展标签
tags 字段是数组,可以添加更多标签:
tags: ["workhub", "添加深色模式", "ui", "feature", "high-priority"]---
📚 相关文档
- `~/.pi/agent/skills/workhub/SKILL.md`: 完整的技能文档
- `~/.pi/agent/skills/workhub/templates/issue-template.md`: Issue 模板
- `~/.pi/agent/skills/workhub/templates/pr-template.md`: PR 模板
- `~/.pi/agent/skills/workhub/UPDATE_SUMMARY.md`: v2.0 更新总结
---
🎉 总结
本次简化更新显著提升了 workhub 技能的可用性:
1. 减少约束:从 30+ 字段减少到 7 个核心字段 2. 提升灵活性:用户可以根据需要自由扩展 3. 降低负担:减少填写负担,提高使用效率 4. 保持核心:保留最核心的元数据,满足基本需求 5. 易于扩展:支持用户自定义添加额外字段
这个简化版本更适合实际使用场景,平衡了结构化和灵活性。
---
📈 版本历史
- v1.0: 初始版本,无 YAML front matter
- v2.0: 添加详细的 YAML front matter(30+ 字段)
- v2.1: 简化 YAML front matter(7 个核心字段)← 当前版本
Issue: [标题]
Goal
[一句话描述要达成的最终状态]
背景/问题
[描述为什么需要这个任务,当前的问题是什么]
验收标准 (Acceptance Criteria)
- [ ] WHEN [条件],系统 SHALL [行为]
- [ ] WHERE [上下文],系统 SHALL [行为]
- [ ] IF [条件],THEN 系统 SHALL [行为]
实施阶段
Phase 1: 规划和准备
- [ ] 分析需求和依赖
- [ ] 设计技术方案
- [ ] 确定实施计划
Phase 2: 执行
- [ ] [子任务 1]
- [ ] [子任务 2]
- [ ] [子任务 3]
Phase 3: 验证
- [ ] 单元测试
- [ ] 集成测试
- [ ] 代码审查
Phase 4: 交付
- [ ] 更新文档
- [ ] 创建 PR
- [ ] 合并主分支
关键决策
| 决策 | 理由 |
|---|---|
| [决策 1] | [理由] |
| [决策 2] | [理由] |
遇到的错误
| 日期 | 错误 | 解决方案 |
|---|---|---|
| [YYYY-MM-DD] | [错误描述] | [如何解决] |
相关资源
- [ ] 相关文档:
docs/architecture/xxx.md - [ ] 相关 Issue:
docs/issues/ISSUE-xxx.md - [ ] 参考资料: [链接]
Notes
[记录研究过程、临时想法、待确认事项]
---
Status 更新日志
- [YYYY-MM-DD HH:MM]: 状态变更 → [新状态],备注: [变更原因]
[Pull Request 标题]
简明扼要描述本次变更的核心目的
背景与目的 (Why)
<!-- 说明为什么要进行本次变更,关联的业务背景或技术原因 -->
变更内容概述 (What)
<!-- 列出主要修改点 -->
关联 Issue
- Issues:
docs/issues/yyyymmdd-[描述].md
测试与验证结果 (Test Result)
- [ ] 单元测试通过
- [ ] 集成测试验证
- [ ] 手动回归测试通过
风险与影响评估 (Risk Assessment)
<!-- 说明可能的风险点、影响范围 -->
回滚方案 (Rollback Plan)
<!-- 如果出现问题,如何快速回退到稳定版本 -->
---
变更类型
- [ ] 🐛 Bug Fix
- [ ] ✨ New Feature
- [ ] 📝 Documentation
- [ ] 🚀 Refactoring
- [ ] ⚡ Performance
- [ ] 🔒 Security
- [ ] 🧪 Testing
文件变更列表
| 文件 | 变更类型 | 描述 |
|---|---|---|
src/xxx.ts | 修改 | [描述] |
docs/yyy.md | 新增 | [描述] |
tests/zzz.test.ts | 新增 | [描述] |
详细变更说明
1. [变更点 1]
问题: [解决了什么问题]
方案: [如何解决的]
影响范围: [哪些模块/功能受影响]
2. [变更点 2]
[重复上述结构]
测试命令
# 运行单元测试
bun test
# 运行集成测试
bun test:integration破坏性变更
是否有破坏性变更?
- [ ] 否
- [ ] 是 - [描述破坏性变更及迁移指南]
性能影响
是否有性能影响?
- [ ] 无影响
- [ ] 提升 - [描述性能提升]
- [ ] 下降 - [描述性能下降及原因]
依赖变更
是否引入新的依赖?
- [ ] 否
- [ ] 是 - [列出新增依赖及理由]
安全考虑
是否有安全影响?
- [ ] 否
- [ ] 是 - [描述安全影响及缓解措施]
文档变更
是否需要更新文档?
- [ ] 否
- [ ] 是 - [列出需要更新的文档]
代码审查检查清单
功能性
- [ ] 代码实现了需求
- [ ] 边界情况已处理
- [ ] 错误处理完善
代码质量
- [ ] 代码遵循项目规范
- [ ] 变量命名清晰
- [ ] 没有冗余代码
测试
- [ ] 有对应的单元测试
- [ ] 测试覆盖关键路径
- [ ] 测试通过
审查日志
- [YYYY-MM-DD HH:MM] [审查人]: [审查意见]
- [ ] 问题 1: [描述]
- [ ] 建议 1: [描述]
- [YYYY-MM-DD HH:MM] [作者]: [回应]
- 已解决问题 1: [说明]
最终状态
- 合并时间: [YYYY-MM-DD HH:MM]
- 合并人: [姓名]
- Commit Hash: [hash]
- 部署状态: [待部署 / 已部署]
Workhub 技能更新总结
日期: 2025-01-09 版本: v2.0 更新类型: 功能增强 + 优化
---
📋 更新概述
本次更新为 workhub 技能添加了 YAML front matter 元数据支持,并优化了模板结构,移除了冗余信息。
---
✨ 新功能
1. YAML Front Matter 元数据
所有 Issue 和 PR 文件现在在顶部包含详细的 YAML front matter,包含以下信息:
Issue 元数据字段
| 分类 | 字段 | 说明 |
|---|---|---|
| 基础信息 | id, title, type, status, priority, labels | 唯一标识、标题、类型、状态、优先级、标签 |
| 时间信息 | created, updated, due_date, estimated_hours | 创建时间、更新时间、截止日期、预估工时 |
| 人员信息 | assignees, reviewers, reporter, contributors | 负责人、审查人、报告人、贡献者 |
| 分类和关联 | category, tags, related_issues, blocked_by, blocks | 分类、标签、相关 Issue、阻塞关系 |
| 业务信息 | project, milestone, sprint, story_points | 项目、里程碑、迭代周期、故事点数 |
| 技术信息 | complexity, effort, risk_level, dependencies | 复杂度、工作量、风险级别、依赖项 |
| 指标 | created_by_ai, last_updated_by_ai, version | AI 创建标记、版本号 |
PR 元数据字段
| 分类 | 字段 | 说明 |
|---|---|---|
| 基础信息 | id, title, type, status, labels | 唯一标识、标题、类型、状态、标签 |
| 时间信息 | created, updated, merged_at, closed_at | 创建时间、更新时间、合并时间、关闭时间 |
| 人员信息 | author, reviewers, assignees | 作者、审查人、负责人 |
| 分类和关联 | category, tags, related_prs, related_issues, branch_from, branch_to | 分类、标签、关联关系、分支信息 |
| 业务信息 | project, milestone, linked_issues | 项目、里程碑、链接 Issue |
| 技术信息 | change_type, size, complexity, risk_level | 变更类型、规模、复杂度、风险级别 |
| 指标 | created_by_ai, last_updated_by_ai, version, files_changed, additions, deletions, commits | AI 创建标记、版本号、代码变更统计 |
2. 动态占位符替换
模板支持以下占位符,在创建文件时自动替换:
{{date}}: 当前日期 (格式: yyyy-mm-dd){{description}}: 文件描述{{category}}: 分类(前端/后端/数据库/运维等)
3. 自动生成字段
以下字段由系统自动生成,无需手动填写:
id: 唯一标识 (格式: yyyy-mm-dd-描述)created: 创建时间updated: 更新时间labels: 自动生成的标签列表category: 自动添加分类标签tags: 自动添加描述标签created_by_ai: AI 创建标记last_updated_by_ai: AI 更新标记version: 版本号
---
🎯 优化内容
1. 简化模板结构
移除了 Issue 和 PR 模板中与 YAML front matter 重复的元数据表格:
- ❌ 移除 Issue 的"元数据"表格(文件名、创建时间、状态、优先级、负责人、预计工时)
- ❌ 移除 PR 的"元数据"表格(文件名、创建时间、状态、类型、审查人)
这些信息现在统一在 YAML front matter 中管理,遵循 SSOT 原则。
2. 保持核心内容
保留了以下关键内容部分:
Issue 保留内容
- Goal(目标)
- 背景/问题
- 验收标准
- 实施阶段
- 关键决策
- 遇到的错误
- 相关资源
- Notes
- Status 更新日志
PR 保留内容
- 背景与目的
- 变更内容概述
- 关联 Issue 与 ToDo 条目
- 测试与验证结果
- 风险与影响评估
- 回滚方案
- 变更类型
- 文件变更列表
- 详细变更说明
- 测试命令和输出
- 破坏性变更
- 性能影响
- 依赖变更
- 安全考虑
- 文档变更
- 代码审查检查清单
- 审查日志
- 最终状态
---
🚀 使用方式
创建 Issue
# 基本用法
bun ~/.pi/agent/skills/workhub/lib.ts create issue "添加深色模式"
# 带分类
bun ~/.pi/agent/skills/workhub/lib.ts create issue "添加深色模式" 前端生成的文件包含:
---
# 基础信息
id: "2025-01-09-添加深色模式"
title: "[标题]"
type: "task"
status: "todo"
priority: "medium"
labels:
- "area:前端"
- "type:task"
- "status:todo"
# 时间信息
created: "2025-01-09"
updated: "2025-01-09"
due_date: ""
estimated_hours: ""
# ... 其他元数据
---创建 PR
# 基本用法
bun ~/.pi/agent/skills/workhub/lib.ts create pr "修复登录bug"
# 带分类
bun ~/.pi/agent/skills/workhub/lib.ts create pr "修复登录bug" 后端生成的文件包含:
---
# 基础信息
id: "2025-01-09-修复登录bug"
title: "[Pull Request 标题]"
type: "change"
status: "draft"
labels:
- "area:后端"
- "type:change"
- "status:draft"
# 时间信息
created: "2025-01-09"
updated: "2025-01-09"
merged_at: ""
closed_at: ""
# ... 其他元数据
------
📊 AI 索引优势
添加 YAML front matter 后,AI 可以:
1. 快速检索:通过标签、类型、状态、优先级等字段快速过滤 2. 智能关联:自动识别相关 Issue 和 PR 之间的依赖关系 3. 统计分析:按时间、分类、状态等维度生成报告 4. 自动化流程:根据状态自动触发后续流程 5. 知识管理:构建结构化的项目知识库
示例查询
# 查找所有高优先级的 Issue
# 查询: priority: "critical" OR priority: "high"
# 查找所有进行中的前端任务
# 查询: category: "前端" AND status: "in-progress"
# 查找所有已合并的 PR
# 查询: status: "merged"
# 查找被阻塞的 Issue
# 查询: blocked_by.length > 0
# 查找某个作者的所有 PR
# 查询: author: "John Doe"---
🔧 技术实现
1. 动态日期生成
function getCurrentDateString(): string {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
return `${year}${month}${day}`;
}
function getISODateString(): string {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}2. 占位符替换
function replaceTemplatePlaceholders(
content: string,
date: string,
description: string,
category?: string
): string {
return content
.replace(/{{date}}/g, date)
.replace(/{{description}}/g, description || "description")
.replace(/{{category}}/g, category || "general");
}3. 文件创建流程
1. 生成文件名(使用 getCurrentDateString()) 2. 读取模板文件 3. 替换占位符(使用 replaceTemplatePlaceholders()) 4. 写入目标文件
---
📝 文件变更
更新的文件
1. `~/.pi/agent/skills/workhub/lib.ts`
- 添加日期生成函数
- 添加占位符替换函数
- 更新
createIssue()函数以支持动态替换 - 更新
createPR()函数以支持动态替换
2. `~/.pi/agent/skills/workhub/templates/issue-template.md`
- 添加 YAML front matter
- 移除冗余的元数据表格
3. `~/.pi/agent/skills/workhub/templates/pr-template.md`
- 添加 YAML front matter
- 移除冗余的元数据表格
4. `~/.pi/agent/skills/workhub/SKILL.md`
- 添加 YAML front matter 字段说明
- 添加 AI 索引优势说明
- 更新模板结构示例
备份文件
- `~/.pi/agent/skills/workhub/lib.ts.backup`: 原始 lib.ts 文件备份
---
✅ 测试验证
测试环境
- 临时目录:
/tmp/test-workhub - 测试命令: 使用
bun运行 TypeScript
测试结果
1. ✅ 初始化文档结构成功 2. ✅ 创建 Issue 成功,YAML front matter 正确生成 3. ✅ 创建 PR 成功,YAML front matter 正确生成 4. ✅ 占位符替换正确(日期、描述、分类) 5. ✅ 自动生成标签正确 6. ✅ 模板简化成功,移除冗余内容
---
🔄 向后兼容性
兼容性说明
- ✅ 完全向后兼容
- ✅ 现有的 Issue 和 PR 文件仍然可以正常使用
- ✅ 新创建的文件自动使用新的 YAML front matter
- ✅ 旧的文件可以手动添加 YAML front matter(可选)
迁移建议
对于现有的 Issue 和 PR 文件,可以选择:
1. 保持原样:旧文件继续使用旧格式 2. 手动迁移:在旧文件顶部添加 YAML front matter 3. 逐步迁移:创建新文件时自动使用新格式,旧文件在编辑时迁移
---
📚 相关文档
- `~/.pi/agent/skills/workhub/SKILL.md`: 完整的技能文档
- `~/.pi/agent/skills/workhub/templates/issue-template.md`: Issue 模板
- `~/.pi/agent/skills/workhub/templates/pr-template.md`: PR 模板
- `~/.pi/agent/skills/workhub/lib.ts`: 主脚本文件
---
🎉 总结
本次更新显著提升了 workhub 技能的功能性和可用性:
1. 结构化元数据:通过 YAML front matter 提供丰富的元数据支持 2. AI 索引优化:便于 AI 快速检索、关联和统计分析 3. 模板简化:移除冗余内容,遵循 SSOT 原则 4. 动态生成:自动填充时间、标签等字段,减少手动输入 5. 向后兼容:不影响现有文件的使用
这些改进使得 workhub 更适合作为项目文档管理和任务跟踪的工具,特别是在 AI 辅助开发的场景下。