chore: retire openhub and pi ts runtime

This commit is contained in:
Agent Board
2026-07-12 14:18:26 +08:00
parent 62959b0c4d
commit 2f5902e3e7
45 changed files with 367 additions and 925 deletions
@@ -1,7 +1,7 @@
// == Pi Lab Page AI Runtime ==
// MNote-native adapter for Pi-first Page AI Lab.
// Renders the MNote-owned Pi Rust Page AI surface. OpenHub is kept as a
// compatibility/admin boundary during migration, not as the default chat owner.
// Renders the MNote-owned Pi Rust Page AI surface. Retired hosts stay in
// recycle; this runtime must stay independent.
// NO setInterval polling.
//
// UI note: @earendil-works/pi-web-ui@0.75.3 was checked as the mature upstream UI.
@@ -199,12 +199,6 @@ export function createSidebarPageAiRuntime(context) {
pageAiOpencodeEventSource: null,
pageAiOpencodeEventSessionId: '',
pageAiOpencodeEventTimer: 0,
pageAiOpenHubStatus: null,
pageAiOpenHubStatusError: '',
pageAiOpenHubBootstrap: null,
pageAiOpenHubIframeUrl: '',
pageAiOpenHubScopeSummary: '',
pageAiOpenHubFallbackReason: '',
pageAiSessionSearchQuery: '',
pageAiSessionSearchResults: [],
pageAiSessionSearchTimer: 0,
@@ -892,10 +886,6 @@ export function createSidebarPageAiRuntime(context) {
}
}
function pageAiOpenHubHostEnabled() {
return true;
}
function pageAiOpencodeStatusLabel(status) {
var node = status && typeof status === 'object' ? status : {};
var state = String(node.status || node.state || node.runtimeStatus || '').trim();
@@ -1151,116 +1141,6 @@ export function createSidebarPageAiRuntime(context) {
return lines.join('\n');
}
function pageAiOpenHubScopeSummary(scope) {
var node = scope && typeof scope === 'object' ? scope : {};
var workspace = node.workspaceScope && typeof node.workspaceScope === 'object' ? node.workspaceScope : {};
var items = [];
if (node.openhubUserKey || node.openhub_user_key) items.push('openhub_user_key=' + String(node.openhubUserKey || node.openhub_user_key));
if (node.openhubWorkspaceKey || node.workspace_key) items.push('workspace_key=' + String(node.openhubWorkspaceKey || node.workspace_key));
if (workspace.workspaceId) items.push('workspace=' + String(workspace.workspaceId));
if (workspace.rootUri) items.push('rootUri=' + String(workspace.rootUri));
if (node.openhubSessionScope || node.session_scope) items.push('session_scope=' + String(node.openhubSessionScope || node.session_scope));
if (node.skillScope || node.skill_scope) items.push('skill_scope=' + String(node.skillScope || node.skill_scope));
if (node.mcpScope) items.push('mcp_scope=' + String(node.mcpScope));
if (node.toolPermissionScope || node.tool_permission_scope) items.push('tool_permission_scope=' + String(node.toolPermissionScope || node.tool_permission_scope));
if (node.weknoraToolScope || node.weknora_tool_scope) items.push('weknora_tool_scope=' + String(node.weknoraToolScope || node.weknora_tool_scope));
return items.join('\n');
}
function pageAiOpenHubStatusText(status) {
var node = status && typeof status === 'object' ? status : {};
if (node.ok === true || String(node.status || '').trim() === 'ready') return '已连接 OpenHub';
if (String(node.status || '').trim() === 'degraded') return 'OpenHub 连接受限';
return '正在连接 OpenHub';
}
function pageAiRenderOpenHubHostChrome() {
var drawer = document.querySelector('[data-testid="wolai-page-ai-drawer"]');
if (!(drawer instanceof HTMLElement) || drawer.getAttribute('data-page-ai-openhub-host') !== 'true') return;
var bootstrap = pageUiState.pageAiOpenHubBootstrap && typeof pageUiState.pageAiOpenHubBootstrap === 'object' ? pageUiState.pageAiOpenHubBootstrap : {};
var scope = bootstrap.scope && typeof bootstrap.scope === 'object' ? bootstrap.scope : {};
var status = pageUiState.pageAiOpenHubStatus && typeof pageUiState.pageAiOpenHubStatus === 'object' ? pageUiState.pageAiOpenHubStatus : {};
var statusNode = drawer.querySelector('[data-page-ai-openhub-runtime-status]');
if (statusNode instanceof HTMLElement) {
statusNode.textContent = pageUiState.pageAiOpenHubStatusError || pageAiOpenHubStatusText(status);
statusNode.setAttribute('data-state', pageUiState.pageAiOpenHubStatusError ? 'error' : (status.ok ? 'ok' : 'degraded'));
}
var userNode = drawer.querySelector('[data-page-ai-openhub-user-key]');
if (userNode instanceof HTMLElement) userNode.textContent = String(scope.openhubUserKey || scope.openhub_user_key || '等待 bootstrap');
var authNode = drawer.querySelector('[data-page-ai-openhub-auth-truth]');
if (authNode instanceof HTMLElement) authNode.textContent = '登录真相:MNote mnote_session;拒绝 OpenHub JWT/localStorage';
var workspaceNode = drawer.querySelector('[data-page-ai-openhub-workspace-scope]');
if (workspaceNode instanceof HTMLElement) workspaceNode.textContent = pageAiOpenHubScopeSummary(scope) || '等待 workspace/rootUri/session/tool scope';
var guardNode = drawer.querySelector('[data-page-ai-openhub-route-guard]');
if (guardNode instanceof HTMLElement) guardNode.textContent = '非 AI 路由 guardlogin/admin/file/knowledge 由 MNote 接管';
var fallbackNode = drawer.querySelector('[data-page-ai-openhub-fallback]');
if (fallbackNode instanceof HTMLElement) {
fallbackNode.textContent = pageUiState.pageAiOpenHubFallbackReason || 'OpenHub 不可用时提示用户刷新或检查服务,不再提供 opencode 页面回退';
}
var iframe = drawer.querySelector('[data-page-ai-openhub-iframe]');
if (iframe instanceof HTMLIFrameElement) {
var nextUrl = String(pageUiState.pageAiOpenHubIframeUrl || bootstrap.openhubIframeUrl || '/page-ai/openhub/ai').trim();
if (nextUrl && iframe.getAttribute('src') !== nextUrl) iframe.setAttribute('src', nextUrl);
iframe.hidden = !nextUrl;
}
}
function pageAiEnsureOpenHubHostDrawer() {
var drawer = ensurePageAiDrawer();
pageAiInstallMNoteOpenFileBridge();
if (drawer.getAttribute('data-page-ai-openhub-host') !== 'true') {
drawer.setAttribute('data-page-ai-openhub-host', 'true');
drawer.removeAttribute('data-page-ai-opencode-host');
drawer.setAttribute('data-mnote-acp-runtime', 'openhub-opencode');
drawer.innerHTML = '' +
'<div class="wolai-page-ai-resize-handle" data-page-ai-resize-handle title="拖动调整页面 AI 宽度" aria-hidden="true"></div>' +
'<div class="wolai-page-ai-panel wolai-page-ai-opencode-panel" role="dialog" aria-modal="false" aria-label="OpenHub AI">' +
'<details class="wolai-page-ai-openhub-diagnostics" data-page-ai-openhub-bootstrap-copy hidden aria-hidden="true">' +
'<summary>诊断</summary>' +
'<div class="wolai-page-ai-opencode-row"><span>用户隔离</span><code data-page-ai-openhub-user-key>等待 bootstrap</code></div>' +
'<div class="wolai-page-ai-opencode-row"><span>认证边界</span><strong data-page-ai-openhub-auth-truth>登录真相:MNote mnote_session</strong></div>' +
'<pre class="wolai-page-ai-opencode-empty" data-page-ai-openhub-workspace-scope>等待 workspace/rootUri/session/tool scope</pre>' +
'<div class="wolai-page-ai-opencode-badges"><span data-page-ai-openhub-route-guard>非 AI 路由 guardlogin/admin/file/knowledge</span><span data-page-ai-openhub-fallback>OpenHub 不可用时提示刷新或检查服务</span></div>' +
'</details>' +
'<div class="wolai-page-ai-opencode-frame-wrap" data-page-ai-openhub-frame-wrap>' +
'<iframe class="wolai-page-ai-opencode-iframe" data-page-ai-openhub-iframe title="OpenHub AI 面板" allow="clipboard-read; clipboard-write" referrerpolicy="same-origin" src="about:blank"></iframe>' +
'</div>' +
'</div>';
}
pageAiRenderOpenHubHostChrome();
void pageAiBootstrapOpenHubHost();
return drawer;
}
async function pageAiBootstrapOpenHubHost() {
var context = pageAiBuildOpencodeContextPayload();
try {
var statusResponse = await fetch('/api/page-ai/openhub/status', { headers: { accept: 'application/json' }, cache: 'no-store' });
pageUiState.pageAiOpenHubStatus = await statusResponse.json().catch(function() { return null; }) || {};
var response = await fetch('/api/page-ai/openhub/bootstrap', {
method: 'POST',
headers: { 'content-type': 'application/json', accept: 'application/json' },
cache: 'no-store',
body: JSON.stringify(context)
});
var payload = await response.json().catch(function() { return null; });
if (!response.ok) throw new Error(payload && (payload.error || payload.message) ? String(payload.error || payload.message) : 'HTTP ' + response.status);
pageUiState.pageAiOpenHubBootstrap = payload || {};
pageUiState.pageAiOpenHubStatusError = '';
pageUiState.pageAiOpenHubIframeUrl = String(payload && payload.openhubIframeUrl || '/page-ai/openhub/ai').trim();
var statusFallback = pageUiState.pageAiOpenHubStatus && pageUiState.pageAiOpenHubStatus.fallback ? pageUiState.pageAiOpenHubStatus.fallback : null;
pageUiState.pageAiOpenHubFallbackReason = payload && payload.fallback
? String(payload.fallback.reason || '')
: (statusFallback ? String(statusFallback.reason || '') : '');
pageUiState.pageAiOpenHubScopeSummary = pageAiOpenHubScopeSummary(payload && payload.scope);
pageAiRenderOpenHubHostChrome();
} catch (error) {
pageUiState.pageAiOpenHubStatusError = error instanceof Error ? error.message : String(error);
pageUiState.pageAiOpenHubFallbackReason = 'OpenHub bootstrap 不可用,请刷新或检查 OpenHub 服务';
pageAiRenderOpenHubHostChrome();
}
}
function pageAiPostOpencodeBridgeMessage(type, payload) {
var iframe = document.querySelector('[data-page-ai-opencode-iframe]');
if (!(iframe instanceof HTMLIFrameElement) || !iframe.contentWindow) return false;
@@ -1268,45 +1148,6 @@ export function createSidebarPageAiRuntime(context) {
return true;
}
function pageAiInstallMNoteOpenFileBridge() {
if (pageUiState.pageAiMNoteOpenFileBridgeInstalled) return;
pageUiState.pageAiMNoteOpenFileBridgeInstalled = true;
window.addEventListener('message', function(event) {
if (event.origin !== window.location.origin) return;
var message = event.data && typeof event.data === 'object' ? event.data : null;
if (message && message.source === 'openhub-ai' && message.type === 'mnote:minimize-openhub') {
closePageAiDrawer();
return;
}
if (message && message.source === 'openhub-ai' && message.type === 'mnote:get-active-tab-address') {
var addressPayload = pageAiCurrentActiveTabAddressPayload();
var requestPayload = message.payload && typeof message.payload === 'object' ? message.payload : {};
var kind = String(requestPayload.kind || message.kind || 'tab').trim();
var value = kind === 'folder' ? addressPayload.folderUrl : addressPayload.tabUrl;
if (event.source && typeof event.source.postMessage === 'function') {
event.source.postMessage({
source: 'mnote-page-ai',
type: 'mnote:active-tab-address',
requestId: message.requestId || '',
payload: Object.assign({}, addressPayload, {
kind: kind === 'folder' ? 'folder' : 'tab',
value: value
})
}, event.origin);
}
return;
}
if (!message || (message.type !== 'mnote:open-file' && message.type !== 'mnote:open-reference')) return;
if (message.source !== 'openhub-diff' && message.source !== 'openhub-changed-files' && message.source !== 'openhub-citation') return;
var payload = message.payload && typeof message.payload === 'object' ? message.payload : {};
pageAiOpenOpencodeChangedFile(message.path || payload.path || payload.href || '', {
rootUri: String(message.rootUri || payload.rootUri || payload.root_uri || currentRootUri() || '').trim(),
workspaceId: String(message.workspaceId || payload.workspaceId || payload.workspace_id || resolveWorkspaceId(document.body) || '').trim(),
documentId: String(message.documentId || payload.documentId || payload.document_id || '').trim()
});
});
}
function pageAiInstallOpencodeBridge() {
if (pageUiState.pageAiOpencodeBridgeInstalled) return;
pageUiState.pageAiOpencodeBridgeInstalled = true;
@@ -1540,10 +1381,8 @@ export function createSidebarPageAiRuntime(context) {
function pageAiEnsureOpencodeHostDrawer() {
var drawer = ensurePageAiDrawer();
pageAiInstallMNoteOpenFileBridge();
if (drawer.getAttribute('data-page-ai-opencode-host') !== 'true') {
drawer.setAttribute('data-page-ai-opencode-host', 'true');
drawer.removeAttribute('data-page-ai-openhub-host');
drawer.setAttribute('data-mnote-acp-runtime', 'opencode');
drawer.innerHTML = '' +
'<div class="wolai-page-ai-resize-handle" data-page-ai-resize-handle title="拖动调整页面 AI 宽度" aria-hidden="true"></div>' +
@@ -1828,17 +1667,17 @@ export function createSidebarPageAiRuntime(context) {
if (isMarkdown) {
if (window.__mnoteLocalFolderEventBus && typeof window.__mnoteLocalFolderEventBus.emitChangedFiles === 'function') {
window.__mnoteLocalFolderEventBus.emitChangedFiles({
source: 'openhub_changed_file_bridge',
reason: 'openhub_changed_file',
source: 'opencode_changed_file_bridge',
reason: 'opencode_changed_file',
rootUri: rootUri,
workspaceId: workspaceId,
changedFiles: [{ relativePath: targetPath, documentId: documentId, changeType: 'modified' }],
affectedParents: [{ relativePath: pageAiParentRelativePath(targetPath), reason: 'openhub_changed_file' }]
affectedParents: [{ relativePath: pageAiParentRelativePath(targetPath), reason: 'opencode_changed_file' }]
});
}
if (typeof window.__mnoteDocumentPaneRuntime.openPrimaryDocument === 'function') {
if (documentId === String(currentDocumentId() || '').trim()) {
document.documentElement.setAttribute('data-mnote-page-ai-openhub-document-pane-refresh', targetPath);
document.documentElement.setAttribute('data-mnote-page-ai-opencode-document-pane-refresh', targetPath);
return true;
}
void window.__mnoteDocumentPaneRuntime.openPrimaryDocument({
@@ -1847,7 +1686,7 @@ export function createSidebarPageAiRuntime(context) {
sourceKind: currentSourceKind() || 'local_folder',
rootUri: rootUri
});
document.documentElement.setAttribute('data-mnote-page-ai-openhub-document-pane-refresh', targetPath);
document.documentElement.setAttribute('data-mnote-page-ai-opencode-document-pane-refresh', targetPath);
return true;
}
}
@@ -3872,20 +3711,6 @@ export function createSidebarPageAiRuntime(context) {
function openPageAiDrawer() {
if (pageAiOpenHubHostEnabled()) {
pageAiEnsureContextRefState();
void pageAiLoadAllowedRoots().then(function() {
pageAiRenderOpenHubHostChrome();
}).catch(function() {
pageAiRenderOpenHubHostChrome();
});
var openhubDrawer = pageAiEnsureOpenHubHostDrawer();
pageAiApplyDrawerWidth(openhubDrawer);
openhubDrawer.hidden = false;
pageUiState.pageAiOpen = true;
updatePageAiTriggerState();
return;
}
if (pageAiOpencodeHostEnabled()) {
pageAiEnsureContextRefState();
void pageAiLoadAllowedRoots().then(function() {
@@ -5095,9 +4920,6 @@ export function createSidebarPageAiRuntime(context) {
});
}
}
if (action === 'openhub-refresh-bootstrap') {
void pageAiBootstrapOpenHubHost();
}
if (action === 'cancel-queued-run') {
void pageAiCancelQueuedRun(pageAiAction.getAttribute('data-page-ai-queue-id'));
}