Harden auth/vault path sanitization and clean WeKnora docs
This commit is contained in:
@@ -1186,15 +1186,15 @@
|
||||
var documentId = String(urlDocumentId || activeWorkspacePath.documentId || active.documentId || '').trim();
|
||||
var fileTreeWorkspacePath = activeFileTreeWorkspacePath(documentId) || {};
|
||||
var workspacePath = Object.assign({}, activeWorkspacePath, fileTreeWorkspacePath);
|
||||
var session = piLabState.session || {};
|
||||
var pagePath = normalizeSlashes(urlPagePath || workspacePath.relativePath || workspacePath.path || active.relativePath || active.path || localMarkdownRelativePathFromDocumentId(documentId) || session.pagePath || '');
|
||||
// Do not fall back to piLabState.session.* — that re-amplifies stale context after navigation.
|
||||
var pagePath = normalizeSlashes(urlPagePath || workspacePath.relativePath || workspacePath.path || active.relativePath || active.path || localMarkdownRelativePathFromDocumentId(documentId) || '');
|
||||
var resourceKind = String(workspacePath.resourceKind || workspacePath.kind || active.resourceKind || active.kind || '').trim().toLowerCase();
|
||||
var isDirectory = resourceKind === 'directory' || resourceKind === 'folder' || resourceKind === 'workspace';
|
||||
var isStandalonePiPage = currentUrl().pathname === '/page-ai/pi';
|
||||
var isLocalMarkdownPage = documentId.indexOf('local-md:') === 0 || /\.md$/i.test(pagePath);
|
||||
if (isDirectory || (isStandalonePiPage && pagePath && !isLocalMarkdownPage)) pagePath = '';
|
||||
var rootUri = String(currentRootUri() || workspacePath.rootUri || active.rootUri || session.rootUri || '').trim();
|
||||
var workspaceId = String(currentWorkspaceId() || workspacePath.workspaceId || active.workspaceId || session.workspaceId || '').trim();
|
||||
var rootUri = String(currentRootUri() || workspacePath.rootUri || active.rootUri || '').trim();
|
||||
var workspaceId = String(currentWorkspaceId() || workspacePath.workspaceId || active.workspaceId || '').trim();
|
||||
var titleNode = document.querySelector('[data-page-title-current="true"]') || document.querySelector('.wolai-breadcrumb-current');
|
||||
var title = String(active.title || workspacePath.title || (titleNode && titleNode.textContent) || document.title || '').trim();
|
||||
var selection = currentSelectionText();
|
||||
@@ -1278,12 +1278,13 @@
|
||||
var context = currentPageContext();
|
||||
refreshSelectionSummary();
|
||||
if (!piLabState.session) piLabState.session = {};
|
||||
if (context.pagePath) piLabState.session.pagePath = context.pagePath;
|
||||
if (context.pageTitle) piLabState.session.pageTitle = context.pageTitle;
|
||||
if (context.rootUri) piLabState.session.rootUri = context.rootUri;
|
||||
if (context.workspaceId) piLabState.session.workspaceId = context.workspaceId;
|
||||
// Always sync (including empty) so navigation away from a page clears stale context.
|
||||
piLabState.session.pagePath = context.pagePath || '';
|
||||
piLabState.session.pageTitle = context.pageTitle || '';
|
||||
piLabState.session.rootUri = context.rootUri || '';
|
||||
piLabState.session.workspaceId = context.workspaceId || '';
|
||||
var folderPath = currentFolderPathFromPagePath(context.pagePath);
|
||||
if (folderPath !== null) piLabState.session.folderPath = folderPath;
|
||||
piLabState.session.folderPath = folderPath === null ? '' : folderPath;
|
||||
updateContextStrip();
|
||||
return context;
|
||||
}
|
||||
@@ -2294,11 +2295,11 @@
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
function deleteHistorySession(sessionId) {
|
||||
async function deleteHistorySession(sessionId) {
|
||||
if (!sessionId) return Promise.resolve();
|
||||
var existing = currentHistorySession(sessionId);
|
||||
var title = existing ? historyTitle(existing) : sessionId;
|
||||
if (!window.confirm('删除历史对话“' + title + '”?')) return Promise.resolve();
|
||||
if (!(await window.mnote.confirm('删除历史对话“' + title + '”?'))) return Promise.resolve();
|
||||
return fetch(API.SESSIONS + '/' + encodeURIComponent(sessionId), {
|
||||
method: 'DELETE',
|
||||
credentials: 'same-origin',
|
||||
@@ -2313,10 +2314,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
function clearHistorySessions() {
|
||||
async function clearHistorySessions() {
|
||||
var count = Array.isArray(piLabState.history) ? piLabState.history.length : 0;
|
||||
if (!count) return Promise.resolve();
|
||||
if (!window.confirm('清空全部 ' + count + ' 条 Pi 历史对话?')) return Promise.resolve();
|
||||
if (!(await window.mnote.confirm('清空全部 ' + count + ' 条 Pi 历史对话?'))) return Promise.resolve();
|
||||
return fetch(API.SESSIONS + '?limit=1000', {
|
||||
method: 'DELETE',
|
||||
credentials: 'same-origin',
|
||||
@@ -2618,8 +2619,10 @@
|
||||
if (lightrag) lightrag.textContent = '唯一默认';
|
||||
if (changedFiles) {
|
||||
var files = {};
|
||||
piLabState.changedFiles.forEach(function (file) { if (file) files[file] = true; });
|
||||
piLabState.messages.forEach(function (msg) {
|
||||
(Array.isArray(piLabState.changedFiles) ? piLabState.changedFiles : []).forEach(function (file) {
|
||||
if (file) files[file] = true;
|
||||
});
|
||||
(Array.isArray(piLabState.messages) ? piLabState.messages : []).forEach(function (msg) {
|
||||
if (msg && msg.diffSummary && Array.isArray(msg.diffSummary.files)) {
|
||||
msg.diffSummary.files.forEach(function (file) { if (file) files[file] = true; });
|
||||
}
|
||||
@@ -3264,7 +3267,7 @@
|
||||
function collectPiArtifacts() {
|
||||
var artifacts = [];
|
||||
var seen = {};
|
||||
piLabState.messages.forEach(function (msg) {
|
||||
(Array.isArray(piLabState.messages) ? piLabState.messages : []).forEach(function (msg) {
|
||||
if (!msg) return;
|
||||
(Array.isArray(msg.citations) ? msg.citations : []).forEach(function (cit, index) {
|
||||
var key = 'citation:' + (cit.url || cit.source || cit.title || index);
|
||||
@@ -3307,7 +3310,7 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
piLabState.changedFiles.forEach(function (file) {
|
||||
(Array.isArray(piLabState.changedFiles) ? piLabState.changedFiles : []).forEach(function (file) {
|
||||
if (!file || seen['diff:' + file]) return;
|
||||
seen['diff:' + file] = true;
|
||||
artifacts.push({ kind: 'diff', title: file, summary: '文件变更' });
|
||||
@@ -3722,8 +3725,10 @@
|
||||
|
||||
function handleToolCallEventPayload(payload) {
|
||||
payload = payload || {};
|
||||
// Fail-closed: only explicit allowed===true triggers side effects / changedFiles.
|
||||
var allowed = payload.allowed === true;
|
||||
applyToolCallSideEffects({
|
||||
ok: payload.allowed !== false,
|
||||
ok: allowed,
|
||||
toolName: payload.toolName,
|
||||
result: {
|
||||
rootUri: payload.rootUri,
|
||||
@@ -3733,7 +3738,7 @@
|
||||
});
|
||||
piLabState.receipts.push({
|
||||
toolName: payload.toolName,
|
||||
allowed: payload.allowed !== false,
|
||||
allowed: allowed,
|
||||
denyReason: payload.denyReason || null,
|
||||
diffSummary: payload.diffSummary || null,
|
||||
citationCount: payload.citationCount || 0,
|
||||
@@ -3746,9 +3751,9 @@
|
||||
toolCallId: payload.toolCallId || payload.id || ('receipt:' + (payload.toolName || 'tool') + ':' + piLabState.receipts.length),
|
||||
toolName: payload.toolName || 'tool',
|
||||
args: payload.params || payload.args || {},
|
||||
}, payload.allowed === false ? 'denied' : 'done', {
|
||||
}, allowed ? 'done' : 'denied', {
|
||||
result: {
|
||||
allowed: payload.allowed !== false,
|
||||
allowed: allowed,
|
||||
denyReason: payload.denyReason || null,
|
||||
diffSummary: payload.diffSummary || null,
|
||||
citationCount: payload.citationCount || 0,
|
||||
@@ -3757,7 +3762,9 @@
|
||||
approvalConfirmed: payload.approvalConfirmed === true,
|
||||
toolPolicy: payload.toolPolicy || '',
|
||||
});
|
||||
if (payload.normalizedFilePath && payload.diffSummary) piLabState.changedFiles.push(payload.normalizedFilePath);
|
||||
if (allowed && payload.normalizedFilePath && payload.diffSummary) {
|
||||
piLabState.changedFiles.push(payload.normalizedFilePath);
|
||||
}
|
||||
updateReceiptDisplay();
|
||||
updateContextStrip();
|
||||
}
|
||||
@@ -4591,7 +4598,8 @@
|
||||
function parseUnifiedPatch(patchText) {
|
||||
if (!patchText) return [];
|
||||
var files = [];
|
||||
var fileLines = patchText.split('\\n');
|
||||
// Real newlines (JSON-parsed patch text), not the two-char sequence \ + n.
|
||||
var fileLines = String(patchText).replace(/\r\n/g, '\n').split('\n');
|
||||
|
||||
var currentFile = null;
|
||||
var currentHunk = null;
|
||||
@@ -4982,8 +4990,8 @@
|
||||
}
|
||||
var copyMarkdown = event.target && event.target.closest ? event.target.closest('[data-page-ai-pi-lab-copy-markdown]') : null;
|
||||
if (copyMarkdown) {
|
||||
copyTextToClipboard(copyMarkdown.getAttribute('data-page-ai-pi-lab-copy-markdown') || '').then(function () {
|
||||
showPiToast('Markdown copied', 'success');
|
||||
copyTextToClipboard(copyMarkdown.getAttribute('data-page-ai-pi-lab-copy-markdown') || '').then(function (ok) {
|
||||
showPiToast(ok ? 'Markdown copied' : '复制失败(剪贴板不可用)', ok ? 'success' : 'warning');
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -4999,7 +5007,11 @@
|
||||
}
|
||||
var openArtifact = event.target && event.target.closest ? event.target.closest('[data-page-ai-pi-lab-artifact-open]') : null;
|
||||
if (openArtifact) {
|
||||
var artUrl = openArtifact.getAttribute('data-page-ai-pi-lab-artifact-open') || openArtifact.getAttribute('href') || '';
|
||||
var artUrl = String(openArtifact.getAttribute('data-page-ai-pi-lab-artifact-open') || openArtifact.getAttribute('href') || '').trim();
|
||||
if (!artUrl || artUrl === '#') {
|
||||
showPiToast('引用无效或无法访问', 'warning');
|
||||
return;
|
||||
}
|
||||
window.dispatchEvent(new CustomEvent('mnote:open-reference', {
|
||||
detail: {
|
||||
source: 'page_ai_pi_lab_artifact',
|
||||
@@ -5007,9 +5019,7 @@
|
||||
url: artUrl,
|
||||
},
|
||||
}));
|
||||
if (!artUrl || artUrl === '#') {
|
||||
showPiToast('引用无效或无法访问', 'warning');
|
||||
}
|
||||
return;
|
||||
}
|
||||
var viewDiff = event.target && event.target.closest ? event.target.closest('[data-page-ai-pi-lab-artifact-view-diff]') : null;
|
||||
if (viewDiff) {
|
||||
@@ -5020,15 +5030,17 @@
|
||||
}
|
||||
var copyArtifactMarkdown = event.target && event.target.closest ? event.target.closest('[data-page-ai-pi-lab-artifact-copy-markdown]') : null;
|
||||
if (copyArtifactMarkdown) {
|
||||
copyTextToClipboard(copyArtifactMarkdown.getAttribute('data-page-ai-pi-lab-artifact-copy-markdown') || '').then(function () {
|
||||
showPiToast('Artifact markdown copied', 'success');
|
||||
copyTextToClipboard(copyArtifactMarkdown.getAttribute('data-page-ai-pi-lab-artifact-copy-markdown') || '').then(function (ok) {
|
||||
showPiToast(ok ? 'Artifact markdown copied' : '复制失败(剪贴板不可用)', ok ? 'success' : 'warning');
|
||||
});
|
||||
return;
|
||||
}
|
||||
var copyArtifact = event.target && event.target.closest ? event.target.closest('[data-page-ai-pi-lab-artifact-copy]') : null;
|
||||
if (copyArtifact) {
|
||||
var raw = copyArtifact.getAttribute('data-page-ai-pi-lab-artifact-copy') || '';
|
||||
copyTextToClipboard(raw).then(function () { showPiToast('Artifact raw copied', 'success'); });
|
||||
copyTextToClipboard(raw).then(function (ok) {
|
||||
showPiToast(ok ? 'Artifact raw copied' : '复制失败(剪贴板不可用)', ok ? 'success' : 'warning');
|
||||
});
|
||||
return;
|
||||
}
|
||||
var deleteTarget = event.target && event.target.closest ? event.target.closest('[data-page-ai-pi-lab-history-delete]') : null;
|
||||
|
||||
Reference in New Issue
Block a user