Compact imported folder conversation previews

This commit is contained in:
kris
2026-04-06 16:45:35 +08:00
parent 6d90123092
commit 992f8dbba4
2 changed files with 75 additions and 6 deletions

View File

@@ -488,6 +488,33 @@ function buildFolderSearchAliases(items: ConversationItem[]) {
: undefined;
}
function compactImportedThreadPreview(preview?: string) {
const value = preview?.trim();
if (!value) return "";
if (/^已从设备.+导入线程《.+》[。.]?$/.test(value)) {
return "已导入线程";
}
return value;
}
function trimLocalWorkspacePrefix(label?: string) {
const value = label?.trim();
if (!value) return "";
const normalized = value.replaceAll("\\", "/");
const patterns = [
/^\/Users\/[^/]+\/code\/(.+)$/i,
/^\/home\/[^/]+\/code\/(.+)$/i,
/^[A-Za-z]:\/Users\/[^/]+\/code\/(.+)$/i,
];
for (const pattern of patterns) {
const match = normalized.match(pattern);
if (match?.[1]) {
return match[1];
}
}
return value;
}
export function getConversationItems(state: BossState): ConversationItem[] {
const conversations = state.projects.map((project) => buildConversationItem(state, project));
@@ -548,8 +575,12 @@ export function getConversationHomeItems(state: BossState): ConversationItem[] {
}
return b.latestReplyAt.localeCompare(a.latestReplyAt);
})[0];
const recentThreadLabel = latestItem.threadTitle.trim();
const recentThreadLabel = trimLocalWorkspacePrefix(latestItem.threadTitle);
const searchAliases = buildFolderSearchAliases(items);
const latestPreview = compactImportedThreadPreview(latestItem.preview);
const latestMessagePreview = compactImportedThreadPreview(
latestItem.lastMessagePreview || latestItem.preview,
);
passthrough.push({
conversationId: `folder-${folderKey}`,
conversationType: "folder_archive",
@@ -571,12 +602,11 @@ export function getConversationHomeItems(state: BossState): ConversationItem[] {
searchTargetProjectIds: searchAliases.targetProjectIds,
}
: {}),
preview:
latestItem.preview || `包含 ${items.length} 个线程,最近活跃:《${latestItem.threadTitle}`,
preview: latestPreview || `包含 ${items.length} 个线程,最近活跃:《${recentThreadLabel || latestItem.threadTitle}`,
lastMessagePreview:
latestItem.lastMessagePreview ||
latestItem.preview ||
`包含 ${items.length} 个线程,最近活跃:《${latestItem.threadTitle}`,
latestMessagePreview ||
latestPreview ||
`包含 ${items.length} 个线程,最近活跃:《${recentThreadLabel || latestItem.threadTitle}`,
activityIconCount: Math.max(0, Math.min(4, items.reduce((sum, entry) => sum + entry.activityIconCount, 0))),
latestReplyAt: latestItem.latestReplyAt,
latestReplyLabel: latestItem.latestReplyLabel,

View File

@@ -542,6 +542,45 @@ test("folder archive homepage rows keep the project title, compact subtitle, and
assert.equal(presentation.href, "/conversations/folders/mac-studio%3Aboss");
});
test("conversation home compacts imported previews and trims local workspace prefixes from folder subtitles", async () => {
await setup();
const state = await readState();
state.projects = state.projects.filter((project) => project.id === "master-agent");
state.projects.push(
{
...buildImportedThreadProject(
"mac-studio",
"wenshen-thread-1",
"wenshenapp",
"/Users/kris/code/wenshenapp",
"/Users/kris/code/wenshenapp/docs/superpowers/specs/2026-04-06-context-cleanup-design.md",
"thread-1",
"2026-04-06T15:00:00+08:00",
),
preview: "已从设备 Mac Studio 导入线程《/Users/kris/code/wenshenapp/docs/superpowers/specs/2026-04-06-context-cleanup-design.md》。",
lastMessageAt: "2026-04-06T15:00:00+08:00",
},
buildImportedThreadProject(
"mac-studio",
"wenshen-thread-2",
"wenshenapp",
"/Users/kris/code/wenshenapp",
"补齐 Android 会话可读性",
"thread-2",
"2026-04-06T14:00:00+08:00",
),
);
const folder = getConversationHomeItems(state).find((item) => item.projectId === "mac-studio:/users/kris/code/wenshenapp");
assert.ok(folder, "expected grouped folder archive item");
assert.equal(folder?.conversationType, "folder_archive");
assert.equal(folder?.folderLabel, "2 个线程 · 最近wenshenapp/docs/superpowers/specs/2026-04-06-context-cleanup-design.md");
assert.equal(folder?.preview, "已导入线程");
assert.equal(folder?.lastMessagePreview, "已导入线程");
});
test("folder archive homepage rows expose pin toggles when the folder is pinned", async () => {
await setup();
const state = await readState();