refactor: centralize channel ui metadata

This commit is contained in:
Peter Steinberger
2026-01-20 13:10:26 +00:00
parent 6f9861bb9b
commit fdb171cb15
19 changed files with 240 additions and 68 deletions

View File

@@ -0,0 +1,29 @@
import type { ChannelMessageActionName } from "./types.js";
export type BlueBubblesActionSpec = {
gate: string;
groupOnly?: boolean;
unsupportedOnMacOS26?: boolean;
};
export const BLUEBUBBLES_ACTIONS = {
react: { gate: "reactions" },
edit: { gate: "edit", unsupportedOnMacOS26: true },
unsend: { gate: "unsend" },
reply: { gate: "reply" },
sendWithEffect: { gate: "sendWithEffect" },
renameGroup: { gate: "renameGroup", groupOnly: true },
setGroupIcon: { gate: "setGroupIcon", groupOnly: true },
addParticipant: { gate: "addParticipant", groupOnly: true },
removeParticipant: { gate: "removeParticipant", groupOnly: true },
leaveGroup: { gate: "leaveGroup", groupOnly: true },
sendAttachment: { gate: "sendAttachment" },
} as const satisfies Partial<Record<ChannelMessageActionName, BlueBubblesActionSpec>>;
export const BLUEBUBBLES_ACTION_NAMES = Object.keys(
BLUEBUBBLES_ACTIONS,
) as ChannelMessageActionName[];
export const BLUEBUBBLES_GROUP_ACTIONS = new Set<ChannelMessageActionName>(
BLUEBUBBLES_ACTION_NAMES.filter((action) => BLUEBUBBLES_ACTIONS[action]?.groupOnly),
);

View File

@@ -5,6 +5,22 @@ import type { PluginOrigin } from "../../plugins/types.js";
import type { ClawdbotPackageManifest } from "../../plugins/manifest.js";
import type { ChannelMeta } from "./types.js";
export type ChannelUiMetaEntry = {
id: string;
label: string;
detailLabel: string;
systemImage?: string;
};
export type ChannelUiCatalog = {
entries: ChannelUiMetaEntry[];
order: string[];
labels: Record<string, string>;
detailLabels: Record<string, string>;
systemImages: Record<string, string>;
byId: Record<string, ChannelUiMetaEntry>;
};
export type ChannelPluginCatalogEntry = {
id: string;
meta: ChannelMeta;
@@ -116,6 +132,34 @@ function buildCatalogEntry(candidate: {
return { id, meta, install };
}
export function buildChannelUiCatalog(
plugins: Array<{ id: string; meta: ChannelMeta }>,
): ChannelUiCatalog {
const entries: ChannelUiMetaEntry[] = plugins.map((plugin) => {
const detailLabel = plugin.meta.detailLabel ?? plugin.meta.selectionLabel ?? plugin.meta.label;
return {
id: plugin.id,
label: plugin.meta.label,
detailLabel,
...(plugin.meta.systemImage ? { systemImage: plugin.meta.systemImage } : {}),
};
});
const order = entries.map((entry) => entry.id);
const labels: Record<string, string> = {};
const detailLabels: Record<string, string> = {};
const systemImages: Record<string, string> = {};
const byId: Record<string, ChannelUiMetaEntry> = {};
for (const entry of entries) {
labels[entry.id] = entry.label;
detailLabels[entry.id] = entry.detailLabel;
if (entry.systemImage) {
systemImages[entry.id] = entry.systemImage;
}
byId[entry.id] = entry;
}
return { entries, order, labels, detailLabels, systemImages, byId };
}
export function listChannelPluginCatalogEntries(
options: CatalogOptions = {},
): ChannelPluginCatalogEntry[] {