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
@@ -389,6 +389,21 @@ export const localMarkdownRelativePathFromDocumentId = (documentId) => {
return decodeLocalIdSegment(segment).replace(/^\/+/, '');
};
export const localMarkdownRelativePathFromDocumentsHref = (href) => {
const value = String(href || '').trim();
if (!value) return '';
let url = null;
try {
url = new URL(value, window.location?.origin || 'http://127.0.0.1:3000');
} catch (_) {
return '';
}
if (!url.pathname.startsWith('/documents/')) return '';
const segment = decodeURIComponent(url.pathname.slice('/documents/'.length));
if (!segment.startsWith('local-md:')) return '';
return localMarkdownRelativePathFromDocumentId(segment);
};
export const localMarkdownDocumentIdFromRelativePath = (relativePath) => {
const normalized = String(relativePath || '').trim().replace(/^\/+/, '');
if (!normalized) return '';
@@ -440,7 +455,12 @@ export const normalizeLocalPageRelativePath = (value, context) => {
if (!text || text.startsWith('#')) return '';
if (text.startsWith('/documents/')) return text;
if (text.startsWith('/api/') || text.startsWith('http://') || text.startsWith('https://') || text.startsWith('mailto:')) return '';
const baseDir = text.startsWith('/') ? '' : localMarkdownDirectoryFromDocumentId(context?.documentId);
const currentPath = localMarkdownRelativePathFromDocumentId(context?.documentId);
const textPath = text.replace(/^\/+/, '');
const currentTop = currentPath.split('/').filter(Boolean)[0] || '';
const textTop = textPath.split('/').filter(Boolean)[0] || '';
const looksRootRelative = Boolean(currentTop && textTop && currentTop === textTop);
const baseDir = text.startsWith('/') || looksRootRelative ? '' : localMarkdownDirectoryFromDocumentId(context?.documentId);
const parts = (baseDir ? `${baseDir}/${text}` : text)
.replace(/\\/g, '/')
.split('/');
@@ -752,6 +772,32 @@ export const tiptapNodeToEditorBlock = (node, index) => {
childBlockIds: [],
};
}
if (node?.type === 'paragraph') {
const children = Array.isArray(node?.content) ? node.content : [];
if (children.length === 1 && children[0]?.type === 'text') {
const textNode = children[0];
const linkMark = Array.isArray(textNode.marks)
? textNode.marks.find((mark) => {
const className = String(mark?.attrs?.class || '');
return mark?.type === 'link' && className.split(/\s+/).includes('mnote-page-block-link');
})
: null;
if (linkMark?.attrs?.href) {
const href = String(linkMark.attrs.href || '').trim();
const sourcePath = localMarkdownRelativePathFromDocumentsHref(href) || unwrapMarkdownLinkTarget(href);
return {
blockId,
blockType: 'page_reference',
props: {
title: String(textNode.text || '').trim() || '页面',
sourcePath,
},
contentNodes: inlineTextNodes(node),
childBlockIds: [],
};
}
}
}
if (node?.type === 'paragraph') return { blockId, blockType: 'paragraph', props: {}, contentNodes: inlineTextNodes(node), childBlockIds: [] };
if (node?.type === 'heading') {
const level = Math.max(1, Math.min(6, Number(node?.attrs?.level || 1) || 1));
@@ -795,6 +841,11 @@ export const legacyBlocksFromEditorDocument = (editorDocument) => (
? { language: block.props?.language || null }
: block.blockType === 'mindmap'
? mindmapPropsFromAttrs(block.props || {}, block.blockId)
: block.blockType === 'page_reference'
? {
title: block.props?.title || flattenText(block.contentNodes || []) || '页面',
sourcePath: block.props?.sourcePath || block.props?.source_path || block.props?.href || '',
}
: block.blockType === 'image'
? { ...(block.props || {}) }
: block.blockType === 'toc'