feat: finalize mindspace service extraction phase a

This commit is contained in:
john
2026-07-03 08:40:28 +08:00
parent 506a551438
commit ec5b1a6e3f
32 changed files with 2834 additions and 490 deletions
+26 -7
View File
@@ -265,11 +265,25 @@ function mergeDeveloperTools(capabilities) {
return tools;
}
function resolveSandboxMcpLocalRoot(sandboxMcp) {
const localRoot = sandboxMcp?.workspaceRoot || sandboxMcp?.sandboxRoot || '';
return localRoot ? String(localRoot) : '';
}
function resolveSandboxMcpCompatRoot(sandboxMcp) {
const compatRoot = sandboxMcp?.sandboxRoot || sandboxMcp?.workspaceRoot || '';
return compatRoot ? String(compatRoot) : '';
}
function sandboxMcpEnvs(sandboxMcp, mcpTools) {
const localRoot = resolveSandboxMcpLocalRoot(sandboxMcp);
const compatRoot = resolveSandboxMcpCompatRoot(sandboxMcp);
const envs = {
SANDBOX_ROOT: sandboxMcp.sandboxRoot,
ALLOWED_TOOLS: mcpTools.join(','),
};
if (compatRoot) envs.SANDBOX_ROOT = compatRoot;
if (sandboxMcp.workspaceRoot || localRoot) envs.MINDSPACE_WORKSPACE_ROOT = sandboxMcp.workspaceRoot || localRoot;
if (sandboxMcp.workspaceRef) envs.MINDSPACE_WORKSPACE_REF = sandboxMcp.workspaceRef;
if (sandboxMcp.userId) envs.PRIVATE_DATA_USER_ID = sandboxMcp.userId;
for (const key of [
'DATABASE_URL',
@@ -289,9 +303,11 @@ function sandboxMcpEnvs(sandboxMcp, mcpTools) {
* Build goose agent/start extension_overrides from resolved capability flags.
* Returns null when the caller should use server defaults (admin / unrestricted).
*
* sandboxMcp: { serverPath, sandboxRoot, nodeExecPath? }
* When provided for a static_publish user, the built-in developer extension is replaced
* by a sandboxed stdio MCP that enforces filesystem boundaries at the OS level.
* sandboxMcp: { serverPath, sandboxRoot?, workspaceRoot?, workspaceRef?, nodeExecPath? }
* `sandboxRoot` remains the legacy local-path compatibility field.
* `workspaceRoot` is the preferred local adapter field for future MindSpace runtime extraction.
* When a local root is available for a static_publish user, the built-in developer extension
* is replaced by a sandboxed stdio MCP that enforces filesystem boundaries at the OS level.
*/
export function buildAgentExtensionPolicy(
capabilities,
@@ -303,7 +319,9 @@ export function buildAgentExtensionPolicy(
const extensions = [];
if (capabilities.static_publish || (capabilities.private_data_space && sandboxMcp)) {
if (sandboxMcp?.serverPath && sandboxMcp?.sandboxRoot) {
const localRoot = resolveSandboxMcpLocalRoot(sandboxMcp);
const compatRoot = resolveSandboxMcpCompatRoot(sandboxMcp);
if (sandboxMcp?.serverPath && localRoot) {
// Sandboxed stdio MCP: enforces SANDBOX_ROOT at the OS level.
// Replaces the built-in developer extension so path traversal is impossible.
const mcpTools = sandboxMcpTools(capabilities);
@@ -316,8 +334,9 @@ export function buildAgentExtensionPolicy(
display_name: 'sandbox-fs',
bundled: false,
cmd: resolveSandboxMcpNodeExecPath(sandboxMcp.nodeExecPath),
// sandboxRoot passed as argv[2] so it works even if goosed doesn't forward envs
args: [sandboxMcp.serverPath, sandboxMcp.sandboxRoot],
// Legacy MCP still accepts a local filesystem root as argv[2] even when the source
// capability is named workspaceRoot instead of sandboxRoot.
args: [sandboxMcp.serverPath, compatRoot],
// envs (goosed field name) as belt-and-suspenders backup
envs: sandboxMcpEnvs(sandboxMcp, mcpTools),
available_tools: mcpTools,