@xgent-ai/skills 0.1.0
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/.claude/hooks/xgent-statusline.js +63 -0
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/bin/xgent-skills.js +92 -0
- package/package.json +29 -0
- package/skills/dev-plan/SKILL.md +130 -0
- package/skills/dev-plan/evals/evals.json +72 -0
- package/skills/dev-plan/references/plan-skeleton.md +101 -0
- package/skills/dev-plan/scripts/check_paths.sh +32 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Claude Code Statusline — context-remaining only.
|
|
2
|
+
//
|
|
3
|
+
// Shows nothing but the remaining context budget as a 10-cell bar + percent.
|
|
4
|
+
// Pure Node, no third-party deps. Silent-fails on every error path — must
|
|
5
|
+
// NEVER throw or hang the user terminal.
|
|
6
|
+
|
|
7
|
+
function runStatusline() {
|
|
8
|
+
let input = '';
|
|
9
|
+
// Exit silently on stalled stdin.
|
|
10
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
11
|
+
process.stdin.setEncoding('utf8');
|
|
12
|
+
process.stdin.on('data', (chunk) => {
|
|
13
|
+
input += chunk;
|
|
14
|
+
});
|
|
15
|
+
process.stdin.on('end', () => {
|
|
16
|
+
clearTimeout(stdinTimeout);
|
|
17
|
+
try {
|
|
18
|
+
const data = input ? JSON.parse(input) : {};
|
|
19
|
+
const remaining = data.context_window?.remaining_percentage;
|
|
20
|
+
if (remaining == null) return;
|
|
21
|
+
|
|
22
|
+
// Reserve the auto-compact buffer so the bar reflects *usable* headroom
|
|
23
|
+
// (the same accounting the GSD/gomad statuslines used).
|
|
24
|
+
const totalCtx = data.context_window?.total_tokens || 1_000_000;
|
|
25
|
+
const acw = parseInt(process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW || '0', 10);
|
|
26
|
+
const bufferPct = acw > 0 ? Math.min(100, (acw / totalCtx) * 100) : 16.5;
|
|
27
|
+
|
|
28
|
+
const left = Math.max(
|
|
29
|
+
0,
|
|
30
|
+
Math.min(100, Math.round(((remaining - bufferPct) / (100 - bufferPct)) * 100)),
|
|
31
|
+
);
|
|
32
|
+
// Bar + percent reflect *used* (occupied) share of the usable window.
|
|
33
|
+
const used = 100 - left;
|
|
34
|
+
const filled = Math.floor(used / 10);
|
|
35
|
+
const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
|
|
36
|
+
|
|
37
|
+
// Usable tokens still free (actual remaining minus the reserved
|
|
38
|
+
// auto-compact buffer), shown in K.
|
|
39
|
+
const usableRemaining = Math.max(0, Math.round((totalCtx * (remaining - bufferPct)) / 100));
|
|
40
|
+
const availK = `${Math.round(usableRemaining / 1000)}K available`;
|
|
41
|
+
|
|
42
|
+
// Greener with more headroom; blinking red when nearly out.
|
|
43
|
+
let color;
|
|
44
|
+
let prefix = '';
|
|
45
|
+
if (left > 50) {
|
|
46
|
+
color = '32';
|
|
47
|
+
} else if (left > 35) {
|
|
48
|
+
color = '33';
|
|
49
|
+
} else if (left > 20) {
|
|
50
|
+
color = '38;5;208';
|
|
51
|
+
} else {
|
|
52
|
+
color = '5;31';
|
|
53
|
+
prefix = '💀 ';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
process.stdout.write(`\x1b[${color}m${prefix}${bar} ${used}% ${availK}\x1b[0m`);
|
|
57
|
+
} catch {
|
|
58
|
+
// Silent fail — never break the statusline.
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
runStatusline();
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 XGENT.ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# XGENT Skills
|
|
2
|
+
|
|
3
|
+
XGENT 的 [Agent Skills](https://skills.sh) 集合,可安装到 Claude Code、Cursor、Codex 等支持 skill 的 Agent 中。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
安装全部 skills:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx skills add XGENT-ai/skills
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
只安装指定 skill:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx skills add XGENT-ai/skills --skill dev-plan
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Claude Code 辅助工具
|
|
20
|
+
|
|
21
|
+
本仓库同时以 [`@xgent-ai/skills`](https://www.npmjs.com/package/@xgent-ai/skills) 发布到 npm,自带 `xgent-skills` 命令,可为任意项目安装 XGENT 的 Claude Code hooks(当前包含 statusline)并在项目 `.claude/settings.json` 中启用对应配置:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 在目标项目根目录执行(也可显式传目录:npx @xgent-ai/skills install <dir>)
|
|
25
|
+
npx @xgent-ai/skills install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
安装是幂等的:hook 文件按内容比对,只在有变化时覆盖;`settings.json` 按顶层 key 合并,已有的其他配置保持不动。
|
|
29
|
+
|
|
30
|
+
## Skills 列表
|
|
31
|
+
|
|
32
|
+
| Skill | 说明 |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| [dev-plan](skills/dev-plan/SKILL.md) | 以资深产品经理 + 资深架构师的双重视角,基于当前代码库的真实现状撰写高质量开发计划 |
|
|
35
|
+
|
|
36
|
+
## 目录结构
|
|
37
|
+
|
|
38
|
+
每个 skill 位于 `skills/<name>/` 目录下,包含一个带 `name` 与 `description` frontmatter 的 `SKILL.md`:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
skills/
|
|
42
|
+
└── dev-plan/
|
|
43
|
+
├── SKILL.md # skill 主体(必需)
|
|
44
|
+
├── references/ # 补充参考文档
|
|
45
|
+
├── scripts/ # 辅助脚本
|
|
46
|
+
└── evals/ # 评测用例
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// xgent-skills — 为目标项目安装 XGENT 的 Claude Code hooks 并启用相关 settings。
|
|
3
|
+
// 零依赖,Node >= 18。
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
|
|
10
|
+
const PKG_ROOT = path.join(__dirname, '..');
|
|
11
|
+
const HOOKS_SRC_DIR = path.join(PKG_ROOT, '.claude', 'hooks');
|
|
12
|
+
|
|
13
|
+
// 写入目标项目 .claude/settings.json 的配置,按顶层 key 合并:
|
|
14
|
+
// 这里列出的 key 以本包为准覆盖,其余已有配置保持不动。
|
|
15
|
+
const MANAGED_SETTINGS = {
|
|
16
|
+
statusLine: {
|
|
17
|
+
type: 'command',
|
|
18
|
+
command: 'node "$CLAUDE_PROJECT_DIR/.claude/hooks/xgent-statusline.js"',
|
|
19
|
+
padding: 0,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function usage() {
|
|
24
|
+
console.log(`用法: npx @xgent-ai/skills <command>
|
|
25
|
+
|
|
26
|
+
命令:
|
|
27
|
+
install [dir] 为目标项目(默认当前目录)安装 .claude/hooks 下的全部
|
|
28
|
+
hook,并在 .claude/settings.json 中启用对应配置
|
|
29
|
+
help 显示本帮助
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function install(dirArg) {
|
|
34
|
+
const targetDir = path.resolve(dirArg || process.cwd());
|
|
35
|
+
if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
|
|
36
|
+
console.error(`错误: 目标目录不存在: ${targetDir}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const hooksDestDir = path.join(targetDir, '.claude', 'hooks');
|
|
41
|
+
fs.mkdirSync(hooksDestDir, { recursive: true });
|
|
42
|
+
for (const name of fs.readdirSync(HOOKS_SRC_DIR)) {
|
|
43
|
+
const content = fs.readFileSync(path.join(HOOKS_SRC_DIR, name));
|
|
44
|
+
const dest = path.join(hooksDestDir, name);
|
|
45
|
+
let status = '安装';
|
|
46
|
+
if (fs.existsSync(dest)) {
|
|
47
|
+
status = content.equals(fs.readFileSync(dest)) ? '未变' : '更新';
|
|
48
|
+
}
|
|
49
|
+
if (status !== '未变') {
|
|
50
|
+
fs.writeFileSync(dest, content, { mode: 0o755 });
|
|
51
|
+
}
|
|
52
|
+
console.log(` ${status} .claude/hooks/${name}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const settingsPath = path.join(targetDir, '.claude', 'settings.json');
|
|
56
|
+
let settings = {};
|
|
57
|
+
if (fs.existsSync(settingsPath)) {
|
|
58
|
+
try {
|
|
59
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
60
|
+
} catch {
|
|
61
|
+
console.error(`错误: ${settingsPath} 不是合法 JSON,未修改该文件,请先手动修复。`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const before = JSON.stringify(settings);
|
|
66
|
+
Object.assign(settings, MANAGED_SETTINGS);
|
|
67
|
+
if (JSON.stringify(settings) === before) {
|
|
68
|
+
console.log(' 未变 .claude/settings.json');
|
|
69
|
+
} else {
|
|
70
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
71
|
+
console.log(' 写入 .claude/settings.json (statusLine)');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`完成: ${targetDir}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
78
|
+
switch (cmd) {
|
|
79
|
+
case 'install':
|
|
80
|
+
install(args[0]);
|
|
81
|
+
break;
|
|
82
|
+
case undefined:
|
|
83
|
+
case 'help':
|
|
84
|
+
case '--help':
|
|
85
|
+
case '-h':
|
|
86
|
+
usage();
|
|
87
|
+
break;
|
|
88
|
+
default:
|
|
89
|
+
console.error(`未知命令: ${cmd}\n`);
|
|
90
|
+
usage();
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xgent-ai/skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "XGENT skills 与 Claude Code 辅助工具:通过 npx 为项目安装 hooks 并启用 settings",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"skills",
|
|
8
|
+
"statusline"
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/XGENT-ai/skills.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"bin": {
|
|
16
|
+
"xgent-skills": "bin/xgent-skills.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
".claude/hooks",
|
|
21
|
+
"skills"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-plan
|
|
3
|
+
description: 以资深产品经理 + 资深架构师的双重视角,基于当前代码库的真实现状撰写高质量开发计划。凡用户要求「写开发计划 / 出设计方案 / 做规划 / 立项 / 写 PLAN / 按模板写计划」,或提出一个功能需求并期望得到"先规划、后实施"的可执行方案文档时,务必使用本 skill——即使用户没有明说"计划"二字。Use whenever the user asks for a development plan, design doc, feature proposal, or implementation roadmap that must be grounded in the actual codebase.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dev-plan · 基于代码事实的开发计划撰写
|
|
7
|
+
|
|
8
|
+
## 你的角色与这份文档的命运
|
|
9
|
+
|
|
10
|
+
你同时是**资深产品经理**和**资深架构师**。写出的计划会交给另一个实现者(人或 Agent)在**单一上下文内从头做到验证收尾**——实现期不会回来问你问题,也不该重开设计讨论。所以:
|
|
11
|
+
|
|
12
|
+
- **产品经理视角**负责:需求吃透、范围收敛(敢砍、敢排期)、每条需求有落点或显式排除、实用性优先于炫技。
|
|
13
|
+
- **架构师视角**负责:方案建立在**读过的代码**上而非想象上、复用优先于新造、取舍写明代价、可行性经得起追问、验证与安全从计划期就定义好。
|
|
14
|
+
|
|
15
|
+
**一切失败模式的根源只有一个:计划里出现了没有事实来源的断言。** 每一句"复用 X""参照 Y""Z 已支持"都必须能回溯到:① 用户的原话,或 ② 本次调查中读到的代码/文档(带路径)。做不到就标为开放问题,不许编。
|
|
16
|
+
|
|
17
|
+
## 流程总览
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
0. 定位模板与范例 → 找到项目的计划模板和 2-3 份同类型高质量旧计划
|
|
21
|
+
1. 需求解析与定性 → 逐条编号需求;判定计划类型;识别必须先问的产品决策
|
|
22
|
+
2. 代码事实调查 → (重头戏) 并行调查,产出带路径的《事实清单》
|
|
23
|
+
3. 决策先行 → 先写 §0:决策表 + 关键取舍 + 明确不做
|
|
24
|
+
4. 撰写正文 → 照模板骨架,按类型裁剪
|
|
25
|
+
5. 自检与收尾 → 模板自检清单 + 路径真实性 + 需求映射全覆盖 + 交叉一致性
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
除非用户明确只要"简单聊聊思路",完整走全部六步。步骤 2 绝不可跳过——没有调查的计划就是命题作文。
|
|
29
|
+
|
|
30
|
+
## 第 0 步:定位模板与范例
|
|
31
|
+
|
|
32
|
+
1. **找模板**:依次尝试 ① 用户指定的路径;② `goal/PLAN-TEMPLATE.md`;③ 全仓库 glob `**/PLAN-TEMPLATE*.md`。找到后**通读全文**——模板通常自带元原则、骨架、按类型裁剪指引和写作自检清单,那些就是本 skill 的具体化,以模板为准。
|
|
33
|
+
2. **找不到模板**:用本 skill 自带的通用骨架 `references/plan-skeleton.md`,并向用户说明"项目无计划模板,采用通用骨架"。
|
|
34
|
+
3. **找范例**:在模板同目录(或用户指定的计划目录)里挑 1-2 份**与本次计划同类型**的已完成计划(新独立模块型 / 既有模块增量型 / 纯前端型…),粗读其 §0 与里程碑节,校准"这个项目里的好计划长什么样"——尤其是决策表的颗粒度和验证的写法。模板若点名了样板文档,优先读那几份。
|
|
35
|
+
|
|
36
|
+
## 第 1 步:需求解析与定性
|
|
37
|
+
|
|
38
|
+
1. **逐条编号**用户的原始需求(R1、R2…)。这张清单贯穿始终:最终计划的"需求 → 设计映射"表必须逐条覆盖它,一条都不许吞。用户一句话里往往藏着多条需求,拆开;含糊的地方先记下,带着问题去调查。
|
|
39
|
+
2. **定性计划类型**(新独立模块 / 既有模块增量 / 纯前端 / 平台横切面…),决定骨架怎么裁剪、去读哪份范例、调查往哪个方向使劲。
|
|
40
|
+
3. **识别"必须有人拍板"的产品决策**——真正影响范围与形态、无法从代码或惯例推出的那种(比如"面向管理员还是全员""要不要独立计费")。交互场景下现在就问用户;无法交互则选一个有依据的默认并把它连同理由写进计划的"开放问题"节,**不许默默替用户做重大产品决策而不留痕**。
|
|
41
|
+
|
|
42
|
+
## 第 2 步:代码事实调查(重头戏)
|
|
43
|
+
|
|
44
|
+
写计划前先把地基打在事实上。有子代理(Explore/general-purpose)就**并行**派活,每路带明确问题;仓库小或问题窄时自己搜也行。五路调查:
|
|
45
|
+
|
|
46
|
+
| 路 | 问题 | 产出 |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| **现状盘点** | 与本需求相关的功能现在有什么?(路由、表、UI、服务、配置) | 现有能力清单 + 路径;避免重复造和漏改 |
|
|
49
|
+
| **复用范式** | 全仓库里与要做的东西**最同构的既有实现**是哪个?它的关键文件在哪? | "照抄 `<具体文件路径>` 范式"级别的锚点,而非"参照既有做法" |
|
|
50
|
+
| **上游契约核对** | 本计划要读写的每一个既有模块/服务的接口,现状够不够用? | 每个上游一条:**「已核实(`路径`):零改动」或精确增量清单**——没有第三种状态 |
|
|
51
|
+
| **端口/环境/命名现状** | 端口表、环境变量、命名空间的**当前真值**(读实际配置文件,不信旧文档) | 新增件不与现状冲突的依据 |
|
|
52
|
+
| **已知坑搬运** | memory 目录、CLAUDE.md、旧计划的 PROGRESS/DEFERRED 文档里,与本计划相关的坑 | 一行一坑 + 出处,直接搬进计划的"已知坑"节 |
|
|
53
|
+
|
|
54
|
+
产出一份**《事实清单》**(工作产物,不直接进计划),每条带标签与来源:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
[现状] SPMS issue 表已有 ai_assigned 字段但未使用 (apps/spms-server/src/db/schema.ts)
|
|
58
|
+
[契约·已核实] files-server presign 面覆盖本需求,零改动 (apps/files-server/src/routes/presign.ts)
|
|
59
|
+
[契约·增量] 通知服务缺服务态入口 → 需加 scope 一项 + notify.ts 服务态变体 (P0,漏则 M3 卡死)
|
|
60
|
+
[坑] seed 后租户 UUID 重生成,跨库引用要重解析 (memory: reseed-recovery)
|
|
61
|
+
[开放] 未查到 X 的现有实现;是否自建待产品拍板
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**红线:没读过的代码不许写"已核实"。** 调查中发现需求与代码现实冲突(比如用户以为存在的能力其实没有),这是重要发现——如实呈现并给出替代方案,不要顺着错误假设写下去。
|
|
65
|
+
|
|
66
|
+
**核实要核到行为,不止存在。** 「已核实」的对象是**计划所依赖的那个行为**——文件存在、函数同名、接口能调通,都不等于契约成立;实现期最贵的返工全部来自"行为想当然"。事实清单里凡属以下类别,必须把行为细节(数字、语义)抄进来:
|
|
67
|
+
|
|
68
|
+
- **分页/批量推进**:上游接口有没有 offset/cursor?"重复调用"会推进到下一批,还是永远命中同一批?你的方案若依赖"分批扇出",这一条不核实等于整个机制不成立。
|
|
69
|
+
- **限流/配额/上限**的具体数值与作用域(每租户?每调用方?每分钟?),超限行为是排队还是失败。
|
|
70
|
+
- **鉴权模板的 claims 形状**:要照抄的 gate 里到底有没有 `permissions`/`bypass`?抄了一个没有权限位的 gate,再叠"按权限下放"的设计就是空中楼阁。
|
|
71
|
+
- **密钥/加密的密钥域**:复用的加密函数绑的是哪个 env/密钥?轮换/灾备是否与你的数据绑死在别人的密钥上?
|
|
72
|
+
- **框架层行为**:如框架校验失败先于业务闸返 4xx——"业务错误一律 200"的承诺需要宽 schema/手动解析才能兑现,计划里要写明。
|
|
73
|
+
- **事务/失败语义**:被复用的"钩子/发射点"在事务内还是事务外?进程崩溃时丢不丢?你承诺的可靠性等级(at-least-once 等)必须与之相容。
|
|
74
|
+
|
|
75
|
+
## 第 3 步:决策先行
|
|
76
|
+
|
|
77
|
+
正文之前先把 §0 钉死——所有实现期会引发争论的点(形态/协议/凭证/权限/边界/复用策略)在这里一次拍完:
|
|
78
|
+
|
|
79
|
+
- **决策表**:每行 = 决策点 + 选择 + **含义**(对部署件/既有代码/边界的影响;能"零改动"的明说)。只写选择不写影响的决策等于没做。
|
|
80
|
+
- **职责边界**:一张"谁拥有什么"的表 + 一句话把职责切死,实现期所有"要不要顺手做"回来看这句。
|
|
81
|
+
- **关键取舍**:每条 = 选择 → **代价**(显式承认) → 缓解/兜底(实在缓解不了就写"风险显式承认")。重点覆盖:降级路径、幂等/重试、**并发与竞态**(两个层面都要:① 后台 worker/队列写清原子认领、基于截止时间的僵尸判定、计数器原子更新——读后写的熔断计数、按旧时间戳清扫 running 这类竞态在计划期就要堵死;② 普通请求路径上**任何跨请求的 check-then-write**——先查状态再写入的流程(如"检查问卷开放→插入答卷"对上"管理员并发关闭")必须写明事务内锁或条件写)、**数据生命周期**(每张新表对其引用的实体逐个走查"被删/被转移/被失效"场景:FK/NOT NULL/UNIQUE 约束必须与声明的回退语义相容——写着 NOT NULL 外键又承诺"删除后回退占位"是自相矛盾;快照列注明每条写路径的**服务端权威来源**,绝不信前端传值)、安全收口、显式截断、回归风险及其门。
|
|
82
|
+
- **明确不做**:所有容易蔓延的相邻功能逐条出表,**每条给去向**(二期 / 另立项 / 依赖某底座就绪)。产品经理的价值一半在这张表上——评审时会被问"那 X 呢"的都要提前出现在这。
|
|
83
|
+
|
|
84
|
+
## 第 4 步:撰写正文
|
|
85
|
+
|
|
86
|
+
照模板骨架 + 类型裁剪写。通用写作规矩(与模板自身指引冲突时以模板为准):
|
|
87
|
+
|
|
88
|
+
1. **复用具名到文件路径**——"照抄 `apps/xx/src/lib/gate.ts` 范式",禁止"参照既有做法"。
|
|
89
|
+
2. **数字来自调查**——端口、表名、scope 名、上限值,全部来自第 2 步的事实清单,不来自记忆或旧文档。
|
|
90
|
+
3. **热查询点名索引**——汇总/列表/统计查询的过滤列,要么指出已有索引(带名字),要么写进迁移新增;别让聚合裸扫大表。
|
|
91
|
+
4. **闸门有顺序,错误面要对齐**——同一端点叠多道闸(存在性/scope/角色/成员资格)时写明顺序;计划承诺的错误码必须是**第一道会失败的闸**真正抛出的(先查成员再查存在性,非成员对不存在的资源拿到的就是 403 而非 NOT_FOUND——想承诺 NOT_FOUND 就得先查存在性);每类拒绝写明传输层 status(4xx)还是业务错误(200+错误体),验证章节按此断言。
|
|
92
|
+
5. **每个里程碑自带验收**——里程碑表每行的"验证"列非空(脚本断言 + 真实环境走查);上一步不绿不进下一步;重构类步骤以"既有验证全绿"为回归门。
|
|
93
|
+
6. **安全项 = 可断言项**——安全清单每条都要能翻译成一条验证断言,写不出断言的不算安全项。
|
|
94
|
+
7. **需求 → 设计映射兜底**——结尾一张表,R1…Rn 逐条指到具体章节 + 机制 + 验证脚本;项目硬约束(多租户/i18n/设计规范等)也入表;排除项汇总指到"明确不做"。
|
|
95
|
+
8. **规模感**:参考模板给的行数区间(无模板时 200-500 行);范围决策约 1/3、验证约 1/4——这两块薄了计划就不可执行。调查过程的原始材料**不要**倾倒进计划,计划只留结论 + 路径。
|
|
96
|
+
|
|
97
|
+
## 第 5 步:自检与收尾
|
|
98
|
+
|
|
99
|
+
1. **过模板自检清单**(模板通常自带;没有就用 `references/plan-skeleton.md` 末尾的通用版),逐项打勾,不过的回去改。
|
|
100
|
+
2. **路径真实性**:跑 `scripts/check_paths.sh <计划文件> <仓库根>`,列出计划中引用但不存在的路径;逐条人工判断——★新增文件与占位符本来就不存在(正常),**"复用/已核实"类路径出现在 MISSING 里就是虚构,必须修**。
|
|
101
|
+
3. **需求映射全覆盖**:对照第 1 步的 R1…Rn 逐条核对映射表,有空格说明设计有洞。
|
|
102
|
+
4. **交叉一致性自检(抓自相矛盾)**:换上实现者的眼睛把全篇重读一遍——计划是分章节写出来的,各章节各自合理但互相打架是最常见的深层缺陷。专抓四类:
|
|
103
|
+
- 机制章节用到的每个 scope/服务态调用/凭证,反查 seed/SA/清单章节确实配了——设计用了 `directory.read` 而服务账号只给了 `notification.send`,实现期必卡死;
|
|
104
|
+
- 验证章节的每条断言在设计章节有依据——不许"验收要求了设计里不存在的东西"(如断言 CSV 含备注列,而设计定义的 CSV 没有该列);
|
|
105
|
+
- 承诺的不变量互不冲突——"信封 id 恒定"与"重投递克隆新行"不能同时成立,发现即回去改设计;
|
|
106
|
+
- 新增的每个标识符(错误码/共享包导出/env/部署 values 字段)都有对应的登记文件项——漏一处 typecheck/部署就断;
|
|
107
|
+
- 每个权限/角色/开关位**逐跳追通**:UI 入口可见性 → token/bootstrap 载荷 → 服务端真闸——任何一跳不携带该位就是断链(后端支持 bypass 删除但 bootstrap 不返 bypass、发了角色模板但服务端只认租户 role,都是这类);
|
|
108
|
+
- 同一口径(导出格式、通知语义、上限值)在全篇多处出现的,逐处对齐——在一处修正的决定必须同步到其余所有提及处,只修一处等于没修。
|
|
109
|
+
5. **落盘**:默认写到项目的计划目录(与模板/范例同目录),命名循既有惯例(如 `goal/<代号>.md`);目标文件已存在时先确认再覆盖。
|
|
110
|
+
6. **汇报**:向用户交付时,除了计划路径,单独列出:① 留给用户拍板的开放问题;② 调查中发现的、与用户假设冲突的事实;③ 你替用户砍掉/推迟的范围(让用户有机会否决)。
|
|
111
|
+
|
|
112
|
+
## 红线(任何情况下不违反)
|
|
113
|
+
|
|
114
|
+
- **只写计划,不动手实现。** 交付物是计划文档;用户要实施会另说。
|
|
115
|
+
- **不虚构核实。** "已核实"三个字后面必须是本次真读过的路径。
|
|
116
|
+
- **不缩水验证。** 验证章节 + 里程碑验收占计划近一半篇幅是特征不是浪费——砍这里等于交付一份不可执行的愿望清单。
|
|
117
|
+
- **不吞需求。** 用户的每条原始需求,要么有设计落点,要么被显式排除并给出去向,没有第三种下场。
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 本仓库(xgent-ai-portal)默认值
|
|
122
|
+
|
|
123
|
+
在本仓库使用时,以下路径与惯例直接采用,不必重新探测:
|
|
124
|
+
|
|
125
|
+
- **模板**:`goal/PLAN-TEMPLATE.md`(自带元原则 §A、骨架 §B、类型裁剪 §C、写作自检 §D——以它为准)。计划落盘到 `goal/<大写代号>.md`。
|
|
126
|
+
- **样板计划**:新独立 App 型读 `goal/GIT.md` 或 `goal/LMS-RESOURCE.md`;既有 App 增量型读 `goal/PMS-MCP.md`。
|
|
127
|
+
- **端口真值**:`apps/web/vite.config.ts` + 根 `package.json` 的 `dev:all`——别信旧文档端口图。
|
|
128
|
+
- **已知坑来源**:`~/.claude/projects/-Users-rockie-Documents-GitHub-xgent-xgent-ai-portal/memory/`(先看 `MEMORY.md` 索引)、根 `CLAUDE.md`、`goal/*-PROGRESS.md` / `*-DEFERRED.md`。
|
|
129
|
+
- **平台硬约束**(必进需求映射表):多租户隔离(全表 `tenantId`);业务状态一律 200 + `{ok,data}`(HTTP status 只表传输层);字典表 `sort` 规范;三语 i18n;前端两步法(`impeccable` 设计 + Chrome 真浏览器验证);列表接口 `Page<T>` 服务端分页。
|
|
130
|
+
- **新独立 App 的同构基线**:独立后端(Elysia + Drizzle + 独立 Postgres 库 `xgent-<key>`)+ TDT 自省 gate + 前端经 host `sdk.callService` + 应用市场 listing seed + `verify-*.ts` 脚本挂 `verify:all`——决策表第一行"形态"从这里出发。
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "dev-plan",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 0,
|
|
6
|
+
"name": "spms-worklog-incremental",
|
|
7
|
+
"prompt": "给 SPMS(研发项目管理)加工时管理:①Issue 上可以记工时(谁、日期、小时数、备注),自己记的可改可删;②项目维度出工时汇总(按成员/按迭代两个口径);③汇总可导出 CSV。写一份开发计划。",
|
|
8
|
+
"expected_output": "一份既有 App 增量型开发计划(goal/ 惯例格式):决策表含形态(内嵌 spms-server 增量)、数据模型(工时表带 tenantId)、复用具名到 spms 现有文件路径、里程碑每步带验证、需求映射覆盖 ①②③",
|
|
9
|
+
"files": [],
|
|
10
|
+
"assertions": [
|
|
11
|
+
"decision-table-with-implications: 计划含关键架构决策表(含决策点/选择/含义或等价三列),且每行的含义/影响列非空",
|
|
12
|
+
"tradeoffs-state-costs: 存在关键取舍内容,且至少 3 条显式写出「代价」并附缓解/兜底",
|
|
13
|
+
"explicit-out-of-scope-with-destination: 有「明确不在本期/不做」清单,每项附去向(二期/另立项/理由)",
|
|
14
|
+
"milestones-each-verifiable: 里程碑/阶段表每行有非空的验证/验收列",
|
|
15
|
+
"requirements-mapping-covers-all: 有需求→设计映射表,①记工时②两口径汇总③CSV导出 逐条有落点",
|
|
16
|
+
"cited-paths-really-exist: 计划引用 ≥5 个真实仓库文件路径,且复用/已核实类引用无虚构(check_paths.sh 的 MISSING 只含新增★/占位路径)",
|
|
17
|
+
"tenant-isolation-stated: 多租户隔离(tenantId/租户收口)作为硬约束出现在数据模型或映射表",
|
|
18
|
+
"api-convention-200-business: 错误/业务状态设计符合仓库约定(业务失败 200+错误体;不用 4xx/201/204 表业务状态),或至少无违反该约定的设计",
|
|
19
|
+
"worklog-ownership-gate: 「自己记的可改可删」有对应权限闸设计(本人可改删、他人/管理员边界明确)",
|
|
20
|
+
"reuse-names-spms-files: 复用具名到 spms-server/spms-app 的真实现有文件路径(而非泛泛「参照既有做法」)",
|
|
21
|
+
"internal-consistency-no-contradictions: 全篇无章节间自相矛盾——验证断言与设计定义一致、机制所用 scope/凭证在 seed/SA 清单中存在、承诺的不变量互不冲突、新增标识符(错误码/导出/env/部署值)有登记文件项(通读抽查)",
|
|
22
|
+
"upstream-behavior-accurate: 计划对上游行为的陈述(分页/批量推进、限流数值、gate claims 形状、密钥域、事务/失败语义)与仓库代码实际一致——对计划中 ≥3 处行为级依赖抽查核实"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": 1,
|
|
27
|
+
"name": "survey-new-standalone-app",
|
|
28
|
+
"prompt": "我想在应用市场新增一个「问卷调查」App:租户管理员创建问卷(支持单选/多选/填空题),发布给全租户或指定成员填写,每人限填一次,收集后有结果统计页(选项分布、填写率)。参考平台既有独立后端 App 的形态,写一份开发计划。",
|
|
29
|
+
"expected_output": "一份新独立 App 型开发计划:决策表定形态/端口/DB/鉴权(与 files/sms/qbank 同构并指名模板文件)、端口不与现状冲突、数据模型全表 tenantId、安全清单+verify 脚本清单、里程碑到 verify:all + 浏览器走查、需求映射全覆盖",
|
|
30
|
+
"files": [],
|
|
31
|
+
"assertions": [
|
|
32
|
+
"decision-table-with-implications: 计划含关键架构决策表(含决策点/选择/含义或等价三列),且每行的含义/影响列非空",
|
|
33
|
+
"tradeoffs-state-costs: 存在关键取舍内容,且至少 3 条显式写出「代价」并附缓解/兜底",
|
|
34
|
+
"explicit-out-of-scope-with-destination: 有「明确不在本期/不做」清单,每项附去向(二期/另立项/理由)",
|
|
35
|
+
"milestones-each-verifiable: 里程碑/阶段表每行有非空的验证/验收列",
|
|
36
|
+
"requirements-mapping-covers-all: 有需求→设计映射表,建问卷(三题型)/发布对象/限填一次/结果统计 逐条有落点",
|
|
37
|
+
"cited-paths-really-exist: 计划引用 ≥5 个真实仓库文件路径,且复用/已核实类引用无虚构(check_paths.sh 的 MISSING 只含新增★/占位路径)",
|
|
38
|
+
"tenant-isolation-stated: 多租户隔离(全表 tenantId)作为硬约束出现在数据模型或映射表",
|
|
39
|
+
"api-convention-200-business: 错误/业务状态设计符合仓库约定(业务失败 200+错误体;不用 4xx/201/204 表业务状态),或至少无违反该约定的设计",
|
|
40
|
+
"ports-no-conflict: 新 App 选定的本地 dev 端口不与 apps/web/vite.config.ts 及根 package.json dev:all 中现有端口冲突",
|
|
41
|
+
"isomorphic-with-template-files: 与既有独立后端 App 同构的声明落到具体模板文件路径(如某既有 app 的 gate/seed/verify 文件)",
|
|
42
|
+
"single-submission-constraint: 「每人限填一次」有数据库唯一约束或等价幂等设计",
|
|
43
|
+
"audience-targeting-design: 「全租户或指定成员」的发布对象有具体可见性/授权设计",
|
|
44
|
+
"internal-consistency-no-contradictions: 全篇无章节间自相矛盾——验证断言与设计定义一致、机制所用 scope/凭证在 seed/SA 清单中存在、承诺的不变量互不冲突、新增标识符(错误码/导出/env/部署值)有登记文件项(通读抽查)",
|
|
45
|
+
"upstream-behavior-accurate: 计划对上游行为的陈述(分页/批量推进、限流数值、gate claims 形状、密钥域、事务/失败语义)与仓库代码实际一致——对计划中 ≥3 处行为级依赖抽查核实"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": 2,
|
|
50
|
+
"name": "outbound-webhook-platform",
|
|
51
|
+
"prompt": "平台需要出站 Webhook 能力:租户管理员配置订阅(目标 URL + 密钥 + 勾选事件类型),平台内关键事件(如成员加入/移除、应用安装/卸载)发生时推送 JSON 到外部系统,带 HMAC 签名、失败重试和投递日志页。写份开发计划。",
|
|
52
|
+
"expected_output": "一份平台横切面型开发计划:形态决策(portal api 内嵌模块 vs 独立服务,带理由)、SSRF 收口与签名/重试取舍写明代价、事件源头核对到具体现有代码路径、投递日志分页遵循 Page<T>、里程碑带验证、需求映射覆盖订阅/推送/签名/重试/日志",
|
|
53
|
+
"files": [],
|
|
54
|
+
"assertions": [
|
|
55
|
+
"decision-table-with-implications: 计划含关键架构决策表(含决策点/选择/含义或等价三列),且每行的含义/影响列非空",
|
|
56
|
+
"tradeoffs-state-costs: 存在关键取舍内容,且至少 3 条显式写出「代价」并附缓解/兜底",
|
|
57
|
+
"explicit-out-of-scope-with-destination: 有「明确不在本期/不做」清单,每项附去向(二期/另立项/理由)",
|
|
58
|
+
"milestones-each-verifiable: 里程碑/阶段表每行有非空的验证/验收列",
|
|
59
|
+
"requirements-mapping-covers-all: 有需求→设计映射表,订阅配置/事件推送/HMAC签名/失败重试/投递日志页 逐条有落点",
|
|
60
|
+
"cited-paths-really-exist: 计划引用 ≥5 个真实仓库文件路径,且复用/已核实类引用无虚构(check_paths.sh 的 MISSING 只含新增★/占位路径)",
|
|
61
|
+
"tenant-isolation-stated: 多租户隔离(tenantId/按租户收口)作为硬约束出现在数据模型或映射表",
|
|
62
|
+
"api-convention-200-business: 错误/业务状态设计符合仓库约定(业务失败 200+错误体;不用 4xx/201/204 表业务状态),或至少无违反该约定的设计",
|
|
63
|
+
"event-sources-verified-in-code: 事件源头(成员变更/应用安装卸载发生在哪段现有代码)核对到具体真实文件路径",
|
|
64
|
+
"ssrf-egress-hardening: 租户可配任意目标 URL 的 SSRF 面有收口设计(禁内网/localhost、协议限制或白名单)",
|
|
65
|
+
"hmac-and-retry-concrete: HMAC 签名方案具体(算法/header/防重放任一)且重试有策略(退避/次数上限/终态)",
|
|
66
|
+
"delivery-log-paginated: 投递日志页遵循服务端分页(Page<T> 或等价约定)",
|
|
67
|
+
"internal-consistency-no-contradictions: 全篇无章节间自相矛盾——验证断言与设计定义一致、机制所用 scope/凭证在 seed/SA 清单中存在、承诺的不变量互不冲突、新增标识符(错误码/导出/env/部署值)有登记文件项(通读抽查)",
|
|
68
|
+
"upstream-behavior-accurate: 计划对上游行为的陈述(分页/批量推进、限流数值、gate claims 形状、密钥域、事务/失败语义)与仓库代码实际一致——对计划中 ≥3 处行为级依赖抽查核实"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# 通用开发计划骨架(项目无自带模板时的兜底)
|
|
2
|
+
|
|
3
|
+
> 使用方式:照抄章节结构;`<尖括号>` 为占位;写作指引(引用块)写完删掉。
|
|
4
|
+
> 目标读者是**实现者**(人或 Agent),他们只执行、不重开设计讨论——所以决策、边界、验收必须在这份文档里一次说死。
|
|
5
|
+
|
|
6
|
+
```markdown
|
|
7
|
+
# <代号> · <项目名> · <功能名>(<形态> · <4-8 个关键架构特征,用 " · " 串起>)
|
|
8
|
+
|
|
9
|
+
> 站在 <本计划依赖的既有模块/文档,带路径链接> 之上。
|
|
10
|
+
> 本期交付:**<一段话说清交付物形态与核心能力>**。
|
|
11
|
+
> 本期的独特职责:<一句话定位;与最相近既有物的差异对照>。
|
|
12
|
+
> **<顶层排除:最容易被误解为在范围内的东西,第一屏就排除>**。
|
|
13
|
+
|
|
14
|
+
## 0. 本期范围与决策
|
|
15
|
+
|
|
16
|
+
<一句话定性:难点不在 <别人以为难的>,而在 ①… ②… ③…>
|
|
17
|
+
|
|
18
|
+
| # | 决策点 | 选择 | 含义 |
|
|
19
|
+
| --- | --- | --- | --- |
|
|
20
|
+
| 1 | 形态 | … | <对部署/既有代码/边界的影响;能"零改动"的明说> |
|
|
21
|
+
| 2 | <协议/凭证/权限/数据归属/复用策略…> | … | … |
|
|
22
|
+
|
|
23
|
+
### 0.1 职责边界:<X> 拥有什么,本模块拥有什么
|
|
24
|
+
| | <系统A> | <本模块(本期)> | <系统B> |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| 拥有 | … | … | … |
|
|
27
|
+
| 红线 | — | **<本模块绝不做的事>** | … |
|
|
28
|
+
|
|
29
|
+
一句话:<把职责切分说死;实现期所有"要不要顺手做"回来看这句>。
|
|
30
|
+
|
|
31
|
+
### 0.2 关键取舍(显式记录而非默默处理)
|
|
32
|
+
- **a. <标题>。** <选了什么、为什么>。代价:<显式承认>。缓解:<手段/兜底>。
|
|
33
|
+
- <重点覆盖:降级路径、幂等/重试、安全收口、显式截断、最大回归风险及其门>
|
|
34
|
+
|
|
35
|
+
### 0.3 明确不在本期
|
|
36
|
+
- **<最容易蔓延的相邻功能>**——<去向:二期/另立项/依赖某底座>。
|
|
37
|
+
|
|
38
|
+
## 1. 拓扑与改动面
|
|
39
|
+
<涉及的模块/目录逐个列,★ 标新增;每条一两行写清承载什么;增量型写"增量清单 + 零改动声明">
|
|
40
|
+
<端口/环境变量/脚本等新增项逐个列名 + 默认值 + 语义;与现状核对过不冲突>
|
|
41
|
+
|
|
42
|
+
## 2. 数据模型
|
|
43
|
+
| 表 | 关键列 | 说明(语义 + 唯一键/索引) |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
<声明项目的数据约定:软引用/外键策略、排序字段规范、分页契约、迁移工具及其退路>
|
|
46
|
+
|
|
47
|
+
## 3. 集成与契约
|
|
48
|
+
<逐个上游:「已核实(`路径`):零改动」或精确增量(现状缺口 → 最小改法 → 漏掉的后果);没有第三种状态>
|
|
49
|
+
<需要的种子数据/配置逐条编号,实现期照单执行>
|
|
50
|
+
|
|
51
|
+
## 4. 服务端机制(核心业务)
|
|
52
|
+
<鉴权链以哪个文件为模板;路由清单按分组列全 + 每组的闸;
|
|
53
|
+
本期最核心的 1-2 条管线用编号步骤写透(幂等短路、失败回退、每步用谁的凭证);
|
|
54
|
+
消费/写入的门逐道列出并注明"服务端强制,前端隐藏只是体验">
|
|
55
|
+
|
|
56
|
+
## 5. 前端
|
|
57
|
+
<视图与信息架构按角色列;重头戏页面标出;空态/错误态/进行中态把关点;i18n 要求>
|
|
58
|
+
|
|
59
|
+
## 6. 安全清单(验收断言的来源)
|
|
60
|
+
<每条都要能翻译成 §7 的一条验证断言——写不出断言的不算安全项;
|
|
61
|
+
覆盖:凭证存储、越权矩阵、租户/用户隔离、限流、敏感值不进 URL 与日志>
|
|
62
|
+
|
|
63
|
+
## 7. 验证
|
|
64
|
+
### 7.1 自动化断言脚本 <每支一行写清覆盖面;标出核心;隔离/越权/招牌能力必有专门脚本>
|
|
65
|
+
### 7.2 跨模块回归 <复用/扩展哪些既有验证>
|
|
66
|
+
### 7.3 真实环境走查 <用"→"串出步骤级走查脚本,含故障注入与越权入口>
|
|
67
|
+
### 7.4 静态校验 <类型检查/i18n 完整性等>
|
|
68
|
+
|
|
69
|
+
## 8. 里程碑(每步可验证)
|
|
70
|
+
| # | 里程碑 | 内容 | 验证 |
|
|
71
|
+
| --- | --- | --- | --- |
|
|
72
|
+
| M1 | <骨架+契约接入> | <重构先行的独立 commit + 回归门> | <断言点;"既有套件全绿"> |
|
|
73
|
+
| Mn | <收尾> | <文档 + 挂总验证> | <全量回归 + 真实环境全链路> |
|
|
74
|
+
|
|
75
|
+
## 9. 风险与开放问题
|
|
76
|
+
- **<最大风险>**:<门/缓解>。
|
|
77
|
+
- **开放问题(实现前确认)**:① <决策留白>;② <发现的全局缺口——不临时补也不放大,单列>。
|
|
78
|
+
|
|
79
|
+
## 10. 已知坑(沿用既有教训)
|
|
80
|
+
<一行一坑 + 出处;P0 加粗>
|
|
81
|
+
|
|
82
|
+
## 11. 需求 → 设计映射(自检)
|
|
83
|
+
| # | 需求 | 本期落点 |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| R1 | <原始需求逐条> | <§号 + 机制名 + 验证脚本名> |
|
|
86
|
+
| — | <项目硬约束> | … |
|
|
87
|
+
| — | **不在本期**:<排除项汇总> | §0.3 |
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 写作自检(发出前过一遍)
|
|
91
|
+
|
|
92
|
+
- [ ] 决策表每行都有「含义」——只写选择不写影响的决策等于没做。
|
|
93
|
+
- [ ] 每条取舍都有**代价**字样;每个排除项都有去向。
|
|
94
|
+
- [ ] 每个上游契约要么「已核实(路径)」要么列了精确增量——没有第三种状态。
|
|
95
|
+
- [ ] 里程碑表每行「验证」列非空,最后一行落到全量回归 + 真实环境走查。
|
|
96
|
+
- [ ] §6 安全清单每条能对应 §7 的一条断言。
|
|
97
|
+
- [ ] §11 映射覆盖全部原始需求 + 项目硬约束 + 排除项。
|
|
98
|
+
- [ ] 已知坑节搬运了相关历史教训。
|
|
99
|
+
- [ ] 交叉一致性:机制用到的凭证/scope 在配置清单中存在;验收断言与设计相符;承诺的不变量互不冲突;新增标识符(错误码/导出/env/部署值)都有登记点;同一口径的多处提及逐处对齐。
|
|
100
|
+
- [ ] 上游行为级核实:分页推进/限流数值/claims 形状/密钥域/事务语义——计划依赖的行为与代码实际一致,不止"文件存在"。
|
|
101
|
+
- [ ] 闸门顺序与错误面:多道闸写明顺序,承诺的错误码 = 第一道会失败的闸抛出的;权限位从 UI 可见性到服务端真闸逐跳追通。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 用法: check_paths.sh <计划.md> [仓库根,默认 .]
|
|
3
|
+
# 从计划文档提取反引号内的仓库路径样式 token,检查真实存在性,打印 MISSING 列表。
|
|
4
|
+
# 注意:报告仅供人工复核——★新增文件、占位符、示例路径本来就不存在(正常);
|
|
5
|
+
# "复用/已核实"类路径出现在 MISSING 里才是问题(虚构引用)。
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
plan="$1"; root="${2:-.}"
|
|
8
|
+
missing=0; checked=0
|
|
9
|
+
exts='ts|tsx|js|jsx|mjs|cjs|json|md|css|scss|html|sh|sql|ya?ml|toml|py|txt|svg|png|conf|env'
|
|
10
|
+
while IFS= read -r p; do
|
|
11
|
+
first="${p%%/*}"; last="${p##*/}"
|
|
12
|
+
# 只检查两类 token:① 首段是仓库根下真实目录(仓库根相对路径);② 末段带常见文件扩展名。
|
|
13
|
+
# 其余(如 tools/list、files.read/files.write 这类方法名/scope 名)跳过。
|
|
14
|
+
if [ ! -d "$root/$first" ] && ! [[ "$last" =~ \.($exts)$ ]]; then continue; fi
|
|
15
|
+
checked=$((checked + 1))
|
|
16
|
+
[ -e "$root/$p" ] && continue
|
|
17
|
+
# 计划常写 workspace 相对路径(如 src/lib/gate.ts 或 routes/git.ts),尝试常见 monorepo 布局
|
|
18
|
+
found=0
|
|
19
|
+
for base in "$root"/apps/*/ "$root"/apps/*/src/ "$root"/packages/*/ "$root"/packages/*/src/; do
|
|
20
|
+
[ -e "$base$p" ] && { found=1; break; }
|
|
21
|
+
done
|
|
22
|
+
if [ "$found" -eq 0 ]; then echo "MISSING: $p"; missing=$((missing + 1)); fi
|
|
23
|
+
done < <(
|
|
24
|
+
grep -oE '`[^`]+`' "$plan" | tr -d '`' \
|
|
25
|
+
| grep -E '^[A-Za-z0-9_.@-]+(/[A-Za-z0-9_.@-]+)+/?$' \
|
|
26
|
+
| grep -vE '[<>*{}()]' \
|
|
27
|
+
| grep -vE '^(https?:|node_modules/|@)' \
|
|
28
|
+
| sort -u
|
|
29
|
+
)
|
|
30
|
+
echo "---"
|
|
31
|
+
echo "共检查 $checked 个路径样式 token,MISSING $missing 个。"
|
|
32
|
+
echo "(存在的不打印;MISSING 需逐条人工判断:新增(★)/占位路径可忽略,复用/已核实类路径缺失必须修)"
|