Phase 1(写作工作台重构):编辑器选中一段即可「润色选段」,复用同步 /refine 回炉 (只读、不写库,守不变量 #3);不满意可「再沟通」——以上一版产出为输入 + 作者新意见 再改一版,形成版本栈(useRefine,已单测)。接受回填按内容重锚落回草稿,原文已变则 提示重选、绝不盲替换(applyRefinement,已单测)。Editor 上报选区,结果以内联卡片展示。
25 lines
949 B
TypeScript
25 lines
949 B
TypeScript
// 润色/再沟通 accept 回填:把选中原文替换为产出。选区偏移可能因异步/流式漂移,
|
||
// 故先按 range 校验,未命中则按原文内容重锚(indexOf)——原文已不存在则返回 null,
|
||
// 由调用方提示作者重新选择,绝不盲替换(plan §3.3 mustFix)。
|
||
|
||
export interface SelectionRange {
|
||
start: number;
|
||
end: number;
|
||
}
|
||
|
||
export function applyRefinement(
|
||
fullText: string,
|
||
original: string,
|
||
refined: string,
|
||
range: SelectionRange,
|
||
): string | null {
|
||
// 选区未漂移:range 处正好是原文 → 原地替换。
|
||
if (fullText.slice(range.start, range.end) === original) {
|
||
return fullText.slice(0, range.start) + refined + fullText.slice(range.end);
|
||
}
|
||
// 漂移:按内容重锚,保守取首个匹配。
|
||
const idx = fullText.indexOf(original);
|
||
if (idx === -1) return null;
|
||
return fullText.slice(0, idx) + refined + fullText.slice(idx + original.length);
|
||
}
|