fix(agent): download.recheck 复用下载同步的 qB 客户端

qB 客户端缓存改为按 ServerContext 共享(downloaderClientFor),Agent 不再自己 new 客户端,
与下载同步、面板共用同一登录会话和凭证处理。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-03 23:20:28 +08:00
1 parent 74f2c7649e
commit 3d3a4cefc6
2 files changed
+35 -28

No files matched your search

@@ -1,7 +1,6 @@
import { createQbClient, type DownloaderClient, qbAuthConfig } from "@umt/adapters";
import { CapabilityError, type CapabilityRegistry } from "@umt/agent";
import { capabilitySpec, type DownloadStatus } from "@umt/contracts";
import type { DownloaderInstanceRow } from "@umt/db";
import { downloaderClientFor } from "../acquisition-organize/ports.ts";
import type { ServerContext } from "../types.ts";
import { planBinding } from "./authorize.ts";
import type { AgentModuleOptions } from "./runner.ts";
@@ -15,16 +14,6 @@ const RECHECK_FROM: DownloadStatus[] = ["missing", "failed", "stalled", "paused"
/** resume 允许的起点 */
const RESUME_FROM: DownloadStatus[] = ["paused", "stalled", "failed"];
async function defaultClient(ctx: ServerContext, inst: DownloaderInstanceRow): Promise<DownloaderClient> {
const settings = (inst.settings ?? {}) as Record<string, unknown>;
const secret = inst.secret_ref ? await ctx.secrets.resolve(inst.secret_ref) : undefined;
return createQbClient({
instanceId: inst.id,
baseUrl: inst.base_url,
...qbAuthConfig({ authKind: settings.authKind, username: inst.username, secret: secret ?? null }),
});
}
/** 持续授权的对象范围:按下载任务 → 计划 → Slot → 作品核对(authorize 对非计划类能力拿不到目标作品) */
async function checkGrantScope(ctx: ServerContext, grantId: string, planId: string | null) {
const g = await ctx.db.selectFrom("automation_grant").select("scope").where("id", "=", grantId).executeTakeFirst();
@@ -75,7 +64,8 @@ export function registerDownloadRecoveryCapabilities(
.where("id", "=", dt.instance_id)
.executeTakeFirst();
if (!inst) throw new CapabilityError("not_found", "下载器实例不存在");
const client = opts.downloader ? await opts.downloader(inst) : await defaultClient(ctx, inst);
// 与下载同步共用按实例缓存的客户端(同一登录会话与凭证处理),不另建
const client = opts.downloader ? await opts.downloader(inst) : await downloaderClientFor(ctx, inst);
try {
if (input.action === "recheck") await client.recheck([dt.torrent_hash]);
else await client.resume([dt.torrent_hash]);