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
@@ -107,7 +107,7 @@ export function registerSourcesCapabilities(registry: CapabilityRegistry, rt: ()
|
||||
.selectAll()
|
||||
.where("id", "=", input.sourceReleaseId)
|
||||
.executeTakeFirst();
|
||||
if (!row) throw new Error("来源资源不存在");
|
||||
if (!row) throw new Error("资源不存在");
|
||||
// 库存(media_asset)归 W2-C,这里只按作品只读查询
|
||||
const inventory = row.media_entity_id
|
||||
? await r.ctx.db
|
||||
@@ -130,7 +130,7 @@ export function registerSourcesCapabilities(registry: CapabilityRegistry, rt: ()
|
||||
.executeTakeFirst();
|
||||
srId = o?.source_release_id ?? null;
|
||||
}
|
||||
if (!srId) throw new Error("找不到来源资源");
|
||||
if (!srId) throw new Error("资源不存在");
|
||||
const actor = { type: "agent" as const, id: ctx.actorId };
|
||||
const c = input.candidate;
|
||||
if (c?.mediaEntityId || (c?.provider && c.entityType && c.externalId)) {
|
||||
|
||||
@@ -157,7 +157,7 @@ export const D = {
|
||||
sourceReleases: {
|
||||
list: list(
|
||||
"/source-releases",
|
||||
"站点资源列表",
|
||||
"资源列表",
|
||||
SourceRelease,
|
||||
{
|
||||
siteId: Id.optional(),
|
||||
@@ -167,7 +167,7 @@ export const D = {
|
||||
},
|
||||
TR,
|
||||
),
|
||||
get: get("/source-releases/{id}", "站点资源详情", SourceRelease, TR),
|
||||
get: get("/source-releases/{id}", "资源详情", SourceRelease, TR),
|
||||
},
|
||||
observations: {
|
||||
list: list(
|
||||
|
||||
@@ -129,7 +129,7 @@ export function decisionRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
.where("source_release_id", "=", d.subject_id)
|
||||
.executeTakeFirst();
|
||||
if (!(pool?.candidates as PoolCandidate[] | undefined)?.[opt.input.candidateIndex]) {
|
||||
throw new ApiException("conflict", "候选已变化,请刷新后重试");
|
||||
throw new ApiException("conflict", "候选已变化,刷新后重试");
|
||||
}
|
||||
await assignReleaseIdentity(
|
||||
rt(),
|
||||
|
||||
@@ -521,7 +521,7 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
});
|
||||
route(app, D.sourceReleases.get, async ({ params }) => {
|
||||
const row = await db().selectFrom("source_release").selectAll().where("id", "=", params.id).executeTakeFirst();
|
||||
if (!row) throw new ApiException("not_found", "来源资源不存在");
|
||||
if (!row) throw new ApiException("not_found", "资源不存在");
|
||||
return toApi(row);
|
||||
});
|
||||
route(
|
||||
@@ -530,7 +530,7 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
method: "post",
|
||||
path: "/source-releases/{id}/identity",
|
||||
scope: "organize.execute",
|
||||
summary: "人工指定来源资源的作品/内容单元(加人工锁,自动识别不再改写)",
|
||||
summary: "人工指定资源的作品/内容单元(加人工锁,自动识别不再改写)",
|
||||
tags: T_RELEASES,
|
||||
params: IdParam,
|
||||
body: ReleaseIdentityAssign,
|
||||
@@ -544,7 +544,7 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
method: "post",
|
||||
path: "/source-releases/{id}/unlock",
|
||||
scope: "organize.execute",
|
||||
summary: "解除来源资源的人工锁并重新识别",
|
||||
summary: "解除资源的人工锁并重新识别",
|
||||
tags: T_RELEASES,
|
||||
params: IdParam,
|
||||
response: Accepted,
|
||||
@@ -556,7 +556,7 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
.where("id", "=", params.id)
|
||||
.returning(["id", "site_id"])
|
||||
.executeTakeFirst();
|
||||
if (!row) throw new ApiException("not_found", "来源资源不存在");
|
||||
if (!row) throw new ApiException("not_found", "资源不存在");
|
||||
await audit(db(), actor, "identity.release_unlocked", { type: "source_release", id: params.id });
|
||||
const r = await rt().ctx.engine.enqueue(
|
||||
"resolveObservation",
|
||||
|
||||
@@ -17,7 +17,7 @@ export function workbenchRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
method: "get",
|
||||
path: "/sites/{id}/releases",
|
||||
scope: "read",
|
||||
summary: "站点资源列表/搜索(快照优先,必要时实时补查;标注来源与更新时间)",
|
||||
summary: "资源列表/搜索(快照优先,必要时实时补查;标注来源与更新时间)",
|
||||
tags: T,
|
||||
params: z.object({ id: Id }),
|
||||
query: WorkbenchReleaseQuery,
|
||||
@@ -31,7 +31,7 @@ export function workbenchRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
method: "get",
|
||||
path: "/sites/{id}/releases/{rid}",
|
||||
scope: "read",
|
||||
summary: "站点资源详情(refresh=true 时实时复核详情;失败保留既有数据)",
|
||||
summary: "资源详情(refresh=true 时实时复核详情;失败保留既有数据)",
|
||||
tags: T,
|
||||
params: z.object({ id: Id, rid: Id }),
|
||||
query: z.object({ refresh: z.enum(["true", "false"]).optional() }),
|
||||
|
||||
@@ -209,14 +209,14 @@ export async function ingestFeed(
|
||||
kind: "source_unreachable",
|
||||
severity: "warning",
|
||||
title: `Feed「${feed.name}」凭证失效`,
|
||||
summary: "RSS 返回 401/403 或过期提示;已停止自动重试。请更新 Feed 链接或站点账号凭证后手动恢复。",
|
||||
summary: "RSS 返回 401/403 或过期提示,已停止自动重试。更新 Feed 链接或站点账号凭证后恢复抓取。",
|
||||
subjectType: "feed_source",
|
||||
subjectId: feed.id,
|
||||
dedupeKey: `feed-auth:${feed.id}`,
|
||||
evidence: { feedId: feed.id, siteId: feed.site_id, siteAccountId: feed.site_account_id, error: lastError },
|
||||
options: [
|
||||
{ key: "reset", label: "已更新凭证,恢复抓取" },
|
||||
{ key: "disable", label: "停用该 Feed" },
|
||||
{ key: "disable", label: "停用 Feed" },
|
||||
],
|
||||
});
|
||||
out = { ...out, status: "auth_failed", reason: "auth" };
|
||||
|
||||
@@ -64,7 +64,7 @@ export async function assignReleaseIdentity(
|
||||
): Promise<{ mediaEntityId: string; contentUnitIds: string[] }> {
|
||||
const { ctx } = rt;
|
||||
const release = await ctx.db.selectFrom("source_release").selectAll().where("id", "=", srId).executeTakeFirst();
|
||||
if (!release) throw new ApiException("not_found", "来源资源不存在");
|
||||
if (!release) throw new ApiException("not_found", "资源不存在");
|
||||
const parsed = parseRelease(release.title, release.subtitle ? { subtitle: release.subtitle } : {});
|
||||
const site = ((release.raw as Record<string, unknown>)?._site ?? {}) as { categoryName?: string };
|
||||
const variety = looksLikeVariety(parsed, site.categoryName ?? release.category_raw);
|
||||
@@ -241,7 +241,7 @@ export async function setEntityIdentity(rt: SourcesRuntime, entityId: string, in
|
||||
if (!id) throw new ApiException("not_found", "作品不存在");
|
||||
const other = await entityByExternal(trx, input);
|
||||
if (other && other !== id) {
|
||||
throw new ApiException("conflict", `该外部身份已属于作品 ${other},如为重复作品请使用合并`);
|
||||
throw new ApiException("conflict", `该外部身份已属于作品 ${other}。如果是重复作品,改用合并`);
|
||||
}
|
||||
if (other === id) return { mediaEntityId: id, changed: false };
|
||||
const olds = await trx
|
||||
|
||||
@@ -557,7 +557,7 @@ async function toPool(
|
||||
kind: "identity_ambiguous",
|
||||
severity: "info",
|
||||
title: `待确认身份:${release.title}`,
|
||||
summary: `${candidates.length} 个候选证据等级相近(${detail}),请选择或忽略`,
|
||||
summary: `${candidates.length} 个候选证据等级相近(${detail})。选择一个或忽略`,
|
||||
subjectType: "source_release",
|
||||
subjectId: release.id,
|
||||
dedupeKey: `identity:${release.id}`,
|
||||
|
||||
@@ -85,7 +85,7 @@ async function onAuthError(rt: SourcesRuntime, trx: Exec, site: SiteRow, e: Site
|
||||
kind: "source_unreachable",
|
||||
severity: "warning",
|
||||
title: `站点「${site.name}」登录失效`,
|
||||
summary: `${e.kind}:${e.message}。已停止该站自动访问,请更新账号凭证后恢复。`,
|
||||
summary: `${e.kind}:${e.message}。已停止自动访问该站点。更新账号凭证后恢复访问。`,
|
||||
subjectType: "site",
|
||||
subjectId: site.id,
|
||||
dedupeKey: `site-auth:${site.id}`,
|
||||
|
||||
Reference in new issue
Block a user