docs(plan): v0.2 adds Pi subagents and scheduled-jobs board

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-28 02:09:39 +08:00
1 parent b839ed4056
commit 16ab2a6c84
97 files changed
+592 -648

No files matched your search

+21 -33
View File
@@ -220,7 +220,7 @@ export function RenameDialog({ root, entry, onClose }: { root: FileRoot; entry:
onSuccess: (r) => {
const it = r.items[0];
const c = it?.candidates[0];
if (!it || !c) return toast.info("没有可信的识别结果,无法给出建议名");
if (!it || !c) return toast.info("识别结果不可信,没有建议名");
setName(suggestName(c, it.parsed, entry.name, isDir));
setErr(null);
},
@@ -255,7 +255,7 @@ export function RenameDialog({ root, entry, onClose }: { root: FileRoot; entry:
reason === "exists"
? "目标名已存在,不会覆盖"
: reason === "download_active"
? "做种中,改名会让下载器找不到文件"
? "正在做种,改名会让下载器找不到文件"
: filesErrorText(e),
);
},
@@ -325,14 +325,10 @@ export function RenameDialog({ root, entry, onClose }: { root: FileRoot; entry:
))}
</ul>
{pv.assetLocations > 0 ? (
<Notice tone="neutral">
将同步 {pv.assetLocations} 条资产位置,并写一条整理记录(action=rename)。
</Notice>
<Notice tone="neutral">将同步 {pv.assetLocations} 条资产位置,并写一条整理记录。</Notice>
) : null}
{pv.bindings.length > 0 ? (
<Notice tone="warning">
这是作品/季的绑定目录:将新建绑定并把旧绑定标记为已替代,之后新集入库进入新目录。
</Notice>
<Notice tone="warning">这是作品/季的绑定目录。改名后旧绑定标为已替代,新集入库到新目录。</Notice>
) : null}
</>
) : null}
@@ -422,7 +418,7 @@ export function TransferDialog({
onError: (e) => {
const reason = filesErrorReason(e);
if (reason === "plan_stale") {
setErr("源文件在预览后发生了变化,已重新生成预览,请再确认一次。");
setErr("源文件在预览后有变化,已重新预览。确认后再执行。");
runPreview(target, mode);
} else setErr(filesErrorText(e));
},
@@ -437,7 +433,7 @@ export function TransferDialog({
<DialogTitle>{mode === "move" ? "移动到…" : "复制到…"}</DialogTitle>
<DialogDescription>
{items.length === 1 ? baseName(items[0]?.path ?? "") : `${items.length} 项`} ·
先预览前后路径、冲突与空间,确认后才执行; 统一走可恢复的整理计划,跨卷为 Copy → 核验 → 删源。
先预览路径、冲突与空间,确认后执行。跨卷按复制 → 核验 → 删源执行。
</DialogDescription>
</DialogHeader>
<div className="grid min-h-0 gap-4 overflow-y-auto md:grid-cols-[15rem_minmax(0,1fr)]">
@@ -475,7 +471,7 @@ export function TransferDialog({
}}
/>
</div>
<p className="text-meta text-muted-foreground">只有可写的媒体库根能作为目标。</p>
<p className="text-meta text-muted-foreground">只有可写的库根能作为目标。</p>
</div>
<div className="min-w-0 space-y-3">
{target && targetRoot ? (
@@ -512,7 +508,7 @@ export function TransferDialog({
</div>
{hnrBlocked ? (
<Notice tone="destructive">
{plan.hnrBlocks.length} 项仍在做种且 H&R 未满足,不能 Move。可改用“复制”,或等 H&R 满足后再移动。
{plan.hnrBlocks.length} 项仍在做种且 H&R 未满足,不能移动。改用复制,或等 H&R 满足后再移动。
<button
type="button"
className="ml-1 underline"
@@ -526,7 +522,7 @@ export function TransferDialog({
</button>
</Notice>
) : null}
{plan.truncated ? <Notice tone="warning">源文件过多,预览只列出前一部分;执行覆盖全部。</Notice> : null}
{plan.truncated ? <Notice tone="warning">源文件过多,预览只列出前一部分,执行时处理全部。</Notice> : null}
<ul className="space-y-1.5">
{plan.pairs.map((p) => {
const sr = rootById.get(p.source.root);
@@ -654,7 +650,7 @@ export function DeleteDialog({
reason === "permanent_disabled"
? "系统设置未开启永久删除(files.allowPermanentDelete)"
: reason === "approval_required"
? "需要审批:API Key 删除每次都要一次性审批"
? "用 API Key 删除,每次都需要审批"
: filesErrorText(e),
);
},
@@ -666,9 +662,7 @@ export function DeleteDialog({
<DialogContent className="max-h-[92dvh] grid-rows-[auto_minmax(0,1fr)_auto] sm:max-w-2xl">
<DialogHeader>
<DialogTitle>{single ? `删除 ${single}?` : `删除 ${items.length} 项?`}</DialogTitle>
<DialogDescription>
删除前已做引用检查:做种任务、已登记资产、路径绑定。删除不会动下载器里的任务。
</DialogDescription>
<DialogDescription>已检查做种任务、已登记资产和路径绑定。下载器里的任务不受影响。</DialogDescription>
</DialogHeader>
<div className="min-h-0 space-y-3 overflow-y-auto">
{check.isPending ? (
@@ -715,7 +709,7 @@ export function DeleteDialog({
</p>
))}
{c.assets.length ? (
<p>已登记资产 {c.assets.length} 个(删除后退役,满足的 Slot 退回待处理)</p>
<p>已登记资产 {c.assets.length} 个(删除后退役,已满足的版本目标退回待处理)</p>
) : null}
{c.bindings.map((bd) => (
<p key={bd.bindingId}>
@@ -723,7 +717,7 @@ export function DeleteDialog({
{bd.seasonNumber != null ? ` 第 ${bd.seasonNumber} 季` : ""}
</p>
))}
{c.sharedInode ? <p>共享 inode(硬链接):只删除这一处链接,其他位置的文件不受影响</p> : null}
{c.sharedInode ? <p>共享 inode(硬链接):只删这一处链接,其他位置不受影响</p> : null}
</div>
</li>
);
@@ -736,7 +730,7 @@ export function DeleteDialog({
<span>
同时退役资产
<span className="block text-meta text-muted-foreground">
资产位置标为已移除、资产退役;满足的 Slot 退回待处理并建待处理事项。
资产位置标为已移除,资产退役;已满足的版本目标退回待处理。
</span>
</span>
</label>
@@ -746,9 +740,7 @@ export function DeleteDialog({
<input type="checkbox" className="mt-1" checked={unbind} onChange={(e) => setUnbind(e.target.checked)} />
<span>
解除路径绑定
<span className="block text-meta text-muted-foreground">
绑定标为已替代;之后该作品入库会重新选择目录。
</span>
<span className="block text-meta text-muted-foreground">绑定标为已替代,该作品下次入库重新选目录。</span>
</span>
</label>
) : null}
@@ -764,7 +756,7 @@ export function DeleteDialog({
/>
<span>
移入回收站
<span className="block text-meta text-muted-foreground">保留 7 天,期间可在回收站还原到原位置。</span>
<span className="block text-meta text-muted-foreground">到期前可在回收站还原。</span>
</span>
</label>
<label
@@ -782,7 +774,7 @@ export function DeleteDialog({
<span>
永久删除
<span className="block text-meta text-muted-foreground">
{isAdmin ? "不可恢复;需在系统设置开启后才可用。" : "仅管理员会话可用。"}
{isAdmin ? "不可恢复。需要在系统设置里开启。" : "仅管理员会话可用。"}
</span>
</span>
</label>
@@ -866,9 +858,7 @@ export function CopyPathDialog({ root, entry, onClose }: { root: FileRoot; entry
</li>
))}
</ul>
<p className="text-meta text-muted-foreground">
下载器与媒体服务器视角的路径按系统设置里的路径映射换算,见“系统设置 → 路径映射”。
</p>
<p className="text-meta text-muted-foreground">下载器与媒体服务器看到的路径按“系统设置 → 路径映射”换算。</p>
</DialogContent>
</Dialog>
);
@@ -890,9 +880,9 @@ export function ScrapeDialog({ entry, onClose }: { entry: FileEntry; onClose: ()
onSuccess: (r) => {
const extra =
r.nfo === "not_implemented" || r.images === "not_implemented"
? "NFO/图片投影尚未实现,本次只刷新了字段。"
? "还不支持写 NFO 和图片,只刷新了字段。"
: r.nfo === "skipped"
? "目标 NFO 不是本系统生成且字段已锁定,未覆盖。"
? "目标 NFO 不是本工具生成且字段已锁定,未覆盖。"
: "";
toast.success(`已提交元数据刷新${r.lockedFields.length ? `,${r.lockedFields.length} 个锁定字段不动` : ""}`, {
description: extra || undefined,
@@ -908,9 +898,7 @@ export function ScrapeDialog({ entry, onClose }: { entry: FileEntry; onClose: ()
<DialogContent>
<DialogHeader>
<DialogTitle>刮削 {asset.title}</DialogTitle>
<DialogDescription>
字段级刷新元数据:用户锁定的字段不动,不改路径。非本系统生成的 NFO 不会被覆盖。
</DialogDescription>
<DialogDescription>按字段刷新元数据,锁定的字段和路径不变。不覆盖非本工具生成的 NFO。</DialogDescription>
</DialogHeader>
<div className="flex items-center justify-between gap-3 text-caption">
写 NFO 到绑定目录