chore: Enable "curly" rule to avoid single-statement if confusion/errors.

This commit is contained in:
cpojer
2026-01-31 16:19:20 +09:00
parent 009b16fab8
commit 5ceff756e1
1266 changed files with 27871 additions and 9393 deletions

View File

@@ -6,7 +6,9 @@ const getGroupSurfaces = () => new Set<string>([...listDeliverableMessageChannel
function normalizeGroupLabel(raw?: string) {
const trimmed = raw?.trim().toLowerCase() ?? "";
if (!trimmed) return "";
if (!trimmed) {
return "";
}
const dashed = trimmed.replace(/\s+/g, "-");
const cleaned = dashed.replace(/[^a-z0-9#@._+-]+/g, "-");
return cleaned.replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "");
@@ -14,8 +16,12 @@ function normalizeGroupLabel(raw?: string) {
function shortenGroupId(value?: string) {
const trimmed = value?.trim() ?? "";
if (!trimmed) return "";
if (trimmed.length <= 14) return trimmed;
if (!trimmed) {
return "";
}
if (trimmed.length <= 14) {
return trimmed;
}
return `${trimmed.slice(0, 6)}...${trimmed.slice(-4)}`;
}
@@ -63,7 +69,9 @@ export function resolveGroupSessionKey(ctx: MsgContext): GroupKeyResolution | nu
from.includes(":group:") ||
from.includes(":channel:") ||
isWhatsAppGroupId;
if (!looksLikeGroup) return null;
if (!looksLikeGroup) {
return null;
}
const providerHint = ctx.Provider?.trim().toLowerCase();
@@ -74,7 +82,9 @@ export function resolveGroupSessionKey(ctx: MsgContext): GroupKeyResolution | nu
const provider = headIsSurface
? head
: (providerHint ?? (isWhatsAppGroupId ? "whatsapp" : undefined));
if (!provider) return null;
if (!provider) {
return null;
}
const second = parts[1]?.trim().toLowerCase();
const secondIsKind = second === "group" || second === "channel";
@@ -89,7 +99,9 @@ export function resolveGroupSessionKey(ctx: MsgContext): GroupKeyResolution | nu
: parts.slice(1).join(":")
: from;
const finalId = id.trim().toLowerCase();
if (!finalId) return null;
if (!finalId) {
return null;
}
return {
key: `${provider}:${kind}:${finalId}`,

View File

@@ -12,7 +12,9 @@ export function resolveMainSessionKey(cfg?: {
session?: { scope?: SessionScope; mainKey?: string };
agents?: { list?: Array<{ id?: string; default?: boolean }> };
}): string {
if (cfg?.session?.scope === "global") return "global";
if (cfg?.session?.scope === "global") {
return "global";
}
const agents = cfg?.agents?.list ?? [];
const defaultAgentId =
agents.find((agent) => agent?.default)?.id ?? agents[0]?.id ?? DEFAULT_AGENT_ID;
@@ -40,7 +42,9 @@ export function resolveExplicitAgentSessionKey(params: {
agentId?: string | null;
}): string | undefined {
const agentId = params.agentId?.trim();
if (!agentId) return undefined;
if (!agentId) {
return undefined;
}
return resolveAgentMainSessionKey({ cfg: params.cfg, agentId });
}
@@ -50,7 +54,9 @@ export function canonicalizeMainSessionAlias(params: {
sessionKey: string;
}): string {
const raw = params.sessionKey.trim();
if (!raw) return raw;
if (!raw) {
return raw;
}
const agentId = normalizeAgentId(params.agentId);
const mainKey = normalizeMainKey(params.cfg?.session?.mainKey);
@@ -63,7 +69,11 @@ export function canonicalizeMainSessionAlias(params: {
const isMainAlias =
raw === "main" || raw === mainKey || raw === agentMainSessionKey || raw === agentMainAliasKey;
if (params.cfg?.session?.scope === "global" && isMainAlias) return "global";
if (isMainAlias) return agentMainSessionKey;
if (params.cfg?.session?.scope === "global" && isMainAlias) {
return "global";
}
if (isMainAlias) {
return agentMainSessionKey;
}
return raw;
}

View File

@@ -11,16 +11,34 @@ const mergeOrigin = (
existing: SessionOrigin | undefined,
next: SessionOrigin | undefined,
): SessionOrigin | undefined => {
if (!existing && !next) return undefined;
if (!existing && !next) {
return undefined;
}
const merged: SessionOrigin = existing ? { ...existing } : {};
if (next?.label) merged.label = next.label;
if (next?.provider) merged.provider = next.provider;
if (next?.surface) merged.surface = next.surface;
if (next?.chatType) merged.chatType = next.chatType;
if (next?.from) merged.from = next.from;
if (next?.to) merged.to = next.to;
if (next?.accountId) merged.accountId = next.accountId;
if (next?.threadId != null && next.threadId !== "") merged.threadId = next.threadId;
if (next?.label) {
merged.label = next.label;
}
if (next?.provider) {
merged.provider = next.provider;
}
if (next?.surface) {
merged.surface = next.surface;
}
if (next?.chatType) {
merged.chatType = next.chatType;
}
if (next?.from) {
merged.from = next.from;
}
if (next?.to) {
merged.to = next.to;
}
if (next?.accountId) {
merged.accountId = next.accountId;
}
if (next?.threadId != null && next.threadId !== "") {
merged.threadId = next.threadId;
}
return Object.keys(merged).length > 0 ? merged : undefined;
};
@@ -40,20 +58,38 @@ export function deriveSessionOrigin(ctx: MsgContext): SessionOrigin | undefined
const threadId = ctx.MessageThreadId ?? undefined;
const origin: SessionOrigin = {};
if (label) origin.label = label;
if (provider) origin.provider = provider;
if (surface) origin.surface = surface;
if (chatType) origin.chatType = chatType;
if (from) origin.from = from;
if (to) origin.to = to;
if (accountId) origin.accountId = accountId;
if (threadId != null && threadId !== "") origin.threadId = threadId;
if (label) {
origin.label = label;
}
if (provider) {
origin.provider = provider;
}
if (surface) {
origin.surface = surface;
}
if (chatType) {
origin.chatType = chatType;
}
if (from) {
origin.from = from;
}
if (to) {
origin.to = to;
}
if (accountId) {
origin.accountId = accountId;
}
if (threadId != null && threadId !== "") {
origin.threadId = threadId;
}
return Object.keys(origin).length > 0 ? origin : undefined;
}
export function snapshotSessionOrigin(entry?: SessionEntry): SessionOrigin | undefined {
if (!entry?.origin) return undefined;
if (!entry?.origin) {
return undefined;
}
return { ...entry.origin };
}
@@ -64,7 +100,9 @@ export function deriveGroupSessionPatch(params: {
groupResolution?: GroupKeyResolution | null;
}): Partial<SessionEntry> | null {
const resolution = params.groupResolution ?? resolveGroupSessionKey(params.ctx);
if (!resolution?.channel) return null;
if (!resolution?.channel) {
return null;
}
const channel = resolution.channel;
const subject = params.ctx.GroupSubject?.trim();
@@ -87,9 +125,15 @@ export function deriveGroupSessionPatch(params: {
channel,
groupId: resolution.id,
};
if (nextSubject) patch.subject = nextSubject;
if (nextGroupChannel) patch.groupChannel = nextGroupChannel;
if (space) patch.space = space;
if (nextSubject) {
patch.subject = nextSubject;
}
if (nextGroupChannel) {
patch.groupChannel = nextGroupChannel;
}
if (space) {
patch.space = space;
}
const displayName = buildGroupDisplayName({
provider: channel,
@@ -99,7 +143,9 @@ export function deriveGroupSessionPatch(params: {
id: resolution.id,
key: params.sessionKey,
});
if (displayName) patch.displayName = displayName;
if (displayName) {
patch.displayName = displayName;
}
return patch;
}
@@ -112,11 +158,15 @@ export function deriveSessionMetaPatch(params: {
}): Partial<SessionEntry> | null {
const groupPatch = deriveGroupSessionPatch(params);
const origin = deriveSessionOrigin(params.ctx);
if (!groupPatch && !origin) return null;
if (!groupPatch && !origin) {
return null;
}
const patch: Partial<SessionEntry> = groupPatch ? { ...groupPatch } : {};
const mergedOrigin = mergeOrigin(params.existing?.origin, origin);
if (mergedOrigin) patch.origin = mergedOrigin;
if (mergedOrigin) {
patch.origin = mergedOrigin;
}
return Object.keys(patch).length > 0 ? patch : null;
}

View File

@@ -60,7 +60,9 @@ export function resolveSessionFilePath(
export function resolveStorePath(store?: string, opts?: { agentId?: string }) {
const agentId = normalizeAgentId(opts?.agentId ?? DEFAULT_AGENT_ID);
if (!store) return resolveDefaultSessionStorePath(agentId);
if (!store) {
return resolveDefaultSessionStorePath(agentId);
}
if (store.includes("{agentId}")) {
const expanded = store.replaceAll("{agentId}", agentId);
if (expanded.startsWith("~")) {
@@ -68,6 +70,8 @@ export function resolveStorePath(store?: string, opts?: { agentId?: string }) {
}
return path.resolve(expanded);
}
if (store.startsWith("~")) return path.resolve(store.replace(/^~(?=$|[\\/])/, os.homedir()));
if (store.startsWith("~")) {
return path.resolve(store.replace(/^~(?=$|[\\/])/, os.homedir()));
}
return path.resolve(store);
}

View File

@@ -25,7 +25,9 @@ const GROUP_SESSION_MARKERS = [":group:", ":channel:"];
export function isThreadSessionKey(sessionKey?: string | null): boolean {
const normalized = (sessionKey ?? "").toLowerCase();
if (!normalized) return false;
if (!normalized) {
return false;
}
return THREAD_SESSION_MARKERS.some((marker) => normalized.includes(marker));
}
@@ -34,10 +36,16 @@ export function resolveSessionResetType(params: {
isGroup?: boolean;
isThread?: boolean;
}): SessionResetType {
if (params.isThread || isThreadSessionKey(params.sessionKey)) return "thread";
if (params.isGroup) return "group";
if (params.isThread || isThreadSessionKey(params.sessionKey)) {
return "thread";
}
if (params.isGroup) {
return "group";
}
const normalized = (params.sessionKey ?? "").toLowerCase();
if (GROUP_SESSION_MARKERS.some((marker) => normalized.includes(marker))) return "group";
if (GROUP_SESSION_MARKERS.some((marker) => normalized.includes(marker))) {
return "group";
}
return "dm";
}
@@ -48,10 +56,18 @@ export function resolveThreadFlag(params: {
threadStarterBody?: string | null;
parentSessionKey?: string | null;
}): boolean {
if (params.messageThreadId != null) return true;
if (params.threadLabel?.trim()) return true;
if (params.threadStarterBody?.trim()) return true;
if (params.parentSessionKey?.trim()) return true;
if (params.messageThreadId != null) {
return true;
}
if (params.threadLabel?.trim()) {
return true;
}
if (params.threadStarterBody?.trim()) {
return true;
}
if (params.parentSessionKey?.trim()) {
return true;
}
return isThreadSessionKey(params.sessionKey);
}
@@ -102,11 +118,15 @@ export function resolveChannelResetConfig(params: {
channel?: string | null;
}): SessionResetConfig | undefined {
const resetByChannel = params.sessionCfg?.resetByChannel;
if (!resetByChannel) return undefined;
if (!resetByChannel) {
return undefined;
}
const normalized = normalizeMessageChannel(params.channel);
const fallback = params.channel?.trim().toLowerCase();
const key = normalized ?? fallback;
if (!key) return undefined;
if (!key) {
return undefined;
}
return resetByChannel[key] ?? resetByChannel[key.toLowerCase()];
}
@@ -133,10 +153,18 @@ export function evaluateSessionFreshness(params: {
}
function normalizeResetAtHour(value: number | undefined): number {
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_RESET_AT_HOUR;
if (typeof value !== "number" || !Number.isFinite(value)) {
return DEFAULT_RESET_AT_HOUR;
}
const normalized = Math.floor(value);
if (!Number.isFinite(normalized)) return DEFAULT_RESET_AT_HOUR;
if (normalized < 0) return 0;
if (normalized > 23) return 23;
if (!Number.isFinite(normalized)) {
return DEFAULT_RESET_AT_HOUR;
}
if (normalized < 0) {
return 0;
}
if (normalized > 23) {
return 23;
}
return normalized;
}

View File

@@ -10,9 +10,13 @@ import type { SessionScope } from "./types.js";
// Decide which session bucket to use (per-sender vs global).
export function deriveSessionKey(scope: SessionScope, ctx: MsgContext) {
if (scope === "global") return "global";
if (scope === "global") {
return "global";
}
const resolvedGroup = resolveGroupSessionKey(ctx);
if (resolvedGroup) return resolvedGroup.key;
if (resolvedGroup) {
return resolvedGroup.key;
}
const from = ctx.From ? normalizeE164(ctx.From) : "";
return from || "unknown";
}
@@ -23,15 +27,21 @@ export function deriveSessionKey(scope: SessionScope, ctx: MsgContext) {
*/
export function resolveSessionKey(scope: SessionScope, ctx: MsgContext, mainKey?: string) {
const explicit = ctx.SessionKey?.trim();
if (explicit) return explicit.toLowerCase();
if (explicit) {
return explicit.toLowerCase();
}
const raw = deriveSessionKey(scope, ctx);
if (scope === "global") return raw;
if (scope === "global") {
return raw;
}
const canonicalMainKey = normalizeMainKey(mainKey);
const canonical = buildAgentMainSessionKey({
agentId: DEFAULT_AGENT_ID,
mainKey: canonicalMainKey,
});
const isGroup = raw.includes(":group:") || raw.includes(":channel:");
if (!isGroup) return canonical;
if (!isGroup) {
return canonical;
}
return `agent:${DEFAULT_AGENT_ID}:${raw}`;
}

View File

@@ -74,7 +74,9 @@ function normalizeSessionEntryDelivery(entry: SessionEntry): SessionEntry {
entry.lastTo === normalized.lastTo &&
entry.lastAccountId === normalized.lastAccountId &&
entry.lastThreadId === normalized.lastThreadId;
if (sameDelivery && sameLast) return entry;
if (sameDelivery && sameLast) {
return entry;
}
return {
...entry,
deliveryContext: nextDelivery,
@@ -87,7 +89,9 @@ function normalizeSessionEntryDelivery(entry: SessionEntry): SessionEntry {
function normalizeSessionStore(store: Record<string, SessionEntry>): void {
for (const [key, entry] of Object.entries(store)) {
if (!entry) continue;
if (!entry) {
continue;
}
const normalized = normalizeSessionEntryDelivery(entry);
if (normalized !== entry) {
store[key] = normalized;
@@ -136,7 +140,9 @@ export function loadSessionStore(
// Best-effort migration: message provider → channel naming.
for (const entry of Object.values(store)) {
if (!entry || typeof entry !== "object") continue;
if (!entry || typeof entry !== "object") {
continue;
}
const rec = entry as unknown as Record<string, unknown>;
if (typeof rec.channel !== "string" && typeof rec.provider === "string") {
rec.channel = rec.provider;
@@ -203,7 +209,9 @@ async function saveSessionStoreUnlocked(
err && typeof err === "object" && "code" in err
? String((err as { code?: unknown }).code)
: null;
if (code === "ENOENT") return;
if (code === "ENOENT") {
return;
}
throw err;
}
return;
@@ -233,7 +241,9 @@ async function saveSessionStoreUnlocked(
err2 && typeof err2 === "object" && "code" in err2
? String((err2 as { code?: unknown }).code)
: null;
if (code2 === "ENOENT") return;
if (code2 === "ENOENT") {
return;
}
throw err2;
}
return;
@@ -313,7 +323,9 @@ async function withSessionStoreLock<T>(
await new Promise((r) => setTimeout(r, pollIntervalMs));
continue;
}
if (code !== "EEXIST") throw err;
if (code !== "EEXIST") {
throw err;
}
const now = Date.now();
if (now - startedAt > timeoutMs) {
@@ -352,9 +364,13 @@ export async function updateSessionStoreEntry(params: {
return await withSessionStoreLock(storePath, async () => {
const store = loadSessionStore(storePath);
const existing = store[sessionKey];
if (!existing) return null;
if (!existing) {
return null;
}
const patch = await update(existing);
if (!patch) return existing;
if (!patch) {
return existing;
}
const next = mergeSessionEntry(existing, patch);
store[sessionKey] = next;
await saveSessionStoreUnlocked(storePath, store);
@@ -379,8 +395,12 @@ export async function recordSessionMetaFromInbound(params: {
existing,
groupResolution: params.groupResolution,
});
if (!patch) return existing ?? null;
if (!existing && !createIfMissing) return null;
if (!patch) {
return existing ?? null;
}
if (!existing && !createIfMissing) {
return null;
}
const next = mergeSessionEntry(existing, patch);
store[sessionKey] = next;
return next;

View File

@@ -15,12 +15,16 @@ function stripQuery(value: string): string {
function extractFileNameFromMediaUrl(value: string): string | null {
const trimmed = value.trim();
if (!trimmed) return null;
if (!trimmed) {
return null;
}
const cleaned = stripQuery(trimmed);
try {
const parsed = new URL(cleaned);
const base = path.basename(parsed.pathname);
if (!base) return null;
if (!base) {
return null;
}
try {
return decodeURIComponent(base);
} catch {
@@ -28,7 +32,9 @@ function extractFileNameFromMediaUrl(value: string): string | null {
}
} catch {
const base = path.basename(cleaned);
if (!base || base === "/" || base === ".") return null;
if (!base || base === "/" || base === ".") {
return null;
}
return base;
}
}
@@ -42,7 +48,9 @@ export function resolveMirroredTranscriptText(params: {
const names = mediaUrls
.map((url) => extractFileNameFromMediaUrl(url))
.filter((name): name is string => Boolean(name && name.trim()));
if (names.length > 0) return names.join(", ");
if (names.length > 0) {
return names.join(", ");
}
return "media";
}
@@ -55,7 +63,9 @@ async function ensureSessionHeader(params: {
sessionFile: string;
sessionId: string;
}): Promise<void> {
if (fs.existsSync(params.sessionFile)) return;
if (fs.existsSync(params.sessionFile)) {
return;
}
await fs.promises.mkdir(path.dirname(params.sessionFile), { recursive: true });
const header = {
type: "session",
@@ -76,18 +86,24 @@ export async function appendAssistantMessageToSessionTranscript(params: {
storePath?: string;
}): Promise<{ ok: true; sessionFile: string } | { ok: false; reason: string }> {
const sessionKey = params.sessionKey.trim();
if (!sessionKey) return { ok: false, reason: "missing sessionKey" };
if (!sessionKey) {
return { ok: false, reason: "missing sessionKey" };
}
const mirrorText = resolveMirroredTranscriptText({
text: params.text,
mediaUrls: params.mediaUrls,
});
if (!mirrorText) return { ok: false, reason: "empty text" };
if (!mirrorText) {
return { ok: false, reason: "empty text" };
}
const storePath = params.storePath ?? resolveDefaultSessionStorePath(params.agentId);
const store = loadSessionStore(storePath, { skipCache: true });
const entry = store[sessionKey] as SessionEntry | undefined;
if (!entry?.sessionId) return { ok: false, reason: `unknown sessionKey: ${sessionKey}` };
if (!entry?.sessionId) {
return { ok: false, reason: `unknown sessionKey: ${sessionKey}` };
}
const sessionFile =
entry.sessionFile?.trim() || resolveSessionTranscriptPath(entry.sessionId, params.agentId);

View File

@@ -102,7 +102,9 @@ export function mergeSessionEntry(
): SessionEntry {
const sessionId = patch.sessionId ?? existing?.sessionId ?? crypto.randomUUID();
const updatedAt = Math.max(existing?.updatedAt ?? 0, patch.updatedAt ?? 0, Date.now());
if (!existing) return { ...patch, sessionId, updatedAt };
if (!existing) {
return { ...patch, sessionId, updatedAt };
}
return { ...existing, ...patch, sessionId, updatedAt };
}