diff --git a/src/security/temp-path-guard.test.ts b/src/security/temp-path-guard.test.ts index d5d2abb88..1d2a0c1dc 100644 --- a/src/security/temp-path-guard.test.ts +++ b/src/security/temp-path-guard.test.ts @@ -1,3 +1,4 @@ +import { spawnSync } from "node:child_process"; import fs from "node:fs/promises"; import path from "node:path"; import ts from "typescript"; @@ -104,6 +105,56 @@ async function listTsFiles(dir: string): Promise { return out; } +function parsePathList(stdout: string): Set { + const out = new Set(); + for (const line of stdout.split(/\r?\n/)) { + const trimmed = line.trim(); + if (!trimmed) { + continue; + } + out.add(path.resolve(trimmed)); + } + return out; +} + +function prefilterLikelyTmpdirJoinFiles(root: string): Set | null { + const commonArgs = [ + "--files-with-matches", + "--glob", + "*.ts", + "--glob", + "*.tsx", + "--glob", + "!**/*.test.ts", + "--glob", + "!**/*.test.tsx", + "--glob", + "!**/*.e2e.ts", + "--glob", + "!**/*.e2e.tsx", + "--glob", + "!**/*.d.ts", + "--no-messages", + ]; + const joined = spawnSync("rg", [...commonArgs, "path\\.join", root], { encoding: "utf8" }); + if (joined.error || (joined.status !== 0 && joined.status !== 1)) { + return null; + } + const tmpdir = spawnSync("rg", [...commonArgs, "os\\.tmpdir", root], { encoding: "utf8" }); + if (tmpdir.error || (tmpdir.status !== 0 && tmpdir.status !== 1)) { + return null; + } + const joinMatches = parsePathList(joined.stdout); + const tmpdirMatches = parsePathList(tmpdir.stdout); + const intersection = new Set(); + for (const file of joinMatches) { + if (tmpdirMatches.has(file)) { + intersection.add(file); + } + } + return intersection; +} + describe("temp path guard", () => { it("skips test helper filename variants", () => { expect(shouldSkip("src/commands/test-helpers.ts")).toBe(true); @@ -139,7 +190,8 @@ describe("temp path guard", () => { for (const root of RUNTIME_ROOTS) { const absRoot = path.join(repoRoot, root); - const files = await listTsFiles(absRoot); + const rgPrefiltered = prefilterLikelyTmpdirJoinFiles(absRoot); + const files = rgPrefiltered ? [...rgPrefiltered] : await listTsFiles(absRoot); for (const file of files) { const relativePath = path.relative(repoRoot, file); if (shouldSkip(relativePath)) { diff --git a/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts b/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts index 9017da673..72572110e 100644 --- a/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts +++ b/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts @@ -99,9 +99,15 @@ describe("monitorSignalProvider tool results", () => { autoStart: false, baseUrl: "http://127.0.0.1:8080", abortSignal: abortController.signal, + reconnectPolicy: { + initialMs: 1, + maxMs: 1, + factor: 1, + jitter: 0, + }, }); - await vi.advanceTimersByTimeAsync(1_000); + await vi.advanceTimersByTimeAsync(5); await monitorPromise; expect(streamMock).toHaveBeenCalledTimes(2); diff --git a/src/signal/monitor.ts b/src/signal/monitor.ts index 461f38c21..d874fea11 100644 --- a/src/signal/monitor.ts +++ b/src/signal/monitor.ts @@ -9,6 +9,7 @@ import { warnMissingProviderGroupPolicyFallbackOnce, } from "../config/runtime-group-policy.js"; import type { SignalReactionNotificationMode } from "../config/types.js"; +import type { BackoffPolicy } from "../infra/backoff.js"; import { waitForTransportReady } from "../infra/transport-ready.js"; import { saveMediaBuffer } from "../media/store.js"; import { createNonExitingRuntime, type RuntimeEnv } from "../runtime.js"; @@ -46,6 +47,7 @@ export type MonitorSignalOpts = { allowFrom?: Array; groupAllowFrom?: Array; mediaMaxMb?: number; + reconnectPolicy?: Partial; }; function resolveRuntime(opts: MonitorSignalOpts): RuntimeEnv { @@ -449,6 +451,7 @@ export async function monitorSignalProvider(opts: MonitorSignalOpts = {}): Promi account, abortSignal: daemonLifecycle.abortSignal, runtime, + policy: opts.reconnectPolicy, onEvent: (event) => { void handleEvent(event).catch((err) => { runtime.error?.(`event handler failed: ${String(err)}`);