style: fix extension lint violations

This commit is contained in:
Peter Steinberger
2026-04-06 14:45:04 +01:00
parent e8141716b4
commit af62a2c2e4
380 changed files with 2067 additions and 1501 deletions

View File

@@ -3,7 +3,6 @@ import type { ChannelAccountSnapshot } from "openclaw/plugin-sdk/channel-contrac
import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-send-result";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
import { createLoggerBackedRuntime } from "openclaw/plugin-sdk/runtime";
import { monitorTlonProvider } from "./monitor/index.js";
import { tlonSetupWizard } from "./setup-surface.js";
import {

View File

@@ -2,7 +2,6 @@ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
import { createHybridChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
import { createChatChannelPlugin, type ChannelPlugin } from "openclaw/plugin-sdk/channel-core";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
import {
@@ -12,20 +11,14 @@ import {
import { tlonChannelConfigSchema } from "./config-schema.js";
import { tlonDoctor } from "./doctor.js";
import { resolveTlonOutboundSessionRoute } from "./session-route.js";
import {
applyTlonSetupConfig,
createTlonSetupWizardBase,
resolveTlonSetupConfigured,
tlonSetupAdapter,
} from "./setup-core.js";
import { createTlonSetupWizardBase, tlonSetupAdapter } from "./setup-core.js";
import {
formatTargetHint,
normalizeShip,
parseTlonTarget,
resolveTlonOutboundTarget,
} from "./targets.js";
import { resolveTlonAccount, listTlonAccountIds } from "./types.js";
import { validateUrbitBaseUrl } from "./urbit/base-url.js";
import { listTlonAccountIds, resolveTlonAccount } from "./types.js";
const TLON_CHANNEL_ID = "tlon" as const;

View File

@@ -17,7 +17,7 @@ export function createTlonCitationResolver(params: { api: TlonScryApi; runtime:
const scryPath = `/channels/v4/${cite.nest}/posts/post/${cite.postId}.json`;
runtime.log?.(`[tlon] Fetching cited post: ${scryPath}`);
const data: any = await api.scry(scryPath);
const data: unknown = await api.scry(scryPath);
if (data?.essay?.content) {
return extractMessageText(data.essay.content) || null;
}

View File

@@ -16,7 +16,7 @@ export async function fetchGroupChanges(
return changes;
}
return null;
} catch (error: any) {
} catch (error: unknown) {
runtime.log?.(
`[tlon] Failed to fetch changes (falling back to full init): ${error?.message ?? String(error)}`,
);
@@ -39,11 +39,11 @@ export async function fetchInitData(
): Promise<InitData> {
try {
runtime.log?.("[tlon] Fetching groups-ui init data...");
const initData = (await api.scry("/groups-ui/v6/init.json")) as any;
const initData = await api.scry("/groups-ui/v6/init.json");
const channels: string[] = [];
if (initData?.groups) {
for (const groupData of Object.values(initData.groups as Record<string, any>)) {
for (const groupData of Object.values(initData.groups as Record<string, unknown>)) {
if (groupData && typeof groupData === "object" && groupData.channels) {
for (const channelNest of Object.keys(groupData.channels)) {
if (channelNest.startsWith("chat/")) {
@@ -71,7 +71,7 @@ export async function fetchInitData(
}
return { channels, foreigns };
} catch (error: any) {
} catch (error: unknown) {
runtime.log?.(`[tlon] Init data fetch failed: ${error?.message ?? String(error)}`);
return { channels: [], foreigns: null };
}

View File

@@ -54,12 +54,12 @@ export async function fetchChannelHistory(
const scryPath = `/channels/v4/${channelNest}/posts/newest/${count}/outline.json`;
runtime?.log?.(`[tlon] Fetching history: ${scryPath}`);
const data: any = await api.scry(scryPath);
const data: unknown = await api.scry(scryPath);
if (!data) {
return [];
}
let posts: any[] = [];
let posts: unknown[] = [];
if (Array.isArray(data)) {
posts = data;
} else if (data.posts && typeof data.posts === "object") {
@@ -84,7 +84,7 @@ export async function fetchChannelHistory(
runtime?.log?.(`[tlon] Extracted ${messages.length} messages from history`);
return messages;
} catch (error: any) {
} catch (error: unknown) {
runtime?.log?.(`[tlon] Error fetching channel history: ${error?.message ?? String(error)}`);
return [];
}
@@ -129,13 +129,13 @@ export async function fetchThreadHistory(
const scryPath = `/channels/v4/${channelNest}/posts/post/id/${formattedParentId}/replies/newest/${count}.json`;
runtime?.log?.(`[tlon] Fetching thread history: ${scryPath}`);
const data: any = await api.scry(scryPath);
const data: unknown = await api.scry(scryPath);
if (!data) {
runtime?.log?.(`[tlon] No thread history data returned`);
return [];
}
let replies: any[] = [];
let replies: unknown[] = [];
if (Array.isArray(data)) {
replies = data;
} else if (data.replies && Array.isArray(data.replies)) {
@@ -161,18 +161,18 @@ export async function fetchThreadHistory(
runtime?.log?.(`[tlon] Extracted ${messages.length} thread replies from history`);
return messages;
} catch (error: any) {
} catch (error: unknown) {
runtime?.log?.(`[tlon] Error fetching thread history: ${error?.message ?? String(error)}`);
// Fall back to trying alternate path structure
try {
const altPath = `/channels/v4/${channelNest}/posts/post/id/${formatUd(parentId)}.json`;
runtime?.log?.(`[tlon] Trying alternate path: ${altPath}`);
const data: any = await api.scry(altPath);
const data: unknown = await api.scry(altPath);
if (data?.seal?.meta?.replyCount > 0 && data?.replies) {
const replies = Array.isArray(data.replies) ? data.replies : Object.values(data.replies);
const messages = replies
.map((reply: any) => ({
.map((reply: unknown) => ({
author: reply.memo?.author || "unknown",
content: extractMessageText(reply.memo?.content || []),
timestamp: reply.memo?.sent || Date.now(),
@@ -183,7 +183,7 @@ export async function fetchThreadHistory(
runtime?.log?.(`[tlon] Extracted ${messages.length} replies from post data`);
return messages;
}
} catch (altError: any) {
} catch (altError: unknown) {
runtime?.log?.(`[tlon] Alternate path also failed: ${altError?.message ?? String(altError)}`);
}
return [];

View File

@@ -1,4 +1,4 @@
import type { RuntimeEnv, ReplyPayload, OpenClawConfig } from "../../api.js";
import type { ReplyPayload, RuntimeEnv } from "../../api.js";
import { createLoggerBackedRuntime } from "../../api.js";
import { getTlonRuntime } from "../runtime.js";
import { createSettingsManager, type TlonSettingsStore } from "../settings.js";
@@ -6,21 +6,20 @@ import { normalizeShip, parseChannelNest } from "../targets.js";
import { resolveTlonAccount } from "../types.js";
import { authenticate } from "../urbit/auth.js";
import { ssrfPolicyFromDangerouslyAllowPrivateNetwork } from "../urbit/context.js";
import type { Foreigns, DmInvite } from "../urbit/foreigns.js";
import type { DmInvite, Foreigns } from "../urbit/foreigns.js";
import { sendDm, sendGroupMessage } from "../urbit/send.js";
import { UrbitSSEClient } from "../urbit/sse-client.js";
import { createTlonApprovalRuntime } from "./approval-runtime.js";
import {
type PendingApproval,
type AdminCommand,
createPendingApproval,
isApprovalResponse,
isAdminCommand,
isApprovalResponse,
type PendingApproval,
} from "./approval.js";
import { resolveChannelAuthorization } from "./authorization.js";
import { createTlonCitationResolver } from "./cites.js";
import { fetchAllChannels, fetchInitData } from "./discovery.js";
import { cacheMessage, getChannelHistory, fetchThreadHistory } from "./history.js";
import { cacheMessage, fetchThreadHistory, getChannelHistory } from "./history.js";
import { downloadMessageImages } from "./media.js";
import { createProcessedMessageTracker } from "./processed-messages.js";
import {
@@ -31,15 +30,13 @@ import {
} from "./settings-helpers.js";
import {
extractMessageText,
extractCites,
formatModelName,
isBotMentioned,
stripBotMention,
isDmAllowed,
isGroupInviteAllowed,
isSummarizationRequest,
resolveAuthorizedMessageText,
type ParsedCite,
stripBotMention,
} from "./utils.js";
export type MonitorTlonOpts = {
@@ -50,7 +47,7 @@ export type MonitorTlonOpts = {
export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<void> {
const core = getTlonRuntime();
const cfg = core.config.loadConfig() as OpenClawConfig;
const cfg = core.config.loadConfig();
if (cfg.channels?.tlon?.enabled === false) {
return;
}
@@ -90,7 +87,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
try {
runtime.log?.(`[tlon] Attempting authentication to ${accountUrl}...`);
return await authenticate(accountUrl, accountCode, { ssrfPolicy });
} catch (error: any) {
} catch (error: unknown) {
runtime.error?.(
`[tlon] Failed to authenticate (attempt ${attempt}): ${error?.message ?? String(error)}`,
);
@@ -171,7 +168,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
runtime.log?.(`[tlon] Bot nickname: ${botNickname}`);
}
}
} catch (error: any) {
} catch (error: unknown) {
runtime.log?.(`[tlon] Could not fetch nickname: ${error?.message ?? String(error)}`);
}
@@ -238,7 +235,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
groupChannels = initData.channels;
}
initForeigns = initData.foreigns;
} catch (error: any) {
} catch (error: unknown) {
runtime.error?.(`[tlon] Auto-discovery failed: ${error?.message ?? String(error)}`);
}
}
@@ -305,8 +302,8 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
senderShip,
isGroup,
channelNest,
hostShip,
channelName,
_hostShip,
_channelName,
timestamp,
parentId,
isThreadReply,
@@ -323,7 +320,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
if (attachments.length > 0) {
runtime.log?.(`[tlon] Downloaded ${attachments.length} image(s) from message`);
}
} catch (error: any) {
} catch (error: unknown) {
runtime.log?.(`[tlon] Failed to download images: ${error?.message ?? String(error)}`);
}
}
@@ -346,7 +343,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
`[tlon] Added thread context (${threadHistory.length} replies) to message`,
);
}
} catch (error: any) {
} catch (error: unknown) {
runtime?.log?.(`[tlon] Could not fetch thread context: ${error?.message ?? String(error)}`);
// Continue without thread context - not critical
}
@@ -393,7 +390,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
"2. Key decisions or conclusions\n" +
"3. Action items if any\n" +
"4. Notable participants";
} catch (error: any) {
} catch (error: unknown) {
const errorMsg = `Sorry, I encountered an error while fetching the channel history: ${error?.message ?? String(error)}`;
if (isGroup && groupChannel) {
const parsed = parseChannelNest(groupChannel);
@@ -569,10 +566,6 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
extPayload.model ||
extRoute.model ||
(typeof defaultModel === "string" ? defaultModel : defaultModel?.primary);
extPayload.metadata?.model ||
extPayload.model ||
extRoute.model ||
(typeof defaultModel === "string" ? defaultModel : defaultModel?.primary);
replyText = `${replyText}\n\n_[Generated by ${formatModelName(modelInfo)}]_`;
}
@@ -613,7 +606,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
const _watchedDMs = new Set<string>();
const refreshWatchedChannels = async (): Promise<number> => {
const discoveredChannels = await fetchAllChannels(api!, runtime);
const discoveredChannels = await fetchAllChannels(api, runtime);
let newCount = 0;
for (const channelNest of discoveredChannels) {
if (!watchedChannels.has(channelNest)) {
@@ -625,15 +618,15 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
};
const { resolveAllCites } = createTlonCitationResolver({
api: { scry: (path) => api!.scry(path) },
api: { scry: (path) => api.scry(path) },
runtime,
});
const { queueApprovalRequest, handleApprovalResponse, handleAdminCommand } =
createTlonApprovalRuntime({
api: {
poke: (payload) => api!.poke(payload),
scry: (path) => api!.scry(path),
poke: (payload) => api.poke(payload),
scry: (path) => api.scry(path),
},
runtime,
botShipName,

View File

@@ -130,7 +130,9 @@ export function isBotMentioned(
* "~bot-ship /status" → "/status"
*/
export function stripBotMention(messageText: string, botShipName: string): string {
if (!messageText || !botShipName) return messageText;
if (!messageText || !botShipName) {
return messageText;
}
return messageText.replace(normalizeShip(botShipName), "").trim();
}

View File

@@ -533,7 +533,9 @@ describe("Security: Sender Role Identification", () => {
// Helper to compute sender role (mirrors logic in monitor/index.ts)
function getSenderRole(senderShip: string, ownerShip: string | null): "owner" | "user" {
if (!ownerShip) return "user";
if (!ownerShip) {
return "user";
}
return normalizeShip(senderShip) === normalizeShip(ownerShip) ? "owner" : "user";
}

View File

@@ -208,7 +208,7 @@ function parseSettingsEvent(event: unknown): { key: string; value: unknown } | n
return null;
}
return {
key: String(put["entry-key"] ?? ""),
key: typeof put["entry-key"] === "string" ? put["entry-key"] : "",
value: put.value,
};
}
@@ -220,7 +220,7 @@ function parseSettingsEvent(event: unknown): { key: string; value: unknown } | n
return null;
}
return {
key: String(del["entry-key"] ?? ""),
key: typeof del["entry-key"] === "string" ? del["entry-key"] : "",
value: undefined,
};
}

View File

@@ -1,19 +1,16 @@
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
import {
applyTlonSetupConfig,
createTlonSetupWizardBase,
resolveTlonSetupConfigured,
resolveTlonSetupStatusLines,
type TlonSetupInput,
tlonSetupAdapter,
} from "./setup-core.js";
import { normalizeShip } from "./targets.js";
import { listTlonAccountIds, resolveTlonAccount, type TlonResolvedAccount } from "./types.js";
import { resolveTlonAccount, type TlonResolvedAccount } from "./types.js";
import { isBlockedUrbitHostname, validateUrbitBaseUrl } from "./urbit/base-url.js";
const channel = "tlon" as const;
const _channel = "tlon" as const;
function isConfigured(account: TlonResolvedAccount): boolean {
function _isConfigured(account: TlonResolvedAccount): boolean {
return Boolean(account.ship && account.url && account.code);
}

View File

@@ -105,9 +105,9 @@ export function resolveTlonAccount(
}
const merged = resolveMergedTlonAccountConfig(cfg, resolvedAccountId);
const ship = (merged.ship ?? null) as string | null;
const url = (merged.url ?? null) as string | null;
const code = (merged.code ?? null) as string | null;
const ship = merged.ship ?? null;
const url = merged.url ?? null;
const code = merged.code ?? null;
const dangerouslyAllowPrivateNetwork = isPrivateNetworkOptInEnabled(merged)
? true
: typeof merged.network?.dangerouslyAllowPrivateNetwork === "boolean"
@@ -116,20 +116,20 @@ export function resolveTlonAccount(
typeof merged.allowPrivateNetwork === "boolean"
? merged.allowPrivateNetwork
: null;
const groupChannels = (merged.groupChannels ?? []) as string[];
const dmAllowlist = (merged.dmAllowlist ?? []) as string[];
const groupInviteAllowlist = (merged.groupInviteAllowlist ?? []) as string[];
const autoDiscoverChannels = (merged.autoDiscoverChannels ?? null) as boolean | null;
const showModelSignature = (merged.showModelSignature ?? null) as boolean | null;
const autoAcceptDmInvites = (merged.autoAcceptDmInvites ?? null) as boolean | null;
const autoAcceptGroupInvites = (merged.autoAcceptGroupInvites ?? null) as boolean | null;
const ownerShip = (merged.ownerShip ?? null) as string | null;
const defaultAuthorizedShips = (merged.defaultAuthorizedShips ?? []) as string[];
const groupChannels = merged.groupChannels ?? [];
const dmAllowlist = merged.dmAllowlist ?? [];
const groupInviteAllowlist = merged.groupInviteAllowlist ?? [];
const autoDiscoverChannels = merged.autoDiscoverChannels ?? null;
const showModelSignature = merged.showModelSignature ?? null;
const autoAcceptDmInvites = merged.autoAcceptDmInvites ?? null;
const autoAcceptGroupInvites = merged.autoAcceptGroupInvites ?? null;
const ownerShip = merged.ownerShip ?? null;
const defaultAuthorizedShips = merged.defaultAuthorizedShips ?? [];
const configured = Boolean(ship && url && code);
return {
accountId: resolvedAccountId,
name: (merged.name ?? null) as string | null,
name: merged.name ?? null,
enabled: merged.enabled !== false,
configured,
ship,

View File

@@ -5,7 +5,9 @@ describe("validateUrbitBaseUrl", () => {
it("adds https:// when scheme is missing and strips path/query fragments", () => {
const result = validateUrbitBaseUrl("example.com/foo?bar=baz");
expect(result.ok).toBe(true);
if (!result.ok) return;
if (!result.ok) {
return;
}
expect(result.baseUrl).toBe("https://example.com");
expect(result.hostname).toBe("example.com");
});
@@ -13,21 +15,27 @@ describe("validateUrbitBaseUrl", () => {
it("rejects non-http schemes", () => {
const result = validateUrbitBaseUrl("file:///etc/passwd");
expect(result.ok).toBe(false);
if (result.ok) return;
if (result.ok) {
return;
}
expect(result.error).toContain("http:// or https://");
});
it("rejects embedded credentials", () => {
const result = validateUrbitBaseUrl("https://user:pass@example.com");
expect(result.ok).toBe(false);
if (result.ok) return;
if (result.ok) {
return;
}
expect(result.error).toContain("credentials");
});
it("normalizes a trailing dot in the hostname for origin construction", () => {
const result = validateUrbitBaseUrl("https://example.com./foo");
expect(result.ok).toBe(true);
if (!result.ok) return;
if (!result.ok) {
return;
}
expect(result.baseUrl).toBe("https://example.com");
expect(result.hostname).toBe("example.com");
});
@@ -35,7 +43,9 @@ describe("validateUrbitBaseUrl", () => {
it("preserves port in the normalized origin", () => {
const result = validateUrbitBaseUrl("http://example.com:8080/~/login");
expect(result.ok).toBe(true);
if (!result.ok) return;
if (!result.ok) {
return;
}
expect(result.baseUrl).toBe("http://example.com:8080");
});
});

View File

@@ -242,7 +242,7 @@ export function markdownToStory(markdown: string): Story {
const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
if (headerMatch) {
const level = headerMatch[1].length as 1 | 2 | 3 | 4 | 5 | 6;
const tag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
const tag = `h${level}`;
story.push({
block: {
header: {

View File

@@ -54,7 +54,7 @@ export async function uploadImageFromUrl(imageUrl: string): Promise<string> {
await release();
}
} catch (err) {
console.warn(`[tlon] Failed to upload image, using original URL: ${err}`);
console.warn(`[tlon] Failed to upload image, using original URL: ${String(err)}`);
return imageUrl;
}
}