// v2.1 触发逻辑自测 — 模拟真实任务输入,验证判断 0 硬门槛是否拦得住 import { planDispatch, hardTrigger, isConversation, canSelfExecute, selectProfile, VERSION, SKILL_NAME, lessonEntry } from '../lib/index.mjs'; let pass = 0, fail = 0; const check = (name, got, want) => { const ok = JSON.stringify(got) === JSON.stringify(want); ok ? pass++ : fail++; console.log(`${ok ? '✅' : '❌'} ${name}`); if (!ok) console.log(` got = ${JSON.stringify(got)}\n want = ${JSON.stringify(want)}`); }; console.log(`\n== ${SKILL_NAME} v${VERSION} 触发逻辑自测 ==\n`); // ── 判断 0:硬门槛(v2.0 失效场景必须被拦住)────────────────────────── check('H1 git 路径(失效原场景):必须派,走 claude-p', planDispatch('/opt/data/git-repos/skill-heterarchy/ 这是项目级任务'), { action: 'dispatch', hit: 'H1', label: 'git 仓库路径', profile: 'fullstack', mechanism: 'claude-p', parallel: false }); check('H1 相对路径 git-repos', hardTrigger('改一下 ./git-repos/foo/SKILL.md')?.id, 'H1'); check('H1 .git 目录', hardTrigger('看看 .git/config 里有什么')?.id, 'H1'); check('H2 git clone → claude-p', planDispatch('git clone https://github.com/x/y.git 然后跑起来').mechanism, 'claude-p'); check('H2 git commit → claude-p', planDispatch('帮我 git commit 并 push 一下').hit, 'H2'); check('H3 构建 → delegate-task', planDispatch('帮我 build 一下这个包的产物').mechanism, 'delegate-task'); check('H3 重构多文件', planDispatch('重构多文件里的日志模块').hit, 'H3'); check('H3 CI 关键词', planDispatch('配一下 CI 流水线').hit, 'H3'); check('H4 技能开发/安装 → claude-p', planDispatch('开发一个 skill 并安装到 /opt/data/skills/'), { action: 'dispatch', hit: 'H4', label: '技能开发/安装', profile: 'fullstack', mechanism: 'claude-p', parallel: false }); check('H4 改 SKILL.md', planDispatch('改 SKILL.md 的 frontmatter 版本号').hit, 'H4'); check('H5 用户显式"项目级任务" → 派(profile 由文本再判)', planDispatch('这是个项目级任务,你来安排'), { action: 'dispatch', hit: 'H5', label: '用户显式声明', profile: 'fullstack', mechanism: 'delegate-task', parallel: false }); check('H5 "派 CC 做" → 派', planDispatch('这个派 CC 做').hit, 'H5'); check('H6 批量容器 → devops 并行', planDispatch('把 34 台容器的配置全部更新一遍', { parallel: true }), { action: 'dispatch', hit: 'H6', label: '批量对象', profile: 'devops', mechanism: 'delegate-task', parallel: true }); check('H6 全舰队', planDispatch('全舰队逐台检查健康状态').hit, 'H6'); // ── 判断 1:沟通不误伤 ──────────────────────────────────────────────── check('沟通:你好 → reply', planDispatch('你好').action, 'reply'); check('沟通:收到 → reply', planDispatch('收到!').action, 'reply'); check('沟通:谢谢 → reply', planDispatch('谢谢').action, 'reply'); check('isConversation 空串 → true', isConversation(''), true); // ── 判断 2:整条请求累计预算(v2.1 修正口径)────────────────────────── check('累计 2 调用 → 允许自做', canSelfExecute({ cumulativeToolCalls: 2 }), true); check('累计 3 调用 → 必须派发', canSelfExecute({ cumulativeToolCalls: 3 }), false); check('已知信息 → 允许自做', canSelfExecute({ known: true }), true); check('无计划 → 不臆断自做', canSelfExecute(null), false); // 关键回归:单步 ≤2 但累计超预算,不得自做 check('★ 单步 2 但累计 12 → 走派发(v2.0 于此失守)', planDispatch('顺手把报告里的错别字改一下', { plan: { toolCalls: 2, cumulativeToolCalls: 12 } }).action, 'dispatch'); // 非硬门槛的软任务仍可自做 check('软任务累计 1 调用 → self', planDispatch('把这句话翻译成英文', { plan: { cumulativeToolCalls: 1 } }).action, 'self'); // ── 判断 3:Profile 自动映射 ────────────────────────────────────────── check('Profile:小说 → writer', selectProfile('写一章小说'), 'writer'); check('Profile:调研 → researcher', selectProfile('调研一下竞品'), 'researcher'); check('Profile:部署 → devops', selectProfile('部署到线上'), 'devops'); check('Profile:兜底 → fullstack', selectProfile('随便弄弄'), 'fullstack'); // ── 判断 4:需要项目上下文 → claude-p ──────────────────────────────── check('needsProjectContext → claude-p', planDispatch('帮我看看这个功能', { needsProjectContext: true }).mechanism, 'claude-p'); // ── 教训库条目 ─────────────────────────────────────────────────────── check('lessonEntry 产出表格行', lessonEntry({ date: '2026-10-08', hit: 'H1', action: '自己改 SKILL.md', should: 'fullstack/CC', cause: '跳过判断0' }), '| 2026-10-08 | H1 | 自己改 SKILL.md | fullstack/CC | 跳过判断0 |'); console.log(`\n== 结果:${pass} 通过 / ${fail} 失败 ==\n`); process.exit(fail === 0 ? 0 : 1);