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:
1 parent
b839ed4056
commit
16ab2a6c84
97 files changed
+592
-648
No files matched your search
@@ -95,17 +95,16 @@ export async function transfer(
|
||||
const t = await resolveIn(d, body.target.root, body.target.path);
|
||||
if (!t.lst?.isDirectory() || t.isSymlink) throw new FilesError("bad_request", "目标必须是已存在的目录");
|
||||
if (!t.def.libraryRootId || !(await isWritableTarget(t.def, t.rootReal)))
|
||||
throw new FilesError("not_writable", `目标根 ${t.def.name} 不可写(仅 managed 库根可作为目标)`);
|
||||
throw new FilesError("not_writable", `目标根 ${t.def.name} 不可写,只能选 managed 库根`);
|
||||
|
||||
const sources: Resolved[] = [];
|
||||
for (const it of body.items) {
|
||||
const s = await resolveIn(d, it.root, it.path);
|
||||
if (s.rel === "") throw new FilesError("bad_request", "不能移动/复制根目录本身");
|
||||
if (mode === "move" && !s.def.modifiable)
|
||||
throw new FilesError("not_writable", `源根 ${s.def.name} 为只读登记,不能移动(可复制)`);
|
||||
if (s.rel === "") throw new FilesError("bad_request", "根目录不能移动或复制");
|
||||
if (mode === "move" && !s.def.modifiable) throw new FilesError("not_writable", `源根 ${s.def.name} 只读,只能复制`);
|
||||
if (within(t.abs, s.abs)) throw new FilesError("bad_request", `目标在源目录之内: ${s.rel}`);
|
||||
if (dirname(s.abs) === t.abs) throw new FilesError("bad_request", `源已在目标目录中: ${s.rel}`);
|
||||
if (s.isSymlink) throw new FilesError("bad_request", `不移动符号链接本身: ${s.rel}`);
|
||||
if (s.isSymlink) throw new FilesError("bad_request", `不能移动符号链接: ${s.rel}`);
|
||||
sources.push(s);
|
||||
}
|
||||
const names = sources.map((s) => basename(s.abs));
|
||||
@@ -149,7 +148,7 @@ export async function transfer(
|
||||
const reason = planned.reason ?? "plan_failed";
|
||||
throw new FilesError(
|
||||
reason.startsWith("library_root_offline") ? "root_unavailable" : "bad_request",
|
||||
`无法生成搬运计划:${reason}`,
|
||||
`无法生成计划:${reason}`,
|
||||
);
|
||||
}
|
||||
const planFiles = planned.plan.organize.files;
|
||||
@@ -190,9 +189,9 @@ export async function transfer(
|
||||
const allowCross = (await d.ctx.settings.get("organize")).allowCrossVolumeMove;
|
||||
const crossBlocked = mode === "move" && !allowCross && pairs.some((p) => p.crossDevice);
|
||||
const warnings: string[] = [];
|
||||
if (crossBlocked) warnings.push("跨卷移动未开启(设置 → 整理 → 允许跨卷 Move),执行会被拒绝;可改用复制");
|
||||
if (crossBlocked) warnings.push("未开启跨卷移动,执行会失败。改用复制,或在 设置 → 整理 中开启");
|
||||
if (conflictSrc.size > 0) warnings.push(`${conflictSrc.size} 个文件在目标已存在,不覆盖,执行时记为失败`);
|
||||
if (truncated) warnings.push("源文件数超过上限,请分批操作");
|
||||
if (truncated) warnings.push("源文件数超过上限,分批操作");
|
||||
const base = { mode, pairs, totalBytes, freeBytes, spaceOk, hnrBlocks, truncated, warnings };
|
||||
|
||||
if (body.dryRun) {
|
||||
@@ -219,19 +218,19 @@ export async function transfer(
|
||||
throw new FilesError("plan_stale", `源在预览后发生变化(大小/修改时间/文件清单): ${s.rel}`);
|
||||
}
|
||||
if (plan.content.files && hashJson(plan.content.files) !== hashJson(filePairs))
|
||||
throw new FilesError("plan_stale", "重新计算的前后路径与预览不一致(目标已变化),请重新预览");
|
||||
if (truncated) throw new FilesError("bad_request", "源目录文件数超过上限,请分批操作");
|
||||
throw new FilesError("plan_stale", "目标已变化,与预览不一致。重新预览");
|
||||
if (truncated) throw new FilesError("bad_request", "源目录文件数超过上限,分批操作");
|
||||
if (!spaceOk) throw new FilesError("bad_request", `目标卷空间不足:需要 ${needBytes},可用 ${freeBytes}`);
|
||||
if (crossBlocked)
|
||||
throw new FilesError(
|
||||
"bad_request",
|
||||
"跨卷移动未开启(settings.organize.allowCrossVolumeMove),请改用复制或开启后重试",
|
||||
"未开启跨卷移动(settings.organize.allowCrossVolumeMove)。改用复制,或开启后重试",
|
||||
);
|
||||
if (mode === "move") {
|
||||
if (hnrBlocks.length > 0)
|
||||
throw new FilesError(
|
||||
"download_active",
|
||||
`源属于纳管下载任务(${[...new Set(hnrBlocks.map((h) => h.taskId))].join(", ")}),裸移动会让下载器丢失文件;请用整理入库(Move 会按 H&R 判定并移交)`,
|
||||
`源属于下载任务 ${[...new Set(hnrBlocks.map((h) => h.taskId))].join(", ")},直接移动会让下载器丢失文件。改用整理入库,它会按做种义务决定能否移动`,
|
||||
);
|
||||
if (!isAdmin(principal)) {
|
||||
// 每个源按其(目录则为其下)已登记资产求作品集合,逐一核对授权;任一不覆盖 → 整体拒绝并列出未授权项
|
||||
@@ -273,7 +272,7 @@ export async function transfer(
|
||||
}
|
||||
if (!rec.recordId || rec.status === "failed") {
|
||||
await markTask(db, taskId, "failed", { error: rec.reason ?? rec.status });
|
||||
throw new FilesError("bad_request", `搬运计划不可执行:${rec.reason ?? rec.status}`);
|
||||
throw new FilesError("bad_request", `计划不可执行:${rec.reason ?? rec.status}`);
|
||||
}
|
||||
const recordId = rec.recordId;
|
||||
await db.updateTable("organization_record").set({ task_id: taskId }).where("id", "=", recordId).execute();
|
||||
|
||||
Reference in new issue
Block a user