msh-exam-analysis — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited msh-exam-analysis (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
针对 mingshihuichuguo.com/homework/student/<id> 的模考作业,按学生 本人手写习惯输出两份错题分析 txt 到桌面:
阅读.txt听力.txt只写阅读和听力。写作 / 口语不在范围内(用户不要求)。
https://mingshihuichuguo.com/homework/student/<id> 网址注意:粘贴错题内容(不含 URL)不触发,必须给完整 URL。
~/.msh-skill-state.json,下次不重复问eval 一次拿整段 innerText,不逐题 snapshot目标:10 分钟内完成(含浏览器重启等待 ≤ 8s)。
怎么知道刚才走错路了:
playwright-cli --s=default click → 走错路,回去重抓playwright-cli --s=default snapshot → 立刻停,回去换 evalplaywright-cli tab-select → 删掉,换 eval 找链接下面 4 段 eval 代码覆盖 90% 工作流。先复制,再按需改。
playwright-cli --s=default eval "() => {
const a = document.querySelector('a[href*=\"/homework/student/\"]');
if (a) { a.click(); return 'clicked: ' + a.href; }
return 'not found, current: ' + location.href;
}"playwright-cli --s=default eval "() => {
const b = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === '阅读M1');
if (b) { b.click(); return 'clicked 阅读M1'; }
return 'not found';
}"把 '阅读M1' 换 '阅读M2' / '听力M1' / '听力M2' / '答题解析' 都行。
playwright-cli --s=default eval "() => {
const items = Array.from(document.querySelectorAll('div'))
.filter(d => /^\(\d+\)\s*[✓✗]$/.test(d.textContent.trim().replace(/\s+/g, '')))
.filter(d => !d.querySelector('div'));
const seen = new Set();
return items.map(d => {
const m = d.textContent.match(/\((\d+)\)\s*([✓✗])/);
return m ? {n: +m[1], wrong: m[2] === '✗'} : null;
}).filter(Boolean).filter(i => seen.has(i.n) ? false : (seen.add(i.n), true));
}"返回 [{n:1, wrong:true}, ...]。这次 eval 不点任何东西,纯读。
playwright-cli --s=default eval "(wrongNums) => new Promise(async resolve => {
const results = {};
const allItems = Array.from(document.querySelectorAll('div'))
.filter(d => /^\(\d+\)\s*[✓✗]$/.test(d.textContent.trim().replace(/\s+/g, '')))
.filter(d => !d.querySelector('div'));
for (const n of wrongNums) {
const item = allItems.find(d => d.textContent.includes('(' + n + ')'));
if (!item) { results[n] = 'NOT FOUND'; continue; }
item.click();
await new Promise(r => setTimeout(r, 400));
const detail = document.body.innerText;
const start = detail.search(/(题目前引导|题干|得分)/);
let end = detail.length;
const nextMatch = detail.slice(start + 50).match(/\n\(\d+\)\s*[✓✗]/);
if (nextMatch) end = start + 50 + nextMatch.index;
results[n] = detail.slice(start, end);
}
resolve(results);
})" '[1,8,17]'调用方式:'<上面整段代码>' '[1,8,17]' —— 外层引号包代码,第二个参数是 JSON 数组字符串。
playwright-cli --s=default eval "(wrongNums) => new Promise(async resolve => {
const tr = {};
const allItems = Array.from(document.querySelectorAll('div'))
.filter(d => /^\(\d+\)\s*[✓✗]$/.test(d.textContent.trim().replace(/\s+/g, '')))
.filter(d => !d.querySelector('div'));
for (const n of wrongNums) {
const item = allItems.find(d => d.textContent.includes('(' + n + ')'));
item.click();
await new Promise(r => setTimeout(r, 400));
const btn = Array.from(document.querySelectorAll('button, div, span'))
.find(e => e.textContent.trim() === '原文' && e.children.length === 0);
if (btn) {
btn.scrollIntoView({block: 'center'});
btn.click();
await new Promise(r => setTimeout(r, 300));
const pop = Array.from(document.querySelectorAll('.el-popover'))
.find(p => getComputedStyle(p).display !== 'none' && p.offsetHeight > 0);
tr[n] = pop ? pop.innerText : '(no popover)';
} else {
tr[n] = '(no 原文 btn)';
}
}
resolve(tr);
})" '[5,14,26,27]'T2 切 section → T3 拿错题列表 → T4 拿右栏 innerText → T5 拿 transcript(仅听力)4 个 section 一共 4 × (1 T2 + 1 T3 + 1 T4 + 0/1 T5) = 12-16 次 eval,0 次 click,0 次 snapshot。
从用户消息里抽 homework/student/(\d+),抽不到就自然语言追问一次:
"请粘贴完整的 mingshihuichuguo.com 作业链接,格式:https://mingshihuichuguo.com/homework/student/<数字>"合法:https / http 都行,纯数字 id。追问第二次还错就退出。
~/.msh-skill-state.json文件不存在就跳过这一步。文件存在则读 {browser, lastRestartAck}:
OS:uname -s(失败 fallback node -e "console.log(process.platform)")。
浏览器探测按 OS 走(只跑第一个找到的两个就停):
ls Edge/Chrome 常见安装路径 ls "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" 2>/dev/null
ls "C:/Program Files/Microsoft/Edge/Application/msedge.exe" 2>/dev/null
ls "C:/Program Files/Google/Chrome/Application/chrome.exe" 2>/dev/nullls /Applications/Microsoft Edge.app /Applications/Google Chrome.appwhich msedge microsoft-edge google-chrome google-chrome-stable判定:
npx playwright-cli --version
ls "$USERPROFILE/.playwright/cli.config.json" 2>/dev/null
curl -s --max-time 2 http://127.0.0.1:9222/json/versionnpm install -g @playwright/cli(只这一次)references/数据获取.md 重启浏览器跑完跑一次:
node -e "require('fs').writeFileSync(require('os').homedir()+'/.msh-skill-state.json', JSON.stringify({browser:'msedge',lastRestartAck:new Date().toISOString()},null,2))"替换 msedge 为实际浏览器名。
只在第一次(缓存里没 lastRestartAck)问一次:
"要附加到 Edge 抓数据,需要带 --remote-debugging-port=9222 重启 Edge。会杀掉所有 Edge 进程(未保存 tab/表单会丢),重启后会恢复 tab 和登录态。"
确认后跑一次;之后同会话内不重复问。下次有缓存直接跳过。
参考 references/数据获取.md 的"快进抓取"小节:
输出位置(用户桌面):
~/Desktop/阅读.txt
~/Desktop/听力.txt只分析错的题。对的题不写,不总结"对了几道/错了哪几道"。
告诉用户两个文件路径(仅此一句,别复述做了什么)。
写报告前先 bash 数一次这次跑的 playwright-cli 命令分布:
# bash 历史可能没用,改用:scan 之前所有调用的命令记录
# 简化:自己数一下
echo "playwright-cli click count: <自己数>"
echo "playwright-cli snapshot count: <自己数>"
echo "playwright-cli tab-select count: <自己数>"过线标准:
playwright-cli --s=default click 调用次数 ≤ 4(最多 4 个 section 各 1 次 T2 切 section)playwright-cli --s=default snapshot = 0playwright-cli --s=default tab-select = 0任意一项超线 = 回去重抓。问自己:
写完报告再 grep 一次桌面文件长度(wc -l 两份),过短说明数据没抓全。
完整对照见 references/style-guide.md。最关键的几条:
/。阅读.txt,别带"第五次模考-真题16-"这种长前缀)。不要:完整答案列表、抄题目、原文整段贴、生词三栏字典。
references/style-guide.md — 风格正反例references/数据获取.md — 拿 URL → 抓数据的流程(含快进抓取代码段)references/模板对照.md — 同一道题,手写版 vs AI 版的对比手写错题分析/ — 5 份原始手写样本~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.