Claude Code, Skill
Pptedit
创建、修改、调试和验收 H5、HTML 单页、落地页与网页 Deck。当任务需要修改真实网页源码并在浏览器中验证时使用;不适用于没有 HTML 运行时的原生演示文件。
Compatibility: Not stated.
Grade C
One Medium finding. Read the report before installing.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
OBFUSCATION_MINIFIED_PAYLOAD
Why this grade
- OBFUSCATION_MINIFIED_PAYLOAD Medium
Contains a very long line with almost no spaces in a script or style file.
assets/layout-reference.js, line 71
function acceptFile(file){if(busy||!file)return;figmaSource=null;updateMode();const version=++importVersion;if(activeImport){activeImport.abort();activeImport=null;}loadedUrl='';q(
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Concern
can delete files.
PERMISSION_DELETE_FILES
scripts/figma_mcp.py, line 35
self.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
scripts/figma_reference.py, line 33
process=subprocess.run(['curl','--fail','--location','--silent','--show-error',
scripts/local_codex.py, line 24
result = subprocess.run([executable, '--version'], capture_output=True, text=True, timeout=10)
Show more
scripts/local_codex.py, line 62
result = subprocess.run(command, input=prompt, text=True, encoding='utf-8', stdout=log, stderr=log,
scripts/local_notes.py, line 33
proc = subprocess.run([str(python), str(Path(__file__).with_name('generate-notes-local.py')),
scripts/setup-local-codex.py, line 37
login = subprocess.run([runtime['path'], 'login', 'status'], capture_output=True, text=True, timeout=15)
scripts/setup-local-codex.py, line 60
process = subprocess.Popen([sys.executable, str(Path(__file__).with_name('layout-bridge.py')),
scripts/test-chapters-browser.mjs, line 61
} finally { await browser?.close(); adapter.kill(); server.close(); await fs.rm(root, { recursive: true, force: true }); }
scripts/test-figma-mcp.py, line 45
patch('figma_mcp.subprocess.Popen',return_value=process),patch('figma_mcp.threading.Thread'),\
scripts/test-order-sync-browser.mjs, line 55
}finally{await browser?.close();adapter.kill();server.close();await fs.rm(root,{recursive:true,force:true});}
scripts/test-overview-drag-browser.mjs, line 89
}finally{await browser?.close();server.kill();staticServer.close();await fs.rm(root,{recursive:true,force:true});}
scripts/test-page-grouping-browser.mjs, line 61
}finally{await browser?.close();adapter.kill();server.close();await fs.rm(root,{recursive:true,force:true});}
scripts/test-page-sorting-browser.mjs, line 103
} finally {await browser?.close();server.kill();await fs.rm(root,{recursive:true,force:true});}
Install and update
Pass
No install-time script found, and dependencies are pinned or absent.
Network
Concern
can reach a host that is not written as a fixed address. can reach raw.githubusercontent.com. The description does not name that host.
NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST
assets/layout-reference.js, line 68
path,options={})=>{const response=await fetch(config.url+path,{...options,headers:{'Co
assets/notes-editor.js, line 23
abort(),15000);try{const response=await fetch(config.url+path,{...options,signal:contr
assets/pptedit-frame.js, line 30
const response = await fetch('/state?page=' + page, { headers });
Show more
assets/pptedit-frame.js, line 96
const response = await fetch('/delete-page', { method: 'POST', headers, body: JSON.stringify({ page: targetPage, previousOrder }) });
assets/pptedit-frame.js, line 208
const response = await fetch('/reorder', { method: 'POST', headers, body: JSON.stringify({ order, previousOrder, navigation }) });
assets/pptedit-frame.js, line 336
cached = { text: fetch(imagePath, { cache: 'no-cache' }).then(response => {
assets/pptedit-frame.js, line 489
const response = await fetch('/save', { method: 'POST', headers, body: JSON.stringify({ page, svg, revision: source.revision }) });
assets/preview-edit-mode.js, line 114
const response = await fetch(config.url + '/health', { signal: AbortSignal.timeout(4000) });
scripts/test-chapters-browser.mjs, line 25
for (let i = 0; i < 50; i++) { try { if ((await fetch(`http://127.0.0.1:${port}/health`)).ok) break; } catch {} await new Promise(r => setTimeout(r, 100)); }
scripts/test-order-sync-browser.mjs, line 19
for(let i=0;i<50;i++){try{if((await fetch(`http://127.0.0.1:${port}/health`)).ok)break;}catch{}await new Promise(r=>setTimeout(r,100));}
scripts/test-overview-drag-browser.mjs, line 57
for(let i=0;i<60;i++){try{if((await fetch(`http://127.0.0.1:${port}/health`)).ok)break;}catch{}await new Promise(r=>setTimeout(r,100));}
scripts/test-page-delete-browser.mjs, line 23
try { if ((await fetch(`http://127.0.0.1:${port}/health`)).ok) break; } catch {}
scripts/test-page-grouping-browser.mjs, line 19
for(let i=0;i<50;i++){try{if((await fetch(`http://127.0.0.1:${port}/health`)).ok)break;}catch{}await new Promise(r=>setTimeout(r,100));}
scripts/test-page-grouping-browser.mjs, line 58
const conflict=await fetch(`http://127.0.0.1:${port}/chapters`,{met
scripts/test-page-sorting-browser.mjs, line 20
for (let i=0;i<50;i++) {try {if ((await fetch(`http://127.0.0.1:${port}/health`)).ok) break;}catch{} await new Promise(r=>setTimeout(r,100));}
scripts/test-svg-group-browser.mjs, line 22
try { if ((await fetch(`http://127.0.0.1:${port}/health`)).ok) break; } catch {}
Secrets
Concern
reads a credential or environment file.
SECRETS_PATH_DOTENV
.gitignore, line 2
._*
.gitignore, line 3
.env
.gitignore, line 5
!.env.example
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Concern
contains a minified payload.
OBFUSCATION_MINIFIED_PAYLOAD
assets/layout-reference.js, line 71
function acceptFile(file){if(busy||!file)return;figmaSource=null;updateMode();const version=++importVersion;if(activeImport){activeImport.abort();activeImport=null;}loadedUrl='';q(
assets/layout-reference.js, line 104
async function loadHistory(){const targetPage=Number(page?.page),version=++historyVersion;historyList.textContent='正在读取当前页记录…';try{const result=await request('/history');if(version
assets/h5-editor/editor.js, line 1
/**
Show more
scripts/test-notes-editor.mjs, line 9
const context={window:{PPT_NARRATION_HOST:{getSlides:()=>[slide],getIndex:()=>0,goTo:()=>rendered++},PPT_LAYOUT_REFERENCE:{url:'http://127.0.0.1:48765',token:'test'}},document:{get
scripts/test-order-sync-browser.mjs, line 13
await fs.writeFile(path.join(root,'index.html'),`<!doctype html><meta charset="utf-8"><link rel="stylesheet" href="/assets/preview-navigation.css"><link rel="stylesheet" href="/ass
scripts/test-order-sync-browser.mjs, line 16
const server=http.createServer(async(req,res)=>{try{const url=new URL(req.url,'http://local').pathname;const file=url.startsWith('/assets/')?path.join(process.cwd(),url):path.join(
scripts/test-page-grouping-browser.mjs, line 13
await fs.writeFile(path.join(root,'index.html'),`<!doctype html><meta charset="utf-8"><link rel="stylesheet" href="/assets/preview-navigation.css"><link rel="stylesheet" href="/ass
scripts/test-page-grouping-browser.mjs, line 16
const server=http.createServer(async(req,res)=>{try{const url=new URL(req.url,'http://local').pathname;const file=url.startsWith('/assets/')?path.join(process.cwd(),url):path.join(
Licence
Pass
A licence file is present (LICENSE).
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit 115bb9c8280d. can delete files. can reach a host that is not written as a fixed address. can reach raw.githubusercontent.com. The description does not name that host. reads a credential or environment file. contains a minified payload.
Date and source
Date checked:
github.com
Commit graded: 115bb9c8280d41339c1f79618d374cf7576adc66
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.