Merge branch 'deai2'

Co-Authored-By: Claude Fable 5.1 <[email protected]>

# Conflicts:
#	apps/server/src/modules/acquisition-organize/services/organize.ts
#	apps/web/app/routes/console/sites.$siteId.tsx
This commit is contained in:
root committed 2026-09-29 21:26:16 +08:00
commit 12bc4664b6
247 files changed
+2658 -2148

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ class MemStore {
}
// 验收 S7:生产构建里 ?mock=1 不得把演示数据当真实运行展示
describe("Agent 演示开关", () => {
describe("智能体演示开关", () => {
it("只在开发构建或后端 provider=fake 时允许", () => {
expect(agentMockAllowed({ dev: true })).toBe(true);
expect(agentMockAllowed({ dev: false, provider: "fake" })).toBe(true);
+2 -2
View File
@@ -155,9 +155,9 @@ export const DOWNLOAD_STATUS_TONE: Record<DownloadStatus, "success" | "warning"
export const PAUSE_REASON_LABEL = {
user: "用户暂停",
threshold: "阈值暂停",
threshold: "下载盘满暂停",
policy: "策略暂停",
agent: "Agent 暂停",
agent: "智能体暂停",
} as const;
export const PLAN_STATUS_LABEL: Record<PlanStatus, string> = {
+1 -1
View File
@@ -106,7 +106,7 @@ export function useFetchFeedNow() {
export function feedGapHint(f: FeedSource, now = Date.now()): string | null {
if (f.possibleGap) {
const at = new Date(f.possibleGap.detectedAt).toLocaleString("zh-CN", { hour12: false });
return `疑似缺口(${at} 检测,${f.possibleGap.backfillQueued ? "已排补漏" : "Feed 未关联站点,无法自动补漏"})`;
return `疑似缺口(${at} 检测,${f.possibleGap.backfillQueued ? "已排补漏" : "RSS 未关联站点,无法自动补漏"})`;
}
if (!f.enabled || !f.lastSuccessAt) return null;
const gapMs = now - new Date(f.lastSuccessAt).getTime();
+1 -1
View File
@@ -64,7 +64,7 @@ export function inventoryFlags(
});
}
if (releaseResolution && releaseResolution === "resolved" && flags.length === 0) {
flags.push({ key: "tracked", label: "已识别,无版本目标", tone: "neutral" });
flags.push({ key: "tracked", label: "已识别,无收录版本", tone: "neutral" });
}
return flags;
}
+1 -1
View File
@@ -107,7 +107,7 @@ export const RECORD_STATUS_TONE: Record<OrganizationStatus, "success" | "warning
cancelled: "neutral",
};
export const TRIGGER_LABEL: Record<OrganizationTrigger, string> = { auto: "自动", manual: "手动", agent: "Agent" };
export const TRIGGER_LABEL: Record<OrganizationTrigger, string> = { auto: "自动", manual: "手动", agent: "智能体" };
/** dryRun 生成的整理计划冻结为 artifact(kind=plan),GET /artifacts/{id} 读取逐文件预览 */
export function useArtifact(id: string | null | undefined) {
+4 -4
View File
@@ -99,14 +99,14 @@ export function useRuleSuppressions() {
export type RuleRefs = {
/** 规则组 id → 引用它的订阅(params.ruleGroupIds 或私有组) */
subscriptions: Map<string, { id: string; title: string }[]>;
/** 规则组 id → 引用它的版本目标 */
/** 规则组 id → 引用它的收录版本 */
slots: Map<string, { id: string; name: string }[]>;
};
const SubPage = cursorPage(Subscription);
const SlotPage = cursorPage(AcquisitionSlot);
/** 引用关系:列表接口不带引用计数,前端从订阅与版本目标反查(各取前 200 条) */
/** 引用关系:列表接口不带引用计数,前端从订阅与收录版本反查(各取前 200 条) */
export function useRuleRefs() {
return useQuery({
queryKey: ruleKeys.refs,
@@ -150,7 +150,7 @@ function useInvalidate() {
const qc = useQueryClient();
return () => {
void qc.invalidateQueries({ queryKey: ruleKeys.all });
// 旧偏好标签页与订阅/版本目标的规则组显示同源
// 旧偏好标签页与订阅/收录版本的规则组显示同源
void qc.invalidateQueries({ queryKey: ["preferences"] });
};
}
@@ -175,7 +175,7 @@ export function useUpdateRuleGroup() {
});
}
/** 删除:标记删除并写抑制记录;被版本目标/订阅引用时 409 */
/** 删除:标记删除并写抑制记录;被收录版本/订阅引用时 409 */
export function useDeleteRuleGroup() {
const done = useInvalidate();
return useMutation({
+1 -1
View File
@@ -105,7 +105,7 @@ export function useSiteRequestStats(siteId: string | undefined) {
export function accessSummary(s: SiteRequestStats): string {
const dur = (sec: number) => (sec % 3600 === 0 ? `${sec / 3600} 小时` : `${Math.round(sec / 60)} 分钟`);
const parts = [
`快照每 ${dur(s.snapshotIntervalSec)} ${s.access.snapshotMaxPages} 页`,
`抓取每 ${dur(s.snapshotIntervalSec)} ${s.access.snapshotMaxPages} 页`,
`健康检测每 ${dur(s.access.healthCheckIntervalSec)}`,
];
if (s.access.detailCacheSec > 0) parts.push(`详情缓存 ${dur(s.access.detailCacheSec)}`);
+2 -2
View File
@@ -77,7 +77,7 @@ export function useUpdateSubscription() {
api.patch<unknown>(`/subscriptions/${id}`, body).then((d) => parseOrThrow(Subscription, d, "/subscriptions")),
onSuccess: () => {
void qc.invalidateQueries({ queryKey: subscriptionKeys.all });
// best_version 写到版本目标的升级策略
// best_version 写到收录版本的升级策略
void qc.invalidateQueries({ queryKey: ["slots"] });
},
});
@@ -246,7 +246,7 @@ export function useFillSlot() {
});
}
/** 版本目标排序:第一个成为主版本 */
/** 收录版本排序:第一个成为主版本 */
export function useSetSlotOrder() {
const done = useInvalidateSubs();
return useMutation({
+19 -8
View File
@@ -11,7 +11,8 @@ import {
type TaskStatus,
} from "@umt/contracts";
import { organizationActionLabel, organizationLabel } from "~/lib/labels.ts";
import { PLAN_STATUS_LABEL } from "./downloads.ts";
import { humanizeReason, reasonLine } from "~/lib/reasons.ts";
import { PAUSE_REASON_LABEL, PLAN_STATUS_LABEL } from "./downloads.ts";
import { apiParsed } from "./parse.ts";
// 业务任务视图:按 trace 汇总的业务时间线(参考 MovieClaw task-activity)
@@ -23,7 +24,7 @@ const RecordPage = cursorPage(PublicOrganizationRecord);
const DecisionPage = cursorPage(Decision);
const RESOLUTION_LABEL = {
unresolved: "待识别",
unresolved: "未识别",
resolved: "已识别",
ambiguous: "有歧义,待确认",
unidentifiable: "无法识别",
@@ -173,7 +174,7 @@ export function buildTimeline(input: {
stage: "plan",
at: plan.createdAt,
title: `创建下载计划(${plan.purpose === "fill" ? "补缺" : plan.purpose === "upgrade" ? "升级" : "换源"})`,
detail: plan.statusReason,
detail: humanizeReason(plan.statusReason),
tone: "neutral",
});
if (plan.updatedAt !== plan.createdAt)
@@ -182,7 +183,7 @@ export function buildTimeline(input: {
stage: "plan",
at: plan.updatedAt,
title: `计划状态:${PLAN_STATUS_LABEL[plan.status]}`,
detail: plan.statusReason,
detail: humanizeReason(plan.statusReason),
tone: plan.status === "failed" ? "destructive" : plan.status === "expired" ? "warning" : "neutral",
});
}
@@ -199,7 +200,7 @@ export function buildTimeline(input: {
key: "dl-pause",
stage: "download",
at: task.updatedAt,
title: task.pauseReason === "threshold" ? "缓存达到硬阈值,已暂停" : `已暂停(${task.pauseReason})`,
title: task.pauseReason === "threshold" ? "下载盘超过暂停线,已暂停" : PAUSE_REASON_LABEL[task.pauseReason],
tone: "warning",
ongoing: task.status === "paused",
});
@@ -239,7 +240,15 @@ export function buildTimeline(input: {
stage: "organization",
at: r.startedAt ?? r.createdAt,
title: `整理 ${organizationActionLabel(r.action)}:${organizationLabel(r.status).label}`,
detail: `${c.succeeded}/${c.total} 文件成功${c.failed ? `,${c.failed} 失败` : ""}${c.skipped ? `,${c.skipped} 跳过` : ""}${r.reason ? ` · ${r.reason.message}` : ""}`,
detail:
[
c.total ? `${c.succeeded}/${c.total} 个文件成功` : null,
c.failed ? `${c.failed} 个失败` : null,
c.skipped ? `${c.skipped} 个跳过` : null,
r.reason ? reasonLine(r.reason) : null,
]
.filter(Boolean)
.join(" · ") || null,
tone: RECORD_TONE[r.status],
href: `/console/organize/${r.id}`,
ongoing: r.status === "running" || r.status === "queued",
@@ -260,7 +269,7 @@ export function buildTimeline(input: {
key: `agent-${d.id}`,
stage: "agent",
at: d.updatedAt,
title: "Agent 已介入调查",
title: "智能体已介入调查",
tone: "neutral",
href: `/console/agent/${d.agentRunId}`,
});
@@ -275,7 +284,9 @@ export function buildTimeline(input: {
at: t.startedAt ?? t.createdAt,
title: `任务 ${TASK_KIND_LABEL[t.kind] ?? t.kind}:${TASK_STATUS_TEXT[t.status] ?? t.status}`,
detail:
[t.attempts > 1 ? `第 ${t.attempts} 次尝试` : null, t.waitReason, err].filter(Boolean).join(" · ") || null,
[t.attempts > 1 ? `第 ${t.attempts} 次尝试` : null, humanizeReason(t.waitReason), humanizeReason(err)]
.filter(Boolean)
.join(" · ") || null,
tone: TASK_STATUS_TONE[t.status],
href: `/console/tasks/${encodeURIComponent(t.id)}`,
ongoing: ACTIVE_TASK.includes(t.status),