feat: advance local-first conflict and search indexing

- 补齐本地 markdown 冲突处理与合并写回路径\n- 增加本地搜索索引路由、刷新与 browser smoke\n- 同步更新 current-priority checklist 的阶段进度
This commit is contained in:
lix-2026
2026-05-19 09:38:57 +08:00
parent 8ed594f1c2
commit 1b5d6a2a2d
12 changed files with 1622 additions and 49 deletions
@@ -113,9 +113,13 @@ async function run() {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "mnote-local-conflict-ui-"));
const acceptFile = "accept-disk.md";
const keepFile = "keep-current.md";
const mergeFile = "merge-result.md";
const agentFile = "agent-conflict.md";
writeWorkspaceManifest(root, "user_real");
fs.writeFileSync(path.join(root, acceptFile), markdown("Accept Disk", ["initial accept"]), "utf8");
fs.writeFileSync(path.join(root, keepFile), markdown("Keep Current", ["initial keep"]), "utf8");
fs.writeFileSync(path.join(root, mergeFile), markdown("Merge Result", ["initial merge"]), "utf8");
fs.writeFileSync(path.join(root, agentFile), markdown("Agent Conflict", ["initial agent"]), "utf8");
const browser = await chromium.launch({
headless: true,
@@ -189,6 +193,57 @@ async function run() {
assert(!keepContent.includes(diskKeepToken), "保留当前版本后磁盘版本内容不应覆盖当前编辑器内容");
steps.push({ label: "keep-current", ok: true });
await openDocument(page, root, mergeFile);
await waitForEditorText(page, "initial merge");
const localMergeToken = `local-merge-${Date.now()}`;
const diskMergeToken = `disk-merge-${Date.now()}`;
const mergedToken = `merged-merge-${Date.now()}`;
await typeDirtyText(page, ` ${localMergeToken}`);
fs.writeFileSync(path.join(root, mergeFile), markdown("Merge Result", ["initial merge", diskMergeToken]), "utf8");
await waitForEditorStatus(page, "external-change-conflict");
await page.locator('[data-testid="mnote-editor-conflict-panel"]').waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
await page.locator('[data-testid="mnote-conflict-open-diff"]').click({ timeout: UI_TIMEOUT_MS });
await page.locator('[data-testid="mnote-conflict-diff-panel"]').waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
await page.locator('[data-testid="mnote-conflict-merge-text"]').fill(`initial merge\n${localMergeToken}\n${diskMergeToken}\n${mergedToken}`);
await page.locator('[data-testid="mnote-conflict-merge-save"]').click({ timeout: UI_TIMEOUT_MS });
await waitForFileText(path.join(root, mergeFile), mergedToken);
const mergeContent = fs.readFileSync(path.join(root, mergeFile), "utf8");
assert(mergeContent.includes(localMergeToken), "合并结果应保留当前编辑器内容");
assert(mergeContent.includes(diskMergeToken), "合并结果应保留磁盘内容");
assert(mergeContent.includes(mergedToken), "合并结果应写入合并后的新内容");
steps.push({ label: "merge-save", ok: true });
await openDocument(page, root, agentFile);
await waitForEditorText(page, "initial agent");
const localAgentToken = `local-agent-${Date.now()}`;
const diskAgentToken = `disk-agent-${Date.now()}`;
const agentRunId = `run-agent-conflict-${Date.now()}`;
await typeDirtyText(page, ` ${localAgentToken}`);
fs.writeFileSync(path.join(root, agentFile), markdown("Agent Conflict", ["initial agent", diskAgentToken]), "utf8");
await page.evaluate(({ documentId, runId }) => {
window.dispatchEvent(new CustomEvent("mnote:page-ai-tool-write-completed", {
detail: {
toolName: "agent.changed_files",
normalizedToolName: "agent.changed_files",
documentId,
runId,
traceId: `trace-${runId}`,
toolCallId: `${runId}:agent.changed_files`,
},
}));
}, { documentId: localMdDocumentId(agentFile), runId: agentRunId });
await waitForEditorStatus(page, "external-change-conflict");
await page.locator('[data-testid="mnote-editor-conflict-panel"]').waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
await page.waitForFunction(
(expected) => {
const panel = document.querySelector('[data-testid="mnote-editor-conflict-panel"]');
return (panel?.textContent || "").includes(expected);
},
`agent run ${agentRunId}`,
{ timeout: UI_TIMEOUT_MS },
);
steps.push({ label: "agent-conflict-source", ok: true });
const result = { ok: true, baseUrl: BASE_URL, root, steps };
fs.writeFileSync(RESULT_PATH, `${JSON.stringify(result, null, 2)}\n`, "utf8");
console.log(`task451 local markdown conflict resolution UI smoke passed: ${RESULT_PATH}`);