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

@@ -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}`,