diff --git a/AGENTS.md b/AGENTS.md index 947db98..e88dc02 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,7 @@ 可用工具:`list_components` / `get_component` / `search_components`。 -2. **CLI**:`node packages/tools/cli/bin/ua.js list | info | index | docs | style | verify` +2. **CLI**:`node packages/tools/cli/bin/ua.js list | info | index | docs | style | verify | changelog` 3. **静态索引**:`.ua/index.json`(机器可读索引)、`llms.txt`(速览)或 **`llms-full.txt`(全量 Agent 文档:逐组件参数 / 回调 / 手把手步骤 / 令牌,无图形纯文本,喂给 Agent 首选)**。 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8c06ae1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,114 @@ +# 变更日志 + +> 由 `ua changelog` 依据 git 提交史生成,请勿手改;条目按提交时间倒序。 + +## 迭代 + +- `b3c3bc7` iter(g14): 演示站目录支持关键字过滤 +- `1b75fb4` iter(g12): verify 增加 backlog 与留痕交叉校验 +- `2f8ccb6` iter(g10): 新增 statistic 统计数值组件 +- `d8d45fc` iter(g09): 新增 descriptions 描述列表组件 +- `0e385cd` iter(g08): 新增 segmented 分段控制器组件 +- `db96a30` iter(g07): 新增 timeline 时间线组件 +- `b6c9489` iter(g06): 组件数门禁覆盖 README +- `9651c39` iter(g05): verify 增加 llms-full 同步校验 +- `c0bb8d7` iter(g04): dataTable 筛选框加搜索图标前缀 +- `bfa7013` iter(g03): 输入组件补 prefix/suffix 附加块 +- `33979b2` iter(g02): 新增 image 图片组件 +- `98f557c` iter(g01): ua docs 幂等化防时间戳弄脏工作区 +- `a5439fe` iter(f06): 锁文件入库并补全目录树 +- `265060f` iter(f05): index 幂等化防时间戳弄脏工作区 +- `99ce0cd` iter(f04): commit-lint 收严强制 scope +- `f57da4c` iter(f03): 新增留痕格式门禁 lint-iterations +- `f2fc286` iter(f02): check 链描述补 verify 第六步 +- `c19f83b` iter(f01): 组件数漂移纳入 verify 门禁并修正文档 +- `c457e0c` iter(e05): 新增 divider 分隔线组件 +- `fd4ee01` iter(e04): 新增 empty 空状态组件 +- `ee20322` iter(e03): 新增 rate 评分组件 + +## 功能 + +- `7072f77` feat(cli): 新增 commit-lint 提交信息校验 + +## 文档 + +- `dc4bac4` docs: 同步提交规范到 AGENTS/ITERATION/cli 清单 + +## 维护 + +- `3161340` chore(backlog): 记录 g14 完成 +- `4ffc654` chore(backlog): 记录 g12 完成 +- `07b9b75` chore(backlog): 记录 g10 完成 +- `cf65939` chore(backlog): 记录 g09 完成 +- `086831d` chore(backlog): 记录 g08 完成 +- `7cf1f28` chore(backlog): 记录 g07 完成 +- `511a390` chore(backlog): 记录 g06 完成 +- `8d439f0` chore(backlog): 记录 g05 完成 +- `86c72f7` chore(backlog): 记录 g04 完成 +- `5131977` chore(backlog): 记录 g03 完成 +- `d5ac26a` chore(backlog): 记录 g02 完成 +- `0c42c6f` chore(backlog): 记录 g01 完成 +- `7ce8bf7` chore(backlog): 记录 f06 完成 +- `35c9f00` chore(backlog): 记录 f05 完成 +- `fbe0348` chore(backlog): 记录 f04 完成 +- `f1363e8` chore(backlog): 记录 f03 完成 +- `3fb3cd2` chore(backlog): 记录 f02 完成 +- `b9b05f5` chore(backlog): 记录 f01 完成 +- `67374c7` chore(backlog): 灌入审计产出的 f01-f06 应修条目 +- `cbf1d4a` chore: 留痕补 commit 哈希 +- `84d008b` chore: 留痕补 commit 哈希 +- `62d4ce6` chore: 留痕补 commit 哈希 +- `4f7d1e8` chore: 留痕补 e02 commit 哈希 +- `47bea0b` chore: 留痕补 e01 commit 哈希 +- `b89d1cd` chore: backlog 记录 d29 done +- `c8154b4` chore: backlog 记录 d27/d28 done +- `734017a` chore: backlog 记录 d26 done + +## 其他 + +- `fc7a1e8` iter: e02 新增 stepper 步骤条组件(三态流转 + active 信号双向绑定 + clickable 回跳) +- `20d7b94` iter: e01 新增 inputNumber 数字输入组件(−/+ 步进 + 键盘上下调节,信号双向绑定,min/max/step 夹取) +- `d7226f4` iter: 协议加时钟硬规范——时长禁止自报估算,预算判断改 date 实测差值 +- `f8934ba` iter: d29 menu Home/End 跳转(与 select 键盘导航对称) +- `8e16829` iter: d28 drawer 焦点陷阱(Tab/Shift+Tab 回绕、关闭归还焦点) +- `fac74a3` iter: d27 modal 焦点陷阱(Tab/Shift+Tab 回绕、role=dialog、关闭归还焦点) +- `82f48aa` iter: d26 select 键盘导航(↑↓ 环形移动、Home/End、Esc 回焦触发器) +- `6a5e662` iter: d25 menu 条目支持快捷键提示 +- `6efe3ab` iter: d24 重写 README + 组件清单防漂移校验 +- `f361a19` iter: d23 alert 标题行 + 可关闭 + role=alert +- `f86da98` iter: d22 新增头像 avatar 组件 +- `00a6104` iter: d21 无障碍收尾(aria-label / role / aria-hidden) +- `9cfdb43` iter: d20 progress 支持不确定态 +- `4555542` iter: d19 dataTable 选中态受控 +- `4012923` iter: d18 硬编码颜色门禁 + 清掉 ui.css 残留 #fff +- `bdc1fec` iter: d17 表单错误态覆盖包裹式控件 + 校验时机事件 +- `fa168b9` iter: d16 dataTable 落地列宽 width +- `1c03c81` iter: d15 CLI 包补清单 + 文档组件数纠正 +- `d3fc754` iter: d14 新增抽屉 drawer 组件 +- `730ee1a` iter: d13 dataTable 列对齐与单元格格式化 +- `9eefdcb` iter: d12 新增可关闭标签 tag 组件 +- `d1a2864` iter: d11 modal 补 size 档位与 footer 操作区 +- `a08f157` iter: d10 toast 手动关闭 + 堆叠上限 +- `a11157b` iter: d09 新增滑块 slider 组件 +- `1a4b2c1` iter: d08 演示页侧边目录 + 滚动高亮 +- `fb9ab88` iter: d07 新增可交互气泡卡片 popover +- `582318a` iter: d06 新增 ua verify 门禁(清单/文档/演示锚点一致性) +- `60c0524` iter: d05 新增面包屑 breadcrumb 组件 +- `ccbdcb9` iter: d04 dataTable 接加载态(骨架行 + 交互禁用) +- `df2fb34` iter: d03 新增折叠面板 accordion 组件 +- `6b9fa95` iter: d02 select/radioGroup 补 disabled + 修复 select 箭头旋转 +- `84277a7` iter: d01 新增下拉菜单 menu 组件(弹层/键盘导航/reduced-motion) +- `f9324dd` iter: c02 textField/textarea 补 disabled 禁用态(布尔或信号绑定) +- `2a5892a` iter: c01 button/checkbox/switch 补 disabled 禁用态(布尔或信号绑定) +- `83bc1e2` iter: b05 文档站 props 表补齐默认值列(df 字段),manifest 驱动链路核查闭环 +- `8c9a63b` iter: b04 新增独立 pagination 分页器并与 dataTable 页码联动 +- `2882057` iter: b03 新增 skeleton 骨架屏组件(三形状占位 + 扫光 + reduced-motion 兜底) +- `ece38bc` iter: b02 新增 toast 消息提示组件(四语义工厂 + 右上角堆叠 + 3s 自动消失) +- `aaf6fdc` iter: 协议升级为连续迭代+心跳监护模式 +- `a57577a` iter: b01 新增 tooltip 悬浮提示组件 +- `e9165ea` iter: b01 前置修复——style 检查先剥离字面量,消除 URL 中 // 误判 +- `17a4fb1` iter: 新增 Gitea REST API 包装脚本 +- `305826e` iter: 新增 Gitea 认证推送包装脚本 +- `ccba3db` iter: 自我迭代协议与点子库初始化 +- `0de9b6e` init: @ui-arch 私人组件库 monorepo +- `a186d71` Initial commit diff --git a/package.json b/package.json index e90901f..a626376 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "check": "npm run build && npm run style && npm run typecheck && npm run smoke && npm run index && npm run verify && npm run lint-iterations", "ua": "node packages/tools/cli/bin/ua.js", "verify": "node packages/tools/cli/bin/ua.js verify", - "lint-iterations": "node packages/tools/cli/bin/ua.js lint-iterations" + "lint-iterations": "node packages/tools/cli/bin/ua.js lint-iterations", + "changelog": "node packages/tools/cli/bin/ua.js changelog", + "changelog:check": "node packages/tools/cli/bin/ua.js changelog --check" }, "devDependencies": { "typescript": "^5.6.0" diff --git a/packages/tools/cli/bin/ua.js b/packages/tools/cli/bin/ua.js index 8176edb..4bebe16 100644 --- a/packages/tools/cli/bin/ua.js +++ b/packages/tools/cli/bin/ua.js @@ -3,6 +3,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -635,6 +636,49 @@ function checkLlmsFull(pkgs, issues) { } } +/*** 生成 CHANGELOG.md:按提交类型前缀分组渲染 git 史(输出不含时间戳,可幂等比对);--check 只校验不写盘 ***/ +function cmdChangelog(args) { + const check = args.includes('--check'); + const res = spawnSync('git', ['log', '-n', '400', '--pretty=format:%h\t%s'], { cwd: ROOT, encoding: 'utf8' }); + if (res.status !== 0) { console.error('changelog: 读取 git log 失败(是否在 git 仓库内?)'); process.exit(1); } + const rows = res.stdout.split(/\r?\n/).filter(Boolean).map((line) => { + const [hash, ...rest] = line.split('\t'); // 第一段为短哈希,其余为标题(标题可能含制表符) + return { hash, subject: rest.join('\t') }; + }); + const groups = [ + { title: '迭代', test: /^iter\(/ }, // 自动化迭代提交 + { title: '功能', test: /^feat[(:]/ }, // 新功能 + { title: '修复', test: /^fix[(:]/ }, // 缺陷修复 + { title: '文档', test: /^docs[(:]/ }, // 文档变更 + { title: '维护', test: /^(chore|refactor|test|build|ci)[(:]/ }, // 杂项维护 + ]; + const buckets = new Map(groups.map((g) => [g.title, []])); + buckets.set('其他', []); // 未匹配前缀的提交兜底 + for (const row of rows) { + const hit = groups.find((g) => g.test.test(row.subject)); + buckets.get(hit ? hit.title : '其他').push(row); + } + const parts = ['# 变更日志', '', '> 由 `ua changelog` 依据 git 提交史生成,请勿手改;条目按提交时间倒序。', '']; + for (const [title, list] of buckets) { + if (!list.length) continue; // 空分组不渲染 + parts.push(`## ${title}`, ''); + for (const row of list) parts.push(`- \`${row.hash}\` ${row.subject}`); + parts.push(''); + } + const next = parts.join('\n'); + const file = path.join(ROOT, 'CHANGELOG.md'); + const prev = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : ''; + const same = prev.replace(/\r\n/g, '\n') === next; + if (check) { + if (!same) { console.error('changelog: CHANGELOG.md 与提交史不一致,请运行 ua changelog 重新生成'); process.exit(1); } + console.log('changelog OK (与提交史一致)'); + return; + } + if (same) { console.log('changelog unchanged, skip'); return; } // 无变化不写盘,避免空提交 + fs.writeFileSync(file, next); + console.log(`changelog written -> CHANGELOG.md (${rows.length} commits)`); +} + /*** 交叉校验留痕与条目:done 条目必须有一条 done 留痕,留痕 id 必须存在于 backlog(防「标完成无记录 / 记录指向幽灵条目」) ***/ function checkIterations() { const issues = []; @@ -804,6 +848,9 @@ switch (cmd) { case 'commit-lint': cmdCommitLint(args); break; + case 'changelog': + cmdChangelog(args); + break; case 'lint-iterations': cmdLintIterations(); break; @@ -811,6 +858,6 @@ switch (cmd) { cmdMcp(); break; default: - console.log('usage: ua |docs|style|verify|commit-lint|lint-iterations|mcp>'); + console.log('usage: ua |docs|style|verify|commit-lint|lint-iterations|changelog|mcp>'); process.exit(cmd ? 1 : 0); }