Просмотр исходного кода

chore(task): 登记 M0 仓库骨架任务规划工件

prd / design / implement / task.json——M0 完整规划,对应 feat(v7) 骨架实现。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lingfengQAQ 22 часов назад
Родитель
Сommit
dbcb3226ca

+ 122 - 0
.trellis/tasks/06-27-m0-repo-skeleton/design.md

@@ -0,0 +1,122 @@
+# 技术设计:M0 仓库骨架
+
+## 1. 设计范围
+
+骨架与脚手架,**无业务逻辑**。交付物:`v7/` Node 包雏形、`node:test` 测试骨架、版本门槛检查、双矩阵 CI、文档回填。下游 M1+ 在此骨架上长真实代码。
+
+## 2. 目录布局(落点 `v7/`)
+
+```
+v7/
+├── package.json                 # name=webnovel-writer, type=module, engines.node>=22.13.0, 零 deps
+├── bin/
+│   └── webnovel-writer.js       # CLI 入口:先跑版本门槛 → 子命令分发(init/update 占位)
+├── src/
+│   ├── installer/index.js       # 安装器(占位)
+│   ├── state-machine/index.js   # 状态机单入口(占位)
+│   ├── mechanical-check/index.js# 机检(占位)
+│   ├── prep/index.js            # 备料(占位)
+│   ├── finalize/index.js        # 定稿原子提交(占位)
+│   ├── cache/index.js           # .cache/index.db 缓存(占位)
+│   ├── storage/index.js         # 存储适配器端口(占位,M1 落地小端口)
+│   └── runtime/node-version.js  # 版本门槛检查(M0 唯一真实逻辑)
+└── test/
+    ├── node-version.test.js     # 版本门槛断言
+    └── chinese-path.test.js     # 中文路径 UTF-8 往返占位用例
+```
+
+**模块划分依据**:实施计划 M0「src/ 模块划分(安装器/状态机/机检/备料/定稿/缓存)」+ spec §1.5 架构原则(拆小端口、状态机只编排)。`storage/` 单列,承接 M1 的 Storage Adapter 接口。
+
+## 3. 关键契约
+
+### 3.1 版本门槛 `src/runtime/node-version.js`
+
+```js
+// 纯函数,便于测试:传入版本串,返回 {ok, message}
+export function checkNodeVersion(versionString) // "v22.13.0" → {ok:true}
+export const MIN_NODE = '22.13.0'
+```
+
+- 解析 `process.version`(形如 `v22.13.0`),与 `22.13.0` 做语义比较(按 major/minor/patch 数值,不做字符串比较)。
+- 不达标:返回中文人话提示(指明当前版本、所需 `>=22.13.0`、升级指引),调用方打印到 stderr 并 `process.exit(1)`。
+- 达标:静默放行。
+- **纯函数与副作用分离**:比较逻辑是纯函数(吃版本串吐结果),`process.exit` 在 `bin/` 入口做——这样测试不依赖真实运行版本。
+
+### 3.2 CLI 入口 `bin/webnovel-writer.js`
+
+```
+#!/usr/bin/env node
+1. checkNodeVersion(process.version) → 不过则人话提示 + exit(1)
+2. 解析 argv[2] 子命令:init | update | (其余 → 人话"未知命令",exit(1))
+3. init/update 当前打印"M0 占位,未实现",exit(0)——不崩溃
+```
+
+### 3.3 package.json 要点
+
+```json
+{
+  "name": "webnovel-writer",
+  "type": "module",
+  "engines": { "node": ">=22.13.0" },
+  "bin": { "webnovel-writer": "bin/webnovel-writer.js" },
+  "scripts": { "test": "node --test" },
+  "dependencies": {}
+}
+```
+
+- `dependencies` 必须为空(零运行时依赖铁律)。`devDependencies` 也尽量空——`node:test` 内置,无需第三方。
+- `engines.node` 是声明;真实拦截靠 §3.1 运行时检查(npm 默认不强制 engines)。
+
+## 4. 测试设计(`node:test` + `node:assert`)
+
+- **node-version.test.js**:对 `checkNodeVersion` 喂 `v22.12.0`(不过)、`v22.13.0`(过)、`v24.15.0`(过)、`v21.0.0`(不过),断言 `ok` 与 message 非空。纯函数,跨平台稳定。
+- **chinese-path.test.js**:在 `os.tmpdir()` 下建含中文名的目录与文件(如 `测试目录/章节-001.md`),写入中文 UTF-8 内容再读回,断言往返一致、且显式 `encoding:'utf8'`。为 M2+ 的"中文路径全链路 CI"占位。用 `node:test` 的 `after` 清理临时目录。
+
+## 5. CI 设计(GitHub Actions)
+
+落 `.github/workflows/v7-ci.yml`(与 v6 既有 workflow 并存,独立 job 名加 `v7-` 前缀避免混淆):
+
+```yaml
+name: v7 CI
+on:
+  push: { branches: [v7] }
+  pull_request: { branches: [v7] }
+jobs:
+  test:
+    strategy:
+      matrix:
+        os: [ubuntu-latest, windows-latest]
+        node: ['22.13.0', 'lts/*']
+    runs-on: ${{ matrix.os }}
+    defaults: { run: { working-directory: v7 } }
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-node@v4
+        with: { node-version: ${{ matrix.node }} }
+      - run: node --test
+      - run: node bin/webnovel-writer.js --version   # 版本门槛冒烟(达标放行)
+```
+
+- 矩阵 4 组合(2 OS × 2 Node)。`22.13.0` 验地板,`lts/*` 验当前。
+- `working-directory: v7` 让所有步骤在子目录内跑。
+- Windows job 自动覆盖中文路径用例(test 里含 chinese-path)。
+- 仅触发于 `v7` 分支与对 `v7` 的 PR,不干扰 master/v6 CI。
+
+> `--version` 子命令需在 bin 入口支持(打印包版本,顺带证明入口可执行)。
+
+## 6. 文档回填(文档先行)
+
+- `directory-structure.md` §2:「(v7 代码目录待定)」→ `v7/` 实际布局(package.json/bin/src/test)。
+- `directory-structure.md` §4:填实「src/ 模块划分」「测试目录与命名约定(`v7/test/**/*.test.js`,与 src 镜像,node:test)」;题材模板位置仍留白(知识层平移任务)。
+
+## 7. 边界与非目标
+
+- `src/**/index.js` 只导出占位(空函数/常量),**禁止**写真实逻辑——避免在 RFC 后格式微调时返工。
+- 不配 lint/格式化(可下个任务);不引入 TypeScript(纯 JS + ESM,零构建步骤)。
+- 不碰 `webnovel-writer/`(v6)与仓库根 Python 遗产。
+
+## 8. 风险与缓解
+
+- **风险**:`lts/*` 解析到的版本将来变化导致 CI 漂移。**缓解**:地板 `22.13.0` 固定兜底,`lts/*` 仅作前瞻;真出问题锁具体版本。
+- **风险**:Windows runner 默认编码非 UTF-8 导致中文用例假阴性。**缓解**:测试内所有 IO 显式 `utf8`,不依赖 locale;这正是该用例要守护的不变量。
+- **风险**:`engines.node` 不被 npm 强制,低版本仍能装。**缓解**:运行时 §3.1 检查兜底,入口最早执行。

+ 62 - 0
.trellis/tasks/06-27-m0-repo-skeleton/implement.md

@@ -0,0 +1,62 @@
+# 执行计划:M0 仓库骨架
+
+> 前置:已读 prd.md、design.md,以及后端规范 directory-structure / quality-guidelines。
+> 落点全部在 `v7/`、`.github/workflows/`、`.trellis/spec/backend/`;不碰 v6 与根 Python 遗产。
+> 本机命令:`node`(v24.15.0 可用);Python 脚本用 `python` 或 `py` 均可(已修),带 `PYTHONUTF8=1`。
+
+## 阶段 A:包骨架
+
+- [ ] A1 建 `v7/package.json`:name=webnovel-writer、type=module、engines.node>=22.13.0、bin、scripts.test=`node --test`、dependencies={}(design §3.3)
+- [ ] A2 建 `v7/bin/webnovel-writer.js`:shebang + 版本门槛先行 + 子命令分发(init/update/--version 占位,未知命令人话提示)(design §3.2)
+- [ ] A3 建 `v7/src/` 七个占位模块(installer/state-machine/mechanical-check/prep/finalize/cache/storage 各一 index.js,导出占位)
+- [ ] A4 建 `v7/src/runtime/node-version.js`:`checkNodeVersion(versionString)` 纯函数 + `MIN_NODE`(design §3.1)
+
+**验证 A**:`cd v7 && node bin/webnovel-writer.js --version`(打印版本不崩);`node bin/webnovel-writer.js init`(打印占位,exit 0)
+
+## 阶段 B:测试骨架
+
+- [ ] B1 `v7/test/node-version.test.js`:喂 v22.12.0/v22.13.0/v24.15.0/v21.0.0,断言 ok 与 message(design §4)
+- [ ] B2 `v7/test/chinese-path.test.js`:tmpdir 下中文目录+文件 UTF-8 往返断言,after 清理(design §4)
+
+**验证 B**:`cd v7 && node --test` → 全绿(本机 Node 24,满足门槛)
+
+**评审门 1**:零 dependencies(`grep -A2 '"dependencies"' v7/package.json` 为空对象);无第三方 import(`grep -rn "require(\|from '[^.]" v7/src v7/test` 只应见 node: 内置)
+
+## 阶段 C:CI
+
+- [ ] C1 建 `.github/workflows/v7-ci.yml`:matrix [ubuntu,windows]×['22.13.0','lts/*'],working-directory v7,步骤 node --test + 版本冒烟(design §5)
+- [ ] C2 确认只触发 v7 分支/PR,不影响 master
+
+**验证 C**:本地 `python -c "import yaml,sys; yaml.safe_load(open('.github/workflows/v7-ci.yml',encoding='utf-8'))"` 语法校验(PYTHONUTF8=1);推分支后看 Actions 双平台绿
+
+## 阶段 D:文档回填(文档先行)
+
+- [ ] D1 directory-structure.md §2:「(v7 代码目录待定)」→ v7/ 实际布局
+- [ ] D2 directory-structure.md §4:填 src/ 模块划分 + 测试目录命名约定;题材模板留白
+- [ ] D3 directory-structure.md 版本注脚:基线 1.0 → 1.1(M0 落地修订),上游 spec 0.6 → 0.8
+
+**验证 D**:通读 §2/§4 与 `v7/` 实际一致,无"待定"残留
+
+## 阶段 E:收尾
+
+- [ ] E1 全量验证:`cd v7 && node --test` 绿 + 版本门槛低版本路径有测试覆盖
+- [ ] E2 过 quality-guidelines §5 评审清单(零依赖/无 Python/UTF-8/错误不崩/文档先行)
+- [ ] E3 `task.py current` 确认任务,spec update 评估(阶段 3.3),提交(前缀 feat,作用域 v7 骨架)
+
+**出口判据复核(对齐 prd Acceptance)**:
+- [ ] CI ubuntu + windows 双绿
+- [ ] 版本门槛 <22.13.0 人话提示 + 非零退出,有测试
+- [ ] package.json 零 deps / type module / engines>=22.13.0
+- [ ] directory-structure §2/§4 已回填
+- [ ] 中文路径占位用例在 Windows job 跑过
+
+## 回滚点
+
+- 阶段 A-D 各自独立,未提交前删 `v7/` 或 `.github/workflows/v7-ci.yml` 即回到原点。
+- 全部在新增文件内,不改既有文件(除 directory-structure.md)——回滚 directory-structure.md 用 `git checkout`。
+
+## 提交计划
+
+建议单一 commit(骨架是一个整体):
+`feat(v7): M0 仓库骨架——v7/ npm 包 + node:test + 双矩阵 CI + Node 版本门槛`
+文档回填可并入同一 commit(文档与骨架同生)。

+ 76 - 0
.trellis/tasks/06-27-m0-repo-skeleton/prd.md

@@ -0,0 +1,76 @@
+# PRD: M0 仓库骨架
+
+## Goal
+
+为 v7 搭起**第一批可运行的工程骨架**:一个零依赖的 Node npm 包雏形、`node:test` 测试骨架、Linux/Windows 双矩阵 CI,以及 Node 版本门槛检查。骨架格式无关(不依赖 story repo 格式细节),RFC 怎么改都不浪费。
+
+本任务**不实现任何业务逻辑**(写章流程、缓存、状态机的真实行为都在 M1+)。M0 只交付"能跑起来、CI 能绿、版本门槛能挡"的空壳与脚手架。
+
+## Background
+
+- 当前 `v7` 分支下 v7 产品代码为 **0 行**:仓库根没有 `package.json`,`webnovel-writer/` 是冻结的 v6 Python 遗产。
+- v7 是 **Node ≥ 22.13.0、零第三方运行时依赖**的全新重写(缓存用内置 `node:sqlite`,无需 flag 的最低版本即 22.13.0)。
+- 上游已就绪:PRD 1.0、story-repo-spec 0.8、multi-agent-spec v3.4、后端开发规范基线 1.0、O4 缓存设计已定稿。
+- 实施计划(`v7-implementation-plan.md` §2)定义 M0 为"立即可开、不等 RFC"的首个里程碑。
+
+## Scope(范围决策,已与作者确认)
+
+- **代码落点**:新建 `v7/` 子目录承载 Node 包;v6 `webnovel-writer/` 与仓库根 Python 遗产**原地不动**。将来 beta 通过合并时再决定是否上提到根。
+- **包名**:`webnovel-writer`(对应 `npx webnovel-writer`,npm 发布名)。
+
+## Requirements
+
+### R1: npm 包骨架(`v7/`)
+
+- `v7/package.json`:`name=webnovel-writer`、`type=module`(ESM)、`engines.node>=22.13.0`、`dependencies` 为空(铁律:零运行时依赖)、`bin` 指向入口、`scripts.test` 跑 `node --test`。
+- `v7/bin/`:CLI 入口(`webnovel-writer init` / `update` 的命令分发空壳,子命令打印"未实现"占位但不报错崩溃)。
+- `v7/src/`:按职责划分的模块目录骨架(安装器 / 状态机 / 机检 / 备料 / 定稿 / 缓存 / 存储适配器),每个目录一个 `index.js` 导出空接口或占位,**不含真实逻辑**。
+- 模块划分须与后端规范 directory-structure §3 原则一致,并回填该文件 §4 待补项。
+
+### R2: Node 版本门槛(出口判据之一,必须真实可跑)
+
+- 一个版本检查函数:读 `process.version`,低于 `22.13.0` 时输出**人话提示**(中文、指明需要的版本与升级指引),并以非零退出码终止;满足时静默放行。
+- 该检查在 CLI 入口最早期执行(任何子命令之前)。
+- 必须有对应测试(构造低版本输入走断言,不真依赖运行环境版本)。
+
+### R3: 测试骨架(`node:test`,零依赖)
+
+- 用 Node 内置 `node:test` + `node:assert`,不引入任何第三方测试框架。
+- 测试目录与命名约定:`v7/test/` 下 `*.test.js`,与 `src/` 镜像。约定写回 directory-structure §4。
+- 至少含:版本门槛测试、一个**中文路径占位用例**(创建含中文名的临时目录并读写一个 UTF-8 文件,断言往返一致——为后续全链路 CI 占位)。
+
+### R4: CI 双矩阵(出口判据之一)
+
+- GitHub Actions workflow(落 `.github/workflows/`),矩阵 `os = [ubuntu-latest, windows-latest]` × `node = [22.13.0(地板), lts/*]`。
+- 步骤:装 Node → `node --test`(在 `v7/`)→ 版本门槛检查冒烟。
+- Windows job 必须实际跑中文路径占位用例(验证 UTF-8 文件 IO 不依赖系统 locale)。
+- 文件 IO 一律显式 UTF-8 无 BOM;CI 不依赖系统 locale。
+
+### R5: 文档回填(文档先行铁律)
+
+- `directory-structure.md` §2:把"(v7 代码目录待定)"替换为 `v7/` 实际布局。
+- `directory-structure.md` §4:填实 src/ 模块划分、测试目录与命名约定两项(题材模板位置留到知识层平移任务)。
+
+## Acceptance Criteria(出口判据,逐条可验证)
+
+- [ ] `cd v7 && node --test` 在本机绿(含版本门槛测试 + 中文路径占位用例)。
+- [ ] CI 在 **ubuntu-latest 与 windows-latest 双双绿**。
+- [ ] Node `<22.13.0` 时版本门槛给中文人话提示并非零退出;`≥22.13.0` 放行——有测试覆盖。
+- [ ] `v7/package.json` 零 `dependencies`、`engines.node>=22.13.0`、`type=module`。
+- [ ] `directory-structure.md` §2/§4 已回填,与实际 `v7/` 布局一致。
+- [ ] 全程零第三方运行时依赖、无 Python 引入。
+
+## Out of Scope
+
+- 任何业务逻辑(缓存重建器、精准读取接口、写章八阶段、状态机判定、安装器真实行为)——M1+。
+- 平台壳生成、SKILL.md 入口、SessionStart 注入——M4/M5。
+- lint/格式化工具选型可在本任务顺带定,也可留到下个任务(非阻塞 M0 出口)。
+- 把 v7/ 上提到仓库根——beta 合并时再议。
+
+## Confirmed Facts from Codebase
+
+- 仓库根无 `package.json`;`v7` 分支当前无任何 `.js` 源码、无 `src/`。
+- `webnovel-writer/`(v6)为 Python:hooks/skills/scripts/templates/dashboard/evals。
+- 后端规范 `directory-structure.md` §2 已预留"(v7 代码目录待定)"、§4 三个待补项。
+- 质量规范要求:零依赖、`node:test` 候选、UTF-8 无 BOM、Windows 中文路径 CI、缩进两空格、commit 前缀 feat/fix/docs/chore。
+- 本机 Python 必须用 `py`(`python` 是 Store 占位 stub,静默退出 49)。

+ 26 - 0
.trellis/tasks/06-27-m0-repo-skeleton/task.json

@@ -0,0 +1,26 @@
+{
+  "id": "m0-repo-skeleton",
+  "name": "m0-repo-skeleton",
+  "title": "M0 仓库骨架",
+  "description": "v7 第一批代码:v7/ 子目录 npm 包骨架 + node:test 测试骨架 + Linux/Windows 双矩阵 CI(含中文路径用例空壳)+ Node ≥22.13.0 版本门槛。出口:CI 双平台绿、版本门槛检查与人话提示可跑",
+  "status": "in_progress",
+  "dev_type": null,
+  "scope": null,
+  "package": null,
+  "priority": "P1",
+  "creator": "claude",
+  "assignee": "claude",
+  "createdAt": "2026-06-27",
+  "completedAt": null,
+  "branch": null,
+  "base_branch": "v7",
+  "worktree_path": null,
+  "commit": null,
+  "pr_url": null,
+  "subtasks": [],
+  "children": [],
+  "parent": null,
+  "relatedFiles": [],
+  "notes": "",
+  "meta": {}
+}