feat(server): gate scheduling, search and login by site capabilities (IA-2)

- snapshots only for sites with list; feed polling only for RSS kinds;
  user data / health checks only for sites with login; search site set
  only includes searchable sites; live search / snapshot skip with
  reason unsupported instead of hitting the site
- refresh-login / credentials need login, manual snapshot needs list (400)
- POST /sites accepts kind and rssUrl (site + feed in one transaction,
  key generated from host); RSS belongs to a site: feeds created without
  siteId go to the same-host custom RSS source site, siteId cannot be
  cleared
- fix: secret name clash when a site gets a second default-named feed
- command palette regrouped; agent site.list returns kind and
  capabilities; system prompt notes RSS lives under sites

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-30 00:29:56 +08:00
1 parent 89d2c81de6
commit ec65435328
15 files changed
+486 -80

No files matched your search

+4 -2
View File
@@ -14,6 +14,7 @@ import { type SiteRow, sql } from "@umt/db";
import { applyFacets, type FacetInput, normalizeTitle, parseFacetParam, parseRelease } from "@umt/domain";
import type { SourcesRuntime } from "../sources-identity/runtime.ts";
import { upsertSiteRelease } from "../sources-identity/service/snapshot.ts";
import { siteCan } from "../sources-identity/site-kinds.ts";
import { raceAbort } from "./media.ts";
// 跨站资源搜索:选中的已启用站点逐站调适配器 search(每站共享限流器 + 单站超时 + 站点级并发上限);
@@ -63,15 +64,16 @@ export class ReleaseFanout {
private readonly opts: FanoutOptions,
) {}
/** 参与搜索的候选站点:启用且未删除(按名称排序) */
/** 参与搜索的候选站点:启用、未删除且支持搜索(IA-2 按站点类型与定义的获取方式;按名称排序) */
async enabledSites(): Promise<SiteRow[]> {
return this.rt()
const rows = await this.rt()
.ctx.db.selectFrom("site")
.selectAll()
.where("enabled", "=", true)
.where("deleted_at", "is", null)
.orderBy("name")
.execute();
return rows.filter((s) => siteCan(s, "search"));
}
/**