Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
aeb1487
新增 skill 链接检测,实测 11 处断链
Aug 8, 2026
9d1c532
抽出逐行扫描公共层,容错坏路径与不可读文件
Aug 8, 2026
170b0cc
新增悬空 skill 名与二级引用检测
Aug 8, 2026
61183cb
修复不可读 SKILL.md 抛错,补注裸名盲区
Aug 8, 2026
0e848b1
新增 reference 目录缺失与文件行数检测
Aug 8, 2026
46bab0a
新增 _meta.json 发布清单一致性检测
Aug 8, 2026
108f259
新增 doctor 自检入口,汇总六项检查
Aug 8, 2026
8bf4885
订正读文件注释,收紧 SKILL.md 豁免并补边界用例
Aug 8, 2026
56381af
新增 npm test 入口并在 CI 中运行测试
Aug 8, 2026
6cd6087
修正 KV 前置条件的断链,指向 makers-storage
Aug 8, 2026
4b52218
修正 makers-migration 跨 skill 引用路径
Aug 8, 2026
b202a30
makers-migration 的框架引用改为单跳转点
Aug 8, 2026
7a540b2
清除 4 个不存在的 skill 名引用
Aug 8, 2026
d58ecb2
拆分 crewai.md 至 500 行以内
Aug 8, 2026
aa446cc
CLI 最低版本要求统一为 1.6.7
Aug 8, 2026
18be562
预览前必须询问用户,与专家团 prompt 对齐
Aug 8, 2026
756a1d7
修正 env-adaption 章节编号断裂
Aug 8, 2026
687eebf
为超 100 行的 reference 补目录,并让悬空名检测跳过锚点 slug
Aug 8, 2026
cae0f37
补齐 _meta.json 发布清单并将 doctor 接入 CI
Aug 8, 2026
4f20dcf
hook 改为聚合所有命中的 skill 校验规则
Aug 8, 2026
ad1cf2b
为 9 个 skill 声明 validate 硬校验规则
Aug 8, 2026
f8317f3
hook 测试改为断言规则不变量而非固定数组
Aug 8, 2026
f3335a3
重新生成多平台产物
Aug 8, 2026
9dda898
del:ci
Aug 10, 2026
74bc439
回退 CLI 版本口径与预览策略改动
Aug 10, 2026
abf252f
删除 next.config 的否定式校验规则,避免误报
Aug 10, 2026
362fe0b
hook 出错时静默退出,不再因缺 skills 目录报错
Aug 10, 2026
72ad5a4
feat:npm 默认使用淘宝源,规范部署后的输出
Aug 11, 2026
f7053d9
Merge remote-tracking branch 'origin/main' into feat/skills-optim
Aug 13, 2026
6d02ee3
重新生成多平台产物
Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions codex/makers-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ description: >-
Do NOT trigger for deployment workflows (use edgeone-pages-deploy).
Do NOT trigger for generic AI framework development outside
an EdgeOne Makers project.
pathPatterns:
- agents/**
validate:
- pattern: "process\\.env|os\\.environ"
message: "Read env via context.env inside agents/ and cloud-functions/, never process.env or os.environ (Critical Rule 3)."
- pattern: "headers\\s*\\.\\s*get\\s*\\("
message: "Headers are plain objects here: context.request.headers['x-name'], not .get('x-name') (Critical Rule 4)."
- pattern: "langgraphStore\\s*\\?\\?\\s*store"
message: "Never write `store?.langgraphStore ?? store` — in cloud-function context it falls back to a store with no .get and crashes (Critical Rule 12)."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
5 changes: 5 additions & 0 deletions codex/makers-cloud-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ name: edgeone-makers-cloud-functions
description: >-
EdgeOne Makers Cloud Functions — Node.js, Go, and Python runtimes.
Use when building server-side APIs, Express/Koa patterns, or backend logic.
pathPatterns:
- cloud-functions/**
validate:
- pattern: "process\\.env|os\\.environ"
message: "Read env via context.env inside cloud-functions/, never process.env or os.environ."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
6 changes: 6 additions & 0 deletions codex/makers-deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ description: >-
commands — the skill contains critical rules for parsing deploy output and presenting access URLs.
Do NOT trigger for post-deployment runtime errors (e.g. CORS issues, 500 errors after deploy —
use edgeone-makers-dev for troubleshooting).
pathPatterns:
- "*.sh"
- .github/workflows/**
validate:
- pattern: "whoami[^\\n]*\\s-t\\s"
message: "edgeone whoami does not accept -t. Check the exit code instead: 0 = logged in, 1 = not."
metadata:
author: edgeone
version: "2.2.0"
Expand Down
2 changes: 2 additions & 0 deletions codex/makers-edge-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ validate:
message: "Use plain object headers for this runtime surface."
- pattern: "fs\\.writeFile"
message: "Edge Functions do not support filesystem writes."
- pattern: "Response\\.json\\s*\\("
message: "Response.json() is not available in this V8 runtime — use new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } })."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
8 changes: 8 additions & 0 deletions codex/makers-env-adaption.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ description: >-
Covers: non-interactive CLI flags, network isolation workarounds, login in sandbox,
proxy bypass, file preview constraints (MUST use http:// via dev server, NEVER file://,
NEVER python -m http.server / npx serve), dev server requirements.
pathPatterns:
- "*.sh"
- package.json
validate:
- pattern: "python\\s+-m\\s+http\\.server|npx\\s+(serve|http-server)"
message: "Use `edgeone makers dev` — self-hosted static servers skip Blob credentials, Cloud Functions routing, Edge Functions and middleware."
- pattern: "localhost:80(88|89)"
message: "Use 127.0.0.1, not localhost — in the sandbox localhost resolves to ::1 and yields false 404s."
metadata:
author: edgeone
version: "1.1.1"
Expand Down
6 changes: 6 additions & 0 deletions codex/makers-middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ name: edgeone-makers-middleware
description: >-
Edge middleware for EdgeOne Makers — request interception, redirects, rewrites,
auth guards, A/B testing, and header injection at the edge (V8 runtime).
pathPatterns:
- middleware.js
- middleware.ts
validate:
- pattern: "NextRequest|NextResponse|next/server"
message: "Framework projects must use the framework's own middleware. This platform format takes a context object with next/redirect/rewrite — not NextRequest/NextResponse."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
6 changes: 6 additions & 0 deletions codex/makers-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ description: >-
convert Express/Next.js API routes to Makers handlers, or add platform capabilities
(context.tools, context.sandbox, context.store).
Do NOT trigger for new agent projects (use makers-agents instead).
pathPatterns:
- agents/**
- cloud-functions/**
validate:
- pattern: "process\\.env|os\\.environ"
message: "Migration checklist: replace process.env / os.environ with context.env (TS) or ctx env access (Python)."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
5 changes: 5 additions & 0 deletions codex/makers-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ name: edgeone-makers-storage
description: >-
KV and Blob storage services on EdgeOne Makers. KV for edge key-value pairs,
Blob for file/object storage in Cloud Functions. Covers SDK usage, setup, and troubleshooting.
pathPatterns:
- edge-functions/**
validate:
- pattern: "context\\.env\\.[A-Za-z_]*[Kk][Vv]"
message: "KV is a console-bound global variable, not on context.env — call my_kv.get(...) directly. See makers-storage/references/kv.md."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
9 changes: 9 additions & 0 deletions cursor/rules/makers-agents.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ description: >-
Do NOT trigger for deployment workflows (use edgeone-pages-deploy).
Do NOT trigger for generic AI framework development outside
an EdgeOne Makers project.
pathPatterns:
- agents/**
validate:
- pattern: "process\\.env|os\\.environ"
message: "Read env via context.env inside agents/ and cloud-functions/, never process.env or os.environ (Critical Rule 3)."
- pattern: "headers\\s*\\.\\s*get\\s*\\("
message: "Headers are plain objects here: context.request.headers['x-name'], not .get('x-name') (Critical Rule 4)."
- pattern: "langgraphStore\\s*\\?\\?\\s*store"
message: "Never write `store?.langgraphStore ?? store` — in cloud-function context it falls back to a store with no .get and crashes (Critical Rule 12)."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
5 changes: 5 additions & 0 deletions cursor/rules/makers-cloud-functions.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ name: edgeone-makers-cloud-functions
description: >-
EdgeOne Makers Cloud Functions — Node.js, Go, and Python runtimes.
Use when building server-side APIs, Express/Koa patterns, or backend logic.
pathPatterns:
- cloud-functions/**
validate:
- pattern: "process\\.env|os\\.environ"
message: "Read env via context.env inside cloud-functions/, never process.env or os.environ."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
6 changes: 6 additions & 0 deletions cursor/rules/makers-deploy.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ description: >-
commands — the skill contains critical rules for parsing deploy output and presenting access URLs.
Do NOT trigger for post-deployment runtime errors (e.g. CORS issues, 500 errors after deploy —
use edgeone-makers-dev for troubleshooting).
pathPatterns:
- "*.sh"
- .github/workflows/**
validate:
- pattern: "whoami[^\\n]*\\s-t\\s"
message: "edgeone whoami does not accept -t. Check the exit code instead: 0 = logged in, 1 = not."
metadata:
author: edgeone
version: "2.2.0"
Expand Down
2 changes: 2 additions & 0 deletions cursor/rules/makers-edge-functions.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ validate:
message: "Use plain object headers for this runtime surface."
- pattern: "fs\\.writeFile"
message: "Edge Functions do not support filesystem writes."
- pattern: "Response\\.json\\s*\\("
message: "Response.json() is not available in this V8 runtime — use new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } })."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
8 changes: 8 additions & 0 deletions cursor/rules/makers-env-adaption.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ description: >-
Covers: non-interactive CLI flags, network isolation workarounds, login in sandbox,
proxy bypass, file preview constraints (MUST use http:// via dev server, NEVER file://,
NEVER python -m http.server / npx serve), dev server requirements.
pathPatterns:
- "*.sh"
- package.json
validate:
- pattern: "python\\s+-m\\s+http\\.server|npx\\s+(serve|http-server)"
message: "Use `edgeone makers dev` — self-hosted static servers skip Blob credentials, Cloud Functions routing, Edge Functions and middleware."
- pattern: "localhost:80(88|89)"
message: "Use 127.0.0.1, not localhost — in the sandbox localhost resolves to ::1 and yields false 404s."
metadata:
author: edgeone
version: "1.1.1"
Expand Down
6 changes: 6 additions & 0 deletions cursor/rules/makers-middleware.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ name: edgeone-makers-middleware
description: >-
Edge middleware for EdgeOne Makers — request interception, redirects, rewrites,
auth guards, A/B testing, and header injection at the edge (V8 runtime).
pathPatterns:
- middleware.js
- middleware.ts
validate:
- pattern: "NextRequest|NextResponse|next/server"
message: "Framework projects must use the framework's own middleware. This platform format takes a context object with next/redirect/rewrite — not NextRequest/NextResponse."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
6 changes: 6 additions & 0 deletions cursor/rules/makers-migration.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ description: >-
convert Express/Next.js API routes to Makers handlers, or add platform capabilities
(context.tools, context.sandbox, context.store).
Do NOT trigger for new agent projects (use makers-agents instead).
pathPatterns:
- agents/**
- cloud-functions/**
validate:
- pattern: "process\\.env|os\\.environ"
message: "Migration checklist: replace process.env / os.environ with context.env (TS) or ctx env access (Python)."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
5 changes: 5 additions & 0 deletions cursor/rules/makers-storage.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ name: edgeone-makers-storage
description: >-
KV and Blob storage services on EdgeOne Makers. KV for edge key-value pairs,
Blob for file/object storage in Cloud Functions. Covers SDK usage, setup, and troubleshooting.
pathPatterns:
- edge-functions/**
validate:
- pattern: "context\\.env\\.[A-Za-z_]*[Kk][Vv]"
message: "KV is a console-bound global variable, not on context.env — call my_kv.get(...) directly. See makers-storage/references/kv.md."
metadata:
author: edgeone
version: "1.0.0"
Expand Down
94 changes: 71 additions & 23 deletions hooks/validate-write.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,32 @@ function parseSkillValidateRule(skillPath) {
};
}

/**
* 读取各能力声明的 validate 规则。
*
* 读不到就返回空数组,绝不抛错:本函数跑在 PreToolUse 钩子里,
* 模型每写一个文件都会经过它。references/ 不存在(部分安装、
* CLAUDE_PLUGIN_ROOT 解析错位)时若抛 ENOENT,用户每次写文件都会看到一次报错。
* 校验器失效的正确表现是「不提醒」,而不是「报错」。
*/
export function loadSkillValidateRules(skillsDir = DEFAULT_SKILLS_DIR) {
if (skillsDir === DEFAULT_SKILLS_DIR && cachedRules) return cachedRules;
const rules = readdirSync(skillsDir, { withFileTypes: true })
let entries;
try {
entries = readdirSync(skillsDir, { withFileTypes: true });
} catch {
return [];
}
const rules = entries
.filter((entry) => entry.isDirectory())
.map((entry) => join(skillsDir, entry.name, 'SKILL.md'))
.map((skillPath) => parseSkillValidateRule(skillPath))
.map((skillPath) => {
try {
return parseSkillValidateRule(skillPath);
} catch {
return null;
}
})
.filter(Boolean);
if (skillsDir === DEFAULT_SKILLS_DIR) cachedRules = rules;
return rules;
Expand Down Expand Up @@ -147,21 +167,33 @@ function getToolWriteContent(payload) {
return '';
}

function findSkillForPath(filePath, rules) {
if (!filePath) return null;
for (const rule of rules) {
if (rule.pathPatterns.some((pattern) => globToRegExp(pattern).test(filePath))) return rule;
}
return null;
/**
* 返回所有 pathPatterns 命中该路径的规则。
*
* 不能只取第一条:规则按目录字母序加载,而 `agents/**` 与
* `cloud-functions/**` 这类前缀天然会重叠。只取首条等于让「哪条铁律生效」
* 由目录名的字母序偶然决定,多个能力共管同一路径时会静默丢提醒。
*/
function findSkillsForPath(filePath, rules) {
if (!filePath) return [];
return rules.filter((rule) =>
rule.pathPatterns.some((pattern) => globToRegExp(pattern).test(filePath)),
);
}

function selectValidationMatches(content, rule) {
/**
* 收集全部命中的校验项,message 去重并保留首次出现顺序。
* 每项带上来源 skill,供 signal log 归因。
*/
function selectValidationMatches(content, matchedRules) {
const seen = new Set();
const matches = [];
for (const item of rule.validate) {
if (new RegExp(item.pattern).test(content) && !seen.has(item.message)) {
for (const rule of matchedRules) {
for (const item of rule.validate) {
if (!new RegExp(item.pattern).test(content)) continue;
if (seen.has(item.message)) continue;
seen.add(item.message);
matches.push(item);
matches.push({ ...item, skill: rule.skill });
}
}
return matches;
Expand All @@ -176,13 +208,13 @@ export function buildValidateWriteOutput(payload, options = {}) {
const content = getToolWriteContent(payload);
if (!content) return null;

const rule = findSkillForPath(
const matchedRules = findSkillsForPath(
getToolPath(getToolInput(payload)),
options.rules || loadSkillValidateRules(),
);
if (!rule) return null;
if (matchedRules.length === 0) return null;

const matches = selectValidationMatches(content, rule);
const matches = selectValidationMatches(content, matchedRules);
if (matches.length === 0) return null;

if (shouldWriteSignalLog(options)) {
Expand All @@ -191,7 +223,7 @@ export function buildValidateWriteOutput(payload, options = {}) {
{
hook: 'PreToolUse',
trigger: 'validate',
matchedSkill: rule.skill,
matchedSkill: match.skill,
reason: match.message,
toolName: getToolName(payload),
},
Expand All @@ -216,17 +248,33 @@ async function readStdin() {
return input;
}

/**
* 钩子入口。任何异常都吞掉并静默返回:
* 这段代码挡在模型每一次 Edit/Write 前面,宁可漏一次提醒,
* 也不能因为自身出错(stdin 不是合法 JSON、规则读不到等)
* 让用户每写一个文件都看到一次报错。
*/
export async function main() {
const rawInput = await readStdin();
const payload = rawInput.trim() ? JSON.parse(rawInput) : {};
const output = buildValidateWriteOutput(payload, { enableSignalLog: true });
let payload;
try {
const rawInput = await readStdin();
payload = rawInput.trim() ? JSON.parse(rawInput) : {};
} catch {
return;
}

let output;
try {
output = buildValidateWriteOutput(payload, { enableSignalLog: true });
} catch {
return;
}

if (!output) return;
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
});
// main() 内部已兜住所有异常;这里再兜一层,保证退出码始终是 0。
main().catch(() => {});
}
Loading
Loading