- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目 - 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线 - 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径 验证: - cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1 - cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1 - git diff --check - git diff --cached --check - codegraph index . --force && codegraph status . - codegraph sync . && codegraph status .
133 lines
5.6 KiB
JavaScript
133 lines
5.6 KiB
JavaScript
export function createSidebarPageAiPermissionRuntime(context) {
|
|
const {
|
|
documentRef,
|
|
pageAiPreviewValue,
|
|
pageUiState,
|
|
renderPageAiConversation,
|
|
} = context;
|
|
const doc = documentRef || document;
|
|
|
|
function pageAiPermissionMessage(payload, eventType) {
|
|
payload = payload && typeof payload === 'object' ? payload : {};
|
|
var permissionId = String(payload.permissionId || payload.permission_id || payload.id || ('perm_' + Date.now())).trim();
|
|
var toolName = String(payload.toolName || payload.tool || payload.name || payload.method || 'session/request_permission').trim();
|
|
var args = payload.arguments || payload.args || payload.input || payload.params || payload;
|
|
var decision = String(payload.decision || payload.result || '').trim();
|
|
if (!decision && eventType === 'permission.denied') decision = 'denied';
|
|
if (!decision && eventType === 'permission.allowed') decision = 'allowed';
|
|
return {
|
|
role: 'tool',
|
|
kind: 'permission',
|
|
permissionId: permissionId,
|
|
toolName: toolName,
|
|
argsSummary: pageAiPreviewValue(args),
|
|
content: decision === 'denied' ? '已自动拒绝权限请求' : (decision === 'allowed' ? '已自动允许权限请求' : '等待权限确认'),
|
|
resolved: decision === 'denied' || decision === 'allowed',
|
|
decision: decision
|
|
};
|
|
}
|
|
|
|
function pageAiApplyPermissionEvent(eventName, payloadText) {
|
|
var payload = null;
|
|
try {
|
|
payload = JSON.parse(payloadText || 'null');
|
|
} catch (_) {
|
|
payload = {};
|
|
}
|
|
var message = pageAiPermissionMessage(payload, eventName);
|
|
var existing = pageUiState.pageAiMessages.find(function(item) {
|
|
return item.kind === 'permission' && item.permissionId === message.permissionId;
|
|
});
|
|
if (existing) {
|
|
Object.assign(existing, message);
|
|
} else {
|
|
pageUiState.pageAiMessages.push(message);
|
|
}
|
|
pageUiState.pageAiPermissionRequests = pageUiState.pageAiPermissionRequests.filter(function(item) {
|
|
return item.permissionId !== message.permissionId;
|
|
}).concat([message]).slice(-20);
|
|
if (!message.resolved) {
|
|
pageAiShowPermissionDialog(message);
|
|
} else {
|
|
pageAiHidePermissionDialog();
|
|
}
|
|
}
|
|
|
|
function pageAiResolvePermission(permissionId, decision) {
|
|
permissionId = String(permissionId || '').trim();
|
|
if (!permissionId) return;
|
|
var runId = pageUiState.pageAiCurrentRunId;
|
|
if (runId) {
|
|
fetch('/api/hermes/client/runs/' + encodeURIComponent(runId) + '/resolve-permission', {
|
|
method: 'POST',
|
|
headers: { 'content-type': 'application/json' },
|
|
body: JSON.stringify({ permissionId: permissionId, decision: decision })
|
|
}).then(function(response) {
|
|
if (!response.ok) console.warn('resolve-permission 后端返回异常', response.status);
|
|
}).catch(function(err) {
|
|
console.warn('resolve-permission 请求失败', err);
|
|
});
|
|
} else {
|
|
console.warn('resolve-permission: 无活跃 runId,只能本地更新');
|
|
}
|
|
pageUiState.pageAiMessages.forEach(function(item) {
|
|
if (item.kind === 'permission' && item.permissionId === permissionId) {
|
|
item.resolved = true;
|
|
item.decision = decision;
|
|
item.content = decision === 'allow' ? '已允许权限请求' : '已拒绝权限请求';
|
|
}
|
|
});
|
|
var dialog = doc.querySelector('[data-page-ai-permission-dialog]');
|
|
if (dialog instanceof HTMLElement) dialog.hidden = true;
|
|
renderPageAiConversation();
|
|
}
|
|
|
|
function pageAiHidePermissionDialog() {
|
|
var dialog = doc.querySelector('[data-page-ai-permission-dialog]');
|
|
if (dialog instanceof HTMLElement) dialog.hidden = true;
|
|
}
|
|
|
|
function pageAiShowPermissionDialog(message) {
|
|
if (!message || message.kind !== 'permission') return;
|
|
if (message.resolved) {
|
|
pageAiHidePermissionDialog();
|
|
return;
|
|
}
|
|
var dialog = doc.querySelector('[data-page-ai-permission-dialog]');
|
|
if (!(dialog instanceof HTMLElement)) {
|
|
dialog = doc.createElement('div');
|
|
dialog.className = 'wolai-page-ai-permission-dialog';
|
|
dialog.setAttribute('data-page-ai-permission-dialog', 'true');
|
|
dialog.innerHTML = '' +
|
|
'<div class="wolai-page-ai-permission-panel" role="dialog" aria-modal="false">' +
|
|
'<div class="wolai-page-ai-memory-title" data-page-ai-permission-tool></div>' +
|
|
'<div class="wolai-page-ai-tool-meta" data-page-ai-permission-args></div>' +
|
|
'<div class="wolai-page-ai-message-actions">' +
|
|
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-permission-action="allow" data-page-ai-permission-dialog-action>允许</button>' +
|
|
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-permission-action="deny" data-page-ai-permission-dialog-action>拒绝</button>' +
|
|
'</div>' +
|
|
'</div>';
|
|
doc.body.appendChild(dialog);
|
|
}
|
|
var tool = dialog.querySelector('[data-page-ai-permission-tool]');
|
|
if (tool instanceof HTMLElement) tool.textContent = message.toolName || 'session/request_permission';
|
|
var args = dialog.querySelector('[data-page-ai-permission-args]');
|
|
if (args instanceof HTMLElement) args.textContent = message.argsSummary || message.content || '';
|
|
dialog.querySelectorAll('[data-page-ai-permission-dialog-action]').forEach(function(button) {
|
|
if (button instanceof HTMLButtonElement) {
|
|
button.setAttribute('data-page-ai-permission-id', message.permissionId || '');
|
|
button.disabled = Boolean(message.resolved);
|
|
}
|
|
});
|
|
dialog.hidden = false;
|
|
}
|
|
|
|
return {
|
|
pageAiPermissionMessage,
|
|
pageAiApplyPermissionEvent,
|
|
pageAiResolvePermission,
|
|
pageAiHidePermissionDialog,
|
|
pageAiShowPermissionDialog
|
|
};
|
|
}
|