chore: land tree view-state, vault, Pi module split, and repo hygiene

Persist PageTree expand state via control-plane view-state and align
chevron/DOM with restored expansion; keep Sidex-style shallow page-tree
scan and drop the unused recursive scanner that only added cargo noise.

Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi
into a module package, and retire Hermes/ACP/OpenHub recycle + root
harness evidence from the index while gitignoring recycle and local
diag dumps.

Archive superseded design/bugs docs under old/, point architecture at
ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor
regressions so the working tree can stay clean.
This commit is contained in:
Agent Board
2026-07-21 05:13:05 +08:00
parent 6f9c7d3b58
commit b798f628ee
264 changed files with 17480 additions and 17314 deletions
@@ -464,6 +464,149 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
return true;
}
/**
* Soft-open password vault: swap main content only, keep sidebar PageTree/FileTree DOM.
* Full /vault navigation re-SSRs the tree and drops expand state — avoid that on left-rail click.
*/
function ensureVaultWorkbenchRuntimeLoaded() {
if (window.mnote && window.mnote.vaultWorkbench && typeof window.mnote.vaultWorkbench.boot === 'function') {
return Promise.resolve(window.mnote.vaultWorkbench);
}
return new Promise(function (resolve, reject) {
var existing = document.querySelector('script[data-mnote-vault-runtime="1"]');
if (existing) {
var onLoad = function () {
existing.removeEventListener('load', onLoad);
existing.removeEventListener('error', onError);
if (window.mnote && window.mnote.vaultWorkbench) resolve(window.mnote.vaultWorkbench);
else reject(new Error('vault_workbench_runtime_missing'));
};
var onError = function () {
existing.removeEventListener('load', onLoad);
existing.removeEventListener('error', onError);
reject(new Error('vault_workbench_runtime_load_failed'));
};
existing.addEventListener('load', onLoad);
existing.addEventListener('error', onError);
return;
}
var script = document.createElement('script');
script.src = '/api/mnote-browser-runtime/vault-workbench-runtime.js';
script.defer = true;
script.setAttribute('data-mnote-vault-runtime', '1');
script.onload = function () {
if (window.mnote && window.mnote.vaultWorkbench) resolve(window.mnote.vaultWorkbench);
else reject(new Error('vault_workbench_runtime_missing'));
};
script.onerror = function () {
reject(new Error('vault_workbench_runtime_load_failed'));
};
document.head.appendChild(script);
});
}
function buildVaultWorkbenchShellHtml(workspaceId, rootUri) {
var ws = escapeHtml(String(workspaceId || '').trim());
var root = escapeHtml(String(rootUri || '').trim());
return (
'<section class="mnote-vault-workbench" data-testid="mnote-vault-workbench" data-workspace-id="' +
ws +
'" data-root-uri="' +
root +
'" data-status="active">' +
'<header class="mnote-vault-header">' +
'<div class="mnote-vault-header-main">' +
'<h1>密码箱</h1>' +
'<p class="mnote-vault-status" data-vault-status role="status" aria-live="polite"></p>' +
'</div>' +
'<div class="mnote-vault-header-actions">' +
'<button type="button" data-vault-create data-testid="vault-create">新建</button>' +
'<button type="button" data-vault-cipher-book data-testid="vault-cipher-book">密文簿</button>' +
'<input type="search" data-vault-search data-testid="vault-search" placeholder="搜索标题、用户名、标签、分组…" aria-label="搜索密码条目" />' +
'<div class="mnote-vault-tabs" role="tablist">' +
'<button type="button" role="tab" data-vault-tab="active" class="is-active" aria-selected="true">在用</button>' +
'<button type="button" role="tab" data-vault-tab="deleted" aria-selected="false">已删除</button>' +
'</div>' +
'</div>' +
'</header>' +
'<div class="mnote-vault-body">' +
'<aside class="mnote-vault-list" data-vault-list data-testid="vault-list" aria-label="密码条目列表"></aside>' +
'<main class="mnote-vault-detail" data-vault-detail data-testid="vault-detail" aria-label="条目详情"></main>' +
'</div>' +
'</section>'
);
}
function markVaultNavActive() {
document.querySelectorAll('.mnote-sidebar-nav a.active, .wolai-quick-actions a.active').forEach(function (link) {
link.classList.remove('active');
});
document
.querySelectorAll('a[data-mnote-nav="vault"], a[data-testid="mnote-nav-vault"]')
.forEach(function (link) {
link.classList.add('active');
});
}
async function openVaultWorkbenchSoft(targetUrl, options) {
var url =
targetUrl instanceof URL
? targetUrl
: new URL(String(targetUrl || '/vault'), window.location.origin);
if (url.pathname !== '/vault') {
window.location.assign(url.pathname + url.search + url.hash);
return false;
}
copyWorkspaceSourceParams(url);
if (!url.searchParams.get('sourceKind') && (url.searchParams.get('rootUri') || currentRootUri())) {
url.searchParams.set('sourceKind', 'local_folder');
}
if (!url.searchParams.get('rootUri')) {
var bodyRoot = currentRootUri();
if (bodyRoot) url.searchParams.set('rootUri', bodyRoot);
}
var rootUri = (url.searchParams.get('rootUri') || currentRootUri() || '').trim();
var workspaceId = (
currentWorkspaceId() ||
resolveWorkspaceId(document.body) ||
(document.getElementById('sidebar-tree-root') &&
document.getElementById('sidebar-tree-root').getAttribute('data-workspace-id')) ||
''
).trim();
var content = document.querySelector('article.mnote-content');
if (!(content instanceof HTMLElement)) {
window.location.assign(url.pathname + url.search + url.hash);
return false;
}
var nextHref = url.pathname + url.search + url.hash;
if (mnoteNavigationInFlight === 'vault:' + nextHref) return true;
mnoteNavigationInFlight = 'vault:' + nextHref;
try {
// Preserve #sidebar-tree-root / #sidebar-file-tree-root; only replace main pane.
content.innerHTML = buildVaultWorkbenchShellHtml(workspaceId, rootUri);
if (document.body instanceof HTMLElement) {
document.body.setAttribute('data-mnote-page', 'vault');
if (rootUri) document.body.setAttribute('data-mnote-root-uri', rootUri);
document.body.setAttribute('data-mnote-source-kind', 'local_folder');
}
document.title = '密码箱';
markVaultNavActive();
if (!(options && options.replaceUrl === false)) {
window.history.pushState({ mnoteSoftNav: 'vault' }, '', nextHref);
}
var vaultApi = await ensureVaultWorkbenchRuntimeLoaded();
if (vaultApi && typeof vaultApi.boot === 'function') vaultApi.boot();
return true;
} catch (error) {
console.warn('[mnote vault] soft open failed, falling back to full navigation', error);
window.location.assign(nextHref);
return false;
} finally {
if (mnoteNavigationInFlight === 'vault:' + nextHref) mnoteNavigationInFlight = '';
}
}
window.__mnoteOpenVaultWorkbench = openVaultWorkbenchSoft;
function openCurrentNavigationPage(trigger) {
if (currentSourceKind() === 'local_folder') {
var rootUri = currentRootUri();
@@ -3387,6 +3530,34 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
return;
}
var vaultNavLink = closestAction(
e.target,
'a[data-mnote-nav="vault"], a[data-testid="mnote-nav-vault"], a[href="/vault"], a[href^="/vault?"]'
);
if (vaultNavLink instanceof HTMLAnchorElement) {
// Modifier / middle-click: keep native full navigation (new tab etc.).
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
try {
var enrichUrl = new URL(vaultNavLink.getAttribute('href') || '/vault', window.location.origin);
if (enrichUrl.pathname === '/vault') {
copyWorkspaceSourceParams(enrichUrl);
vaultNavLink.setAttribute('href', enrichUrl.pathname + enrichUrl.search + enrichUrl.hash);
}
} catch (_) {}
} else {
try {
var vaultUrl = new URL(vaultNavLink.getAttribute('href') || '/vault', window.location.origin);
if (vaultUrl.pathname === '/vault') {
e.preventDefault();
copyWorkspaceSourceParams(vaultUrl);
vaultNavLink.setAttribute('href', vaultUrl.pathname + vaultUrl.search + vaultUrl.hash);
void openVaultWorkbenchSoft(vaultUrl);
return;
}
} catch (_) {}
}
}
var localFolderTrigger = closestAction(e.target, '[data-mnote-action="open-local-folder"]');
if (localFolderTrigger) {
e.preventDefault();
@@ -3908,6 +4079,15 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
sidebarFileTreeSelection.focusedRowId = rowId;
});
syncSidebarFileTreeSelection();
// Shell-first home: FileTree may be a pending placeholder; hydrate after first paint.
if (typeof sidebarTreeLiveApply.hydratePendingFileTreeShell === 'function') {
var schedulePendingHydrate = typeof queueMicrotask === 'function'
? queueMicrotask
: function(fn) { setTimeout(fn, 0); };
schedulePendingHydrate(function() {
void sidebarTreeLiveApply.hydratePendingFileTreeShell('boot');
});
}
schedulePendingLocalFolderRestoreFocus();
var recentPageOptionsApply = { documentId: '', at: 0 };
function applyPrimaryPageOptionsOnce(documentId) {