Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
import type { Foreigns } from "../urbit/foreigns.js";
import { asRecord, formatChangesDate, formatErrorMessage } from "./utils.js";
export async function fetchGroupChanges(
api: { scry: (path: string) => Promise<unknown> },
runtime: RuntimeEnv,
daysAgo = 5,
) {
try {
const changeDate = formatChangesDate(daysAgo);
runtime.log?.(`[tlon] Fetching group changes since ${daysAgo} days ago (${changeDate})...`);
const changes = await api.scry(`/groups-ui/v5/changes/${changeDate}.json`);
if (changes) {
runtime.log?.("[tlon] Successfully fetched changes data");
return changes;
}
return null;
} catch (error: unknown) {
runtime.log?.(
`[tlon] Failed to fetch changes (falling back to full init): ${formatErrorMessage(error)}`,
);
return null;
}
}
export interface InitData {
channels: string[];
foreigns: Foreigns | null;
}
/**
* Fetch groups-ui init data, returning channels and foreigns.
* This is a single scry that provides both channel discovery and pending invites.
*/
export async function fetchInitData(
api: { scry: (path: string) => Promise<unknown> },
runtime: RuntimeEnv,
): Promise<InitData> {
try {
runtime.log?.("[tlon] Fetching groups-ui init data...");
const initData = asRecord(await api.scry("/groups-ui/v6/init.json"));
const channels: string[] = [];
const groups = asRecord(initData?.groups);
if (groups) {
for (const groupData of Object.values(groups)) {
const typedGroupData = asRecord(groupData);
const groupChannels = asRecord(typedGroupData?.channels);
if (groupChannels) {
for (const channelNest of Object.keys(groupChannels)) {
if (channelNest.startsWith("chat/")) {
channels.push(channelNest);
}
}
}
}
}
if (channels.length > 0) {
runtime.log?.(`[tlon] Auto-discovered ${channels.length} chat channel(s)`);
} else {
runtime.log?.("[tlon] No chat channels found via auto-discovery");
}
const foreignsValue = asRecord(initData?.foreigns);
const foreigns = foreignsValue ? (foreignsValue as Foreigns) : null;
if (foreigns) {
const pendingCount = Object.values(foreigns).filter((f) =>
f.invites?.some((i) => i.valid),
).length;
if (pendingCount > 0) {
runtime.log?.(`[tlon] Found ${pendingCount} pending group invite(s)`);
}
}
return { channels, foreigns };
} catch (error: unknown) {
runtime.log?.(`[tlon] Init data fetch failed: ${formatErrorMessage(error)}`);
return { channels: [], foreigns: null };
}
}
export async function fetchAllChannels(
api: { scry: (path: string) => Promise<unknown> },
runtime: RuntimeEnv,
): Promise<string[]> {
const { channels } = await fetchInitData(api, runtime);
return channels;
}
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland