paseo-req-kit 1.8.0 → 1.9.0-beta.2
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.
- package/CHANGELOG.md +38 -0
- package/README.md +2 -0
- package/bin/req-plugin.mjs +226 -0
- package/bin/req.mjs +27 -0
- package/contracts/README.md +2 -0
- package/contracts/cli-json.md +66 -0
- package/contracts/usage-record.md +48 -0
- package/docs/adr/0026-machine-records-and-api.md +23 -0
- package/docs/adr/0027-paseo-plugin.md +23 -0
- package/docs/adr/README.md +2 -0
- package/docs/guide//344/275/277/347/224/250/350/200/205/346/214/207/345/215/227.md +2 -0
- package/docs/guide//345/256/211/350/243/205/344/270/216/345/215/207/347/272/247.md +26 -0
- package/docs/guide//347/273/264/346/212/244/350/200/205/346/214/207/345/215/227.md +3 -1
- 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 +10 -0
- package/engine/src/api.ts +397 -0
- package/engine/src/control.ts +2 -2
- package/engine/src/eval.ts +2 -0
- package/engine/src/index-cmd.ts +33 -0
- package/engine/src/main.ts +26 -0
- package/engine/src/records.ts +271 -0
- package/engine/src/state.ts +3 -0
- package/engine/src/stats.ts +479 -0
- package/install.mjs +3 -0
- package/package.json +3 -2
- package/paseo-plugin/OVERVIEW.md +7 -0
- package/paseo-plugin/client/data.ts +55 -0
- package/paseo-plugin/client/detail.tsx +277 -0
- package/paseo-plugin/client/format.ts +101 -0
- package/paseo-plugin/client/live.ts +161 -0
- package/paseo-plugin/client/overview.tsx +89 -0
- package/paseo-plugin/client/panel.tsx +56 -0
- package/paseo-plugin/client/row.tsx +40 -0
- package/paseo-plugin/client/settings.tsx +90 -0
- package/paseo-plugin/client/sidebar.tsx +27 -0
- package/paseo-plugin/client/stats.tsx +80 -0
- package/paseo-plugin/client/ui.tsx +111 -0
- package/paseo-plugin/index.client.tsx +52 -0
- package/paseo-plugin/index.server.ts +41 -0
- package/paseo-plugin/package.json +22 -0
- package/paseo-plugin/paseo-plugin.json +6 -0
- package/paseo-plugin/server/handlers.ts +45 -0
- package/paseo-plugin/server/req.ts +100 -0
- package/paseo-plugin/shared/contracts.ts +165 -0
- package/paseo-plugin/tsconfig.json +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
每个版本分为"使用者会看到的变化"和"升级须知"。升级步骤见 [docs/guide/安装与升级.md](docs/guide/安装与升级.md)。
|
|
4
4
|
|
|
5
|
+
## 1.9.0-beta.2
|
|
6
|
+
|
|
7
|
+
Paseo 插件:在 Paseo 的界面里查看和管理需求。
|
|
8
|
+
|
|
9
|
+
### 使用者会看到的变化
|
|
10
|
+
|
|
11
|
+
- **req-kit 插件**(`req plugin install`):在 Paseo 的网页端、桌面版和手机上都能用。
|
|
12
|
+
- 侧边栏的"需求":本机所有项目的需求,按"需要你处理、进行中、待测试验证、最近完成"分组,带待处理的数量。
|
|
13
|
+
- 需求详情:每一步的状态、用时和结论(点开进入那个步骤的 agent)、质量门、联合需求的各仓库、用量;可以读需求说明、方案、确认预览、提测说明、完成报告等。
|
|
14
|
+
- 确认方案、停止、继续、开始测试验证:每个都要再确认一次,做的事与终端里的 `req` 命令完全相同。
|
|
15
|
+
- 每个工作区头部的"需求"按钮和面板、步骤 agent 输入框旁的"需求"按钮、使用统计页、Ctrl+K 中的"需求总览"。
|
|
16
|
+
- 插件设置中可以打开"只读",给只看不操作的人用。
|
|
17
|
+
- **安装脚本**最后询问是否安装插件(`--with-plugin` 直接安装,`--no-plugin` 不问;PowerShell 用 `$ReqKitPlugin`)。
|
|
18
|
+
- **修正**:安装脚本判断 Paseo 网页界面是否已开启时,读错了 `paseo daemon config get` 的输出("已设置"被当成"已开启")。
|
|
19
|
+
|
|
20
|
+
### 升级须知
|
|
21
|
+
|
|
22
|
+
- 插件是可选的。安装时会询问是否打开 Paseo 的插件总开关(`pluginsEnabled`):插件是不受沙箱限制的代码;req-kit 插件只运行本机的 `req api`,不连接外部服务。
|
|
23
|
+
- 装过插件后,`req setup`、`req upgrade`、`req use` 会自动把插件换成启用的版本。插件随 req-kit 一起发布,不需要单独的 npm 包。
|
|
24
|
+
- 需要 Paseo 0.11。1.9 之前运行过的需求,先在项目目录运行一次 `req index --rebuild`。设计决定见 ADR 0027。
|
|
25
|
+
|
|
26
|
+
## 1.9.0-beta.1
|
|
27
|
+
|
|
28
|
+
1.9 的基础:本机知道自己有哪些需求,记下每次运行的用时和用量,并给程序一个稳定的读取接口。插件(beta.2)和外部系统集成(beta.3)都建在它上面。
|
|
29
|
+
|
|
30
|
+
### 使用者会看到的变化
|
|
31
|
+
|
|
32
|
+
- **使用统计 `req stats`**:在任何目录运行,看本机最近 30 天(`--since`、`--month 2026-10`)的统计:有进展和完成的需求数、交付周期、返工(评审轮数、需要缺陷修复的占比、质量门失败次数)、等待确认和等待决定的时长、各步骤用时、token 用量和费用、不同 builder 的比较。
|
|
33
|
+
- **给管理方的汇报**:`req stats --report --month 2026-10` 生成汇总(`.md`)和每个需求一行的明细(`.csv`,可以用表格软件打开)。几台机器一起汇报时,每台 `req stats --month 2026-10 --export`,再在一处 `req stats --merge <文件…> --month 2026-10 --report`。
|
|
34
|
+
- **本机的需求索引**:运行过的需求会登记在本机,`req index` 查看。1.9 之前运行过的需求在项目目录运行一次 `req index --rebuild` 补登;`req index --prune` 清理目录已不在的。
|
|
35
|
+
- **`req api`**:给程序用的 JSON 输出:列出本机或当前仓库的需求、一个需求的步骤和质量门、读取功能目录中的文档、统计,以及确认方案、停止、继续、开始测试验证这几个管理操作。Paseo 插件将通过它工作。格式见 `contracts/cli-json.md`。
|
|
36
|
+
|
|
37
|
+
### 升级须知
|
|
38
|
+
|
|
39
|
+
- 新增本机文件:`~/.req-kit/index/`(每个需求一个小文件)和 `~/.req-kit/usage/runs.jsonl`(每次运行一行)。只在本机,不记需求内容和代码,不会自动发往任何地方。不想记录时设置环境变量 `REQ_KIT_NO_RECORD=1`。
|
|
40
|
+
- 统计只从升级后的运行开始;之前的运行没有记录。
|
|
41
|
+
- 状态文件、结果文件和提示词都没有变化。设计决定见 ADR 0026。
|
|
42
|
+
|
|
5
43
|
## 1.8.0
|
|
6
44
|
|
|
7
45
|
第一个正式版。汇总 1.8.0-beta.1 到 beta.3 的全部内容(各节见下),并让新机器一条命令就能从零用起来。
|
package/README.md
CHANGED
|
@@ -74,6 +74,8 @@ irm https://paseo-req-kit.vercel.app/install.ps1 | iex
|
|
|
74
74
|
2. 在项目的 Paseo 对话中运行 `/req-setup` —— 接入项目(每个项目一次);
|
|
75
75
|
3. 在 Paseo 对话中输入 `/req 我想……` —— 开始第一个需求。
|
|
76
76
|
|
|
77
|
+
想在 Paseo 的界面(网页端、桌面版、手机)里看需求总览和进度、确认方案或停止继续,运行 `req plugin install` 安装 req-kit 的 Paseo 插件。
|
|
78
|
+
|
|
77
79
|
其他安装方式(npm、离线安装包、git)、各 agent 的配置写法和升级回滚,见 [安装与升级](docs/guide/安装与升级.md)。
|
|
78
80
|
|
|
79
81
|
## 工作原理
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// `req plugin`: the req-kit plugin for Paseo (1.9, ADR 0027).
|
|
2
|
+
//
|
|
3
|
+
// req plugin install [--yes] copy the plugin to <kit home>/paseo-plugin and install it in Paseo
|
|
4
|
+
// req plugin status whether it is installed and running
|
|
5
|
+
// req plugin remove remove it from Paseo
|
|
6
|
+
//
|
|
7
|
+
// The plugin ships inside this package (paseo-plugin/). It is installed from a fixed copy under
|
|
8
|
+
// the kit home, so upgrading or switching req-kit versions only refreshes that copy and reloads
|
|
9
|
+
// the plugin (refreshPlugin, called by install.mjs); the plugin always matches the active version.
|
|
10
|
+
// Turning on Paseo's plugin switch (pluginsEnabled) needs the person's consent: plugins run
|
|
11
|
+
// unsandboxed on this machine.
|
|
12
|
+
import { spawnSync } from "node:child_process";
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import readline from "node:readline";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
|
|
19
|
+
export const PLUGIN_ID = "req-kit";
|
|
20
|
+
const KIT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
21
|
+
|
|
22
|
+
export function kitHome(env = process.env) {
|
|
23
|
+
const override = env.REQ_KIT_HOME?.trim();
|
|
24
|
+
return override ? path.resolve(override) : path.join(os.homedir(), ".req-kit");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function stagedDir(home = kitHome()) {
|
|
28
|
+
return path.join(home, "paseo-plugin");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Copies this version's plugin to the fixed directory Paseo installs from. */
|
|
32
|
+
export function stagePlugin(kitRoot = KIT_ROOT, home = kitHome()) {
|
|
33
|
+
const from = path.join(kitRoot, "paseo-plugin");
|
|
34
|
+
if (!fs.existsSync(path.join(from, "paseo-plugin.json"))) throw new Error(`这个版本的 req-kit 没有附带 Paseo 插件(${from})`);
|
|
35
|
+
const to = stagedDir(home);
|
|
36
|
+
fs.rmSync(to, { recursive: true, force: true });
|
|
37
|
+
fs.cpSync(from, to, {
|
|
38
|
+
recursive: true,
|
|
39
|
+
filter: (src) => !path.relative(from, src).split(path.sep).includes("node_modules"),
|
|
40
|
+
});
|
|
41
|
+
return to;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The paseo command: REQ_KIT_PASEO_BIN (tests; empty means none), else paseo on PATH. */
|
|
45
|
+
function paseoCommand(env = process.env) {
|
|
46
|
+
if (env.REQ_KIT_PASEO_BIN !== undefined) return env.REQ_KIT_PASEO_BIN || null;
|
|
47
|
+
const cmd = process.platform === "win32" ? "paseo.cmd" : "paseo";
|
|
48
|
+
return run(cmd, ["--version"], 30_000, env).status === 0 ? cmd : null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// A .cmd shim on Windows only runs through the shell; quote what the shell would split.
|
|
52
|
+
const WINDOWS = process.platform === "win32";
|
|
53
|
+
const quote = (a) => (WINDOWS && /[\s"&|<>^]/.test(a) ? `"${a.replace(/"/g, '""')}"` : a);
|
|
54
|
+
|
|
55
|
+
function run(cmd, args, timeout, env = process.env) {
|
|
56
|
+
return spawnSync(WINDOWS ? quote(cmd) : cmd, WINDOWS ? args.map(quote) : args, { encoding: "utf8", windowsHide: true, timeout, shell: WINDOWS, env });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function paseo(cmd, args, env = process.env) {
|
|
60
|
+
const r = run(cmd, args, 180_000, env);
|
|
61
|
+
let json = null;
|
|
62
|
+
try {
|
|
63
|
+
json = JSON.parse((r.stdout ?? "").trim());
|
|
64
|
+
} catch {
|
|
65
|
+
json = null;
|
|
66
|
+
}
|
|
67
|
+
return { ok: r.status === 0, json, text: `${r.stdout ?? ""}${r.stderr ?? ""}`.trim() };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function pluginEntry(cmd, env = process.env) {
|
|
71
|
+
const r = paseo(cmd, ["plugin", "ls", "--json"], env);
|
|
72
|
+
if (!r.ok) return { error: r.text };
|
|
73
|
+
const list = Array.isArray(r.json) ? r.json : Array.isArray(r.json?.data) ? r.json.data : [];
|
|
74
|
+
return { entry: list.find((p) => p.id === PLUGIN_ID) ?? null };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function pluginsEnabled(cmd, env = process.env) {
|
|
78
|
+
const r = paseo(cmd, ["daemon", "config", "get", "pluginsEnabled", "--json"], env);
|
|
79
|
+
const value = r.json?.value ?? r.json?.data?.value;
|
|
80
|
+
return value === true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function ask(question) {
|
|
84
|
+
if (!process.stdin.isTTY) return Promise.resolve(false);
|
|
85
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
86
|
+
return new Promise((resolve) =>
|
|
87
|
+
rl.question(question, (answer) => {
|
|
88
|
+
rl.close();
|
|
89
|
+
resolve(/^(y|yes|是|好|可以)$/i.test(answer.trim()));
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const say = (s) => console.log(s);
|
|
95
|
+
|
|
96
|
+
function manualSteps(dir) {
|
|
97
|
+
say("也可以在 Paseo 中手动安装:");
|
|
98
|
+
say(" 1. 设置 → Plugins → 打开 Enable plugins(插件是不受限制的代码,可以访问这台机器上的文件和进程)");
|
|
99
|
+
say(` 2. 在 Plugin source 中填:${dir}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function installPlugin({ yes = false, env = process.env, kitRoot = KIT_ROOT } = {}) {
|
|
103
|
+
const dir = stagePlugin(kitRoot, kitHome(env));
|
|
104
|
+
say(`插件文件:${dir}`);
|
|
105
|
+
const cmd = paseoCommand(env);
|
|
106
|
+
if (!cmd) {
|
|
107
|
+
say("没有找到 paseo 命令(桌面版 Paseo 管理的 daemon 通常没有)。");
|
|
108
|
+
manualSteps(dir);
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
if (!pluginsEnabled(cmd, env)) {
|
|
112
|
+
say("");
|
|
113
|
+
say("Paseo 的插件总开关(pluginsEnabled)是关着的。");
|
|
114
|
+
say("插件是受信任、不受沙箱限制的代码:它的后台部分可以访问这台机器上的文件、进程和网络。");
|
|
115
|
+
say("req-kit 插件只运行本机的 req 命令,不连接任何外部服务。");
|
|
116
|
+
const agreed = yes || (await ask("打开 Paseo 的插件总开关并安装 req-kit 插件?[y/N] "));
|
|
117
|
+
if (!agreed) {
|
|
118
|
+
say("没有安装。之后可以运行 req plugin install(或加 --yes)。");
|
|
119
|
+
manualSteps(dir);
|
|
120
|
+
return 1;
|
|
121
|
+
}
|
|
122
|
+
const set = paseo(cmd, ["daemon", "config", "set", "pluginsEnabled", "true", "--json"], env);
|
|
123
|
+
if (!set.ok) {
|
|
124
|
+
say(`没能打开插件总开关:${set.text}`);
|
|
125
|
+
manualSteps(dir);
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
say("✓ 已打开 Paseo 的插件总开关");
|
|
129
|
+
}
|
|
130
|
+
const found = pluginEntry(cmd, env);
|
|
131
|
+
if (found.error) {
|
|
132
|
+
say(`读取不了 Paseo 的插件列表:${found.error}`);
|
|
133
|
+
say("请确认 Paseo daemon 在运行(paseo daemon status)。");
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
const r = found.entry ? paseo(cmd, ["plugin", "reload", PLUGIN_ID, "--json"], env) : paseo(cmd, ["plugin", "install", dir, "--json"], env);
|
|
137
|
+
if (!r.ok) {
|
|
138
|
+
say(`${found.entry ? "重新加载" : "安装"}失败:${r.text}`);
|
|
139
|
+
say(`查看插件输出:paseo plugin logs ${PLUGIN_ID}`);
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
const after = pluginEntry(cmd, env).entry;
|
|
143
|
+
if (after?.status === "running") {
|
|
144
|
+
say(`✓ req-kit 插件${found.entry ? "已更新" : "已安装"},正在运行。在 Paseo 侧边栏中点"需求"打开。`);
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
say(`插件状态:${after?.status ?? "未知"}${after?.error ? `(${after.error})` : ""}。查看输出:paseo plugin logs ${PLUGIN_ID}`);
|
|
148
|
+
return 1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function pluginStatus({ env = process.env } = {}) {
|
|
152
|
+
const dir = stagedDir(kitHome(env));
|
|
153
|
+
const staged = fs.existsSync(path.join(dir, "package.json")) ? JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8")).version : null;
|
|
154
|
+
say(staged ? `插件文件:${dir}(版本 ${staged})` : "还没有准备插件文件:运行 req plugin install");
|
|
155
|
+
const cmd = paseoCommand(env);
|
|
156
|
+
if (!cmd) {
|
|
157
|
+
say("没有找到 paseo 命令,无法查看 Paseo 中的状态(在 Paseo 的 设置 → Plugins 中查看)。");
|
|
158
|
+
return staged ? 0 : 1;
|
|
159
|
+
}
|
|
160
|
+
const found = pluginEntry(cmd, env);
|
|
161
|
+
if (found.error) {
|
|
162
|
+
say(`读取不了 Paseo 的插件列表:${found.error}`);
|
|
163
|
+
return 1;
|
|
164
|
+
}
|
|
165
|
+
if (!found.entry) {
|
|
166
|
+
say("Paseo 中没有安装 req-kit 插件:运行 req plugin install");
|
|
167
|
+
return 1;
|
|
168
|
+
}
|
|
169
|
+
say(`Paseo 中的 req-kit 插件:${found.entry.status}${found.entry.error ? `(${found.entry.error})` : ""}`);
|
|
170
|
+
if (!pluginsEnabled(cmd, env)) say("注意:Paseo 的插件总开关是关着的(设置 → Plugins → Enable plugins)。");
|
|
171
|
+
return found.entry.status === "running" ? 0 : 1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function removePlugin({ env = process.env } = {}) {
|
|
175
|
+
const cmd = paseoCommand(env);
|
|
176
|
+
if (cmd) {
|
|
177
|
+
const found = pluginEntry(cmd, env);
|
|
178
|
+
if (found.entry) {
|
|
179
|
+
const r = paseo(cmd, ["plugin", "remove", PLUGIN_ID, "--json"], env);
|
|
180
|
+
if (!r.ok) {
|
|
181
|
+
say(`移除失败:${r.text}`);
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
say("✓ 已从 Paseo 移除 req-kit 插件(Paseo 的插件总开关保持原样)");
|
|
185
|
+
} else say("Paseo 中没有安装 req-kit 插件");
|
|
186
|
+
} else say("没有找到 paseo 命令:请在 Paseo 的 设置 → Plugins 中移除 req-kit。");
|
|
187
|
+
fs.rmSync(stagedDir(kitHome(env)), { recursive: true, force: true });
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* After a version becomes active (req setup, upgrade, use): if the plugin was installed,
|
|
193
|
+
* refresh its files from that version and reload it. Quiet and best effort.
|
|
194
|
+
*/
|
|
195
|
+
export function refreshPlugin({ kitRoot = KIT_ROOT, env = process.env, log = () => {} } = {}) {
|
|
196
|
+
const home = kitHome(env);
|
|
197
|
+
if (!fs.existsSync(path.join(stagedDir(home), "paseo-plugin.json"))) return false;
|
|
198
|
+
try {
|
|
199
|
+
stagePlugin(kitRoot, home);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
log(`没能更新 Paseo 插件的文件:${error.message}`);
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
const cmd = paseoCommand(env);
|
|
205
|
+
const r = cmd ? paseo(cmd, ["plugin", "reload", PLUGIN_ID, "--json"], env) : null;
|
|
206
|
+
log(r?.ok ? "Paseo 插件已更新到这个版本" : `Paseo 插件的文件已更新;在 Paseo 中重新加载它:paseo plugin reload ${PLUGIN_ID}(或 设置 → Plugins)`);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
211
|
+
const [sub = "status", ...rest] = process.argv.slice(2);
|
|
212
|
+
let code;
|
|
213
|
+
try {
|
|
214
|
+
if (sub === "install") code = await installPlugin({ yes: rest.includes("--yes") || rest.includes("-y") });
|
|
215
|
+
else if (sub === "status") code = pluginStatus();
|
|
216
|
+
else if (sub === "remove" || sub === "uninstall") code = removePlugin();
|
|
217
|
+
else {
|
|
218
|
+
console.error(`没有 "${sub}" 这个子命令。可用:req plugin install [--yes]、req plugin status、req plugin remove`);
|
|
219
|
+
code = 2;
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error(error.message);
|
|
223
|
+
code = 1;
|
|
224
|
+
}
|
|
225
|
+
process.exit(code);
|
|
226
|
+
}
|
package/bin/req.mjs
CHANGED
|
@@ -30,6 +30,21 @@ const HELP = `req-kit ${version}(${kitRoot})
|
|
|
30
30
|
req digest --schedule "0 9 * * 1"
|
|
31
31
|
让 Paseo 按时间表发送需求总览(例子为每周一 9:00);取消:req digest --cancel <ID>
|
|
32
32
|
|
|
33
|
+
使用情况(可以在任何目录运行):
|
|
34
|
+
req stats [--since 30d] [--month 2026-10]
|
|
35
|
+
本机的使用统计:需求数、交付周期、返工、等待、各步骤用时、用量
|
|
36
|
+
req stats --report [--out 目录]
|
|
37
|
+
生成汇报用的汇总(.md)和每个需求一行的表格(.csv)
|
|
38
|
+
req stats --export [文件] 导出本机的运行记录;汇总多台机器:req stats --merge <文件…> --report
|
|
39
|
+
req index [--rebuild [目录…]] [--prune]
|
|
40
|
+
本机记录的需求(Paseo 插件据此找到所有需求);1.9 之前运行过的用 --rebuild 补登
|
|
41
|
+
req api <命令> … 给程序用的 JSON 输出(见 contracts/cli-json.md)
|
|
42
|
+
|
|
43
|
+
Paseo 插件(在 Paseo 中查看和管理需求):
|
|
44
|
+
req plugin install [--yes] 安装或更新插件;需要时会询问是否打开 Paseo 的插件总开关
|
|
45
|
+
req plugin status 插件是否在运行
|
|
46
|
+
req plugin remove 从 Paseo 移除插件
|
|
47
|
+
|
|
33
48
|
本机维护:
|
|
34
49
|
req doctor [--no-project] 体检:安装、配置、daemon、当前项目
|
|
35
50
|
req configure 配置向导:选择 builder 和 reviewer 用的 agent
|
|
@@ -156,6 +171,18 @@ switch (command) {
|
|
|
156
171
|
case "digest":
|
|
157
172
|
code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "digest.ts"), ...rest]) : 1;
|
|
158
173
|
break;
|
|
174
|
+
case "stats":
|
|
175
|
+
code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "stats.ts"), ...rest]) : 1;
|
|
176
|
+
break;
|
|
177
|
+
case "index":
|
|
178
|
+
code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "index-cmd.ts"), ...rest]) : 1;
|
|
179
|
+
break;
|
|
180
|
+
case "api":
|
|
181
|
+
code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "api.ts"), ...rest]) : 1;
|
|
182
|
+
break;
|
|
183
|
+
case "plugin":
|
|
184
|
+
code = node([path.join(kitRoot, "bin", "req-plugin.mjs"), ...rest]);
|
|
185
|
+
break;
|
|
159
186
|
case "notify-test":
|
|
160
187
|
code = needTsx() ? node([tsxCli, path.join(kitRoot, "engine", "src", "notify-test.ts"), ...rest]) : 1;
|
|
161
188
|
break;
|
package/contracts/README.md
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
| `decisions.tsv`、`changes.md`、`acceptance.md` 与需求总览 | [feature-files.md](feature-files.md) | 见各文件说明 |
|
|
11
11
|
| `.requirement-pipeline/verify.md` | [verify.md](verify.md) | 自由格式,建议结构见文件 |
|
|
12
12
|
| 外部通知(企业 IM 等)收到的事件 | [notifier-event.md](notifier-event.md) | `schema: 1` |
|
|
13
|
+
| `req api` 的输出(Paseo 插件等程序读取) | [cli-json.md](cli-json.md) | `schema: 1` |
|
|
14
|
+
| `~/.req-kit/index/`、`~/.req-kit/usage/runs.jsonl` | [usage-record.md](usage-record.md) | `schema: 1` |
|
|
13
15
|
|
|
14
16
|
格式版本的规则:
|
|
15
17
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 给程序用的 JSON 输出:`req api`
|
|
2
|
+
|
|
3
|
+
1.9.0 起。Paseo 插件和其他程序通过 `req api` 读取需求、执行管理操作,不直接读写状态文件。每个命令输出一行 JSON:
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{ "schema": 1, "kitVersion": "1.9.0", "data": … }
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
出错时退出码为 1:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{ "schema": 1, "kitVersion": "1.9.0", "error": { "code": "not_found", "message": "没有找到需求……" } }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`code`:`bad_arguments`(参数不对)、`not_found`(目录或需求不存在)、`not_allowed`(不允许的文件或命令)、`failed`(其他错误)。
|
|
16
|
+
|
|
17
|
+
`schema` 只在不兼容的修改时增加;新增字段不改变 `schema`,读取方应忽略不认识的字段。
|
|
18
|
+
|
|
19
|
+
## 命令
|
|
20
|
+
|
|
21
|
+
| 命令 | `data` |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `req api version` | `{ kitVersion, kitRoot, apiSchema, paseo, featuresDir }`:`paseo` 是这个版本支持的 Paseo 范围 |
|
|
24
|
+
| `req api list [--repo <目录>]` | 这个仓库所有工作区中的需求,数组,每项见下面的"需求" |
|
|
25
|
+
| `req api list --all` | 本机记录过的所有需求([需求索引](usage-record.md)),同上;目录已不在的 `present: false` |
|
|
26
|
+
| `req api status <需求> [--repo <目录>]` | 一个需求的详情,见下面的"详情" |
|
|
27
|
+
| `req api file <需求> <文件> [--repo <目录>]` | `{ featureDir, file, size, truncated, content }`;只能读取功能目录中的文档(见下),最多 512 KB |
|
|
28
|
+
| `req api stats [--since 30d] [--month 2026-10]` | `req stats --json` 的内容,见 [使用记录](usage-record.md) |
|
|
29
|
+
| `req api index [--rebuild <目录>…] [--prune]` | 不带选项:索引的全部条目;`--rebuild`:`{ scanned, registered, pruned, total }` |
|
|
30
|
+
| `req api run <approve\|stop\|resume\|verify> <需求> [--repo <目录>] [选项]` | `{ command, featureDir, ok, exitCode, message }`。在 `--repo`(默认当前目录)中执行与 `req <命令> <需求>` 完全相同的操作;`ok` 为 false 时退出码为 1 |
|
|
31
|
+
|
|
32
|
+
`<需求>` 的写法与 `req status` 相同:功能目录、目录名或名称中能唯一确定的一部分。需求在为它新建的工作区中开发时,`--repo` 写对话所在的目录或那个工作区都可以。
|
|
33
|
+
|
|
34
|
+
`req api file` 能读取的文件:`spec.md`、`alignment.md`、`spec-review.md`、`changes.md`、`decisions.tsv`、`design.md`、`design-review.md`、`preview.md`、`contract.md`、`diagnosis.md`、`assessment.md`、`implementation.md`、`progress.md`、`code-review.md`、`handoff.md`、`service-start.md`、`verification.md`、`report.md`、`acceptance.md`、`lessons.tsv`。
|
|
35
|
+
|
|
36
|
+
## 需求(`list` 的每一项)
|
|
37
|
+
|
|
38
|
+
| 字段 | 含义 |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `key` | 需求在本机的标识(对话所在目录 + 功能目录) |
|
|
41
|
+
| `project` | 项目名:对话所在目录的目录名 |
|
|
42
|
+
| `repo` | 需求所在的目录(有自己的工作区时是那个工作区) |
|
|
43
|
+
| `sourceRepo` / `workspaceId` | 有自己的工作区时:对话所在的目录、Paseo 工作区 ID;否则 null |
|
|
44
|
+
| `featureDir` / `name` / `title` | 功能目录、目录名、需求标题 |
|
|
45
|
+
| `type` / `profile` / `branch` | 需求类型(`defect`、`refactor`、`assessment` 或 null)、档位、分支 |
|
|
46
|
+
| `stage` | 与 `req list` 相同的阶段说明,如"开发中""等待确认方案""待验收" |
|
|
47
|
+
| `status` | 状态文件的 `status`;还没运行过为 null |
|
|
48
|
+
| `running` | 后台进程是否在运行 |
|
|
49
|
+
| `phase` | `develop` / `verify` |
|
|
50
|
+
| `attention` | 需要人处理的事:`approval`(确认方案)、`business`(需求方决定)、`interrupted`(中断,可以继续)、`not_completed`(结束但未完成);没有为 null |
|
|
51
|
+
| `current` | 正在运行的步骤 `[{ key, title, agentId }]` |
|
|
52
|
+
| `updatedAt` | 最近一次变化的时间 |
|
|
53
|
+
| `usage` | `{ steps, agentMinutes, inputTokens, outputTokens, costUsd }`;没运行过为 null |
|
|
54
|
+
| `present` | 目录是否还在 |
|
|
55
|
+
|
|
56
|
+
## 详情(`status`)
|
|
57
|
+
|
|
58
|
+
"需求"的全部字段,另加:
|
|
59
|
+
|
|
60
|
+
| 字段 | 含义 |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `files` | 功能目录中存在的、可以用 `req api file` 读取的文件 |
|
|
63
|
+
| `run` | `{ attempt, startedAt, updatedAt, pid, phaseMode, stopReason, outcome, queuedSince, verifyAt, approval, originAgentId }`;没运行过为 null |
|
|
64
|
+
| `steps` | 每个步骤一项:`{ key, stepId, title, phase, attempt, round, agentId, startedAt, endedAt, minutes, outcome, result, error, usage }`;`title` 是给人看的名称(如"代码评审(第 2 轮)"),`result` 是结论的文字(如"需要修改") |
|
|
65
|
+
| `gate` | 质量门:状态文件中的 `gate` |
|
|
66
|
+
| `joint` | 联合需求的其他仓库:`[{ name, slug, repo, sourceRepo, branch, workspaceId, gate }]` |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 本机的需求索引与使用记录
|
|
2
|
+
|
|
3
|
+
1.9.0 起,引擎在本机配置目录(默认 `~/.req-kit`,可用 `REQ_KIT_HOME` 改变)下记两样东西。它们只在这台机器上,不提交进任何仓库,也不会自动发往任何地方。环境变量 `REQ_KIT_NO_RECORD=1` 时两样都不记(评估运行就是这样)。
|
|
4
|
+
|
|
5
|
+
## 需求索引 `index/<key>.json`
|
|
6
|
+
|
|
7
|
+
每个在本机运行过的需求一个文件,记录它在哪里,供 `req api list --all` 和 Paseo 插件找到本机所有的需求。需求的阶段、进度仍然现场从功能目录读取(ADR 0010)。
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"schema": 1,
|
|
12
|
+
"key": "3f2a9c1e5b7d4e8a",
|
|
13
|
+
"repo": "/home/me/work/shop-sms-login",
|
|
14
|
+
"featureDir": "docs/features/20261012-sms-login",
|
|
15
|
+
"sourceRepo": "/home/me/work/shop",
|
|
16
|
+
"workspaceId": "ws_123",
|
|
17
|
+
"project": "shop",
|
|
18
|
+
"registeredAt": "2026-10-12T09:00:00.000Z"
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`key` 由对话所在的目录(没有自己的工作区时即 `repo`)和功能目录算出。`req index --rebuild` 为 1.9 之前运行过的需求补登,`req index --prune` 移除目录已不在的。
|
|
23
|
+
|
|
24
|
+
## 使用记录 `usage/runs.jsonl`
|
|
25
|
+
|
|
26
|
+
每次流水线运行(后台进程从开始到结束,包括停在等待确认、等待需求方、研发完成处)结束时追加一行:
|
|
27
|
+
|
|
28
|
+
| 字段 | 含义 |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `schema` / `kind` | `1` / `"run"` |
|
|
31
|
+
| `machine` / `kitVersion` | 主机名、req-kit 版本 |
|
|
32
|
+
| `requirement` | `{ key, project, name, title, type, profile }` |
|
|
33
|
+
| `run` | `{ startedAt, endedAt, attempt, phase, phaseMode, status, outcome, stopReason }`;`status` 是运行结束时的状态,`outcome` 是完成时报告的结论 |
|
|
34
|
+
| `agents` | `{ builder, reviewer }`:当时配置的 agent(如 `claude/opus(bypassPermissions)`) |
|
|
35
|
+
| `steps` | 这次运行中开始的步骤:`{ key, stepId, phase, attempt, round, startedAt, endedAt, minutes, outcome, inputTokens, outputTokens, costUsd }`;agent 没有报告的用量为 null |
|
|
36
|
+
| `gate` | `{ runs, failed }`:这次运行中质量门运行的次数、发现新失败的次数 |
|
|
37
|
+
|
|
38
|
+
不记录需求内容、代码和对话。
|
|
39
|
+
|
|
40
|
+
## 统计口径(`req stats`)
|
|
41
|
+
|
|
42
|
+
- 一段时间的用量、步骤用时:结束时间在这段时间内的运行。
|
|
43
|
+
- 交付周期:需求第一次开始到完成(最后一次运行以"已完成"结束)的小时数,用这个需求的全部运行,算在完成的那段时间。
|
|
44
|
+
- 代码评审轮数、缺陷修复轮数:不同的(尝试、轮次、仓库)个数;评审分方向或评审小组的几个成员算一轮。
|
|
45
|
+
- 等待:相邻两次运行之间的间隔,按前一次结束时的状态归类:等待确认方案、等待需求方决定、研发完成到开始测试验证、中断到继续。
|
|
46
|
+
- 合并多台机器的导出时,同一机器、同一需求、同一开始时间的运行只算一次。
|
|
47
|
+
|
|
48
|
+
`req stats --json` 和 `req api stats` 输出同样的对象(`schema: 1`):`period`、`machines`、`active`、`completed`、`byType`、`cycleHours`、`steps`、`rework`、`waits`、`usage`、`byBuilder`、`requirements`(每个需求一项,字段与 `req stats --csv` 的列对应)。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 0026 本机的需求索引、使用记录和 req api
|
|
2
|
+
|
|
3
|
+
- 状态:已采纳(补充 [0010](0010-generated-feature-overview.md):仓库内的总览仍现场生成;[0014](0014-notifier-slot.md):通知槽不变)
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
1.9 要做两件依赖同一份数据的事:Paseo 插件在网页端列出本机所有项目的需求、做确认和停止这类管理操作;管理方要定期看到 req-kit 的使用情况(多少需求、多快、返工多少、花了多少)。在此之前,需求的状态分散在各仓库各工作区的功能目录里,`req list` 只看得到当前仓库;用时和用量只在每个需求的状态文件中,没有跨需求的汇总;`req list`、`req status` 只输出给人看的文字,程序要用只能解析文字或直接读状态文件,后者把状态文件的内部格式变成了对外约定。
|
|
8
|
+
|
|
9
|
+
## 决定
|
|
10
|
+
|
|
11
|
+
- **需求索引**:引擎每次写状态文件时,确认本机配置目录下的 `index/<key>.json` 记着这个需求在哪里(目录、功能目录、对话所在目录、工作区),一个需求一个文件,几个流水线同时运行也不会互相覆盖。索引只记位置,阶段和进度仍然现场从功能目录读取,所以不会和实际情况不一致。
|
|
12
|
+
- **使用记录**:每次运行(后台进程从开始到结束)结束时向 `usage/runs.jsonl` 追加一行:步骤、用时、用量、质量门、结束时的状态。按运行而不是按需求记,追加即可,不用改写旧记录;需求层面的数字(交付周期、评审轮数、等待时长)在统计时从同一需求的各次运行算出。
|
|
13
|
+
- **只在本机,不自动上报**:两样都不提交进仓库,也不发往任何地方;不记需求内容和代码。汇总给管理方时由人导出(`req stats --export`)再合并(`--merge`);之后定下汇总通道时,用 1.9 的集成模块订阅"运行结束",数据格式不变。
|
|
14
|
+
- **`req stats`**:Markdown 汇总、JSON、每个需求一行的 CSV,`--report` 生成汇报用的两份文件。
|
|
15
|
+
- **`req api`**:给程序的稳定接口,一行 JSON,带 `schema`。读操作(list、status、file、stats、index)不改变任何东西;管理操作 `req api run <approve|stop|resume|verify>` 就是在相应目录执行 `req <命令>`,引擎仍是唯一修改状态的一方。`file` 只能读功能目录中的文档白名单。
|
|
16
|
+
- **评估和测试不进记录**:`REQ_KIT_NO_RECORD=1` 关闭记录,评估运行设置它;测试把本机配置目录指向临时目录。
|
|
17
|
+
|
|
18
|
+
## 影响
|
|
19
|
+
|
|
20
|
+
- 插件和脚本只依赖 `contracts/cli-json.md`,状态文件的内部格式可以继续演进。
|
|
21
|
+
- 1.9 之前运行过的需求不在索引里,需要 `req index --rebuild` 补登;删掉的目录在索引里显示为"已移除",`--prune` 清理。
|
|
22
|
+
- 记录是尽力而为的:写失败不影响流水线,被强制结束(kill -9、断电)的运行没有记录,统计会少算这次运行。
|
|
23
|
+
- 主机名写进每条记录,用于合并多台机器的数据时区分来源。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 0027 Paseo 插件:随 req-kit 一起发布,只通过 req api 工作
|
|
2
|
+
|
|
3
|
+
- 状态:已采纳(建立在 [0026](0026-machine-records-and-api.md) 的需求索引和 `req api` 之上;不改变 [0003](0003-script-engine-not-hub.md):流程仍由脚本引擎驱动)
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
需求方和项目经理想在 Paseo 的网页端或手机上看到所有需求在哪一步、卡在哪里,并做确认方案、停止、继续这类操作,而不是在对话里问或在终端敲 `req`。Paseo 0.11 有完整的插件机制:界面(侧边栏、页面、工作区面板、按钮、命令中心)、daemon 侧的 RPC 和生命周期事件,同一份界面代码在桌面版、网页端和手机上运行。
|
|
8
|
+
|
|
9
|
+
## 决定
|
|
10
|
+
|
|
11
|
+
- **插件只做展示和管理,不参与流程**:每个读取是一次 `req api`,每个管理操作是 `req api run <approve|stop|resume|verify>`,与在终端执行 `req <命令>` 完全相同。插件不读写状态文件,引擎仍是唯一修改需求状态的一方。不提供发起需求(需要在对话中对齐)、编辑需求说明或方案、修改配置、删除。
|
|
12
|
+
- **随 req-kit 一起发布,从固定目录安装**:插件源码在仓库的 `paseo-plugin/`,打进 `paseo-req-kit` 包。`req plugin install` 把当前版本的插件复制到 `~/.req-kit/paseo-plugin`,用 `paseo plugin install <目录>` 安装;之后每次启用版本(setup、upgrade、use)都刷新这个目录并 `paseo plugin reload`。这样插件版本总是和启用的 req-kit 一致,也不需要单独的 npm 包、网络或第二套发布配置。设计时曾考虑第二个 npm 包,Paseo 的目录安装让它变得不必要。
|
|
13
|
+
- **插件总开关要人同意**:Paseo 的 `pluginsEnabled` 默认关闭,插件是不受沙箱限制的代码。`req plugin install` 和安装脚本都先说明再询问,`--yes` / `--with-plugin` 表示同意;移除插件不改动总开关。
|
|
14
|
+
- **只读模式**:Paseo 的插件没有按用户区分的权限,能连上 daemon 的人都能操作。插件设置中的"只读"隐藏管理操作,daemon 侧也拒绝它们。
|
|
15
|
+
- **只依赖 `req api` 的格式**:插件通过本机配置目录的 `active.json` 找到启用的版本并运行它的 `req api`,不引用 req-kit 的内部代码;req-kit 太旧时插件给出升级提示。
|
|
16
|
+
- **界面按 Paseo 的跨平台规则写**:只用 React Native 组件和主题颜色,不用 DOM。插件的界面部分由 CI 用 Paseo 的 SDK 做类型检查(`paseo-plugin/` 的开发依赖),daemon 侧和 `req plugin` 有单元测试;界面效果需要在真实的 Paseo 中检查。
|
|
17
|
+
|
|
18
|
+
## 影响
|
|
19
|
+
|
|
20
|
+
- 新增 `req plugin install|status|remove`,安装脚本最后可选安装插件。
|
|
21
|
+
- 列表靠轮询刷新(默认 10 秒,可设置);daemon 侧把短时间内的多个列表请求合并成一次 `req api list`。
|
|
22
|
+
- 步骤 agent 的"需求"按钮靠 req-kit 给步骤 agent 打的标签(`requirement-pipeline`)找到需求;工作区的"需求"按钮按目录匹配需求。
|
|
23
|
+
- `paseo-plugin/package.json` 的版本必须与 req-kit 相同(测试检查),`paseo-plugin.json` 的 Paseo 范围与 `reqKit.paseo` 相同。
|
package/docs/adr/README.md
CHANGED
|
@@ -27,3 +27,5 @@ req-kit 自身的设计决定。修改其中任何一条,请新增一条 ADR
|
|
|
27
27
|
- [0023 需求类型、质量门、按切片实现](0023-types-gate-slices.md)
|
|
28
28
|
- [0024 让分歧更早暴露:验收例子、方案确认点、两个方向的评审、反复的问题变成规则](0024-confirm-early-review-axes.md)
|
|
29
29
|
- [0025 联合需求:一个需求同时改几个仓库](0025-joint-requirements.md)
|
|
30
|
+
- [0026 本机的需求索引、使用记录和 req api](0026-machine-records-and-api.md)
|
|
31
|
+
- [0027 Paseo 插件:随 req-kit 一起发布,只通过 req api 工作](0027-paseo-plugin.md)
|
|
@@ -60,6 +60,8 @@ req-kit 帮你把一个需求从"我想要……"做到"可以验收":你在 P
|
|
|
60
60
|
|
|
61
61
|
也可以不进对话,在终端里用 `req` 命令(需要开发同事装好并加入 PATH,见 [安装与升级](安装与升级.md)):在项目目录中 `req list` 看所有需求,`req status` 看进度(多个需求时写名称的一部分,如 `req status sms-login`),`req stop`、`req resume` 暂停和继续。
|
|
62
62
|
|
|
63
|
+
装了 req-kit 插件的话(见 [安装与升级](安装与升级.md) 第 13 节),在 Paseo 侧边栏点"需求":本机所有项目的需求一页看完,"需要你处理"的排在最前;点开一个需求能看到每一步的进度和用时、读需求说明、方案、确认预览和完成报告,也可以直接确认方案、停止、继续或开始测试验证。网页端、桌面版和手机上都能用。
|
|
64
|
+
|
|
63
65
|
每个步骤都会出现在这个对话的子 agent 列表里(名字形如"[20261012-sms-login] 6-代码评审 第2轮"),点开可以看到它在做什么。功能目录下的 `progress.md` 按时间记录了每一步的结果。
|
|
64
66
|
|
|
65
67
|
可能收到的通知(团队接入了企业 IM 的话,这些通知也会发到 IM):
|
|
@@ -125,6 +125,8 @@ node install.mjs --configure
|
|
|
125
125
|
| `req upgrade` | 升级到最新版本 |
|
|
126
126
|
| `req notify-test` | 给外部通知发测试消息 |
|
|
127
127
|
| `req digest` | 项目的需求总览;`--notify` 发到外部通知,`--schedule "0 9 * * 1"` 每周一 9 点自动发送 |
|
|
128
|
+
| `req stats` | 本机的使用统计;`--report --month 2026-10` 生成汇报用的文件,`--export` / `--merge` 汇总多台机器 |
|
|
129
|
+
| `req index --rebuild` | 把 1.9 之前运行过的需求登记进本机的需求索引(Paseo 插件据此列出所有需求) |
|
|
128
130
|
|
|
129
131
|
`<需求>` 可以只写名称中能唯一确定的一部分,如 `sms-login`。`req help` 查看全部。不加 PATH 也可以用完整路径 `~/.req-kit/bin/req`(Windows 为 `%USERPROFILE%\.req-kit\bin\req.cmd`)。
|
|
130
132
|
|
|
@@ -355,3 +357,27 @@ node ~/tools/req-kit/versions/<当前版本>/install.mjs --uninstall
|
|
|
355
357
|
|
|
356
358
|
事件的类型和字段见 [contracts/notifier-event.md](../../contracts/notifier-event.md)。通知失败只记日志,不影响流水线。项目配置(`.requirement-pipeline.json`)中的 `notifiers` 会被忽略。
|
|
357
359
|
|
|
360
|
+
## 13. Paseo 插件(可选)
|
|
361
|
+
|
|
362
|
+
1.9 起,req-kit 附带一个 Paseo 插件,把需求搬进 Paseo 的界面(网页端、桌面版、手机都能用):
|
|
363
|
+
|
|
364
|
+
- 侧边栏的"需求":本机所有项目的需求,按"需要你处理、进行中、待测试验证、最近完成"分组,带待处理的数量。
|
|
365
|
+
- 需求详情:每一步的状态、用时和结论(点开即进入那个步骤的 agent)、质量门、联合需求的各仓库、用量;可以读需求说明、方案、确认预览、提测说明、完成报告等文档。
|
|
366
|
+
- 管理操作:确认方案、停止、继续、开始测试验证。每个操作都要再确认一次,做的事和终端里的 `req approve`、`req stop`、`req resume`、`req verify` 完全一样,流水线本身不受插件影响。
|
|
367
|
+
- 每个工作区头部的"需求"按钮和面板、步骤 agent 输入框旁的"需求"按钮、使用统计(同 `req stats`),以及 Ctrl+K(macOS 为 ⌘K)中的"需求总览"。
|
|
368
|
+
|
|
369
|
+
**安装**:在运行 Paseo daemon 的机器上运行
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
req plugin install
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
它把当前版本的插件复制到 `~/.req-kit/paseo-plugin`,再用 Paseo 的命令行安装。Paseo 的插件总开关(`pluginsEnabled`)默认是关着的:插件是不受沙箱限制的代码,后台部分可以访问这台机器上的文件和进程,所以打开前会先问你(`--yes` 表示同意)。req-kit 插件只运行本机的 `req api`,不连接任何外部服务。一键安装脚本在最后也会问一次是否安装(`--with-plugin` 直接安装,`--no-plugin` 不问)。
|
|
376
|
+
|
|
377
|
+
没有 `paseo` 命令时(例如只用桌面版 Paseo),在 Paseo 的 设置 → Plugins 中打开 Enable plugins,再在 Plugin source 中填 `~/.req-kit/paseo-plugin` 的完整路径(运行 `req plugin install` 会准备好这个目录并显示路径)。
|
|
378
|
+
|
|
379
|
+
**更新**:不用单独做。`req setup`、`req upgrade`、`req use` 启用一个版本时,如果装过插件,会把插件文件换成这个版本的并让 Paseo 重新加载,插件总是和启用的 req-kit 版本一致。
|
|
380
|
+
|
|
381
|
+
**只读**:网页端会给只看不操作的人用时,在 Paseo 的 设置 → Plugins → req-kit 中打开"只读":不再显示管理操作,插件的后台也会拒绝它们。能连上这台 daemon 的人都能看到插件,Paseo 的插件没有按用户区分的权限。
|
|
382
|
+
|
|
383
|
+
**其他**:`req plugin status` 看插件是否在运行;`req plugin remove` 从 Paseo 移除(不改插件总开关)。插件需要 req-kit 1.9 和 Paseo 0.11。1.9 之前运行过的需求要先在项目目录运行一次 `req index --rebuild` 才会出现在插件里。插件出问题时:`paseo plugin logs req-kit`。
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
| 入口、手册、方法 skill、原则 | `npm test` + 对话评估中受影响的剧本(`evals/conversation/`) |
|
|
27
27
|
| 安装器 | `npm test`(在临时 HOME 中测试),并在 Windows 上实际装一次 |
|
|
28
28
|
| 评估用例 | `npm run eval:self-check`(参考实现必须通过隐藏验收) |
|
|
29
|
+
| Paseo 插件(`paseo-plugin/`) | `npm test`(插件后台和 `req plugin`);在 `paseo-plugin/` 中 `npm install && npm run typecheck`(CI 的 plugin 任务也会做);用 `req plugin install` 装到一台 Paseo 上,在网页端和手机宽度下看一遍,切换一次深色主题 |
|
|
29
30
|
|
|
30
31
|
提示词改动以评估结果为准:如实率(不夸大)不能下降;隐藏验收通过率、用时、轮次与上一次对比,变差时说明原因。
|
|
31
32
|
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
|
|
61
62
|
没有使用 changesets 等发布工具(见 ADR 0013):发布频率低,CHANGELOG 由人写更贴近使用者。
|
|
62
63
|
|
|
63
|
-
**对外约定**:通知事件(`contracts/notifier-event.md`)由各团队自己的 IM 模块读取,同一 `schema` 内只增加字段;`req`
|
|
64
|
+
**对外约定**:通知事件(`contracts/notifier-event.md`)由各团队自己的 IM 模块读取,同一 `schema` 内只增加字段;`req` 的子命令和参数会被写进各团队的使用说明,改名时保留旧名一个主版本。`req api` 的输出(`contracts/cli-json.md`)是插件和脚本读取的格式,同一 `schema` 内只增加字段。
|
|
64
65
|
|
|
65
66
|
## 5. 处理复盘提交的问题
|
|
66
67
|
|
|
@@ -83,3 +84,4 @@
|
|
|
83
84
|
| `evals/` | 评估:样例仓库、用例、对话剧本 |
|
|
84
85
|
| `contracts/` | 文件格式约定 |
|
|
85
86
|
| `docs/adr/` | 设计决定 |
|
|
87
|
+
| `paseo-plugin/` | Paseo 插件:`client/`(界面,React Native)、`server/`(daemon 侧,运行 `req api`)、`shared/`(RPC 约定)。版本号与根目录的 `package.json` 相同,升版本时两处一起改 |
|
|
@@ -275,6 +275,16 @@ Paseo 自带的 `/paseo-advisor`、`/paseo-committee` 等编排 skill 也可以
|
|
|
275
275
|
|
|
276
276
|
`req digest` 在项目目录中列出所有工作区里的需求,按"需要处理、待验收、开发中、对齐中、已验收(最近 7 天)"分组,附用时与用量。`--notify` 同时发给外部通知(事件类型 `digest`);`--schedule "<cron>"` 让 Paseo 按时间表(本机时区)启动一个短暂的 agent 执行 `req digest --notify`,例如每周一 9 点:`req digest --schedule "0 9 * * 1"`;取消:`req digest --cancel <定时任务 ID>`。
|
|
277
277
|
|
|
278
|
+
## 使用统计
|
|
279
|
+
|
|
280
|
+
1.9.0 起,每次流水线运行结束时,引擎在本机的 `~/.req-kit/usage/runs.jsonl` 追加一条记录:各步骤的用时和用量、质量门、评审和缺陷轮数、结束时的状态(格式见 [使用记录](../../contracts/usage-record.md))。只记在本机,不记需求内容和代码,也不会自动发往任何地方。
|
|
281
|
+
|
|
282
|
+
- `req stats`:最近 30 天的统计(`--since 2w`、`--since 2026-10-01`、`--month 2026-10`):有进展和完成的需求数、交付周期、返工(评审轮数、需要缺陷修复的占比、质量门失败)、各种等待的时长、各步骤用时、用量,以及不同 builder 的比较。`--json`、`--csv` 输出机器可读的格式。
|
|
283
|
+
- `req stats --report --month 2026-10 [--out 目录]`:生成给管理方汇报用的两份文件:`req-kit-usage-2026-10.md`(汇总)和 `.csv`(每个需求一行,可以用表格软件打开)。
|
|
284
|
+
- 几台机器一起汇报:每台机器运行 `req stats --month 2026-10 --export`,得到 `req-kit-usage-<主机名>-<日期>.jsonl`;把这些文件放到一起,运行 `req stats --merge <文件…> --month 2026-10 --report`。
|
|
285
|
+
|
|
286
|
+
本机的需求索引 `~/.req-kit/index/` 记录每个运行过的需求在哪个目录,Paseo 插件据此在一个页面列出本机所有项目的需求。1.9 之前运行过的需求不在索引里,在项目目录运行一次 `req index --rebuild` 补登;目录删掉后用 `req index --prune` 清理。
|
|
287
|
+
|
|
278
288
|
## 团队配置
|
|
279
289
|
|
|
280
290
|
几台机器、多个项目共用的设置(统一的模型、评审小组、超时、要求的 req-kit 版本)可以放在一份团队配置里。把它放进一个团队共用的 git 仓库,各台机器克隆下来,在本机配置 `~/.req-kit/config.json` 中写上它的路径(绝对路径,或相对 `~/.req-kit/` 的路径):
|