fix: resolve lint errors (unused vars, imports, formatting)

- Prefix unused test variables with underscore
- Remove unused piSpec import and idleMs class member
- Fix import ordering and code formatting
This commit is contained in:
Eng. Juan Combetto
2025-12-05 00:36:41 +09:00
committed by Peter Steinberger
parent 518af0ef24
commit 4a35bcec21
9 changed files with 144 additions and 126 deletions

View File

@@ -16,8 +16,8 @@ import {
formatToolAggregate,
shortenMeta,
shortenPath,
TOOL_RESULT_FLUSH_COUNT,
TOOL_RESULT_DEBOUNCE_MS,
TOOL_RESULT_FLUSH_COUNT,
} from "./tool-meta.js";
import type { ReplyPayload } from "./types.js";
@@ -345,7 +345,11 @@ export async function runCommandReply(
// Tau (pi agent) needs --continue to reload prior messages when resuming.
// Without it, pi starts from a blank state even though we pass the session file path.
if (agentKind === "pi" && !isNewSession && !sessionArgList.includes("--continue")) {
if (
agentKind === "pi" &&
!isNewSession &&
!sessionArgList.includes("--continue")
) {
sessionArgList.push("--continue");
}
@@ -433,10 +437,7 @@ export async function runCommandReply(
}
};
let lastStreamedAssistant: string | undefined;
const streamAssistant = (msg?: {
role?: string;
content?: unknown[];
}) => {
const streamAssistant = (msg?: { role?: string; content?: unknown[] }) => {
if (!onPartialReply || msg?.role !== "assistant") return;
const textBlocks = Array.isArray(msg.content)
? (msg.content as Array<{ type?: string; text?: string }>)
@@ -478,68 +479,37 @@ export async function runCommandReply(
cwd: reply.cwd,
prompt: body,
timeoutMs,
onEvent:
onPartialReply
? (line: string) => {
try {
const ev = JSON.parse(line) as {
type?: string;
message?: {
role?: string;
content?: unknown[];
details?: Record<string, unknown>;
arguments?: Record<string, unknown>;
toolCallId?: string;
tool_call_id?: string;
toolName?: string;
name?: string;
};
onEvent: onPartialReply
? (line: string) => {
try {
const ev = JSON.parse(line) as {
type?: string;
message?: {
role?: string;
content?: unknown[];
details?: Record<string, unknown>;
arguments?: Record<string, unknown>;
toolCallId?: string;
tool_call_id?: string;
toolName?: string;
args?: Record<string, unknown>;
name?: string;
};
// Capture metadata as soon as the tool starts (from args).
if (ev.type === "tool_execution_start") {
const toolName = ev.toolName;
const meta = inferToolMeta({
toolName,
name: ev.toolName,
arguments: ev.args,
});
if (ev.toolCallId) {
toolMetaById.set(ev.toolCallId, meta);
}
if (meta) {
if (pendingToolName && toolName && toolName !== pendingToolName) {
flushPendingTool();
}
if (!pendingToolName) pendingToolName = toolName;
pendingMetas.push(meta);
if (
TOOL_RESULT_FLUSH_COUNT > 0 &&
pendingMetas.length >= TOOL_RESULT_FLUSH_COUNT
) {
flushPendingTool();
} else {
if (pendingTimer) clearTimeout(pendingTimer);
pendingTimer = setTimeout(
flushPendingTool,
TOOL_RESULT_DEBOUNCE_MS,
);
}
}
toolCallId?: string;
toolName?: string;
args?: Record<string, unknown>;
};
// Capture metadata as soon as the tool starts (from args).
if (ev.type === "tool_execution_start") {
const toolName = ev.toolName;
const meta = inferToolMeta({
toolName,
name: ev.toolName,
arguments: ev.args,
});
if (ev.toolCallId) {
toolMetaById.set(ev.toolCallId, meta);
}
if (
(ev.type === "message" || ev.type === "message_end") &&
ev.message?.role === "tool_result" &&
Array.isArray(ev.message.content)
) {
const toolName = inferToolName(ev.message);
const toolCallId =
ev.message.toolCallId ?? ev.message.tool_call_id;
const meta =
inferToolMeta(ev.message) ??
(toolCallId ? toolMetaById.get(toolCallId) : undefined);
if (meta) {
if (
pendingToolName &&
toolName &&
@@ -548,32 +518,66 @@ export async function runCommandReply(
flushPendingTool();
}
if (!pendingToolName) pendingToolName = toolName;
if (meta) pendingMetas.push(meta);
pendingMetas.push(meta);
if (
TOOL_RESULT_FLUSH_COUNT > 0 &&
pendingMetas.length >= TOOL_RESULT_FLUSH_COUNT
) {
flushPendingTool();
return;
} else {
if (pendingTimer) clearTimeout(pendingTimer);
pendingTimer = setTimeout(
flushPendingTool,
TOOL_RESULT_DEBOUNCE_MS,
);
}
if (pendingTimer) clearTimeout(pendingTimer);
pendingTimer = setTimeout(
flushPendingTool,
TOOL_RESULT_DEBOUNCE_MS,
);
}
if (
ev.type === "message_end" ||
ev.type === "message_update" ||
ev.type === "message"
) {
streamAssistant(ev.message);
}
} catch {
// ignore malformed lines
}
if (
(ev.type === "message" || ev.type === "message_end") &&
ev.message?.role === "tool_result" &&
Array.isArray(ev.message.content)
) {
const toolName = inferToolName(ev.message);
const toolCallId =
ev.message.toolCallId ?? ev.message.tool_call_id;
const meta =
inferToolMeta(ev.message) ??
(toolCallId ? toolMetaById.get(toolCallId) : undefined);
if (
pendingToolName &&
toolName &&
toolName !== pendingToolName
) {
flushPendingTool();
}
if (!pendingToolName) pendingToolName = toolName;
if (meta) pendingMetas.push(meta);
if (
TOOL_RESULT_FLUSH_COUNT > 0 &&
pendingMetas.length >= TOOL_RESULT_FLUSH_COUNT
) {
flushPendingTool();
return;
}
if (pendingTimer) clearTimeout(pendingTimer);
pendingTimer = setTimeout(
flushPendingTool,
TOOL_RESULT_DEBOUNCE_MS,
);
}
if (
ev.type === "message_end" ||
ev.type === "message_update" ||
ev.type === "message"
) {
streamAssistant(ev.message);
}
} catch {
// ignore malformed lines
}
: undefined,
}
: undefined,
});
flushPendingTool();
return rpcResult;
@@ -610,10 +614,10 @@ export async function runCommandReply(
type ReplyItem = { text: string; media?: string[] };
const replyItems: ReplyItem[] = [];
const includeToolResultsInline =
const includeToolResultsInline =
verboseLevel === "on" && !onPartialReply && parsedToolResults.length > 0;
if (includeToolResultsInline) {
if (includeToolResultsInline) {
const aggregated = parsedToolResults.reduce<
{ toolName?: string; metas: string[]; previews: string[] }[]
>((acc, tr) => {
@@ -647,7 +651,8 @@ export async function runCommandReply(
const formatPreview = (texts: string[]) => {
const joined = texts.join(" ").trim();
if (!joined) return "";
const clipped = joined.length > 120 ? `${joined.slice(0, 117)}` : joined;
const clipped =
joined.length > 120 ? `${joined.slice(0, 117)}` : joined;
return ` — “${clipped}`;
};
@@ -662,7 +667,7 @@ export async function runCommandReply(
media: mediaFound?.length ? mediaFound : undefined,
});
}
}
}
for (const t of parsedTexts) {
const { text: cleanedText, mediaUrls: mediaFound } =

View File

@@ -11,12 +11,12 @@ import {
saveSessionStore,
} from "../config/sessions.js";
import { info, isVerbose, logVerbose } from "../globals.js";
import { triggerWarelayRestart } from "../infra/restart.js";
import { ensureMediaHosted } from "../media/host.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import type { TwilioRequester } from "../twilio/types.js";
import { sendTypingIndicator } from "../twilio/typing.js";
import { triggerWarelayRestart } from "../infra/restart.js";
import { chunkText } from "./chunk.js";
import { runCommandReply } from "./command-reply.js";
import {
@@ -358,7 +358,13 @@ export async function getReplyFromConfig(
await saveSessionStore(storePath, sessionStore);
}
// If verbose directive is also present, persist it too.
if (hasVerboseDirective && inlineVerbose && sessionEntry && sessionStore && sessionKey) {
if (
hasVerboseDirective &&
inlineVerbose &&
sessionEntry &&
sessionStore &&
sessionKey
) {
if (inlineVerbose === "off") {
delete sessionEntry.verboseLevel;
} else {
@@ -431,9 +437,7 @@ export async function getReplyFromConfig(
const to = (ctx.To ?? "").replace(/^whatsapp:/, "");
const isSamePhone = from && to && from === to;
const abortKey = sessionKey ?? (from || undefined) ?? (to || undefined);
const rawBodyNormalized = (
sessionCtx.BodyStripped ?? sessionCtx.Body ?? ""
)
const rawBodyNormalized = (sessionCtx.BodyStripped ?? sessionCtx.Body ?? "")
.trim()
.toLowerCase();

View File

@@ -18,8 +18,8 @@ describe("sessions", () => {
});
it("keeps group chats distinct", () => {
expect(
deriveSessionKey("per-sender", { From: "12345-678@g.us" }),
).toBe("group:12345-678@g.us");
expect(deriveSessionKey("per-sender", { From: "12345-678@g.us" })).toBe(
"group:12345-678@g.us",
);
});
});

View File

@@ -678,7 +678,7 @@ describe("config and templating", () => {
},
};
const ack = await index.getReplyFromConfig(
const _ack = await index.getReplyFromConfig(
{ Body: "/v:on", From: "+1", To: "+2" },
undefined,
cfg,
@@ -979,7 +979,7 @@ describe("config and templating", () => {
const batchBody =
"[Current message - respond to this]\nPeter: @Clawd UK /thinking medium /v on";
const ack = await index.getReplyFromConfig(
const _ack = await index.getReplyFromConfig(
{
Body: batchBody,
From: "group:456@g.us",
@@ -1000,7 +1000,7 @@ describe("config and templating", () => {
const persisted = JSON.parse(
await fs.promises.readFile(storePath, "utf-8"),
) as Record<string, { thinkingLevel?: string; verboseLevel?: string }>;
const entry = Object.values(persisted)[0] as {
const _entry = Object.values(persisted)[0] as {
thinkingLevel?: string;
verboseLevel?: string;
};

View File

@@ -7,7 +7,6 @@ import {
autoReplyIfConfigured,
getReplyFromConfig,
} from "./auto-reply/reply.js";
import { enableConsoleCapture } from "./logging.js";
import { applyTemplate } from "./auto-reply/templating.js";
import { createDefaultDeps, monitorTwilio } from "./cli/deps.js";
import { promptYesNo } from "./cli/prompt.js";
@@ -33,6 +32,7 @@ import {
ensureTailscaledInstalled,
getTailnetHostname,
} from "./infra/tailscale.js";
import { enableConsoleCapture } from "./logging.js";
import { runCommandWithTimeout, runExec } from "./process/exec.js";
import { monitorWebProvider } from "./provider-web.js";
import { createClient } from "./twilio/client.js";

View File

@@ -4,7 +4,8 @@ const DEFAULT_LAUNCHD_LABEL = "com.steipete.warelay";
export function triggerWarelayRestart(): void {
const label = process.env.WARELAY_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL;
const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
const uid =
typeof process.getuid === "function" ? process.getuid() : undefined;
const target = uid !== undefined ? `gui/${uid}/${label}` : label;
const child = spawn("launchctl", ["kickstart", "-k", target], {
detached: true,

View File

@@ -1,8 +1,6 @@
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
import readline from "node:readline";
import { piSpec } from "../agents/pi.js";
type TauRpcOptions = {
argv: string[];
cwd?: string;
@@ -24,7 +22,6 @@ class TauRpcClient {
private stderr = "";
private buffer: string[] = [];
private idleTimer: NodeJS.Timeout | null = null;
private readonly idleMs = 120;
private pending:
| {
resolve: (r: TauRpcResult) => void;
@@ -58,7 +55,12 @@ class TauRpcClient {
const out = this.buffer.join("\n");
clearTimeout(pending.timer);
// Treat process exit as completion with whatever output we captured.
pending.resolve({ stdout: out, stderr: this.stderr, code: code ?? 0, signal });
pending.resolve({
stdout: out,
stderr: this.stderr,
code: code ?? 0,
signal,
});
}
this.dispose();
});

View File

@@ -84,13 +84,15 @@ function buildMentionConfig(cfg: ReturnType<typeof loadConfig>): MentionConfig {
const gc = cfg.inbound?.groupChat;
const requireMention = gc?.requireMention !== false; // default true
const mentionRegexes =
gc?.mentionPatterns?.map((p) => {
try {
return new RegExp(p, "i");
} catch {
return null;
}
}).filter((r): r is RegExp => Boolean(r)) ?? [];
gc?.mentionPatterns
?.map((p) => {
try {
return new RegExp(p, "i");
} catch {
return null;
}
})
.filter((r): r is RegExp => Boolean(r)) ?? [];
return { requireMention, mentionRegexes };
}
@@ -728,7 +730,7 @@ export async function monitorWebProvider(
const senderLabel =
latest.senderName && latest.senderE164
? `${latest.senderName} (${latest.senderE164})`
: latest.senderName ?? latest.senderE164 ?? "Unknown";
: (latest.senderName ?? latest.senderE164 ?? "Unknown");
combinedBody = `${combinedBody}\\n[from: ${senderLabel}]`;
// Clear stored history after using it
groupHistories.set(conversationId, []);
@@ -834,7 +836,7 @@ export async function monitorWebProvider(
const fromDisplay =
latest.chatType === "group"
? conversationId
: latest.from ?? "unknown";
: (latest.from ?? "unknown");
if (isVerbose()) {
console.log(
success(
@@ -850,24 +852,26 @@ export async function monitorWebProvider(
}
} catch (err) {
console.error(
danger(`Failed sending web auto-reply to ${latest.from ?? conversationId}: ${String(err)}`),
danger(
`Failed sending web auto-reply to ${latest.from ?? conversationId}: ${String(err)}`,
),
);
}
}
};
};
const enqueueBatch = async (msg: WebInboundMsg) => {
const key = msg.conversationId ?? msg.from;
const bucket = pendingBatches.get(key) ?? { messages: [] };
bucket.messages.push(msg);
pendingBatches.set(key, bucket);
if (getQueueSize() === 0) {
await processBatch(key);
} else {
bucket.timer =
bucket.timer ?? setTimeout(() => void processBatch(key), 150);
}
};
const enqueueBatch = async (msg: WebInboundMsg) => {
const key = msg.conversationId ?? msg.from;
const bucket = pendingBatches.get(key) ?? { messages: [] };
bucket.messages.push(msg);
pendingBatches.set(key, bucket);
if (getQueueSize() === 0) {
await processBatch(key);
} else {
bucket.timer =
bucket.timer ?? setTimeout(() => void processBatch(key), 150);
}
};
const listener = await (listenerFactory ?? monitorWebInbox)({
verbose,

View File

@@ -339,7 +339,9 @@ export async function monitorWebInbox(options: {
} as const;
}
function unwrapMessage(message: proto.IMessage | undefined): proto.IMessage | undefined {
function unwrapMessage(
message: proto.IMessage | undefined,
): proto.IMessage | undefined {
if (!message) return undefined;
if (message.ephemeralMessage?.message) {
return unwrapMessage(message.ephemeralMessage.message as proto.IMessage);