mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-20 05:31:30 +00:00
Reduce lint suppressions in core tests and runtime
This commit is contained in:
@@ -91,7 +91,8 @@
|
||||
|
||||
- Language: TypeScript (ESM). Prefer strict typing; avoid `any`.
|
||||
- Formatting/linting via Oxlint and Oxfmt.
|
||||
- Never add `@ts-nocheck` and do not disable `no-explicit-any`; fix root causes and update Oxlint/Oxfmt config only when required.
|
||||
- Never add `@ts-nocheck` and do not add inline lint suppressions by default. Fix root causes first; only keep a suppression when the code is intentionally correct, the rule cannot express that safely, and the comment explains why.
|
||||
- Do not disable `no-explicit-any`; prefer real types, `unknown`, or a narrow adapter/helper instead. Update Oxlint/Oxfmt config only when required.
|
||||
- Dynamic import guardrail: do not mix `await import("x")` and static `import ... from "x"` for the same module in production code paths. If you need lazy loading, create a dedicated `*.runtime.ts` boundary (that re-exports from `x`) and dynamically import that boundary from lazy callers only.
|
||||
- Dynamic import verification: after refactors that touch lazy-loading/module boundaries, run `pnpm build` and check for `[INEFFECTIVE_DYNAMIC_IMPORT]` warnings before submitting.
|
||||
- Extension SDK self-import guardrail: inside an extension package, do not import that same extension via `openclaw/plugin-sdk/<extension>` from production files. Route internal imports through a local barrel such as `./api.ts` or `./runtime-api.ts`, and keep the `plugin-sdk/<extension>` path as the external contract only.
|
||||
|
||||
@@ -111,7 +111,6 @@ vi.mock("./manager-runtime.js", () => ({
|
||||
|
||||
import { QmdMemoryManager } from "./qmd-manager.js";
|
||||
import { closeAllMemorySearchManagers, getMemorySearchManager } from "./search-manager.js";
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method -- mocked static function
|
||||
const createQmdManagerMock = vi.mocked(QmdMemoryManager.create);
|
||||
|
||||
type SearchManagerResult = Awaited<ReturnType<typeof getMemorySearchManager>>;
|
||||
@@ -169,8 +168,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
const second = await getMemorySearchManager({ cfg, agentId: "main" });
|
||||
|
||||
expect(first.manager).toBe(second.manager);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(1);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("evicts failed qmd wrapper so next call retries qmd", async () => {
|
||||
@@ -191,8 +189,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
const second = await getMemorySearchManager({ cfg, agentId: retryAgentId });
|
||||
requireManager(second);
|
||||
expect(second.manager).not.toBe(first.manager);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(2);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("does not cache qmd managers for status-only requests", async () => {
|
||||
@@ -210,8 +207,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
model: "qmd",
|
||||
requestedProvider: "qmd",
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(2);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(2);
|
||||
expect(mockMemoryIndexGet).not.toHaveBeenCalled();
|
||||
|
||||
await first.manager?.close?.();
|
||||
@@ -244,8 +240,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
chunks: 42,
|
||||
sourceCounts: [{ source: "memory", files: 10, chunks: 42 }],
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledWith(
|
||||
expect(createQmdManagerMock.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining({ agentId, mode: "status" }),
|
||||
);
|
||||
});
|
||||
@@ -260,8 +255,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
requireManager(full);
|
||||
requireManager(status);
|
||||
expect(status.manager).not.toBe(full.manager);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(1);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(1);
|
||||
await status.manager?.close?.();
|
||||
expect(mockPrimary.close).not.toHaveBeenCalled();
|
||||
|
||||
@@ -280,8 +274,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
const second = await getMemorySearchManager({ cfg, agentId, purpose: "status" });
|
||||
requireManager(second);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(2);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(2);
|
||||
expect(mockPrimary.close).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -305,8 +298,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
|
||||
const third = await getMemorySearchManager({ cfg, agentId: retryAgentId });
|
||||
expect(third.manager).toBe(secondManager);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(2);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("falls back to builtin search when qmd fails with sqlite busy", async () => {
|
||||
@@ -346,8 +338,7 @@ describe("getMemorySearchManager caching", () => {
|
||||
const second = await getMemorySearchManager({ cfg, agentId: "teardown-agent" });
|
||||
expect(second.manager).toBeTruthy();
|
||||
expect(second.manager).not.toBe(firstManager);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
expect(createQmdManagerMock).toHaveBeenCalledTimes(2);
|
||||
expect(createQmdManagerMock.mock.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("closes builtin index managers on teardown after runtime is loaded", async () => {
|
||||
|
||||
@@ -1,12 +1,52 @@
|
||||
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
||||
import { beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
loadRunOverflowCompactionHarness,
|
||||
mockedEnsureRuntimePluginsLoaded,
|
||||
mockedRunEmbeddedAttempt,
|
||||
} from "./run.overflow-compaction.harness.js";
|
||||
import type { EmbeddedRunAttemptResult } from "./run/types.js";
|
||||
|
||||
let runEmbeddedPiAgent: typeof import("./run.js").runEmbeddedPiAgent;
|
||||
|
||||
function makeAttemptResult(
|
||||
overrides: Partial<EmbeddedRunAttemptResult> = {},
|
||||
): EmbeddedRunAttemptResult {
|
||||
return {
|
||||
aborted: false,
|
||||
timedOut: false,
|
||||
timedOutDuringCompaction: false,
|
||||
promptError: null,
|
||||
sessionIdUsed: "test-session",
|
||||
messagesSnapshot: [],
|
||||
assistantTexts: [],
|
||||
toolMetas: [],
|
||||
lastAssistant: undefined,
|
||||
didSendViaMessagingTool: false,
|
||||
messagingToolSentTexts: [],
|
||||
messagingToolSentMediaUrls: [],
|
||||
messagingToolSentTargets: [],
|
||||
cloudCodeAssistFormatError: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function makeAssistantMessage(
|
||||
overrides: Partial<AssistantMessage> = {},
|
||||
): NonNullable<EmbeddedRunAttemptResult["lastAssistant"]> {
|
||||
return {
|
||||
role: "assistant",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
model: "gpt-5.2",
|
||||
usage: { input: 0, output: 0 } as AssistantMessage["usage"],
|
||||
stopReason: "end_turn" as AssistantMessage["stopReason"],
|
||||
timestamp: Date.now(),
|
||||
content: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("runEmbeddedPiAgent usage reporting", () => {
|
||||
beforeAll(async () => {
|
||||
({ runEmbeddedPiAgent } = await loadRunOverflowCompactionHarness());
|
||||
@@ -18,14 +58,11 @@ describe("runEmbeddedPiAgent usage reporting", () => {
|
||||
});
|
||||
|
||||
it("bootstraps runtime plugins with the resolved workspace before running", async () => {
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce({
|
||||
aborted: false,
|
||||
promptError: null,
|
||||
timedOut: false,
|
||||
sessionIdUsed: "test-session",
|
||||
assistantTexts: ["Response 1"],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any);
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
|
||||
makeAttemptResult({
|
||||
assistantTexts: ["Response 1"],
|
||||
}),
|
||||
);
|
||||
|
||||
await runEmbeddedPiAgent({
|
||||
sessionId: "test-session",
|
||||
@@ -44,14 +81,11 @@ describe("runEmbeddedPiAgent usage reporting", () => {
|
||||
});
|
||||
|
||||
it("forwards gateway subagent binding opt-in to runtime plugin bootstrap", async () => {
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce({
|
||||
aborted: false,
|
||||
promptError: null,
|
||||
timedOut: false,
|
||||
sessionIdUsed: "test-session",
|
||||
assistantTexts: ["Response 1"],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any);
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
|
||||
makeAttemptResult({
|
||||
assistantTexts: ["Response 1"],
|
||||
}),
|
||||
);
|
||||
|
||||
await runEmbeddedPiAgent({
|
||||
sessionId: "test-session",
|
||||
@@ -77,14 +111,11 @@ describe("runEmbeddedPiAgent usage reporting", () => {
|
||||
});
|
||||
|
||||
it("forwards sender identity fields into embedded attempts", async () => {
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce({
|
||||
aborted: false,
|
||||
promptError: null,
|
||||
timedOut: false,
|
||||
sessionIdUsed: "test-session",
|
||||
assistantTexts: ["Response 1"],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any);
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
|
||||
makeAttemptResult({
|
||||
assistantTexts: ["Response 1"],
|
||||
}),
|
||||
);
|
||||
|
||||
await runEmbeddedPiAgent({
|
||||
sessionId: "test-session",
|
||||
@@ -111,14 +142,11 @@ describe("runEmbeddedPiAgent usage reporting", () => {
|
||||
});
|
||||
|
||||
it("forwards memory flush write paths into memory-triggered attempts", async () => {
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce({
|
||||
aborted: false,
|
||||
promptError: null,
|
||||
timedOut: false,
|
||||
sessionIdUsed: "test-session",
|
||||
assistantTexts: [],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any);
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
|
||||
makeAttemptResult({
|
||||
assistantTexts: [],
|
||||
}),
|
||||
);
|
||||
|
||||
await runEmbeddedPiAgent({
|
||||
sessionId: "test-session",
|
||||
@@ -156,19 +184,15 @@ describe("runEmbeddedPiAgent usage reporting", () => {
|
||||
// We expect result.meta.agentMeta.usage.total to be 200 (last turn total).
|
||||
// The bug causes it to be 350 (accumulated total).
|
||||
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce({
|
||||
aborted: false,
|
||||
promptError: null,
|
||||
timedOut: false,
|
||||
sessionIdUsed: "test-session",
|
||||
assistantTexts: ["Response 1", "Response 2"],
|
||||
lastAssistant: {
|
||||
usage: { input: 150, output: 50, total: 200 },
|
||||
stopReason: "end_turn",
|
||||
},
|
||||
attemptUsage: { input: 250, output: 100, total: 350 },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any);
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
|
||||
makeAttemptResult({
|
||||
assistantTexts: ["Response 1", "Response 2"],
|
||||
lastAssistant: makeAssistantMessage({
|
||||
usage: { input: 150, output: 50, total: 200 } as unknown as AssistantMessage["usage"],
|
||||
}),
|
||||
attemptUsage: { input: 250, output: 100, total: 350 },
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await runEmbeddedPiAgent({
|
||||
sessionId: "test-session",
|
||||
|
||||
@@ -198,9 +198,8 @@ async function runLockWatchdogCheck(nowMs = Date.now()): Promise<number> {
|
||||
continue;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
`[session-write-lock] releasing lock held for ${heldForMs}ms (max=${held.maxHoldMs}ms): ${held.lockPath}`,
|
||||
process.stderr.write(
|
||||
`[session-write-lock] releasing lock held for ${heldForMs}ms (max=${held.maxHoldMs}ms): ${held.lockPath}\n`,
|
||||
);
|
||||
|
||||
const didRelease = await releaseHeldLock(sessionFile, held, { force: true });
|
||||
|
||||
@@ -226,8 +226,7 @@ export async function runGatewayLoop(params: {
|
||||
// Keep process alive; SIGUSR1 triggers an in-process restart (no supervisor required).
|
||||
// SIGTERM/SIGINT still exit after a graceful shutdown.
|
||||
let isFirstStart = true;
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
for (;;) {
|
||||
onIteration();
|
||||
try {
|
||||
server = await params.start();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { compactEmbeddedPiSessionDirect } from "../agents/pi-embedded-runner/compact.runtime.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
// ---------------------------------------------------------------------------
|
||||
// We dynamically import the registry so we can get a fresh module per test
|
||||
// group when needed. For most groups we use the shared singleton directly.
|
||||
@@ -46,8 +47,7 @@ const mockedCompactEmbeddedPiSessionDirect = vi.mocked(compactEmbeddedPiSessionD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Build a config object with a contextEngine slot for testing. */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function configWithSlot(engineId: string): any {
|
||||
function configWithSlot(engineId: string): OpenClawConfig {
|
||||
return { plugins: { slots: { contextEngine: engineId } } };
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@ export async function delegateCompactionToRuntime(
|
||||
// Import through a dedicated runtime boundary so the lazy edge remains effective.
|
||||
const { compactEmbeddedPiSessionDirect } =
|
||||
await import("../agents/pi-embedded-runner/compact.runtime.js");
|
||||
type RuntimeCompactionParams = Parameters<typeof compactEmbeddedPiSessionDirect>[0];
|
||||
|
||||
// runtimeContext carries the full CompactEmbeddedPiSessionParams fields set
|
||||
// by runtime callers. We spread them and override the fields that come from
|
||||
// the public ContextEngine compact() signature directly.
|
||||
const runtimeContext: ContextEngineRuntimeContext = params.runtimeContext ?? {};
|
||||
const runtimeContext = (params.runtimeContext ?? {}) as ContextEngineRuntimeContext &
|
||||
Partial<RuntimeCompactionParams>;
|
||||
const currentTokenCount =
|
||||
params.currentTokenCount ??
|
||||
(typeof runtimeContext.currentTokenCount === "number" &&
|
||||
@@ -32,7 +34,6 @@ export async function delegateCompactionToRuntime(
|
||||
? Math.floor(runtimeContext.currentTokenCount)
|
||||
: undefined);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridge runtimeContext matches CompactEmbeddedPiSessionParams
|
||||
const result = await compactEmbeddedPiSessionDirect({
|
||||
...runtimeContext,
|
||||
sessionId: params.sessionId,
|
||||
@@ -41,8 +42,9 @@ export async function delegateCompactionToRuntime(
|
||||
...(currentTokenCount !== undefined ? { currentTokenCount } : {}),
|
||||
force: params.force,
|
||||
customInstructions: params.customInstructions,
|
||||
workspaceDir: (runtimeContext.workspaceDir as string) ?? process.cwd(),
|
||||
} as Parameters<typeof compactEmbeddedPiSessionDirect>[0]);
|
||||
workspaceDir:
|
||||
typeof runtimeContext.workspaceDir === "string" ? runtimeContext.workspaceDir : process.cwd(),
|
||||
});
|
||||
|
||||
return {
|
||||
ok: result.ok,
|
||||
|
||||
@@ -75,15 +75,13 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
...actual.promises,
|
||||
mkdir: async (p: string) => {
|
||||
if (!isFixtureInMock(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.mkdir as any)(p, { recursive: true });
|
||||
return await actual.promises.mkdir(p, { recursive: true });
|
||||
}
|
||||
ensureDir(p);
|
||||
},
|
||||
readFile: async (p: string) => {
|
||||
if (!isFixtureInMock(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.readFile as any)(p, "utf-8");
|
||||
return await actual.promises.readFile(p, "utf-8");
|
||||
}
|
||||
const entry = fsState.entries.get(absInMock(p));
|
||||
if (!entry || entry.kind !== "file") {
|
||||
@@ -93,16 +91,14 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
writeFile: async (p: string, data: string | Uint8Array) => {
|
||||
if (!isFixtureInMock(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.writeFile as any)(p, data, "utf-8");
|
||||
return await actual.promises.writeFile(p, data, "utf-8");
|
||||
}
|
||||
const content = typeof data === "string" ? data : Buffer.from(data).toString("utf-8");
|
||||
setFile(p, content);
|
||||
},
|
||||
rename: async (from: string, to: string) => {
|
||||
if (!isFixtureInMock(from) || !isFixtureInMock(to)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.rename as any)(from, to);
|
||||
return await actual.promises.rename(from, to);
|
||||
}
|
||||
const fromAbs = absInMock(from);
|
||||
const toAbs = absInMock(to);
|
||||
@@ -116,8 +112,7 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
copyFile: async (from: string, to: string) => {
|
||||
if (!isFixtureInMock(from) || !isFixtureInMock(to)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.copyFile as any)(from, to);
|
||||
return await actual.promises.copyFile(from, to);
|
||||
}
|
||||
const entry = fsState.entries.get(absInMock(from));
|
||||
if (!entry || entry.kind !== "file") {
|
||||
@@ -127,8 +122,7 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
stat: async (p: string) => {
|
||||
if (!isFixtureInMock(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.stat as any)(p);
|
||||
return await actual.promises.stat(p);
|
||||
}
|
||||
const entry = fsState.entries.get(absInMock(p));
|
||||
if (!entry) {
|
||||
@@ -142,8 +136,7 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
access: async (p: string) => {
|
||||
if (!isFixtureInMock(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.access as any)(p);
|
||||
return await actual.promises.access(p);
|
||||
}
|
||||
const entry = fsState.entries.get(absInMock(p));
|
||||
if (!entry) {
|
||||
@@ -152,8 +145,7 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
unlink: async (p: string) => {
|
||||
if (!isFixtureInMock(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.promises.unlink as any)(p);
|
||||
return await actual.promises.unlink(p);
|
||||
}
|
||||
fsState.entries.delete(absInMock(p));
|
||||
},
|
||||
@@ -169,15 +161,13 @@ vi.mock("node:fs/promises", async (importOriginal) => {
|
||||
...actual,
|
||||
mkdir: async (p: string, _opts?: unknown) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.mkdir as any)(p, { recursive: true });
|
||||
return await actual.mkdir(p, { recursive: true });
|
||||
}
|
||||
ensureDir(p);
|
||||
},
|
||||
writeFile: async (p: string, data: string, _enc?: unknown) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return await (actual.writeFile as any)(p, data, "utf-8");
|
||||
return await actual.writeFile(p, data, "utf-8");
|
||||
}
|
||||
setFile(p, data);
|
||||
},
|
||||
|
||||
@@ -34,10 +34,9 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
...actual,
|
||||
existsSync: (p: string) =>
|
||||
isFixturePath(p) ? state.entries.has(absInMock(p)) : actual.existsSync(p),
|
||||
readFileSync: (p: string, encoding?: unknown) => {
|
||||
readFileSync: (p: string, encoding?: BufferEncoding) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return actual.readFileSync(p as any, encoding as any) as unknown;
|
||||
return actual.readFileSync(p, encoding);
|
||||
}
|
||||
const entry = readFixtureEntry(p);
|
||||
if (entry?.kind === "file") {
|
||||
@@ -47,8 +46,7 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
statSync: (p: string) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return actual.statSync(p as any) as unknown;
|
||||
return actual.statSync(p);
|
||||
}
|
||||
const entry = readFixtureEntry(p);
|
||||
if (entry?.kind === "file") {
|
||||
|
||||
@@ -31,10 +31,9 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
...actual,
|
||||
existsSync: (p: string) =>
|
||||
isFixturePath(p) ? state.entries.has(abs(p)) : actual.existsSync(p),
|
||||
readFileSync: (p: string, encoding?: unknown) => {
|
||||
readFileSync: (p: string, encoding?: BufferEncoding) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return actual.readFileSync(p as any, encoding as any) as unknown;
|
||||
return actual.readFileSync(p, encoding);
|
||||
}
|
||||
const entry = state.entries.get(abs(p));
|
||||
if (!entry || entry.kind !== "file") {
|
||||
@@ -44,8 +43,7 @@ vi.mock("node:fs", async (importOriginal) => {
|
||||
},
|
||||
statSync: (p: string) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return actual.statSync(p as any) as unknown;
|
||||
return actual.statSync(p);
|
||||
}
|
||||
const entry = state.entries.get(abs(p));
|
||||
if (!entry) {
|
||||
@@ -74,10 +72,9 @@ vi.mock("node:fs/promises", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("node:fs/promises")>();
|
||||
const wrapped = {
|
||||
...actual,
|
||||
readFile: async (p: string, encoding?: unknown) => {
|
||||
readFile: async (p: string, encoding?: BufferEncoding) => {
|
||||
if (!isFixturePath(p)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (await actual.readFile(p as any, encoding as any)) as unknown;
|
||||
return await actual.readFile(p, encoding);
|
||||
}
|
||||
const entry = state.entries.get(abs(p));
|
||||
if (!entry || entry.kind !== "file") {
|
||||
|
||||
@@ -17,9 +17,9 @@ import { VERSION } from "../version.js";
|
||||
import { ensureNodeHostConfig, saveNodeHostConfig, type NodeHostGatewayConfig } from "./config.js";
|
||||
import {
|
||||
coerceNodeInvokePayload,
|
||||
handleInvoke,
|
||||
type SkillBinsProvider,
|
||||
buildNodeInvokeResultParams,
|
||||
handleInvoke,
|
||||
} from "./invoke.js";
|
||||
|
||||
export { buildNodeInvokeResultParams };
|
||||
@@ -35,6 +35,10 @@ type NodeHostRunOptions = {
|
||||
|
||||
const DEFAULT_NODE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
||||
|
||||
function writeStderrLine(message: string): void {
|
||||
process.stderr.write(`${message}\n`);
|
||||
}
|
||||
|
||||
function resolveExecutablePathFromEnv(bin: string, pathEnv: string): string | null {
|
||||
if (bin.includes("/") || bin.includes("\\")) {
|
||||
return null;
|
||||
@@ -208,12 +212,10 @@ export async function runNodeHost(opts: NodeHostRunOptions): Promise<void> {
|
||||
},
|
||||
onConnectError: (err) => {
|
||||
// keep retrying (handled by GatewayClient)
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`node host gateway connect failed: ${err.message}`);
|
||||
writeStderrLine(`node host gateway connect failed: ${err.message}`);
|
||||
},
|
||||
onClose: (code, reason) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`node host gateway closed (${code}): ${reason}`);
|
||||
writeStderrLine(`node host gateway closed (${code}): ${reason}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user