paseo-req-kit 0.0.0-stage → 1.7.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/LICENSE +21 -0
  3. package/README.md +141 -2
  4. package/SCOPE.md +11 -0
  5. package/bin/locate.mjs +46 -0
  6. package/bin/req-doctor.mjs +21 -0
  7. package/bin/req.mjs +175 -0
  8. package/bin/start-pipeline +21 -0
  9. package/bin/start-pipeline.mjs +22 -0
  10. package/config.example.json +101 -0
  11. package/contracts/README.md +18 -0
  12. package/contracts/feature-files.md +87 -0
  13. package/contracts/notifier-event.md +71 -0
  14. package/contracts/result-file.md +17 -0
  15. package/contracts/spec.md +34 -0
  16. package/contracts/state.md +44 -0
  17. package/contracts/verify.md +39 -0
  18. package/docs/adr/0001-step-agents-under-origin-chat.md +15 -0
  19. package/docs/adr/0002-no-directory-switch-in-chat.md +15 -0
  20. package/docs/adr/0003-script-engine-not-hub.md +15 -0
  21. package/docs/adr/0004-result-files.md +15 -0
  22. package/docs/adr/0005-no-default-branch-local-commits-only.md +15 -0
  23. package/docs/adr/0006-skill-install-targets.md +15 -0
  24. package/docs/adr/0007-own-interview-skill.md +15 -0
  25. package/docs/adr/0008-entries-do-not-call-entries.md +15 -0
  26. package/docs/adr/0009-versioned-install-layout.md +15 -0
  27. package/docs/adr/0010-generated-feature-overview.md +15 -0
  28. package/docs/adr/0011-resume-after-completion.md +15 -0
  29. package/docs/adr/0012-review-panel.md +18 -0
  30. package/docs/adr/0013-no-release-tooling.md +15 -0
  31. package/docs/adr/0014-notifier-slot.md +19 -0
  32. package/docs/adr/0015-incremental-continue.md +17 -0
  33. package/docs/adr/0016-upgrade-from-tags.md +19 -0
  34. package/docs/adr/0017-use-paseo-capabilities.md +18 -0
  35. package/docs/adr/0018-own-worktree-option.md +21 -0
  36. package/docs/adr/0019-parallel-orchestration.md +21 -0
  37. package/docs/adr/0020-scheduling-through-the-chat.md +21 -0
  38. package/docs/adr/0021-npm-version-manager.md +19 -0
  39. package/docs/adr/0022-develop-and-verify-phases.md +32 -0
  40. package/docs/adr/README.md +26 -0
  41. package/docs/guide//344/275/277/347/224/250/350/200/205/346/214/207/345/215/227.md +78 -0
  42. package/docs/guide//345/256/211/350/243/205/344/270/216/345/215/207/347/272/247.md +348 -0
  43. package/docs/guide//347/273/264/346/212/244/350/200/205/346/214/207/345/215/227.md +85 -0
  44. package/docs/guide//351/241/271/347/233/256/345/256/232/345/210/266/344/270/216/350/277/220/350/241/214/350/247/204/345/210/231.md +251 -0
  45. package/engine/prompts/00-shared-context.md +100 -0
  46. package/engine/prompts/02-spec-review.md +46 -0
  47. package/engine/prompts/03-design.md +50 -0
  48. package/engine/prompts/03a-design-proposal.md +30 -0
  49. package/engine/prompts/04-design-review.md +72 -0
  50. package/engine/prompts/04b-design-revise.md +34 -0
  51. package/engine/prompts/05-implement.md +66 -0
  52. package/engine/prompts/06-code-review.md +66 -0
  53. package/engine/prompts/07-review-fix.md +41 -0
  54. package/engine/prompts/07b-handoff.md +45 -0
  55. package/engine/prompts/08-service-start.md +59 -0
  56. package/engine/prompts/09-verify.md +90 -0
  57. package/engine/prompts/10-defect-fix.md +41 -0
  58. package/engine/prompts/10b-reverify.md +43 -0
  59. package/engine/prompts/11-report.md +93 -0
  60. package/engine/prompts/browser-verify.md +13 -0
  61. package/engine/prompts/incremental.md +21 -0
  62. package/engine/prompts/panel-member.md +38 -0
  63. package/engine/prompts/paseo-services.md +9 -0
  64. package/engine/prompts/verify-deployed.md +14 -0
  65. package/engine/src/activity.ts +87 -0
  66. package/engine/src/cli-args.ts +204 -0
  67. package/engine/src/config.ts +479 -0
  68. package/engine/src/configure.ts +237 -0
  69. package/engine/src/control.ts +230 -0
  70. package/engine/src/daemon-check.ts +104 -0
  71. package/engine/src/daemon-version.ts +66 -0
  72. package/engine/src/digest.ts +133 -0
  73. package/engine/src/doctor.ts +435 -0
  74. package/engine/src/eval.ts +324 -0
  75. package/engine/src/features.ts +268 -0
  76. package/engine/src/git.ts +30 -0
  77. package/engine/src/launch.ts +405 -0
  78. package/engine/src/locations.ts +55 -0
  79. package/engine/src/main.ts +313 -0
  80. package/engine/src/messages.ts +308 -0
  81. package/engine/src/notifiers.ts +76 -0
  82. package/engine/src/notify-test.ts +97 -0
  83. package/engine/src/paseo-json.ts +73 -0
  84. package/engine/src/paseo-profiles.ts +133 -0
  85. package/engine/src/paseo-runtime.ts +437 -0
  86. package/engine/src/paths.ts +10 -0
  87. package/engine/src/pipeline.ts +1126 -0
  88. package/engine/src/preflight.ts +298 -0
  89. package/engine/src/prompts.ts +72 -0
  90. package/engine/src/queue.ts +61 -0
  91. package/engine/src/runtime-loader.ts +14 -0
  92. package/engine/src/runtime.ts +155 -0
  93. package/engine/src/schedule-time.ts +51 -0
  94. package/engine/src/smoke-test.ts +202 -0
  95. package/engine/src/spec-review.ts +100 -0
  96. package/engine/src/state.ts +278 -0
  97. package/engine/src/steps.ts +242 -0
  98. package/engine/src/usage.ts +67 -0
  99. package/engine/src/worktree.ts +72 -0
  100. package/install.mjs +928 -0
  101. package/notifiers/im-template.mjs +58 -0
  102. package/package.json +67 -4
  103. package/principles/INDEX.md +11 -0
  104. package/skills/acceptance-criteria/SKILL.md +52 -0
  105. package/skills/principle-delete-before-add/SKILL.md +33 -0
  106. package/skills/principle-dont-block-on-humans/SKILL.md +35 -0
  107. package/skills/principle-fix-root-cause/SKILL.md +33 -0
  108. package/skills/principle-prove-it-works/SKILL.md +33 -0
  109. package/skills/principle-report-honestly/SKILL.md +33 -0
  110. package/skills/principle-speak-to-reader/SKILL.md +33 -0
  111. package/skills/principle-this-requirement-only/SKILL.md +33 -0
  112. package/skills/req/SKILL.md +99 -0
  113. package/skills/req/playbooks/accept.md +65 -0
  114. package/skills/req/playbooks/change.md +51 -0
  115. package/skills/req/playbooks/incident.md +55 -0
  116. package/skills/req/playbooks/new.md +83 -0
  117. package/skills/req/playbooks/small.md +48 -0
  118. package/skills/req/playbooks/status.md +39 -0
  119. package/skills/req/playbooks/takeover.md +51 -0
  120. package/skills/req/playbooks/verify.md +57 -0
  121. package/skills/req-doctor/SKILL.md +36 -0
  122. package/skills/req-retro/SKILL.md +79 -0
  123. package/skills/req-setup/SKILL.md +101 -0
  124. package/skills/req-setup/templates/paseo/copy-local-files.mjs +32 -0
  125. package/skills/req-setup/templates/paseo/with-port.mjs +36 -0
  126. package/skills/requirement-interview/SKILL.md +94 -0
  127. package/skills/requirement-kickoff/SKILL.md +17 -0
  128. package/skills/result-report/SKILL.md +34 -0
  129. package/skills/spec-writing/SKILL.md +41 -0
  130. package/skills/spec-writing/spec-template.md +106 -0
package/bin/req.mjs ADDED
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ // The `req` command: short names for the things people do in a terminal.
3
+ // install.mjs writes ~/.req-kit/bin/req (and req.cmd on Windows) pointing here.
4
+ // Everything it does is also available through the full commands it prints in `req help`.
5
+ import { spawnSync } from "node:child_process";
6
+ import fs from "node:fs";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { findTsxCli, layoutOf } from "./locate.mjs";
11
+
12
+ const kitRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
13
+ const version = JSON.parse(fs.readFileSync(path.join(kitRoot, "package.json"), "utf8")).version;
14
+ const tsxCli = findTsxCli(kitRoot) ?? path.join(kitRoot, "node_modules", "tsx", "dist", "cli.mjs");
15
+ const launcher = path.join(kitRoot, "bin", "start-pipeline.mjs");
16
+
17
+ const HELP = `req-kit ${version}(${kitRoot})
18
+
19
+ 在项目目录(或它的工作区)中运行:
20
+ req list 列出这个项目的所有需求和阶段
21
+ req status [需求] 查看进度;只有一个需求运行过时可以不写
22
+ req stop <需求> 停止流水线(之后可以继续)
23
+ req resume <需求> 从上次中断处继续;需求改过时只处理变化的部分
24
+ req verify <需求> [--verify-env local|deployed] [--defects fix|handback|report]
25
+ 研发完成后开始测试验证(分阶段执行时)
26
+ req start <需求> [--profile quick|standard] [--phases gated] [--at 22:00]
27
+ 启动流水线(通常由 /req 在对话中启动,这里用于终端中手工启动)
28
+ req digest [--notify] 项目的需求总览;--notify 同时发到外部通知(如企业 IM)
29
+ req digest --schedule "0 9 * * 1"
30
+ 让 Paseo 按时间表发送需求总览(例子为每周一 9:00);取消:req digest --cancel <ID>
31
+
32
+ 本机维护:
33
+ req doctor [--no-project] 体检:安装、配置、daemon、当前项目
34
+ req configure 配置向导:选择 builder 和 reviewer 用的 agent
35
+ req upgrade [版本] [--beta] 升级到最新版本(或指定版本),自动选能支持本机 Paseo 的版本;
36
+ req upgrade --check 只看有没有新版本
37
+ req versions 已安装的版本和 npm 上的版本
38
+ req use <版本> 切换到已安装的另一个版本(回滚)
39
+ req check 检查安装状态
40
+ req notify-test [--type blocked|failed|completed|milestone|permission]
41
+ 给配置的外部通知(如企业 IM)发一条测试消息
42
+ req version 显示版本和安装位置
43
+
44
+ <需求> 可以写功能目录(docs/features/20261012-sms-login)、目录名,或名称中能唯一确定的一部分(sms-login)。
45
+ 在对话中的用法见 /req;完整说明见 ${path.join(kitRoot, "docs", "guide")}。`;
46
+
47
+ function readJson(file) {
48
+ try {
49
+ return JSON.parse(fs.readFileSync(file, "utf8"));
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ function node(args) {
56
+ const result = spawnSync(process.execPath, args, { stdio: "inherit", windowsHide: true });
57
+ if (result.error) {
58
+ console.error(result.error.message);
59
+ return 1;
60
+ }
61
+ return result.status ?? 1;
62
+ }
63
+
64
+ function needTsx() {
65
+ if (fs.existsSync(tsxCli)) return true;
66
+ console.error(`依赖未安装:在 ${kitRoot} 中执行 npm install,然后运行 node install.mjs`);
67
+ return false;
68
+ }
69
+
70
+ /** Takes the first argument as the requirement, unless it is an option. */
71
+ function feature(rest, required) {
72
+ if (rest[0] && !rest[0].startsWith("-")) return ["--feature", rest[0], ...rest.slice(1)];
73
+ if (required) {
74
+ console.error(`请写出是哪个需求,例如:req ${command} sms-login(用 req list 查看全部需求)`);
75
+ process.exit(2);
76
+ }
77
+ return rest;
78
+ }
79
+
80
+ const [command = "help", ...rest] = process.argv.slice(2);
81
+ const installer = path.join(kitRoot, "install.mjs");
82
+ const MANAGED = { setup: ["--setup"], upgrade: ["--upgrade"], use: ["--use"], versions: ["--versions"] };
83
+
84
+ // Installed with `npm i -g`: this copy manages the versions under ~/tools/req-kit/versions
85
+ // and hands every other command to the version in use.
86
+ if (layoutOf(kitRoot).kind === "manager") {
87
+ if (command in MANAGED) {
88
+ const flags = command === "upgrade" && rest.includes("--check") ? ["--latest"] : MANAGED[command];
89
+ process.exit(node([installer, ...flags, ...rest.filter((a) => a !== "--check")]));
90
+ }
91
+ const kitHome = process.env.REQ_KIT_HOME?.trim() ? path.resolve(process.env.REQ_KIT_HOME.trim()) : path.join(os.homedir(), ".req-kit");
92
+ const active = readJson(path.join(kitHome, "active.json"));
93
+ const activeReq = active?.root ? path.join(active.root, "bin", "req.mjs") : null;
94
+ if (command === "version" || command === "--version" || command === "-v") {
95
+ console.log(`req-kit 管理器 ${version}(${kitRoot})`);
96
+ console.log(active ? `当前启用的版本:${active.version}(${active.root})` : "还没有启用任何版本:运行 req setup");
97
+ process.exit(0);
98
+ }
99
+ if (!activeReq || !fs.existsSync(activeReq)) {
100
+ if (["help", "--help", "-h"].includes(command)) {
101
+ console.log(`req-kit 管理器 ${version}\n\n还没有安装任何版本。先运行:req setup\n\n其他命令:req versions、req upgrade、req use <版本>`);
102
+ process.exit(0);
103
+ }
104
+ console.error(active ? `当前启用的版本 ${active.version} 不在了(${active.root})。运行 req versions 查看已安装的版本,再 req use <版本>。` : "还没有安装任何 req-kit 版本。先运行:req setup");
105
+ process.exit(1);
106
+ }
107
+ process.exit(node([activeReq, command, ...rest]));
108
+ }
109
+
110
+ let code;
111
+ switch (command) {
112
+ case "list":
113
+ case "ls":
114
+ code = node([launcher, "--list", ...rest]);
115
+ break;
116
+ case "status":
117
+ case "st":
118
+ code = node([launcher, "--status", ...feature(rest, false)]);
119
+ break;
120
+ case "stop":
121
+ code = node([launcher, "--stop", ...feature(rest, true)]);
122
+ break;
123
+ case "resume":
124
+ code = node([launcher, "--resume", ...feature(rest, true)]);
125
+ break;
126
+ case "verify":
127
+ code = node([launcher, "--phase", "verify", ...feature(rest, true)]);
128
+ break;
129
+ case "start":
130
+ code = node([launcher, ...feature(rest, true)]);
131
+ break;
132
+ case "doctor":
133
+ code = node([path.join(kitRoot, "bin", "req-doctor.mjs"), ...rest]);
134
+ break;
135
+ case "configure":
136
+ case "config":
137
+ code = node([path.join(kitRoot, "install.mjs"), "--configure", ...rest]);
138
+ break;
139
+ case "upgrade":
140
+ code = rest.includes("--check")
141
+ ? node([path.join(kitRoot, "install.mjs"), "--latest", ...rest.filter((a) => a !== "--check")])
142
+ : node([path.join(kitRoot, "install.mjs"), "--upgrade", ...rest]);
143
+ break;
144
+ case "setup":
145
+ case "use":
146
+ case "versions":
147
+ code = node([installer, ...MANAGED[command], ...rest]);
148
+ break;
149
+ case "check":
150
+ code = node([path.join(kitRoot, "install.mjs"), "--check", ...rest]);
151
+ break;
152
+ case "digest":
153
+ code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "digest.ts"), ...rest]) : 1;
154
+ break;
155
+ case "notify-test":
156
+ code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "notify-test.ts"), ...rest]) : 1;
157
+ break;
158
+ case "version":
159
+ case "--version":
160
+ case "-v":
161
+ console.log(`req-kit ${version}(${kitRoot})`);
162
+ code = 0;
163
+ break;
164
+ case "help":
165
+ case "--help":
166
+ case "-h":
167
+ console.log(HELP);
168
+ code = 0;
169
+ break;
170
+ default:
171
+ console.error(`没有 "${command}" 这个命令。\n`);
172
+ console.error(HELP);
173
+ code = 2;
174
+ }
175
+ process.exit(code);
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ # Starts the requirement pipeline in the background and returns immediately.
3
+ # Same as bin/start-pipeline.mjs, for bash users. The skill uses the .mjs launcher,
4
+ # which also works from PowerShell and cmd.
5
+ set -euo pipefail
6
+ SOURCE="${BASH_SOURCE[0]}"
7
+ while [ -L "$SOURCE" ]; do
8
+ DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
9
+ SOURCE="$(readlink "$SOURCE")"
10
+ [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE"
11
+ done
12
+ TOOL_DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
13
+ TSX="$TOOL_DIR/node_modules/.bin/tsx"
14
+ if [ ! -x "$TSX" ]; then
15
+ TSX="$(command -v tsx || true)"
16
+ fi
17
+ if [ -z "$TSX" ]; then
18
+ echo "未启动:找不到 tsx。请先在 $TOOL_DIR 中执行 npm install。" >&2
19
+ exit 2
20
+ fi
21
+ exec "$TSX" "$TOOL_DIR/engine/src/launch.ts" "$@"
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ // Shell-independent launcher: works the same from bash, PowerShell and cmd, so any
3
+ // Paseo chat agent (Claude Code, Codex, ...) can run it with plain `node "<path>" ...`.
4
+ // Inside a Paseo chat it reads the chat's agent ID and working directory from the
5
+ // environment Paseo provides (PASEO_AGENT_ID, PASEO_AGENT_CWD).
6
+ import { spawnSync } from "node:child_process";
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { findTsxCli } from "./locate.mjs";
11
+
12
+ const toolDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
13
+ const tsxCli = findTsxCli(toolDir) ?? path.join(toolDir, "node_modules", "tsx", "dist", "cli.mjs");
14
+ if (!fs.existsSync(tsxCli)) {
15
+ console.error(`未启动:找不到 tsx。请先在 ${toolDir} 中执行 npm install。`);
16
+ process.exit(2);
17
+ }
18
+ const result = spawnSync(process.execPath, [tsxCli, path.join(toolDir, "engine", "src", "launch.ts"), ...process.argv.slice(2)], {
19
+ stdio: "inherit",
20
+ windowsHide: true,
21
+ });
22
+ process.exit(result.status ?? 1);
@@ -0,0 +1,101 @@
1
+ {
2
+ "daemonUrl": "ws://127.0.0.1:6767/ws",
3
+ "daemonPasswordEnv": "PASEO_DAEMON_PASSWORD",
4
+ "teamConfig": null,
5
+ "agents": {
6
+ "builder": {
7
+ "provider": "claude/CHANGE-ME",
8
+ "modeId": "bypassPermissions"
9
+ },
10
+ "reviewer": {
11
+ "provider": "codex/CHANGE-ME",
12
+ "modeId": "full-access"
13
+ }
14
+ },
15
+ "defaultProfile": "standard",
16
+ "profiles": {
17
+ "quick": {
18
+ "rounds": {
19
+ "designReview": 1,
20
+ "codeReview": 1,
21
+ "defectFix": 1
22
+ },
23
+ "serviceStart": false
24
+ },
25
+ "standard": {
26
+ "rounds": {
27
+ "designReview": 2,
28
+ "codeReview": 3,
29
+ "defectFix": 3
30
+ },
31
+ "serviceStart": true
32
+ }
33
+ },
34
+ "notifyMilestones": true,
35
+ "notifiers": [],
36
+ "stepTimeoutMinutes": {
37
+ "design": 60,
38
+ "design_review": 30,
39
+ "design_revise": 30,
40
+ "implement": 240,
41
+ "code_review": 45,
42
+ "review_fix": 90,
43
+ "service_start": 30,
44
+ "verify": 120,
45
+ "defect_fix": 120,
46
+ "reverify": 90,
47
+ "report": 30,
48
+ "panel_review": 45,
49
+ "spec_review": 20,
50
+ "design_proposal": 45
51
+ },
52
+ "waitChunkSeconds": 600,
53
+ "permissionPollSeconds": 30,
54
+ "resultFollowUps": 2,
55
+ "attachToOriginChat": true,
56
+ "archiveStepAgents": false,
57
+ "retry": {
58
+ "attempts": 2,
59
+ "backoffSeconds": [
60
+ 60,
61
+ 300
62
+ ]
63
+ },
64
+ "paseoServices": "auto",
65
+ "serviceReadySeconds": 120,
66
+ "quotaWarnPercent": 85,
67
+ "specReview": "standard",
68
+ "designProposals": {
69
+ "enabled": false,
70
+ "profiles": [
71
+ "standard"
72
+ ],
73
+ "members": []
74
+ },
75
+ "browserVerify": "auto",
76
+ "reviewPanel": {
77
+ "enabled": false,
78
+ "steps": [
79
+ "design_review",
80
+ "code_review"
81
+ ],
82
+ "profiles": [
83
+ "standard"
84
+ ],
85
+ "members": []
86
+ },
87
+ "maxConcurrentPipelines": 0,
88
+ "waitingReminderHours": 24,
89
+ "autoResumeMinutes": 30,
90
+ "autoResumeMax": 2,
91
+ "watchdogMinutes": 0,
92
+ "phases": {
93
+ "mode": "continuous",
94
+ "verify": {
95
+ "environment": "local",
96
+ "agents": {},
97
+ "defects": "fix",
98
+ "serviceStart": null
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,18 @@
1
+ # 文件格式约定
2
+
3
+ 这些文件同时被聊天中的 skill、流水线引擎和步骤 agent 读写。改动格式时,同时更新这里、相关代码和测试,并在 `CHANGELOG.md` 的"升级须知"中说明。
4
+
5
+ | 文件 | 约定 | 格式版本 |
6
+ | --- | --- | --- |
7
+ | `docs/features/<目录>/spec.md` | [spec.md](spec.md) | `req-kit/spec@1` |
8
+ | `docs/features/<目录>/.pipeline/state.json` | [state.md](state.md) | `version: 1` |
9
+ | `docs/features/<目录>/.pipeline/results/<步骤>.json` | [result-file.md](result-file.md) | 按步骤固定字段 |
10
+ | `decisions.tsv`、`changes.md`、`acceptance.md` 与需求总览 | [feature-files.md](feature-files.md) | 见各文件说明 |
11
+ | `.requirement-pipeline/verify.md` | [verify.md](verify.md) | 自由格式,建议结构见文件 |
12
+ | 外部通知(企业 IM 等)收到的事件 | [notifier-event.md](notifier-event.md) | `schema: 1` |
13
+
14
+ 格式版本的规则:
15
+
16
+ - 同一主版本内只做可以自动迁移的变更。
17
+ - 引擎读到旧版本的状态文件时自动迁移,原文件保留为 `state.json.bak-v<旧版本>`。
18
+ - 读到比自己新的版本时拒绝运行,提示升级 req-kit 或恢复备份。
@@ -0,0 +1,87 @@
1
+ # 功能目录中由人和 /req 维护的文件
2
+
3
+ 除 spec.md(见 [spec.md](spec.md))外,功能目录 `docs/features/<日期>-<名称>/` 中还有以下约定格式的文件。
4
+
5
+ ## decisions.tsv
6
+
7
+ 决策记录,由流水线各步骤追加。制表符分隔,UTF-8,第一行为表头:
8
+
9
+ ```text
10
+ time step ref decision alternatives reason kind needs_human
11
+ ```
12
+
13
+ | 列 | 内容 |
14
+ | --- | --- |
15
+ | `time` | `YYYY-MM-DD HH:MM` |
16
+ | `step` | 步骤名和轮次,如 `代码评审 第2轮` |
17
+ | `ref` | 相关的 FR / AC / CR 编号或文件,没有写 `-` |
18
+ | `decision` / `alternatives` / `reason` | 各一句话,不含换行和制表符 |
19
+ | `kind` | `假设` / `取舍` / `偏离方案` / `驳回意见` / `不修复` |
20
+ | `needs_human` | `yes` / `no`。`yes` 的行会被完成报告列入"需要你确认的决定" |
21
+
22
+ ## changes.md
23
+
24
+ 需求变更记录,由 `/req` 的"修改需求"手册追加,每次修改一节,新的在后:
25
+
26
+ ```markdown
27
+ ## 第 2 版(2026-10-14)
28
+
29
+ - 变更内容:<改了哪些 FR / AC,新增或删除了什么>
30
+ - 原因:<需求方给出的原因>
31
+ - 对进度的影响:<流水线当时的状态;继续后从方案设计重新开始 / 尚未开始开发>
32
+ - 提出人:<姓名或角色>
33
+ ```
34
+
35
+ spec.md 头部的"版本"与最新一节一致。
36
+
37
+ ## handoff.md(提测说明)
38
+
39
+ 1.7.0 起由流水线研发阶段的最后一步("提测说明")写入并提交。分阶段执行时它是交给测试的单据,连续执行时是功能验证的输入,"只做研发"时是人工测试的依据。六节:这次改了什么(按 FR,附分支和提交范围)、怎么跑起来、自测结果、建议重点测试、已知问题和未完成项、测试需要的准备(只写在哪里取,不写口令)。测试退回后修复时追加"第 N 次提测"一节。
40
+
41
+ ## test-env.md(测试环境说明)
42
+
43
+ 1.7.0 起。在已部署的测试环境中做测试验证(`--verify-env deployed` 或配置 `phases.verify.environment`)时必须有,由 `/req` 的"开始测试验证"手册和用户一起写。流水线只使用其中列出的环境、账号和数据:
44
+
45
+ ```markdown
46
+ # 测试环境:<需求名称>
47
+
48
+ - 地址:https://<测试环境地址>
49
+ - 被测版本怎么确认:<版本号接口 / 页面底部的提交号 / 部署平台上的记录>
50
+ - 账号:<测试账号>,口令在 <环境变量 TEST_PASSWORD / 本机文件 ~/.config/xxx>(不写口令本身)
51
+ - 可以使用的测试数据:<数据范围、可以新建和删除的数据>
52
+ - 不能碰的:<共享数据、会触发外部通知的操作等>
53
+ - 清理方式:<测试数据如何清理>
54
+ ```
55
+
56
+ 只能是测试用途的环境;不写任何生产环境的地址和凭据。
57
+
58
+ ## changes.md 中的"测试验证退回"
59
+
60
+ 1.7.0 起,测试验证按 `defects: handback` 把缺陷退回研发阶段时,流水线在 `changes.md` 末尾追加一节"<日期> 测试验证退回(第 N 次)",来源为"测试验证",缺陷清单在 `verification.md` 最后一轮。研发阶段随后从方案设计开始只处理这些缺陷。
61
+
62
+ ## acceptance.md
63
+
64
+ 验收记录,由 `/req` 的"验收"手册写。验收标准本身只在 spec.md 中维护,这里只记录结果:
65
+
66
+ ```markdown
67
+ # 验收记录:<需求名称>
68
+
69
+ - 验收结论:通过(2026-10-15) / 不通过(2026-10-15) / 进行中
70
+ - 验收人:<姓名或角色>
71
+ - 对照的需求版本:2
72
+ - 对照的报告:report.md(流水线结论:已完成,可以验收)
73
+
74
+ | AC | 结果 | 怎么验证的 | 备注 |
75
+ | --- | --- | --- | --- |
76
+ | AC-1.1 | 通过 / 不通过 / 未验 | <亲自操作 / 执行的命令> | <现象、截图路径> |
77
+
78
+ ## 不通过的处理
79
+
80
+ - AC-2.3:<现象> → 作为缺陷处理 / 作为需求修改 / 接受现状(理由)
81
+ ```
82
+
83
+ `start-pipeline --list` 读取"验收结论"一行来显示"已验收"或"验收未通过"。
84
+
85
+ ## 需求总览
86
+
87
+ 需求总览不是一个提交进仓库的文件。每个需求在自己的工作区和分支上,共用的索引文件会在合并时冲突,所以总览由 `start-pipeline --list` 现场生成:扫描这个仓库所有 worktree 中的 `docs/features/*/spec.md`、状态文件和验收记录。
@@ -0,0 +1,71 @@
1
+ # 外部通知事件(notifier)
2
+
3
+ 流水线除了把消息发回发起的对话,还可以在关键时刻调用本机的通知模块,例如把消息转发到企业内部 IM。req-kit 只定义调用方式和事件格式,不包含任何 IM 的实现;模板见 [notifiers/im-template.mjs](../notifiers/im-template.mjs)。
4
+
5
+ ## 配置
6
+
7
+ 只能写在本机配置(`~/.req-kit/config.json`)或团队配置中,项目配置中的 `notifiers` 会被忽略(项目仓库里的代码不应该决定往哪里发消息)。
8
+
9
+ ```json
10
+ "notifiers": [
11
+ {
12
+ "module": "~/.req-kit/notifiers/im.mjs",
13
+ "events": ["blocked", "failed", "completed"],
14
+ "options": { "webhook": "https://im.example.internal/hook/xxx", "tokenEnv": "IM_TOKEN" }
15
+ }
16
+ ]
17
+ ```
18
+
19
+ | 字段 | 说明 |
20
+ | --- | --- |
21
+ | `module` | 通知模块的路径。相对路径相对于声明它的配置文件;`~/` 表示用户目录。 |
22
+ | `events` | 要接收的事件类型,省略时接收全部(包括以后新增的类型)。 |
23
+ | `options` | 原样传给模块的第二个参数。密钥不要直接写在这里,写环境变量的名字,由模块读取。 |
24
+
25
+ ## 模块
26
+
27
+ ES 模块,默认导出(或导出名为 `notify` 的)函数:
28
+
29
+ ```js
30
+ export default async function notify(event, options) { /* 发送 */ }
31
+ ```
32
+
33
+ - 每个事件调用一次,可以返回 Promise。超过 15 秒没有完成按失败处理。
34
+ - 抛出的错误和超时只记入流水线日志("外部通知失败……不影响流水线"),不会让流水线停下或重试。
35
+ - 模块在一次流水线运行中只加载一次;修改模块后,对之后启动或继续的流水线生效。
36
+ - 测试:`req notify-test [--type blocked|failed|completed|milestone|permission|phase_done|digest]` 发一条带"【测试】"字样的示例事件,不需要运行流水线。
37
+
38
+ ## 事件格式(schema 1)
39
+
40
+ ```json
41
+ {
42
+ "schema": 1,
43
+ "type": "blocked",
44
+ "at": "2026-10-13T08:30:00.000Z",
45
+ "kitVersion": "1.3.0-beta.1",
46
+ "feature": { "dir": "docs/features/20261012-sms-login", "name": "20261012-sms-login", "title": "短信验证码登录" },
47
+ "repo": "D:\\work\\shop",
48
+ "branch": "feature/20261012-sms-login",
49
+ "profile": "standard",
50
+ "originAgentId": "agent-id 或 null",
51
+ "text": "方案审核发现 1 个需要需求方决定的问题,流水线已暂停,请到发起的对话中回答。",
52
+ "details": { "questions": ["……"], "resumeCommand": "node \"…/start-pipeline.mjs\" … --resume" }
53
+ }
54
+ ```
55
+
56
+ `text` 是一两句可以直接发出的话;需要自己排版时用 `details`。
57
+
58
+ | type | 什么时候 | details |
59
+ | --- | --- | --- |
60
+ | `milestone` | 方案确定、开始验证、开始修复缺陷(配置 `notifyMilestones` 为 true 时,每次尝试各一次) | `milestone`:`design-settled`、`code-reviewed`、`fixing-defects`、`handback-<n>`(1.7.0 起,测试验证第 n 次把缺陷退回研发) |
61
+ | `blocked` | 方案审核发现需要需求方决定的问题,流水线已暂停 | `questions`(字符串数组)、`resumeCommand` |
62
+ | `permission` | 步骤 agent 在等待权限批准 | `stepTitle`、`agentTitle`、`requests`(字符串数组) |
63
+ | `failed` | 流水线因错误中断(已自动重试过的临时错误除外) | `stepTitle`、`reason`、`logPath`、`resumeCommand` |
64
+ | `completed` | 流水线结束,报告已生成 | `outcome`(`completed`、`completed_with_issues`、`not_completed`)、`summary`、`reportPath`。"只做研发"时另有 `mode`(`develop-only`)和 `handoffPath`,报告是研发报告,需要人工测试 |
65
+ | `phase_done` | 1.7.0 起。分阶段执行时研发阶段已完成(代码已通过评审、提测说明已写好),流水线停在闸口等待测试验证。测试退回后再次修完也会发 | `handoffPath`(提测说明)、`mode`(`gated`)、`verifyCommand`(开始测试验证的命令,在发起的对话中执行)、`verifyAt`(预约的开始时间,ISO 格式,没有为 null)、`handbacks`(已退回的次数) |
66
+ | `digest` | `req digest --notify`(或由 `req digest --schedule` 创建的 Paseo 定时任务)发送项目的需求总览,1.6.0 起。`feature.title` 为"<项目> 需求总览",`text` 是完整的多行总览 | `features`:每个需求的 `name`、`title`、`stage`、`branch`、`updatedAt`、`usage` |
67
+
68
+ ## 兼容性
69
+
70
+ - 同一 `schema` 内只增加字段,不删除、不改含义;模块应忽略不认识的字段和事件类型。
71
+ - 不兼容的变化会提升 `schema`,并在 `CHANGELOG.md` 的"升级须知"中说明。
@@ -0,0 +1,17 @@
1
+ # 步骤结果文件
2
+
3
+ 每个步骤结束时写一个 JSON 对象到 `.pipeline/results/<步骤键>.json`(路径在提示词的 `<pipeline-context>` 中给出)。引擎只根据它决定下一步,不读 agent 的回复文字。缺失或格式不对时,引擎会在同一个会话里提醒补写,最多 `resultFollowUps` 次(默认 2),仍不对则判定该步骤失败。
4
+
5
+ | 步骤 ID | 字段 |
6
+ | --- | --- |
7
+ | `design` | `has_runnable_service`: boolean |
8
+ | `design_review` | `verdict`: `approved` \| `changes_required` \| `blocked`;为 `blocked` 时 `questions`: 非空字符串数组 |
9
+ | `design_revise`、`implement`、`review_fix`、`defect_fix` | `status`: `done` \| `partial` |
10
+ | `code_review` | `verdict`: `pass` \| `changes_required` |
11
+ | `service_start` | `started`: boolean |
12
+ | `verify` | `result`: `pass` \| `defects_found` \| `blocked` |
13
+ | `reverify` | `result`: `pass` \| `defects_remaining` |
14
+ | `report` | `outcome`: `completed` \| `completed_with_issues` \| `not_completed`;`summary`: string |
15
+ | `panel_review`(评审小组成员,键为 `<评审步骤>-r<轮次>-p<序号>`) | `status`: `done` \| `partial`;意见写在 `<功能目录>/review-panel/<键>.md` |
16
+
17
+ 字段定义以 `engine/src/steps.ts` 为准;改动时同步更新各步骤提示词末尾的"结果文件"一节。
@@ -0,0 +1,34 @@
1
+ # spec.md
2
+
3
+ 需求说明,由 `/req`(`spec-writing` skill)按模板 `skills/spec-writing/spec-template.md` 写成,需求方确认后交给流水线。
4
+
5
+ ## 头部
6
+
7
+ ```markdown
8
+ # <需求名称>
9
+
10
+ - 状态:已确认(2026-10-12)
11
+ - 档位:标准
12
+ - 执行方式:连续
13
+ - 类型:新需求
14
+ - 版本:1
15
+ - 格式:req-kit/spec@1
16
+ ```
17
+
18
+ | 行 | 谁读 | 规则 |
19
+ | --- | --- | --- |
20
+ | `- 状态:` | 引擎 | 以"已确认"开头才能启动流水线。正则:`^\s*-\s*状态\s*[::]\s*已确认` |
21
+ | `- 档位:` | 引擎 | "快速"或"标准"(也接受 `quick` / `standard`)。没有时用配置中的 `defaultProfile` |
22
+ | `- 执行方式:` | 引擎 | "连续"、"分阶段"或"只做研发"(也接受 `continuous` / `gated` / `develop-only`)。可以没有;没有时用配置中的 `phases.mode`,启动参数 `--phases` 优先(1.7 起) |
23
+ | `- 类型:` | `/req` | 新需求 / 小改动 / 缺陷 |
24
+ | `- 版本:` | `/req` | 从 1 开始,每次修改需求加 1 |
25
+ | `- 格式:` | `/req`、引擎(将来) | `req-kit/spec@<n>`。没有这一行的旧 spec 按 `req-kit/spec@1` 处理 |
26
+
27
+ ## 正文中被引用的编号
28
+
29
+ - 功能需求 `FR-<n>`,验收标准 `AC-<n>.<m>`,规则 `BR-<n>`,假设 `A-<n>`。
30
+ - 流水线各步骤和最终报告按这些编号引用,编号一旦确认就不要重排;删除的需求保留编号并注明"已取消"。
31
+
32
+ ## 变更
33
+
34
+ - spec 的内容哈希记录在状态文件中。spec 在流水线中断后被修改,续跑时从方案设计重新开始。
@@ -0,0 +1,44 @@
1
+ # state.json
2
+
3
+ 流水线的运行状态,位于 `docs/features/<目录>/.pipeline/state.json`,只由引擎写入,不提交。
4
+
5
+ ## 当前格式:version 1
6
+
7
+ | 字段 | 类型 | 含义 |
8
+ | --- | --- | --- |
9
+ | `version` | number | 格式版本。没有这个字段的文件按 1 处理 |
10
+ | `repo` | string | 仓库目录(绝对路径) |
11
+ | `featureDir` | string | 功能目录(相对路径,`/` 分隔) |
12
+ | `status` | `running` \| `waiting_for_business` \| `failed` \| `completed` \| `phase_done` | 当前状态。`waiting_for_business` 表示等待需求方决定;`phase_done`(1.7.0 起)表示研发阶段已完成、停在闸口等待测试验证。1.7 之前的引擎把 `phase_done` 当作可以继续的中断,继续时沿用研发结果、直接做验证 |
13
+ | `attempt` | number | 第几次从方案设计开始 |
14
+ | `specHash` | string | 启动时 spec.md 的 sha256 |
15
+ | `originAgentId` | string \| null | 发起对话的 agent,通知发往这里 |
16
+ | `pid` | number | 流水线进程 |
17
+ | `startedAt` / `updatedAt` | ISO 时间 | |
18
+ | `results` | object | 已完成步骤的结果,键为步骤键(如 `code_review-r2`) |
19
+ | `history` | array | 每次步骤执行的记录:agent、起止时间、结果、错误;`usage`(可选,1.3.0 起)为 agent 报告的用量:`inputTokens`、`cachedInputTokens`、`outputTokens`、`totalCostUsd`,agent 没有报告时为 null 或缺少 |
20
+ | `stopReason` / `outcome` | string \| null | 停止原因;最终结论 |
21
+ | `profile` | `quick` \| `standard` | 档位 |
22
+ | `branch` | string \| null | 工作分支,启动时确定 |
23
+ | `milestones` | string[] | 已发送的进展通知,续跑时不重复发送 |
24
+ | `incremental` | object \| null | 可选,1.3.0 起。需求变更或回答问题后的继续:`fromAttempt`(接着哪一次)、`reason`、`baseCommit`(本次开始时的提交,评审看这之后的改动)、`hadImplementation`(上一次是否已写过代码)。第一次运行和 `--restart` 为 null |
25
+ | `worktree` | object \| null | 可选,1.5.0 起。用 `--worktree` 启动、在为需求新建的工作区中开发时:`workspaceId`(Paseo 工作区)、`sourceRepo`(对话所在的目录)。此时 `repo` 是新工作区的目录 |
26
+ | `schedules` | array | 可选,1.6.0 起。这次运行创建的 Paseo 定时任务:`id`、`kind`(`reminder` 提醒 / `auto-resume` 自动继续 / `watchdog` 定时检查)、`at`。下一次运行或暂停命令会取消它们 |
27
+ | `autoResumes` | object \| null | 可选,1.6.0 起。`attempt`、`count`:这次尝试已经预约过几次自动继续 |
28
+ | `queuedSince` | string \| null | 可选,1.6.0 起。正在排队(`maxConcurrentPipelines`)时为开始排队的时间 |
29
+ | `phases` | object \| null | 可选,1.7.0 起。这次运行的执行方式:`mode`(`continuous` / `gated` / `develop-only`)、`environment`(`local` / `deployed`)、`defects`(`fix` / `handback` / `report`)。没有时按 `continuous`、`local`、`fix` 处理 |
30
+ | `phase` | `develop` \| `verify` | 可选,1.7.0 起。当前阶段。用字符串而不是编号,以后增加阶段不用改格式 |
31
+ | `verifyAt` | string \| null | 可选,1.7.0 起。`--verify-at`:研发完成后在这个时间开始测试验证 |
32
+ | `handbacks` | number | 可选,1.7.0 起。测试验证把缺陷退回研发阶段的次数(`defects` 为 `handback`),上限为档位的 `defectFix` 轮数 |
33
+
34
+ `schedules[].kind` 在 1.7.0 起还可能是 `verify-start`(`--verify-at` 预约的测试验证开始)。`history` 中每条步骤记录在 1.7.0 起有可选的 `phase`(`develop` / `verify`),用于按阶段统计用时与用量;没有时按研发阶段统计。
35
+
36
+ ## 迁移
37
+
38
+ 只增加可选字段(缺少时按默认值处理,旧版本引擎读到也不出错)时不提升版本,以便回滚到旧版本后仍能继续已有的流水线;在上表中注明"可选"和起始版本即可。
39
+
40
+ 引擎(`engine/src/state.ts`)中 `STATE_VERSION` 是当前版本,`STATE_MIGRATIONS[n]` 把第 n 版升级到第 n+1 版。增加必需字段或改变已有字段的含义时:
41
+
42
+ 1. `STATE_VERSION` 加 1。
43
+ 2. 在 `STATE_MIGRATIONS` 中加一个从旧版本到新版本的函数,为旧文件补上默认值。
44
+ 3. 在 `engine/test/state.test.ts` 中加一条迁移测试,更新本文件。
@@ -0,0 +1,39 @@
1
+ # .requirement-pipeline/verify.md
2
+
3
+ 项目的验证方法:怎么安装依赖、启动服务、运行测试、准备测试数据。由 `/req-setup` 生成,其中的命令要实际运行过。流水线把它追加到实现、评审修复、服务启动、功能验证、缺陷修复、复验这几个步骤的提示词中("本项目的验证方法"一节)。
4
+
5
+ 格式自由,建议按下面的结构写,每节给出可以直接复制执行的命令:
6
+
7
+ ```markdown
8
+ # 验证方法
9
+
10
+ 最后核对:2026-10-13(/req-setup,全部命令已运行)
11
+
12
+ ## 环境准备
13
+ - Node.js 22,pnpm 9
14
+ - 安装依赖:`pnpm install`
15
+ - 依赖的本地服务:PostgreSQL(`docker compose up -d db`),Redis 不需要
16
+
17
+ ## 构建与静态检查
18
+ - 类型检查:`pnpm typecheck`
19
+ - 代码检查:`pnpm lint`
20
+
21
+ ## 单元与集成测试
22
+ - 全部:`pnpm test`(约 2 分钟,基线 412 个用例全部通过)
23
+ - 单个文件:`pnpm test path/to/file.test.ts`
24
+
25
+ ## 启动服务
26
+ - 命令:`pnpm dev`(在仓库根目录)
27
+ - 就绪判断:`GET http://localhost:3000/health` 返回 200,通常 10 秒内
28
+ - 停止:结束该进程;端口 3000
29
+
30
+ ## 端到端验证
31
+ - 工具:Playwright,`pnpm e2e`;或手工用浏览器访问 http://localhost:3000
32
+ - 测试账号:见 docs/test-accounts.md(不要写入真实口令)
33
+ - 测试替身:短信、支付走 `MOCK_EXTERNAL=1`
34
+
35
+ ## 已知问题
36
+ - `pnpm test` 中 `report.test.ts` 偶发超时,与需求无关
37
+ ```
38
+
39
+ 步骤 agent 发现它过时或不准确时,会在 `service-start.md` 或 `verification.md` 的"建议写入 verify.md 的内容"一节给出实际可行的做法;`/req-setup` 再次运行时会参考这些建议更新本文件。
@@ -0,0 +1,15 @@
1
+ # 0001 步骤 agent 挂在发起的对话下
2
+
3
+ - 状态:已采纳([0018](0018-own-worktree-option.md) 增加了一种可选方式:步骤放在为需求新建的工作区中,仍挂在对话下,对话目录不变)
4
+
5
+ ## 背景
6
+
7
+ Paseo 在创建子 agent 时,如果传了 parent,会使用 parent 的工作目录而不是传入的 cwd。早期版本在两者不一致时改为创建独立 agent,结果步骤的产物写到了别处。
8
+
9
+ ## 决定
10
+
11
+ 步骤 agent 一律作为子 agent 挂在发起的对话下;仓库目录就是这个对话的工作目录。启动前核对两者,不一致时拒绝启动;创建后再核对 agent 的工作目录,不对就归档并报错。
12
+
13
+ ## 影响
14
+
15
+ 使用者在对话的子 agent 列表里就能看到每一步;不会出现产物写错目录的情况。代价是必须在需求所在项目的对话中发起。