chore(gate): fix lint and formatting

This commit is contained in:
Peter Steinberger
2026-01-18 06:01:09 +00:00
parent d1c85cb32d
commit d4bd387e0e
15 changed files with 244 additions and 231 deletions

View File

@@ -4,10 +4,7 @@ import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { import { resolveBootstrapContextForRun, resolveBootstrapFilesForRun } from "./bootstrap-files.js";
resolveBootstrapContextForRun,
resolveBootstrapFilesForRun,
} from "./bootstrap-files.js";
import { import {
clearInternalHooks, clearInternalHooks,
registerInternalHook, registerInternalHook,

View File

@@ -146,78 +146,82 @@ const readSessionMessages = async (sessionFile: string) => {
}; };
describe("runEmbeddedPiAgent", () => { describe("runEmbeddedPiAgent", () => {
it("appends new user + assistant after existing transcript entries", { timeout: 90_000 }, async () => { it(
const { SessionManager } = await import("@mariozechner/pi-coding-agent"); "appends new user + assistant after existing transcript entries",
{ timeout: 90_000 },
async () => {
const { SessionManager } = await import("@mariozechner/pi-coding-agent");
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-agent-")); const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-agent-"));
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-workspace-")); const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-workspace-"));
const sessionFile = path.join(workspaceDir, "session.jsonl"); const sessionFile = path.join(workspaceDir, "session.jsonl");
const sessionManager = SessionManager.open(sessionFile); const sessionManager = SessionManager.open(sessionFile);
sessionManager.appendMessage({ sessionManager.appendMessage({
role: "user", role: "user",
content: [{ type: "text", text: "seed user" }], content: [{ type: "text", text: "seed user" }],
}); });
sessionManager.appendMessage({ sessionManager.appendMessage({
role: "assistant", role: "assistant",
content: [{ type: "text", text: "seed assistant" }], content: [{ type: "text", text: "seed assistant" }],
stopReason: "stop", stopReason: "stop",
api: "openai-responses", api: "openai-responses",
provider: "openai", provider: "openai",
model: "mock-1", model: "mock-1",
usage: { usage: {
input: 1, input: 1,
output: 1, output: 1,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 2,
cost: {
input: 0,
output: 0,
cacheRead: 0, cacheRead: 0,
cacheWrite: 0, cacheWrite: 0,
total: 0, totalTokens: 2,
cost: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
total: 0,
},
}, },
}, timestamp: Date.now(),
timestamp: Date.now(), });
});
const cfg = makeOpenAiConfig(["mock-1"]); const cfg = makeOpenAiConfig(["mock-1"]);
await ensureModels(cfg, agentDir); await ensureModels(cfg, agentDir);
await runEmbeddedPiAgent({ await runEmbeddedPiAgent({
sessionId: "session:test", sessionId: "session:test",
sessionKey: testSessionKey, sessionKey: testSessionKey,
sessionFile, sessionFile,
workspaceDir, workspaceDir,
config: cfg, config: cfg,
prompt: "hello", prompt: "hello",
provider: "openai", provider: "openai",
model: "mock-1", model: "mock-1",
timeoutMs: 5_000, timeoutMs: 5_000,
agentDir, agentDir,
enqueue: immediateEnqueue, enqueue: immediateEnqueue,
}); });
const messages = await readSessionMessages(sessionFile); const messages = await readSessionMessages(sessionFile);
const seedUserIndex = messages.findIndex( const seedUserIndex = messages.findIndex(
(message) => message?.role === "user" && textFromContent(message.content) === "seed user", (message) => message?.role === "user" && textFromContent(message.content) === "seed user",
); );
const seedAssistantIndex = messages.findIndex( const seedAssistantIndex = messages.findIndex(
(message) => (message) =>
message?.role === "assistant" && textFromContent(message.content) === "seed assistant", message?.role === "assistant" && textFromContent(message.content) === "seed assistant",
); );
const newUserIndex = messages.findIndex( const newUserIndex = messages.findIndex(
(message) => message?.role === "user" && textFromContent(message.content) === "hello", (message) => message?.role === "user" && textFromContent(message.content) === "hello",
); );
const newAssistantIndex = messages.findIndex( const newAssistantIndex = messages.findIndex(
(message, index) => index > newUserIndex && message?.role === "assistant", (message, index) => index > newUserIndex && message?.role === "assistant",
); );
expect(seedUserIndex).toBeGreaterThanOrEqual(0); expect(seedUserIndex).toBeGreaterThanOrEqual(0);
expect(seedAssistantIndex).toBeGreaterThan(seedUserIndex); expect(seedAssistantIndex).toBeGreaterThan(seedUserIndex);
expect(newUserIndex).toBeGreaterThan(seedAssistantIndex); expect(newUserIndex).toBeGreaterThan(seedAssistantIndex);
expect(newAssistantIndex).toBeGreaterThan(newUserIndex); expect(newAssistantIndex).toBeGreaterThan(newUserIndex);
}); },
);
it("persists multi-turn user/assistant ordering across runs", async () => { it("persists multi-turn user/assistant ordering across runs", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-agent-")); const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-agent-"));
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-workspace-")); const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-workspace-"));

View File

@@ -23,7 +23,6 @@ import { getApiKeyForModel, resolveModelAuthMode } from "../model-auth.js";
import { ensureClawdbotModelsJson } from "../models-config.js"; import { ensureClawdbotModelsJson } from "../models-config.js";
import { import {
ensureSessionHeader, ensureSessionHeader,
resolveBootstrapMaxChars,
validateAnthropicTurns, validateAnthropicTurns,
validateGeminiTurns, validateGeminiTurns,
} from "../pi-embedded-helpers.js"; } from "../pi-embedded-helpers.js";

View File

@@ -136,7 +136,7 @@ async function resolveContextReport(
bootstrapMaxChars, bootstrapMaxChars,
sandbox: { mode: sandboxRuntime.mode, sandboxed: sandboxRuntime.sandboxed }, sandbox: { mode: sandboxRuntime.mode, sandboxed: sandboxRuntime.sandboxed },
systemPrompt, systemPrompt,
bootstrapFiles: hookAdjustedBootstrapFiles, bootstrapFiles,
injectedFiles, injectedFiles,
skillsPrompt, skillsPrompt,
tools, tools,

View File

@@ -12,7 +12,8 @@ export async function checkGatewayHealth(params: {
timeoutMs?: number; timeoutMs?: number;
}) { }) {
const gatewayDetails = buildGatewayConnectionDetails({ config: params.cfg }); const gatewayDetails = buildGatewayConnectionDetails({ config: params.cfg });
const timeoutMs = typeof params.timeoutMs === "number" && params.timeoutMs > 0 ? params.timeoutMs : 10_000; const timeoutMs =
typeof params.timeoutMs === "number" && params.timeoutMs > 0 ? params.timeoutMs : 10_000;
let healthOk = false; let healthOk = false;
try { try {
await healthCommand({ json: false, timeoutMs }, params.runtime); await healthCommand({ json: false, timeoutMs }, params.runtime);

View File

@@ -211,161 +211,157 @@ async function connectClient(params: { url: string; token: string }) {
} }
describe("gateway (mock openai): tool calling", () => { describe("gateway (mock openai): tool calling", () => {
it( it("runs a Read tool call end-to-end via gateway agent loop", { timeout: 90_000 }, async () => {
"runs a Read tool call end-to-end via gateway agent loop", const prev = {
{ timeout: 90_000 }, home: process.env.HOME,
async () => { configPath: process.env.CLAWDBOT_CONFIG_PATH,
const prev = { token: process.env.CLAWDBOT_GATEWAY_TOKEN,
home: process.env.HOME, skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
configPath: process.env.CLAWDBOT_CONFIG_PATH, skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
token: process.env.CLAWDBOT_GATEWAY_TOKEN, skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, };
skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
};
const originalFetch = globalThis.fetch; const originalFetch = globalThis.fetch;
const openaiBaseUrl = "https://api.openai.com/v1"; const openaiBaseUrl = "https://api.openai.com/v1";
const openaiResponsesUrl = `${openaiBaseUrl}/responses`; const openaiResponsesUrl = `${openaiBaseUrl}/responses`;
const isOpenAIResponsesRequest = (url: string) => const isOpenAIResponsesRequest = (url: string) =>
url === openaiResponsesUrl || url === openaiResponsesUrl ||
url.startsWith(`${openaiResponsesUrl}/`) || url.startsWith(`${openaiResponsesUrl}/`) ||
url.startsWith(`${openaiResponsesUrl}?`); url.startsWith(`${openaiResponsesUrl}?`);
const fetchImpl = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => { const fetchImpl = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
const url = const url =
typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
if (isOpenAIResponsesRequest(url)) { if (isOpenAIResponsesRequest(url)) {
const bodyText = const bodyText =
typeof (init as { body?: unknown } | undefined)?.body !== "undefined" typeof (init as { body?: unknown } | undefined)?.body !== "undefined"
? decodeBodyText((init as { body?: unknown }).body) ? decodeBodyText((init as { body?: unknown }).body)
: input instanceof Request : input instanceof Request
? await input.clone().text() ? await input.clone().text()
: ""; : "";
const parsed = bodyText ? (JSON.parse(bodyText) as Record<string, unknown>) : {}; const parsed = bodyText ? (JSON.parse(bodyText) as Record<string, unknown>) : {};
const inputItems = Array.isArray(parsed.input) ? parsed.input : []; const inputItems = Array.isArray(parsed.input) ? parsed.input : [];
return await buildOpenAIResponsesSse({ input: inputItems }); return await buildOpenAIResponsesSse({ input: inputItems });
} }
if (url.startsWith(openaiBaseUrl)) { if (url.startsWith(openaiBaseUrl)) {
throw new Error(`unexpected OpenAI request in mock test: ${url}`); throw new Error(`unexpected OpenAI request in mock test: ${url}`);
} }
if (!originalFetch) { if (!originalFetch) {
throw new Error(`fetch is not available (url=${url})`); throw new Error(`fetch is not available (url=${url})`);
} }
return await originalFetch(input, init); return await originalFetch(input, init);
}; };
// TypeScript: Bun's fetch typing includes extra properties; keep this test portable. // TypeScript: Bun's fetch typing includes extra properties; keep this test portable.
(globalThis as unknown as { fetch: unknown }).fetch = fetchImpl; (globalThis as unknown as { fetch: unknown }).fetch = fetchImpl;
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-mock-home-")); const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-mock-home-"));
process.env.HOME = tempHome; process.env.HOME = tempHome;
process.env.CLAWDBOT_SKIP_CHANNELS = "1"; process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CRON = "1"; process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
const token = `test-${randomUUID()}`; const token = `test-${randomUUID()}`;
process.env.CLAWDBOT_GATEWAY_TOKEN = token; process.env.CLAWDBOT_GATEWAY_TOKEN = token;
const workspaceDir = path.join(tempHome, "clawd"); const workspaceDir = path.join(tempHome, "clawd");
await fs.mkdir(workspaceDir, { recursive: true }); await fs.mkdir(workspaceDir, { recursive: true });
const nonceA = randomUUID(); const nonceA = randomUUID();
const nonceB = randomUUID(); const nonceB = randomUUID();
const toolProbePath = path.join(workspaceDir, `.clawdbot-tool-probe.${nonceA}.txt`); const toolProbePath = path.join(workspaceDir, `.clawdbot-tool-probe.${nonceA}.txt`);
await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`); await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`);
const configDir = path.join(tempHome, ".clawdbot"); const configDir = path.join(tempHome, ".clawdbot");
await fs.mkdir(configDir, { recursive: true }); await fs.mkdir(configDir, { recursive: true });
const configPath = path.join(configDir, "clawdbot.json"); const configPath = path.join(configDir, "clawdbot.json");
const cfg = { const cfg = {
agents: { defaults: { workspace: workspaceDir } }, agents: { defaults: { workspace: workspaceDir } },
models: { models: {
mode: "replace", mode: "replace",
providers: { providers: {
openai: { openai: {
baseUrl: openaiBaseUrl, baseUrl: openaiBaseUrl,
apiKey: "test", apiKey: "test",
api: "openai-responses", api: "openai-responses",
models: [ models: [
{ {
id: "gpt-5.2", id: "gpt-5.2",
name: "gpt-5.2", name: "gpt-5.2",
api: "openai-responses", api: "openai-responses",
reasoning: false, reasoning: false,
input: ["text"], input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128_000, contextWindow: 128_000,
maxTokens: 4096, maxTokens: 4096,
}, },
], ],
},
}, },
}, },
gateway: { auth: { token } }, },
}; gateway: { auth: { token } },
};
await fs.writeFile(configPath, `${JSON.stringify(cfg, null, 2)}\n`); await fs.writeFile(configPath, `${JSON.stringify(cfg, null, 2)}\n`);
process.env.CLAWDBOT_CONFIG_PATH = configPath; process.env.CLAWDBOT_CONFIG_PATH = configPath;
const port = await getFreeGatewayPort(); const port = await getFreeGatewayPort();
const server = await startGatewayServer(port, { const server = await startGatewayServer(port, {
bind: "loopback", bind: "loopback",
auth: { mode: "token", token }, auth: { mode: "token", token },
controlUiEnabled: false, controlUiEnabled: false,
});
const client = await connectClient({
url: `ws://127.0.0.1:${port}`,
token,
});
try {
const sessionKey = "agent:dev:mock-openai";
await client.request<Record<string, unknown>>("sessions.patch", {
key: sessionKey,
model: "openai/gpt-5.2",
}); });
const client = await connectClient({ const runId = randomUUID();
url: `ws://127.0.0.1:${port}`, const payload = await client.request<{
token, status?: unknown;
}); result?: unknown;
}>(
"agent",
{
sessionKey,
idempotencyKey: `idem-${runId}`,
message:
`Call the read tool on "${toolProbePath}". ` +
`Then reply with exactly: ${nonceA} ${nonceB}. No extra text.`,
deliver: false,
},
{ expectFinal: true },
);
try { expect(payload?.status).toBe("ok");
const sessionKey = "agent:dev:mock-openai"; const text = extractPayloadText(payload?.result);
expect(text).toContain(nonceA);
await client.request<Record<string, unknown>>("sessions.patch", { expect(text).toContain(nonceB);
key: sessionKey, } finally {
model: "openai/gpt-5.2", client.stop();
}); await server.close({ reason: "mock openai test complete" });
await fs.rm(tempHome, { recursive: true, force: true });
const runId = randomUUID(); (globalThis as unknown as { fetch: unknown }).fetch = originalFetch;
const payload = await client.request<{ process.env.HOME = prev.home;
status?: unknown; process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
result?: unknown; process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
}>( process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
"agent", process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
{ process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
sessionKey, process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
idempotencyKey: `idem-${runId}`, }
message: });
`Call the read tool on "${toolProbePath}". ` +
`Then reply with exactly: ${nonceA} ${nonceB}. No extra text.`,
deliver: false,
},
{ expectFinal: true },
);
expect(payload?.status).toBe("ok");
const text = extractPayloadText(payload?.result);
expect(text).toContain(nonceA);
expect(text).toContain(nonceB);
} finally {
client.stop();
await server.close({ reason: "mock openai test complete" });
await fs.rm(tempHome, { recursive: true, force: true });
(globalThis as unknown as { fetch: unknown }).fetch = originalFetch;
process.env.HOME = prev.home;
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
}
},
);
}); });

View File

@@ -4,8 +4,8 @@ import { bm25RankToScore, buildFtsQuery, mergeHybridResults } from "./hybrid.js"
describe("memory hybrid helpers", () => { describe("memory hybrid helpers", () => {
it("buildFtsQuery tokenizes and AND-joins", () => { it("buildFtsQuery tokenizes and AND-joins", () => {
expect(buildFtsQuery("hello world")).toBe("\"hello\" AND \"world\""); expect(buildFtsQuery("hello world")).toBe('"hello" AND "world"');
expect(buildFtsQuery("FOO_bar baz-1")).toBe("\"FOO_bar\" AND \"baz\" AND \"1\""); expect(buildFtsQuery("FOO_bar baz-1")).toBe('"FOO_bar" AND "baz" AND "1"');
expect(buildFtsQuery(" ")).toBeNull(); expect(buildFtsQuery(" ")).toBeNull();
}); });
@@ -84,4 +84,3 @@ describe("memory hybrid helpers", () => {
expect(merged[0]?.score).toBeCloseTo(0.5 * 0.2 + 0.5 * 1.0); expect(merged[0]?.score).toBeCloseTo(0.5 * 0.2 + 0.5 * 1.0);
}); });
}); });

View File

@@ -21,9 +21,13 @@ export type HybridKeywordResult = {
}; };
export function buildFtsQuery(raw: string): string | null { export function buildFtsQuery(raw: string): string | null {
const tokens = raw.match(/[A-Za-z0-9_]+/g)?.map((t) => t.trim()).filter(Boolean) ?? []; const tokens =
raw
.match(/[A-Za-z0-9_]+/g)
?.map((t) => t.trim())
.filter(Boolean) ?? [];
if (tokens.length === 0) return null; if (tokens.length === 0) return null;
const quoted = tokens.map((t) => `"${t.replaceAll("\"", "")}"`); const quoted = tokens.map((t) => `"${t.replaceAll('"', "")}"`);
return quoted.join(" AND "); return quoted.join(" AND ");
} }
@@ -105,4 +109,3 @@ export function mergeHybridResults(params: {
return merged.sort((a, b) => b.score - a.score); return merged.sort((a, b) => b.score - a.score);
} }

View File

@@ -236,7 +236,12 @@ describe("memory index", () => {
query: { query: {
minScore: 0, minScore: 0,
maxResults: 200, maxResults: 200,
hybrid: { enabled: true, vectorWeight: 0.99, textWeight: 0.01, candidateMultiplier: 10 }, hybrid: {
enabled: true,
vectorWeight: 0.99,
textWeight: 0.01,
candidateMultiplier: 10,
},
}, },
}, },
}, },
@@ -284,7 +289,12 @@ describe("memory index", () => {
query: { query: {
minScore: 0, minScore: 0,
maxResults: 200, maxResults: 200,
hybrid: { enabled: true, vectorWeight: 0.01, textWeight: 0.99, candidateMultiplier: 10 }, hybrid: {
enabled: true,
vectorWeight: 0.01,
textWeight: 0.99,
candidateMultiplier: 10,
},
}, },
}, },
}, },

View File

@@ -3,7 +3,8 @@ import type { DatabaseSync } from "node:sqlite";
import { truncateUtf16Safe } from "../utils.js"; import { truncateUtf16Safe } from "../utils.js";
import { cosineSimilarity, parseEmbedding } from "./internal.js"; import { cosineSimilarity, parseEmbedding } from "./internal.js";
const vectorToBlob = (embedding: number[]): Buffer => Buffer.from(new Float32Array(embedding).buffer); const vectorToBlob = (embedding: number[]): Buffer =>
Buffer.from(new Float32Array(embedding).buffer);
export type SearchSource = string; export type SearchSource = string;
@@ -47,9 +48,9 @@ export async function searchVector(params: {
...params.sourceFilterVec.params, ...params.sourceFilterVec.params,
params.limit, params.limit,
) as Array<{ ) as Array<{
id: string; id: string;
path: string; path: string;
start_line: number; start_line: number;
end_line: number; end_line: number;
text: string; text: string;
source: SearchSource; source: SearchSource;

View File

@@ -92,4 +92,3 @@ function ensureColumn(
if (rows.some((row) => row.name === column)) return; if (rows.some((row) => row.name === column)) return;
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`); db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
} }

View File

@@ -156,7 +156,10 @@ async function readOpenAiBatchError(params: {
errorFileId: string; errorFileId: string;
}): Promise<string | undefined> { }): Promise<string | undefined> {
try { try {
const content = await fetchOpenAiFileContent({ openAi: params.openAi, fileId: params.errorFileId }); const content = await fetchOpenAiFileContent({
openAi: params.openAi,
fileId: params.errorFileId,
});
const lines = parseOpenAiBatchOutput(content); const lines = parseOpenAiBatchOutput(content);
const first = lines.find((line) => line.error?.message || line.response?.body?.error); const first = lines.find((line) => line.error?.message || line.response?.body?.error);
const message = const message =
@@ -357,4 +360,3 @@ export async function runOpenAiEmbeddingBatches(params: {
await runWithConcurrency(tasks, params.concurrency); await runWithConcurrency(tasks, params.concurrency);
return byCustomId; return byCustomId;
} }

View File

@@ -22,4 +22,3 @@ export async function loadSqliteVecExtension(params: {
return { ok: false, error: message }; return { ok: false, error: message };
} }
} }

View File

@@ -11,7 +11,10 @@ import { dispatchReplyWithBufferedBlockDispatcher } from "../../auto-reply/reply
import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js"; import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js";
import { resolveEffectiveMessagesConfig, resolveHumanDelayConfig } from "../../agents/identity.js"; import { resolveEffectiveMessagesConfig, resolveHumanDelayConfig } from "../../agents/identity.js";
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js"; import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "../../config/group-policy.js"; import {
resolveChannelGroupPolicy,
resolveChannelGroupRequireMention,
} from "../../config/group-policy.js";
import { resolveStateDir } from "../../config/paths.js"; import { resolveStateDir } from "../../config/paths.js";
import { shouldLogVerbose } from "../../globals.js"; import { shouldLogVerbose } from "../../globals.js";
import { getChildLogger } from "../../logging.js"; import { getChildLogger } from "../../logging.js";

View File

@@ -63,9 +63,9 @@ export async function getDeterministicFreePortBlock(params?: {
for (let attempt = 0; attempt < usable; attempt += 1) { for (let attempt = 0; attempt < usable; attempt += 1) {
const start = base + ((nextTestPortOffset + attempt) % usable); const start = base + ((nextTestPortOffset + attempt) % usable);
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
const ok = ( const ok = (await Promise.all(offsets.map((offset) => isPortFree(start + offset)))).every(
await Promise.all(offsets.map((offset) => isPortFree(start + offset))) Boolean,
).every(Boolean); );
if (!ok) continue; if (!ok) continue;
nextTestPortOffset = (nextTestPortOffset + attempt + blockSize) % usable; nextTestPortOffset = (nextTestPortOffset + attempt + blockSize) % usable;
return start; return start;