feat(meowpanel): 通知中心+文件管理后端补全 (agent-182) — /api/notifications(读TF归档,环形200条)+单删+dismiss_all(保留媒体/进度活动通知); 文件域修4bug(normalize_path丢前导/致白名单必失败、upload multipart 文件名截断恒NULL、rename拼错路径恒ENOTDIR、read>1MB改truncated) + 上传8MB上限+文件名净化+双重白名单防逃逸

meowpanel 8108852f→58a7b186; mipsel/host -Wall -Wextra 0 warning; 宿主 curl 自测全过
需launcher配合项(已记录): MSG_NOTIFY_QUERY 查询帧 + dismiss 广播 IPC
This commit is contained in:
MeowOS committed 2026-08-31 04:14:00 +08:00
1 parent c187b7bce3
commit 563a9be1d6
5 files changed
+438 -75

No files matched your search

+12 -2
View File
@@ -339,7 +339,7 @@
});
}
function doDownload(url, name) {
apiDownload(url).then(blobUrl => {
return apiDownload(url).then(blobUrl => {
const a = document.createElement('a'); a.href = blobUrl; a.download = name || 'file';
document.body.appendChild(a); a.click(); a.remove();
setTimeout(() => URL.revokeObjectURL(blobUrl), 5000);
@@ -432,7 +432,17 @@
if (install) { const fi = $('#app-file'); if (fi) { fi.value = ''; fi.click(); } return; }
if (refresh) { renderApps(); return; }
if (info) { appInfo(info.dataset.ainfo); return; }
if (exp) { e.preventDefault(); doDownload('/api/apps/' + exp.dataset.aexport + '/export', exp.dataset.aexport + '.mpk'); return; }
if (exp) {
e.preventDefault();
if (exp.dataset.busy) return; /* 打包期间防连点 */
exp.dataset.busy = '1';
const oldTxt = exp.textContent;
exp.textContent = '打包中…';
toast('正在打包导出 ' + exp.dataset.aexport + ',请稍候…');
doDownload('/api/apps/' + exp.dataset.aexport + '/export', exp.dataset.aexport + '.mpk')
.finally(() => { delete exp.dataset.busy; exp.textContent = oldTxt; });
return;
}
if (uninst) { appUninstall(uninst.dataset.auninst); return; }
if (goPath) { installFromPath($('#app-install-path').value); return; }
});