chore: migrate to oxlint and oxfmt

Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
This commit is contained in:
Peter Steinberger
2026-01-14 14:31:43 +00:00
parent 912ebffc63
commit c379191f80
1480 changed files with 28608 additions and 43547 deletions

View File

@@ -10,10 +10,7 @@ import {
import { resolveMessageChannelSelection } from "../../infra/outbound/channel-selection.js";
import type { OutboundChannel } from "../../infra/outbound/targets.js";
import { resolveOutboundTarget } from "../../infra/outbound/targets.js";
import {
INTERNAL_MESSAGE_CHANNEL,
normalizeMessageChannel,
} from "../../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL, normalizeMessageChannel } from "../../utils/message-channel.js";
export async function resolveDeliveryTarget(
cfg: ClawdbotConfig,
@@ -29,14 +26,10 @@ export async function resolveDeliveryTarget(
mode: "explicit" | "implicit";
error?: Error;
}> {
const requestedRaw =
typeof jobPayload.channel === "string" ? jobPayload.channel : "last";
const requestedChannelHint =
normalizeMessageChannel(requestedRaw) ?? requestedRaw;
const requestedRaw = typeof jobPayload.channel === "string" ? jobPayload.channel : "last";
const requestedChannelHint = normalizeMessageChannel(requestedRaw) ?? requestedRaw;
const explicitTo =
typeof jobPayload.to === "string" && jobPayload.to.trim()
? jobPayload.to.trim()
: undefined;
typeof jobPayload.to === "string" && jobPayload.to.trim() ? jobPayload.to.trim() : undefined;
const sessionCfg = cfg.session;
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });

View File

@@ -17,9 +17,7 @@ export function pickSummaryFromOutput(text: string | undefined) {
return clean.length > limit ? `${truncateUtf16Safe(clean, limit)}` : clean;
}
export function pickSummaryFromPayloads(
payloads: Array<{ text?: string | undefined }>,
) {
export function pickSummaryFromPayloads(payloads: Array<{ text?: string | undefined }>) {
for (let i = payloads.length - 1; i >= 0; i--) {
const summary = pickSummaryFromOutput(payloads[i]?.text);
if (summary) return summary;
@@ -31,15 +29,11 @@ export function pickSummaryFromPayloads(
* Check if all payloads are just heartbeat ack responses (HEARTBEAT_OK).
* Returns true if delivery should be skipped because there's no real content.
*/
export function isHeartbeatOnlyResponse(
payloads: DeliveryPayload[],
ackMaxChars: number,
) {
export function isHeartbeatOnlyResponse(payloads: DeliveryPayload[], ackMaxChars: number) {
if (payloads.length === 0) return true;
return payloads.every((payload) => {
// If there's media, we should deliver regardless of text content.
const hasMedia =
(payload.mediaUrls?.length ?? 0) > 0 || Boolean(payload.mediaUrl);
const hasMedia = (payload.mediaUrls?.length ?? 0) > 0 || Boolean(payload.mediaUrl);
if (hasMedia) return false;
// Use heartbeat mode to check if text is just HEARTBEAT_OK or short ack.
const result = stripHeartbeatToken(payload.text, {
@@ -50,10 +44,7 @@ export function isHeartbeatOnlyResponse(
});
}
export function resolveHeartbeatAckMaxChars(agentCfg?: {
heartbeat?: { ackMaxChars?: number };
}) {
const raw =
agentCfg?.heartbeat?.ackMaxChars ?? DEFAULT_HEARTBEAT_ACK_MAX_CHARS;
export function resolveHeartbeatAckMaxChars(agentCfg?: { heartbeat?: { ackMaxChars?: number } }) {
const raw = agentCfg?.heartbeat?.ackMaxChars ?? DEFAULT_HEARTBEAT_ACK_MAX_CHARS;
return Math.max(0, raw);
}

View File

@@ -7,11 +7,7 @@ import {
import { runCliAgent } from "../../agents/cli-runner.js";
import { getCliSessionId, setCliSessionId } from "../../agents/cli-session.js";
import { lookupContextTokens } from "../../agents/context.js";
import {
DEFAULT_CONTEXT_TOKENS,
DEFAULT_MODEL,
DEFAULT_PROVIDER,
} from "../../agents/defaults.js";
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../agents/defaults.js";
import { loadModelCatalog } from "../../agents/model-catalog.js";
import { runWithModelFallback } from "../../agents/model-fallback.js";
import {
@@ -34,17 +30,11 @@ import {
} from "../../auto-reply/thinking.js";
import type { CliDeps } from "../../cli/deps.js";
import type { ClawdbotConfig } from "../../config/config.js";
import {
resolveSessionTranscriptPath,
saveSessionStore,
} from "../../config/sessions.js";
import { resolveSessionTranscriptPath, saveSessionStore } from "../../config/sessions.js";
import type { AgentDefaultsConfig } from "../../config/types.js";
import { registerAgentRunContext } from "../../infra/agent-events.js";
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
import {
buildAgentMainSessionKey,
normalizeAgentId,
} from "../../routing/session-key.js";
import { buildAgentMainSessionKey, normalizeAgentId } from "../../routing/session-key.js";
import type { CronJob } from "../types.js";
import { resolveDeliveryTarget } from "./delivery-target.js";
import {
@@ -77,17 +67,12 @@ export async function runCronIsolatedAgentTurn(params: {
: typeof params.job.agentId === "string" && params.job.agentId.trim()
? params.job.agentId
: undefined;
const normalizedRequested = requestedAgentId
? normalizeAgentId(requestedAgentId)
: undefined;
const normalizedRequested = requestedAgentId ? normalizeAgentId(requestedAgentId) : undefined;
const agentConfigOverride = normalizedRequested
? resolveAgentConfig(params.cfg, normalizedRequested)
: undefined;
const { model: overrideModel, ...agentOverrideRest } =
agentConfigOverride ?? {};
const agentId = agentConfigOverride
? (normalizedRequested ?? defaultAgentId)
: defaultAgentId;
const { model: overrideModel, ...agentOverrideRest } = agentConfigOverride ?? {};
const agentId = agentConfigOverride ? (normalizedRequested ?? defaultAgentId) : defaultAgentId;
const agentCfg: AgentDefaultsConfig = Object.assign(
{},
params.cfg.agents?.defaults,
@@ -103,9 +88,7 @@ export async function runCronIsolatedAgentTurn(params: {
agents: Object.assign({}, params.cfg.agents, { defaults: agentCfg }),
};
const baseSessionKey = (
params.sessionKey?.trim() || `cron:${params.job.id}`
).trim();
const baseSessionKey = (params.sessionKey?.trim() || `cron:${params.job.id}`).trim();
const agentSessionKey = buildAgentMainSessionKey({
agentId,
mainKey: baseSessionKey,
@@ -154,9 +137,7 @@ export async function runCronIsolatedAgentTurn(params: {
}
}
const modelOverrideRaw =
params.job.payload.kind === "agentTurn"
? params.job.payload.model
: undefined;
params.job.payload.kind === "agentTurn" ? params.job.payload.model : undefined;
if (modelOverrideRaw !== undefined) {
if (typeof modelOverrideRaw !== "string") {
return { status: "error", error: "invalid model: expected string" };
@@ -188,9 +169,8 @@ export async function runCronIsolatedAgentTurn(params: {
: undefined;
const thinkOverride = normalizeThinkLevel(agentCfg?.thinkingDefault);
const jobThink = normalizeThinkLevel(
(params.job.payload.kind === "agentTurn"
? params.job.payload.thinking
: undefined) ?? undefined,
(params.job.payload.kind === "agentTurn" ? params.job.payload.thinking : undefined) ??
undefined,
);
let thinkLevel = jobThink ?? hooksGmailThinking ?? thinkOverride;
if (!thinkLevel) {
@@ -202,47 +182,29 @@ export async function runCronIsolatedAgentTurn(params: {
});
}
if (thinkLevel === "xhigh" && !supportsXHighThinking(provider, model)) {
throw new Error(
`Thinking level "xhigh" is only supported for ${formatXHighModelHint()}.`,
);
throw new Error(`Thinking level "xhigh" is only supported for ${formatXHighModelHint()}.`);
}
const timeoutMs = resolveAgentTimeoutMs({
cfg: cfgWithAgentDefaults,
overrideSeconds:
params.job.payload.kind === "agentTurn"
? params.job.payload.timeoutSeconds
: undefined,
params.job.payload.kind === "agentTurn" ? params.job.payload.timeoutSeconds : undefined,
});
const delivery =
params.job.payload.kind === "agentTurn" &&
params.job.payload.deliver === true;
const delivery = params.job.payload.kind === "agentTurn" && params.job.payload.deliver === true;
const bestEffortDeliver =
params.job.payload.kind === "agentTurn" &&
params.job.payload.bestEffortDeliver === true;
params.job.payload.kind === "agentTurn" && params.job.payload.bestEffortDeliver === true;
const resolvedDelivery = await resolveDeliveryTarget(
cfgWithAgentDefaults,
agentId,
{
channel:
params.job.payload.kind === "agentTurn"
? (params.job.payload.channel ?? "last")
: "last",
to:
params.job.payload.kind === "agentTurn"
? params.job.payload.to
: undefined,
},
);
const resolvedDelivery = await resolveDeliveryTarget(cfgWithAgentDefaults, agentId, {
channel:
params.job.payload.kind === "agentTurn" ? (params.job.payload.channel ?? "last") : "last",
to: params.job.payload.kind === "agentTurn" ? params.job.payload.to : undefined,
});
const base =
`[cron:${params.job.id} ${params.job.name}] ${params.message}`.trim();
const base = `[cron:${params.job.id} ${params.job.name}] ${params.message}`.trim();
const commandBody = base;
const needsSkillsSnapshot =
cronSession.isNewSession || !cronSession.sessionEntry.skillsSnapshot;
const needsSkillsSnapshot = cronSession.isNewSession || !cronSession.sessionEntry.skillsSnapshot;
const skillsSnapshot = needsSkillsSnapshot
? buildWorkspaceSkillSnapshot(workspaceDir, {
config: cfgWithAgentDefaults,
@@ -267,10 +229,7 @@ export async function runCronIsolatedAgentTurn(params: {
let fallbackProvider = provider;
let fallbackModel = model;
try {
const sessionFile = resolveSessionTranscriptPath(
cronSession.sessionEntry.sessionId,
agentId,
);
const sessionFile = resolveSessionTranscriptPath(cronSession.sessionEntry.sessionId, agentId);
const resolvedVerboseLevel =
(cronSession.sessionEntry.verboseLevel as "on" | "off" | undefined) ??
(agentCfg?.verboseDefault as "on" | "off" | undefined);
@@ -283,16 +242,10 @@ export async function runCronIsolatedAgentTurn(params: {
cfg: cfgWithAgentDefaults,
provider,
model,
fallbacksOverride: resolveAgentModelFallbacksOverride(
params.cfg,
agentId,
),
fallbacksOverride: resolveAgentModelFallbacksOverride(params.cfg, agentId),
run: (providerOverride, modelOverride) => {
if (isCliProvider(providerOverride, cfgWithAgentDefaults)) {
const cliSessionId = getCliSessionId(
cronSession.sessionEntry,
providerOverride,
);
const cliSessionId = getCliSessionId(cronSession.sessionEntry, providerOverride);
return runCliAgent({
sessionId: cronSession.sessionEntry.sessionId,
sessionKey: agentSessionKey,
@@ -340,12 +293,9 @@ export async function runCronIsolatedAgentTurn(params: {
{
const usage = runResult.meta.agentMeta?.usage;
const modelUsed = runResult.meta.agentMeta?.model ?? fallbackModel ?? model;
const providerUsed =
runResult.meta.agentMeta?.provider ?? fallbackProvider ?? provider;
const providerUsed = runResult.meta.agentMeta?.provider ?? fallbackProvider ?? provider;
const contextTokens =
agentCfg?.contextTokens ??
lookupContextTokens(modelUsed) ??
DEFAULT_CONTEXT_TOKENS;
agentCfg?.contextTokens ?? lookupContextTokens(modelUsed) ?? DEFAULT_CONTEXT_TOKENS;
cronSession.sessionEntry.modelProvider = providerUsed;
cronSession.sessionEntry.model = modelUsed;
@@ -359,8 +309,7 @@ export async function runCronIsolatedAgentTurn(params: {
if (hasNonzeroUsage(usage)) {
const input = usage.input ?? 0;
const output = usage.output ?? 0;
const promptTokens =
input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
const promptTokens = input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
cronSession.sessionEntry.inputTokens = input;
cronSession.sessionEntry.outputTokens = output;
cronSession.sessionEntry.totalTokens =
@@ -370,19 +319,16 @@ export async function runCronIsolatedAgentTurn(params: {
await saveSessionStore(cronSession.storePath, cronSession.store);
}
const firstText = payloads[0]?.text ?? "";
const summary =
pickSummaryFromPayloads(payloads) ?? pickSummaryFromOutput(firstText);
const summary = pickSummaryFromPayloads(payloads) ?? pickSummaryFromOutput(firstText);
// Skip delivery for heartbeat-only responses (HEARTBEAT_OK with no real content).
const ackMaxChars = resolveHeartbeatAckMaxChars(agentCfg);
const skipHeartbeatDelivery =
delivery && isHeartbeatOnlyResponse(payloads, ackMaxChars);
const skipHeartbeatDelivery = delivery && isHeartbeatOnlyResponse(payloads, ackMaxChars);
if (delivery && !skipHeartbeatDelivery) {
if (!resolvedDelivery.to) {
const reason =
resolvedDelivery.error?.message ??
"Cron delivery requires a recipient (--to).";
resolvedDelivery.error?.message ?? "Cron delivery requires a recipient (--to).";
if (!bestEffortDeliver) {
return {
status: "error",

View File

@@ -15,10 +15,7 @@ export function resolveCronSession(params: {
agentId: string;
}) {
const sessionCfg = params.cfg.session;
const idleMinutes = Math.max(
sessionCfg?.idleMinutes ?? DEFAULT_IDLE_MINUTES,
1,
);
const idleMinutes = Math.max(sessionCfg?.idleMinutes ?? DEFAULT_IDLE_MINUTES, 1);
const idleMs = idleMinutes * 60_000;
const storePath = resolveStorePath(sessionCfg?.store, {
agentId: params.agentId,