chore: 保存当前架构收口与 bug 修复快照

归档本轮 P0/P1 bug 修复、设计审查迁移、AI selection scope 收口与 stream contract 调整,并保留当前 05 主线迁移起点。
This commit is contained in:
lix-2026
2026-05-18 17:01:35 +08:00
parent 61ee4a38a2
commit a2cb1338c8
953 changed files with 14383 additions and 211845 deletions
+68 -31
View File
@@ -2018,12 +2018,17 @@ fn build_tree_shell_html(
const getFileTreeRowDocumentId = (item) => {
if (!item) return "";
if (item.resourceMeta?.documentId) return item.resourceMeta.documentId;
if (item.rowKind === "document" || item.rowKind === "markdown") return item.nodeId;
if (item.rowKind === "index") return item.nodeId.replace(/^index:/, "");
return "";
};
const getFileTreeRowOwnerDocumentId = (item) => {
if (!item) return "";
if (item.resourceMeta?.documentId) return item.resourceMeta.documentId;
return getFileTreeRowDocumentId(item);
};
const getFileTreeRowAssetId = (item) => {
if (!item) return "";
if (item.resourceMeta?.assetId) return item.resourceMeta.assetId;
@@ -2084,6 +2089,7 @@ fn build_tree_shell_html(
rowKind: "root",
nodeId: null,
documentId: null,
ownerDocumentId: null,
assetId: null,
};
}
@@ -2092,6 +2098,7 @@ fn build_tree_shell_html(
rowKind: normalizeText(row.dataset.rowKind, "document"),
nodeId: normalizeText(row.dataset.nodeId) || null,
documentId: normalizeText(row.dataset.documentId) || null,
ownerDocumentId: normalizeText(row.dataset.ownerDocumentId) || null,
assetId: normalizeText(row.dataset.assetId) || null,
};
};
@@ -2934,13 +2941,14 @@ fn build_tree_shell_html(
const targetItem = targetRowId ? fileTreeRowById.get(targetRowId) : null;
const target = targetItem
? {
rowId: targetItem.rowId,
rowKind: targetItem.rowKind,
nodeId: targetItem.nodeId,
documentId: getFileTreeRowDocumentId(targetItem) || null,
assetId: getFileTreeRowAssetId(targetItem) || null,
}
: { rowId: null, rowKind: "root", nodeId: null, documentId: null, assetId: null };
rowId: targetItem.rowId,
rowKind: targetItem.rowKind,
nodeId: targetItem.nodeId,
documentId: getFileTreeRowDocumentId(targetItem) || null,
ownerDocumentId: getFileTreeRowOwnerDocumentId(targetItem) || null,
assetId: getFileTreeRowAssetId(targetItem) || null,
}
: { rowId: null, rowKind: "root", nodeId: null, documentId: null, ownerDocumentId: null, assetId: null };
if (sourceKind === "local_folder") {
const pasted = await executeLocalFileTreeInternalDrop(
target,
@@ -3030,7 +3038,12 @@ fn build_tree_shell_html(
if (event.key === "F2") {
event.preventDefault();
const rowId = item?.rowId || fileTreeFocusedRowId;
if (rowId) beginInlineRename("filetree", rowId);
const renameItem = rowId ? fileTreeRowById.get(rowId) : null;
if (rowId && getFileTreeRowDocumentId(renameItem)) {
beginInlineRename("filetree", rowId);
} else {
setLastAction("当前资源暂不支持重命名", "error");
}
return;
}
if (event.key === "ArrowDown") {
@@ -3057,7 +3070,11 @@ fn build_tree_shell_html(
event.preventDefault();
if (item) {
const documentId = getFileTreeRowDocumentId(item);
if (documentId) handleNavigate(documentId);
if (documentId) {
handleNavigate(documentId);
} else {
openHydratedFileTreeItem(item);
}
}
return;
}
@@ -3219,7 +3236,7 @@ fn build_tree_shell_html(
});
}
normalizedItems.slice().forEach((item) => {
const itemDocumentId = getFileTreeRowDocumentId(item) || item.resourceMeta?.documentId || item.nodeId;
const itemDocumentId = getFileTreeRowOwnerDocumentId(item) || item.nodeId;
if (removedNodeIds.has(item.nodeId) || itemDocumentId === normalizedDocumentId) {
removeTreeItemEverywhere(item);
changed = true;
@@ -4149,8 +4166,7 @@ fn build_tree_shell_html(
rowKind === "markdown" ||
rowKind === "document" ||
rowKind === "folder" ||
rowKind === "index" ||
(localSource && rowKind === "asset");
rowKind === "index";
const canCopyCut =
rowKind === "markdown" ||
rowKind === "document" ||
@@ -4282,7 +4298,9 @@ fn build_tree_shell_html(
return;
}
if (kind === "rename") {
if (target.rowId) beginInlineRename("filetree", target.rowId);
if (target.rowId && getFileTreeRowDocumentId(item)) {
beginInlineRename("filetree", target.rowId);
}
return;
}
if (kind === "copy" || kind === "cut") {
@@ -4639,8 +4657,14 @@ fn build_tree_shell_html(
const id = inlineRenameState.id;
const item = renameMode === "filetree" ? fileTreeRowById.get(id) : itemById.get(id);
const documentId = renameMode === "filetree"
? getFileTreeRowDocumentId(item) || item?.nodeId || id
? getFileTreeRowDocumentId(item)
: id;
if (!documentId) {
inlineRenameState = { mode: null, id: null, committing: false };
setLastAction("当前资源暂不支持重命名", "error");
renderTree();
return;
}
try {
const result = await sendCommand({
action: "rename",
@@ -4953,6 +4977,7 @@ fn build_tree_shell_html(
const openHydratedFileTreeItem = (item) => {
const documentId = getFileTreeRowDocumentId(item);
const ownerDocumentId = getFileTreeRowOwnerDocumentId(item);
const assetId = getFileTreeRowAssetId(item);
if (item.rowKind === "document" || item.rowKind === "index") {
handleNavigate(documentId || item.nodeId);
@@ -4960,12 +4985,12 @@ fn build_tree_shell_html(
}
setLastAction(` ${assetId || item.rowId}`);
postToHost("tree.asset.open", {
documentId: documentId || null,
documentId: ownerDocumentId || null,
assetId: assetId || null,
objectIdentity: item.resourceMeta?.objectIdentity || null,
target: { documentId: documentId || null },
target: { documentId: ownerDocumentId || null },
payload: {
documentId: documentId || null,
documentId: ownerDocumentId || null,
assetId: assetId || null,
rowId: item.rowId,
rowKind: item.rowKind,
@@ -5122,6 +5147,7 @@ fn build_tree_shell_html(
const bindFileTreeRowEvents = (row, item) => {
if (!(row instanceof HTMLElement) || !item) return;
const documentId = getFileTreeRowDocumentId(item) || null;
const ownerDocumentId = getFileTreeRowOwnerDocumentId(item) || null;
const assetId = getFileTreeRowAssetId(item) || null;
row.dataset.active = String(
item.rowKind === "document" && documentId === currentActiveDocumentId
@@ -5130,6 +5156,7 @@ fn build_tree_shell_html(
row.dataset.rowId = item.rowId;
row.dataset.rowKind = item.rowKind;
row.dataset.documentId = documentId || "";
row.dataset.ownerDocumentId = ownerDocumentId || "";
row.dataset.assetId = assetId || "";
row.dataset.objectIdentity = item.resourceMeta?.objectIdentity
? JSON.stringify(item.resourceMeta.objectIdentity)
@@ -5577,6 +5604,7 @@ fn build_tree_shell_html(
const openFileTreeItem = (item) => {
const documentId = getFileTreeRowDocumentId(item);
const ownerDocumentId = getFileTreeRowOwnerDocumentId(item);
const assetId = getFileTreeRowAssetId(item);
if (item.rowKind === "document" || item.rowKind === "index" || item.rowKind === "markdown") {
handleNavigate(documentId || item.nodeId);
@@ -5584,12 +5612,12 @@ fn build_tree_shell_html(
}
setLastAction(` ${assetId || item.rowId}`);
postToHost("tree.asset.open", {
documentId: documentId || null,
documentId: ownerDocumentId || null,
assetId: assetId || null,
objectIdentity: item.resourceMeta?.objectIdentity || null,
target: { documentId: documentId || null },
target: { documentId: ownerDocumentId || null },
payload: {
documentId: documentId || null,
documentId: ownerDocumentId || null,
assetId: assetId || null,
rowId: item.rowId,
rowKind: item.rowKind,
@@ -5649,6 +5677,7 @@ fn build_tree_shell_html(
const children = getSiblings(item.nodeId);
const hasBranches = canExpandFileTreeRow(item) && children.length > 0;
const documentId = getFileTreeRowDocumentId(item) || null;
const ownerDocumentId = getFileTreeRowOwnerDocumentId(item) || null;
const assetId = getFileTreeRowAssetId(item) || null;
const row = document.createElement("div");
@@ -5661,6 +5690,7 @@ fn build_tree_shell_html(
row.dataset.rowId = item.rowId;
row.dataset.rowKind = item.rowKind;
row.dataset.documentId = documentId || "";
row.dataset.ownerDocumentId = ownerDocumentId || "";
row.dataset.assetId = assetId || "";
row.dataset.objectIdentity = item.resourceMeta?.objectIdentity
? JSON.stringify(item.resourceMeta.objectIdentity)
@@ -5769,15 +5799,17 @@ fn build_tree_shell_html(
const actions = document.createElement("div");
actions.className = "tree-actions";
actions.appendChild(
createActionButton(
ICONS.edit,
"filetree-action-rename",
` ${item.title}`,
() => beginInlineRename("filetree", item.rowId),
false,
),
);
if (getFileTreeRowDocumentId(item)) {
actions.appendChild(
createActionButton(
ICONS.edit,
"filetree-action-rename",
` ${item.title}`,
() => beginInlineRename("filetree", item.rowId),
false,
),
);
}
actions.appendChild(
createActionButton(
ICONS.more,
@@ -7143,6 +7175,11 @@ mod tests {
assert!(html.contains("tree.filetree.external-drop"));
assert!(html.contains("\"rowKind\":\"asset_folder\""));
assert!(html.contains("\"resourceMeta\""));
assert!(html.contains("const getFileTreeRowOwnerDocumentId = (item) => {"));
assert!(html.contains("row.dataset.ownerDocumentId = ownerDocumentId || \"\";"));
assert!(html.contains("if (rowId && getFileTreeRowDocumentId(renameItem))"));
assert!(html.contains("if (getFileTreeRowDocumentId(item))"));
assert!(html.contains("documentId: ownerDocumentId || null"));
assert!(html.contains("dragover"));
assert!(html.contains("hydrateInitialFileTree"));
assert!(html.contains("const usedRustInitialRenderer = hydrateInitialRenderer();"));
@@ -7897,7 +7934,7 @@ mod tests {
payload["result"]["documentId"],
Value::String("page_child".into())
);
assert_eq!(payload["result"]["sortOrder"], Value::from(1));
assert_eq!(payload["result"]["sortOrder"], Value::Null);
assert_eq!(
payload["result"]["execution"]["deletedCount"],
Value::from(1)