diff --git a/src/components/app-ui.tsx b/src/components/app-ui.tsx
index 16bafc9..76b10d4 100644
--- a/src/components/app-ui.tsx
+++ b/src/components/app-ui.tsx
@@ -410,13 +410,17 @@ export function getConversationListItemPresentation(conversation: ConversationIt
}
export function getConversationActionAvailability(conversation: ConversationItem) {
- const canTogglePin = conversation.projectId !== "master-agent";
return {
- canTogglePin,
+ canTogglePin: false,
togglePinLabel: conversation.topPinnedLabel || conversation.manualPinned ? "取消置顶" : "置顶",
};
}
+export function getConversationPinnedBadgeLabel(conversation: ConversationItem) {
+ void conversation;
+ return "";
+}
+
export function getConversationActionsPath(projectId: string) {
return `/api/v1/conversations/${encodeURIComponent(projectId)}/actions`;
}
@@ -526,11 +530,7 @@ export function ConversationList({
- {conversation.projectId === "master-agent"
- ? "置顶"
- : conversation.topPinnedLabel
- ? "置顶"
- : ""}
+ {getConversationPinnedBadgeLabel(conversation)}
{conversation.latestReplyLabel}
{conversation.contextBudgetIndicator.visible &&
diff --git a/tests/conversation-home-items.test.ts b/tests/conversation-home-items.test.ts
index ed29eac..84d23ea 100644
--- a/tests/conversation-home-items.test.ts
+++ b/tests/conversation-home-items.test.ts
@@ -15,6 +15,7 @@ let formatTimestampLabel: (typeof import("../src/lib/boss-projections"))["format
let getConversationListItemPresentation: (typeof import("../src/components/app-ui"))["getConversationListItemPresentation"];
let getConversationActionAvailability: (typeof import("../src/components/app-ui"))["getConversationActionAvailability"];
let getConversationActionsPath: (typeof import("../src/components/app-ui"))["getConversationActionsPath"];
+let getConversationPinnedBadgeLabel: (typeof import("../src/components/app-ui"))["getConversationPinnedBadgeLabel"];
async function setup() {
if (runtimeRoot) return;
@@ -37,6 +38,7 @@ async function setup() {
getConversationListItemPresentation = ui.getConversationListItemPresentation;
getConversationActionAvailability = ui.getConversationActionAvailability;
getConversationActionsPath = ui.getConversationActionsPath;
+ getConversationPinnedBadgeLabel = ui.getConversationPinnedBadgeLabel;
}
test.after(async () => {
@@ -705,7 +707,7 @@ test("conversation home compacts imported previews and trims local workspace pre
assert.equal(item?.lastMessagePreview, "已导入线程");
});
-test("folder archive homepage rows expose pin toggles when the folder is pinned", async () => {
+test("folder archive homepage rows do not expose pin toggles in the Web surface", async () => {
await setup();
const state = await readState();
@@ -738,8 +740,34 @@ test("folder archive homepage rows expose pin toggles when the folder is pinned"
assert.ok(folder, "expected grouped folder archive item");
const actions = getConversationActionAvailability(folder!);
- assert.equal(actions.canTogglePin, true);
- assert.equal(actions.togglePinLabel, "取消置顶");
+ assert.equal(actions.canTogglePin, false);
+});
+
+test("homepage rows do not expose pinned labels in the Web surface", async () => {
+ await setup();
+ const state = await readState();
+
+ state.projects = state.projects.filter((project) => project.id === "master-agent");
+ state.projects.push({
+ ...buildImportedThreadProject(
+ "mac-studio",
+ "boss-thread-1",
+ "Boss",
+ "boss",
+ "归档确认",
+ "thread-1",
+ "2026-03-30T11:00:00+08:00",
+ ),
+ pinned: true,
+ });
+
+ const pinnedThread = getConversationHomeItems(state).find((item) => item.projectId === "boss-thread-1");
+ assert.ok(pinnedThread, "expected pinned thread item");
+ assert.equal(getConversationPinnedBadgeLabel(pinnedThread!), "");
+
+ const masterAgent = getConversationHomeItems(state).find((item) => item.projectId === "master-agent");
+ assert.ok(masterAgent, "expected master agent item");
+ assert.equal(getConversationPinnedBadgeLabel(masterAgent!), "");
});
test("folder archive action path encodes folder keys with nested path segments", async () => {