From 753c1eec23628ce46045e0739c125b51c1cb02c4 Mon Sep 17 00:00:00 2001 From: john Date: Mon, 10 Aug 2026 20:49:36 +0800 Subject: [PATCH] fix(scheduled-task): forward worker env to sandbox MCP goosed stdio MCPs do not inherit Portal env, so scheduled_task_create always reported worker disabled even when H5_REMINDER_WORKER_ENABLED=1. Forward worker flags in sandboxMcpEnvs and add a regression test. Co-authored-by: Cursor --- capabilities.mjs | 8 ++++++++ capabilities.test.mjs | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/capabilities.mjs b/capabilities.mjs index 38aa004..115a8aa 100644 --- a/capabilities.mjs +++ b/capabilities.mjs @@ -606,6 +606,14 @@ function sandboxMcpEnvs(sandboxMcp, mcpTools) { envs[key] = String(value).trim(); } } + // goosed stdio MCPs do not inherit Portal env; forward worker flags so + // scheduled_task_create can report the same enablement as server.mjs. + for (const key of ['H5_REMINDER_WORKER_ENABLED', 'H5_SCHEDULED_TASK_WORKER_ENABLED']) { + const value = process.env[key]; + if (value != null && String(value).trim() !== '') { + envs[key] = String(value).trim(); + } + } if (mcpTools.includes('generate_image')) { if (sandboxMcp.agentApiBaseUrl) { envs.MINDSPACE_AGENT_API_BASE_URL = sandboxMcp.agentApiBaseUrl; diff --git a/capabilities.test.mjs b/capabilities.test.mjs index bb9afcf..c8a4584 100644 --- a/capabilities.test.mjs +++ b/capabilities.test.mjs @@ -507,6 +507,31 @@ test('static_publish with sandboxMcp uses stdio sandbox-fs extension instead of assert.ok(!allTools.includes('shell'), 'shell should not be exposed'); }); +test('sandboxMcpEnvs forwards scheduled task worker flags from portal env', () => { + const previousReminder = process.env.H5_REMINDER_WORKER_ENABLED; + const previousScheduled = process.env.H5_SCHEDULED_TASK_WORKER_ENABLED; + process.env.H5_REMINDER_WORKER_ENABLED = '1'; + delete process.env.H5_SCHEDULED_TASK_WORKER_ENABLED; + try { + const caps = { ...DEFAULT_USER_CAPABILITIES, static_publish: true }; + const policy = buildAgentExtensionPolicy(caps, { + sandboxMcp: { + serverPath: '/opt/portal/mindspace-sandbox-mcp.mjs', + sandboxRoot: '/opt/h5/MindSpace/abc123', + }, + }); + const sandboxExt = policy.extensionOverrides.find((ext) => ext.name === 'sandbox-fs'); + assert.ok(sandboxExt); + assert.equal(sandboxExt.envs.H5_REMINDER_WORKER_ENABLED, '1'); + assert.equal(sandboxExt.envs.H5_SCHEDULED_TASK_WORKER_ENABLED, undefined); + } finally { + if (previousReminder === undefined) delete process.env.H5_REMINDER_WORKER_ENABLED; + else process.env.H5_REMINDER_WORKER_ENABLED = previousReminder; + if (previousScheduled === undefined) delete process.env.H5_SCHEDULED_TASK_WORKER_ENABLED; + else process.env.H5_SCHEDULED_TASK_WORKER_ENABLED = previousScheduled; + } +}); + test('sandboxMcp emits a scoped logical workspace token only for a bound session', () => { const secret = 'mindspace-mcp-policy-secret-1234';