"use client"; import { Minus, Pin, PinOff, Plus, RotateCcw, Undo2, X } from "lucide-react"; import { ThinkingIndicator } from "@/components/ThinkingIndicator"; import { Button } from "@/components/ui/Button"; import { SectionHeader } from "@/components/ui/SectionHeader"; import { StatusNote } from "@/components/ui/StatusNote"; import { buttonClass } from "@/lib/ui/variants"; import { isPinned, kindLabel, reasonLabel, RECENT_N_MAX, RECENT_N_MIN, type InjectionEntity, type InjectionEntityRef, } from "@/lib/workbench/injection"; import { useInjection } from "@/lib/workbench/useInjection"; interface ChapterAssistantProps { projectId: string; chapterNo: number; } // 右栏「本章助手」(UX §6.3)。 // 「本章注入(透明)」读 B0 端点,列出确定性选中的设定/角色 + 入选理由徽标, // 并让作者 📌置顶 / ✕排除 / 调近 N 章(可控版)——「看到的=写章用的」信任牌(不变量 #6)。 // 桌面 aside 包裹;移动端经 Workbench 抽屉复用 AssistantContent。 export function ChapterAssistant({ projectId, chapterNo }: ChapterAssistantProps) { return ( ); } export function AssistantContent({ projectId, chapterNo }: ChapterAssistantProps) { const injection = useInjection(projectId, chapterNo); const data = injection.data; const selected = data?.selected ?? []; const excluded = data?.excluded ?? []; return (
) : null } />
) : null } /> {injection.loading ? (

加载参考信息…

) : !data ? ( // 首次加载失败:data 仍为空 → 满屏错误框 + 重试。

请检查后端连接后重试。

) : ( <> {injection.saveError ? ( // 保存失败:悬浮提示,不替换列表;可关闭 + 重试上一次覆盖。
) : null} {selected.length === 0 ? (

这一章 AI 还没有要参考的设定/角色。可在大纲里点名,或从下方「已排除」里恢复。

) : (
    {selected.map((entity) => ( ))}
)} )} {excluded.length > 0 ? (
    {excluded.map((ref) => ( ))}
) : null}
); } interface EntityRowProps { entity: InjectionEntity; pinned: boolean; disabled: boolean; onTogglePin: (ref: InjectionEntityRef) => void; onExclude: (ref: InjectionEntityRef) => void; } function EntityRow({ entity, pinned, disabled, onTogglePin, onExclude }: EntityRowProps) { const ref: InjectionEntityRef = { kind: entity.kind, name: entity.name }; return (
  • {kindLabel(entity.kind)} {entity.name}
    {(entity.reasons ?? []).map((reason) => ( {reasonLabel(reason)} ))}
  • ); } interface ExcludedRowProps { refItem: InjectionEntityRef; disabled: boolean; onRestore: (ref: InjectionEntityRef) => void; } function ExcludedRow({ refItem, disabled, onRestore }: ExcludedRowProps) { return (
  • {kindLabel(refItem.kind)} {refItem.name}
  • ); } interface RecentStepperProps { value: number; disabled: boolean; onChange: (n: number) => void; } // 「关联近 N 章」步进器:覆盖近况摘要回看章数(钳在 [MIN, MAX])。 function RecentStepper({ value, disabled, onChange }: RecentStepperProps) { return (
    {value}
    ); }