diff --git a/extensions/openshell/openclaw.plugin.json b/extensions/openshell/openclaw.plugin.json index 7b38f981eb8..83fbbfcd486 100644 --- a/extensions/openshell/openclaw.plugin.json +++ b/extensions/openshell/openclaw.plugin.json @@ -56,7 +56,8 @@ }, "timeoutSeconds": { "type": "number", - "minimum": 1 + "minimum": 1, + "maximum": 2147000 } } }, diff --git a/extensions/openshell/src/config.test.ts b/extensions/openshell/src/config.test.ts index e9bafdf45b4..37923f7c477 100644 --- a/extensions/openshell/src/config.test.ts +++ b/extensions/openshell/src/config.test.ts @@ -70,6 +70,14 @@ describe("openshell plugin config", () => { ).toThrow("mode must be one of mirror, remote"); }); + it("rejects timeouts beyond Node's safe timer range", () => { + expect(() => + resolveOpenShellPluginConfig({ + timeoutSeconds: 2_147_001, + }), + ).toThrow("timeoutSeconds must be a number <= 2147000"); + }); + it("keeps the runtime json schema in sync with the manifest config schema", () => { const manifest = JSON.parse( fsSync.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf8"), diff --git a/extensions/openshell/src/config.ts b/extensions/openshell/src/config.ts index 543f74b7a48..3d28a10fa9a 100644 --- a/extensions/openshell/src/config.ts +++ b/extensions/openshell/src/config.ts @@ -42,6 +42,7 @@ const DEFAULT_SOURCE = "openclaw"; const DEFAULT_REMOTE_WORKSPACE_DIR = "/sandbox"; const DEFAULT_REMOTE_AGENT_WORKSPACE_DIR = "/agent"; const DEFAULT_TIMEOUT_MS = 120_000; +const MAX_OPEN_SHELL_TIMEOUT_SECONDS = 2_147_000; const OPEN_SHELL_MANAGED_REMOTE_ROOTS = [ DEFAULT_REMOTE_WORKSPACE_DIR, DEFAULT_REMOTE_AGENT_WORKSPACE_DIR, @@ -90,8 +91,13 @@ const OpenShellPluginConfigSchema = z.strictObject({ "remoteAgentWorkspaceDir must be a non-empty string", ).optional(), timeoutSeconds: z - .number({ error: "timeoutSeconds must be a number >= 1" }) + .number({ + error: `timeoutSeconds must be a number between 1 and ${MAX_OPEN_SHELL_TIMEOUT_SECONDS}`, + }) .min(1, { error: "timeoutSeconds must be a number >= 1" }) + .max(MAX_OPEN_SHELL_TIMEOUT_SECONDS, { + error: `timeoutSeconds must be a number <= ${MAX_OPEN_SHELL_TIMEOUT_SECONDS}`, + }) .optional(), });